mirror of
https://github.com/k2-fsa/sherpa-onnx.git
synced 2026-11-10 21:11:03 +08:00
Add async TTS examples, LinearResampler API, and use node-cpal for microphone (#3623)
This commit is contained in:
1 parent
58bb4b8001
commit
6acf367a39
57 files changed
+1982
-811
No files matched your search
@@ -130,6 +130,7 @@ tar xf kitten-nano-en-v0_1-fp16.tar.bz2
|
||||
rm kitten-nano-en-v0_1-fp16.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_kitten_en.js
|
||||
node ./test_tts_non_streaming_kitten_en_sync.js
|
||||
|
||||
rm -rf kitten-nano-en-v0_1-fp16
|
||||
|
||||
@@ -253,9 +254,9 @@ if [[ $arch != "ia32" && $platform != "win32" ]]; then
|
||||
node ./test_asr_non_streaming_nemo_ctc.js
|
||||
rm -rf sherpa-onnx-nemo-fast-conformer-ctc-be-de-en-es-fr-hr-it-pl-ru-uk-20k
|
||||
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
|
||||
tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
|
||||
rm sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
|
||||
tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
|
||||
rm sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
|
||||
|
||||
node ./test_asr_non_streaming_sense_voice.js
|
||||
|
||||
@@ -268,8 +269,12 @@ if [[ $arch != "ia32" && $platform != "win32" ]]; then
|
||||
|
||||
node ./test_asr_non_streaming_sense_voice_with_hr.js
|
||||
|
||||
rm -rf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17
|
||||
rm -rf dict replace.fst test-hr.wav lexicon.txt
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/silero_vad.onnx
|
||||
|
||||
node ./test_vad_asr_non_streaming_sense_voice_microphone.js
|
||||
|
||||
rm -rf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17
|
||||
rm -rf dict replace.fst test-hr.wav lexicon.txt silero_vad.onnx
|
||||
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-paraformer-zh-2023-09-14.tar.bz2
|
||||
tar xvf sherpa-onnx-paraformer-zh-2023-09-14.tar.bz2
|
||||
@@ -294,6 +299,7 @@ tar xf kokoro-multi-lang-v1_0.tar.bz2
|
||||
rm kokoro-multi-lang-v1_0.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_kokoro_zh_en.js
|
||||
node ./test_tts_non_streaming_kokoro_zh_en_async.js
|
||||
ls -lh *.wav
|
||||
rm -rf kokoro-multi-lang-v1_0
|
||||
|
||||
@@ -302,6 +308,7 @@ tar xf kokoro-en-v0_19.tar.bz2
|
||||
rm kokoro-en-v0_19.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_kokoro_en.js
|
||||
node ./test_tts_non_streaming_kokoro_en_async.js
|
||||
ls -lh *.wav
|
||||
rm -rf kokoro-en-v0_19
|
||||
|
||||
@@ -311,6 +318,7 @@ rm matcha-icefall-en_US-ljspeech.tar.bz2
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/vocoder-models/vocos-22khz-univ.onnx
|
||||
|
||||
node ./test_tts_non_streaming_matcha_icefall_en.js
|
||||
node ./test_tts_non_streaming_matcha_icefall_en_async.js
|
||||
rm vocos-22khz-univ.onnx
|
||||
rm -rf matcha-icefall-en_US-ljspeech
|
||||
|
||||
@@ -320,6 +328,7 @@ rm matcha-icefall-zh-baker.tar.bz2
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/vocoder-models/vocos-22khz-univ.onnx
|
||||
|
||||
node ./test_tts_non_streaming_matcha_icefall_zh.js
|
||||
node ./test_tts_non_streaming_matcha_icefall_zh_async.js
|
||||
rm vocos-22khz-univ.onnx
|
||||
rm -rf matcha-icefall-zh-baker
|
||||
ls -lh *.wav
|
||||
@@ -329,6 +338,7 @@ tar xf vits-piper-en_GB-cori-medium.tar.bz2
|
||||
rm vits-piper-en_GB-cori-medium.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_vits_piper_en.js
|
||||
node ./test_tts_non_streaming_vits_piper_en_async.js
|
||||
rm -rf vits-piper-en_GB-cori-medium
|
||||
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-coqui-de-css10.tar.bz2
|
||||
@@ -336,6 +346,7 @@ tar xvf vits-coqui-de-css10.tar.bz2
|
||||
rm vits-coqui-de-css10.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_vits_coqui_de.js
|
||||
node ./test_tts_non_streaming_vits_coqui_de_async.js
|
||||
rm -rf vits-coqui-de-css10
|
||||
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/sherpa-onnx-vits-zh-ll.tar.bz2
|
||||
@@ -343,6 +354,7 @@ tar xvf sherpa-onnx-vits-zh-ll.tar.bz2
|
||||
rm sherpa-onnx-vits-zh-ll.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_vits_zh_ll.js
|
||||
node ./test_tts_non_streaming_vits_zh_ll_async.js
|
||||
rm -rf sherpa-onnx-vits-zh-ll
|
||||
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-icefall-zh-aishell3.tar.bz2
|
||||
@@ -350,6 +362,7 @@ tar xvf vits-icefall-zh-aishell3.tar.bz2
|
||||
rm vits-icefall-zh-aishell3.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_vits_zh_aishell3.js
|
||||
node ./test_tts_non_streaming_vits_zh_aishell3_async.js
|
||||
rm -rf vits-icefall-zh-aishell3
|
||||
|
||||
echo "----------keyword spotting----------"
|
||||
|
||||
@@ -58,6 +58,7 @@ add_library(sherpa_onnx SHARED
|
||||
version.cc
|
||||
wave-reader.cc
|
||||
wave-writer.cc
|
||||
resampler.cc
|
||||
)
|
||||
|
||||
add_library(sherpa_onnx_c_api SHARED IMPORTED)
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
// scripts/node-addon-api/src/resampler.cc
|
||||
//
|
||||
// Copyright (c) 2026 Xiaomi Corporation
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "macros.h" // NOLINT
|
||||
#include "napi.h" // NOLINT
|
||||
#include "sherpa-onnx/c-api/c-api.h"
|
||||
|
||||
// createLinearResampler(inputSampleRate, outputSampleRate)
|
||||
// Returns an External handle to a SherpaOnnxLinearResampler.
|
||||
static Napi::External<SherpaOnnxLinearResampler> CreateLinearResamplerWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 2) {
|
||||
std::ostringstream os;
|
||||
os << "Expect 2 arguments (inputSampleRate, outputSampleRate). Given: "
|
||||
<< info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsNumber()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a number (inputSampleRate)")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsNumber()) {
|
||||
Napi::TypeError::New(env,
|
||||
"Argument 1 should be a number (outputSampleRate)")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
int32_t input_sample_rate = info[0].As<Napi::Number>().Int32Value();
|
||||
int32_t output_sample_rate = info[1].As<Napi::Number>().Int32Value();
|
||||
|
||||
if (input_sample_rate <= 0 || output_sample_rate <= 0) {
|
||||
Napi::TypeError::New(env,
|
||||
"inputSampleRate and outputSampleRate must be > 0")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const SherpaOnnxLinearResampler *p = SherpaOnnxCreateLinearResampler(
|
||||
input_sample_rate, output_sample_rate, 0, 0);
|
||||
|
||||
return Napi::External<SherpaOnnxLinearResampler>::New(
|
||||
env, const_cast<SherpaOnnxLinearResampler *>(p),
|
||||
[](Napi::Env env, SherpaOnnxLinearResampler *ptr) {
|
||||
SherpaOnnxDestroyLinearResampler(ptr);
|
||||
});
|
||||
}
|
||||
|
||||
// resampleLinear(resamplerHandle, samples, flush)
|
||||
// Returns a Float32Array of resampled samples.
|
||||
// flush should be 1 for the final chunk; 0 otherwise.
|
||||
static Napi::Float32Array ResampleLinearWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 3) {
|
||||
std::ostringstream os;
|
||||
os << "Expect 3 arguments (resampler, samples, flush). Given: "
|
||||
<< info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a resampler handle.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[1].IsTypedArray() ||
|
||||
info[1].As<Napi::TypedArray>().TypedArrayType() != napi_float32_array) {
|
||||
Napi::TypeError::New(env, "Argument 1 should be a Float32Array.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[2].IsNumber()) {
|
||||
Napi::TypeError::New(env, "Argument 2 should be a number (flush: 0 or 1).")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxLinearResampler *p =
|
||||
info[0].As<Napi::External<SherpaOnnxLinearResampler>>().Data();
|
||||
|
||||
Napi::Float32Array samples = info[1].As<Napi::Float32Array>();
|
||||
int32_t input_dim = samples.ElementLength();
|
||||
int32_t flush = info[2].As<Napi::Number>().Int32Value();
|
||||
|
||||
const SherpaOnnxResampleOut *out =
|
||||
SherpaOnnxLinearResamplerResample(p, samples.Data(), input_dim, flush);
|
||||
|
||||
Napi::Float32Array result = Napi::Float32Array::New(env, out->n);
|
||||
std::copy(out->samples, out->samples + out->n, result.Data());
|
||||
|
||||
SherpaOnnxLinearResamplerResampleFree(out);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// linearResamplerReset(resamplerHandle)
|
||||
static void LinearResamplerResetWrapper(const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect 1 argument (resampler). Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a resampler handle.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SherpaOnnxLinearResampler *p =
|
||||
info[0].As<Napi::External<SherpaOnnxLinearResampler>>().Data();
|
||||
|
||||
SherpaOnnxLinearResamplerReset(p);
|
||||
}
|
||||
|
||||
// linearResamplerGetInputSampleRate(resamplerHandle)
|
||||
static Napi::Number LinearResamplerGetInputSampleRateWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect 1 argument (resampler). Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a resampler handle.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxLinearResampler *p =
|
||||
info[0].As<Napi::External<SherpaOnnxLinearResampler>>().Data();
|
||||
|
||||
return Napi::Number::New(
|
||||
env, SherpaOnnxLinearResamplerResampleGetInputSampleRate(p));
|
||||
}
|
||||
|
||||
// linearResamplerGetOutputSampleRate(resamplerHandle)
|
||||
static Napi::Number LinearResamplerGetOutputSampleRateWrapper(
|
||||
const Napi::CallbackInfo &info) {
|
||||
Napi::Env env = info.Env();
|
||||
|
||||
if (info.Length() != 1) {
|
||||
std::ostringstream os;
|
||||
os << "Expect 1 argument (resampler). Given: " << info.Length();
|
||||
|
||||
Napi::TypeError::New(env, os.str()).ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!info[0].IsExternal()) {
|
||||
Napi::TypeError::New(env, "Argument 0 should be a resampler handle.")
|
||||
.ThrowAsJavaScriptException();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
SherpaOnnxLinearResampler *p =
|
||||
info[0].As<Napi::External<SherpaOnnxLinearResampler>>().Data();
|
||||
|
||||
return Napi::Number::New(
|
||||
env, SherpaOnnxLinearResamplerResampleGetOutputSampleRate(p));
|
||||
}
|
||||
|
||||
void InitResampler(Napi::Env env, Napi::Object exports) {
|
||||
exports.Set(Napi::String::New(env, "createLinearResampler"),
|
||||
Napi::Function::New(env, CreateLinearResamplerWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "resampleLinear"),
|
||||
Napi::Function::New(env, ResampleLinearWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "linearResamplerReset"),
|
||||
Napi::Function::New(env, LinearResamplerResetWrapper));
|
||||
|
||||
exports.Set(Napi::String::New(env, "linearResamplerGetInputSampleRate"),
|
||||
Napi::Function::New(env, LinearResamplerGetInputSampleRateWrapper));
|
||||
|
||||
exports.Set(
|
||||
Napi::String::New(env, "linearResamplerGetOutputSampleRate"),
|
||||
Napi::Function::New(env, LinearResamplerGetOutputSampleRateWrapper));
|
||||
}
|
||||
@@ -35,6 +35,8 @@ void InitOnlineSpeechDenoiser(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitVersion(Napi::Env env, Napi::Object exports);
|
||||
|
||||
void InitResampler(Napi::Env env, Napi::Object exports);
|
||||
|
||||
#if __OHOS__
|
||||
void InitUtils(Napi::Env env, Napi::Object exports);
|
||||
#endif
|
||||
@@ -56,6 +58,7 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
||||
InitNonStreamingSpeechDenoiser(env, exports);
|
||||
InitOnlineSpeechDenoiser(env, exports);
|
||||
InitVersion(env, exports);
|
||||
InitResampler(env, exports);
|
||||
|
||||
#if __OHOS__
|
||||
InitUtils(env, exports);
|
||||
|
||||
+145
-44
@@ -174,18 +174,27 @@ The following tables list the examples in this folder.
|
||||
|[./test_tts_non_streaming_zipvoice_zh_en.js](./test_tts_non_streaming_zipvoice_zh_en.js)| Zero-shot text-to-speech with a ZipVoice Chinese/English Model|
|
||||
|[./test_tts_non_streaming_zipvoice_zh_en_async.js](./test_tts_non_streaming_zipvoice_zh_en_async.js)| Zero-shot text-to-speech with a ZipVoice Chinese/English Model using async JS API|
|
||||
|[./test_tts_non_streaming_zipvoice_zh_en_play_async.js](./test_tts_non_streaming_zipvoice_zh_en_play_async.js)| Zero-shot text-to-speech with a ZipVoice Chinese/English Model using async JS API and live audio playback|
|
||||
|[./test_tts_non_streaming_kitten_en.js](./test_tts_non_streaming_kitten_en.js)| Text-to-speech with a KittenTTS English Model|
|
||||
|[./test_tts_non_streaming_kokoro_en.js](./test_tts_non_streaming_kokoro_en.js)| Text-to-speech with a Kokoro English Model|
|
||||
|[./test_tts_non_streaming_kokoro_zh_en.js](./test_tts_non_streaming_kokoro_zh_en.js)| Text-to-speech with a Kokoro Model supporting Chinese and English|
|
||||
|[./test_tts_non_streaming_matcha_icefall_en.js](./test_tts_non_streaming_matcha_icefall_en.js)| Text-to-speech with a [MatchaTTS English Model](https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/matcha.html#matcha-icefall-en-us-ljspeech-american-english-1-female-speaker)|
|
||||
|[./test_tts_non_streaming_matcha_icefall_zh.js](./test_tts_non_streaming_matcha_icefall_zh.js)| Text-to-speech with a [MatchaTTS Chinese Model](https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/matcha.html#matcha-icefall-zh-baker-chinese-1-female-speaker)|
|
||||
|[./test_tts_non_streaming_supertonic_en.js](./test_tts_non_streaming_supertonic_en.js)| Text-to-speech with a Supertonic English Model|
|
||||
|[./test_tts_non_streaming_supertonic_en_async.js](./test_tts_non_streaming_supertonic_en_async.js)| Text-to-speech with a Supertonic English Model using async JS API|
|
||||
|[./test_tts_non_streaming_supertonic_en_play_async.js](./test_tts_non_streaming_supertonic_en_play_async.js)| Text-to-speech with a Supertonic English Model using async JS API and live audio playback|
|
||||
|[./test_tts_non_streaming_vits_piper_en.js](./test_tts_non_streaming_vits_piper_en.js)| Text-to-speech with a [piper](https://github.com/rhasspy/piper) English model|
|
||||
|[./test_tts_non_streaming_vits_coqui_de.js](./test_tts_non_streaming_vits_coqui_de.js)| Text-to-speech with a [coqui](https://github.com/coqui-ai/TTS) German model|
|
||||
|[./test_tts_non_streaming_vits_zh_ll.js](./test_tts_non_streaming_vits_zh_ll.js)| Text-to-speech with a Chinese model using [cppjieba](https://github.com/yanyiwu/cppjieba)|
|
||||
|[./test_tts_non_streaming_vits_zh_aishell3.js](./test_tts_non_streaming_vits_zh_aishell3.js)| Text-to-speech with a Chinese TTS model|
|
||||
|[./test_tts_non_streaming_kitten_en.js](./test_tts_non_streaming_kitten_en.js)| Text-to-speech with a KittenTTS English Model (async API)|
|
||||
|[./test_tts_non_streaming_kitten_en_sync.js](./test_tts_non_streaming_kitten_en_sync.js)| Text-to-speech with a KittenTTS English Model (sync API)|
|
||||
|[./test_tts_non_streaming_kokoro_en.js](./test_tts_non_streaming_kokoro_en.js)| Text-to-speech with a Kokoro English Model (sync API)|
|
||||
|[./test_tts_non_streaming_kokoro_en_async.js](./test_tts_non_streaming_kokoro_en_async.js)| Text-to-speech with a Kokoro English Model (async API)|
|
||||
|[./test_tts_non_streaming_kokoro_zh_en.js](./test_tts_non_streaming_kokoro_zh_en.js)| Text-to-speech with a Kokoro Model supporting Chinese and English (sync API)|
|
||||
|[./test_tts_non_streaming_kokoro_zh_en_async.js](./test_tts_non_streaming_kokoro_zh_en_async.js)| Text-to-speech with a Kokoro Model supporting Chinese and English (async API)|
|
||||
|[./test_tts_non_streaming_matcha_icefall_en.js](./test_tts_non_streaming_matcha_icefall_en.js)| Text-to-speech with a [MatchaTTS English Model](https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/matcha.html#matcha-icefall-en-us-ljspeech-american-english-1-female-speaker) (sync API)|
|
||||
|[./test_tts_non_streaming_matcha_icefall_en_async.js](./test_tts_non_streaming_matcha_icefall_en_async.js)| Text-to-speech with a [MatchaTTS English Model](https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/matcha.html#matcha-icefall-en-us-ljspeech-american-english-1-female-speaker) (async API)|
|
||||
|[./test_tts_non_streaming_matcha_icefall_zh.js](./test_tts_non_streaming_matcha_icefall_zh.js)| Text-to-speech with a [MatchaTTS Chinese Model](https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/matcha.html#matcha-icefall-zh-baker-chinese-1-female-speaker) (sync API)|
|
||||
|[./test_tts_non_streaming_matcha_icefall_zh_async.js](./test_tts_non_streaming_matcha_icefall_zh_async.js)| Text-to-speech with a [MatchaTTS Chinese Model](https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/matcha.html#matcha-icefall-zh-baker-chinese-1-female-speaker) (async API)|
|
||||
|[./test_tts_non_streaming_supertonic_en.js](./test_tts_non_streaming_supertonic_en.js)| Text-to-speech with a Supertonic English Model (sync API)|
|
||||
|[./test_tts_non_streaming_supertonic_en_async.js](./test_tts_non_streaming_supertonic_en_async.js)| Text-to-speech with a Supertonic English Model (async API)|
|
||||
|[./test_tts_non_streaming_supertonic_en_play_async.js](./test_tts_non_streaming_supertonic_en_play_async.js)| Text-to-speech with a Supertonic English Model (async API + live playback)|
|
||||
|[./test_tts_non_streaming_vits_piper_en.js](./test_tts_non_streaming_vits_piper_en.js)| Text-to-speech with a [piper](https://github.com/rhasspy/piper) English model (sync API)|
|
||||
|[./test_tts_non_streaming_vits_piper_en_async.js](./test_tts_non_streaming_vits_piper_en_async.js)| Text-to-speech with a [piper](https://github.com/rhasspy/piper) English model (async API)|
|
||||
|[./test_tts_non_streaming_vits_coqui_de.js](./test_tts_non_streaming_vits_coqui_de.js)| Text-to-speech with a [coqui](https://github.com/coqui-ai/TTS) German model (sync API)|
|
||||
|[./test_tts_non_streaming_vits_coqui_de_async.js](./test_tts_non_streaming_vits_coqui_de_async.js)| Text-to-speech with a [coqui](https://github.com/coqui-ai/TTS) German model (async API)|
|
||||
|[./test_tts_non_streaming_vits_zh_ll.js](./test_tts_non_streaming_vits_zh_ll.js)| Text-to-speech with a Chinese model using [cppjieba](https://github.com/yanyiwu/cppjieba) (sync API)|
|
||||
|[./test_tts_non_streaming_vits_zh_ll_async.js](./test_tts_non_streaming_vits_zh_ll_async.js)| Text-to-speech with a Chinese model using [cppjieba](https://github.com/yanyiwu/cppjieba) (async API)|
|
||||
|[./test_tts_non_streaming_vits_zh_aishell3.js](./test_tts_non_streaming_vits_zh_aishell3.js)| Text-to-speech with a Chinese TTS model (sync API)|
|
||||
|[./test_tts_non_streaming_vits_zh_aishell3_async.js](./test_tts_non_streaming_vits_zh_aishell3_async.js)| Text-to-speech with a Chinese TTS model (async API)|
|
||||
|
||||
|
||||
### Speaker diarization
|
||||
@@ -218,8 +227,8 @@ node ./test_offline_speech_enhancement_gtcrn.js
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/silero_vad.onnx
|
||||
|
||||
|
||||
# To run the test with a microphone, you need to install the package naudiodon2
|
||||
npm install naudiodon2
|
||||
# To run the test with a microphone, you need to install the package node-cpal
|
||||
npm install node-cpal
|
||||
|
||||
node ./test_vad_microphone.js
|
||||
```
|
||||
@@ -279,8 +288,8 @@ rm sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20.tar.bz2
|
||||
|
||||
node ./test_asr_streaming_transducer.js
|
||||
|
||||
# To run the test with a microphone, you need to install the package naudiodon2
|
||||
npm install naudiodon2
|
||||
# To run the test with a microphone, you need to install the package node-cpal
|
||||
npm install node-cpal
|
||||
|
||||
node ./test_asr_streaming_transducer_microphone.js
|
||||
```
|
||||
@@ -297,8 +306,8 @@ node ./test_asr_streaming_ctc.js
|
||||
# To decode with HLG.fst
|
||||
node ./test_asr_streaming_ctc_hlg.js
|
||||
|
||||
# To run the test with a microphone, you need to install the package naudiodon2
|
||||
npm install naudiodon2
|
||||
# To run the test with a microphone, you need to install the package node-cpal
|
||||
npm install node-cpal
|
||||
|
||||
node ./test_asr_streaming_ctc_microphone.js
|
||||
node ./test_asr_streaming_ctc_hlg_microphone.js
|
||||
@@ -313,8 +322,8 @@ rm sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2
|
||||
|
||||
node ./test_asr_streaming_paraformer.js
|
||||
|
||||
# To run the test with a microphone, you need to install the package naudiodon2
|
||||
npm install naudiodon2
|
||||
# To run the test with a microphone, you need to install the package node-cpal
|
||||
npm install node-cpal
|
||||
|
||||
node ./test_asr_streaming_paraformer_microphone.js
|
||||
```
|
||||
@@ -329,7 +338,7 @@ rm sherpa-onnx-zipformer-en-2023-04-01.tar.bz2
|
||||
node ./test_asr_non_streaming_transducer.js
|
||||
|
||||
# To run VAD + non-streaming ASR with transudcer using a microphone
|
||||
npm install naudiodon2
|
||||
npm install node-cpal
|
||||
node ./test_vad_asr_non_streaming_transducer_microphone.js
|
||||
```
|
||||
|
||||
@@ -362,7 +371,7 @@ rm sherpa-onnx-whisper-tiny.en.tar.bz2
|
||||
node ./test_asr_non_streaming_whisper.js
|
||||
|
||||
# To run VAD + non-streaming ASR with Whisper using a microphone
|
||||
npm install naudiodon2
|
||||
npm install node-cpal
|
||||
node ./test_vad_asr_non_streaming_whisper_microphone.js
|
||||
```
|
||||
|
||||
@@ -386,7 +395,7 @@ rm sherpa-onnx-moonshine-tiny-en-int8.tar.bz2
|
||||
node ./test_asr_non_streaming_moonshine.js
|
||||
|
||||
# To run VAD + non-streaming ASR with Moonshine using a microphone
|
||||
npm install naudiodon2
|
||||
npm install node-cpal
|
||||
node ./test_vad_asr_non_streaming_moonshine_microphone.js
|
||||
```
|
||||
|
||||
@@ -447,7 +456,7 @@ rm sherpa-onnx-zipformer-ctc-zh-int8-2025-07-03.tar.bz2
|
||||
node ./test_asr_non_streaming_zipformer_ctc.js
|
||||
|
||||
# To run VAD + non-streaming ASR with Paraformer using a microphone
|
||||
npm install naudiodon2
|
||||
npm install node-cpal
|
||||
node ./test_vad_asr_non_streaming_zipformer_ctc_microphone.js
|
||||
```
|
||||
|
||||
@@ -471,7 +480,7 @@ rm sherpa-onnx-nemo-fast-conformer-ctc-be-de-en-es-fr-hr-it-pl-ru-uk-20k.tar.bz2
|
||||
node ./test_asr_non_streaming_nemo_ctc.js
|
||||
|
||||
# To run VAD + non-streaming ASR with Paraformer using a microphone
|
||||
npm install naudiodon2
|
||||
npm install node-cpal
|
||||
node ./test_vad_asr_non_streaming_nemo_ctc_microphone.js
|
||||
```
|
||||
|
||||
@@ -575,15 +584,15 @@ rm sherpa-onnx-paraformer-zh-2023-09-14.tar.bz2
|
||||
node ./test_asr_non_streaming_paraformer.js
|
||||
|
||||
# To run VAD + non-streaming ASR with Paraformer using a microphone
|
||||
npm install naudiodon2
|
||||
npm install node-cpal
|
||||
node ./test_vad_asr_non_streaming_paraformer_microphone.js
|
||||
```
|
||||
|
||||
### Non-streaming speech recognition with SenseVoice with homophone replacer
|
||||
```bash
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
|
||||
tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
|
||||
rm sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
|
||||
tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
|
||||
rm sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
|
||||
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/hr-files/dict.tar.bz2
|
||||
tar xf dict.tar.bz2
|
||||
@@ -598,14 +607,14 @@ node ./test_asr_non_streaming_sense_voice_with_hr.js
|
||||
### Non-streaming speech recognition with SenseVoice
|
||||
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
|
||||
tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
|
||||
rm sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
|
||||
tar xvf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
|
||||
rm sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2
|
||||
|
||||
node ./test_asr_non_streaming_sense_voice.js
|
||||
|
||||
# To run VAD + non-streaming ASR with Paraformer using a microphone
|
||||
npm install naudiodon2
|
||||
npm install node-cpal
|
||||
node ./test_vad_asr_non_streaming_sense_voice_microphone.js
|
||||
```
|
||||
|
||||
@@ -683,7 +692,7 @@ curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/vocoder-mode
|
||||
node ./test_tts_non_streaming_zipvoice_zh_en.js
|
||||
```
|
||||
|
||||
### Text-to-speech with KittenTTS models (English TTS)
|
||||
### Text-to-speech with KittenTTS models (English TTS, async API)
|
||||
|
||||
```bash
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2
|
||||
@@ -693,6 +702,16 @@ rm kitten-nano-en-v0_1-fp16.tar.bz2
|
||||
node ./test_tts_non_streaming_kitten_en.js
|
||||
```
|
||||
|
||||
### Text-to-speech with KittenTTS models (English TTS, sync API)
|
||||
|
||||
```bash
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2
|
||||
tar xf kitten-nano-en-v0_1-fp16.tar.bz2
|
||||
rm kitten-nano-en-v0_1-fp16.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_kitten_en_sync.js
|
||||
```
|
||||
|
||||
### Text-to-speech with Supertonic TTS models (English TTS, sync API)
|
||||
|
||||
```bash
|
||||
@@ -725,7 +744,7 @@ npm install speaker
|
||||
node ./test_tts_non_streaming_supertonic_en_play_async.js
|
||||
```
|
||||
|
||||
### Text-to-speech with Kokoro TTS models (Chinese + English TTS)
|
||||
### Text-to-speech with Kokoro TTS models (Chinese + English TTS, sync API)
|
||||
|
||||
```bash
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kokoro-multi-lang-v1_0.tar.bz2
|
||||
@@ -735,7 +754,17 @@ rm kokoro-multi-lang-v1_0.tar.bz2
|
||||
node ./test_tts_non_streaming_kokoro_zh_en.js
|
||||
```
|
||||
|
||||
### Text-to-speech with Kokoro TTS models (English TTS)
|
||||
### Text-to-speech with Kokoro TTS models (Chinese + English TTS, async API)
|
||||
|
||||
```bash
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kokoro-multi-lang-v1_0.tar.bz2
|
||||
tar xf kokoro-multi-lang-v1_0.tar.bz2
|
||||
rm kokoro-multi-lang-v1_0.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_kokoro_zh_en_async.js
|
||||
```
|
||||
|
||||
### Text-to-speech with Kokoro TTS models (English TTS, sync API)
|
||||
|
||||
```bash
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kokoro-en-v0_19.tar.bz2
|
||||
@@ -745,7 +774,17 @@ rm kokoro-en-v0_19.tar.bz2
|
||||
node ./test_tts_non_streaming_kokoro_en.js
|
||||
```
|
||||
|
||||
### Text-to-speech with MatchaTTS models (English TTS)
|
||||
### Text-to-speech with Kokoro TTS models (English TTS, async API)
|
||||
|
||||
```bash
|
||||
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kokoro-en-v0_19.tar.bz2
|
||||
tar xf kokoro-en-v0_19.tar.bz2
|
||||
rm kokoro-en-v0_19.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_kokoro_en_async.js
|
||||
```
|
||||
|
||||
### Text-to-speech with MatchaTTS models (English TTS, sync API)
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/matcha-icefall-en_US-ljspeech.tar.bz2
|
||||
tar xf matcha-icefall-en_US-ljspeech.tar.bz2
|
||||
@@ -756,7 +795,18 @@ wget https://github.com/k2-fsa/sherpa-onnx/releases/download/vocoder-models/voco
|
||||
node ./test_tts_non_streaming_matcha_icefall_en.js
|
||||
```
|
||||
|
||||
### Text-to-speech with MatchaTTS models (Chinese TTS)
|
||||
### Text-to-speech with MatchaTTS models (English TTS, async API)
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/matcha-icefall-en_US-ljspeech.tar.bz2
|
||||
tar xf matcha-icefall-en_US-ljspeech.tar.bz2
|
||||
rm matcha-icefall-en_US-ljspeech.tar.bz2
|
||||
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/vocoder-models/vocos-22khz-univ.onnx
|
||||
|
||||
node ./test_tts_non_streaming_matcha_icefall_en_async.js
|
||||
```
|
||||
|
||||
### Text-to-speech with MatchaTTS models (Chinese TTS, sync API)
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/matcha-icefall-zh-baker.tar.bz2
|
||||
tar xvf matcha-icefall-zh-baker.tar.bz2
|
||||
@@ -767,7 +817,18 @@ wget https://github.com/k2-fsa/sherpa-onnx/releases/download/vocoder-models/voco
|
||||
node ./test_tts_non_streaming_matcha_icefall_zh.js
|
||||
```
|
||||
|
||||
### Text-to-speech with piper VITS models (TTS)
|
||||
### Text-to-speech with MatchaTTS models (Chinese TTS, async API)
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/matcha-icefall-zh-baker.tar.bz2
|
||||
tar xvf matcha-icefall-zh-baker.tar.bz2
|
||||
rm matcha-icefall-zh-baker.tar.bz2
|
||||
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/vocoder-models/vocos-22khz-univ.onnx
|
||||
|
||||
node ./test_tts_non_streaming_matcha_icefall_zh_async.js
|
||||
```
|
||||
|
||||
### Text-to-speech with piper VITS models (sync API)
|
||||
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-piper-en_GB-cori-medium.tar.bz2
|
||||
@@ -777,7 +838,17 @@ rm vits-piper-en_GB-cori-medium.tar.bz2
|
||||
node ./test_tts_non_streaming_vits_piper_en.js
|
||||
```
|
||||
|
||||
### Text-to-speech with piper Coqui-ai/TTS models (TTS)
|
||||
### Text-to-speech with piper VITS models (async API)
|
||||
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-piper-en_GB-cori-medium.tar.bz2
|
||||
tar xvf vits-piper-en_GB-cori-medium.tar.bz2
|
||||
rm vits-piper-en_GB-cori-medium.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_vits_piper_en_async.js
|
||||
```
|
||||
|
||||
### Text-to-speech with Coqui-ai/TTS VITS models (German, sync API)
|
||||
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-coqui-de-css10.tar.bz2
|
||||
@@ -787,7 +858,17 @@ rm vits-coqui-de-css10.tar.bz2
|
||||
node ./test_tts_non_streaming_vits_coqui_de.js
|
||||
```
|
||||
|
||||
### Text-to-speech with vits Chinese models (1/2)
|
||||
### Text-to-speech with Coqui-ai/TTS VITS models (German, async API)
|
||||
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-coqui-de-css10.tar.bz2
|
||||
tar xvf vits-coqui-de-css10.tar.bz2
|
||||
rm vits-coqui-de-css10.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_vits_coqui_de_async.js
|
||||
```
|
||||
|
||||
### Text-to-speech with vits Chinese zh-ll models (sync API)
|
||||
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/sherpa-onnx-vits-zh-ll.tar.bz2
|
||||
@@ -797,7 +878,17 @@ rm sherpa-onnx-vits-zh-ll.tar.bz2
|
||||
node ./test_tts_non_streaming_vits_zh_ll.js
|
||||
```
|
||||
|
||||
### Text-to-speech with vits Chinese models (2/2)
|
||||
### Text-to-speech with vits Chinese zh-ll models (async API)
|
||||
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/sherpa-onnx-vits-zh-ll.tar.bz2
|
||||
tar xvf sherpa-onnx-vits-zh-ll.tar.bz2
|
||||
rm sherpa-onnx-vits-zh-ll.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_vits_zh_ll_async.js
|
||||
```
|
||||
|
||||
### Text-to-speech with vits Chinese AiShell3 models (sync API)
|
||||
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-icefall-zh-aishell3.tar.bz2
|
||||
@@ -807,6 +898,16 @@ rm vits-icefall-zh-aishell3.tar.bz2
|
||||
node ./test_tts_non_streaming_vits_zh_aishell3.js
|
||||
```
|
||||
|
||||
### Text-to-speech with vits Chinese AiShell3 models (async API)
|
||||
|
||||
```bash
|
||||
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-icefall-zh-aishell3.tar.bz2
|
||||
tar xvf vits-icefall-zh-aishell3.tar.bz2
|
||||
rm vits-icefall-zh-aishell3.tar.bz2
|
||||
|
||||
node ./test_tts_non_streaming_vits_zh_aishell3_async.js
|
||||
```
|
||||
|
||||
### Spoken language identification with Whisper multi-lingual models
|
||||
|
||||
```bash
|
||||
@@ -821,7 +922,7 @@ rm spoken-language-identification-test-wavs.tar.bz2
|
||||
node ./test_spoken_language_identification.js
|
||||
|
||||
# To run VAD + spoken language identification using a microphone
|
||||
npm install naudiodon2
|
||||
npm install node-cpal
|
||||
node ./test_vad_spoken_language_identification_microphone.js
|
||||
```
|
||||
|
||||
@@ -868,6 +969,6 @@ rm sherpa-onnx-kws-zipformer-wenetspeech-3.3M-2024-01-01.tar.bz2
|
||||
node ./test_keyword_spotter_transducer.js
|
||||
|
||||
# To run keyword spotting using a microphone
|
||||
npm install naudiodon2
|
||||
npm install node-cpal
|
||||
node ./test_keyword_spotter_transducer_microphone.js
|
||||
```
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"node-cpal": "^0.1.1",
|
||||
"sherpa-onnx-node": "^1.13.2"
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,6 @@ const sherpa_onnx = require('sherpa-onnx-node');
|
||||
// the following code
|
||||
//
|
||||
|
||||
// let encoder = new TextEncoder();
|
||||
// let tokens = encoder.encode(
|
||||
// './sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/测试.txt');
|
||||
// let model = encoder.encode(
|
||||
// './sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/测试.int8.onnx');
|
||||
|
||||
|
||||
const config = {
|
||||
'featConfig': {
|
||||
'sampleRate': 16000,
|
||||
@@ -24,11 +17,11 @@ const config = {
|
||||
'modelConfig': {
|
||||
'senseVoice': {
|
||||
'model':
|
||||
'./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/model.int8.onnx',
|
||||
'./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/model.int8.onnx',
|
||||
// 'model': model,
|
||||
'useInverseTextNormalization': 1,
|
||||
},
|
||||
'tokens': './sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/tokens.txt',
|
||||
'tokens': './sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/tokens.txt',
|
||||
// 'tokens': tokens,
|
||||
'numThreads': 2,
|
||||
'provider': 'cpu',
|
||||
@@ -37,7 +30,7 @@ const config = {
|
||||
};
|
||||
|
||||
const waveFilename =
|
||||
'./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/test_wavs/zh.wav';
|
||||
'./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/test_wavs/zh.wav';
|
||||
|
||||
const recognizer = new sherpa_onnx.OfflineRecognizer(config);
|
||||
console.log('Started');
|
||||
|
||||
@@ -10,13 +10,6 @@ const sherpa_onnx = require('sherpa-onnx-node');
|
||||
// the following code
|
||||
//
|
||||
|
||||
// let encoder = new TextEncoder();
|
||||
// let tokens = encoder.encode(
|
||||
// './sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/测试.txt');
|
||||
// let model = encoder.encode(
|
||||
// './sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/测试.int8.onnx');
|
||||
|
||||
|
||||
const config = {
|
||||
'featConfig': {
|
||||
'sampleRate': 16000,
|
||||
@@ -25,11 +18,11 @@ const config = {
|
||||
'modelConfig': {
|
||||
'senseVoice': {
|
||||
'model':
|
||||
'./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/model.int8.onnx',
|
||||
'./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/model.int8.onnx',
|
||||
// 'model': model,
|
||||
'useInverseTextNormalization': 1,
|
||||
},
|
||||
'tokens': './sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/tokens.txt',
|
||||
'tokens': './sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/tokens.txt',
|
||||
// 'tokens': tokens,
|
||||
'numThreads': 2,
|
||||
'provider': 'cpu',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -40,44 +40,45 @@ const stream = recognizer.createStream();
|
||||
let lastText = '';
|
||||
let segmentIndex = 0;
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = recognizer.config.featConfig.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
const display = new sherpa_onnx.Display(50);
|
||||
|
||||
ai.on('data', data => {
|
||||
const samples = new Float32Array(data.buffer);
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: targetSampleRate, samples: resampled});
|
||||
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: recognizer.config.featConfig.sampleRate, samples: samples});
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
const isEndpoint = recognizer.isEndpoint(stream);
|
||||
const text = recognizer.getResult(stream).text.toLowerCase();
|
||||
|
||||
const isEndpoint = recognizer.isEndpoint(stream);
|
||||
const text = recognizer.getResult(stream).text.toLowerCase();
|
||||
if (text.length > 0 && lastText != text) {
|
||||
lastText = text;
|
||||
display.print(segmentIndex, lastText);
|
||||
}
|
||||
if (isEndpoint) {
|
||||
if (text.length > 0) {
|
||||
lastText = text;
|
||||
segmentIndex += 1;
|
||||
}
|
||||
recognizer.reset(stream);
|
||||
}
|
||||
});
|
||||
|
||||
if (text.length > 0 && lastText != text) {
|
||||
lastText = text;
|
||||
display.print(segmentIndex, lastText);
|
||||
}
|
||||
if (isEndpoint) {
|
||||
if (text.length > 0) {
|
||||
lastText = text;
|
||||
segmentIndex += 1;
|
||||
}
|
||||
recognizer.reset(stream);
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -39,45 +39,45 @@ const stream = recognizer.createStream();
|
||||
let lastText = '';
|
||||
let segmentIndex = 0;
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = recognizer.config.featConfig.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
const display = new sherpa_onnx.Display(50);
|
||||
|
||||
ai.on('data', data => {
|
||||
const samples = new Float32Array(data.buffer);
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: targetSampleRate, samples: resampled});
|
||||
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: recognizer.config.featConfig.sampleRate, samples: samples});
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
const isEndpoint = recognizer.isEndpoint(stream);
|
||||
const text = recognizer.getResult(stream).text.toLowerCase();
|
||||
|
||||
const isEndpoint = recognizer.isEndpoint(stream);
|
||||
const text = recognizer.getResult(stream).text.toLowerCase();
|
||||
if (text.length > 0 && lastText != text) {
|
||||
lastText = text;
|
||||
display.print(segmentIndex, lastText);
|
||||
}
|
||||
if (isEndpoint) {
|
||||
if (text.length > 0) {
|
||||
lastText = text;
|
||||
segmentIndex += 1;
|
||||
}
|
||||
recognizer.reset(stream);
|
||||
}
|
||||
});
|
||||
|
||||
if (text.length > 0 && lastText != text) {
|
||||
lastText = text;
|
||||
display.print(segmentIndex, lastText);
|
||||
}
|
||||
if (isEndpoint) {
|
||||
if (text.length > 0) {
|
||||
lastText = text;
|
||||
segmentIndex += 1;
|
||||
}
|
||||
recognizer.reset(stream);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -40,59 +40,60 @@ const stream = recognizer.createStream();
|
||||
let lastText = '';
|
||||
let segmentIndex = 0;
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = recognizer.config.featConfig.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
const display = new sherpa_onnx.Display(50);
|
||||
|
||||
ai.on('data', data => {
|
||||
const samples = new Float32Array(data.buffer);
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: targetSampleRate, samples: resampled});
|
||||
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: recognizer.config.featConfig.sampleRate, samples: samples});
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
const isEndpoint = recognizer.isEndpoint(stream);
|
||||
let text = recognizer.getResult(stream).text.toLowerCase();
|
||||
|
||||
const isEndpoint = recognizer.isEndpoint(stream);
|
||||
let text = recognizer.getResult(stream).text.toLowerCase();
|
||||
if (isEndpoint) {
|
||||
// for online paraformer models, we have to manually padding on endpoint
|
||||
// so that the last word can be recognized
|
||||
const tailPadding =
|
||||
new Float32Array(targetSampleRate * 0.4);
|
||||
stream.acceptWaveform({
|
||||
samples: tailPadding,
|
||||
sampleRate: targetSampleRate
|
||||
});
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
text = recognizer.getResult(stream).text.toLowerCase();
|
||||
}
|
||||
|
||||
if (isEndpoint) {
|
||||
// for online paraformer models, we have to manually padding on endpoint
|
||||
// so that the last word can be recognized
|
||||
const tailPadding =
|
||||
new Float32Array(recognizer.config.featConfig.sampleRate * 0.4);
|
||||
stream.acceptWaveform({
|
||||
samples: tailPadding,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
if (text.length > 0 && lastText != text) {
|
||||
lastText = text;
|
||||
display.print(segmentIndex, lastText);
|
||||
}
|
||||
if (isEndpoint) {
|
||||
if (text.length > 0) {
|
||||
lastText = text;
|
||||
segmentIndex += 1;
|
||||
}
|
||||
recognizer.reset(stream);
|
||||
}
|
||||
});
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
text = recognizer.getResult(stream).text.toLowerCase();
|
||||
}
|
||||
|
||||
if (text.length > 0 && lastText != text) {
|
||||
lastText = text;
|
||||
display.print(segmentIndex, lastText);
|
||||
}
|
||||
if (isEndpoint) {
|
||||
if (text.length > 0) {
|
||||
lastText = text;
|
||||
segmentIndex += 1;
|
||||
}
|
||||
recognizer.reset(stream);
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -43,44 +43,45 @@ const stream = recognizer.createStream();
|
||||
let lastText = '';
|
||||
let segmentIndex = 0;
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = recognizer.config.featConfig.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
const display = new sherpa_onnx.Display(50);
|
||||
|
||||
ai.on('data', data => {
|
||||
const samples = new Float32Array(data.buffer);
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: targetSampleRate, samples: resampled});
|
||||
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: recognizer.config.featConfig.sampleRate, samples: samples});
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
const isEndpoint = recognizer.isEndpoint(stream);
|
||||
const text = recognizer.getResult(stream).text.toLowerCase();
|
||||
|
||||
const isEndpoint = recognizer.isEndpoint(stream);
|
||||
const text = recognizer.getResult(stream).text.toLowerCase();
|
||||
if (text.length > 0 && lastText != text) {
|
||||
lastText = text;
|
||||
display.print(segmentIndex, lastText);
|
||||
}
|
||||
if (isEndpoint) {
|
||||
if (text.length > 0) {
|
||||
lastText = text;
|
||||
segmentIndex += 1;
|
||||
}
|
||||
recognizer.reset(stream);
|
||||
}
|
||||
});
|
||||
|
||||
if (text.length > 0 && lastText != text) {
|
||||
lastText = text;
|
||||
display.print(segmentIndex, lastText);
|
||||
}
|
||||
if (isEndpoint) {
|
||||
if (text.length > 0) {
|
||||
lastText = text;
|
||||
segmentIndex += 1;
|
||||
}
|
||||
recognizer.reset(stream);
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -45,44 +45,45 @@ const stream = recognizer.createStream();
|
||||
let lastText = '';
|
||||
let segmentIndex = 0;
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = recognizer.config.featConfig.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
const display = new sherpa_onnx.Display(50);
|
||||
|
||||
ai.on('data', data => {
|
||||
const samples = new Float32Array(data.buffer);
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: targetSampleRate, samples: resampled});
|
||||
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: recognizer.config.featConfig.sampleRate, samples: samples});
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
|
||||
while (recognizer.isReady(stream)) {
|
||||
recognizer.decode(stream);
|
||||
}
|
||||
const isEndpoint = recognizer.isEndpoint(stream);
|
||||
const text = recognizer.getResult(stream).text.toLowerCase();
|
||||
|
||||
const isEndpoint = recognizer.isEndpoint(stream);
|
||||
const text = recognizer.getResult(stream).text.toLowerCase();
|
||||
if (text.length > 0 && lastText != text) {
|
||||
lastText = text;
|
||||
display.print(segmentIndex, lastText);
|
||||
}
|
||||
if (isEndpoint) {
|
||||
if (text.length > 0) {
|
||||
lastText = text;
|
||||
segmentIndex += 1;
|
||||
}
|
||||
recognizer.reset(stream);
|
||||
}
|
||||
});
|
||||
|
||||
if (text.length > 0 && lastText != text) {
|
||||
lastText = text;
|
||||
display.print(segmentIndex, lastText);
|
||||
}
|
||||
if (isEndpoint) {
|
||||
if (text.length > 0) {
|
||||
lastText = text;
|
||||
segmentIndex += 1;
|
||||
}
|
||||
recognizer.reset(stream);
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -39,36 +39,37 @@ const stream = kws.createStream();
|
||||
let lastText = '';
|
||||
let segmentIndex = 0;
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: kws.config.featConfig.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = kws.config.featConfig.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
const display = new sherpa_onnx.Display(50);
|
||||
|
||||
ai.on('data', data => {
|
||||
const samples = new Float32Array(data.buffer);
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: targetSampleRate, samples: resampled});
|
||||
|
||||
stream.acceptWaveform(
|
||||
{sampleRate: kws.config.featConfig.sampleRate, samples: samples});
|
||||
while (kws.isReady(stream)) {
|
||||
kws.decode(stream);
|
||||
}
|
||||
|
||||
while (kws.isReady(stream)) {
|
||||
kws.decode(stream);
|
||||
}
|
||||
const keyword = kws.getResult(stream).keyword;
|
||||
if (keyword != '') {
|
||||
display.print(segmentIndex, keyword);
|
||||
segmentIndex += 1;
|
||||
}
|
||||
});
|
||||
|
||||
const keyword = kws.getResult(stream).keyword;
|
||||
if (keyword != '') {
|
||||
display.print(segmentIndex, keyword);
|
||||
segmentIndex += 1;
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak.');
|
||||
console.log(`Only words from ${kws.config.keywordsFile} can be recognized`);
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2026 Xiaomi Corporation
|
||||
//
|
||||
// Synchronous text-to-speech with the Kitten model.
|
||||
//
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
function createOfflineTts() {
|
||||
const config = {
|
||||
model: {
|
||||
kitten: {
|
||||
model: './kitten-nano-en-v0_1-fp16/model.fp16.onnx',
|
||||
voices: './kitten-nano-en-v0_1-fp16/voices.bin',
|
||||
tokens: './kitten-nano-en-v0_1-fp16/tokens.txt',
|
||||
dataDir: './kitten-nano-en-v0_1-fp16/espeak-ng-data',
|
||||
},
|
||||
debug: true,
|
||||
numThreads: 1,
|
||||
provider: 'cpu',
|
||||
},
|
||||
maxNumSentences: 1,
|
||||
};
|
||||
return new sherpa_onnx.OfflineTts(config);
|
||||
}
|
||||
|
||||
const tts = createOfflineTts();
|
||||
|
||||
const text =
|
||||
'Today as always, men fall into two groups: slaves and free men. Whoever does not have two-thirds of his day for himself, is a slave, whatever he may be: a statesman, a businessman, an official, or a scholar.';
|
||||
|
||||
const generationConfig = new sherpa_onnx.GenerationConfig({
|
||||
sid: 6,
|
||||
speed: 1.0,
|
||||
silenceScale: 0.2,
|
||||
});
|
||||
|
||||
let start = Date.now();
|
||||
const audio = tts.generate({text, generationConfig});
|
||||
let stop = Date.now();
|
||||
const elapsed_seconds = (stop - start) / 1000;
|
||||
const duration = audio.samples.length / audio.sampleRate;
|
||||
const real_time_factor = elapsed_seconds / duration;
|
||||
console.log('Wave duration', duration.toFixed(3), 'seconds');
|
||||
console.log('Elapsed', elapsed_seconds.toFixed(3), 'seconds');
|
||||
console.log(
|
||||
`RTF = ${elapsed_seconds.toFixed(3)}/${duration.toFixed(3)} =`,
|
||||
real_time_factor.toFixed(3));
|
||||
|
||||
const filename = 'test-kitten-en-sync.wav';
|
||||
sherpa_onnx.writeWave(
|
||||
filename, {samples: audio.samples, sampleRate: audio.sampleRate});
|
||||
|
||||
console.log(`Saved to ${filename}`);
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2026 Xiaomi Corporation
|
||||
//
|
||||
// Asynchronous text-to-speech with the Kokoro English model.
|
||||
//
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
async function createOfflineTts() {
|
||||
const config = {
|
||||
model: {
|
||||
kokoro: {
|
||||
model: './kokoro-en-v0_19/model.onnx',
|
||||
voices: './kokoro-en-v0_19/voices.bin',
|
||||
tokens: './kokoro-en-v0_19/tokens.txt',
|
||||
dataDir: './kokoro-en-v0_19/espeak-ng-data',
|
||||
},
|
||||
debug: false,
|
||||
numThreads: 1,
|
||||
provider: 'cpu',
|
||||
},
|
||||
maxNumSentences: 1,
|
||||
};
|
||||
return await sherpa_onnx.OfflineTts.createAsync(config);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const tts = await createOfflineTts();
|
||||
|
||||
const text =
|
||||
'Today as always, men fall into two groups: slaves and free men. Whoever does not have two-thirds of his day for himself, is a slave, whatever he may be: a statesman, a businessman, an official, or a scholar.';
|
||||
|
||||
const generationConfig = new sherpa_onnx.GenerationConfig({
|
||||
sid: 6,
|
||||
speed: 1.0,
|
||||
silenceScale: 0.2,
|
||||
});
|
||||
|
||||
const start = Date.now();
|
||||
const audio = await tts.generateAsync({
|
||||
text,
|
||||
enableExternalBuffer: true,
|
||||
generationConfig,
|
||||
onProgress: ({samples, progress}) => {
|
||||
process.stdout.write(
|
||||
`Progress: ${(progress * 100).toFixed(1)}%, ` +
|
||||
`Samples: ${samples.length}\r`);
|
||||
return 1;
|
||||
},
|
||||
});
|
||||
|
||||
console.log('');
|
||||
const stop = Date.now();
|
||||
const elapsed_seconds = (stop - start) / 1000;
|
||||
const duration = audio.samples.length / audio.sampleRate;
|
||||
const real_time_factor = elapsed_seconds / duration;
|
||||
console.log('Wave duration', duration.toFixed(3), 'seconds');
|
||||
console.log('Elapsed', elapsed_seconds.toFixed(3), 'seconds');
|
||||
console.log(
|
||||
`RTF = ${elapsed_seconds.toFixed(3)}/${duration.toFixed(3)} =`,
|
||||
real_time_factor.toFixed(3));
|
||||
|
||||
const filename = 'test-kokoro-en-async.wav';
|
||||
sherpa_onnx.writeWave(
|
||||
filename, {samples: audio.samples, sampleRate: audio.sampleRate});
|
||||
console.log(`Saved to ${filename}`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2026 Xiaomi Corporation
|
||||
//
|
||||
// Asynchronous text-to-speech with the Kokoro Chinese+English model.
|
||||
//
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
async function createOfflineTts() {
|
||||
const config = {
|
||||
model: {
|
||||
kokoro: {
|
||||
model: './kokoro-multi-lang-v1_0/model.onnx',
|
||||
voices: './kokoro-multi-lang-v1_0/voices.bin',
|
||||
tokens: './kokoro-multi-lang-v1_0/tokens.txt',
|
||||
dataDir: './kokoro-multi-lang-v1_0/espeak-ng-data',
|
||||
lexicon:
|
||||
'./kokoro-multi-lang-v1_0/lexicon-us-en.txt,./kokoro-multi-lang-v1_0/lexicon-zh.txt',
|
||||
},
|
||||
debug: false,
|
||||
numThreads: 1,
|
||||
provider: 'cpu',
|
||||
},
|
||||
maxNumSentences: 1,
|
||||
};
|
||||
return await sherpa_onnx.OfflineTts.createAsync(config);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const tts = await createOfflineTts();
|
||||
|
||||
const text =
|
||||
'中英文语音合成测试。This is generated by next generation Kaldi using Kokoro without Misaki. 你觉得中英文说的如何呢?';
|
||||
|
||||
const generationConfig = new sherpa_onnx.GenerationConfig({
|
||||
sid: 48,
|
||||
speed: 1.0,
|
||||
silenceScale: 0.2,
|
||||
});
|
||||
|
||||
const start = Date.now();
|
||||
const audio = await tts.generateAsync({
|
||||
text,
|
||||
enableExternalBuffer: true,
|
||||
generationConfig,
|
||||
onProgress: ({samples, progress}) => {
|
||||
process.stdout.write(
|
||||
`Progress: ${(progress * 100).toFixed(1)}%, ` +
|
||||
`Samples: ${samples.length}\r`);
|
||||
return 1;
|
||||
},
|
||||
});
|
||||
|
||||
console.log('');
|
||||
const stop = Date.now();
|
||||
const elapsed_seconds = (stop - start) / 1000;
|
||||
const duration = audio.samples.length / audio.sampleRate;
|
||||
const real_time_factor = elapsed_seconds / duration;
|
||||
console.log('Wave duration', duration.toFixed(3), 'seconds');
|
||||
console.log('Elapsed', elapsed_seconds.toFixed(3), 'seconds');
|
||||
console.log(
|
||||
`RTF = ${elapsed_seconds.toFixed(3)}/${duration.toFixed(3)} =`,
|
||||
real_time_factor.toFixed(3));
|
||||
|
||||
const filename = 'test-kokoro-zh-en-async.wav';
|
||||
sherpa_onnx.writeWave(
|
||||
filename, {samples: audio.samples, sampleRate: audio.sampleRate});
|
||||
console.log(`Saved to ${filename}`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2026 Xiaomi Corporation
|
||||
//
|
||||
// Asynchronous text-to-speech with the Matcha English model.
|
||||
//
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
async function createOfflineTts() {
|
||||
const config = {
|
||||
model: {
|
||||
matcha: {
|
||||
acousticModel: './matcha-icefall-en_US-ljspeech/model-steps-3.onnx',
|
||||
vocoder: './vocos-22khz-univ.onnx',
|
||||
tokens: './matcha-icefall-en_US-ljspeech/tokens.txt',
|
||||
dataDir: './matcha-icefall-en_US-ljspeech/espeak-ng-data',
|
||||
},
|
||||
debug: false,
|
||||
numThreads: 1,
|
||||
provider: 'cpu',
|
||||
},
|
||||
maxNumSentences: 1,
|
||||
};
|
||||
return await sherpa_onnx.OfflineTts.createAsync(config);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const tts = await createOfflineTts();
|
||||
|
||||
const text =
|
||||
'Today as always, men fall into two groups: slaves and free men. Whoever does not have two-thirds of his day for himself, is a slave, whatever he may be: a statesman, a businessman, an official, or a scholar.';
|
||||
|
||||
const generationConfig = new sherpa_onnx.GenerationConfig({
|
||||
sid: 0,
|
||||
speed: 1.0,
|
||||
silenceScale: 0.2,
|
||||
});
|
||||
|
||||
const start = Date.now();
|
||||
const audio = await tts.generateAsync({
|
||||
text,
|
||||
enableExternalBuffer: true,
|
||||
generationConfig,
|
||||
onProgress: ({samples, progress}) => {
|
||||
process.stdout.write(
|
||||
`Progress: ${(progress * 100).toFixed(1)}%, ` +
|
||||
`Samples: ${samples.length}\r`);
|
||||
return 1;
|
||||
},
|
||||
});
|
||||
|
||||
console.log('');
|
||||
const stop = Date.now();
|
||||
const elapsed_seconds = (stop - start) / 1000;
|
||||
const duration = audio.samples.length / audio.sampleRate;
|
||||
const real_time_factor = elapsed_seconds / duration;
|
||||
console.log('Wave duration', duration.toFixed(3), 'seconds');
|
||||
console.log('Elapsed', elapsed_seconds.toFixed(3), 'seconds');
|
||||
console.log(
|
||||
`RTF = ${elapsed_seconds.toFixed(3)}/${duration.toFixed(3)} =`,
|
||||
real_time_factor.toFixed(3));
|
||||
|
||||
const filename = 'test-matcha-en-async.wav';
|
||||
sherpa_onnx.writeWave(
|
||||
filename, {samples: audio.samples, sampleRate: audio.sampleRate});
|
||||
console.log(`Saved to ${filename}`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2026 Xiaomi Corporation
|
||||
//
|
||||
// Asynchronous text-to-speech with the Matcha Chinese model.
|
||||
//
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
async function createOfflineTts() {
|
||||
const config = {
|
||||
model: {
|
||||
matcha: {
|
||||
acousticModel: './matcha-icefall-zh-baker/model-steps-3.onnx',
|
||||
vocoder: './vocos-22khz-univ.onnx',
|
||||
lexicon: './matcha-icefall-zh-baker/lexicon.txt',
|
||||
tokens: './matcha-icefall-zh-baker/tokens.txt',
|
||||
},
|
||||
debug: false,
|
||||
numThreads: 1,
|
||||
provider: 'cpu',
|
||||
},
|
||||
maxNumSentences: 1,
|
||||
ruleFsts:
|
||||
'./matcha-icefall-zh-baker/phone.fst,./matcha-icefall-zh-baker/date.fst,./matcha-icefall-zh-baker/number.fst',
|
||||
};
|
||||
return await sherpa_onnx.OfflineTts.createAsync(config);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const tts = await createOfflineTts();
|
||||
|
||||
const text =
|
||||
'当夜幕降临,星光点点,伴随着微风拂面,我在静谧中感受着时光的流转,思念如涟漪荡漾,梦境如画卷展开,我与自然融为一体,沉静在这片宁静的美丽之中,感受着生命的奇迹与温柔. 某某银行的副行长和一些行政领导表示,他们去过长江和长白山; 经济不断增长。2024年12月31号,拨打110或者18920240511。123456块钱。';
|
||||
|
||||
const generationConfig = new sherpa_onnx.GenerationConfig({
|
||||
sid: 0,
|
||||
speed: 1.0,
|
||||
silenceScale: 0.2,
|
||||
});
|
||||
|
||||
const start = Date.now();
|
||||
const audio = await tts.generateAsync({
|
||||
text,
|
||||
enableExternalBuffer: true,
|
||||
generationConfig,
|
||||
onProgress: ({samples, progress}) => {
|
||||
process.stdout.write(
|
||||
`Progress: ${(progress * 100).toFixed(1)}%, ` +
|
||||
`Samples: ${samples.length}\r`);
|
||||
return 1;
|
||||
},
|
||||
});
|
||||
|
||||
console.log('');
|
||||
const stop = Date.now();
|
||||
const elapsed_seconds = (stop - start) / 1000;
|
||||
const duration = audio.samples.length / audio.sampleRate;
|
||||
const real_time_factor = elapsed_seconds / duration;
|
||||
console.log('Wave duration', duration.toFixed(3), 'seconds');
|
||||
console.log('Elapsed', elapsed_seconds.toFixed(3), 'seconds');
|
||||
console.log(
|
||||
`RTF = ${elapsed_seconds.toFixed(3)}/${duration.toFixed(3)} =`,
|
||||
real_time_factor.toFixed(3));
|
||||
|
||||
const filename = 'test-matcha-zh-async.wav';
|
||||
sherpa_onnx.writeWave(
|
||||
filename, {samples: audio.samples, sampleRate: audio.sampleRate});
|
||||
console.log(`Saved to ${filename}`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -102,4 +102,5 @@ async function main() {
|
||||
// Run the async main
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -138,4 +138,5 @@ async function main() {
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -99,4 +99,5 @@ async function main() {
|
||||
// Run the async main
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -135,4 +135,5 @@ async function main() {
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2026 Xiaomi Corporation
|
||||
//
|
||||
// Asynchronous text-to-speech with the VITS Coqui German model.
|
||||
//
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
async function createOfflineTts() {
|
||||
const config = {
|
||||
model: {
|
||||
vits: {
|
||||
model: './vits-coqui-de-css10/model.onnx',
|
||||
tokens: './vits-coqui-de-css10/tokens.txt',
|
||||
},
|
||||
debug: false,
|
||||
numThreads: 1,
|
||||
provider: 'cpu',
|
||||
},
|
||||
maxNumSentences: 1,
|
||||
};
|
||||
return await sherpa_onnx.OfflineTts.createAsync(config);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const tts = await createOfflineTts();
|
||||
|
||||
const text = 'Alles hat ein Ende, nur die Wurst hat zwei.';
|
||||
|
||||
const generationConfig = new sherpa_onnx.GenerationConfig({
|
||||
sid: 0,
|
||||
speed: 1.0,
|
||||
silenceScale: 0.2,
|
||||
});
|
||||
|
||||
const start = Date.now();
|
||||
const audio = await tts.generateAsync({
|
||||
text,
|
||||
enableExternalBuffer: true,
|
||||
generationConfig,
|
||||
onProgress: ({samples, progress}) => {
|
||||
process.stdout.write(
|
||||
`Progress: ${(progress * 100).toFixed(1)}%, ` +
|
||||
`Samples: ${samples.length}\r`);
|
||||
return 1;
|
||||
},
|
||||
});
|
||||
|
||||
console.log('');
|
||||
const stop = Date.now();
|
||||
const elapsed_seconds = (stop - start) / 1000;
|
||||
const duration = audio.samples.length / audio.sampleRate;
|
||||
const real_time_factor = elapsed_seconds / duration;
|
||||
console.log('Wave duration', duration.toFixed(3), 'seconds');
|
||||
console.log('Elapsed', elapsed_seconds.toFixed(3), 'seconds');
|
||||
console.log(
|
||||
`RTF = ${elapsed_seconds.toFixed(3)}/${duration.toFixed(3)} =`,
|
||||
real_time_factor.toFixed(3));
|
||||
|
||||
const filename = 'test-vits-coqui-de-async.wav';
|
||||
sherpa_onnx.writeWave(
|
||||
filename, {samples: audio.samples, sampleRate: audio.sampleRate});
|
||||
console.log(`Saved to ${filename}`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2026 Xiaomi Corporation
|
||||
//
|
||||
// Asynchronous text-to-speech with the VITS Piper English model.
|
||||
//
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
async function createOfflineTts() {
|
||||
const config = {
|
||||
model: {
|
||||
vits: {
|
||||
model: './vits-piper-en_GB-cori-medium/en_GB-cori-medium.onnx',
|
||||
tokens: './vits-piper-en_GB-cori-medium/tokens.txt',
|
||||
dataDir: './vits-piper-en_GB-cori-medium/espeak-ng-data',
|
||||
},
|
||||
debug: false,
|
||||
numThreads: 1,
|
||||
provider: 'cpu',
|
||||
},
|
||||
maxNumSentences: 1,
|
||||
};
|
||||
return await sherpa_onnx.OfflineTts.createAsync(config);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const tts = await createOfflineTts();
|
||||
|
||||
const text =
|
||||
'Today as always, men fall into two groups: slaves and free men. Whoever does not have two-thirds of his day for himself, is a slave, whatever he may be: a statesman, a businessman, an official, or a scholar.';
|
||||
|
||||
const generationConfig = new sherpa_onnx.GenerationConfig({
|
||||
sid: 0,
|
||||
speed: 1.0,
|
||||
silenceScale: 0.2,
|
||||
});
|
||||
|
||||
const start = Date.now();
|
||||
const audio = await tts.generateAsync({
|
||||
text,
|
||||
enableExternalBuffer: true,
|
||||
generationConfig,
|
||||
onProgress: ({samples, progress}) => {
|
||||
process.stdout.write(
|
||||
`Progress: ${(progress * 100).toFixed(1)}%, ` +
|
||||
`Samples: ${samples.length}\r`);
|
||||
return 1;
|
||||
},
|
||||
});
|
||||
|
||||
console.log('');
|
||||
const stop = Date.now();
|
||||
const elapsed_seconds = (stop - start) / 1000;
|
||||
const duration = audio.samples.length / audio.sampleRate;
|
||||
const real_time_factor = elapsed_seconds / duration;
|
||||
console.log('Wave duration', duration.toFixed(3), 'seconds');
|
||||
console.log('Elapsed', elapsed_seconds.toFixed(3), 'seconds');
|
||||
console.log(
|
||||
`RTF = ${elapsed_seconds.toFixed(3)}/${duration.toFixed(3)} =`,
|
||||
real_time_factor.toFixed(3));
|
||||
|
||||
const filename = 'test-vits-piper-en-async.wav';
|
||||
sherpa_onnx.writeWave(
|
||||
filename, {samples: audio.samples, sampleRate: audio.sampleRate});
|
||||
console.log(`Saved to ${filename}`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2026 Xiaomi Corporation
|
||||
//
|
||||
// Asynchronous text-to-speech with the VITS Chinese (AiShell3) model.
|
||||
//
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
async function createOfflineTts() {
|
||||
const config = {
|
||||
model: {
|
||||
vits: {
|
||||
model: './vits-icefall-zh-aishell3/model.onnx',
|
||||
tokens: './vits-icefall-zh-aishell3/tokens.txt',
|
||||
lexicon: './vits-icefall-zh-aishell3/lexicon.txt',
|
||||
},
|
||||
debug: false,
|
||||
numThreads: 1,
|
||||
provider: 'cpu',
|
||||
},
|
||||
maxNumSentences: 1,
|
||||
ruleFsts:
|
||||
'./vits-icefall-zh-aishell3/date.fst,./vits-icefall-zh-aishell3/phone.fst,./vits-icefall-zh-aishell3/number.fst,./vits-icefall-zh-aishell3/new_heteronym.fst',
|
||||
ruleFars: './vits-icefall-zh-aishell3/rule.far',
|
||||
};
|
||||
return await sherpa_onnx.OfflineTts.createAsync(config);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const tts = await createOfflineTts();
|
||||
|
||||
const text =
|
||||
'他在长沙出生,长白山长大,去过长江,现在他是一个银行的行长,主管行政工作。有困难,请拨110,或者13020240513。今天是2024年5月13号, 他上个月的工资是12345块钱。';
|
||||
|
||||
const generationConfig = new sherpa_onnx.GenerationConfig({
|
||||
sid: 88,
|
||||
speed: 1.0,
|
||||
silenceScale: 0.2,
|
||||
});
|
||||
|
||||
const start = Date.now();
|
||||
const audio = await tts.generateAsync({
|
||||
text,
|
||||
enableExternalBuffer: true,
|
||||
generationConfig,
|
||||
onProgress: ({samples, progress}) => {
|
||||
process.stdout.write(
|
||||
`Progress: ${(progress * 100).toFixed(1)}%, ` +
|
||||
`Samples: ${samples.length}\r`);
|
||||
return 1;
|
||||
},
|
||||
});
|
||||
|
||||
console.log('');
|
||||
const stop = Date.now();
|
||||
const elapsed_seconds = (stop - start) / 1000;
|
||||
const duration = audio.samples.length / audio.sampleRate;
|
||||
const real_time_factor = elapsed_seconds / duration;
|
||||
console.log('Wave duration', duration.toFixed(3), 'seconds');
|
||||
console.log('Elapsed', elapsed_seconds.toFixed(3), 'seconds');
|
||||
console.log(
|
||||
`RTF = ${elapsed_seconds.toFixed(3)}/${duration.toFixed(3)} =`,
|
||||
real_time_factor.toFixed(3));
|
||||
|
||||
const filename = 'test-vits-zh-aishell3-async.wav';
|
||||
sherpa_onnx.writeWave(
|
||||
filename, {samples: audio.samples, sampleRate: audio.sampleRate});
|
||||
console.log(`Saved to ${filename}`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2026 Xiaomi Corporation
|
||||
//
|
||||
// Asynchronous text-to-speech with the VITS Chinese (zh-ll) model.
|
||||
//
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
async function createOfflineTts() {
|
||||
const config = {
|
||||
model: {
|
||||
vits: {
|
||||
model: './sherpa-onnx-vits-zh-ll/model.onnx',
|
||||
tokens: './sherpa-onnx-vits-zh-ll/tokens.txt',
|
||||
lexicon: './sherpa-onnx-vits-zh-ll/lexicon.txt',
|
||||
},
|
||||
debug: false,
|
||||
numThreads: 1,
|
||||
provider: 'cpu',
|
||||
},
|
||||
maxNumSentences: 1,
|
||||
ruleFsts:
|
||||
'./sherpa-onnx-vits-zh-ll/date.fst,./sherpa-onnx-vits-zh-ll/phone.fst,./sherpa-onnx-vits-zh-ll/number.fst',
|
||||
};
|
||||
return await sherpa_onnx.OfflineTts.createAsync(config);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const tts = await createOfflineTts();
|
||||
|
||||
const text =
|
||||
'当夜幕降临,星光点点,伴随着微风拂面,我在静谧中感受着时光的流转,思念如涟漪荡漾,梦境如画卷展开,我与自然融为一体,沉静在这片宁静的美丽之中,感受着生命的奇迹与温柔。2024年5月13号,拨打110或者18920240513。123456块钱。';
|
||||
|
||||
const generationConfig = new sherpa_onnx.GenerationConfig({
|
||||
sid: 2,
|
||||
speed: 1.0,
|
||||
silenceScale: 0.2,
|
||||
});
|
||||
|
||||
const start = Date.now();
|
||||
const audio = await tts.generateAsync({
|
||||
text,
|
||||
enableExternalBuffer: true,
|
||||
generationConfig,
|
||||
onProgress: ({samples, progress}) => {
|
||||
process.stdout.write(
|
||||
`Progress: ${(progress * 100).toFixed(1)}%, ` +
|
||||
`Samples: ${samples.length}\r`);
|
||||
return 1;
|
||||
},
|
||||
});
|
||||
|
||||
console.log('');
|
||||
const stop = Date.now();
|
||||
const elapsed_seconds = (stop - start) / 1000;
|
||||
const duration = audio.samples.length / audio.sampleRate;
|
||||
const real_time_factor = elapsed_seconds / duration;
|
||||
console.log('Wave duration', duration.toFixed(3), 'seconds');
|
||||
console.log('Elapsed', elapsed_seconds.toFixed(3), 'seconds');
|
||||
console.log(
|
||||
`RTF = ${elapsed_seconds.toFixed(3)}/${duration.toFixed(3)} =`,
|
||||
real_time_factor.toFixed(3));
|
||||
|
||||
const filename = 'test-vits-zh-ll-async.wav';
|
||||
sherpa_onnx.writeWave(
|
||||
filename, {samples: audio.samples, sampleRate: audio.sampleRate});
|
||||
console.log(`Saved to ${filename}`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -95,4 +95,5 @@ async function main() {
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -140,4 +140,5 @@ async function main() {
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Error:', err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -60,56 +60,61 @@ const bufferSizeInSeconds = 30;
|
||||
const buffer =
|
||||
new sherpa_onnx.CircularBuffer(bufferSizeInSeconds * vad.config.sampleRate);
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: vad.config.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = vad.config.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
|
||||
let printed = false;
|
||||
let index = 0;
|
||||
ai.on('data', data => {
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(new Float32Array(data.buffer));
|
||||
while (buffer.size() > windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(resampled);
|
||||
while (buffer.size() >= windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -57,56 +57,61 @@ const bufferSizeInSeconds = 30;
|
||||
const buffer =
|
||||
new sherpa_onnx.CircularBuffer(bufferSizeInSeconds * vad.config.sampleRate);
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: vad.config.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = vad.config.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
|
||||
let printed = false;
|
||||
let index = 0;
|
||||
ai.on('data', data => {
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(new Float32Array(data.buffer));
|
||||
while (buffer.size() > windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(resampled);
|
||||
while (buffer.size() >= windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -55,56 +55,61 @@ const bufferSizeInSeconds = 30;
|
||||
const buffer =
|
||||
new sherpa_onnx.CircularBuffer(bufferSizeInSeconds * vad.config.sampleRate);
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: vad.config.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = vad.config.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
|
||||
let printed = false;
|
||||
let index = 0;
|
||||
ai.on('data', data => {
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(new Float32Array(data.buffer));
|
||||
while (buffer.size() > windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(resampled);
|
||||
while (buffer.size() >= windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -16,11 +16,11 @@ function createRecognizer() {
|
||||
'modelConfig': {
|
||||
'senseVoice': {
|
||||
'model':
|
||||
'./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/model.int8.onnx',
|
||||
'./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/model.int8.onnx',
|
||||
'useInverseTextNormalization': 1,
|
||||
},
|
||||
'tokens':
|
||||
'./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/tokens.txt',
|
||||
'./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/tokens.txt',
|
||||
'numThreads': 2,
|
||||
'provider': 'cpu',
|
||||
'debug': 1,
|
||||
@@ -58,56 +58,59 @@ const bufferSizeInSeconds = 30;
|
||||
const buffer =
|
||||
new sherpa_onnx.CircularBuffer(bufferSizeInSeconds * vad.config.sampleRate);
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: vad.config.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = vad.config.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
|
||||
let printed = false;
|
||||
let index = 0;
|
||||
ai.on('data', data => {
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(new Float32Array(data.buffer));
|
||||
while (buffer.size() > windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId, true, {
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(resampled);
|
||||
while (buffer.size() >= windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -60,56 +60,61 @@ const bufferSizeInSeconds = 30;
|
||||
const buffer =
|
||||
new sherpa_onnx.CircularBuffer(bufferSizeInSeconds * vad.config.sampleRate);
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: vad.config.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = vad.config.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
|
||||
let printed = false;
|
||||
let index = 0;
|
||||
ai.on('data', data => {
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(new Float32Array(data.buffer));
|
||||
while (buffer.size() > windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(resampled);
|
||||
while (buffer.size() >= windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -56,56 +56,61 @@ const bufferSizeInSeconds = 30;
|
||||
const buffer =
|
||||
new sherpa_onnx.CircularBuffer(bufferSizeInSeconds * vad.config.sampleRate);
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: vad.config.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = vad.config.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
|
||||
let printed = false;
|
||||
let index = 0;
|
||||
ai.on('data', data => {
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(new Float32Array(data.buffer));
|
||||
while (buffer.size() > windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(resampled);
|
||||
while (buffer.size() >= windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2025 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
//
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -56,56 +56,61 @@ const bufferSizeInSeconds = 30;
|
||||
const buffer =
|
||||
new sherpa_onnx.CircularBuffer(bufferSizeInSeconds * vad.config.sampleRate);
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: vad.config.sampleRate
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = vad.config.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
|
||||
let printed = false;
|
||||
let index = 0;
|
||||
ai.on('data', data => {
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(new Float32Array(data.buffer));
|
||||
while (buffer.size() > windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(resampled);
|
||||
while (buffer.size() >= windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const stream = recognizer.createStream();
|
||||
stream.acceptWaveform({
|
||||
samples: segment.samples,
|
||||
sampleRate: recognizer.config.featConfig.sampleRate
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
recognizer.decode(stream);
|
||||
const r = recognizer.getResult(stream);
|
||||
if (r.text.length > 0) {
|
||||
const text = r.text.toLowerCase().trim();
|
||||
console.log(`${index}: ${text}`);
|
||||
|
||||
const filename = `${index}-${text}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -46,61 +45,71 @@ const bufferSizeInSeconds = 30;
|
||||
const buffer =
|
||||
new sherpa_onnx.CircularBuffer(bufferSizeInSeconds * vad.config.sampleRate);
|
||||
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = vad.config.sampleRate;
|
||||
const resampler =
|
||||
new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: vad.config.sampleRate,
|
||||
}
|
||||
});
|
||||
console.log(
|
||||
`Device: ${inputDevice.name}, native sample rate: ${nativeSampleRate} Hz`);
|
||||
console.log(`Resampling from ${nativeSampleRate} to ${targetSampleRate} Hz`);
|
||||
|
||||
let printed = false;
|
||||
let index = 0;
|
||||
ai.on('data', data => {
|
||||
const windowSize = vad.config.sileroVad.model != '' ?
|
||||
vad.config.sileroVad.windowSize :
|
||||
vad.config.tenVad.windowSize;
|
||||
|
||||
buffer.push(new Float32Array(data.buffer));
|
||||
while (buffer.size() > windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
if (vad.isDetected() && !printed) {
|
||||
console.log(`${index}: Detected speech`);
|
||||
printed = true;
|
||||
}
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true, // true = input/recording stream
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const windowSize = vad.config.sileroVad.model != '' ?
|
||||
vad.config.sileroVad.windowSize :
|
||||
vad.config.tenVad.windowSize;
|
||||
|
||||
if (!vad.isDetected()) {
|
||||
printed = false;
|
||||
}
|
||||
const resampled = resampler.resample(data);
|
||||
buffer.push(resampled);
|
||||
while (buffer.size() >= windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
if (vad.isDetected() && !printed) {
|
||||
console.log(`${index}: Detected speech`);
|
||||
printed = true;
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const filename = `${index}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
const duration = segment.samples.length / vad.config.sampleRate;
|
||||
console.log(`${index} End of speech. Duration: ${duration} seconds`);
|
||||
console.log(`Saved to ${filename}`);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!vad.isDetected()) {
|
||||
printed = false;
|
||||
}
|
||||
|
||||
ai.on('close', () => {
|
||||
console.log('Free resources');
|
||||
});
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
const filename = `${index}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
const duration = segment.samples.length / vad.config.sampleRate;
|
||||
console.log(`${index} End of speech. Duration: ${duration} seconds`);
|
||||
console.log(`Saved to ${filename}`);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
cpal.closeStream(inputStream);
|
||||
console.log('Free resources');
|
||||
process.exit(0);
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2024 Xiaomi Corporation (authors: Fangjun Kuang)
|
||||
|
||||
const portAudio = require('naudiodon2');
|
||||
// console.log(portAudio.getDevices());
|
||||
const cpal = require('node-cpal');
|
||||
|
||||
|
||||
const sherpa_onnx = require('sherpa-onnx-node');
|
||||
|
||||
@@ -51,66 +51,73 @@ const buffer =
|
||||
new sherpa_onnx.CircularBuffer(bufferSizeInSeconds * vad.config.sampleRate);
|
||||
|
||||
|
||||
const ai = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
closeOnError: true, // Close the stream if an audio error is detected, if
|
||||
// set false then just log the error
|
||||
deviceId: -1, // Use -1 or omit the deviceId to select the default device
|
||||
sampleFormat: portAudio.SampleFormatFloat32,
|
||||
sampleRate: vad.config.sampleRate,
|
||||
}
|
||||
});
|
||||
const inputDevice = cpal.getDefaultInputDevice();
|
||||
const deviceConfig = cpal.getDefaultInputConfig(inputDevice.deviceId);
|
||||
const nativeSampleRate = deviceConfig.sampleRate;
|
||||
const targetSampleRate = vad.config.sampleRate;
|
||||
|
||||
const resampler = new sherpa_onnx.LinearResampler(nativeSampleRate, targetSampleRate);
|
||||
|
||||
let printed = false;
|
||||
let index = 0;
|
||||
ai.on('data', data => {
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(new Float32Array(data.buffer));
|
||||
while (buffer.size() > windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
if (vad.isDetected() && !printed) {
|
||||
console.log(`${index}: Detected speech`);
|
||||
printed = true;
|
||||
}
|
||||
|
||||
if (!vad.isDetected()) {
|
||||
printed = false;
|
||||
}
|
||||
const inputStream = cpal.createStream(
|
||||
inputDevice.deviceId,
|
||||
true,
|
||||
{
|
||||
sampleRate: nativeSampleRate,
|
||||
channels: 1,
|
||||
format: 'f32',
|
||||
},
|
||||
(data) => {
|
||||
const resampled = resampler.resample(data);
|
||||
const windowSize = vad.config.sileroVad.windowSize;
|
||||
buffer.push(resampled);
|
||||
while (buffer.size() >= windowSize) {
|
||||
const samples = buffer.get(buffer.head(), windowSize);
|
||||
buffer.pop(windowSize);
|
||||
vad.acceptWaveform(samples);
|
||||
if (vad.isDetected() && !printed) {
|
||||
console.log(`${index}: Detected speech`);
|
||||
printed = true;
|
||||
}
|
||||
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
if (!vad.isDetected()) {
|
||||
printed = false;
|
||||
}
|
||||
|
||||
const stream = slid.createStream();
|
||||
stream.acceptWaveform(
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
const lang = slid.compute(stream);
|
||||
const fullLang = display.of(lang);
|
||||
while (!vad.isEmpty()) {
|
||||
const segment = vad.front();
|
||||
vad.pop();
|
||||
|
||||
const filename = `${index}-${fullLang}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
const stream = slid.createStream();
|
||||
stream.acceptWaveform(
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
const lang = slid.compute(stream);
|
||||
const fullLang = display.of(lang);
|
||||
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
const duration = segment.samples.length / vad.config.sampleRate;
|
||||
console.log(`${index} End of speech. Duration: ${
|
||||
duration} seconds.\n Detected language: ${fullLang}`);
|
||||
console.log(`Saved to ${filename}`);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
const filename = `${index}-${fullLang}-${
|
||||
new Date()
|
||||
.toLocaleTimeString('en-US', {hour12: false})
|
||||
.split(' ')[0]}.wav`
|
||||
.replace(/:/g, '-');
|
||||
|
||||
ai.on('close', () => {
|
||||
sherpa_onnx.writeWave(
|
||||
filename,
|
||||
{samples: segment.samples, sampleRate: vad.config.sampleRate});
|
||||
const duration = segment.samples.length / vad.config.sampleRate;
|
||||
console.log(`${index} End of speech. Duration: ${
|
||||
duration} seconds.\n Detected language: ${fullLang}`);
|
||||
console.log(`Saved to ${filename}`);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
cpal.closeStream(inputStream);
|
||||
console.log('Free resources');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
ai.start();
|
||||
console.log('Started! Please speak');
|
||||
@@ -50,6 +50,7 @@ set(srcs
|
||||
src/version.cc
|
||||
src/wave-reader.cc
|
||||
src/wave-writer.cc
|
||||
src/resampler.cc
|
||||
)
|
||||
|
||||
if(NOT DEFINED ENV{SHERPA_ONNX_INSTALL_DIR})
|
||||
|
||||
@@ -21,3 +21,7 @@ npm i
|
||||
# see test/test_asr_streaming_transducer.js
|
||||
# for usages
|
||||
```
|
||||
|
||||
Please see doc at <https://k2-fsa.github.io/sherpa/onnx/javascript-api/index.html>.
|
||||
|
||||
API doc can be found at <https://k2-fsa.github.io/sherpa/onnx/javascript-api/html/index.html>
|
||||
@@ -1,4 +1,5 @@
|
||||
/** @typedef {import('./types').KeywordSpotterConfig} KeywordSpotterConfig */
|
||||
/** @typedef {import('./types').KeywordSpotterHandle} KeywordSpotterHandle */
|
||||
/** @typedef {import('./types').KeywordResult} KeywordResult */
|
||||
/** @typedef {import('./streaming-asr').OnlineStream} OnlineStream */
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** @typedef {import('./types').OfflineStreamObject} OfflineStreamObject */
|
||||
/** @typedef {import('./types').OfflineStreamHandle} OfflineStreamHandle */
|
||||
/** @typedef {import('./types').OfflineRecognizerHandle} OfflineRecognizerHandle */
|
||||
/** @typedef {import('./types').Waveform} Waveform */
|
||||
/**
|
||||
* @typedef {import('./types').OfflineRecognizerConfig} OfflineRecognizerConfig
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/** @typedef {import('./types').OfflineSpeakerDiarizationConfig} OfflineSpeakerDiarizationConfig */
|
||||
/** @typedef {import('./types').OfflineSpeakerDiarizationHandle} OfflineSpeakerDiarizationHandle */
|
||||
/** @typedef {import('./types').SpeakerDiarizationSegment} SpeakerDiarizationSegment */
|
||||
|
||||
const addon = require('./addon.js');
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/** @typedef {import('./types').OfflineSpeechDenoiserConfig} OfflineSpeechDenoiserConfig */
|
||||
/** @typedef {import('./types').OfflineSpeechDenoiserHandle} OfflineSpeechDenoiserHandle */
|
||||
/** @typedef {import('./types').GeneratedAudio} GeneratedAudio */
|
||||
/** @typedef {import('./types').AudioProcessRequest} AudioProcessRequest */
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/** @typedef {import('./types').OfflineTtsConfig} OfflineTtsConfig */
|
||||
/** @typedef {import('./types').OfflineTtsHandle} OfflineTtsHandle */
|
||||
/** @typedef {import('./types').TtsRequest} TtsRequest */
|
||||
/** @typedef {import('./types').GeneratedAudio} GeneratedAudio */
|
||||
|
||||
@@ -83,7 +84,7 @@ class OfflineTts {
|
||||
*
|
||||
* The progress callback receives streaming audio chunks.
|
||||
*
|
||||
* @param {TtsRequest & { generationConfig?: object, onProgress?: (info: {
|
||||
* @param {TtsRequest & { generationConfig?: GenerationConfig, onProgress?: (info: {
|
||||
* samples: Float32Array, progress: number }) => number | boolean | void
|
||||
* }} obj
|
||||
* @returns {Promise<GeneratedAudio>}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/** @typedef {import('./types').OnlineSpeechDenoiserConfig} OnlineSpeechDenoiserConfig */
|
||||
/** @typedef {import('./types').OnlineSpeechDenoiserHandle} OnlineSpeechDenoiserHandle */
|
||||
/** @typedef {import('./types').GeneratedAudio} GeneratedAudio */
|
||||
/** @typedef {import('./types').AudioProcessRequest} AudioProcessRequest */
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** @typedef {import('./types').OfflinePunctuationHandle} OfflinePunctuationHandle */
|
||||
/** @typedef {import('./types').OfflinePunctuationConfig} OfflinePunctuationConfig */
|
||||
/** @typedef {import('./types').OnlinePunctuationConfig} OnlinePunctuationConfig */
|
||||
/** @typedef {import('./types').OnlinePunctuationHandle} OnlinePunctuationHandle */
|
||||
|
||||
const addon = require('./addon.js');
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/** @typedef {import('./types').LinearResamplerHandle} LinearResamplerHandle */
|
||||
|
||||
const addon = require('./addon.js');
|
||||
|
||||
/**
|
||||
* A linear resampler that converts audio from one sample rate to another.
|
||||
*/
|
||||
class LinearResampler {
|
||||
/**
|
||||
* Create a linear resampler.
|
||||
*
|
||||
* @param {number} inputSampleRate - Input sample rate in Hz.
|
||||
* @param {number} outputSampleRate - Output sample rate in Hz.
|
||||
*/
|
||||
constructor(inputSampleRate, outputSampleRate) {
|
||||
/** @type {LinearResamplerHandle} */
|
||||
this.handle =
|
||||
addon.createLinearResampler(inputSampleRate, outputSampleRate);
|
||||
this.inputSampleRate = inputSampleRate;
|
||||
this.outputSampleRate = outputSampleRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resample a chunk of audio samples.
|
||||
*
|
||||
* Call this for each chunk of input audio. For the final chunk, call
|
||||
* {@link flush} instead so that any internally buffered samples are
|
||||
* emitted.
|
||||
*
|
||||
* @param {Float32Array} samples - Input audio samples.
|
||||
* @returns {Float32Array} Resampled audio samples.
|
||||
*/
|
||||
resample(samples) {
|
||||
return addon.resampleLinear(this.handle, samples, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resample the final chunk of audio and flush internal buffers.
|
||||
*
|
||||
* This is the same as {@link resample} but sets flush=1 so that any
|
||||
* remaining samples buffered inside the resampler are emitted. Call
|
||||
* this once after the last chunk of input audio.
|
||||
*
|
||||
* @param {Float32Array} samples - The final chunk of input audio samples.
|
||||
* @returns {Float32Array} Resampled audio samples including buffered tail.
|
||||
*/
|
||||
flush(samples) {
|
||||
return addon.resampleLinear(this.handle, samples, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the resampler to its initial state, discarding any internal
|
||||
* buffered samples.
|
||||
*/
|
||||
reset() {
|
||||
addon.linearResamplerReset(this.handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the input sample rate.
|
||||
*
|
||||
* @returns {number} Input sample rate in Hz.
|
||||
*/
|
||||
getInputSampleRate() {
|
||||
return addon.linearResamplerGetInputSampleRate(this.handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the output sample rate.
|
||||
*
|
||||
* @returns {number} Output sample rate in Hz.
|
||||
*/
|
||||
getOutputSampleRate() {
|
||||
return addon.linearResamplerGetOutputSampleRate(this.handle);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
LinearResampler,
|
||||
}
|
||||
@@ -19,6 +19,7 @@ const kws = require('./keyword-spotter.js');
|
||||
const sd = require('./non-streaming-speaker-diarization.js');
|
||||
const speech_denoiser = require('./non-streaming-speech-denoiser.js');
|
||||
const online_speech_denoiser = require('./online-speech-denoiser.js');
|
||||
const resampler = require('./resampler.js');
|
||||
|
||||
module.exports = {
|
||||
OnlineRecognizer : streaming_asr.OnlineRecognizer,
|
||||
@@ -40,6 +41,7 @@ module.exports = {
|
||||
OfflineSpeakerDiarization : sd.OfflineSpeakerDiarization,
|
||||
OfflineSpeechDenoiser : speech_denoiser.OfflineSpeechDenoiser,
|
||||
OnlineSpeechDenoiser : online_speech_denoiser.OnlineSpeechDenoiser,
|
||||
LinearResampler : resampler.LinearResampler,
|
||||
version : addon.version,
|
||||
gitSha1 : addon.gitSha1,
|
||||
gitDate : addon.gitDate,
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
/** @typedef {import('./types').SpeakerEmbeddingManagerSearchObj} SpeakerEmbeddingManagerSearchObj */
|
||||
/** @typedef {import('./types').SpeakerEmbeddingManagerVerifyObj} SpeakerEmbeddingManagerVerifyObj */
|
||||
/** @typedef {import('./types').SpeakerEmbeddingExtractorConfig} SpeakerEmbeddingExtractorConfig */
|
||||
/** @typedef {import('./types').SpeakerEmbeddingExtractorHandle} SpeakerEmbeddingExtractorHandle */
|
||||
/** @typedef {import('./types').SpeakerEmbeddingManagerHandle} SpeakerEmbeddingManagerHandle */
|
||||
/** @typedef {import('./streaming-asr').OnlineStream} OnlineStream */
|
||||
|
||||
const addon = require('./addon.js');
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/** @typedef {import('./types').SpokenLanguageIdentificationConfig} SpokenLanguageIdentificationConfig */
|
||||
/** @typedef {import('./types').SpokenLanguageIdentificationHandle} SpokenLanguageIdentificationHandle */
|
||||
/** @typedef {import('./non-streaming-asr').OfflineStream} OfflineStream */
|
||||
|
||||
const addon = require('./addon.js');
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/** @typedef {import('./types').OnlineStreamObject} OnlineStreamObject */
|
||||
/** @typedef {import('./types').OnlineRecognizerHandle} OnlineRecognizerHandle */
|
||||
/** @typedef {import('./types').OnlineStreamHandle} OnlineStreamHandle */
|
||||
/** @typedef {import('./types').DisplayHandle} DisplayHandle */
|
||||
/** @typedef {import('./types').DisplayObject} DisplayObject */
|
||||
/** @typedef {import('./types').OnlineRecognizerConfig} OnlineRecognizerConfig */
|
||||
/** @typedef {import('./types').Waveform} Waveform */
|
||||
|
||||
@@ -52,7 +52,57 @@
|
||||
|
||||
/**
|
||||
* @typedef {Object} OfflinePunctuationHandle
|
||||
* @see src/offline-punctuation.cc
|
||||
* @see src/offline-punctuation.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} LinearResamplerHandle
|
||||
* @see src/resampler.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} OfflineTtsHandle
|
||||
* @see src/non-streaming-tts.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} OnlinePunctuationHandle
|
||||
* @see src/punctuation.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} KeywordSpotterHandle
|
||||
* @see src/keyword-spotter.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SpeakerEmbeddingExtractorHandle
|
||||
* @see src/speaker-identification.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SpeakerEmbeddingManagerHandle
|
||||
* @see src/speaker-identification.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SpokenLanguageIdentificationHandle
|
||||
* @see src/spoken-language-identification.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} OfflineSpeakerDiarizationHandle
|
||||
* @see src/non-streaming-speaker-diarization.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} OfflineSpeechDenoiserHandle
|
||||
* @see src/non-streaming-speech-denoiser.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} OnlineSpeechDenoiserHandle
|
||||
* @see src/online-speech-denoiser.cc
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -234,19 +284,19 @@
|
||||
* @property {number} [useInverseTextNormalization]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline Cohere Transcribe model config
|
||||
* @typedef {Object} OfflineCohereTranscribeModelConfig
|
||||
* @property {string} [encoder]
|
||||
* @property {string} [decoder]
|
||||
* @property {string} [language]
|
||||
* @property {number} [usePunct]
|
||||
* @property {number} [useItn]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline model config.
|
||||
* @typedef {Object} OfflineModelConfig
|
||||
/**
|
||||
* Offline Cohere Transcribe model config
|
||||
* @typedef {Object} OfflineCohereTranscribeModelConfig
|
||||
* @property {string} [encoder]
|
||||
* @property {string} [decoder]
|
||||
* @property {string} [language]
|
||||
* @property {number} [usePunct]
|
||||
* @property {number} [useItn]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline model config.
|
||||
* @typedef {Object} OfflineModelConfig
|
||||
* @property {OfflineTransducerModelConfig} [transducer]
|
||||
* @property {OfflineParaformerModelConfig} [paraformer]
|
||||
* @property {OfflineZipformerCtcModelConfig} [zipformerCtc]
|
||||
@@ -255,14 +305,14 @@
|
||||
* @property {OfflineMedAsrCtcModelConfig} [medasr]
|
||||
* @property {OfflineDolphinModelConfig} [dolphin]
|
||||
* @property {OfflineNeMoCtcModelConfig} [nemoCtc]
|
||||
* @property {OfflineCanaryModelConfig} [canary]
|
||||
* @property {OfflineWhisperModelConfig} [whisper]
|
||||
* @property {OfflineFireRedAsrModelConfig} [fireRedAsr]
|
||||
* @property {OfflineMoonshineModelConfig} [moonshine]
|
||||
* @property {OfflineTdnnModelConfig} [tdnn]
|
||||
* @property {OfflineSenseVoiceModelConfig} [senseVoice]
|
||||
* @property {OfflineCohereTranscribeModelConfig} [cohereTranscribe]
|
||||
* @property {string} [tokens]
|
||||
* @property {OfflineCanaryModelConfig} [canary]
|
||||
* @property {OfflineWhisperModelConfig} [whisper]
|
||||
* @property {OfflineFireRedAsrModelConfig} [fireRedAsr]
|
||||
* @property {OfflineMoonshineModelConfig} [moonshine]
|
||||
* @property {OfflineTdnnModelConfig} [tdnn]
|
||||
* @property {OfflineSenseVoiceModelConfig} [senseVoice]
|
||||
* @property {OfflineCohereTranscribeModelConfig} [cohereTranscribe]
|
||||
* @property {string} [tokens]
|
||||
* @property {number} [numThreads]
|
||||
* @property {boolean|number} [debug]
|
||||
* @property {string} [provider]
|
||||
@@ -512,24 +562,24 @@
|
||||
* @property {number} [lengthScale]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} OfflineTtsZipvoiceModelConfig
|
||||
* @property {string} [tokens]
|
||||
* @property {string} [encoder]
|
||||
* @property {string} [decoder]
|
||||
* @property {string} [vocoder]
|
||||
* @property {string} [dataDir]
|
||||
* @property {string} [lexicon]
|
||||
* @property {number} [featScale]
|
||||
* @property {number} [tShift]
|
||||
* @property {number} [targetRms]
|
||||
* @property {number} [guidanceScale]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} OfflineTtsPocketModelConfig
|
||||
* @property {string} [lmFlow]
|
||||
* @property {string} [lmMain]
|
||||
/**
|
||||
* @typedef {Object} OfflineTtsZipvoiceModelConfig
|
||||
* @property {string} [tokens]
|
||||
* @property {string} [encoder]
|
||||
* @property {string} [decoder]
|
||||
* @property {string} [vocoder]
|
||||
* @property {string} [dataDir]
|
||||
* @property {string} [lexicon]
|
||||
* @property {number} [featScale]
|
||||
* @property {number} [tShift]
|
||||
* @property {number} [targetRms]
|
||||
* @property {number} [guidanceScale]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} OfflineTtsPocketModelConfig
|
||||
* @property {string} [lmFlow]
|
||||
* @property {string} [lmMain]
|
||||
* @property {string} [encoder]
|
||||
* @property {string} [decoder]
|
||||
* @property {string} [textConditioner]
|
||||
@@ -542,12 +592,12 @@
|
||||
* Offline TTS model config
|
||||
* @typedef {Object} OfflineTtsModelConfig
|
||||
* @property {OfflineTtsVitsModelConfig} [vits]
|
||||
* @property {OfflineTtsMatchaModelConfig} [matcha]
|
||||
* @property {OfflineTtsKokoroModelConfig} [kokoro]
|
||||
* @property {OfflineTtsKittenModelConfig} [kitten]
|
||||
* @property {OfflineTtsZipvoiceModelConfig} [zipvoice]
|
||||
* @property {OfflineTtsPocketModelConfig} [pocket]
|
||||
*/
|
||||
* @property {OfflineTtsMatchaModelConfig} [matcha]
|
||||
* @property {OfflineTtsKokoroModelConfig} [kokoro]
|
||||
* @property {OfflineTtsKittenModelConfig} [kitten]
|
||||
* @property {OfflineTtsZipvoiceModelConfig} [zipvoice]
|
||||
* @property {OfflineTtsPocketModelConfig} [pocket]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline TTS configuration (partial, commonly used props).
|
||||
@@ -559,39 +609,39 @@
|
||||
* @property {string} [provider]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline Speech Denoiser model config
|
||||
* @typedef {Object} OfflineSpeechDenoiserGtcrnModelConfig
|
||||
* @property {string} [model]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline Speech Denoiser model config
|
||||
* @typedef {Object} OfflineSpeechDenoiserDpdfNetModelConfig
|
||||
* @property {string} [model]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline Speech Denoiser model config
|
||||
* @typedef {Object} OfflineSpeechDenoiserModelConfig
|
||||
* @property {OfflineSpeechDenoiserGtcrnModelConfig} [gtcrn]
|
||||
* @property {OfflineSpeechDenoiserDpdfNetModelConfig} [dpdfnet]
|
||||
* @property {number} [numThreads]
|
||||
* @property {boolean|number} [debug]
|
||||
* @property {string} [provider]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline Speech Denoiser configuration (partial).
|
||||
* @typedef {Object} OfflineSpeechDenoiserConfig
|
||||
* @property {OfflineSpeechDenoiserModelConfig} [model]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Online Speech Denoiser configuration (partial).
|
||||
* @typedef {Object} OnlineSpeechDenoiserConfig
|
||||
* @property {OfflineSpeechDenoiserModelConfig} [model]
|
||||
*/
|
||||
/**
|
||||
* Offline Speech Denoiser model config
|
||||
* @typedef {Object} OfflineSpeechDenoiserGtcrnModelConfig
|
||||
* @property {string} [model]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline Speech Denoiser model config
|
||||
* @typedef {Object} OfflineSpeechDenoiserDpdfNetModelConfig
|
||||
* @property {string} [model]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline Speech Denoiser model config
|
||||
* @typedef {Object} OfflineSpeechDenoiserModelConfig
|
||||
* @property {OfflineSpeechDenoiserGtcrnModelConfig} [gtcrn]
|
||||
* @property {OfflineSpeechDenoiserDpdfNetModelConfig} [dpdfnet]
|
||||
* @property {number} [numThreads]
|
||||
* @property {boolean|number} [debug]
|
||||
* @property {string} [provider]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline Speech Denoiser configuration (partial).
|
||||
* @typedef {Object} OfflineSpeechDenoiserConfig
|
||||
* @property {OfflineSpeechDenoiserModelConfig} [model]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Online Speech Denoiser configuration (partial).
|
||||
* @typedef {Object} OnlineSpeechDenoiserConfig
|
||||
* @property {OfflineSpeechDenoiserModelConfig} [model]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Offline speaker segmentation (pyannote) model config
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/** @typedef {import('./types').CircularBufferHandle} CircularBufferHandle */
|
||||
/** @typedef {import('./types').VoiceActivityDetectorHandle} VoiceActivityDetectorHandle */
|
||||
/** @typedef {import('./types').SpeechSegment} SpeechSegment */
|
||||
/** @typedef {import('./types').VadConfig} VadConfig */
|
||||
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/resampler.cc
|
||||
@@ -2706,6 +2706,24 @@ struct SherpaOnnxLinearResampler {
|
||||
const SherpaOnnxLinearResampler *SherpaOnnxCreateLinearResampler(
|
||||
int32_t samp_rate_in_hz, int32_t samp_rate_out_hz, float filter_cutoff_hz,
|
||||
int32_t num_zeros) {
|
||||
if (samp_rate_in_hz <= 0 || samp_rate_out_hz <= 0) {
|
||||
SHERPA_ONNX_LOGE("Sample rates must be > 0. Given in=%d out=%d",
|
||||
samp_rate_in_hz, samp_rate_out_hz);
|
||||
return nullptr;
|
||||
}
|
||||
if (num_zeros < 0) {
|
||||
SHERPA_ONNX_LOGE("num_zeros must be >= 0. Given %d", num_zeros);
|
||||
return nullptr;
|
||||
}
|
||||
if (filter_cutoff_hz == 0) {
|
||||
float min_freq = std::min(samp_rate_in_hz, samp_rate_out_hz);
|
||||
filter_cutoff_hz = 0.99f * 0.5f * min_freq;
|
||||
}
|
||||
|
||||
if (num_zeros == 0) {
|
||||
num_zeros = 6;
|
||||
}
|
||||
|
||||
SherpaOnnxLinearResampler *p = new SherpaOnnxLinearResampler;
|
||||
p->impl = std::make_unique<sherpa_onnx::LinearResample>(
|
||||
samp_rate_in_hz, samp_rate_out_hz, filter_cutoff_hz, num_zeros);
|
||||
|
||||
@@ -3664,7 +3664,8 @@ typedef struct SherpaOnnxLinearResampler SherpaOnnxLinearResampler;
|
||||
/**
|
||||
* @brief Create a linear resampler.
|
||||
*
|
||||
* A common choice is:
|
||||
* If @p filter_cutoff_hz or @p num_zeros is 0, the following defaults
|
||||
* are used (same convention as alsa-play.cc):
|
||||
*
|
||||
* @code
|
||||
* float min_freq = samp_rate_in_hz < samp_rate_out_hz ? samp_rate_in_hz
|
||||
@@ -3673,12 +3674,14 @@ typedef struct SherpaOnnxLinearResampler SherpaOnnxLinearResampler;
|
||||
* int32_t num_zeros = 6;
|
||||
* @endcode
|
||||
*
|
||||
* @param samp_rate_in_hz Input sample rate in Hz.
|
||||
* @param samp_rate_out_hz Output sample rate in Hz.
|
||||
* @param filter_cutoff_hz Low-pass cutoff frequency in Hz.
|
||||
* @param num_zeros Low-pass filter width control parameter.
|
||||
* @return A newly allocated resampler. Free it with
|
||||
* SherpaOnnxDestroyLinearResampler().
|
||||
* @param samp_rate_in_hz Input sample rate in Hz. Must be > 0.
|
||||
* @param samp_rate_out_hz Output sample rate in Hz. Must be > 0.
|
||||
* @param filter_cutoff_hz Low-pass cutoff frequency in Hz. Pass 0 to use
|
||||
* the default formula above. Must be >= 0.
|
||||
* @param num_zeros Low-pass filter width control parameter. Pass 0 to use
|
||||
* the default value of 6. Must be >= 0.
|
||||
* @return A newly allocated resampler, or nullptr on invalid input. Free it
|
||||
* with SherpaOnnxDestroyLinearResampler().
|
||||
*/
|
||||
SHERPA_ONNX_API const SherpaOnnxLinearResampler *
|
||||
SherpaOnnxCreateLinearResampler(int32_t samp_rate_in_hz,
|
||||
|
||||
Reference in new issue
Block a user