Untested refactoring, relax exception safety.
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10297
devel/Vosklet.js.symbols
10297
devel/Vosklet.js.symbols
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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();
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user