123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- /*
- * Copyright (C) 2014-2017 Eitan Isaacson
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see: <http://www.gnu.org/licenses/>.
- */
- eSpeakNGWorker.prototype.list_voices = function() {
- var voices = [];
- var i;
- for (var voice = this.get_voices(i = 0); voice.ptr != 0; voice = this.get_voices(++i)) {
- var v = {
- name: voice.get_name(),
- identifier: voice.get_identifier(),
- languages: [],
- }
- var ii = 0;
- var byte = voice.get_languages(ii);
- function nullTerminatedString(offset) {
- var str = '';
- var index = offset;
- var b = voice.get_languages(index++);
- while (b != 0) {
- str += String.fromCharCode(b);
- b = voice.get_languages(index++);
- }
- return str;
- }
- while (byte != 0) {
- var lang = { priority: byte, name: nullTerminatedString(++ii) }
- v.languages.push(lang);
- ii += lang.name.length + 1;
- byte = voice.get_languages(ii);
- }
- voices.push(v);
- }
- return voices;
- };
- var eventTypes = [
- 'list_terminated',
- 'word',
- 'sentence',
- 'mark',
- 'play',
- 'end',
- 'msg_terminated',
- 'phoneme',
- 'samplerate'
- ]
- eSpeakNGWorker.prototype.synthesize = function (aText, aCallback) {
- var eventStructSize = this.getSizeOfEventStruct_();
- function cb(ptr, length, events_pointer) {
- var data = new Float32Array(length*2);
- for (var i = 0; i < length; i++) {
- data[i*2] = Math.max(-1, Math.min(1, getValue(ptr + i*2, 'i16') / 32768));
- data[i*2+1] = data[i*2];
- }
- var events = [];
- var ptr = events_pointer;
- for (ev = wrapPointer(ptr, espeak_EVENT);
- ev.get_type() != Module.espeakEVENT_LIST_TERMINATED;
- ev = wrapPointer((ptr += eventStructSize), espeak_EVENT)) {
- events.push({
- type: eventTypes[ev.get_type()],
- text_position: ev.get_text_position(),
- word_length: ev.get_length(),
- audio_position: ev.get_audio_position()
- });
- }
- return aCallback(data, events) ? 1 : 0;
- }
- var fp = Runtime.addFunction(cb);
- this.synth_(aText, fp);
- Runtime.removeFunction(fp);
- };
- eSpeakNGWorker.prototype.synthesize_ipa = function (aText, aCallback) {
-
- // Use a unique temp file for the worker. Avoid collisions, just in case.
- var ipaVirtualFileName = "espeak-ng-ipa-tmp-" + Math.random().toString().substring(2);
-
- var res = "";
- var code = this.synth_ipa_(aText, ipaVirtualFileName);
- if(code == 0)
- res = FS.readFile(ipaVirtualFileName, { encoding: 'utf8' })
-
- // Clean up the tmp file
- FS.unlink(ipaVirtualFileName);
-
- var ret = {
- code: code,
- ipa: res
- }
-
- return ret;
- };
- // Make this a worker
- if (typeof WorkerGlobalScope !== 'undefined') {
- var worker;
- Module.postRun.push(function () {
- worker = new eSpeakNGWorker();
- postMessage('ready');
- });
- onmessage = function(e) {
-
- if (!worker) {
- throw 'eSpeakNGWorker worker not initialized';
- }
- var args = e.data.args;
- var message = { callback: e.data.callback, done: true };
- if (e.data.method == 'synthesize') {
- args.push(function(samples, events) {
- postMessage(
- { callback: e.data.callback,
- result: [samples.buffer, events] }, [samples.buffer]);
- });
- }
- message.result = [worker[e.data.method].apply(worker, args)];
- if (e.data.callback)
- postMessage(message);
- }
- }
|