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
|
||||
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
|
||||
- setLogLevel: set Kaldi's log level (default: -1)
|
||||
- -2: Error
|
||||
@@ -39,19 +40,19 @@ new Recognizer(model)
|
||||
- ***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
|
||||
- ***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
|
||||
### 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).
|
||||
- If you choose to use this on the main thread, always handle the API through events
|
||||
### Guarantees
|
||||
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.
|
||||
- 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.
|
||||
### Limitations compared to vosk-browser:
|
||||
- Only works on main thread
|
||||
- Microphone only
|
||||
- Fixed memory size at 300MB, changing it require recompilation
|
||||
### Additions to vosk-browser:
|
||||
@@ -67,5 +68,5 @@ For example, if an error occur while loading the model, the "ready" event won't
|
||||
## Usage
|
||||
```
|
||||
<!--Load this from a script tag-->
|
||||
<script src="BrowserRecognizer.js">
|
||||
|
||||
```
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
if(typeof window === 'undefined') {
|
||||
self.addEventListener("install", () => self.skipWaiting());
|
||||
self.addEventListener("activate", e => e.waitUntil(self.clients.claim()));
|
||||
|
||||
async function handleFetch(request) {
|
||||
if(request.cache === "only-if-cached" && request.mode !== "same-origin") {
|
||||
return;
|
||||
|
||||
@@ -2,25 +2,23 @@
|
||||
#include "model.h"
|
||||
#include "recognizer.h"
|
||||
using namespace emscripten;
|
||||
|
||||
EMSCRIPTEN_BINDINGS(BrowserRecognizer) {
|
||||
EMSCRIPTEN_BINDINGS() {
|
||||
function("setLogLevel", &vosk_set_log_level, allow_raw_pointers());
|
||||
|
||||
class_<Model>("__Model__")
|
||||
class_<model, base<genericModel>>("__model__")
|
||||
.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());
|
||||
|
||||
class_<Recognizer>("__Recognizer__")
|
||||
.constructor<Model*, int, int>(allow_raw_pointers())
|
||||
.function("start", &Recognizer::start, allow_raw_pointers())
|
||||
.function("stop", &Recognizer::stop, allow_raw_pointers())
|
||||
.function("deinit", &Recognizer::deinit, 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())
|
||||
.function("setSpkModel", &Recognizer::setSpkModel, allow_raw_pointers())
|
||||
.function("setMaxAlternatives", &Recognizer::setMaxAlternatives, allow_raw_pointers());
|
||||
class_<recognizer, base<genericObj>>("__recognizer__")
|
||||
.constructor<model*, int, int>(allow_raw_pointers())
|
||||
.function("start", &recognizer::start, allow_raw_pointers())
|
||||
.function("stop", &recognizer::stop, allow_raw_pointers())
|
||||
.function("deinit", &recognizer::deinit, 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())
|
||||
.function("setSpkModel", &recognizer::setSpkModel, allow_raw_pointers())
|
||||
.function("setMaxAlternatives", &recognizer::setMaxAlternatives, allow_raw_pointers());
|
||||
};
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "genericModel.h"
|
||||
|
||||
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) {
|
||||
bool genericModel::first = true;
|
||||
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) {
|
||||
vosk_set_log_level(-1);
|
||||
vosk_set_log_level(0);
|
||||
int res{};
|
||||
std::thread t{[&res](){
|
||||
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;
|
||||
}
|
||||
}
|
||||
bool GenericModel::checkId(const std::string& path, const std::string& id) {
|
||||
std::ifstream file {(path + "/id"), std::ifstream::binary};
|
||||
bool genericModel::checkId(const std::string& id) {
|
||||
std::ifstream file {"id", std::ifstream::binary};
|
||||
if(!file.is_open()) {
|
||||
return false;
|
||||
};
|
||||
@@ -27,36 +28,36 @@ bool GenericModel::checkId(const std::string& path, const std::string& id) {
|
||||
file.read(&oldid[0], size);
|
||||
return id.compare(oldid) == 0 ? true : false;
|
||||
}
|
||||
bool GenericModel::loadModel() {
|
||||
if(!checkModel(storepath) || !checkId(storepath, id)) {
|
||||
bool genericModel::loadModel() {
|
||||
if(!checkModel() || !checkId(id)) {
|
||||
if(emscripten_wget(url.c_str(),"opfs/model.tzst") == 1) {
|
||||
fireEv("error", "Unable to fetch model");
|
||||
return false;
|
||||
}
|
||||
if(!extractModel("opfs/model.tzst", storepath)) {
|
||||
if(!extractModel("opfs/model.tzst", ".")) {
|
||||
fireEv("error", "Unable to extract model");
|
||||
}
|
||||
fs::remove("opfs/model.tzst");
|
||||
if(!checkModel(storepath)) {
|
||||
if(!checkModel()) {
|
||||
fireEv("error", "Model URL contains invalid model files");
|
||||
}
|
||||
std::ofstream idFile((storepath + "/id"));
|
||||
std::ofstream idFile("id");
|
||||
if(!idFile.is_open()) {
|
||||
fireEv("error", "Unable to write new id");
|
||||
fs::remove_all(storepath);
|
||||
fs::remove_all(".");
|
||||
return false;
|
||||
}
|
||||
idFile << id;
|
||||
}
|
||||
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{};
|
||||
archive* src {archive_read_new()};
|
||||
archive_entry* entry {};
|
||||
archive_read_support_filter_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;
|
||||
while (archive_read_next_header(src, &entry) == ARCHIVE_OK) {
|
||||
path = archive_entry_pathname(entry);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "genericObj.h"
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
@@ -14,15 +13,13 @@
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class GenericModel : public GenericObj {
|
||||
struct genericModel : genericObj {
|
||||
static bool first;
|
||||
const std::string url{};
|
||||
const std::string id{};
|
||||
static bool extractModel(const char* target, const std::string& dest);
|
||||
static bool checkId(const std::string& path, const std::string& id);
|
||||
public:
|
||||
const std::string storepath{};
|
||||
virtual bool checkModel(const std::string& path) = 0;
|
||||
static bool checkId(const std::string& id);
|
||||
virtual bool checkModel() = 0;
|
||||
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"
|
||||
|
||||
void GenericObj::fireEv(const char *type, const char *content) {
|
||||
void genericObj::fireEv(const char *type, const char *content) {
|
||||
if(content == nullptr) {
|
||||
MAIN_THREAD_EM_ASM({
|
||||
__GenericObj__.objects[$0].dispatchEvent(new Event(UTF8ToString($1)));
|
||||
EM_ASM({
|
||||
__genericObj__.objects[$0].dispatchEvent(new Event(UTF8ToString($1)));
|
||||
},this->index, type);
|
||||
return;
|
||||
}
|
||||
MAIN_THREAD_EM_ASM({
|
||||
__GenericObj__.objects[$0].dispatchEvent(new CustomEvent(UTF8ToString($0), {"details" : UTF8ToString($1)}));
|
||||
EM_ASM({
|
||||
__genericObj__.objects[$0].dispatchEvent(new CustomEvent(UTF8ToString($0), {"details" : UTF8ToString($1)}));
|
||||
},this->index, type, content);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
#include <emscripten.h>
|
||||
|
||||
class GenericObj {
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/console.h>
|
||||
|
||||
struct genericObj {
|
||||
const int index{};
|
||||
public:
|
||||
GenericObj(int index) : index(index) {};
|
||||
genericObj(int index) : index(index) {};
|
||||
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"
|
||||
|
||||
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;
|
||||
model = vosk_model_new(this->storepath.c_str());
|
||||
if(model == nullptr) {
|
||||
mdl = vosk_model_new(".");
|
||||
if(mdl == nullptr) {
|
||||
fireEv("error", "Unable to initialize model");
|
||||
return;
|
||||
}
|
||||
fireEv("ready");
|
||||
};
|
||||
|
||||
bool Model::checkModel(const std::string& path) {
|
||||
return fs::exists(path + "/am/final.mdl") &&
|
||||
fs::exists(path + "/conf/mfcc.conf") &&
|
||||
fs::exists(path + "/conf/model.conf") &&
|
||||
fs::exists(path + "/graph/phones/word_boundary.int") &&
|
||||
fs::exists(path + "/graph/Gr.fst") &&
|
||||
fs::exists(path + "/graph/HCLr.fst") &&
|
||||
fs::exists(path + "/graph/disambig_tid.int") &&
|
||||
fs::exists(path + "/ivector/final.dubm") &&
|
||||
fs::exists(path + "/ivector/final.ie") &&
|
||||
fs::exists(path + "/ivector/final.mat") &&
|
||||
fs::exists(path + "/ivector/global_cmvn.stats") &&
|
||||
fs::exists(path + "/ivector/online_cmvn.conf") &&
|
||||
fs::exists(path + "/ivector/splice.conf");
|
||||
bool model::checkModel() {
|
||||
return fs::exists("am/final.mdl") &&
|
||||
fs::exists("conf/mfcc.conf") &&
|
||||
fs::exists("conf/model.conf") &&
|
||||
fs::exists("graph/phones/word_boundary.int") &&
|
||||
fs::exists("graph/Gr.fst") &&
|
||||
fs::exists("graph/HCLr.fst") &&
|
||||
fs::exists("graph/disambig_tid.int") &&
|
||||
fs::exists("ivector/final.dubm") &&
|
||||
fs::exists("ivector/final.ie") &&
|
||||
fs::exists("ivector/final.mat") &&
|
||||
fs::exists("ivector/global_cmvn.stats") &&
|
||||
fs::exists("ivector/online_cmvn.conf") &&
|
||||
fs::exists("ivector/splice.conf");
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
#pragma once
|
||||
#include "genericModel.h"
|
||||
|
||||
class Model : public GenericModel {
|
||||
bool checkModel(const std::string& path);
|
||||
public:
|
||||
VoskModel* model{};
|
||||
Model(const std::string &url, const std::string& storepath, const std::string& id, int index);
|
||||
struct model : genericModel {
|
||||
bool checkModel();
|
||||
VoskModel* mdl{};
|
||||
model(const std::string &url, const std::string& storepath, const std::string& id, int index);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
class Model extends EventTarget{
|
||||
constructor(url, storepath, id) {
|
||||
super()
|
||||
this.obj = new Module.__Model__(url, storepath, id, __GenericObj__.objects.length)
|
||||
__GenericObj__.objects.push(this)
|
||||
this.obj = (async () => {
|
||||
return new Module.__model__(url, storepath, id, __genericObj__.objects.length)
|
||||
})()
|
||||
__genericObj__.objects.push(this)
|
||||
}
|
||||
delete() {
|
||||
this.obj.then(() => {
|
||||
this.obj.delete()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,31 @@
|
||||
#include "./recognizer.h"
|
||||
void Recognizer::start() {
|
||||
void recognizer::start() {
|
||||
controller.test_and_set(std::memory_order_relaxed);
|
||||
controller.notify_all();
|
||||
}
|
||||
void Recognizer::stop() {
|
||||
void recognizer::stop() {
|
||||
controller.clear(std::memory_order_relaxed);
|
||||
controller.notify_all();
|
||||
}
|
||||
void Recognizer::deinit() {
|
||||
void recognizer::deinit() {
|
||||
done.test_and_set(std::memory_order_relaxed);
|
||||
done.notify_all();
|
||||
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);
|
||||
if(alcGetError(mic) != 0) {
|
||||
fireEv("error", "Unable to initialize microphone");
|
||||
return;
|
||||
}
|
||||
std::thread t{[this](Model* model, int sampleRate) {
|
||||
recognizer = vosk_recognizer_new(model->model,static_cast<float>(sampleRate));
|
||||
if(recognizer == nullptr) {
|
||||
rec = vosk_recognizer_new(mdl->mdl,static_cast<float>(sampleRate));
|
||||
if(rec == nullptr) {
|
||||
fireEv("error", "Unable to construct recognizer");
|
||||
return;
|
||||
}
|
||||
main();
|
||||
}, model, sampleRate};
|
||||
t.detach();
|
||||
}
|
||||
void Recognizer::main() {
|
||||
void recognizer::main() {
|
||||
char buffer[22480];
|
||||
int sample{};
|
||||
fireEv("ready");
|
||||
@@ -38,12 +35,12 @@ void Recognizer::main() {
|
||||
while(controller.test()) {
|
||||
alcGetIntegerv(mic, ALC_CAPTURE_SAMPLES, sizeof(int), &sample);
|
||||
alcCaptureSamples(mic, buffer, sample);
|
||||
switch(vosk_recognizer_accept_waveform(recognizer, buffer, 22480)) {
|
||||
switch(vosk_recognizer_accept_waveform(rec, buffer, 22480)) {
|
||||
case 0:
|
||||
fireEv("result", vosk_recognizer_result(recognizer));
|
||||
fireEv("result", vosk_recognizer_result(rec));
|
||||
break;
|
||||
case 1:
|
||||
fireEv("partialResult", vosk_recognizer_partial_result(recognizer));
|
||||
fireEv("partialResult", vosk_recognizer_partial_result(rec));
|
||||
break;
|
||||
default:
|
||||
fireEv("error", "Recognition result error");
|
||||
@@ -51,24 +48,24 @@ void Recognizer::main() {
|
||||
}
|
||||
alcCaptureStop(mic);
|
||||
}
|
||||
vosk_recognizer_free(recognizer);
|
||||
vosk_recognizer_free(rec);
|
||||
alcCaptureCloseDevice(mic);
|
||||
}
|
||||
void Recognizer::setGrm(const std::string& grm) {
|
||||
vosk_recognizer_set_grm(recognizer, grm.c_str());
|
||||
void recognizer::setGrm(const std::string& grm) {
|
||||
vosk_recognizer_set_grm(rec, grm.c_str());
|
||||
}
|
||||
void Recognizer::setSpkModel(SpkModel* model) {
|
||||
vosk_recognizer_set_spk_model(recognizer,model->model);
|
||||
void recognizer::setSpkModel(spkModel* mdl) {
|
||||
vosk_recognizer_set_spk_model(rec, mdl->mdl);
|
||||
}
|
||||
void Recognizer::setWords(bool words) {
|
||||
vosk_recognizer_set_words(recognizer,words);
|
||||
void recognizer::setWords(bool words) {
|
||||
vosk_recognizer_set_words(rec,words);
|
||||
}
|
||||
void Recognizer::setPartialWords(bool partialWords) {
|
||||
vosk_recognizer_set_partial_words(recognizer, partialWords);
|
||||
void recognizer::setPartialWords(bool partialWords) {
|
||||
vosk_recognizer_set_partial_words(rec, partialWords);
|
||||
}
|
||||
void Recognizer::setNLSML(bool nlsml) {
|
||||
vosk_recognizer_set_nlsml(recognizer, nlsml);
|
||||
void recognizer::setNLSML(bool nlsml) {
|
||||
vosk_recognizer_set_nlsml(rec, nlsml);
|
||||
}
|
||||
void Recognizer::setMaxAlternatives(int alts) {
|
||||
vosk_recognizer_set_max_alternatives(recognizer, alts);
|
||||
void recognizer::setMaxAlternatives(int alts) {
|
||||
vosk_recognizer_set_max_alternatives(rec, alts);
|
||||
}
|
||||
@@ -16,18 +16,17 @@
|
||||
#include <archive_entry.h>
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class Recognizer : public GenericObj {
|
||||
VoskRecognizer* recognizer{};
|
||||
struct recognizer : genericObj {
|
||||
VoskRecognizer* rec{};
|
||||
ALCdevice* mic{};
|
||||
std::atomic_flag done {false};
|
||||
std::atomic_flag controller{false};
|
||||
void main();
|
||||
public:
|
||||
Recognizer(Model* model, int sampleRate, int index);
|
||||
recognizer(model* model, int sampleRate, int index);
|
||||
void start();
|
||||
void stop();
|
||||
void deinit();
|
||||
void setSpkModel(SpkModel* model);
|
||||
void setSpkModel(spkModel* model);
|
||||
void setGrm(const std::string& grm);
|
||||
void setWords(bool words);
|
||||
void setPartialWords(bool partialWords);
|
||||
|
||||
@@ -1,36 +1,57 @@
|
||||
class Recognizer extends EventTarget {
|
||||
constructor(model) {
|
||||
ctx = new (AudioContext || webkitAudioContext)()
|
||||
this.obj = new Module.__Recognizer__(model.obj,ctx.sampleRate,__GenericObj__.objects.length)
|
||||
__GenericObj__.objects.push(this)
|
||||
this.obj = (async () => {
|
||||
new Module.__recognizer__(model.obj,ctx.sampleRate,__genericObj__.objects.length)
|
||||
})()
|
||||
__genericObj__.objects.push(this)
|
||||
ctx.close()
|
||||
return this;
|
||||
}
|
||||
start() {
|
||||
this.obj.then(() => {
|
||||
this.obj.start()
|
||||
})
|
||||
}
|
||||
stop() {
|
||||
this.obj.then(() => {
|
||||
this.obj.stop()
|
||||
})
|
||||
}
|
||||
delete() {
|
||||
this.obj.then(() => {
|
||||
this.obj.deinit()
|
||||
this.obj.delete()
|
||||
})
|
||||
}
|
||||
setWords(words) {
|
||||
this.obj.then(() => {
|
||||
this.obj.setWords(words)
|
||||
})
|
||||
}
|
||||
setPartialWords(partialWords) {
|
||||
this.obj.setPartialWords(words)
|
||||
this.obj.then(() => {
|
||||
this.obj.setPartialWords(partialWords)
|
||||
})
|
||||
}
|
||||
setGrm(grm) {
|
||||
this.obj.then(() => {
|
||||
this.obj.setGrm(grm)
|
||||
})
|
||||
}
|
||||
setSpkModel(model) {
|
||||
this.obj.then(() => {
|
||||
this.obj.setSpkModel(model.obj)
|
||||
})
|
||||
}
|
||||
setNLSML(nlsml) {
|
||||
this.obj.then(() => {
|
||||
this.obj.setNLSML(nlsml)
|
||||
})
|
||||
}
|
||||
setMaxAlternatives(alts) {
|
||||
this.obj.then(() => {
|
||||
this.obj.setMaxAlternatives(alts)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
#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;
|
||||
model = vosk_spk_model_new(this->storepath.c_str());
|
||||
if(model == nullptr) {
|
||||
mdl = vosk_spk_model_new(".");
|
||||
if(mdl == nullptr) {
|
||||
fireEv("error", "Unable to initialize speaker model");
|
||||
}
|
||||
fireEv("ready");
|
||||
};
|
||||
bool SpkModel::checkModel(const std::string& path) {
|
||||
return fs::exists((path + "/mfcc.conf")) &&
|
||||
fs::exists((path + "/final.ext.raw")) &&
|
||||
fs::exists((path + "/mean.vec")) &&
|
||||
fs::exists((path + "/transform.mat"));
|
||||
bool spkModel::checkModel() {
|
||||
return fs::exists("mfcc.conf") &&
|
||||
fs::exists("final.ext.raw") &&
|
||||
fs::exists("mean.vec") &&
|
||||
fs::exists("transform.mat");
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
#pragma once
|
||||
#include "genericModel.h"
|
||||
|
||||
class SpkModel : public GenericModel {
|
||||
bool checkModel(const std::string& path);
|
||||
public:
|
||||
SpkModel(const std::string &url, const std::string& storepath, const std::string& id, const int index);
|
||||
VoskSpkModel* model{};
|
||||
struct spkModel : genericModel {
|
||||
bool checkModel();
|
||||
spkModel(const std::string &url, const std::string& storepath, const std::string& id, const int index);
|
||||
VoskSpkModel* mdl{};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
class SpkModel extends EventTarget{
|
||||
constructor(url, storepath, id) {
|
||||
super()
|
||||
this.obj = new Module.__SpkModel__(url, storepath, id, __GenericObj__.objects.length)
|
||||
__GenericObj__.objects.push(this)
|
||||
this.obj = (async () => {
|
||||
return new Module.__spkModel__(url, storepath, id, __genericObj__.objects.length)
|
||||
})()
|
||||
__genericObj__.objects.push(this)
|
||||
}
|
||||
delete() {
|
||||
this.obj.then(() => {
|
||||
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