Source: env/media/ttsMary.js


/**
 * Media Module: Implementation for Text-To-Speech via MARY TTS
 *
 * @requires CSP for accessing the MARY TTS server, e.g. for default server URL "media-src http://mary.dfki.de:59125/" or "default-src http://mary.dfki.de:59125/"
 *           NOTE if you have configured a different server URL, then that one needs to be enabled via CSP
 *
 * @class MaryWebAudioTTSImpl
 * @memberOf mmir.env.media
 * @hideconstructor
 *
 */

define(['mmirf/mediaManager', 'mmirf/configurationManager', 'mmirf/languageManager', 'mmirf/util/loadFile'], function(mediaManager, config, lang, load){

	/**
	 * @readonly
	 * @inner
	 * @default "ttsMary"
	 * @memberOf mmir.env.media.MaryWebAudioTTSImpl#
	 */
	var _pluginName = 'ttsMary';

	/**
	 * @readonly
	 * @inner
	 * @default "http://mary.dfki.de:59125/"
	 * @memberOf mmir.env.media.MaryWebAudioTTSImpl#
	 */
	var _defaultServerPath = 'http://mary.dfki.de:59125/';

	return function createMaryTTSImpl(_defaultLogger){

		/**
		 * separator char for language- / country-code (specific to TTS service)
		 *
		 * @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @private
		 */
		var _langSeparator = void(0);

		/** @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @private
		 */
		var _getLangParam;
		/** @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @private
		 */
		var _getVoiceParam;

		/**
		 * HELPER retrieve language setting and apply impl. specific corrections/adjustments
		 * (i.e. deal with MARY specific quirks for language/country codes)
		 *
		 * @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @private
		 */
		var _getFixedLang = function(options){

			var locale = _getLangParam(options, _langSeparator);

			return lang.fixLang('mary', locale);
		};

		/**
		 * HELPER parse raw voice information
		 * @param {String} str the raw line decribing the voice (as returned from service)
		 * @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @private
		 */
		var _toVoiceDetails = function(str){

			var infos = str? str.trim().split(/\s/) : [];
			return {
				name: infos[0],
				language: infos[1],
				gender: /^(fe)?male$/i.test(infos[2])? infos[2].toLowerCase() : 'unknown',
				local: false
			}
		};

		/**
		 * HELPER create filter-function for voice depending on language and/or gender
		 * @param {VoiceOptions} options for listing voices:
		 * 				options.language: the language code (may include country code)
		 * @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @private
		 */
		var _createVoiceFilter = function(options){

			var reLang = null, reStr = null;
			if(options.language){
				var parts = options.language.split(/[-_]/);
				reStr = '^'+parts[0];
				if(parts[1]){
					reStr += '[-_]'+parts[1]+'$';
				}
				reLang = new RegExp(reStr, 'i');
			}

			var reName = null;
			var reGender = null;
			if(options.details){

				reStr = options.details.name;
				if(reStr){
					reName = new RegExp('^'+reStr+'$', 'i');
				}

				reStr = options.details.gender;
				if(reStr){
					reGender = new RegExp('^'+reStr+'$', 'i');
				}
			}

			return function(voice){
				return (!reLang || reLang.test(voice.language)) && (!reName || reName.test(voice.name)) && (!reGender || reGender.test(voice.gender));
			}
		};

		/**  @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @private
		 */
		var generateTTSURL = function(text, options){

			text = encodeURIComponent(text);

			var lang = _getFixedLang(options);

			var voice = _getVoiceParam(options);
			var voiceParamStr = voice? '&VOICE='+voice : '';

			return config.get([_pluginName, "baseUrl"], _defaultServerPath) +'process?INPUT_TYPE=TEXT&OUTPUT_TYPE=AUDIO&INPUT_TEXT=' + text + '&LOCALE='+lang + voiceParamStr + '&AUDIO=WAVE_FILE';
		};

		/**  @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @private
		 */
		var createAudio = function(sentence, options, onend, onerror, oninit){

			return mediaManager.getURLAsAudio(
					generateTTSURL(sentence, options),
					onend, onerror, oninit
			);

		};

		/** @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @requires CrossDomain and CSP: allow access to baseUrl (default: "http://mary.dfki.de:59125/")
		 * @private
		 */
		var getList = function(type, callback, onerror){

			var url = config.get([_pluginName, "baseUrl"], _defaultServerPath) + (type === 'voice'? 'voices' : 'locales');
			load({
				url: url,
				dataType: 'text',
				success: function(data){
					// console.log(data)
					callback && callback(data? data.trim().split(/\r?\n/) : []);
				},
				error: onerror
			});
		};

		/** @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @requires CrossDomain and CSP: allow access to baseUrl (default: "http://mary.dfki.de:59125/")
		 * @see mmir.MediaManager#getSpeechLanguages
		 * @private
		 */
		var getLanguageList = function(callback, onerror){

			getList('language', callback, onerror);
		};


		/** @memberOf mmir.env.media.MaryWebAudioTTSImpl#
		 * @requires CrossDomain and CSP: allow access to baseUrl (default: "http://mary.dfki.de:59125/")
		 * @see mmir.MediaManager#getVoices
		 * @private
		 */
		var getVoiceList = function(options, callback, onerror){

			getList('voice', function(list){
				var voices = list.map(function(raw){ return _toVoiceDetails(raw);});
				var isFilter = options && (options.language || (options.details && (options.details.name || options.details.gender)));
				var filteredList = !isFilter? voices : voices.filter(_createVoiceFilter(options));
				var isDetails = options && options.details;
				callback && callback(isDetails? filteredList : filteredList.map(function(v){ return v.name;}));
			}, onerror);
		};

		/**  @memberOf mmir.env.media.MaryWebAudioTTSImpl# */
		return {
			/**
			 * @public
			 * @memberOf mmir.env.media.MaryWebAudioTTSImpl.prototype
			 */
			getPluginName: function(){
				return _pluginName;
			},
			/**
			 * @public
			 * @memberOf mmir.env.media.MaryWebAudioTTSImpl.prototype
			 */
			getCreateAudioFunc: function(){
				return createAudio;
			},
			/**
			 * @public
			 * @memberOf mmir.env.media.MaryWebAudioTTSImpl.prototype
			 */
			getLanguageListFunc: function(){
				return getLanguageList;
			},
			/**
			 * @public
			 * @memberOf mmir.env.media.MaryWebAudioTTSImpl.prototype
			 */
			getVoiceListFunc: function(){
				return getVoiceList;
			},
			/**
			 * @public
			 * @memberOf mmir.env.media.MaryWebAudioTTSImpl.prototype
			 */
			setLangParamFunc: function(getLangParamFunc){
				_getLangParam = getLangParamFunc;
			},
			/**
			 * @public
			 * @memberOf mmir.env.media.MaryWebAudioTTSImpl.prototype
			 */
			setVoiceParamFunc: function(getVoiceParamFunc){
				_getVoiceParam = getVoiceParamFunc;
			}
		};//END: return { ...

	};//END: createMaryTTSImpl(defaultLogger){...

});