Make naming convention consistent, and synchronize code
This commit is contained in:
File diff suppressed because one or more lines are too long
17
README.md
17
README.md
@@ -1,5 +1,6 @@
|
|||||||
# Browser-recognizer
|
# Browser-recognizer
|
||||||
A from-microphone 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 from-microphone 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!
|
||||||
|
- Browser-recognizer can run on the main thread, as well as a web worker, see the "Important" section below for more information
|
||||||
## Interface
|
## Interface
|
||||||
- setLogLevel: set Kaldi's log level (default: -1)
|
- setLogLevel: set Kaldi's log level (default: -1)
|
||||||
- -2: Error
|
- -2: Error
|
||||||
@@ -39,19 +40,19 @@ new Recognizer(model)
|
|||||||
- ***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 for more information
|
- ***error***: An error occured, check the event's **details** property for more information
|
||||||
***delete***: Delete self and free resources
|
- ***delete***: Delete self and free resources
|
||||||
## 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:
|
||||||
|
|
||||||
```
|
```
|
||||||
__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).
|
||||||
|
- If you choose to use this on the main thread, always handle the API through events
|
||||||
### Guarantees
|
### Guarantees
|
||||||
If an error occurs (error event is fired), no changes was made, and no other dependent events will fire.
|
- 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.
|
||||||
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:
|
||||||
- Only works on main thread
|
|
||||||
- Microphone only
|
- Microphone only
|
||||||
- Fixed memory size at 300MB, changing it require recompilation
|
- Fixed memory size at 300MB, changing it require recompilation
|
||||||
### Additions to vosk-browser:
|
### Additions to vosk-browser:
|
||||||
@@ -67,5 +68,5 @@ For example, if an error occur while loading the model, the "ready" event won't
|
|||||||
## Usage
|
## Usage
|
||||||
```
|
```
|
||||||
<!--Load this from a script tag-->
|
<!--Load this from a script tag-->
|
||||||
<script src="BrowserRecognizer.js">
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
if(typeof window === 'undefined') {
|
if(typeof window === 'undefined') {
|
||||||
self.addEventListener("install", () => self.skipWaiting());
|
self.addEventListener("install", () => self.skipWaiting());
|
||||||
self.addEventListener("activate", e => e.waitUntil(self.clients.claim()));
|
self.addEventListener("activate", e => e.waitUntil(self.clients.claim()));
|
||||||
|
|
||||||
async function handleFetch(request) {
|
async function handleFetch(request) {
|
||||||
if(request.cache === "only-if-cached" && request.mode !== "same-origin") {
|
if(request.cache === "only-if-cached" && request.mode !== "same-origin") {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -2,25 +2,23 @@
|
|||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "recognizer.h"
|
#include "recognizer.h"
|
||||||
using namespace emscripten;
|
using namespace emscripten;
|
||||||
|
EMSCRIPTEN_BINDINGS() {
|
||||||
EMSCRIPTEN_BINDINGS(BrowserRecognizer) {
|
|
||||||
function("setLogLevel", &vosk_set_log_level, allow_raw_pointers());
|
function("setLogLevel", &vosk_set_log_level, allow_raw_pointers());
|
||||||
|
class_<model, base<genericModel>>("__model__")
|
||||||
class_<Model>("__Model__")
|
|
||||||
.constructor<std::string, std::string, std::string, int>(allow_raw_pointers());
|
.constructor<std::string, std::string, std::string, int>(allow_raw_pointers());
|
||||||
|
|
||||||
class_<SpkModel>("__SpkModel__")
|
class_<spkModel, base<genericModel>>("__spkModel__")
|
||||||
.constructor<std::string, std::string, std::string, const int>(allow_raw_pointers());
|
.constructor<std::string, std::string, std::string, const int>(allow_raw_pointers());
|
||||||
|
|
||||||
class_<Recognizer>("__Recognizer__")
|
class_<recognizer, base<genericObj>>("__recognizer__")
|
||||||
.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("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())
|
||||||
.function("setNLSML", &Recognizer::setNLSML, allow_raw_pointers())
|
.function("setNLSML", &recognizer::setNLSML, allow_raw_pointers())
|
||||||
.function("setSpkModel", &Recognizer::setSpkModel, allow_raw_pointers())
|
.function("setSpkModel", &recognizer::setSpkModel, allow_raw_pointers())
|
||||||
.function("setMaxAlternatives", &Recognizer::setMaxAlternatives, allow_raw_pointers());
|
.function("setMaxAlternatives", &recognizer::setMaxAlternatives, allow_raw_pointers());
|
||||||
};
|
};
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
#include "genericModel.h"
|
#include "genericModel.h"
|
||||||
|
|
||||||
bool GenericModel::first = true;
|
bool genericModel::first = true;
|
||||||
GenericModel::GenericModel(const std::string &url, const std::string& storepath, const std::string &id, int index) : url(url), id(id), storepath(("opfs/" + storepath)), 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(storepath);
|
||||||
if(first) {
|
if(first) {
|
||||||
vosk_set_log_level(-1);
|
vosk_set_log_level(0);
|
||||||
int res{};
|
int res{};
|
||||||
std::thread t{[&res](){
|
std::thread t{[&res](){
|
||||||
res = wasmfs_create_directory("opfs",0777,wasmfs_create_opfs_backend());
|
res = wasmfs_create_directory("opfs",0777,wasmfs_create_opfs_backend());
|
||||||
@@ -16,8 +17,8 @@ GenericModel::GenericModel(const std::string &url, const std::string& storepath,
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool GenericModel::checkId(const std::string& path, const std::string& id) {
|
bool genericModel::checkId(const std::string& id) {
|
||||||
std::ifstream file {(path + "/id"), std::ifstream::binary};
|
std::ifstream file {"id", std::ifstream::binary};
|
||||||
if(!file.is_open()) {
|
if(!file.is_open()) {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -27,36 +28,36 @@ bool GenericModel::checkId(const std::string& path, 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() {
|
||||||
if(!checkModel(storepath) || !checkId(storepath, id)) {
|
if(!checkModel() || !checkId(id)) {
|
||||||
if(emscripten_wget(url.c_str(),"opfs/model.tzst") == 1) {
|
if(emscripten_wget(url.c_str(),"opfs/model.tzst") == 1) {
|
||||||
fireEv("error", "Unable to fetch model");
|
fireEv("error", "Unable to fetch model");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(!extractModel("opfs/model.tzst", storepath)) {
|
if(!extractModel("opfs/model.tzst", ".")) {
|
||||||
fireEv("error", "Unable to extract model");
|
fireEv("error", "Unable to extract model");
|
||||||
}
|
}
|
||||||
fs::remove("opfs/model.tzst");
|
fs::remove("opfs/model.tzst");
|
||||||
if(!checkModel(storepath)) {
|
if(!checkModel()) {
|
||||||
fireEv("error", "Model URL contains invalid model files");
|
fireEv("error", "Model URL contains invalid model files");
|
||||||
}
|
}
|
||||||
std::ofstream idFile((storepath + "/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(storepath);
|
fs::remove_all(".");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
idFile << id;
|
idFile << id;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool GenericModel::extractModel(const char* target, const std::string& dest) {
|
bool genericModel::extractModel(const char* target, const std::string& dest) {
|
||||||
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, target,22480);
|
archive_read_open_filename(src, ".",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);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#include "genericObj.h"
|
#include "genericObj.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
@@ -14,15 +13,13 @@
|
|||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
class GenericModel : public GenericObj {
|
struct genericModel : genericObj {
|
||||||
static bool first;
|
static bool first;
|
||||||
const std::string url{};
|
const std::string url{};
|
||||||
const std::string id{};
|
const std::string id{};
|
||||||
static bool extractModel(const char* target, const std::string& dest);
|
static bool extractModel(const char* target, const std::string& dest);
|
||||||
static bool checkId(const std::string& path, const std::string& id);
|
static bool checkId(const std::string& id);
|
||||||
public:
|
virtual bool checkModel() = 0;
|
||||||
const std::string storepath{};
|
|
||||||
virtual bool checkModel(const std::string& path) = 0;
|
|
||||||
bool loadModel();
|
bool loadModel();
|
||||||
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);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#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) {
|
if(content == nullptr) {
|
||||||
MAIN_THREAD_EM_ASM({
|
EM_ASM({
|
||||||
__GenericObj__.objects[$0].dispatchEvent(new Event(UTF8ToString($1)));
|
__genericObj__.objects[$0].dispatchEvent(new Event(UTF8ToString($1)));
|
||||||
},this->index, type);
|
},this->index, type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MAIN_THREAD_EM_ASM({
|
EM_ASM({
|
||||||
__GenericObj__.objects[$0].dispatchEvent(new CustomEvent(UTF8ToString($0), {"details" : UTF8ToString($1)}));
|
__genericObj__.objects[$0].dispatchEvent(new CustomEvent(UTF8ToString($0), {"details" : UTF8ToString($1)}));
|
||||||
},this->index, type, content);
|
},this->index, type, content);
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <emscripten.h>
|
|
||||||
|
|
||||||
class GenericObj {
|
#include <emscripten.h>
|
||||||
|
#include <emscripten/console.h>
|
||||||
|
|
||||||
|
struct genericObj {
|
||||||
const int index{};
|
const int index{};
|
||||||
public:
|
genericObj(int index) : index(index) {};
|
||||||
GenericObj(int index) : index(index) {};
|
|
||||||
void fireEv(const char *type, const char *content = nullptr);
|
void fireEv(const char *type, const char *content = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
class __GenericObj__ {static objects = []}
|
class __genericObj__ {static objects = []}
|
||||||
34
src/model.cc
34
src/model.cc
@@ -1,27 +1,27 @@
|
|||||||
#include "model.h"
|
#include "model.h"
|
||||||
|
|
||||||
Model::Model(const std::string &url, const std::string& storepath, const std::string& id, int index) : GenericModel(url, storepath, id, 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()) return;
|
||||||
model = vosk_model_new(this->storepath.c_str());
|
mdl = vosk_model_new(".");
|
||||||
if(model == nullptr) {
|
if(mdl == nullptr) {
|
||||||
fireEv("error", "Unable to initialize model");
|
fireEv("error", "Unable to initialize model");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fireEv("ready");
|
fireEv("ready");
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Model::checkModel(const std::string& path) {
|
bool model::checkModel() {
|
||||||
return fs::exists(path + "/am/final.mdl") &&
|
return fs::exists("am/final.mdl") &&
|
||||||
fs::exists(path + "/conf/mfcc.conf") &&
|
fs::exists("conf/mfcc.conf") &&
|
||||||
fs::exists(path + "/conf/model.conf") &&
|
fs::exists("conf/model.conf") &&
|
||||||
fs::exists(path + "/graph/phones/word_boundary.int") &&
|
fs::exists("graph/phones/word_boundary.int") &&
|
||||||
fs::exists(path + "/graph/Gr.fst") &&
|
fs::exists("graph/Gr.fst") &&
|
||||||
fs::exists(path + "/graph/HCLr.fst") &&
|
fs::exists("graph/HCLr.fst") &&
|
||||||
fs::exists(path + "/graph/disambig_tid.int") &&
|
fs::exists("graph/disambig_tid.int") &&
|
||||||
fs::exists(path + "/ivector/final.dubm") &&
|
fs::exists("ivector/final.dubm") &&
|
||||||
fs::exists(path + "/ivector/final.ie") &&
|
fs::exists("ivector/final.ie") &&
|
||||||
fs::exists(path + "/ivector/final.mat") &&
|
fs::exists("ivector/final.mat") &&
|
||||||
fs::exists(path + "/ivector/global_cmvn.stats") &&
|
fs::exists("ivector/global_cmvn.stats") &&
|
||||||
fs::exists(path + "/ivector/online_cmvn.conf") &&
|
fs::exists("ivector/online_cmvn.conf") &&
|
||||||
fs::exists(path + "/ivector/splice.conf");
|
fs::exists("ivector/splice.conf");
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "genericModel.h"
|
#include "genericModel.h"
|
||||||
|
|
||||||
class Model : public GenericModel {
|
struct model : genericModel {
|
||||||
bool checkModel(const std::string& path);
|
bool checkModel();
|
||||||
public:
|
VoskModel* mdl{};
|
||||||
VoskModel* model{};
|
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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
class Model extends EventTarget{
|
class Model extends EventTarget{
|
||||||
constructor(url, storepath, id) {
|
constructor(url, storepath, id) {
|
||||||
super()
|
super()
|
||||||
this.obj = new Module.__Model__(url, storepath, id, __GenericObj__.objects.length)
|
this.obj = (async () => {
|
||||||
__GenericObj__.objects.push(this)
|
return new Module.__model__(url, storepath, id, __genericObj__.objects.length)
|
||||||
|
})()
|
||||||
|
__genericObj__.objects.push(this)
|
||||||
}
|
}
|
||||||
delete() {
|
delete() {
|
||||||
|
this.obj.then(() => {
|
||||||
this.obj.delete()
|
this.obj.delete()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,34 +1,31 @@
|
|||||||
#include "./recognizer.h"
|
#include "./recognizer.h"
|
||||||
void Recognizer::start() {
|
void recognizer::start() {
|
||||||
controller.test_and_set(std::memory_order_relaxed);
|
controller.test_and_set(std::memory_order_relaxed);
|
||||||
controller.notify_all();
|
controller.notify_all();
|
||||||
}
|
}
|
||||||
void Recognizer::stop() {
|
void recognizer::stop() {
|
||||||
controller.clear(std::memory_order_relaxed);
|
controller.clear(std::memory_order_relaxed);
|
||||||
controller.notify_all();
|
controller.notify_all();
|
||||||
}
|
}
|
||||||
void Recognizer::deinit() {
|
void recognizer::deinit() {
|
||||||
done.test_and_set(std::memory_order_relaxed);
|
done.test_and_set(std::memory_order_relaxed);
|
||||||
done.notify_all();
|
done.notify_all();
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
Recognizer::Recognizer(Model* model, 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) {
|
||||||
fireEv("error", "Unable to initialize microphone");
|
fireEv("error", "Unable to initialize microphone");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::thread t{[this](Model* model, int sampleRate) {
|
rec = vosk_recognizer_new(mdl->mdl,static_cast<float>(sampleRate));
|
||||||
recognizer = vosk_recognizer_new(model->model,static_cast<float>(sampleRate));
|
if(rec == nullptr) {
|
||||||
if(recognizer == nullptr) {
|
|
||||||
fireEv("error", "Unable to construct recognizer");
|
fireEv("error", "Unable to construct recognizer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
main();
|
main();
|
||||||
}, model, sampleRate};
|
|
||||||
t.detach();
|
|
||||||
}
|
}
|
||||||
void Recognizer::main() {
|
void recognizer::main() {
|
||||||
char buffer[22480];
|
char buffer[22480];
|
||||||
int sample{};
|
int sample{};
|
||||||
fireEv("ready");
|
fireEv("ready");
|
||||||
@@ -38,12 +35,12 @@ void Recognizer::main() {
|
|||||||
while(controller.test()) {
|
while(controller.test()) {
|
||||||
alcGetIntegerv(mic, ALC_CAPTURE_SAMPLES, sizeof(int), &sample);
|
alcGetIntegerv(mic, ALC_CAPTURE_SAMPLES, sizeof(int), &sample);
|
||||||
alcCaptureSamples(mic, buffer, sample);
|
alcCaptureSamples(mic, buffer, sample);
|
||||||
switch(vosk_recognizer_accept_waveform(recognizer, buffer, 22480)) {
|
switch(vosk_recognizer_accept_waveform(rec, buffer, 22480)) {
|
||||||
case 0:
|
case 0:
|
||||||
fireEv("result", vosk_recognizer_result(recognizer));
|
fireEv("result", vosk_recognizer_result(rec));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
fireEv("partialResult", vosk_recognizer_partial_result(recognizer));
|
fireEv("partialResult", vosk_recognizer_partial_result(rec));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fireEv("error", "Recognition result error");
|
fireEv("error", "Recognition result error");
|
||||||
@@ -51,24 +48,24 @@ void Recognizer::main() {
|
|||||||
}
|
}
|
||||||
alcCaptureStop(mic);
|
alcCaptureStop(mic);
|
||||||
}
|
}
|
||||||
vosk_recognizer_free(recognizer);
|
vosk_recognizer_free(rec);
|
||||||
alcCaptureCloseDevice(mic);
|
alcCaptureCloseDevice(mic);
|
||||||
}
|
}
|
||||||
void Recognizer::setGrm(const std::string& grm) {
|
void recognizer::setGrm(const std::string& grm) {
|
||||||
vosk_recognizer_set_grm(recognizer, grm.c_str());
|
vosk_recognizer_set_grm(rec, grm.c_str());
|
||||||
}
|
}
|
||||||
void Recognizer::setSpkModel(SpkModel* model) {
|
void recognizer::setSpkModel(spkModel* mdl) {
|
||||||
vosk_recognizer_set_spk_model(recognizer,model->model);
|
vosk_recognizer_set_spk_model(rec, mdl->mdl);
|
||||||
}
|
}
|
||||||
void Recognizer::setWords(bool words) {
|
void recognizer::setWords(bool words) {
|
||||||
vosk_recognizer_set_words(recognizer,words);
|
vosk_recognizer_set_words(rec,words);
|
||||||
}
|
}
|
||||||
void Recognizer::setPartialWords(bool partialWords) {
|
void recognizer::setPartialWords(bool partialWords) {
|
||||||
vosk_recognizer_set_partial_words(recognizer, partialWords);
|
vosk_recognizer_set_partial_words(rec, partialWords);
|
||||||
}
|
}
|
||||||
void Recognizer::setNLSML(bool nlsml) {
|
void recognizer::setNLSML(bool nlsml) {
|
||||||
vosk_recognizer_set_nlsml(recognizer, nlsml);
|
vosk_recognizer_set_nlsml(rec, nlsml);
|
||||||
}
|
}
|
||||||
void Recognizer::setMaxAlternatives(int alts) {
|
void recognizer::setMaxAlternatives(int alts) {
|
||||||
vosk_recognizer_set_max_alternatives(recognizer, alts);
|
vosk_recognizer_set_max_alternatives(rec, alts);
|
||||||
}
|
}
|
||||||
@@ -16,18 +16,17 @@
|
|||||||
#include <archive_entry.h>
|
#include <archive_entry.h>
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
class Recognizer : public GenericObj {
|
struct recognizer : genericObj {
|
||||||
VoskRecognizer* recognizer{};
|
VoskRecognizer* rec{};
|
||||||
ALCdevice* mic{};
|
ALCdevice* mic{};
|
||||||
std::atomic_flag done {false};
|
std::atomic_flag done {false};
|
||||||
std::atomic_flag controller{false};
|
std::atomic_flag controller{false};
|
||||||
void main();
|
void main();
|
||||||
public:
|
recognizer(model* model, int sampleRate, int index);
|
||||||
Recognizer(Model* model, int sampleRate, int index);
|
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
void deinit();
|
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);
|
||||||
void setPartialWords(bool partialWords);
|
void setPartialWords(bool partialWords);
|
||||||
|
|||||||
@@ -1,36 +1,57 @@
|
|||||||
class Recognizer extends EventTarget {
|
class Recognizer extends EventTarget {
|
||||||
constructor(model) {
|
constructor(model) {
|
||||||
ctx = new (AudioContext || webkitAudioContext)()
|
ctx = new (AudioContext || webkitAudioContext)()
|
||||||
this.obj = new Module.__Recognizer__(model.obj,ctx.sampleRate,__GenericObj__.objects.length)
|
this.obj = (async () => {
|
||||||
__GenericObj__.objects.push(this)
|
new Module.__recognizer__(model.obj,ctx.sampleRate,__genericObj__.objects.length)
|
||||||
|
})()
|
||||||
|
__genericObj__.objects.push(this)
|
||||||
ctx.close()
|
ctx.close()
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
start() {
|
start() {
|
||||||
|
this.obj.then(() => {
|
||||||
this.obj.start()
|
this.obj.start()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
stop() {
|
stop() {
|
||||||
|
this.obj.then(() => {
|
||||||
this.obj.stop()
|
this.obj.stop()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
delete() {
|
delete() {
|
||||||
|
this.obj.then(() => {
|
||||||
this.obj.deinit()
|
this.obj.deinit()
|
||||||
this.obj.delete()
|
this.obj.delete()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setWords(words) {
|
setWords(words) {
|
||||||
|
this.obj.then(() => {
|
||||||
this.obj.setWords(words)
|
this.obj.setWords(words)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setPartialWords(partialWords) {
|
setPartialWords(partialWords) {
|
||||||
this.obj.setPartialWords(words)
|
this.obj.then(() => {
|
||||||
|
this.obj.setPartialWords(partialWords)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setGrm(grm) {
|
setGrm(grm) {
|
||||||
|
this.obj.then(() => {
|
||||||
this.obj.setGrm(grm)
|
this.obj.setGrm(grm)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setSpkModel(model) {
|
setSpkModel(model) {
|
||||||
|
this.obj.then(() => {
|
||||||
this.obj.setSpkModel(model.obj)
|
this.obj.setSpkModel(model.obj)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setNLSML(nlsml) {
|
setNLSML(nlsml) {
|
||||||
|
this.obj.then(() => {
|
||||||
this.obj.setNLSML(nlsml)
|
this.obj.setNLSML(nlsml)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
setMaxAlternatives(alts) {
|
setMaxAlternatives(alts) {
|
||||||
|
this.obj.then(() => {
|
||||||
this.obj.setMaxAlternatives(alts)
|
this.obj.setMaxAlternatives(alts)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +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()) return;
|
||||||
model = vosk_spk_model_new(this->storepath.c_str());
|
mdl = vosk_spk_model_new(".");
|
||||||
if(model == nullptr) {
|
if(mdl == nullptr) {
|
||||||
fireEv("error", "Unable to initialize speaker model");
|
fireEv("error", "Unable to initialize speaker model");
|
||||||
}
|
}
|
||||||
fireEv("ready");
|
fireEv("ready");
|
||||||
};
|
};
|
||||||
bool SpkModel::checkModel(const std::string& path) {
|
bool spkModel::checkModel() {
|
||||||
return fs::exists((path + "/mfcc.conf")) &&
|
return fs::exists("mfcc.conf") &&
|
||||||
fs::exists((path + "/final.ext.raw")) &&
|
fs::exists("final.ext.raw") &&
|
||||||
fs::exists((path + "/mean.vec")) &&
|
fs::exists("mean.vec") &&
|
||||||
fs::exists((path + "/transform.mat"));
|
fs::exists("transform.mat");
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "genericModel.h"
|
#include "genericModel.h"
|
||||||
|
|
||||||
class SpkModel : public GenericModel {
|
struct spkModel : genericModel {
|
||||||
bool checkModel(const std::string& path);
|
bool checkModel();
|
||||||
public:
|
spkModel(const std::string &url, const std::string& storepath, const std::string& id, const int index);
|
||||||
SpkModel(const std::string &url, const std::string& storepath, const std::string& id, const int index);
|
VoskSpkModel* mdl{};
|
||||||
VoskSpkModel* model{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
class SpkModel extends EventTarget{
|
class SpkModel extends EventTarget{
|
||||||
constructor(url, storepath, id) {
|
constructor(url, storepath, id) {
|
||||||
super()
|
super()
|
||||||
this.obj = new Module.__SpkModel__(url, storepath, id, __GenericObj__.objects.length)
|
this.obj = (async () => {
|
||||||
__GenericObj__.objects.push(this)
|
return new Module.__spkModel__(url, storepath, id, __genericObj__.objects.length)
|
||||||
|
})()
|
||||||
|
__genericObj__.objects.push(this)
|
||||||
}
|
}
|
||||||
delete() {
|
delete() {
|
||||||
|
this.obj.then(() => {
|
||||||
this.obj.delete()
|
this.obj.delete()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
19
test.cc
Normal file
19
test.cc
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include <emscripten.h>
|
||||||
|
#include <emscripten/console.h>
|
||||||
|
#include <emscripten/bind.h>
|
||||||
|
using namespace emscripten;
|
||||||
|
struct A {
|
||||||
|
void doit() {
|
||||||
|
char bro[] {"Bro"};
|
||||||
|
MAIN_THREAD_EM_ASM({
|
||||||
|
console.log(UTF8ToString($0));
|
||||||
|
},bro);
|
||||||
|
}
|
||||||
|
~A() {
|
||||||
|
emscripten_console_log("Destructor called");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
EMSCRIPTEN_BINDINGS() {
|
||||||
|
class_<A>("A")
|
||||||
|
.smart_ptr_constructor<
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user