talkr-tts
Version:
Wraps speechSynthesis calls for applications that want to animate to the voice
1,746 lines • 54.5 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("talkr-tts", [], factory);
else if(typeof exports === 'object')
exports["talkr-tts"] = factory();
else
root["talkr-tts"] = factory();
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 6);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _events = __webpack_require__(3);
var _events2 = _interopRequireDefault(_events);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
* Base class for TTS objects
*/
var Base = function (_EventEmitter) {
_inherits(Base, _EventEmitter);
function Base(type, id) {
_classCallCheck(this, Base);
if (id === undefined) {
id = Math.random().toString(36).substr(2, 9);
} else if (typeof id !== 'string') {
throw new Error('Invalid id');
}
var _this = _possibleConstructorReturn(this, (Base.__proto__ || Object.getPrototypeOf(Base)).call(this));
_this._id = id;
_this._type = type;
if (!(_this._type in Base.objects)) {
Base.objects[_this._type] = {};
}
Base.lastID[_this._type] = _this._id;
Base.objects[_this._type][_this._id] = _this;
return _this;
}
/**
* Get the id.
* @return {string}
*/
_createClass(Base, [{
key: 'delete',
value: function _delete() {
delete Base.objects[this._type][this._id];
}
}, {
key: 'id',
get: function get() {
return this._id;
},
set: function set(id) {
if (this._id in Base.objects[this._type]) {
delete Base.objects[this._type][this._id];
}
this._id = id;
Base.objects[this._type][this._id] = this;
Base.lastID[this._type] = this._id;
}
}], [{
key: 'getlastID',
value: function getlastID(type) {
return Base.lastID[type];
}
}, {
key: 'getByTypeAndID',
value: function getByTypeAndID(type, id) {
if (type in Base.objects) {
if (id in Base.objects[type]) {
Base.lastID[type] = id;
return Base.objects[type][id];
}
}
return null;
}
}, {
key: 'store',
get: function get() {
return Base.objects;
},
set: function set(store) {
Base.objects = store;
}
}]);
return Base;
}(_events2.default);
exports.default = Base;
Base.lastID = {};
Base.objects = {};
module.exports = exports['default'];
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var hasWindow = (typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window !== null && window.self === window && window.navigator !== null;
var bIsiOS = hasWindow && /iPad|iPhone|iPod/.test(window.navigator.userAgent) && !window.MSStream;
var hasSpeechSynthesis = hasWindow && window.speechSynthesis !== null;
// const iOSEnglishVoices = ['Karen', 'Serena', 'Moira', 'Tessa', 'Samantha'];
// const bIsAndroid = /android/i.test(navigator.userAgent);
var iOSVoiceNames = ['Maged', 'Zuzana', 'Sara', 'Anna', 'Melina', 'Karen', 'Daniel', 'Moira', 'Tessa', 'Alex', 'Monica', 'Paulina', 'Satu', 'Amelie', 'Thomas', 'Carmit', 'Lekha', 'Mariska', 'Damayanti', 'Alice', 'Kyoko', 'Yuna', 'Ellen', 'Xander', 'Nora', 'Zosia', 'Luciana', 'Joana', 'Ioana', 'Milena', 'Laura', 'Alva', 'Kanya', 'Yelda', 'Ting-Ting', 'Sin-Ji', 'Mei-Jia'];
var minimumPriority = 10;
var voiceProperties = {
'Microsoft David Desktop - English (United States)': { male: true, priority: 13 },
'Microsoft Hazel Desktop - English (Great Britain)': { male: false, priority: 14 },
'Microsoft Zira Desktop - English (United States)': { male: false, priority: 14 },
'Google US English': { male: false, priority: 24 },
'Google UK English Female': { male: false, priority: 24 },
'Google UK English Male': { male: true, priority: 23 },
'Lee': { male: true, priority: 33 },
'Fred': { male: true, priority: 8 },
'Alex': { male: true, priority: 34 },
'Daniel': { male: true, priority: 33 },
'Daniel (Enhanced)': { male: true, priority: 43 },
'Oliver': { male: true, priority: 33 },
'Oliver (Enhanced)': { male: true, priority: 43 },
'Samantha': { male: false, priority: 38 },
'Victoria': { male: false, priority: 9 },
'Veena': { male: false, priority: 32 },
'Tessa': { male: false, priority: 37 },
'Fiona': { male: false, priority: 37 },
'Moira': { male: false, priority: 37 },
'Karen': { male: false, priority: 37 }
};
var languageProperties = {
'en': 'English',
'zh': 'Chinese',
'ru': 'Russian',
'de': 'German',
'it': 'Italian',
'pt': 'Portuguese',
'vi': 'Vietnamese',
'tr': 'Turkish',
'th': 'Thai',
'es': 'Spanish',
'fr': 'French',
'sk': 'Slovak',
'ro': 'Romanian',
'pl': 'Polish',
'nl': 'Dutch',
'ko': 'Korean',
'ja': 'Japanese',
'he': 'Hebrew',
'el': 'Greek',
'fi': 'Finish',
'no': 'Norwegian',
'da': 'Danish',
'cs': 'Czech',
'ar': 'Arabic'
};
var languagePropertiesInverted = {
'English': 'en',
'Chinese': 'zh',
'Russian': 'ru',
'German': 'de',
'Italian': 'it',
'Portuguese': 'pt',
'Vietnamese': 'vi',
'Turkish': 'tr',
'Thai': 'th',
'Spanish': 'es',
'French': 'fr',
'Slovak': 'sk',
'Romanian': 'ro',
'Polish': 'pl',
'Dutch': 'nl',
'Korean': 'ko',
'Japanese': 'ja',
'Hebrew': 'he',
'Greek': 'el',
'Finish': 'fi',
'Norwegian': 'no',
'Danish': 'da',
'Czech': 'cs',
'Arabic': 'ar'
};
/*
var langs =
[['Afrikaans', ['af-ZA']],
['Bahasa Indonesia',['id-ID']],
['Bahasa Melayu', ['ms-MY']],
['Català', ['ca-ES']],
['Čeština', ['cs-CZ']],
['Deutsch', ['de-DE']],
['English', ['en-AU', 'Australia'],
['Español', ['es-AR', 'Argentina'],
['Euskara', ['eu-ES']],
['Français', ['fr-FR']],
['Galego', ['gl-ES']],
['Hrvatski', ['hr_HR']],
['IsiZulu', ['zu-ZA']],
['Íslenska', ['is-IS']],
['Italiano', ['it-IT', 'Italia'],
['Magyar', ['hu-HU']],
['Nederlands', ['nl-NL']],
['Norsk bokmål', ['nb-NO']],
['Polski', ['pl-PL']],
['Português', ['pt-BR', 'Brasil'],
['Română', ['ro-RO']],
['Slovenčina', ['sk-SK']],
['Suomi', ['fi-FI']],
['Svenska', ['sv-SE']],
['Türkçe', ['tr-TR']],
['български', ['bg-BG']],
['Pусский', ['ru-RU']],
['Српски', ['sr-RS']],
['한국어', ['ko-KR']],
['中文', ['cmn-Hans-CN', '普通话 (中国大陆)'],
['日本語', ['ja-JP']],
['Lingua latīna', ['la']]];
*/
var Voice = function () {
_createClass(Voice, null, [{
key: 'getLangauges',
value: function getLangauges() {
var codes = [];
var languages = [];
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
if (hasSpeechSynthesis) {
speechSynthesis.getVoices().forEach(function (v) {
codes.push(v.lang.substring(0, 2));
});
}
var unique = codes.filter(onlyUnique);
unique.forEach(function (l) {
if (l in languageProperties) {
languages.push(languageProperties[l]);
} else {
languages.push(l);
}
});
return languages;
}
}, {
key: 'getVoicesForLangauge',
value: function getVoicesForLangauge(language) {
var code = languagePropertiesInverted[language];
var names = [];
var voices = [];
if (code) {
voices = Voice.getVoicesWithLangSubstring(code);
voices.forEach(function (v) {
names.push(v.name);
});
return names;
}
return [];
}
}, {
key: 'getVoicesWithLangSubstring',
value: function getVoicesWithLangSubstring(langSubstr) {
var filteredvoices = [];
if (hasSpeechSynthesis) {
filteredvoices = speechSynthesis.getVoices().filter(function (v) {
if (voiceProperties[v.name]) {
if (voiceProperties[v.name].priority < minimumPriority) {
return false;
}
}
return v.lang.substring(0, langSubstr.length) === langSubstr;
});
}
// iOS returns more than they let you select.
if (bIsiOS) {
var newVoices = [];
var last = filteredvoices.length - 1;
for (var i = last; i >= 0; --i) {
for (var j = 0; j < iOSVoiceNames.length; ++j) {
if (filteredvoices[i].name === iOSVoiceNames[j]) {
newVoices.push(filteredvoices[i]);
}
}
}
filteredvoices = newVoices;
}
// So does Android...all versions?
function sortCompare(a, b) {
var aPriority = 0;
var bPriority = 0;
if (voiceProperties[a.name]) {
aPriority = voiceProperties[a.name].priority;
}
if (voiceProperties[b.name]) {
bPriority = voiceProperties[b.name].priority;
}
if (a.name.includes('Enhanced')) {
aPriority++;
}
if (b.name.includes('Enhanced')) {
bPriority++;
}
return bPriority - aPriority;
}
return filteredvoices.sort(sortCompare);
}
}, {
key: 'getTTSVoice',
value: function getTTSVoice(voiceObj) {
return Voice._getBestVoice(voiceObj.name, voiceObj.locale, voiceObj.isMale, voiceObj.index);
}
}, {
key: '_getBestVoice',
value: function _getBestVoice(name, locale, bIsMale, index) {
if (name) {
var namedVoice = Voice._getVoiceWithName(name);
if (namedVoice) {
return namedVoice;
}
}
var matchingVoices = Voice._getBestVoices(locale, bIsMale);
if (matchingVoices.length > 0) {
if (index != null) {
index = Math.abs(parseInt(index, 10));
index = index % matchingVoices.length;
} else {
index = 0;
}
return matchingVoices[index];
}
// Try english voices if we didn't get any for the provided locale.
if (locale !== 'en') {
console.warn('No voices for locale: ' + locale);
return Voice._getBestVoice(null, 'en', bIsMale, index);
}
var lastResorts = [];
if (hasSpeechSynthesis) {
lastResorts = speechSynthesis.getVoices();
}
if (lastResorts[0]) {
return lastResorts[0];
}
return null;
}
}, {
key: '_getBestVoices',
value: function _getBestVoices(locale, bIsMale) {
var voices = [];
var genderVoices = [];
if (locale && locale.length > 1) {
voices = Voice.getVoicesWithLangSubstring(locale);
}
voices.forEach(function (v) {
if (v.name in voiceProperties) {
if (bIsMale === voiceProperties[v.name].male) {
genderVoices.push(v);
}
} else {
// We don't know the gender of this voice. Let's cross our fingers.
genderVoices.push(v);
}
});
// Try with only the first two letters of the locale.
if (genderVoices.length === 0 && locale.length > 2) {
return this._getBestVoices(locale.substring(0, 2), bIsMale);
}
// Any gender will do at this point.
if (genderVoices.length === 0) {
voices.forEach(function (v) {
genderVoices.push(v);
});
}
return genderVoices;
}
}, {
key: '_getVoicesWithName',
value: function _getVoicesWithName(name) {
if (hasSpeechSynthesis) {
return speechSynthesis.getVoices().filter(function (v) {
return v.name === name;
});
}
return [];
}
}, {
key: '_getVoiceWithName',
value: function _getVoiceWithName(name) {
if (hasSpeechSynthesis) {
var voices = speechSynthesis.getVoices().filter(function (v) {
return v.name === name;
});
if (voices.length > 0) {
return voices[0];
}
}
return null;
}
}, {
key: 'doesSupportPitchAndRate',
value: function doesSupportPitchAndRate(name) {
var namedVoice = Voice._getVoiceWithName(name);
if (namedVoice) {
return namedVoice.localService === true;
}
return false;
}
}]);
function Voice(locale, bIsMale, preference) {
_classCallCheck(this, Voice);
this._locale = locale;
this._bIsMale = bIsMale;
this._name = preference;
this._index = null;
if (this._locale === undefined) {
this._locale = Voice.defaultlocale;
}
if (this._bIsMale === undefined) {
this._bIsMale = Voice.defaultbIsMale;
}
if (this._name !== undefined) {
if (this._name in voiceProperties) {
this._bIsMale = voiceProperties[this._name].male;
}
}
// A number for the name indicates we should choose a different
// voice than the first.
if (this._name && !isNaN(this._name)) {
this._index = this._name;
this._name = null;
}
Voice.defaultlocale = this._locale;
Voice.defaulbIsMale = this._bIsMale;
}
_createClass(Voice, [{
key: 'index',
get: function get() {
return this._index;
}
}, {
key: 'name',
get: function get() {
return this._name;
}
}, {
key: 'locale',
get: function get() {
return this._locale;
}
}, {
key: 'isMale',
get: function get() {
return this._bIsMale;
}
}, {
key: 'language',
get: function get() {
return languageProperties[this._locale.substring(0, 2)];
}
}]);
return Voice;
}();
exports.default = Voice;
Voice.defaultlocale = 'en-US';
Voice.defaultbIsMale = false;
module.exports = exports['default'];
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _base = __webpack_require__(0);
var _base2 = _interopRequireDefault(_base);
var _voice = __webpack_require__(1);
var _voice2 = _interopRequireDefault(_voice);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var Face = function (_Base) {
_inherits(Face, _Base);
// The id is the first parameter. It is used to store the URL
function Face(id, voice) {
_classCallCheck(this, Face);
var _this = _possibleConstructorReturn(this, (Face.__proto__ || Object.getPrototypeOf(Face)).call(this, 'face', id));
if (voice === undefined) {
voice = new _voice2.default();
}
_this._voice = voice;
return _this;
}
// TODO: remove
_createClass(Face, [{
key: 'url',
get: function get() {
return this._id;
},
set: function set(url) {
this._id = url;
}
}, {
key: 'voice',
get: function get() {
return this._voice;
},
set: function set(voice) {
this._voice = voice;
}
}], [{
key: 'getByID',
value: function getByID(id) {
return _base2.default.getByTypeAndID('face', id);
}
}, {
key: 'getlastID',
value: function getlastID() {
return _base2.default.getlastID('face');
}
}, {
key: 'fromJSON',
value: function fromJSON(json) {
if (json['_id']) {
var v = json['_voice'];
var voice = null;
if (v) {
voice = new _voice2.default(v['_locale'], v['_bIsMale'], v['_name']);
}
return new Face(json['_id'], voice);
}
return null;
}
}]);
return Face;
}(_base2.default);
exports.default = Face;
module.exports = exports['default'];
/***/ }),
/* 3 */
/***/ (function(module, exports) {
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
err.context = er;
throw err;
}
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
args = Array.prototype.slice.call(arguments, 1);
handler.apply(this, args);
}
} else if (isObject(handler)) {
args = Array.prototype.slice.call(arguments, 1);
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.prototype.listenerCount = function(type) {
if (this._events) {
var evlistener = this._events[type];
if (isFunction(evlistener))
return 1;
else if (evlistener)
return evlistener.length;
}
return 0;
};
EventEmitter.listenerCount = function(emitter, type) {
return emitter.listenerCount(type);
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Utterance = function () {
function Utterance(text, pitch, rate, delay) {
_classCallCheck(this, Utterance);
this._text = text;
this._pitch = pitch;
this._rate = rate;
this._delay = delay;
if (this._pitch === undefined) {
this._pitch = 1.0;
}
if (this._rate === undefined) {
this._rate = 1.0;
}
if (this._delay === undefined) {
this._delay = 0.0;
}
}
_createClass(Utterance, [{
key: "text",
get: function get() {
return this._text;
},
set: function set(val) {
this._text = val;
}
}, {
key: "pitch",
get: function get() {
return this._pitch;
},
set: function set(val) {
this._pitch = val;
}
}, {
key: "rate",
get: function get() {
return this._rate;
},
set: function set(val) {
this._rate = val;
}
}, {
key: "delay",
get: function get() {
return this._delay;
},
set: function set(val) {
this._delay = val;
}
}]);
return Utterance;
}();
exports.default = Utterance;
module.exports = exports["default"];
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _utterance = __webpack_require__(4);
var _utterance2 = _interopRequireDefault(_utterance);
var _voice = __webpack_require__(1);
var _voice2 = _interopRequireDefault(_voice);
var _face = __webpack_require__(2);
var _face2 = _interopRequireDefault(_face);
var _base = __webpack_require__(0);
var _base2 = _interopRequireDefault(_base);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var hasWindow = (typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window !== null && window.self === window;
var speechSynthesis = hasWindow && 'speechSynthesis' in window ? window.speechSynthesis : null;
var Clip = function (_Base) {
_inherits(Clip, _Base);
function Clip(utterances, face, id) {
_classCallCheck(this, Clip);
var _this = _possibleConstructorReturn(this, (Clip.__proto__ || Object.getPrototypeOf(Clip)).call(this, 'clip', id));
if (utterances === undefined) {
utterances = [];
}
if (typeof utterances === 'string') {
_this._utterances = _this._splitUtterances(utterances);
} else if (Array.isArray(utterances)) {
utterances.forEach(function (ut) {
if (!(ut instanceof _utterance2.default)) {
throw Error('Invalid utterance array.');
}
});
_this._utterances = utterances;
} else {
throw Error('Unknown type for utterances.');
}
if (typeof face === 'string') {
_this._faceid = face;
} else if (face instanceof _face2.default) {
_this._faceid = face.id;
} else {
var lastID = _face2.default.getlastID();
if (!lastID) {
lastID = new _face2.default().id;
}
_this._faceid = lastID;
}
_this._stopped = true;
return _this;
}
/**
* Get the utterances.
* @return {Utterance[]}
*/
_createClass(Clip, [{
key: 'playAfterDelay',
value: function playAfterDelay(msg) {
if (this._stopped) {
return;
}
speechSynthesis.speak(msg);
// The delay parameter is added to the SpeechSynthesisUtterance object
if (msg.delay > 0) {
speechSynthesis.pause();
setTimeout(function () {
var event = new Event('start');
// Trigger the start events again.
msg.delay = 0;
msg.dispatchEvent(event);
speechSynthesis.resume();
}, msg.delay * 1000);
}
}
}, {
key: 'playUtterances',
value: function playUtterances(onPlayUtteranceWithDur, onFinishedClip, onStartClip) {
var _this2 = this;
this._stopped = false;
Clip.playing = this;
if (speechSynthesis) {
if (speechSynthesis.speaking) {
// console.log("Can't play TTS when we are already speaking");
// if (onFinishedClip) onFinishedClip();
// return;
speechSynthesis.cancel();
}
this._ssUtterances = [];
for (var i = 0, l = this._utterances.length; i < l; ++i) {
var utterance = this._utterances[i];
var utteranceText = utterance.text;
if (!utteranceText || utteranceText.length === 0) {
continue;
}
var msg = new SpeechSynthesisUtterance();
// if you change the rate, you would have to adjust
var speakingDurationEstimate = utteranceText.length * 50;
// Chinese needs a different calculation. Haven't tried other Asian languages.
if (utteranceText.match(/[\u3400-\u9FBF]/)) {
speakingDurationEstimate = utteranceText.length * 200;
}
msg.rate = utterance.rate;
msg.pitch = utterance.pitch;
msg.text = utteranceText;
// Add delay as paramater for ease of use
msg.delay = utterance.delay;
if (this.voice) {
msg.voice = _voice2.default.getTTSVoice(this.voice);
if (msg.voice) {
msg.voiceURI = msg.voice.voiceURI;
}
}
this._ssUtterances.push([msg, speakingDurationEstimate]);
}
// Now setup the events
if (this._ssUtterances.length > 0) {
this._ssUtterances[0][0].addEventListener('start', function () {
if (onStartClip) {
if (_this2._ssUtterances[0][0].delay === 0) {
onStartClip();
}
}
});
this._ssUtterances[this._ssUtterances.length - 1][0].addEventListener('end', function () {
if (onFinishedClip) {
onFinishedClip();
}
_this2._stopped = true;
Clip.playing = null;
// Safe to clear this out now.
_this2._ssUtterances = [];
});
for (var _i = 0, _l = this._ssUtterances.length; _i < _l; ++_i) {
(function (msg, dur) {
msg.addEventListener('start', function () {
if (onPlayUtteranceWithDur) {
if (msg.delay === 0) {
onPlayUtteranceWithDur(dur, _this2.face);
}
}
});
})(this._ssUtterances[_i][0], this._ssUtterances[_i][1]);
}
for (var _i2 = 0, _l2 = this._ssUtterances.length - 1; _i2 < _l2; ++_i2) {
(function (msg1, msg2) {
msg1.addEventListener('end', function () {
_this2.playAfterDelay(msg2);
});
})(this._ssUtterances[_i2][0], this._ssUtterances[_i2 + 1][0]);
}
this.playAfterDelay(this._ssUtterances[0][0]);
}
}
}
}, {
key: 'updateText',
value: function updateText(text) {
var newUtterances = this._splitUtterances(text);
var curLen = this._utterances.length;
var newLen = newUtterances.length;
// Easy case, the number of Utterances didn't change
if (curLen === newLen) {
for (var i = 0; i < curLen; ++i) {
this._utterances[i].text = newUtterances[i].text;
}
return;
}
// Store the original utterances in a dictionary with text as key.
var utteranceDict = {};
for (var _i3 = 0; _i3 < curLen; ++_i3) {
if (this._utterances[_i3].text in utteranceDict) {
// handle duplicate utterances with different pitch/rate
utteranceDict[this._utterances[_i3].text].push(this._utterances[_i3]);
} else {
utteranceDict[this._utterances[_i3].text] = [this._utterances[_i3]];
}
}
var defaultRateIndices = [];
for (var _i4 = 0; _i4 < newLen; ++_i4) {
var newText = newUtterances[_i4].text;
if (newText in utteranceDict) {
newUtterances[_i4] = utteranceDict[newText].shift();
if (utteranceDict[newText].length === 0) {
delete utteranceDict[newText];
}
} else {
defaultRateIndices.push(_i4);
}
}
// Match the leftovers
if (defaultRateIndices.length > 0 && Object.values(utteranceDict).length > 0) {
var cachedText = newUtterances[defaultRateIndices[0]].text;
newUtterances[defaultRateIndices[0]] = Object.values(utteranceDict)[0][0];
newUtterances[defaultRateIndices[0]].text = cachedText;
}
this._utterances = newUtterances;
}
/**
* Convert a string containing punctuation-separated utterances into an array
* of utterances
* @param {string} text - The string containing punctuation-separated utterances.
* @return {Utterance[]} An array of Utterance objects
*/
}, {
key: '_splitUtterances',
value: function _splitUtterances(text) {
// Splitting each utterance up using punctuation is important. Intra-utterance
// punctuation will add silence to the tts which looks bad unless the mouth stops moving
// correctly. Better to split it into separate utterances so play_for_duration will move when
// talking, and be on frame 0 when not.
var utterances = [];
// split everything betwen deliminators [.?,!], but include the deliminator.
var substrings = text.match(/[^.?,!]+[.?,!]?/g);
if (substrings) {
for (var i = 0, l = substrings.length; i < l; ++i) {
var str = substrings[i].trim();
// Make sure there is something to say other than the deliminator
var numpunc = (str.match(/[.?,!]/g) || []).length;
if (str.length - numpunc > 0) {
utterances.push(new _utterance2.default(str));
}
}
}
return utterances;
}
}, {
key: 'utterances',
get: function get() {
return this._utterances;
}
}, {
key: 'face',
/**
* Gets the Face
* @return {Face}
*/
get: function get() {
return _face2.default.getByID(this._faceid);
},
set: function set(face) {
if (typeof face === 'string') {
if (_face2.default.getByID(face)) {
this._faceid = face;
}
}
this._faceid = face.id;
}
}, {
key: 'voice',
/**
* Gets the Voice
* @return {Voice}
*/
get: function get() {
return this.face.voice;
},
set: function set(voice) {
this.face.voice = voice;
}
}, {
key: 'text',
get: function get() {
var combinedText = '';
var numUtterances = this._utterances.length;
for (var i = 0; i < numUtterances; ++i) {
combinedText = combinedText + this._utterances[i].text + ' ';
}
return combinedText.trim();
}
}, {
key: 'sceneid',
get: function get() {
return this._sceneid;
},
set: function set(id) {
this._sceneid = id;
}
}], [{
key: 'stop',
value: function stop() {
if (Clip.playing) {
Clip.playing._stopped = true;
}
Clip.playing = null;
if (speechSynthesis) {
speechSynthesis.cancel();
}
}
}, {
key: 'getByID',
value: function getByID(id) {
return _base2.default.getByTypeAndID('clip', id);
}
}, {
key: 'fromJSON',
value: function fromJSON(json) {
if (json['_utterances'] && json['_id']) {
var utterances = [];
for (var i = 0, l = json['_utterances'].length; i < l; ++i) {
var ut = json['_utterances'][i];
utterances.push(new _utterance2.default(ut._text, ut._rate, ut._pitch, ut._delay));
}
var newClip = new Clip(utterances, json['_faceid'], json['_id']);
newClip._sceneid = json['_sceneid'];
return newClip;
}
return null;
}
}]);
return Clip;
}(_base2.default);
exports.default = Clip;
Clip.playing = null;
module.exports = exports['default'];
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Scene = exports.Clip = exports.Utterance = exports.Voice = exports.Face = exports.Base = undefined;
var _face = __webpack_require__(2);
var _face2 = _interopRequireDefault(_face);
var _voice = __webpack_require__(1);
var _voice2 = _interopRequireDefault(_voice);
var _utterance = __webpack_require__(4);
var _utterance2 = _interopRequireDefault(_utterance);
var _clip = __webpack_require__(5);
var _clip2 = _interopRequireDefault(_clip);
var _scene = __webpack_require__(7);
var _scene2 = _interopRequireDefault(_scene);
var _base = __webpack_require__(0);
var _base2 = _interopRequireDefault(_base);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.Base = _base2.default;
exports.Face = _face2.default;
exports.Voice = _voice2.default;
exports.Utterance = _utterance2.default;
exports.Clip = _clip2.default;
exports.Scene = _scene2.default;
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
var _clip = __webpack_require__(5);
var _clip2 = _interopRequireDefault(_clip);
var _base = __webpack_require__(0);
var _base2 = _interopRequireDefault(_base);
var _events = __webpack_require__(3);
var _events2 = _interopRequireDefault(_events);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var Scene = function (_Base) {
_inherits(Scene, _Base);
function Scene(clipIDs, id) {
_classCallCheck(this, Scene);
var _this = _possibleConstructorReturn(this, (Scene.__proto__ || Object.getPrototypeOf(Scene)).call(this, 'scene', id));
if (clipIDs === undefined) {
clipIDs = [];
}
if (Array.isArray(clipIDs)) {
clipIDs.forEach(function (id) {
if (typeof id !== 'string') {
throw Error('Invalid clip id.');
}
});
} else {
throw Error('clipIDs were not an array.');
}
_this._clips = clipIDs;
_this._stopped = true;
_this._name = null;
return _this;
}
_createClass(Scene, [{
key: 'deleteClip',
value: function deleteClip(id) {
var i = this._clips.indexOf(id);
if (i > -1) {
var clip = _clip2.default.getByID(id);
this._clips.splice(i, 1);
if (clip) {
clip.delete();
}
}
}
}, {
key: 'addClip',
value: function addClip(id) {
var clip = _clip2.default.getByID(id);
if (clip) {
this._clips.push(id);
clip.sceneid = this._id;
}
}
}, {
key: 'delete',
value: function _delete() {
this._clips.forEach(function (clipid) {
delete _base2.default.objects['clip'][clipid];
});
_get(Scene.prototype.__proto__ || Object.getPrototypeOf(Scene.prototype), 'delete', this).call(this);
}
}, {
key: 'playClips',
value: function playClips(startIndex) {
var _this2 = this;
Scene.playing = this;
if (startIndex === undefined) {
startIndex = 0;
}
var numclips = this._clips.length;
this._stopped = false;
if (numclips <= startIndex) {
return;
}
var onPlayUtteranceWithDur = function onPlayUtteranceWithDur(dur, face) {
Scene.eventEmitter.emit('utterancestart', { 'duration': dur, 'face': face });
};
var that = this;
var onPlayNextClip = null;
var playClipAtIndex = function playClipAtIndex(clipIndex) {
if (_this2._stopped) {
return;
}
var clip = _clip2.default.getByID(that.clipIDs[clipIndex]);
if (clip) {
Scene.eventEmitter.emit('clipstart', clip);
clip.playUtterances(onPlayUtteranceWithDur, onPlayNextClip);
} else {
throw new Error('unknown clip ID: ' + that.clipIDs[clipIndex]);
}
};
var clipIndex = startIndex;
onPlayNextClip = function onPlayNextClip() {
if (clipIndex === numclips - 1) {
Scene.eventEmitter.emit('scenefinished');
Scene.playing = null;
return;
}
Scene.eventEmitter.emit('clipfinished', clipIndex);
clipIndex += 1;
playClipAtIndex(clipIndex);
};
playClipAtIndex(startIndex);
}
}, {
key: 'clipIDs',
get: function get() {
return this._clips;
}
}, {
key: 'name',
get: function get() {
return this._name;
},
set: function set(name) {
this._name = name;
}
}, {
key: 'text',
get: function get() {
var text = '';
this._clips.forEach(function (clipid) {
var clip = _clip2.default.getByID(clipid);
if (!clip) {
throw new Error('Invalid clip ID.');
}
text += clip.text + ' ';
});
return text.trim();
}
}, {
key: 'clips',
get: function get() {
var clips = [];
this._clips.forEach(function (clipid) {
var clip = _clip2.default.getByID(clipid);
if (!clip) {
throw new Error('Invalid clip ID.');
}
clips.push(clip);
});
return clips;
}
}], [{
key: 'stop',
value: function stop() {
if (Scene.playing) {
Scene.playing._stopped = true;
}
Scene.playing = null;
_clip2.default.stop();
}
}, {
key: 'fromTextAndFace',
value: function fromTextAndFace(text, face) {
var newClip = new _clip2.default(text, face);
return new Scene([newClip.id]);
}
}, {
key: 'getByID',
value: function getByID(id) {
return _base2.default.getByTypeAndID('scene', id);
}
}, {
key: 'fromJSON',
value: function fromJSON(json) {
if (json['_clips'] && json['_id']) {
var scene = new Scene(json['_clips'], json['_id']);
var name = json['_name'];
if (name) {
scene.name = name;
}
return scene;
}
return null;
}
}]);
return Scene;
}(_base2.default);
exports.default = Scene;
Scene.playing = null;
Scene.eventEmitter = new _events2.default();
_base2.default.objects['scene'] = {};
module.exports = exports['default'];
/***/ })
/******/ ]);
});
//# sourceMappingURL=talkr-tts.js.map