Untested refactoring, relax exception safety.

This commit is contained in:
msqr1
2024-03-12 23:45:44 -07:00
parent 2091845b04
commit 471d35729a
8 changed files with 43 additions and 10352 deletions

View File

@@ -1,7 +1,7 @@
# Overview # Overview
- **STILL UNDER DEVELOPMENT!** - **STILL UNDER DEVELOPMENT!**
- A speech recognizer built on Vosk that can be run on the browser, inspired by [vosk-browser](https://github.com/ccoreilly/vosk-browser), but built from scratch and no code taken! - A speech recognizer built on Vosk that can be run on the browser, inspired by [vosk-browser](https://github.com/ccoreilly/vosk-browser), but built from scratch and no code taken!
- Designed with strong exception safety - Designed with basic/nothrow exception safety
- See the *usage* folder's README.md for API documentation, notes. - See the *usage* folder's README.md for API documentation, notes.
- See the *devel* folder for the newest build (not guaranteed to work) and the JS build script - See the *devel* folder for the newest build (not guaranteed to work) and the JS build script
@@ -10,7 +10,7 @@
- Model storage path management (for multiple models) - Model storage path management (for multiple models)
- Model ID management (for model updates) - Model ID management (for model updates)
- Smaller JS size (>3.1MB vs 1.7MB) - Smaller JS size (>3.1MB vs 1.7MB)
- All related files (worker.js, worklet processors,...) are bundled - All related files (pthread worker, worklet processor,...) are merged
- Shorter from-scratch build time - Shorter from-scratch build time

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
#include "genericModel.h" #include "genericModel.h"
genericModel::genericModel(std::string storepath, std::string id, int index, bool normalMdl) : index(index), normalMdl(normalMdl), storepath(std::move(storepath)), id(std::move(id)) {} genericModel::genericModel(std::string storepath, std::string id, int index, bool normalMdl) : index(index), normalMdl(normalMdl), storepath(std::move(storepath)), id(std::move(id)), entry(archive_entry_new()) {}
void genericModel::load() { void genericModel::load() {
auto main{[this](){ auto main{[this](){
if(normalMdl) { if(normalMdl) {
@@ -45,6 +45,7 @@ bool genericModel::checkFiles() {
fs::exists("transform.mat", tank); fs::exists("transform.mat", tank);
} }
genericModel::~genericModel() { genericModel::~genericModel() {
archive_entry_free(entry);
if(normalMdl) vosk_model_free(std::get<0>(mdl)); if(normalMdl) vosk_model_free(std::get<0>(mdl));
else vosk_spk_model_free(std::get<1>(mdl)); else vosk_spk_model_free(std::get<1>(mdl));
} }
@@ -150,22 +151,15 @@ void genericModel::afterFetch() {
bool genericModel::extract() { bool genericModel::extract() {
static fs::path path{}; static fs::path path{};
static int fd{}; static int fd{};
archive_entry* entry{archive_entry_new()};
archive* src {archive_read_new()}; archive* src {archive_read_new()};
auto cleanup {[&](){
archive_entry_free(entry);
archive_read_free(src);
}};
archive_read_support_format_tar(src); archive_read_support_format_tar(src);
archive_read_open_filename(src, "/opfs/m0dEl.tar", 10240); archive_read_open_filename(src, "/opfs/m0dEl.tar", 10240);
if(archive_errno(src) != 0) { if(archive_errno(src) != 0) {
cleanup();
emscripten_console_log(archive_error_string(src)); emscripten_console_log(archive_error_string(src));
return false; return false;
} }
while(archive_read_next_header2(src, entry) == ARCHIVE_OK) { while(archive_read_next_header2(src, entry) == ARCHIVE_OK) {
if(archive_errno(src) != 0) { if(archive_errno(src) != 0) {
cleanup();
emscripten_console_log(archive_error_string(src)); emscripten_console_log(archive_error_string(src));
return false; return false;
} }
@@ -179,19 +173,17 @@ bool genericModel::extract() {
} }
fd = creat(path.c_str(),0777); fd = creat(path.c_str(),0777);
if(fd == -1) { if(fd == -1) {
cleanup();
return false; return false;
} }
archive_read_data_into_fd(src, fd); archive_read_data_into_fd(src, fd);
close(fd); close(fd);
if(archive_errno(src) != 0) { if(archive_errno(src) != 0) {
cleanup();
emscripten_console_log(archive_error_string(src)); emscripten_console_log(archive_error_string(src));
return false; return false;
} }
} }
fs::remove("README",tank); fs::remove("README",tank);
fs::remove("/opfs/m0dEl.tar",tank); fs::remove("/opfs/m0dEl.tar",tank);
cleanup(); archive_read_free(src);
return true; return true;
} }

View File

@@ -20,6 +20,7 @@ struct genericModel {
std::string id; std::string id;
std::variant<VoskModel*, VoskSpkModel*> mdl; std::variant<VoskModel*, VoskSpkModel*> mdl;
reusableThrd thrd; reusableThrd thrd;
archive_entry* entry;
bool extract(); bool extract();
void load(); void load();
void check(); void check();

View File

@@ -16,7 +16,7 @@ void fireEv(const char *type, const char *content, int index) {
} }
reusableThrd::reusableThrd() { reusableThrd::reusableThrd() {
std::thread thrd{[this](){ std::thread thrd{[this](){
while(!done.test()) { while(!done.test(std::memory_order_relaxed)) {
blocker.wait(done.test(std::memory_order_relaxed) || queue.empty(), std::memory_order_relaxed); blocker.wait(done.test(std::memory_order_relaxed) || queue.empty(), std::memory_order_relaxed);
blocker.clear(std::memory_order_relaxed); blocker.clear(std::memory_order_relaxed);
while(!queue.empty()) { while(!queue.empty()) {

View File

@@ -57,13 +57,13 @@ class genericModel extends EventTarget {
} }
} }
Module.makeModel = async (url, storepath, id) => { Module.makeModel = async (url, storepath, id) => {
for (obj in objs) { for (let obj in objs) {
if (typeof obj.normalMdl !== "undefined" && obj.normalMdl && obj.url === url && obj.storepath === storepath && obj.id === id) return obj; if (typeof obj.normalMdl !== "undefined" && obj.normalMdl && obj.url === url && obj.storepath === storepath && obj.id === id) return obj;
} }
return genericModel._init(url, storepath, id, true); return genericModel._init(url, storepath, id, true);
} }
Module.makeSpkModel = async (url, storepath, id) => { Module.makeSpkModel = async (url, storepath, id) => {
for(obj in objs) { for(let obj in objs) {
if(typeof obj.normalMdl !== "undefined" && !obj.normalMdl && obj.url === url && obj.storepath === storepath && obj.id === id) { if(typeof obj.normalMdl !== "undefined" && !obj.normalMdl && obj.url === url && obj.storepath === storepath && obj.id === id) {
return obj; return obj;
} }

View File

@@ -1,25 +1,16 @@
#include "recognizer.h" #include "recognizer.h"
recognizer::recognizer(genericModel* model, float sampleRate, int index) : index(index) { recognizer::recognizer(genericModel* model, float sampleRate, int index) : index(index) {
auto main{[this, model, sampleRate](){
rec = vosk_recognizer_new(std::get<0>(model->mdl),sampleRate); rec = vosk_recognizer_new(std::get<0>(model->mdl),sampleRate);
finishConstruction(); finishConstruction(model, nullptr);
}};
tryStealMdlThrd(main, model);
} }
recognizer::recognizer(genericModel* model, genericModel* spkMdl, float sampleRate, int index) { recognizer::recognizer(genericModel* model, genericModel* spkMdl, float sampleRate, int index) {
auto main{[this, model, sampleRate, spkMdl](){
rec = vosk_recognizer_new_spk(std::get<0>(model->mdl), sampleRate, std::get<1>(spkMdl->mdl)); rec = vosk_recognizer_new_spk(std::get<0>(model->mdl), sampleRate, std::get<1>(spkMdl->mdl));
finishConstruction(); finishConstruction(model, spkMdl);
}};
tryStealMdlThrd(main, model);
} }
recognizer::recognizer(genericModel* model, const std::string& grm, float sampleRate, int index, int dummy) { recognizer::recognizer(genericModel* model, const std::string& grm, float sampleRate, int index, int dummy) {
auto main{[this, model, sampleRate, grm](){
rec = vosk_recognizer_new_grm(std::get<0>(model->mdl), sampleRate, grm.c_str()); rec = vosk_recognizer_new_grm(std::get<0>(model->mdl), sampleRate, grm.c_str());
finishConstruction(); finishConstruction(model, nullptr);
}};
tryStealMdlThrd(main, model);
} }
recognizer::~recognizer() { recognizer::~recognizer() {
done.test_and_set(std::memory_order_relaxed); done.test_and_set(std::memory_order_relaxed);
@@ -29,35 +20,39 @@ recognizer::~recognizer() {
vosk_recognizer_free(rec); vosk_recognizer_free(rec);
free(dataPtr); free(dataPtr);
} }
void recognizer::tryStealMdlThrd(std::function<void()>&& main, genericModel* model) { void recognizer::finishConstruction(genericModel* model, genericModel* spkModel) {
if(model->recognizerUsedThrd) {
model->thrd.addTask(std::move(main));
model->recognizerUsedThrd = true;
return;
}
std::thread t{main};
t.detach();
}
void recognizer::finishConstruction() {
if(rec == nullptr) { if(rec == nullptr) {
fireEv("_continue", "Unable to initialize recognizer", this->index); fireEv("_continue", "Unable to initialize recognizer", this->index);
return; return;
} }
fireEv("_continue", nullptr, this->index); auto main {[this](){
fireEv("_continue", nullptr, index);
while(!done.test(std::memory_order_relaxed)) { while(!done.test(std::memory_order_relaxed)) {
controller.wait(!done.test(std::memory_order_relaxed), std::memory_order_relaxed); controller.wait(!done.test(std::memory_order_relaxed), std::memory_order_relaxed);
controller.clear(std::memory_order_relaxed); controller.clear(std::memory_order_relaxed);
if(done.test(std::memory_order_relaxed)) continue; if(done.test(std::memory_order_relaxed)) continue;
switch(vosk_recognizer_accept_waveform_f(rec, dataPtr, 512)) { switch(vosk_recognizer_accept_waveform_f(rec, dataPtr, 512)) {
case 0: case 0:
fireEv("result", vosk_recognizer_result(rec), this->index); fireEv("result", vosk_recognizer_result(rec), index);
break; break;
case 1: case 1:
fireEv("partialResult", vosk_recognizer_partial_result(rec), this->index); fireEv("partialResult", vosk_recognizer_partial_result(rec), index);
} }
} }
}};
if(!model->recognizerUsedThrd) {
model->recognizerUsedThrd = true;
model->thrd.addTask(main);
return;
}
if(spkModel != nullptr && !spkModel->recognizerUsedThrd) {
spkModel->recognizerUsedThrd = true;
spkModel->thrd.addTask(main);
}
std::thread t{main};
t.detach();
} }
void recognizer::acceptWaveForm() { void recognizer::acceptWaveForm() noexcept {
controller.test_and_set(std::memory_order_relaxed); controller.test_and_set(std::memory_order_relaxed);
controller.notify_one(); controller.notify_one();
} }

View File

@@ -12,7 +12,7 @@ struct recognizer {
recognizer(genericModel* model, genericModel* spkModel, float sampleRate, int index); recognizer(genericModel* model, genericModel* spkModel, float sampleRate, int index);
recognizer(genericModel* model, const std::string& grm, float sampleRate, int index, int dummy); recognizer(genericModel* model, const std::string& grm, float sampleRate, int index, int dummy);
~recognizer(); ~recognizer();
void finishConstruction(); void finishConstruction(genericModel* model, genericModel* spkModel);
void tryStealMdlThrd(std::function<void()>&& main, genericModel* mdl); void tryStealMdlThrd(std::function<void()>&& main, genericModel* mdl);
void acceptWaveForm(); void acceptWaveForm();
void setSpkModel(genericModel* model); void setSpkModel(genericModel* model);