diff --git a/.github/workflows/run-java-test.yaml b/.github/workflows/run-java-test.yaml index 7fe3d451..dae47b1a 100644 --- a/.github/workflows/run-java-test.yaml +++ b/.github/workflows/run-java-test.yaml @@ -105,6 +105,15 @@ jobs: make -j4 ls -lh lib + - name: Run speech enhancement (GTCRN) + shell: bash + run: | + cd ./java-api-examples + ./run-non-streaming-speech-enhancement-gtcrn.sh + ls -lh *.wav + + rm -fv gtcrn_simple.onnx *.wav + - name: Run java test (Online add punctuations) shell: bash run: | diff --git a/java-api-examples/NonStreamingSpeechEnhancementGtcrn.java b/java-api-examples/NonStreamingSpeechEnhancementGtcrn.java new file mode 100644 index 00000000..09c668af --- /dev/null +++ b/java-api-examples/NonStreamingSpeechEnhancementGtcrn.java @@ -0,0 +1,38 @@ +// Copyright 2025 Xiaomi Corporation + +// This file shows how to use speech enhancement models in sherpa-onnx +// +// please download files in this script from +// https://github.com/k2-fsa/sherpa-onnx/releases/tag/speech-enhancement-models + +import com.k2fsa.sherpa.onnx.*; + +public class NonStreamingSpeechEnhancementGtcrn { + public static void main(String[] args) { + String model = "./gtcrn_simple.onnx"; + OfflineSpeechDenoiserGtcrnModelConfig gtcrn = + OfflineSpeechDenoiserGtcrnModelConfig.builder().setModel(model).build(); + + OfflineSpeechDenoiserModelConfig modelConfig = + OfflineSpeechDenoiserModelConfig.builder() + .setGtcrn(gtcrn) + .setNumThreads(1) + .setDebug(true) + .setProvider("cpu") + .build(); + OfflineSpeechDenoiserConfig config = + OfflineSpeechDenoiserConfig.builder().setModel(modelConfig).build(); + + OfflineSpeechDenoiser speech_denoiser = new OfflineSpeechDenoiser(config); + + String testWaveFilename = "./inp_16k.wav"; + WaveReader reader = new WaveReader(testWaveFilename); + + DenoisedAudio denoised = speech_denoiser.run(reader.getSamples(), reader.getSampleRate()); + String outFilename = "enhanced-16k.wav"; + WaveWriter.write(outFilename, denoised.getSamples(), denoised.getSampleRate()); + System.out.printf("Saved to %s\n", outFilename); + + speech_denoiser.release(); + } +} diff --git a/java-api-examples/run-non-streaming-speech-enhancement-gtcrn.sh b/java-api-examples/run-non-streaming-speech-enhancement-gtcrn.sh new file mode 100755 index 00000000..ed2cb6f1 --- /dev/null +++ b/java-api-examples/run-non-streaming-speech-enhancement-gtcrn.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +set -ex + +if [[ ! -f ../build/lib/libsherpa-onnx-jni.dylib && ! -f ../build/lib/libsherpa-onnx-jni.so ]]; then + mkdir -p ../build + pushd ../build + cmake \ + -DSHERPA_ONNX_ENABLE_PYTHON=OFF \ + -DSHERPA_ONNX_ENABLE_TESTS=OFF \ + -DSHERPA_ONNX_ENABLE_CHECK=OFF \ + -DBUILD_SHARED_LIBS=ON \ + -DSHERPA_ONNX_ENABLE_PORTAUDIO=OFF \ + -DSHERPA_ONNX_ENABLE_JNI=ON \ + .. + + make -j4 + ls -lh lib + popd +fi + +if [ ! -f ../sherpa-onnx/java-api/build/sherpa-onnx.jar ]; then + pushd ../sherpa-onnx/java-api + make + popd +fi + +if [ ! -f ./gtcrn_simple.onnx ]; then + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speech-enhancement-models/gtcrn_simple.onnx +fi + +if [ ! -f ./inp_16k.wav ]; then + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speech-enhancement-models/inp_16k.wav +fi + +java \ + -Djava.library.path=$PWD/../build/lib \ + -cp ../sherpa-onnx/java-api/build/sherpa-onnx.jar \ + NonStreamingSpeechEnhancementGtcrn.java diff --git a/sherpa-onnx/csrc/offline-speech-denoiser-gtcrn-model.cc b/sherpa-onnx/csrc/offline-speech-denoiser-gtcrn-model.cc index ef7e04f5..1de44f22 100644 --- a/sherpa-onnx/csrc/offline-speech-denoiser-gtcrn-model.cc +++ b/sherpa-onnx/csrc/offline-speech-denoiser-gtcrn-model.cc @@ -9,6 +9,15 @@ #include #include +#if __ANDROID_API__ >= 9 +#include "android/asset_manager.h" +#include "android/asset_manager_jni.h" +#endif + +#if __OHOS__ +#include "rawfile/raw_file_manager.h" +#endif + #include "sherpa-onnx/csrc/file-utils.h" #include "sherpa-onnx/csrc/onnx-utils.h" #include "sherpa-onnx/csrc/session.h" @@ -193,4 +202,14 @@ OfflineSpeechDenoiserGtcrnModel::GetMetaData() const { return impl_->GetMetaData(); } +#if __ANDROID_API__ >= 9 +template OfflineSpeechDenoiserGtcrnModel::OfflineSpeechDenoiserGtcrnModel( + AAssetManager *mgr, const OfflineSpeechDenoiserModelConfig &config); +#endif + +#if __OHOS__ +template OfflineSpeechDenoiserGtcrnModel::OfflineSpeechDenoiserGtcrnModel( + NativeResourceManager *mgr, const OfflineSpeechDenoiserModelConfig &config); +#endif + } // namespace sherpa_onnx diff --git a/sherpa-onnx/java-api/Makefile b/sherpa-onnx/java-api/Makefile index 27a2b775..249e3eb8 100644 --- a/sherpa-onnx/java-api/Makefile +++ b/sherpa-onnx/java-api/Makefile @@ -84,6 +84,11 @@ java_files += OfflineSpeakerDiarizationSegment.java java_files += OfflineSpeakerDiarizationCallback.java java_files += OfflineSpeakerDiarization.java +java_files += OfflineSpeechDenoiserGtcrnModelConfig.java +java_files += OfflineSpeechDenoiserModelConfig.java +java_files += OfflineSpeechDenoiserConfig.java +java_files += DenoisedAudio.java +java_files += OfflineSpeechDenoiser.java class_files := $(java_files:%.java=%.class) diff --git a/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/DenoisedAudio.java b/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/DenoisedAudio.java new file mode 100644 index 00000000..dcad1d5b --- /dev/null +++ b/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/DenoisedAudio.java @@ -0,0 +1,32 @@ +// Copyright 2025 Xiaomi Corporation + +package com.k2fsa.sherpa.onnx; + +public class DenoisedAudio { + static { + System.loadLibrary("sherpa-onnx-jni"); + } + + private final float[] samples; + private final int sampleRate; + + public DenoisedAudio(float[] samples, int sampleRate) { + this.samples = samples; + this.sampleRate = sampleRate; + } + + public int getSampleRate() { + return sampleRate; + } + + public float[] getSamples() { + return samples; + } + + // return true if saved successfully. + public boolean save(String filename) { + return saveImpl(filename, samples, sampleRate); + } + + private native boolean saveImpl(String filename, float[] samples, int sampleRate); +} diff --git a/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiser.java b/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiser.java new file mode 100644 index 00000000..5eceaa6f --- /dev/null +++ b/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiser.java @@ -0,0 +1,43 @@ +// Copyright 2025 Xiaomi Corporation + +package com.k2fsa.sherpa.onnx; + +public class OfflineSpeechDenoiser { + static { + System.loadLibrary("sherpa-onnx-jni"); + } + + private long ptr = 0; + + public OfflineSpeechDenoiser(OfflineSpeechDenoiserConfig config) { + ptr = newFromFile(config); + } + + public int getSampleRate() { + return getSampleRate(ptr); + } + + public DenoisedAudio run(float[] samples, int sampleRate) { + return run(ptr, samples, sampleRate); + } + + protected void finalize() throws Throwable { + release(); + } + + public void release() { + if (this.ptr == 0) { + return; + } + delete(this.ptr); + this.ptr = 0; + } + + private native void delete(long ptr); + + private native int getSampleRate(long ptr); + + private native DenoisedAudio run(long ptr, float[] samples, int sampleRate); + + private native long newFromFile(OfflineSpeechDenoiserConfig config); +} diff --git a/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiserConfig.java b/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiserConfig.java new file mode 100644 index 00000000..0dc885e7 --- /dev/null +++ b/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiserConfig.java @@ -0,0 +1,27 @@ +// Copyright 2025 Xiaomi Corporation +package com.k2fsa.sherpa.onnx; + +public class OfflineSpeechDenoiserConfig { + private final OfflineSpeechDenoiserModelConfig model; + + private OfflineSpeechDenoiserConfig(OfflineSpeechDenoiserConfig.Builder builder) { + this.model = builder.model; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private OfflineSpeechDenoiserModelConfig model = OfflineSpeechDenoiserModelConfig.builder().build(); + + public OfflineSpeechDenoiserConfig build() { + return new OfflineSpeechDenoiserConfig(this); + } + + public Builder setModel(OfflineSpeechDenoiserModelConfig model) { + this.model = model; + return this; + } + } +} diff --git a/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiserGtcrnModelConfig.java b/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiserGtcrnModelConfig.java new file mode 100644 index 00000000..5caf056b --- /dev/null +++ b/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiserGtcrnModelConfig.java @@ -0,0 +1,31 @@ +// Copyright 2025 Xiaomi Corporation +package com.k2fsa.sherpa.onnx; + +public class OfflineSpeechDenoiserGtcrnModelConfig { + private final String model; + + private OfflineSpeechDenoiserGtcrnModelConfig(Builder builder) { + this.model = builder.model; + } + + public static Builder builder() { + return new Builder(); + } + + public String getModel() { + return model; + } + + public static class Builder { + private String model = ""; + + public OfflineSpeechDenoiserGtcrnModelConfig build() { + return new OfflineSpeechDenoiserGtcrnModelConfig(this); + } + + public Builder setModel(String model) { + this.model = model; + return this; + } + } +} diff --git a/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiserModelConfig.java b/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiserModelConfig.java new file mode 100644 index 00000000..3d35d0ab --- /dev/null +++ b/sherpa-onnx/java-api/src/com/k2fsa/sherpa/onnx/OfflineSpeechDenoiserModelConfig.java @@ -0,0 +1,51 @@ +// Copyright 2025 Xiaomi Corporation +package com.k2fsa.sherpa.onnx; + +public class OfflineSpeechDenoiserModelConfig { + private final OfflineSpeechDenoiserGtcrnModelConfig gtcrn; + private final int numThreads; + private final boolean debug; + private final String provider; + + private OfflineSpeechDenoiserModelConfig(Builder builder) { + this.gtcrn = builder.gtcrn; + this.numThreads = builder.numThreads; + this.debug = builder.debug; + this.provider = builder.provider; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private OfflineSpeechDenoiserGtcrnModelConfig gtcrn = OfflineSpeechDenoiserGtcrnModelConfig.builder().build(); + private int numThreads = 1; + private boolean debug = true; + private String provider = "cpu"; + + public OfflineSpeechDenoiserModelConfig build() { + return new OfflineSpeechDenoiserModelConfig(this); + } + + public Builder setGtcrn(OfflineSpeechDenoiserGtcrnModelConfig gtcrn) { + this.gtcrn = gtcrn; + return this; + } + + public Builder setNumThreads(int numThreads) { + this.numThreads = numThreads; + return this; + } + + public Builder setDebug(boolean debug) { + this.debug = debug; + return this; + } + + public Builder setProvider(String provider) { + this.provider = provider; + return this; + } + } +}