Draft 2 (failed)

This commit is contained in:
msqr1
2024-01-18 23:47:10 -08:00
parent 97ba7ee1b8
commit 91a21271d5
22 changed files with 350 additions and 299 deletions

19
.gitignore vendored
View File

@@ -1,10 +1,11 @@
.vscode
test.sh
index.html
model.tzst
clapack-wasm
kaldi
libarchive
vosk-api
zstd zstd
test.cc vosk-api
kaldi
test
test.sh
libarchive
.vscode
clapack-wasm
node_modules
package.json
package-lock.json

File diff suppressed because one or more lines are too long

View File

@@ -12,34 +12,6 @@
var Module = {}; var Module = {};
// Node.js support
var ENVIRONMENT_IS_NODE = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string';
if (ENVIRONMENT_IS_NODE) {
// Create as web-worker-like an environment as we can.
var nodeWorkerThreads = require('worker_threads');
var parentPort = nodeWorkerThreads.parentPort;
parentPort.on('message', (data) => onmessage({ data: data }));
var fs = require('fs');
var vm = require('vm');
Object.assign(global, {
self: global,
require,
Module,
location: {
href: __filename
},
Worker: nodeWorkerThreads.Worker,
importScripts: (f) => vm.runInThisContext(fs.readFileSync(f, 'utf8'), {filename: f}),
postMessage: (msg) => parentPort.postMessage(msg),
performance: global.performance || { now: Date.now },
});
}
// Thread-local guard variable for one-time init of the JS state // Thread-local guard variable for one-time init of the JS state
var initializedJS = false; var initializedJS = false;
@@ -49,11 +21,6 @@ function assert(condition, text) {
function threadPrintErr() { function threadPrintErr() {
var text = Array.prototype.slice.call(arguments).join(' '); var text = Array.prototype.slice.call(arguments).join(' ');
// See https://github.com/emscripten-core/emscripten/issues/14804
if (ENVIRONMENT_IS_NODE) {
fs.writeSync(2, text + '\n');
return;
}
console.error(text); console.error(text);
} }
function threadAlert() { function threadAlert() {
@@ -97,6 +64,7 @@ function handleMessage(e) {
// And add a callback for when the runtime is initialized. // And add a callback for when the runtime is initialized.
self.startWorker = (instance) => { self.startWorker = (instance) => {
Module = instance;
// Notify the main thread that this thread has loaded. // Notify the main thread that this thread has loaded.
postMessage({ 'cmd': 'loaded' }); postMessage({ 'cmd': 'loaded' });
// Process any messages that were queued before the thread was ready. // Process any messages that were queued before the thread was ready.
@@ -133,6 +101,7 @@ function handleMessage(e) {
importScripts(objectUrl); importScripts(objectUrl);
URL.revokeObjectURL(objectUrl); URL.revokeObjectURL(objectUrl);
} }
loadBR(Module);
} else if (e.data.cmd === 'run') { } else if (e.data.cmd === 'run') {
// Pass the thread address to wasm to store it for fast access. // Pass the thread address to wasm to store it for fast access.
Module['__emscripten_thread_init'](e.data.pthread_ptr, /*is_main=*/0, /*is_runtime=*/0, /*can_block=*/1); Module['__emscripten_thread_init'](e.data.pthread_ptr, /*is_main=*/0, /*is_runtime=*/0, /*can_block=*/1);

View File

@@ -25,7 +25,7 @@ spkModel.init(url, storepath, id)
- ***delete***: Delete self and free resources - ***delete***: Delete self and free resources
#### Events #### Events
- ***ready***: The model is ready to be put into a recognizer via the constructor, or setSpkModel() for SpkModel. - ***ready***: The model is ready to be put into a recognizer via the constructor, or setSpkModel() for SpkModel.
- ***error***: An error occured, check the event's **details** property. - ***error***: An error occured, check the event's "details" property.
### Recognizer ### Recognizer
``` ```
recognizer = new Recognizer() recognizer = new Recognizer()
@@ -43,11 +43,11 @@ recognizer.init(model)
- ***setMaxAlternatives***: Set the max number of alternatives for result event (default: false) - ***setMaxAlternatives***: Set the max number of alternatives for result event (default: false)
- ***setGrm***: Add grammar to the recognizer (default: none) - ***setGrm***: Add grammar to the recognizer (default: none)
- ***setSpkModel***: Set the speaker model of the recognizer (default: none) - ***setSpkModel***: Set the speaker model of the recognizer (default: none)
- ***delete***: Delete self and free resources - ***delete***: Call stop, delete self and free all resource
#### Events #### Events
- ***partialResult***: There is a partial recognition result, check the event's **details** property - ***partialResult***: There is a partial recognition result, check the event's "details" property
- ***result***: There is a full recognition result, check the event's **details** property - ***result***: There is a full recognition result, check the event's "details" property
- ***error***: An error occured, check the event's **details** property. - ***error***: An error occured, check the event's "details" property.
## Other key points ## Other key points
### IMPORTANT ### IMPORTANT
- You MUST call delete() on objects at the end of its usage. Or put: - You MUST call delete() on objects at the end of its usage. Or put:
@@ -56,7 +56,8 @@ recognizer.init(model)
__genericObj__.objects.forEach(obj => obj.delete()) __genericObj__.objects.forEach(obj => obj.delete())
``` ```
at the end of your program to automatically do that. We have to do this because Emscripten doesn't call destructors. See [here](https://emscripten.org/docs/getting_started/FAQ.html#what-does-exiting-the-runtime-mean-why-don-t-atexit-s-run). at the end of your program to automatically do that. We have to do this because Emscripten doesn't call destructors. See [here](https://emscripten.org/docs/getting_started/FAQ.html#what-does-exiting-the-runtime-mean-why-don-t-atexit-s-run).
- To be safe, always handle the API through events by adding all event listener before calling init(). - To be safe, always handle the API through events by adding all event listener before calling init() on objects.
- Always call init on the regular Model object before calling init on the recognizer. SpkModel can be init and set later.
### Guarantees ### Guarantees
- If an error occurs (error event is fired), no changes was made, and no other dependent events will fire. For example, if an error occur while loading the model, the "ready" event won't fire in order to prevent executing code on a nonexistent model. - If an error occurs (error event is fired), no changes was made, and no other dependent events will fire. For example, if an error occur while loading the model, the "ready" event won't fire in order to prevent executing code on a nonexistent model.
### Limitations compared to vosk-browser: ### Limitations compared to vosk-browser:

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<script src="BrowserRecognizer.js" defer></script>
<script type="module" src="src/genericObj.js" defer></script>
<script src="src/model.js" defer></script>
<script src="src/spkModel.js" defer></script>
<script src="src/recognizer.js" defer></script>
</head>
<script>
</script>
</html>

View File

@@ -8,6 +8,8 @@
# Total build time is around 45 minutes, mostly from building Kaldi # Total build time is around 45 minutes, mostly from building Kaldi
sudo apt install shtool libtool autogen autotools-dev pkg-config make && sudo apt install shtool libtool autogen autotools-dev pkg-config make &&
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash &&
nvm install 20.11.0 &&
SRC=$(realpath src) && SRC=$(realpath src) &&
KALDI=$(realpath kaldi) && KALDI=$(realpath kaldi) &&
@@ -52,7 +54,7 @@ echo "PACKAGE_VERSION = 1.8.0" >> $OPENFST/Makefile &&
cd $KALDI/src && cd $KALDI/src &&
git apply $SRC/kaldi.patch && git apply $SRC/kaldi.patch &&
CXXFLAGS="-O3 -msse3 -mssse3 -msse4.1 -msse4.2 -mavx -msimd128 -UHAVE_EXECINFO_H -pthread -flto" LDFLAGS="-O3 -sERROR_ON_UNDEFINED_SYMBOLS=0 -lembind -pthread -flto" emconfigure ./configure --use-cuda=no --with-cudadecoder=no --static --static-math=yes --static-fst=yes --double-precision=yes --debug-level=0 --clapack-root=$CLAPACK_WASM --host=WASM && CXXFLAGS="-O3 -msimd128 -UHAVE_EXECINFO_H -pthread -flto" LDFLAGS="-O3 -sERROR_ON_UNDEFINED_SYMBOLS=0 -lembind -pthread -flto" emconfigure ./configure --use-cuda=no --with-cudadecoder=no --static --static-math=yes --static-fst=yes --debug-level=0 --clapack-root=$CLAPACK_WASM --host=WASM &&
emmake make online2 lm rnnlm && emmake make online2 lm rnnlm &&
cd $VOSK/src && cd $VOSK/src &&
@@ -61,4 +63,4 @@ em++ -pthread -O3 -flto -I. -I$KALDI/src -I$OPENFST/include $VOSK_FILES -c &&
emar -rcs vosk.a ${VOSK_FILES//.cc/.o} && emar -rcs vosk.a ${VOSK_FILES//.cc/.o} &&
cd $SRC cd $SRC
em++ -O3 genericObj.cc genericModel.cc model.cc spkModel.cc recognizer.cc bindings.cc -sWASMFS -sWASM_BIGINT -sSUPPORT_BIG_ENDIAN -sSINGLE_FILE -sINITIAL_MEMORY=300mb -sASYNCIFY -sPTHREAD_POOL_SIZE=2 -pthread --no-entry -flto --post-js genericObj.js --post-js model.js --post-js spkModel.js --post-js recognizer.js -I. -I$LIBARCHIVE/include -I$VOSK/src -L$LIBARCHIVE/lib -larchive -L$ZSTD/lib -lzstd -L$KALDI/src -l:online2/kaldi-online2.a -l:decoder/kaldi-decoder.a -l:ivector/kaldi-ivector.a -l:gmm/kaldi-gmm.a -l:tree/kaldi-tree.a -l:feat/kaldi-feat.a -l:cudamatrix/kaldi-cudamatrix.a -l:lat/kaldi-lat.a -l:lm/kaldi-lm.a -l:rnnlm/kaldi-rnnlm.a -l:hmm/kaldi-hmm.a -l:nnet3/kaldi-nnet3.a -l:transform/kaldi-transform.a -l:matrix/kaldi-matrix.a -l:fstext/kaldi-fstext.a -l:util/kaldi-util.a -l:base/kaldi-base.a -L$OPENFST/lib -l:libfst.a -l:libfstngram.a -L$CLAPACK_WASM -l:CBLAS/lib/cblas.a -l:CLAPACK-3.2.1/lapack.a -l:CLAPACK-3.2.1/libcblaswr.a -l:f2c_BLAS-3.8.0/blas.a -l:libf2c/libf2c.a -L$VOSK/src -l:vosk.a -lopfs.js -lembind -lopenal -o BrowserRecognizer.js em++ -O3 genericObj.cc genericModel.cc model.cc spkModel.cc recognizer.cc bindings.cc -sWASMFS -sWASM_BIGINT -sSUPPORT_BIG_ENDIAN -sSINGLE_FILE -sMODULARIZE -sASYNCIFY -sEXPORT_NAME=loadBR -sENVIRONMENT=web,worker -sINITIAL_MEMORY=300mb -sPTHREAD_POOL_SIZE=2 -pthread -flto -I. -I$LIBARCHIVE/include -I$VOSK/src -L$LIBARCHIVE/lib -larchive -L$ZSTD/lib -lzstd -L$KALDI/src -l:online2/kaldi-online2.a -l:decoder/kaldi-decoder.a -l:ivector/kaldi-ivector.a -l:gmm/kaldi-gmm.a -l:tree/kaldi-tree.a -l:feat/kaldi-feat.a -l:cudamatrix/kaldi-cudamatrix.a -l:lat/kaldi-lat.a -l:lm/kaldi-lm.a -l:rnnlm/kaldi-rnnlm.a -l:hmm/kaldi-hmm.a -l:nnet3/kaldi-nnet3.a -l:transform/kaldi-transform.a -l:matrix/kaldi-matrix.a -l:fstext/kaldi-fstext.a -l:util/kaldi-util.a -l:base/kaldi-base.a -L$OPENFST/lib -l:libfst.a -l:libfstngram.a -L$CLAPACK_WASM -l:CBLAS/lib/cblas.a -l:CLAPACK-3.2.1/lapack.a -l:CLAPACK-3.2.1/libcblaswr.a -l:f2c_BLAS-3.8.0/blas.a -l:libf2c/libf2c.a -L$VOSK/src -l:vosk.a -lopfs.js -lembind -lopenal -o ../BrowserRecognizer.js

View File

@@ -2,6 +2,13 @@
#include "model.h" #include "model.h"
#include "recognizer.h" #include "recognizer.h"
using namespace emscripten; using namespace emscripten;
int main() {
//vosk_set_log_level(-1);
std::thread t{[](){
wasmfs_create_directory("/opfs",0777,wasmfs_create_opfs_backend());
}};
t.detach();
}
EMSCRIPTEN_BINDINGS() { EMSCRIPTEN_BINDINGS() {
function("setLogLevel", &vosk_set_log_level, allow_raw_pointers()); function("setLogLevel", &vosk_set_log_level, allow_raw_pointers());
class_<model>("__model__") class_<model>("__model__")
@@ -14,7 +21,6 @@ EMSCRIPTEN_BINDINGS() {
.constructor<model*, int, int>(allow_raw_pointers()) .constructor<model*, int, int>(allow_raw_pointers())
.function("start", &recognizer::start, allow_raw_pointers()) .function("start", &recognizer::start, allow_raw_pointers())
.function("stop", &recognizer::stop, allow_raw_pointers()) .function("stop", &recognizer::stop, allow_raw_pointers())
.function("deinit", &recognizer::deinit, allow_raw_pointers())
.function("setWords", &recognizer::setWords, allow_raw_pointers()) .function("setWords", &recognizer::setWords, allow_raw_pointers())
.function("setPartialWords", &recognizer::setPartialWords, allow_raw_pointers()) .function("setPartialWords", &recognizer::setPartialWords, allow_raw_pointers())
.function("setGrm", &recognizer::setGrm, allow_raw_pointers()) .function("setGrm", &recognizer::setGrm, allow_raw_pointers())

16
src/clapack-wasm.patch Normal file
View File

@@ -0,0 +1,16 @@
diff --git a/libf2c/main.c b/libf2c/main.c
index d95fdc9..ac82f68 100644
--- a/libf2c/main.c
+++ b/libf2c/main.c
@@ -105,9 +105,9 @@ char **xargv;
int
#ifdef KR_headers
-main(argc, argv) int argc; char **argv;
+m(argc, argv) int argc; char **argv;
#else
-main(int argc, char **argv)
+m(int argc, char **argv)
#endif
{
xargc = argc;

View File

@@ -1,21 +1,9 @@
#include "genericModel.h" #include "genericModel.h"
bool genericModel::first = true;
genericModel::genericModel(const std::string &url, const std::string& storepath, const std::string &id, int index) : url(url), id(id), genericObj(index) { genericModel::genericModel(const std::string &url, const std::string& storepath, const std::string &id, int index) : url(url), id(id), genericObj(index) {
fs::current_path("/opfs");
fs::create_directories(storepath);
fs::current_path(storepath); fs::current_path(storepath);
if(first) {
vosk_set_log_level(0);
int res{};
std::thread t{[&res](){
res = wasmfs_create_directory("opfs",0777,wasmfs_create_opfs_backend());
}};
t.join();
if(res == 1){
fireEv("error", "Unable to create OPFS directory");
return;
}
first = false;
}
} }
bool genericModel::checkId(const std::string& id) { bool genericModel::checkId(const std::string& id) {
std::ifstream file {"id", std::ifstream::binary}; std::ifstream file {"id", std::ifstream::binary};
@@ -28,42 +16,46 @@ bool genericModel::checkId(const std::string& id) {
file.read(&oldid[0], size); file.read(&oldid[0], size);
return id.compare(oldid) == 0 ? true : false; return id.compare(oldid) == 0 ? true : false;
} }
bool genericModel::loadModel() { bool genericModel::loadModel(const std::string& storepath) {
if(!checkModel() || !checkId(id)) { if(!checkModel() || !checkId(id)) {
if(emscripten_wget(url.c_str(),"opfs/model.tzst") == 1) { char filename[] {"/opfs/XXXXXX.tzst"};
close(mkostemps(filename, 5, O_PATH));
if(emscripten_wget(url.c_str(),filename) == 1) {
fireEv("error", "Unable to fetch model"); fireEv("error", "Unable to fetch model");
return false; return false;
} }
if(!extractModel()) { if(!extractModel(filename)) {
fireEv("error", "Unable to extract model"); fireEv("error", "Unable to extract model");
return false; return false;
} }
fs::remove("opfs/model.tzst"); fs::remove(filename);
if(!checkModel()) { if(!checkModel()) {
fireEv("error", "Model URL contains invalid model files"); fireEv("error", "Model URL contains invalid model files");
fs::remove_all("."); fs::current_path("/opfs");
fs::remove_all(storepath);
return false; return false;
} }
std::ofstream idFile("id"); std::ofstream idFile("id");
if(!idFile.is_open()) { if(!idFile.is_open()) {
fireEv("error", "Unable to write new id"); fireEv("error", "Unable to write new id");
fs::remove_all("."); fs::remove_all(storepath);
return false; return false;
} }
idFile << id; idFile << id;
} }
return true; return true;
} }
bool genericModel::extractModel() { bool genericModel::extractModel(char* name) {
std::string path{}; std::string path{};
archive* src {archive_read_new()}; archive* src {archive_read_new()};
archive_entry* entry {}; archive_entry* entry {};
archive_read_support_filter_all(src); archive_read_support_filter_all(src);
archive_read_support_format_all(src); archive_read_support_format_all(src);
archive_read_open_filename(src, "opfs/model.tzst",10240); archive_read_open_filename(src, name,10240);
if(archive_errno(src) != 0) return false; if(archive_errno(src) != 0) return false;
while (archive_read_next_header(src, &entry) == ARCHIVE_OK) { while (archive_read_next_header(src, &entry) == ARCHIVE_OK) {
path = archive_entry_pathname(entry); path = archive_entry_pathname(entry);
// Strip first component
archive_entry_set_pathname(entry, path.substr(path.find("/")).c_str()); archive_entry_set_pathname(entry, path.substr(path.find("/")).c_str());
if(archive_errno(src) != 0) return false; if(archive_errno(src) != 0) return false;
archive_read_extract(src, entry, ARCHIVE_EXTRACT_UNLINK); archive_read_extract(src, entry, ARCHIVE_EXTRACT_UNLINK);

View File

@@ -6,6 +6,7 @@
#include <fstream> #include <fstream>
#include <thread> #include <thread>
#include <fcntl.h>
#include <vosk_api.h> #include <vosk_api.h>
#include <archive.h> #include <archive.h>
#include <archive_entry.h> #include <archive_entry.h>
@@ -15,12 +16,11 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
struct genericModel : genericObj { struct genericModel : genericObj {
static bool first;
const std::string url{}; const std::string url{};
const std::string id{}; const std::string id{};
static bool extractModel(); static bool extractModel(char *name);
static bool checkId(const std::string& id); static bool checkId(const std::string& id);
virtual bool checkModel() = 0; virtual bool checkModel() = 0;
bool loadModel(); bool loadModel(const std::string& storepath);
genericModel(const std::string& url, const std::string& storepath, const std::string& id, int index); genericModel(const std::string &url, const std::string &storepath, const std::string &id, int index);
}; };

View File

@@ -1,13 +1,11 @@
#include "genericObj.h" #include "genericObj.h"
void genericObj::fireEv(const char *type, const char *content) { void genericObj::fireEv(const char *type, const char *content) {
if(content == nullptr) {
EM_ASM({
__genericObj__.objects[$0].dispatchEvent(new Event(UTF8ToString($1)));
},this->index, type);
return;
}
EM_ASM({ EM_ASM({
__genericObj__.objects[$0].dispatchEvent(new CustomEvent(UTF8ToString($0), {"details" : UTF8ToString($1)})); if($0 === 0) {
__genericObj__.objects[$0].dispatchEvent(new Event(UTF8ToString($1)));
return;
}
__genericObj__.objects[$0].dispatchEvent(new CustomEvent(UTF8ToString($1), {"details" : UTF8ToString($2)}));
},this->index, type, content); },this->index, type, content);
} }

View File

@@ -1 +1,2 @@
class __genericObj__ {static objects = []} class __genericObj__ {static objects = []}

View File

@@ -25,18 +25,7 @@ index 4573e24f1..4af4e73ea 100644
MultiThreadable::~MultiThreadable() { MultiThreadable::~MultiThreadable() {
// default implementation does nothing // default implementation does nothing
diff --git a/src/base/kaldi-types.h b/src/base/kaldi-types.h
index 7ebf4f853..2f5979e42 100644
--- a/src/base/kaldi-types.h
+++ b/src/base/kaldi-types.h
@@ -20,6 +20,7 @@
#ifndef KALDI_BASE_KALDI_TYPES_H_
#define KALDI_BASE_KALDI_TYPES_H_ 1
+#define KALDI_DOUBLEPRECISION 1
namespace kaldi {
// TYPEDEFS ..................................................................
diff --git a/src/ivector/ivector-extractor.cc b/src/ivector/ivector-extractor.cc diff --git a/src/ivector/ivector-extractor.cc b/src/ivector/ivector-extractor.cc
index c3a122281..71d37256d 100644 index c3a122281..71d37256d 100644
--- a/src/ivector/ivector-extractor.cc --- a/src/ivector/ivector-extractor.cc

View File

@@ -1,7 +1,7 @@
#include "model.h" #include "model.h"
model::model(const std::string &url, const std::string& storepath, const std::string& id, int index) : genericModel(url, id, storepath, index) { model::model(const std::string &url, const std::string& storepath, const std::string& id, int index) : genericModel(url, id, storepath, index) {
if(!loadModel()) return; if(!loadModel(storepath)) return;
mdl = vosk_model_new("."); mdl = vosk_model_new(".");
if(mdl == nullptr) { if(mdl == nullptr) {
fireEv("error", "Unable to initialize model"); fireEv("error", "Unable to initialize model");
@@ -9,7 +9,9 @@ model::model(const std::string &url, const std::string& storepath, const std::st
} }
fireEv("ready"); fireEv("ready");
}; };
model::~model() {
vosk_model_free(mdl);
}
bool model::checkModel() { bool model::checkModel() {
return fs::exists("am/final.mdl") && return fs::exists("am/final.mdl") &&
fs::exists("conf/mfcc.conf") && fs::exists("conf/mfcc.conf") &&

View File

@@ -5,6 +5,7 @@ struct model : genericModel {
bool checkModel(); bool checkModel();
VoskModel* mdl{}; VoskModel* mdl{};
model(const std::string &url, const std::string& storepath, const std::string& id, int index); model(const std::string &url, const std::string& storepath, const std::string& id, int index);
~model();
}; };

View File

@@ -3,12 +3,10 @@ class Model extends EventTarget{
super() super()
} }
init(url, storepath, id) { init(url, storepath, id) {
this.obj = new Module.__model__(url, storepath, id, __genericObj__.objects.length); this.obj = new BrowserRecognizer.__model__(url, storepath, id, __genericObj__.objects.length);
__genericObj__.objects.push(this) __genericObj__.objects.push(this)
} }
delete() { delete() {
this.obj.then(() => { this.obj.delete()
this.obj.delete()
})
} }
} }

View File

@@ -7,11 +7,6 @@ void recognizer::stop() {
controller.clear(std::memory_order_relaxed); controller.clear(std::memory_order_relaxed);
controller.notify_all(); controller.notify_all();
} }
void recognizer::deinit() {
done.test_and_set(std::memory_order_relaxed);
done.notify_all();
stop();
}
recognizer::recognizer(model* mdl, int sampleRate, int index) : genericObj(index) { recognizer::recognizer(model* mdl, int sampleRate, int index) : genericObj(index) {
mic = alcCaptureOpenDevice("Emscripten OpenAL capture",sampleRate, AL_FORMAT_MONO16, 22480); mic = alcCaptureOpenDevice("Emscripten OpenAL capture",sampleRate, AL_FORMAT_MONO16, 22480);
if(alcGetError(mic) != 0) { if(alcGetError(mic) != 0) {
@@ -25,32 +20,15 @@ recognizer::recognizer(model* mdl, int sampleRate, int index) : genericObj(index
} }
main(); main();
} }
void recognizer::main() { recognizer::~recognizer() {
char buffer[22480]; done.test_and_set(std::memory_order_relaxed);
int sample{}; done.notify_all();
fireEv("ready"); stop();
while(!done.test()) {
controller.wait(done.test(std::memory_order_relaxed), std::memory_order_relaxed);
alcCaptureStart(mic);
while(controller.test()) {
alcGetIntegerv(mic, ALC_CAPTURE_SAMPLES, sizeof(int), &sample);
alcCaptureSamples(mic, buffer, sample);
switch(vosk_recognizer_accept_waveform(rec, buffer, 22480)) {
case 0:
fireEv("result", vosk_recognizer_result(rec));
break;
case 1:
fireEv("partialResult", vosk_recognizer_partial_result(rec));
break;
default:
fireEv("error", "Recognition result error");
}
}
alcCaptureStop(mic);
}
vosk_recognizer_free(rec); vosk_recognizer_free(rec);
alcCaptureCloseDevice(mic); alcCaptureCloseDevice(mic);
} }
void recognizer::acceptWaveForm() {
}
void recognizer::setGrm(const std::string& grm) { void recognizer::setGrm(const std::string& grm) {
vosk_recognizer_set_grm(rec, grm.c_str()); vosk_recognizer_set_grm(rec, grm.c_str());
} }

View File

@@ -19,13 +19,11 @@ namespace fs = std::filesystem;
struct recognizer : genericObj { struct recognizer : genericObj {
VoskRecognizer* rec{}; VoskRecognizer* rec{};
ALCdevice* mic{}; ALCdevice* mic{};
std::atomic_flag done {false}; void acceptWaveForm();
std::atomic_flag controller{false};
void main();
recognizer(model* model, int sampleRate, int index); recognizer(model* model, int sampleRate, int index);
~recognizer();
void start(); void start();
void stop(); void stop();
void deinit();
void setSpkModel(spkModel* model); void setSpkModel(spkModel* model);
void setGrm(const std::string& grm); void setGrm(const std::string& grm);
void setWords(bool words); void setWords(bool words);

View File

@@ -4,7 +4,7 @@ class Recognizer extends EventTarget {
} }
init(model) { init(model) {
ctx = new (AudioContext || webkitAudioContext)() ctx = new (AudioContext || webkitAudioContext)()
new Module.__recognizer__(model.obj,ctx.sampleRate,__genericObj__.objects.length) new BrowserRecognizer.__recognizer__(model.obj,ctx.sampleRate,__genericObj__.objects.length)
ctx.close() ctx.close()
__genericObj__.objects.push(this) __genericObj__.objects.push(this)
} }
@@ -15,7 +15,6 @@ class Recognizer extends EventTarget {
this.obj.stop() this.obj.stop()
} }
delete() { delete() {
this.obj.deinit()
this.obj.delete() this.obj.delete()
} }
setWords(words) { setWords(words) {

View File

@@ -1,12 +1,15 @@
#include "spkModel.h" #include "spkModel.h"
spkModel::spkModel(const std::string &url, const std::string& storepath, const std::string& id, int index) : genericModel(url, storepath, id, index) { spkModel::spkModel(const std::string &url, const std::string& storepath, const std::string& id, int index) : genericModel(url, storepath, id, index) {
if(!loadModel()) return; if(!loadModel(storepath)) return;
mdl = vosk_spk_model_new("."); mdl = vosk_spk_model_new(".");
if(mdl == nullptr) { if(mdl == nullptr) {
fireEv("error", "Unable to initialize speaker model"); fireEv("error", "Unable to initialize speaker model");
} }
fireEv("ready"); fireEv("ready");
}; };
spkModel::~spkModel() {
vosk_spk_model_free(mdl);
}
bool spkModel::checkModel() { bool spkModel::checkModel() {
return fs::exists("mfcc.conf") && return fs::exists("mfcc.conf") &&
fs::exists("final.ext.raw") && fs::exists("final.ext.raw") &&

View File

@@ -3,8 +3,9 @@
struct spkModel : genericModel { struct spkModel : genericModel {
bool checkModel(); bool checkModel();
spkModel(const std::string &url, const std::string& storepath, const std::string& id, const int index);
VoskSpkModel* mdl{}; VoskSpkModel* mdl{};
spkModel(const std::string &url, const std::string& storepath, const std::string& id, const int index);
~spkModel();
}; };

View File

@@ -3,7 +3,7 @@ class SpkModel extends EventTarget{
super() super()
} }
init(url, storepath, id) { init(url, storepath, id) {
this.obj = new Module.__spkModel__(url, storepath, id, __genericObj__.objects.length) this.obj = new BrowserRecognizer.__spkModel__(url, storepath, id, __genericObj__.objects.length)
__genericObj__.objects.push(this) __genericObj__.objects.push(this)
} }
delete() { delete() {