Revamp event system to not switch from C++ --> JS twice. Fix transferer node offset
This commit is contained in:
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
Vosklet.wasm
BIN
Vosklet.wasm
Binary file not shown.
@@ -5,7 +5,7 @@
|
||||
using namespace emscripten;
|
||||
|
||||
EMSCRIPTEN_BINDINGS() {
|
||||
function("setLogLevel", &vosk_set_log_level, allow_raw_pointers());
|
||||
function("setLogLevel", &vosk_set_log_level);
|
||||
|
||||
enum_<VoskEndpointerMode>("EpMode")
|
||||
.value("ANSWER_DEFAULT", VOSK_EP_ANSWER_DEFAULT)
|
||||
@@ -14,22 +14,22 @@ EMSCRIPTEN_BINDINGS() {
|
||||
.value("ANSWER_VERY_LONG", VOSK_EP_ANSWER_VERY_LONG);
|
||||
|
||||
class_<CommonModel>("CommonModel")
|
||||
.constructor<int, bool, std::string, std::string, int, int>(allow_raw_pointers())
|
||||
.function("findWord", &CommonModel::findWord, allow_raw_pointers());
|
||||
.constructor<int, bool, std::string, std::string, int, int>(return_value_policy::take_ownership())
|
||||
.function("findWord", &CommonModel::findWord);
|
||||
|
||||
class_<Recognizer>("Recognizer")
|
||||
.constructor<int, float, CommonModel*>(allow_raw_pointers())
|
||||
.constructor<int, float, CommonModel*, CommonModel*>(allow_raw_pointers())
|
||||
.constructor<int, float, CommonModel*, std::string, int>(allow_raw_pointers())
|
||||
.function("safeDelete", &Recognizer::safeDelete, allow_raw_pointers())
|
||||
.function("acceptWaveform", &Recognizer::acceptWaveform, allow_raw_pointers())
|
||||
.function("reset", &Recognizer::reset, allow_raw_pointers())
|
||||
.function("setEndpointerMode", &Recognizer::setEndpointerMode, allow_raw_pointers())
|
||||
.function("setEndpointerDelays", &Recognizer::setEndpointerDelays, allow_raw_pointers())
|
||||
.function("setWords", &Recognizer::setWords, allow_raw_pointers())
|
||||
.function("setPartialWords", &Recognizer::setPartialWords, allow_raw_pointers())
|
||||
.function("setGrm", &Recognizer::setGrm, allow_raw_pointers())
|
||||
.function("setNLSML", &Recognizer::setNLSML, allow_raw_pointers())
|
||||
.constructor<int, float, CommonModel*>(return_value_policy::take_ownership())
|
||||
.constructor<int, float, CommonModel*, CommonModel*>(return_value_policy::take_ownership())
|
||||
.constructor<int, float, CommonModel*, std::string, int>(return_value_policy::take_ownership())
|
||||
.function("safeDelete", &Recognizer::safeDelete)
|
||||
.function("acceptWaveform", &Recognizer::acceptWaveform)
|
||||
.function("reset", &Recognizer::reset)
|
||||
.function("setEndpointerMode", &Recognizer::setEndpointerMode)
|
||||
.function("setEndpointerDelays", &Recognizer::setEndpointerDelays)
|
||||
.function("setWords", &Recognizer::setWords)
|
||||
.function("setPartialWords", &Recognizer::setPartialWords)
|
||||
.function("setGrm", &Recognizer::setGrm)
|
||||
.function("setNLSML", &Recognizer::setNLSML)
|
||||
.function("setSpkModel", &Recognizer::setSpkModel, allow_raw_pointers())
|
||||
.function("setMaxAlternatives", &Recognizer::setMaxAlternatives, allow_raw_pointers());
|
||||
.function("setMaxAlternatives", &Recognizer::setMaxAlternatives);
|
||||
};
|
||||
@@ -1,20 +1,20 @@
|
||||
#include "Recognizer.h"
|
||||
#include <atomic>
|
||||
|
||||
static const char* recognizerInitErr{"Unable to initialize recognizer"};
|
||||
const char* recognizerInitErr{"Unable to initialize recognizer"};
|
||||
Recognizer::Recognizer(int index, float sampleRate, CommonModel* model) :
|
||||
rec{vosk_recognizer_new(std::get<VoskModel*>(model->mdl), sampleRate)} {
|
||||
if(rec == nullptr) mtFireEv(index, Event::status, reinterpret_cast<int>(recognizerInitErr));
|
||||
if(rec == nullptr) fireEv(index, Event::status, recognizerInitErr);
|
||||
else globalPool.exec([this, index]{main(index);});
|
||||
}
|
||||
Recognizer::Recognizer(int index, float sampleRate, CommonModel* model, CommonModel* spkModel) :
|
||||
rec{vosk_recognizer_new_spk(std::get<VoskModel*>(model->mdl), sampleRate, std::get<VoskSpkModel*>(spkModel->mdl))} {
|
||||
if(rec == nullptr) mtFireEv(index, Event::status, reinterpret_cast<int>(recognizerInitErr));
|
||||
if(rec == nullptr) fireEv(index, Event::status, recognizerInitErr);
|
||||
else globalPool.exec([this, index]{main(index);});
|
||||
}
|
||||
Recognizer::Recognizer(int index, float sampleRate, CommonModel* model, const std::string& grm, int) :
|
||||
rec{vosk_recognizer_new_grm(std::get<VoskModel*>(model->mdl), sampleRate, grm.c_str())} {
|
||||
if(rec == nullptr) mtFireEv(index, Event::status, reinterpret_cast<int>(recognizerInitErr));
|
||||
if(rec == nullptr) fireEv(index, Event::status, recognizerInitErr);
|
||||
else globalPool.exec([this, index]{main(index);});
|
||||
}
|
||||
void Recognizer::safeDelete(bool _processCurrent) {
|
||||
|
||||
25
src/Util.cc
25
src/Util.cc
@@ -3,12 +3,12 @@
|
||||
#include "emscripten/wasm_worker.h"
|
||||
#include "emscripten/em_js.h"
|
||||
|
||||
EM_JS(void, mtFireEv, (int index, int typeIdx, int content), {
|
||||
objs[index].dispatchEvent(new CustomEvent(events[typeIdx], { "detail" : content == 0 ? null : UTF8ToString(content) }));
|
||||
EM_JS(void, fireEv, (int idx, int typeIdx, const char* content), {
|
||||
if(ENVIRONMENT_IS_WEB) objs[idx].dispatchEvent(new CustomEvent(events[typeIdx], {
|
||||
"detail": content == 0 ? null : UTF8ToString(content)
|
||||
}));
|
||||
else self.postMessage([idx, typeIdx, content]);
|
||||
});
|
||||
void fireEv(int index, int typeIdx, const char* content) {
|
||||
emscripten_wasm_worker_post_function_viii(0, mtFireEv, index, typeIdx, reinterpret_cast<int>(content));
|
||||
}
|
||||
int untar(unsigned char* tar, int tarSize, const std::string& storepath) {
|
||||
if(std::memcmp(tar + 257, "ustar", 5)) return IncorrectFormat;
|
||||
size_t size{};
|
||||
@@ -49,7 +49,7 @@ int untar(unsigned char* tar, int tarSize, const std::string& storepath) {
|
||||
}
|
||||
return Successful;
|
||||
}
|
||||
static void workerStartup(int _pool) {
|
||||
void workerStartup(int _pool) {
|
||||
WorkerPool& pool{*reinterpret_cast<WorkerPool*>(_pool)};
|
||||
std::function<void()> fn;
|
||||
while(!pool.done) {
|
||||
@@ -73,15 +73,16 @@ static void workerStartup(int _pool) {
|
||||
}
|
||||
using _startupFn = void(*)(int);
|
||||
EM_JS(void, startupWorkers, (_startupFn startupFn, WorkerPool* pool), {
|
||||
Object.values(_wasmWorkers).forEach(worker => {
|
||||
for(let worker of Object.values(_wasmWorkers)) {
|
||||
worker.postMessage({
|
||||
"_wsc": startupFn,
|
||||
"x": [ pool ]
|
||||
});
|
||||
})
|
||||
worker.onmessage = msg => fireEv(...msg.data);
|
||||
}
|
||||
})
|
||||
static constexpr int workerStack{32768};
|
||||
static std::array<std::byte, MAX_WORKERS * workerStack> stacks;
|
||||
constexpr int workerStack{32768};
|
||||
std::array<std::byte, MAX_WORKERS * workerStack> stacks;
|
||||
WorkerPool::WorkerPool() {
|
||||
for(int i{}; i < MAX_WORKERS; ++i) {
|
||||
emscripten_create_wasm_worker(&stacks[i * workerStack], workerStack);
|
||||
@@ -90,10 +91,14 @@ WorkerPool::WorkerPool() {
|
||||
}
|
||||
#undef MAX_WORKERS
|
||||
WorkerPool::~WorkerPool() {
|
||||
// LTO will remove the EM_JS definition for some reason if it isn't called in the same translation unit (I get undefined symbols), even though it is annotated with EMSCRIPTEN_KEEPALIVE. "Call" it here (this destructor is never called) to workaround that. I'm going to file an issue on Emscripten
|
||||
fireEv(0, 0);
|
||||
/*
|
||||
done = true;
|
||||
emscripten_atomic_store_u32(&qLock, false);
|
||||
emscripten_atomic_notify(&qLock, -1);
|
||||
emscripten_terminate_all_wasm_workers();
|
||||
*/
|
||||
}
|
||||
void WorkerPool::exec(std::function<void()> fn) {
|
||||
taskQ.emplace(fn);
|
||||
|
||||
@@ -41,11 +41,7 @@ struct WorkerPool {
|
||||
~WorkerPool();
|
||||
void exec(std::function<void()> fn);
|
||||
};
|
||||
// Must be called from the main thread
|
||||
extern "C" void mtFireEv(int index, int typeIdx, int content);
|
||||
|
||||
// Must be called from a wasm worker
|
||||
void fireEv(int index, int typeIdx, const char* content = nullptr);
|
||||
extern "C" void fireEv(int idx, int typeIdx, const char* content = nullptr);
|
||||
|
||||
int untar(unsigned char* tar, int tarSize, const std::string& storepath);
|
||||
|
||||
|
||||
@@ -51,17 +51,18 @@ let processorURL = URL.createObjectURL(new Blob(['(', (() => {
|
||||
registerProcessor('VoskletTransferer', class extends AudioWorkletProcessor {
|
||||
constructor(opts) {
|
||||
super();
|
||||
this.filledSize = 0;
|
||||
this.bufferSize = opts.processorOptions.bufferSize;
|
||||
this.buffer = new Float32Array(this.bufferSize);
|
||||
this.filled = 0;
|
||||
this.bufSize = opts.processorOptions[0];
|
||||
this.buf = new Float32Array(this.bufSize);
|
||||
}
|
||||
process(inputs) {
|
||||
if(inputs[0][0]) {
|
||||
this.buffer.set(inputs[0][0], this.filledSize += 128);
|
||||
if(this.filledSize >= this.bufferSize) {
|
||||
this.filledSize = 0;
|
||||
this.port.postMessage(this.buffer, [this.buffer.buffer]);
|
||||
this.buffer = new Float32Array(this.bufferSize);
|
||||
this.buf.set(inputs[0][0], this.filled);
|
||||
this.filled += 128;
|
||||
if(this.filled >= this.bufSize) {
|
||||
this.filled = 0;
|
||||
this.port.postMessage(this.buf, [this.buf.buffer]);
|
||||
this.buf = new Float32Array(this.bufSize);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -158,14 +159,14 @@ Module = {
|
||||
storageWorker.terminate();
|
||||
},
|
||||
|
||||
'createTransferer': async (ctx, bufferSize) => {
|
||||
'createTransferer': async (ctx, bufSize) => {
|
||||
await ctx.audioWorklet.addModule(processorURL);
|
||||
return new AudioWorkletNode(ctx, 'VoskletTransferer', {
|
||||
channelCountMode: 'explicit',
|
||||
numberOfInputs: 1,
|
||||
numberOfOutputs: 0,
|
||||
channelCount: 1,
|
||||
processorOptions: { bufferSize: bufferSize }
|
||||
processorOptions: [bufSize]
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user