├── src
├── test
│ ├── resources
│ │ ├── sample.wav
│ │ └── logback.xml
│ └── java
│ │ └── com
│ │ └── orctom
│ │ └── rnnoise
│ │ └── DenoiserIT.java
└── main
│ ├── resources
│ ├── darwin
│ │ └── librnnoise.dylib
│ ├── linux-amd64
│ │ └── librnnoise.so
│ └── linux-x86-64
│ │ └── librnnoise.so
│ └── java
│ └── com
│ └── orctom
│ └── rnnoise
│ ├── exception
│ └── IllegalFrameSizeException.java
│ ├── Bytes.java
│ └── Denoiser.java
├── .gitignore
└── pom.xml
/src/test/resources/sample.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orctom/rnnoise-java/HEAD/src/test/resources/sample.wav
--------------------------------------------------------------------------------
/src/main/resources/darwin/librnnoise.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orctom/rnnoise-java/HEAD/src/main/resources/darwin/librnnoise.dylib
--------------------------------------------------------------------------------
/src/main/resources/linux-amd64/librnnoise.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orctom/rnnoise-java/HEAD/src/main/resources/linux-amd64/librnnoise.so
--------------------------------------------------------------------------------
/src/main/resources/linux-x86-64/librnnoise.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orctom/rnnoise-java/HEAD/src/main/resources/linux-x86-64/librnnoise.so
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | DummyTests.java
2 | DummyTest.java
3 | .gradle
4 | .idea
5 | *.iml
6 | *.ipr
7 | *.iws
8 | /files/
9 | build/
10 | target/
11 |
12 | .classpath
13 | .settings/
14 | .project
15 |
16 | *.log
17 | *tmp*
18 | diagrams
19 | *.versionsBackup
20 | *.pcm
21 |
--------------------------------------------------------------------------------
/src/main/java/com/orctom/rnnoise/exception/IllegalFrameSizeException.java:
--------------------------------------------------------------------------------
1 | package com.orctom.rnnoise.exception;
2 |
3 | public class IllegalFrameSizeException extends RuntimeException {
4 |
5 | public IllegalFrameSizeException(String message) {
6 | super(message);
7 | }
8 |
9 | public IllegalFrameSizeException(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [%d{yyy-MM-dd HH:mm:ss.SSS}] [%thread] %-5level %logger{35} %line - %m%n
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/main/java/com/orctom/rnnoise/Bytes.java:
--------------------------------------------------------------------------------
1 | package com.orctom.rnnoise;
2 |
3 | public abstract class Bytes {
4 |
5 | public static byte[] toByteArray(float[] input) {
6 | byte[] ret = new byte[input.length * 2];
7 | for (int i = 0; i < input.length; ++i) {
8 | short x = ((Float) input[i]).shortValue();
9 | ret[i * 2] = (byte) (x & 0x00FF);
10 | ret[i * 2 + 1] = (byte) ((x & 0xFF00) >> 8);
11 | }
12 | return ret;
13 | }
14 |
15 | public static float[] toFloatArray(byte[] input) {
16 | float[] ret = new float[input.length / 2];
17 | for (int i = 0; i < input.length / 2; ++i) {
18 | if ((input[i * 2 + 1] & 0x80) != 0) {
19 | ret[i] = -32768 + ((input[i * 2 + 1] & 0x7f) << 8) | (input[i * 2] & 0xff);
20 | } else {
21 | ret[i] = ((input[i * 2 + 1] << 8) & 0xff00) | (input[i * 2] & 0xff);
22 | }
23 | }
24 | return ret;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.orctom
6 | basepom
7 | 1.3
8 |
9 |
10 | rnnoise-java
11 | 1.1.2-SNAPSHOT
12 |
13 | rnnoise for Java
14 | https://github.com/orctom/rnnoise-java//
15 |
16 |
17 | https://github.com/orctom/rnnoise-java/issues
18 | GitHub
19 |
20 |
21 |
22 | Apache License, Version 2.0
23 | http://www.apache.org/licenses/LICENSE-2.0
24 | repo
25 |
26 |
27 |
28 | https://github.com/orctom/rnnoise-java/
29 | scm:git:git@github.com:orctom/rnnoise-java.git
30 | scm:git:git@github.com:orctom/rnnoise-java.git
31 | HEAD
32 |
33 |
34 |
35 | 1.8
36 |
37 |
38 |
39 |
40 | net.java.dev.jna
41 | jna
42 | 4.5.0
43 |
44 |
45 | org.slf4j
46 | slf4j-api
47 | 1.7.25
48 |
49 |
50 | com.google.guava
51 | guava
52 | 23.0
53 | test
54 |
55 |
56 | ch.qos.logback
57 | logback-classic
58 | 1.2.3
59 | test
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/test/java/com/orctom/rnnoise/DenoiserIT.java:
--------------------------------------------------------------------------------
1 | package com.orctom.rnnoise;
2 |
3 | import com.google.common.base.Stopwatch;
4 | import com.google.common.io.ByteStreams;
5 | import com.google.common.io.Files;
6 | import org.junit.Test;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import java.io.File;
11 | import java.io.InputStream;
12 | import java.util.Arrays;
13 |
14 | public class DenoiserIT {
15 |
16 | private static final Logger LOGGER = LoggerFactory.getLogger(DenoiserIT.class);
17 |
18 | @Test
19 | public void process() throws Exception {
20 | try (Denoiser denoiser = new Denoiser()) {
21 | InputStream in = DenoiserIT.class.getResourceAsStream("/sample.wav");
22 | byte[] bytes = ByteStreams.toByteArray(in);
23 | // int frameSize = 9600;
24 | int frameSize = 12800;
25 | int startIndex = 0;
26 | int endIndex = frameSize;
27 | boolean isFistFrame = true;
28 | LOGGER.debug("total: {}", bytes.length);
29 | byte[] output = new byte[bytes.length];
30 | while (startIndex < bytes.length) {
31 | if (endIndex > bytes.length) {
32 | endIndex = bytes.length;
33 | }
34 | byte[] data = Arrays.copyOfRange(bytes, startIndex, endIndex);
35 | LOGGER.debug("{} --> {}", startIndex, endIndex);
36 | Stopwatch stopwatch = Stopwatch.createStarted();
37 | byte[] dataOut = denoiser.process(data);
38 | LOGGER.debug("took: {}", stopwatch);
39 |
40 | if (isFistFrame) {
41 | isFistFrame = false;
42 | startIndex += frameSize;
43 | endIndex += frameSize;
44 | continue;
45 | }
46 | System.arraycopy(dataOut, 0, output, startIndex, endIndex - startIndex);
47 | startIndex += frameSize;
48 | endIndex += frameSize;
49 | }
50 |
51 | String cwd = System.getProperty("user.dir");
52 | File file = new File(cwd, "processed.pcm");
53 | if (file.exists()) {
54 | boolean deleted = file.delete();
55 | LOGGER.debug("deleted: {}", deleted);
56 | }
57 |
58 | Files.write(output, file);
59 | LOGGER.debug("Processed wrote to: {}", file.getAbsolutePath());
60 | } catch (Exception e) {
61 | e.printStackTrace();
62 | }
63 | LOGGER.debug("done.");
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/orctom/rnnoise/Denoiser.java:
--------------------------------------------------------------------------------
1 | package com.orctom.rnnoise;
2 |
3 | import com.sun.jna.Library;
4 | import com.sun.jna.Native;
5 | import com.sun.jna.Pointer;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import java.io.Closeable;
10 | import java.util.Arrays;
11 | import java.util.concurrent.atomic.AtomicBoolean;
12 |
13 | public class Denoiser implements Closeable {
14 |
15 | private static final Logger LOGGER = LoggerFactory.getLogger(Denoiser.class);
16 |
17 | private static final int FRAME_SIZE = 960;
18 |
19 | private Pointer state;
20 |
21 | private AtomicBoolean stopped = new AtomicBoolean(false);
22 |
23 | public Denoiser() {
24 | LOGGER.debug("Denoiser started");
25 | state = Rnnoise.INSTANCE.rnnoise_create();
26 | }
27 |
28 | public void close() {
29 | LOGGER.debug("Denoiser closed");
30 | if (stopped.getAndSet(true)) {
31 | return;
32 | }
33 |
34 | Rnnoise.INSTANCE.rnnoise_destroy(state);
35 | state = null;
36 | }
37 |
38 | public byte[] process(byte[] pcm) {
39 | int len = pcm.length;
40 | if (len < FRAME_SIZE) {
41 | return pcm;
42 | }
43 |
44 | byte[] denoised = new byte[len];
45 | int startIndex = 0;
46 | int endIndex = FRAME_SIZE;
47 | while (startIndex < len) {
48 | if (endIndex > len) {
49 | endIndex = len;
50 | }
51 |
52 | LOGGER.trace("start: {}, end: {}", startIndex, endIndex);
53 |
54 | byte[] frame = Arrays.copyOfRange(pcm, startIndex, endIndex);
55 | byte[] processed = processFrame(frame);
56 | System.arraycopy(processed, 0, denoised, startIndex, processed.length);
57 | startIndex += FRAME_SIZE;
58 | endIndex += FRAME_SIZE;
59 | }
60 |
61 | return denoised;
62 | }
63 |
64 | private byte[] processFrame(byte[] frame) {
65 | if (frame.length != FRAME_SIZE) {
66 | return frame;
67 | }
68 |
69 | float[] pcmIn = Bytes.toFloatArray(frame);
70 | float[] pcmOut = new float[pcmIn.length];
71 | Rnnoise.INSTANCE.rnnoise_process_frame(state, pcmOut, pcmIn);
72 | return Bytes.toByteArray(pcmOut);
73 | }
74 |
75 | public interface Rnnoise extends Library {
76 |
77 | Rnnoise INSTANCE = (Rnnoise) Native.loadLibrary("rnnoise", Rnnoise.class);
78 |
79 | Pointer rnnoise_create();
80 |
81 | int rnnoise_get_size();
82 |
83 | int rnnoise_init(Pointer state);
84 |
85 | void rnnoise_process_frame(Pointer state, float[] out, float[] in);
86 |
87 | void rnnoise_destroy(Pointer stata);
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------