Revamp event system to not switch from C++ --> JS twice. Fix transferer node offset

This commit is contained in:
msqr1
2024-10-02 20:42:39 -07:00
parent da3c7a269a
commit 30228eb0c1
9 changed files with 49 additions and 47 deletions

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

Binary file not shown.

View File

@@ -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);
};

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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]
});
},