139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi/* com_svox_picottsengine.cpp
239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
3b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
4b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *
5b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen * Licensed under the Apache License, Version 2.0 (the "License");
6b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen * you may not use this file except in compliance with the License.
7b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen * You may obtain a copy of the License at
8b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *
9b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *     http://www.apache.org/licenses/LICENSE-2.0
10b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *
11b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen * Unless required by applicable law or agreed to in writing, software
12b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen * distributed under the License is distributed on an "AS IS" BASIS,
13b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen * See the License for the specific language governing permissions and
15b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen * limitations under the License.
164bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *
174bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   This is the Manager layer.  It sits on top of the native Pico engine
184bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   and provides the interface to the defined Google TTS engine API.
194bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   The Google engine API is the boundary to allow a TTS engine to be swapped.
204bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   The Manager layer also provide the SSML tag interpretation.
214bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   The supported SSML tags are mapped to corresponding tags natively supported by Pico.
224bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   Native Pico functions always begin with picoXXX.
234bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *
244bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   In the Pico engine, the language cannot be changed indpendently of the voice.
254bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   If either the voice or locale/language are changed, a new resource is loaded.
264bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *
274bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   Only a subset of SSML 1.0 tags are supported.
284bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   Some SSML tags involve significant complexity.
294bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *   If the language is changed through an SSML tag, there is a latency for the load.
304bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi *
31b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen */
32070c0460fcdfe276cce9dbf49a883d7c6a02c5c4Jean-Michel Trivi//#define LOG_NDEBUG 0
33b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
34b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#include <stdio.h>
35b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#include <unistd.h>
364bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi#include <stdlib.h>
37b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
38b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#define LOG_TAG "SVOX Pico Engine"
39b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
40b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#include <utils/Log.h>
4139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi#include <utils/String16.h>                     /* for strlen16 */
42b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#include <android_runtime/AndroidRuntime.h>
43f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert#include <TtsEngine.h>
44f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
4539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi#include <cutils/jstring.h>
46b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#include <picoapi.h>
47b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#include <picodefs.h>
48f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
4939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi#include "svox_ssml_parser.h"
50b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
51b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chenusing namespace android;
52b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
53b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/* adaptation layer defines */
544eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi#define PICO_MEM_SIZE       2500000
5554823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi/* speaking rate    */
5639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi#define PICO_MIN_RATE        20
57b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#define PICO_MAX_RATE       500
5839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi#define PICO_DEF_RATE       100
5954823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi/* speaking pitch   */
6039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi#define PICO_MIN_PITCH       50
61b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#define PICO_MAX_PITCH      200
6239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi#define PICO_DEF_PITCH      100
6354823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi/* speaking volume  */
6439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi#define PICO_MIN_VOLUME       0
65b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#define PICO_MAX_VOLUME     500
662821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi#define PICO_DEF_VOLUME     100
6739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
6854823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi/* string constants */
69b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#define MAX_OUTBUF_SIZE     128
70a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Triviconst char * PICO_SYSTEM_LINGWARE_PATH      = "/system/tts/lang_pico/";
7139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * PICO_LINGWARE_PATH             = "/sdcard/svox/";
7239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * PICO_VOICE_NAME                = "PicoVoice";
7339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * PICO_SPEED_OPEN_TAG            = "<speed level='%d'>";
7439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * PICO_SPEED_CLOSE_TAG           = "</speed>";
7539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * PICO_PITCH_OPEN_TAG            = "<pitch level='%d'>";
7639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * PICO_PITCH_CLOSE_TAG           = "</pitch>";
7739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * PICO_VOLUME_OPEN_TAG           = "<volume level='%d'>";
7839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * PICO_VOLUME_CLOSE_TAG          = "</volume>";
7939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * PICO_PHONEME_OPEN_TAG          = "<phoneme ph='";
804bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Triviconst char * PICO_PHONEME_CLOSE_TAG         = "'/>";
8139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
8239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi/* supported voices
8339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi   Pico does not seperately specify the voice and locale.   */
8439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * picoSupportedLangIso3[]        = { "eng",              "eng",              "deu",              "spa",              "fra",              "ita" };
8539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * picoSupportedCountryIso3[]     = { "USA",              "GBR",              "DEU",              "ESP",              "FRA",              "ITA" };
861ee916b1cdb8e54192a4d11d7fae4cd0953baadbJean-Michel Triviconst char * picoSupportedLang[]            = { "en-US",            "en-GB",            "de-DE",            "es-ES",            "fr-FR",            "it-IT" };
8739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * picoInternalLang[]             = { "en-US",            "en-GB",            "de-DE",            "es-ES",            "fr-FR",            "it-IT" };
8839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * picoInternalTaLingware[]       = { "en-US_ta.bin",     "en-GB_ta.bin",     "de-DE_ta.bin",     "es-ES_ta.bin",     "fr-FR_ta.bin",     "it-IT_ta.bin" };
8939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * picoInternalSgLingware[]       = { "en-US_lh0_sg.bin", "en-GB_kh0_sg.bin", "de-DE_gl0_sg.bin", "es-ES_zl0_sg.bin", "fr-FR_nk0_sg.bin", "it-IT_cm0_sg.bin" };
9039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * picoInternalUtppLingware[]     = { "en-US_utpp.bin",   "en-GB_utpp.bin",   "de-DE_utpp.bin",   "es-ES_utpp.bin",   "fr-FR_utpp.bin",   "it-IT_utpp.bin" };
9139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst int picoNumSupportedVocs              = 6;
92b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
9354823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi/* supported properties */
9439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst char * picoSupportedProperties[]      = { "language", "rate", "pitch", "volume" };
9539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Triviconst int    picoNumSupportedProperties     = 4;
96b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
9754823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
9854823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi/* adapation layer global variables */
9939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel TrivisynthDoneCB_t * picoSynthDoneCBPtr;
10039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivivoid *          picoMemArea         = NULL;
10139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_System     picoSystem          = NULL;
10239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_Resource   picoTaResource      = NULL;
10339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_Resource   picoSgResource      = NULL;
10439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_Resource   picoUtppResource    = NULL;
10539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_Engine     picoEngine          = NULL;
10639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_Char *     picoTaFileName      = NULL;
10739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_Char *     picoSgFileName      = NULL;
10839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_Char *     picoUtppFileName    = NULL;
10939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_Char *     picoTaResourceName  = NULL;
11039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_Char *     picoSgResourceName  = NULL;
11139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivipico_Char *     picoUtppResourceName = NULL;
11254823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Triviint     picoSynthAbort = 0;
11339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivichar *  picoProp_currLang   = NULL;                 /* current language */
11454823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Triviint     picoProp_currRate   = PICO_DEF_RATE;        /* current rate     */
11554823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Triviint     picoProp_currPitch  = PICO_DEF_PITCH;       /* current pitch    */
11654823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Triviint     picoProp_currVolume = PICO_DEF_VOLUME;      /* current volume   */
11754823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
1189b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Triviint picoCurrentLangIndex = -1;
119b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
1205ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivichar * pico_alt_lingware_path = NULL;
1215ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi
122b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
123b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/* internal helper functions */
124b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
12539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi/** checkForLocale
12639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  Check whether the requested locale is among the supported locales.
1271ee916b1cdb8e54192a4d11d7fae4cd0953baadbJean-Michel Trivi *  @locale -  the locale to check, either in xx or xx-YY format
12839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  return index of the locale, or -1 if not supported.
129b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
13039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivistatic int checkForLocale( const char * locale )
131b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
13254823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi     int found = -1;                                         /* language not found   */
13339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi     int i;
13439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi     if (locale == NULL) {
13531a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("checkForLocale called with NULL language");
1364bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        return found;
13739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi     }
13854823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
13954823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi    /* Verify that the requested locale is a locale that we support.    */
1404bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    for (i = 0; i < picoNumSupportedVocs; i ++) {
1414bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (strcmp(locale, picoSupportedLang[i]) == 0) { /* in array */
142b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            found = i;
143b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            break;
144b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        }
14554823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi    };
14639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
147410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi    /* The exact locale was not found.    */
1484bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (found < 0) {
14954823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi        /* We didn't find an exact match; it may have been specified with only the first 2 characters.
15039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi           This could overmatch ISO 639-3 language codes.%%                                   */
151410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi
152410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi        /* check whether the current language matches the locale's language */
153410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi        if ((picoCurrentLangIndex > -1) &&
154410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi                (strncmp(locale, picoSupportedLang[picoCurrentLangIndex], 2) == 0)) {
155410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi            /* the current language matches the requested language, let's use it */
156410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi            found = picoCurrentLangIndex;
157410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi        } else {
158410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi            /* check whether we can find a match at least on the language */
159410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi            for (i = 0; i < picoNumSupportedVocs; i ++) {
160410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi                if (strncmp(locale, picoSupportedLang[i], 2) == 0) {
161410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi                    found = i;
162410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi                    break;
163410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi                }
164b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            }
165b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        }
166410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi
1674bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (found < 0) {
16831a809cefabaafd5b82574df08615855f1019a43Steve Block            ALOGE("TtsEngine::set language called with unsupported locale %s", locale);
169b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        }
17054823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi    };
171b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    return found;
172b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
173b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
17454823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
175b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/** cleanResources
17654823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi *  Unloads any loaded Pico resources.
177b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
17854823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivistatic void cleanResources( void )
179b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
1804bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoEngine) {
18154823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi        pico_disposeEngine( picoSystem, &picoEngine );
18239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        pico_releaseVoiceDefinition( picoSystem, (pico_Char *) PICO_VOICE_NAME );
183b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoEngine = NULL;
184b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
1854bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoUtppResource) {
18654823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi        pico_unloadResource( picoSystem, &picoUtppResource );
187b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoUtppResource = NULL;
188b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
1894bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoTaResource) {
19054823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi        pico_unloadResource( picoSystem, &picoTaResource );
191b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoTaResource = NULL;
192b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
1934bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoSgResource) {
19454823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi        pico_unloadResource( picoSystem, &picoSgResource );
195b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoSgResource = NULL;
196b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
197dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi
198dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi    if (picoSystem) {
199dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        pico_terminate(&picoSystem);
200dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        picoSystem = NULL;
201dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi    }
2029b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    picoCurrentLangIndex = -1;
203b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
204b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
20554823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
206b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/** cleanFiles
20754823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi *  Frees any memory allocated for file and resource strings.
208b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
20954823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivistatic void cleanFiles( void )
210b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
2114bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoProp_currLang) {
21239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        free( picoProp_currLang );
213b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoProp_currLang = NULL;
214b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
2154eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
2164bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoTaFileName) {
21739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        free( picoTaFileName );
218b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoTaFileName = NULL;
219b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
2204eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
2214bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoSgFileName) {
22239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        free( picoSgFileName );
223b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoSgFileName = NULL;
224b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
2254eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
2264bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoUtppFileName) {
22739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        free( picoUtppFileName );
228b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoUtppFileName = NULL;
229b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
2304eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
2314bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoTaResourceName) {
23239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        free( picoTaResourceName );
233b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoTaResourceName = NULL;
234b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
2354eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
2364bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoSgResourceName) {
23739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        free( picoSgResourceName );
238b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoSgResourceName = NULL;
239b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
2404eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
2414bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoUtppResourceName) {
24239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        free( picoUtppResourceName );
243b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoUtppResourceName = NULL;
244b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
245b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
246b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
2479b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi/** hasResourcesForLanguage
2489b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi *  Check to see if the resources required to load the language at the specified index
2499b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi *  are properly installed
2509b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi *  @langIndex - the index of the language to check the resources for. The index is valid.
2519b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi *  return true if the required resources are installed, false otherwise
2529b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi */
2539b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivistatic bool hasResourcesForLanguage(int langIndex) {
2549b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    FILE * pFile;
2559b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    char* fileName = (char*)malloc(PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE);
2564bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi
257a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    /* check resources on system (under PICO_SYSTEM_LINGWARE_PATH). */
258a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    strcpy((char*)fileName, PICO_SYSTEM_LINGWARE_PATH);
259a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    strcat((char*)fileName, (const char*)picoInternalTaLingware[langIndex]);
260a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    pFile = fopen(fileName, "r");
261a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    if (pFile != NULL) {
262a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        /* "ta" file found. */
263a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        fclose (pFile);
264a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        /* now look for "sg" file. */
265a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        strcpy((char*)fileName, PICO_SYSTEM_LINGWARE_PATH);
266a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        strcat((char*)fileName, (const char*)picoInternalSgLingware[langIndex]);
267a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        pFile = fopen(fileName, "r");
268a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        if (pFile != NULL) {
269a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi            /* "sg" file found, no need to continue checking, return success. */
270a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi            fclose(pFile);
271a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi            free(fileName);
272a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi            return true;
273a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        }
274a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    }
275a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi
276a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    /* resources not found on system, check resources on alternative location */
2775ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi    /* (under pico_alt_lingware_path).                                            */
2785ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi    strcpy((char*)fileName, pico_alt_lingware_path);
2799b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    strcat((char*)fileName, (const char*)picoInternalTaLingware[langIndex]);
2804bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    pFile = fopen(fileName, "r");
2814bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (pFile == NULL) {
2829b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        free(fileName);
2839b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        return false;
2849b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    } else {
2859b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        fclose (pFile);
2869b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    }
2879b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi
2885ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi    strcpy((char*)fileName, pico_alt_lingware_path);
2899b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    strcat((char*)fileName, (const char*)picoInternalSgLingware[langIndex]);
2909b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    pFile = fopen(fileName, "r");
2919b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    if (pFile == NULL) {
2929b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        free(fileName);
2939b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        return false;
2949b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    } else {
2959b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        fclose(pFile);
2969b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        free(fileName);
2979b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        return true;
2989b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    }
2999b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi}
3009b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi
3014eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi/** doLanguageSwitchFromLangIndex
30239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  Switch to the requested locale.
30339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  If the locale is already loaded, it returns immediately.
30439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  If another locale is already is loaded, it will first be unloaded and the new one then loaded.
30539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  If no locale is loaded, the requested locale will be loaded.
30639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @langIndex -  the index of the locale/voice to load, which is guaranteed to be supported.
307b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  return TTS_SUCCESS or TTS_FAILURE
3084eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi */
30939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivistatic tts_result doLanguageSwitchFromLangIndex( int langIndex )
310b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
31139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int ret;                                        /* function result code */
31239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
313dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi    if (langIndex>=0) {
314dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        /* If we already have a loaded locale, check whether it is the same one as requested.   */
315dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        if (picoProp_currLang && (strcmp(picoProp_currLang, picoSupportedLang[langIndex]) == 0)) {
316659851c7b5a2d0023266bf34634179ff8d08e3baSteve Block            //ALOGI("Language already loaded (%s == %s)", picoProp_currLang,
317410a1a0acbd50d7a73f0b2dbfc3e52c0808fc98dJean-Michel Trivi            //        picoSupportedLang[langIndex]);
318dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi            return TTS_SUCCESS;
319dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        }
320b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
321b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
322dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi    /* It is not the same locale; unload the current one first. Also invalidates the system object*/
323b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    cleanResources();
3244eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
32539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Allocate memory for file and resource names.     */
326b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    cleanFiles();
327dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi
328dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi    if (picoSystem==NULL) {
329dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        /*re-init system object*/
330dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        ret = pico_initialize( picoMemArea, PICO_MEM_SIZE, &picoSystem );
331dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        if (PICO_OK != ret) {
33231a809cefabaafd5b82574df08615855f1019a43Steve Block            ALOGE("Failed to initialize the pico system object\n");
333dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi            return TTS_FAILURE;
334dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        }
335dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi    }
336dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi
33739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    picoProp_currLang   = (char *)      malloc( 10 );
33839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    picoTaFileName      = (pico_Char *) malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE );
33939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    picoSgFileName      = (pico_Char *) malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE );
34039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    picoUtppFileName    = (pico_Char *) malloc( PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE );
34139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    picoTaResourceName  = (pico_Char *) malloc( PICO_MAX_RESOURCE_NAME_SIZE );
34239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    picoSgResourceName  = (pico_Char *) malloc( PICO_MAX_RESOURCE_NAME_SIZE );
34339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    picoUtppResourceName =(pico_Char *) malloc( PICO_MAX_RESOURCE_NAME_SIZE );
34439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
345dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi    if (
346dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        (picoProp_currLang==NULL) || (picoTaFileName==NULL) || (picoSgFileName==NULL) ||
347dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        (picoUtppFileName==NULL) || (picoTaResourceName==NULL) || (picoSgResourceName==NULL) ||
348dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        (picoUtppResourceName==NULL)
349dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        ) {
35031a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to allocate memory for internal strings\n");
351dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        cleanResources();
352dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi        return TTS_FAILURE;
353dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi    }
354dd1501a7191f7be46c119296ae5bcf2c3dc6e5e8Jean-Michel Trivi
355a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    /* Find where to load the resource files from: system or alternative location              */
356a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    /* based on availability of the Ta file. Try the alternative location first, this is where */
3575ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi    /* more recent language file updates would be installed (under pico_alt_lingware_path).        */
358a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    bool bUseSystemPath = true;
359a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    FILE * pFile;
360a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    char* tmpFileName = (char*)malloc(PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE);
3615ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi    strcpy((char*)tmpFileName, pico_alt_lingware_path);
362a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    strcat((char*)tmpFileName, (const char*)picoInternalTaLingware[langIndex]);
363a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    pFile = fopen(tmpFileName, "r");
364a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    if (pFile != NULL) {
3655ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi        /* "ta" file found under pico_alt_lingware_path, don't use the system path. */
366a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        fclose (pFile);
367a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        bUseSystemPath = false;
368a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    }
369a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    free(tmpFileName);
370a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi
37139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Set the path and file names for resource files.  */
372a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    if (bUseSystemPath) {
373a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        strcpy((char *) picoTaFileName,   PICO_SYSTEM_LINGWARE_PATH);
374a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        strcpy((char *) picoSgFileName,   PICO_SYSTEM_LINGWARE_PATH);
375a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi        strcpy((char *) picoUtppFileName, PICO_SYSTEM_LINGWARE_PATH);
376a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    } else {
3775ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi        strcpy((char *) picoTaFileName,   pico_alt_lingware_path);
3785ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi        strcpy((char *) picoSgFileName,   pico_alt_lingware_path);
3795ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi        strcpy((char *) picoUtppFileName, pico_alt_lingware_path);
380a8d076f716bca609b7e740cd888177fbc589a521Jean-Michel Trivi    }
38139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    strcat((char *) picoTaFileName,   (const char *) picoInternalTaLingware[langIndex]);
38239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    strcat((char *) picoSgFileName,   (const char *) picoInternalSgLingware[langIndex]);
38339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    strcat((char *) picoUtppFileName, (const char *) picoInternalUtppLingware[langIndex]);
38439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
38539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Load the text analysis Lingware resource file.   */
38639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    ret = pico_loadResource( picoSystem, picoTaFileName, &picoTaResource );
3874bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (PICO_OK != ret) {
38831a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to load textana resource for %s [%d]", picoSupportedLang[langIndex], ret);
389b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanResources();
390b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanFiles();
391b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
392b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
3934eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
39439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Load the signal generation Lingware resource file.   */
39539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    ret = pico_loadResource( picoSystem, picoSgFileName, &picoSgResource );
3964bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (PICO_OK != ret) {
39731a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to load siggen resource for %s [%d]", picoSupportedLang[langIndex], ret);
398b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanResources();
399b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanFiles();
400b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
401b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
4024eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
40339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Load the utpp Lingware resource file if exists - NOTE: this file is optional
40439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       and is currently not used. Loading is only attempted for future compatibility.
40539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       If this file is not present the loading will still succeed.                      */
40639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    ret = pico_loadResource( picoSystem, picoUtppFileName, &picoUtppResource );
4074bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if ((PICO_OK != ret) && (ret != PICO_EXC_CANT_OPEN_FILE)) {
40831a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to load utpp resource for %s [%d]", picoSupportedLang[langIndex], ret);
409b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanResources();
410b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanFiles();
411b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
4124bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
4134eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
41439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Get the text analysis resource name.     */
41539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    ret = pico_getResourceName( picoSystem, picoTaResource, (char *) picoTaResourceName );
4164bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (PICO_OK != ret) {
41731a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to get textana resource name for %s [%d]", picoSupportedLang[langIndex], ret);
418b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanResources();
419b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanFiles();
420b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
421b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
4224eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
42339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Get the signal generation resource name. */
42439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    ret = pico_getResourceName( picoSystem, picoSgResource, (char *) picoSgResourceName );
425744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    if ((PICO_OK == ret) && (picoUtppResource != NULL)) {
42639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        /* Get utpp resource name - optional: see note above.   */
42739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        ret = pico_getResourceName( picoSystem, picoUtppResource, (char *) picoUtppResourceName );
4284bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (PICO_OK != ret)  {
42931a809cefabaafd5b82574df08615855f1019a43Steve Block            ALOGE("Failed to get utpp resource name for %s [%d]", picoSupportedLang[langIndex], ret);
430b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            cleanResources();
431b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            cleanFiles();
432b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            return TTS_FAILURE;
433b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        }
434b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
4354bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (PICO_OK != ret) {
43631a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to get siggen resource name for %s [%d]", picoSupportedLang[langIndex], ret);
437b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanResources();
438b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanFiles();
439b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
440b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
4414eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
44239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Create a voice definition.   */
44339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    ret = pico_createVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME );
4444bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (PICO_OK != ret) {
44531a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to create voice for %s [%d]", picoSupportedLang[langIndex], ret);
446b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanResources();
447b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanFiles();
448b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
449b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
4504eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
45139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Add the text analysis resource to the voice. */
45239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    ret = pico_addResourceToVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME, picoTaResourceName );
4534bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (PICO_OK != ret) {
45431a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to add textana resource to voice for %s [%d]", picoSupportedLang[langIndex], ret);
455b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanResources();
456b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanFiles();
457b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
458b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
4594eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
46039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Add the signal generation resource to the voice. */
46139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    ret = pico_addResourceToVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME, picoSgResourceName );
462744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    if ((PICO_OK == ret) && (picoUtppResource != NULL)) {
46339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        /* Add utpp resource to voice - optional: see note above.   */
46439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        ret = pico_addResourceToVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME, picoUtppResourceName );
4654bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (PICO_OK != ret) {
46631a809cefabaafd5b82574df08615855f1019a43Steve Block            ALOGE("Failed to add utpp resource to voice for %s [%d]", picoSupportedLang[langIndex], ret);
467b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            cleanResources();
468b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            cleanFiles();
469b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            return TTS_FAILURE;
470b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        }
471b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
4724eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
4734bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (PICO_OK != ret) {
47431a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to add siggen resource to voice for %s [%d]", picoSupportedLang[langIndex], ret);
475b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanResources();
476b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanFiles();
477b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
478b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
479b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
48039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    ret = pico_newEngine( picoSystem, (const pico_Char *) PICO_VOICE_NAME, &picoEngine );
4814bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (PICO_OK != ret) {
48231a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to create engine for %s [%d]", picoSupportedLang[langIndex], ret);
483b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanResources();
484b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        cleanFiles();
485b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
486b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
4874eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
48839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Set the current locale/voice.    */
48939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    strcpy( picoProp_currLang, picoSupportedLang[langIndex] );
4905da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi    picoCurrentLangIndex = langIndex;
491659851c7b5a2d0023266bf34634179ff8d08e3baSteve Block    ALOGI("loaded %s successfully", picoProp_currLang);
492b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    return TTS_SUCCESS;
493b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
494b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
49539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
4964eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi/** doLanguageSwitch
49739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  Switch to the requested locale.
49839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  If this locale is already loaded, it returns immediately.
49939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  If another locale is already loaded, this will first be unloaded
50039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  and the new one then loaded.
50139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  If no locale is loaded, the requested will be loaded.
5021ee916b1cdb8e54192a4d11d7fae4cd0953baadbJean-Michel Trivi *  @locale -  the locale to check, either in xx or xx-YY format (i.e "en" or "en-US")
5034eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi *  return TTS_SUCCESS or TTS_FAILURE
5044eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi*/
50539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivistatic tts_result doLanguageSwitch( const char * locale )
5064eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi{
50739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int loclIndex;                              /* locale index */
5084eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
50939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Load the new locale. */
51039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    loclIndex = checkForLocale( locale );
5114bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (loclIndex < 0)  {
51231a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Tried to swith to non-supported locale %s", locale);
51339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        return TTS_FAILURE;
5144bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
515659851c7b5a2d0023266bf34634179ff8d08e3baSteve Block    //ALOGI("Found supported locale %s", picoSupportedLang[loclIndex]);
51639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    return doLanguageSwitchFromLangIndex( loclIndex );
5174eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi}
5184eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
51939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
520b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/** doAddProperties
52139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  Add <speed>, <pitch> and <volume> tags to the text,
52239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  if the properties have been set to non-default values, and return the new string.
52339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  The calling function is responsible for freeing the returned string.
524b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  @str - text to apply tags to
525b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  return new string with tags applied
526b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
52739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivistatic char * doAddProperties( const char * str )
528b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
52939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    char *  data = NULL;
53039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int     haspitch, hasspeed, hasvol;                 /* parameters           */
53139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int     textlen;                                    /* property string length   */
53239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    haspitch = 0; hasspeed = 0; hasvol = 0;
53339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    textlen = strlen(str) + 1;
5344bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoProp_currPitch != PICO_DEF_PITCH) {          /* non-default pitch    */
535b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        textlen += strlen(PICO_PITCH_OPEN_TAG) + 5;
536b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        textlen += strlen(PICO_PITCH_CLOSE_TAG);
537b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        haspitch = 1;
538b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
5394bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoProp_currRate != PICO_DEF_RATE) {            /* non-default rate     */
540b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        textlen += strlen(PICO_SPEED_OPEN_TAG) + 5;
541b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        textlen += strlen(PICO_SPEED_CLOSE_TAG);
542b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        hasspeed = 1;
543b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
544474a319cfd410d4bbc5c76d0b382348181f499b8Charles Chen
5452821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi    if (picoProp_currVolume != PICO_DEF_VOLUME) {        /* non-default volume   */
546b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        textlen += strlen(PICO_VOLUME_OPEN_TAG) + 5;
547b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        textlen += strlen(PICO_VOLUME_CLOSE_TAG);
548b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        hasvol = 1;
5492821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi    }
5504eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
55139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Compose the property strings.    */
55239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    data = (char *) malloc( textlen );                  /* allocate string      */
5534bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (!data) {
554b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return NULL;
555b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
55654823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi    memset(data, 0, textlen);                           /* clear it             */
5574bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (haspitch) {
558b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        char* tmp = (char*)malloc(strlen(PICO_PITCH_OPEN_TAG) + strlen(PICO_PITCH_CLOSE_TAG) + 5);
559b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        sprintf(tmp, PICO_PITCH_OPEN_TAG, picoProp_currPitch);
560b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        strcat(data, tmp);
561b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        free(tmp);
562b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
5634eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
5644bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (hasspeed) {
565b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        char* tmp = (char*)malloc(strlen(PICO_SPEED_OPEN_TAG) + strlen(PICO_SPEED_CLOSE_TAG) + 5);
566b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        sprintf(tmp, PICO_SPEED_OPEN_TAG, picoProp_currRate);
567b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        strcat(data, tmp);
568b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        free(tmp);
569b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
5704eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
5714bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (hasvol) {
572b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        char* tmp = (char*)malloc(strlen(PICO_VOLUME_OPEN_TAG) + strlen(PICO_VOLUME_CLOSE_TAG) + 5);
573b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        sprintf(tmp, PICO_VOLUME_OPEN_TAG, picoProp_currVolume);
574b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        strcat(data, tmp);
575b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        free(tmp);
576b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
5774eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
578b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    strcat(data, str);
5794bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (hasvol) {
580b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        strcat(data, PICO_VOLUME_CLOSE_TAG);
581b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
5824eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
5834bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (hasspeed) {
584b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        strcat(data, PICO_SPEED_CLOSE_TAG);
585b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
5864eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
5874bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (haspitch) {
588b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        strcat(data, PICO_PITCH_CLOSE_TAG);
589b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
590b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    return data;
591b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
592b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
59354823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
594d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi/** get_tok
595d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  Searches for tokens in a string
596d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @str - text to be processed
597d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @pos - position of first character to be searched in str
598d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @textlen - postion of last character to be searched
599d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @tokstart - address of a variable to receive the start of the token found
600d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @tokstart - address of a variable to receive the length of the token found
601d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  return : 1=token found, 0=token not found
602d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  notes : the token separator set could be enlarged adding characters in "seps"
603d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi*/
604d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivistatic int  get_tok(const char * str , int pos, int textlen, int *tokstart, int *toklen)
605d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi{
606d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    const char * seps = " ";
607d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
608d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    /*look for start*/
609d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    while ((pos<textlen) && (strchr(seps,str[pos]) != NULL)) {
610d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        pos++;
611d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
612d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    if (pos == textlen) {
613d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        /*no characters != seps found whithin string*/
614d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        return 0;
615d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
616d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    *tokstart = pos;
617d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    /*look for end*/
618d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    while ((pos<textlen) && (strchr(seps,str[pos]) == NULL)) {
619d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        pos++;
620d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
621d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    *toklen = pos - *tokstart;
622d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    return 1;
623d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi}/*get_tok*/
624d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
625d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
626d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi/** get_sub_tok
627d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  Searches for subtokens in a token having a compound structure with camel case like "xxxYyyy"
628d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @str - text to be processed
629d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @pos - position of first character to be searched in str
630d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @textlen - postion of last character to be searched in str
631d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @tokstart - address of a variable to receive the start of the sub token found
632d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @tokstart - address of a variable to receive the length of the sub token found
633d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  return : 1=sub token found, 0=sub token not found
634d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  notes : the sub token separator set could be enlarged adding characters in "seps"
635d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi*/
636d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivistatic int  get_sub_tok(const char * str , int pos, int textlen, int *tokstart, int *toklen) {
637d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
638d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    const char * seps = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
639d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
640d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    if (pos == textlen) {
641d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        return 0;
642d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
643d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
644d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    /*first char != space*/
645d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    *tokstart = pos;
646d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    /*finding first non separator*/
647d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    while ((pos < textlen) && (strchr(seps, str[pos]) != NULL)) {
648d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        pos++;
649d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
650d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    if (pos == textlen) {
651d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        /*characters all in seps found whithin string : return full token*/
652d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        *toklen = pos - *tokstart;
653d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        return 1;
654d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
655d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    /*pos should be pointing to first non seps and more chars are there*/
656d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    /*finding first separator*/
657d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    while ((pos < textlen) && (strchr(seps, str[pos]) == NULL)) {
658d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        pos++;
659d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
660d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    if (pos == textlen) {
661d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        /*transition non seps->seps not found : return full token*/
662d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        *toklen = pos - *tokstart;
663d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        return 1;
664d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
665d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    *toklen = pos - *tokstart;
666d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    return 1;
667d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi}/*get_sub_tok*/
668d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
669d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
670d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi/** doCamelCase
671d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  Searches for tokens having a compound structure with camel case and transforms them as follows :
672d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *        "XxxxYyyy" -->> "Xxxx Yyyy",
673d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *        "xxxYyyy"  -->> "xxx Yyyy",
674d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *        "XXXYyyy"  -->> "XXXYyyy"
675d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *        etc....
676d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  The calling function is responsible for freeing the returned string.
677d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  @str - text to be processed
678d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi *  return new string with text processed
679d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi*/
680d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivistatic char * doCamelCase( const char * str )
681d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi{
682d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    int     textlen;             /* input string length   */
683d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    int     totlen;              /* output string length   */
684d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    int     tlen_2, nsubtok;     /* nuber of subtokens   */
685d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    int     toklen, tokstart;    /*legnth and start of generic token*/
686d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    int     stoklen, stokstart;  /*legnth and start of generic sub-token*/
687d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    int     pos, tokpos, outpos; /*postion of current char in input string and token and output*/
688d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    char    *data;               /*pointer of the returned string*/
689d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
690d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    pos = 0;
691d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    tokpos = 0;
692d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    toklen = 0;
693d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    stoklen = 0;
694d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    tlen_2 = 0;
695d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    totlen = 0;
696d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
697d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    textlen = strlen(str) + 1;
698d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
699d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    /*counting characters after sub token splitting including spaces*/
700d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    //while ((pos<textlen) && (str[pos]!=0)) {
701d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    while (get_tok(str, pos, textlen, &tokstart, &toklen)) {
702d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        tokpos = tokstart;
703d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        tlen_2 = 0;
704d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        nsubtok = 0;
705d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        while (get_sub_tok(str, tokpos, tokstart+toklen, &stokstart, &stoklen)) {
706d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            totlen += stoklen;
707d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            tlen_2 += stoklen;
708d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            tokpos = stokstart + stoklen;
709d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            nsubtok += 1;
710d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        }
711d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        totlen += nsubtok;    /*add spaces between subtokens*/
712d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        pos = tokstart + tlen_2;
713d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
714d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    //}
715d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    /* Allocate the return string */
7162821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi
717d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    data = (char *) malloc( totlen );                  /* allocate string      */
718d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    if (!data) {
719d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        return NULL;
720d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
721d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    memset(data, 0, totlen);                           /* clear it             */
722d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    outpos = 0;
723d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    pos = 0;
724d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    /*copying characters*/
725d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    //while ((pos<textlen) && (str[pos]!=0)) {
726d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    while (get_tok  (str, pos, textlen, &tokstart, &toklen)) {
727d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        tokpos = tokstart;
728d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        tlen_2 = 0;
729d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        nsubtok = 0;
730d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        while (get_sub_tok(str, tokpos, tokstart+toklen, &stokstart, &stoklen)) {
731d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            strncpy(&(data[outpos]), &(str[stokstart]), stoklen);
732d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            outpos += stoklen;
733d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            strncpy(&(data[outpos]), " ", 1);
734d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            tlen_2 += stoklen;
735d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            outpos += 1;
736d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            tokpos = stokstart + stoklen;
737d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        }
738d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        pos=tokstart+tlen_2;
739d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    }
740d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    //}
7412821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi    if (outpos == 0) {
7422821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi        outpos = 1;
7432821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi    }
7442821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi    data[outpos-1] = 0;
745d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    return data;
746d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi}/*doCamelCase*/
747d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
748d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi
74939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi/** createPhonemeString
75039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  Wrap all individual words in <phoneme> tags.
75139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  The Pico <phoneme> tag only supports one word in each tag,
75239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  therefore they must be individually wrapped!
75339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @xsampa - text to convert to Pico phomene string
75439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @length - length of the input string
75539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  return new string with tags applied
75639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi*/
7574bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Triviextern char * createPhonemeString( const char * xsampa, int length )
75839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi{
75939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    char *  convstring = NULL;
76039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int     origStrLen = strlen(xsampa);
76139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int     numWords   = 1;
76239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int     start, totalLength, i, j;
76339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
764744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    for (i = 0; i < origStrLen; i ++) {
765744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        if ((xsampa[i] == ' ') || (xsampa[i] == '#')) {
766744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi            numWords ++;
767744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        }
768744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    }
769744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi
770744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    if (numWords == 1) {
771744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        convstring = new char[origStrLen + 17];
772744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        convstring[0] = '\0';
773744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        strcat(convstring, PICO_PHONEME_OPEN_TAG);
774744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        strcat(convstring, xsampa);
775744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        strcat(convstring, PICO_PHONEME_CLOSE_TAG);
776744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    } else {
777744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        char * words[numWords];
778744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        start = 0; totalLength = 0; i = 0; j = 0;
779744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        for (i=0, j=0; i < origStrLen; i++) {
780744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi            if ((xsampa[i] == ' ') || (xsampa[i] == '#')) {
781744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi                words[j]    = new char[i+1-start+17];
782744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi                words[j][0] = '\0';
783744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi                strcat( words[j], PICO_PHONEME_OPEN_TAG);
784744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi                strncat(words[j], xsampa+start, i-start);
785744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi                strcat( words[j], PICO_PHONEME_CLOSE_TAG);
786744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi                start = i + 1;
787744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi                j++;
788744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi                totalLength += strlen(words[j-1]);
789744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi            }
790744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        }
791744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        words[j]    = new char[i+1-start+17];
792744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        words[j][0] = '\0';
793744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        strcat(words[j], PICO_PHONEME_OPEN_TAG);
794744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        strcat(words[j], xsampa+start);
795744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        strcat(words[j], PICO_PHONEME_CLOSE_TAG);
796744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        totalLength += strlen(words[j]);
797744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        convstring = new char[totalLength + 1];
798744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        convstring[0] = '\0';
799744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        for (i=0 ; i < numWords ; i++) {
800744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi            strcat(convstring, words[i]);
801744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi            delete [] words[i];
802744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        }
803744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    }
804744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi
805744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    return convstring;
80639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi}
80739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
8084bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi/* The XSAMPA uses as many as 5 characters to represent a single IPA code.  */
80939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivitypedef struct tagPhnArr
8104bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi{
81139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    char16_t    strIPA;             /* IPA Unicode symbol       */
8124bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    char        strXSAMPA[6];       /* SAMPA sequence           */
8134bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi} PArr;
81439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
815e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi#define phn_cnt (134+7)
81639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
81739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel TriviPArr    PhnAry[phn_cnt] = {
81839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
819e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    /* XSAMPA conversion table
820e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi	   This maps a single IPA symbol to a sequence representing XSAMPA.
821e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi       This relies upon a direct one-to-one correspondance
822e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi       including diphthongs and affricates.						      */
82339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
824e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    /* Vowels (23) complete     */
82539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x025B,        "E"},
82639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0251,        "A"},
82739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0254,        "O"},
82839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x00F8,        "2"},
82939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0153,        "9"},
83039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0276,        "&"},
83139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0252,        "Q"},
83239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x028C,        "V"},
83339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0264,        "7"},
83439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x026F,        "M"},
83539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0268,        "1"},
83639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0289,        "}"},
83739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x026A,        "I"},
83839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x028F,        "Y"},
83939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x028A,        "U"},
84039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0259,        "@"},
84139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0275,        "8"},
84239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0250,        "6"},
84339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x00E6,        "{"},
84439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x025C,        "3"},
8454bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x025A,        "@`"},
8464bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x025E,        "3\\\\"},
8474bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0258,        "@\\\\"},
84839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
849e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    /* Consonants (60) complete */
8504bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0288,        "t`"},
8514bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0256,        "d`"},
8524bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x025F,        "J\\\\"},
85339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0261,        "g"},
8544bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0262,        "G\\\\"},
85539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0294,        "?"},
85639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0271,        "F"},
8574bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0273,        "n`"},
85839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0272,        "J"},
85939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x014B,        "N"},
8604bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0274,        "N\\\\"},
8614bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0299,        "B\\\\"},
8624bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0280,        "R\\\\"},
86339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x027E,        "4"},
8644bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x027D,        "r`"},
8654bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0278,        "p\\\\"},
86639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x03B2,        "B"},
86739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x03B8,        "T"},
86839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x00F0,        "D"},
86939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0283,        "S"},
87039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0292,        "Z"},
8714bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0282,        "s`"},
8724bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0290,        "z`"},
87339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x00E7,        "C"},
8744bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x029D,        "j\\\\"},
87539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0263,        "G"},
87639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x03C7,        "X"},
87739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0281,        "R"},
8784bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0127,        "X\\\\"},
8794bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0295,        "?\\\\"},
8804bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0266,        "h\\\\"},
88139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x026C,        "K"},
8824bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x026E,        "K\\\\"},
88339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x028B,        "P"},
8844bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0279,        "r\\\\"},
8854bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x027B,        "r\\\\'"},
8864bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0270,        "M\\\\"},
8874bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x026D,        "l`"},
88839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x028E,        "L"},
8894bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x029F,        "L\\\\"},
89039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0253,        "b_<"},
89139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0257,        "d_<"},
89239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0284,        "J\\_<"},
89339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0260,        "g_<"},
89439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x029B,        "G\\_<"},
89539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x028D,        "W"},
89639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0265,        "H"},
8974bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x029C,        "H\\\\"},
8984bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x02A1,        ">\\\\"},
8994bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x02A2,        "<\\\\"},
900e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x0267,        "x\\\\"},		/* hooktop heng	*/
9014bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0298,        "O\\\\"},
9024bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x01C0,        "|\\\\"},
9034bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x01C3,        "!\\\\"},
90439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x01C2,        "=\\"},
90539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x01C1,        "|\\|\\"},
9064bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x027A,        "l\\\\"},
9074bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0255,        "s\\\\"},
9084bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x0291,        "z\\\\"},
90939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x026B,        "l_G"},
91039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
911e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi
912e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    /* Diacritics (37) complete */
91339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x02BC,        "_>"},
91439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0325,        "_0"},
91539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x030A,        "_0"},
91639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x032C,        "_v"},
91739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x02B0,        "_h"},
91839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0324,        "_t"},
91939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0330,        "_k"},
92039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x033C,        "_N"},
92139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x032A,        "_d"},
92239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x033A,        "_a"},
92339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x033B,        "_m"},
92439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0339,        "_O"},
92539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x031C,        "_c"},
92639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x031F,        "_+"},
92739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0320,        "_-"},
928e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x0308,        "_\""},     /* centralized		*/
92939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x033D,        "_x"},
93039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0318,        "_A"},
93139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0319,        "_q"},
9324bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x02DE,        "`"},
93339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x02B7,        "_w"},
93439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x02B2,        "_j"},
93539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x02E0,        "_G"},
936e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x02E4,        "_?\\\\"},	/* pharyngealized	*/
937e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x0303,        "~"},		/* nasalized		*/
93839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x207F,        "_n"},
93939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x02E1,        "_l"},
94039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x031A,        "_}"},
94139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x0334,        "_e"},
942e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x031D,        "_r"},		/* raised  equivalent to 02D4 */
943e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x02D4,        "_r"},		/* raised  equivalent to 031D */
944e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x031E,        "_o"},		/* lowered equivalent to 02D5 */
945e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x02D5,        "_o"},		/* lowered equivalent to 031E */
946e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x0329,        "="},		/* sylabic			*/
947e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x032F,        "_^"},		/* non-sylabic		*/
948e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x0361,        "_"},		/* top tie bar		*/
94939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x035C,        "_"},
950e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi
951e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    /* Suprasegmental (15) incomplete */
952e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x02C8,        "\""},		/* primary   stress	*/
953e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x02CC,        "%"},		/* secondary stress	*/
954e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x02D0,        ":"},		/* long				*/
955e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x02D1,        ":\\\\"},	/* half-long		*/
956e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x0306,        "_X"},		/* extra short		*/
957e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi
958e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x2016,        "||"},		/* major group		*/
959e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x203F,        "-\\\\"},	/* bottom tie bar	*/
960e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x2197,        "<R>"},		/* global rise		*/
961e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x2198,        "<F>"},		/* global fall		*/
962e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x2193,        "<D>"},		/* downstep			*/
963e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x2191,        "<U>"},		/* upstep			*/
964e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x02E5,        "<T>"},		/* extra high level	*/
965e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x02E7,        "<M>"},		/* mid level		*/
966e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi    {0x02E9,        "<B>"},		/* extra low level	*/
967e76209c9322210aaf4cb36b4d3a5f727510ef7b9Jean-Michel Trivi
9683cebc19d44aba7d72b0154655cdd2b70cb2be32aJean-Michel Trivi    {0x025D,        "3`:"},		/* non-IPA	%%		*/
96939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
97039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Affricates (6) complete  */
97139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x02A3,        "d_z"},
97239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x02A4,        "d_Z"},
9734bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x02A5,        "d_z\\\\"},
97439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x02A6,        "t_s"},
97539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    {0x02A7,        "t_S"},
9764bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    {0x02A8,        "t_s\\\\"}
97739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    };
97839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
97939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
98039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivivoid CnvIPAPnt( const char16_t IPnt, char * XPnt )
98139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi{
98239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    char16_t        ThisPnt = IPnt;                     /* local copy of single IPA codepoint   */
98339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int             idx;                                /* index into table         */
984744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi
98539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Convert an individual IPA codepoint.
98639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       A single IPA code could map to a string.
98739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       Search the table.  If it is not found, use the same character.
98839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       Since most codepoints can be contained within 16 bits,
98939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       they are represented as wide chars.              */
99039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    XPnt[0] = 0;                                        /* clear the result string  */
99139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
99239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Search the table for the conversion. */
9934bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    for (idx = 0; idx < phn_cnt; idx ++) {               /* for each item in table   */
994744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        if (IPnt == PhnAry[idx].strIPA) {                /* matches IPA code         */
9954bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            strcat( XPnt, (const char *)&(PhnAry[idx].strXSAMPA) ); /* copy the XSAMPA string   */
9964bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            return;
99739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        }
9984bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
99939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    strcat(XPnt, (const char *)&ThisPnt);               /* just copy it             */
100039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi}
100139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
100239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
100339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi/** cnvIpaToXsampa
100439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  Convert an IPA character string to an XSAMPA character string.
100539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @ipaString - input IPA string to convert
100639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @outXsampaString - converted XSAMPA string is passed back in this parameter
100739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  return size of the new string
100839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi*/
10094bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi
10104bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Triviint cnvIpaToXsampa( const char16_t * ipaString, size_t ipaStringSize, char ** outXsampaString )
101139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi{
10124bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    size_t xsize;                                  /* size of result               */
1013d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    size_t ipidx;                                  /* index into IPA string        */
10144bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    char * XPnt;                                   /* short XSAMPA char sequence   */
101539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
101639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Convert an IPA string to an XSAMPA string and store the xsampa string in *outXsampaString.
101739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       It is the responsibility of the caller to free the allocated string.
101839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       Increment through the string.  For each base & combination convert it to the XSAMP equivalent.
101939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       Because of the XSAMPA limitations, not all IPA characters will be covered.       */
102039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    XPnt = (char *) malloc(6);
10214bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    xsize   = (4 * ipaStringSize) + 8;          /* assume more than double size */
1022744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    *outXsampaString = (char *) malloc( xsize );/* allocate return string   */
102339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    *outXsampaString[0] = 0;
1024744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    xsize = 0;                                  /* clear final              */
10254bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi
1026744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    for (ipidx = 0; ipidx < ipaStringSize; ipidx ++) { /* for each IPA code        */
1027744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        CnvIPAPnt( ipaString[ipidx], XPnt );           /* get converted character  */
1028744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi        strcat((char *)*outXsampaString, XPnt );       /* concatenate XSAMPA       */
10294bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
103039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    free(XPnt);
1031744a0e6d86f037a9f815adbcbb2dc5f410aa5007Jean-Michel Trivi    xsize = strlen(*outXsampaString);                  /* get the final length     */
103239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    return xsize;
103339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi}
103439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
103539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
103639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi/* Google Engine API function implementations */
1037b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
1038b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/** init
103939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  Allocates Pico memory block and initializes the Pico system.
1040b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  synthDoneCBPtr - Pointer to callback function which will receive generated samples
10415ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi *  config - the engine configuration parameters, here only contains the non-system path
10425ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi *      for the lingware location
1043b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  return tts_result
1044b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
104553a14fa444487d31d735b9a90d01c075be2418baJean-Michel Trivitts_result TtsEngine::init( synthDoneCB_t synthDoneCBPtr, const char *config )
1046b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
10474bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (synthDoneCBPtr == NULL) {
104831a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Callback pointer is NULL");
1049b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
1050b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
10514eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
105239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    picoMemArea = malloc( PICO_MEM_SIZE );
10534bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (!picoMemArea) {
105431a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to allocate memory for Pico system");
1055b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
1056b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
10574eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
105839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    pico_Status ret = pico_initialize( picoMemArea, PICO_MEM_SIZE, &picoSystem );
10594bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (PICO_OK != ret) {
106031a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("Failed to initialize Pico system");
106139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        free( picoMemArea );
1062b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoMemArea = NULL;
1063b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
1064b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
10654eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
1066b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    picoSynthDoneCBPtr = synthDoneCBPtr;
10674bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi
10689b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    picoCurrentLangIndex = -1;
10694bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi
10705ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi    // was the initialization given an alternative path for the lingware location?
10715ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi    if ((config != NULL) && (strlen(config) > 0)) {
10725ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi        pico_alt_lingware_path = (char*)malloc(strlen(config));
10735ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi        strcpy((char*)pico_alt_lingware_path, config);
1074c659351ad768dbc200bafc80b422908771087280Steve Block        ALOGV("Alternative lingware path %s", pico_alt_lingware_path);
10755ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi    } else {
1076398201b57015e1698fad25d9586b97c88936947aNarayan Kamath        pico_alt_lingware_path = (char*)malloc(strlen(PICO_LINGWARE_PATH) + 1);
10775ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi        strcpy((char*)pico_alt_lingware_path, PICO_LINGWARE_PATH);
1078c659351ad768dbc200bafc80b422908771087280Steve Block        ALOGV("Using predefined lingware path %s", pico_alt_lingware_path);
10795ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi    }
10805ec310c3cff5d5bde0aad3ba4964a31b89476755Jean-Michel Trivi
1081b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    return TTS_SUCCESS;
1082b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
1083b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
108454823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
1085b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/** shutdown
108654823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi *  Unloads all Pico resources; terminates Pico system and frees Pico memory block.
1087b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  return tts_result
1088b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
108954823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivitts_result TtsEngine::shutdown( void )
1090b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
1091b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    cleanResources();
10924eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
10934bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoSystem) {
1094b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        pico_terminate(&picoSystem);
1095b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoSystem = NULL;
1096b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
10974bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (picoMemArea) {
1098b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        free(picoMemArea);
1099b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoMemArea = NULL;
1100b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
11014eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
1102b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    cleanFiles();
1103b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    return TTS_SUCCESS;
1104b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
1105b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
110639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
110739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi/** loadLanguage
110839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  Load a new language.
110939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @lang - string with ISO 3 letter language code.
111039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @country - string with ISO 3 letter country code .
111139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @variant - string with language variant for that language and country pair.
111239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  return tts_result
111339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi*/
111439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivitts_result TtsEngine::loadLanguage(const char *lang, const char *country, const char *variant)
111539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi{
111639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    return TTS_FAILURE;
111739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    //return setProperty("language", value, size);
111839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi}
111939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
112039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
112139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi/** setLanguage
112239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  Load a new language (locale).  Use the ISO 639-3 language codes.
112339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @lang - string with ISO 639-3 language code.
112439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @country - string with ISO 3 letter country code.
112539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @variant - string with language variant for that language and country pair.
112639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  return tts_result
112739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi */
112839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivitts_result TtsEngine::setLanguage( const char * lang, const char * country, const char * variant )
112939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi{
1130659851c7b5a2d0023266bf34634179ff8d08e3baSteve Block    //ALOGI("TtsEngine::setLanguage %s %s %s", lang, country, variant);
113139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int langIndex;
113239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int countryIndex;
113339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int i;
113439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
113539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    if (lang == NULL)
113639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        {
113731a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("TtsEngine::setLanguage called with NULL language");
113839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        return TTS_FAILURE;
113939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        }
114039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
114139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* We look for a match on the language first
114239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       then we look for a match on the country.
114339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       If no match on the language:
114439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi             return an error.
114539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       If match on the language, but no match on the country:
114639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi             load the language found for the language match.
114739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       If match on the language, and match on the country:
114839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi             load the language found for the country match.     */
114939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
115039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Find a match on the language.    */
115139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    langIndex = -1;                                     /* no match */
115239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    for (i = 0; i < picoNumSupportedVocs; i ++)
115339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        {
115439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        if (strcmp(lang, picoSupportedLangIso3[i]) == 0)
115539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            {
115639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            langIndex = i;
115739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            break;
115839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            }
115939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        }
116039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    if (langIndex < 0)
116139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        {
116239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        /* The language isn't supported.    */
116331a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("TtsEngine::setLanguage called with unsupported language");
116439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        return TTS_FAILURE;
116539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        }
116639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
116739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Find a match on the country, if there is one.    */
116839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    if (country != NULL)
116939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        {
117039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        countryIndex = -1;
117139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        for (i = langIndex; i < picoNumSupportedVocs; i ++)
117239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            {
117339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            if (   (strcmp(lang,    picoSupportedLangIso3[i])    == 0)
117439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi                && (strcmp(country, picoSupportedCountryIso3[i]) == 0))
117539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi                {
117639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi                countryIndex = i;
117739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi                break;
117839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi                }
117939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            }
118039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
118139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        if (countryIndex < 0)
118239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            {
118339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            /* We didn't find a match on the country, but we had a match on the language.
118439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi               Use that language.                                                       */
1185659851c7b5a2d0023266bf34634179ff8d08e3baSteve Block            ALOGI("TtsEngine::setLanguage found matching language(%s) but not matching country(%s).",
118639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi                    lang, country);
118739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            }
118839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        else
118939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            {
119039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            /* We have a match on both the language and the country.    */
119139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            langIndex = countryIndex;
119239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            }
119339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        }
119439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
119539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    return doLanguageSwitchFromLangIndex( langIndex );      /* switch the language  */
119639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi}
119739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
119839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
1199b8f46add889c597c8c305691b1aa656d68bfa5c8Jean-Michel Trivi/** isLanguageAvailable
1200b8f46add889c597c8c305691b1aa656d68bfa5c8Jean-Michel Trivi *  Returns the level of support for a language.
1201b8f46add889c597c8c305691b1aa656d68bfa5c8Jean-Michel Trivi *  @lang - string with ISO 3 letter language code.
1202b8f46add889c597c8c305691b1aa656d68bfa5c8Jean-Michel Trivi *  @country - string with ISO 3 letter country code .
1203b8f46add889c597c8c305691b1aa656d68bfa5c8Jean-Michel Trivi *  @variant - string with language variant for that language and country pair.
12049b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi *  return tts_support_result
1205b8f46add889c597c8c305691b1aa656d68bfa5c8Jean-Michel Trivi*/
1206b8f46add889c597c8c305691b1aa656d68bfa5c8Jean-Michel Trivitts_support_result TtsEngine::isLanguageAvailable(const char *lang, const char *country,
1207b8f46add889c597c8c305691b1aa656d68bfa5c8Jean-Michel Trivi            const char *variant) {
12089b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    int langIndex = -1;
12099b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    int countryIndex = -1;
12109b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    //-------------------------
12119b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    // language matching
12129b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    // if no language specified
12139b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    if (lang == NULL)  {
121431a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("TtsEngine::isLanguageAvailable called with no language");
12159b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        return TTS_LANG_NOT_SUPPORTED;
12169b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    }
12179b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi
12189b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    // find a match on the language
121939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    for (int i = 0; i < picoNumSupportedVocs; i++)
12209b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    {
12219b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        if (strcmp(lang, picoSupportedLangIso3[i]) == 0) {
12229b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi            langIndex = i;
12239b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi            break;
12249b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        }
12259b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    }
12269b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    if (langIndex < 0) {
12279b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        // language isn't supported
1228c659351ad768dbc200bafc80b422908771087280Steve Block        ALOGV("TtsEngine::isLanguageAvailable called with unsupported language");
12299b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        return TTS_LANG_NOT_SUPPORTED;
12309b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    }
12319b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi
12329b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    //-------------------------
12339b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    // country matching
12349b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    // if no country specified
12359b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    if ((country == NULL) || (strlen(country) == 0)) {
12369b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        // check installation of matched language
12379b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        return (hasResourcesForLanguage(langIndex) ? TTS_LANG_AVAILABLE : TTS_LANG_MISSING_DATA);
12389b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    }
12394bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi
12409b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    // find a match on the country
124139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    for (int i = langIndex; i < picoNumSupportedVocs; i++) {
12429b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        if ((strcmp(lang, picoSupportedLangIso3[i]) == 0)
12439b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi                && (strcmp(country, picoSupportedCountryIso3[i]) == 0)) {
12449b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi            countryIndex = i;
12459b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi            break;
12469b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        }
12479b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    }
12489b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    if (countryIndex < 0)  {
12499b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        // we didn't find a match on the country, but we had a match on the language
12509b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        // check installation of matched language
12519b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        return (hasResourcesForLanguage(langIndex) ? TTS_LANG_AVAILABLE : TTS_LANG_MISSING_DATA);
12529b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    } else {
12539b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        // we have a match on the language and the country
12549b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        langIndex = countryIndex;
12559b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        // check installation of matched language + country
12569b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        return (hasResourcesForLanguage(langIndex) ? TTS_LANG_COUNTRY_AVAILABLE : TTS_LANG_MISSING_DATA);
12579b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    }
12584bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi
12599b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    // no variants supported in this library, TTS_LANG_COUNTRY_VAR_AVAILABLE cannot be returned.
1260b8f46add889c597c8c305691b1aa656d68bfa5c8Jean-Michel Trivi}
1261b8f46add889c597c8c305691b1aa656d68bfa5c8Jean-Michel Trivi
12624eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
1263b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/** getLanguage
126454823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi *  Get the currently loaded language - if any.
12659b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi *  @lang - string with current ISO 3 letter language code, empty string if no loaded language.
12669b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi *  @country - string with current ISO 3 letter country code, empty string if no loaded language.
12679b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi *  @variant - string with current language variant, empty string if no loaded language.
1268b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  return tts_result
1269b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
12709b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivitts_result TtsEngine::getLanguage(char *language, char *country, char *variant)
12719b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi{
12729b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    if (picoCurrentLangIndex == -1) {
12739b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        strcpy(language, "\0");
12749b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        strcpy(country, "\0");
12759b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        strcpy(variant, "\0");
12769b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    } else {
12775f6105e73f0c74acd10126175d4952ade10a0b05Jean-Michel Trivi        strcpy(language, picoSupportedLangIso3[picoCurrentLangIndex]);
12785f6105e73f0c74acd10126175d4952ade10a0b05Jean-Michel Trivi        strcpy(country, picoSupportedCountryIso3[picoCurrentLangIndex]);
12799b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        // no variant in this implementation
12809b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi        strcpy(variant, "\0");
12819b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    }
12829b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    return TTS_SUCCESS;
12839b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi}
12849b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi
12859b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi
12869b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi/** setAudioFormat
12879b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi * sets the audio format to use for synthesis, returns what is actually used.
12889b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi * @encoding - reference to encoding format
12899b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi * @rate - reference to sample rate
12909b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi * @channels - reference to number of channels
12919b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi * return tts_result
12929b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi * */
12937ffd31ba2584359996e04cd3d4d92f810d651066Narayan Kamathtts_result TtsEngine::setAudioFormat(tts_audio_format& encoding, uint32_t& rate,
12949b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi            int& channels)
1295b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
12969b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    // ignore the input parameters, the enforced audio parameters are fixed here
12977ffd31ba2584359996e04cd3d4d92f810d651066Narayan Kamath    encoding = TTS_AUDIO_FORMAT_PCM_16_BIT;
12989b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    rate = 16000;
12999b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    channels = 1;
13009b08cc440f25c4722ca112642be87053fc47f918Jean-Michel Trivi    return TTS_SUCCESS;
1301b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
1302b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
130354823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
1304b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/** setProperty
130554823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi *  Set property. The supported properties are:  language, rate, pitch and volume.
1306b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  @property - name of property to set
1307b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  @value - value to set
1308b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  @size - size of value
1309b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  return tts_result
1310b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
131154823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivitts_result TtsEngine::setProperty( const char * property, const char * value, const size_t size )
1312b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
131339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int rate;
131439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int pitch;
131539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int volume;
131639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
131739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Set a specific property for the engine.
131839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       Supported properties include: language (locale), rate, pitch, volume.    */
131954823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi    /* Sanity check */
13204bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (property == NULL) {
132131a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("setProperty called with property NULL");
1322b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_PROPERTY_UNSUPPORTED;
13234bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
13244eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
13254bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (value == NULL) {
132631a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("setProperty called with value NULL");
1327b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_VALUE_INVALID;
13284bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
13294eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
13304bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (strncmp(property, "language", 8) == 0) {
133139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        /* Verify it's in correct format.   */
13324bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (strlen(value) != 2 && strlen(value) != 6) {
133331a809cefabaafd5b82574df08615855f1019a43Steve Block            ALOGE("change language called with incorrect format");
1334b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            return TTS_VALUE_INVALID;
13354bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
13364eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
133739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        /* Try to switch to specified language. */
13384bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (doLanguageSwitch(value) == TTS_FAILURE) {
133931a809cefabaafd5b82574df08615855f1019a43Steve Block            ALOGE("failed to load language");
1340b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            return TTS_FAILURE;
13414bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        } else {
1342b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            return TTS_SUCCESS;
1343b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        }
13444bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    } else if (strncmp(property, "rate", 4) == 0) {
134539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        rate = atoi(value);
13464bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (rate < PICO_MIN_RATE) {
134739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            rate = PICO_MIN_RATE;
13484bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
13494bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (rate > PICO_MAX_RATE) {
135039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            rate = PICO_MAX_RATE;
13514bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
1352b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoProp_currRate = rate;
1353b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_SUCCESS;
13544bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    } else if (strncmp(property, "pitch", 5) == 0) {
135539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        pitch = atoi(value);
13564bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (pitch < PICO_MIN_PITCH) {
135739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            pitch = PICO_MIN_PITCH;
13584bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
13594bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (pitch > PICO_MAX_PITCH) {
136039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            pitch = PICO_MAX_PITCH;
13614bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
1362b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoProp_currPitch = pitch;
1363b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_SUCCESS;
13644bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    } else if (strncmp(property, "volume", 6) == 0) {
136539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        volume = atoi(value);
13664bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (volume < PICO_MIN_VOLUME) {
136739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            volume = PICO_MIN_VOLUME;
13684bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
13694bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (volume > PICO_MAX_VOLUME) {
137039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            volume = PICO_MAX_VOLUME;
13714bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
1372b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoProp_currVolume = volume;
1373b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_SUCCESS;
13744bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
1375b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
1376b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    return TTS_PROPERTY_UNSUPPORTED;
1377b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
1378b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
137954823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
1380b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/** getProperty
138154823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi *  Get the property.  Supported properties are:  language, rate, pitch and volume.
1382b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  @property - name of property to get
138339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @value    - buffer which will receive value of property
138439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @iosize   - size of value - if size is too small on return this will contain actual size needed
1385b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  return tts_result
1386b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
138739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivitts_result TtsEngine::getProperty( const char * property, char * value, size_t * iosize )
1388b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
138939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Get the property for the engine.
139039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi       This property was previously set by setProperty or by default.       */
139154823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi    /* sanity check */
13924bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (property == NULL) {
139331a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("getProperty called with property NULL");
1394b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_PROPERTY_UNSUPPORTED;
13954bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
13964eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
13974bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (value == NULL) {
139831a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("getProperty called with value NULL");
1399b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_VALUE_INVALID;
14004bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
14014eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
14024bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (strncmp(property, "language", 8) == 0) {
14034bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (picoProp_currLang == NULL) {
1404b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            strcpy(value, "");
14054bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        } else {
14064bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            if (*iosize < strlen(picoProp_currLang)+1)  {
1407b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen                *iosize = strlen(picoProp_currLang) + 1;
1408b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen                return TTS_PROPERTY_SIZE_TOO_SMALL;
140939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            }
14104bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            strcpy(value, picoProp_currLang);
141139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        }
14124bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        return TTS_SUCCESS;
14134bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    } else if (strncmp(property, "rate", 4) == 0) {
1414b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        char tmprate[4];
1415b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        sprintf(tmprate, "%d", picoProp_currRate);
14164bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (*iosize < strlen(tmprate)+1) {
1417b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            *iosize = strlen(tmprate) + 1;
1418b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            return TTS_PROPERTY_SIZE_TOO_SMALL;
1419b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        }
1420b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        strcpy(value, tmprate);
1421b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_SUCCESS;
14224bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    } else if (strncmp(property, "pitch", 5) == 0) {
1423b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        char tmppitch[4];
1424b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        sprintf(tmppitch, "%d", picoProp_currPitch);
14254bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (*iosize < strlen(tmppitch)+1) {
1426b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            *iosize = strlen(tmppitch) + 1;
1427b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            return TTS_PROPERTY_SIZE_TOO_SMALL;
1428b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        }
1429b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        strcpy(value, tmppitch);
1430b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_SUCCESS;
14314bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    } else if (strncmp(property, "volume", 6) == 0) {
1432b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        char tmpvol[4];
1433b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        sprintf(tmpvol, "%d", picoProp_currVolume);
14344bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (*iosize < strlen(tmpvol)+1) {
1435b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            *iosize = strlen(tmpvol) + 1;
1436b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            return TTS_PROPERTY_SIZE_TOO_SMALL;
14374bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
1438b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        strcpy(value, tmpvol);
1439b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_SUCCESS;
14404bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
144139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi
144239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Unknown property */
144331a809cefabaafd5b82574df08615855f1019a43Steve Block    ALOGE("Unsupported property");
144439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    return TTS_PROPERTY_UNSUPPORTED;
1445b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
1446b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
144754823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
1448b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/** synthesizeText
144954823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi *  Synthesizes a text string.
145039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  The text string could be annotated with SSML tags.
145139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @text     - text to synthesize
145239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi *  @buffer   - buffer which will receive generated samples
1453b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  @bufferSize - size of buffer
1454b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  @userdata - pointer to user data which will be passed back to callback function
1455b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  return tts_result
1456b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
145739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivitts_result TtsEngine::synthesizeText( const char * text, int8_t * buffer, size_t bufferSize, void * userdata )
1458b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
145939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int         err;
146039358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    int         cbret;
146139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    pico_Char * inp = NULL;
1462d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi    char *      expanded_text = NULL;
146339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    pico_Char * local_text = NULL;
146439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    short       outbuf[MAX_OUTBUF_SIZE/2];
146539358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    pico_Int16  bytes_sent, bytes_recv, text_remaining, out_data_type;
1466b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    pico_Status ret;
146739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    SvoxSsmlParser * parser = NULL;
14684eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
146939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    picoSynthAbort = 0;
14704bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (text == NULL) {
147131a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("synthesizeText called with NULL string");
1472b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
14734bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    }
14744eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
14752821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi    if (strlen(text) == 0) {
14762821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi        return TTS_SUCCESS;
14772821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi    }
14782821fc14ed38e674f41309fc52d5f52a6b9bb1daJean-Michel Trivi
14794bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if (buffer == NULL) {
148031a809cefabaafd5b82574df08615855f1019a43Steve Block        ALOGE("synthesizeText called with NULL buffer");
1481b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        return TTS_FAILURE;
148239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    }
14834bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi
14844bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    if ( (strncmp(text, "<speak", 6) == 0) || (strncmp(text, "<?xml", 5) == 0) ) {
14854bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        /* SSML input */
14864bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        parser = new SvoxSsmlParser();
14874bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (parser && parser->initSuccessful()) {
14884bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            err = parser->parseDocument(text, 1);
14894bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            if (err == XML_STATUS_ERROR) {
14904bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                /* Note: for some reason expat always thinks the input document has an error
14914bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                   at the end, even when the XML document is perfectly formed */
1492659851c7b5a2d0023266bf34634179ff8d08e3baSteve Block                ALOGI("Warning: SSML document parsed with errors");
14934bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            }
14944bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            char * parsed_text = parser->getParsedDocument();
14954bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            if (parsed_text) {
14964bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                /* Add property tags to the string - if any.    */
14974bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                local_text = (pico_Char *) doAddProperties( parsed_text );
14984bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                if (!local_text) {
149931a809cefabaafd5b82574df08615855f1019a43Steve Block                    ALOGE("Failed to allocate memory for text string");
15004bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                    delete parser;
15014bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                    return TTS_FAILURE;
15024bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                }
15034bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                char * lang = parser->getParsedDocumentLanguage();
15045da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                if (lang != NULL) {
15055da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                    if (doLanguageSwitch(lang) == TTS_FAILURE) {
150631a809cefabaafd5b82574df08615855f1019a43Steve Block                        ALOGE("Failed to switch to language (%s) specified in SSML document.", lang);
15075da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                        delete parser;
15085da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                        return TTS_FAILURE;
15095da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                    }
15105da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                } else {
15115da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                    // lang is NULL, pick a language so the synthesis can be performed
15125da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                    if (picoCurrentLangIndex == -1) {
15135da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                        // no current language loaded, pick the first one and load it
15145da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                        if (doLanguageSwitchFromLangIndex(0) == TTS_FAILURE) {
151531a809cefabaafd5b82574df08615855f1019a43Steve Block                            ALOGE("Failed to switch to default language.");
15165da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                            delete parser;
15175da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                            return TTS_FAILURE;
15185da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                        }
15195da148ef02f1ed01db73163c2befde420b875a9fJean-Michel Trivi                    }
1520659851c7b5a2d0023266bf34634179ff8d08e3baSteve Block                    //ALOGI("No language in SSML, using current language (%s).", picoProp_currLang);
15214bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                }
15224bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                delete parser;
15234bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            } else {
152431a809cefabaafd5b82574df08615855f1019a43Steve Block                ALOGE("Failed to parse SSML document");
15254bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                delete parser;
15264bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                return TTS_FAILURE;
15274bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            }
15284bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        } else {
152931a809cefabaafd5b82574df08615855f1019a43Steve Block            ALOGE("Failed to create SSML parser");
15304bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            if (parser) {
15314bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                delete parser;
15324bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            }
15334bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            return TTS_FAILURE;
15344bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
15354bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    } else {
1536d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi        /* camelCase pre-processing */
1537fcc21f46aeca27a74898c1d111f4e153001db2a2Jean-Michel Trivi        expanded_text = doCamelCase(text);
15384bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        /* Add property tags to the string - if any.    */
1539fcc21f46aeca27a74898c1d111f4e153001db2a2Jean-Michel Trivi        local_text = (pico_Char *) doAddProperties( expanded_text );
1540fcc21f46aeca27a74898c1d111f4e153001db2a2Jean-Michel Trivi        if (expanded_text) {
1541070c0460fcdfe276cce9dbf49a883d7c6a02c5c4Jean-Michel Trivi            free( expanded_text );
1542fcc21f46aeca27a74898c1d111f4e153001db2a2Jean-Michel Trivi        }
15434bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (!local_text) {
154431a809cefabaafd5b82574df08615855f1019a43Steve Block            ALOGE("Failed to allocate memory for text string");
15454bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            return TTS_FAILURE;
15464bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
1547b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
15484eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
154939358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    text_remaining = strlen((const char *) local_text) + 1;
15504eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
155139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    inp = (pico_Char *) local_text;
15524eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
1553b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    size_t bufused = 0;
15544eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
155554823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi    /* synthesis loop   */
15564bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi    while (text_remaining) {
15574bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (picoSynthAbort) {
15587bc39b0d41efe0d8733490d54e14bc392d9f0b6dJean-Michel Trivi            ret = pico_resetEngine( picoEngine, PICO_RESET_SOFT );
1559b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            break;
15604bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
15614eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
156254823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi        /* Feed the text into the engine.   */
156339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        ret = pico_putTextUtf8( picoEngine, inp, text_remaining, &bytes_sent );
15644bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (ret != PICO_OK) {
156531a809cefabaafd5b82574df08615855f1019a43Steve Block            ALOGE("Error synthesizing string '%s': [%d]", text, ret);
15664bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            if (local_text) {
156739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi                free( local_text );
156839358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi            }
15694bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            return TTS_FAILURE;
15704bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        }
15714eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
1572b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        text_remaining -= bytes_sent;
1573b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        inp += bytes_sent;
15744bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        do {
15754bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            if (picoSynthAbort) {
15767bc39b0d41efe0d8733490d54e14bc392d9f0b6dJean-Michel Trivi                ret = pico_resetEngine( picoEngine, PICO_RESET_SOFT );
1577b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen                break;
1578b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            }
157954823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi            /* Retrieve the samples and add them to the buffer. */
1580d434f44285f109dfbda5a4e821b89f53d2050ca7Jean-Michel Trivi            ret = pico_getData( picoEngine, (void *) outbuf, MAX_OUTBUF_SIZE, &bytes_recv,
15814bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                    &out_data_type );
15824bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            if (bytes_recv) {
15834bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                if ((bufused + bytes_recv) <= bufferSize) {
158439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi                    memcpy(buffer+bufused, (int8_t *) outbuf, bytes_recv);
1585b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen                    bufused += bytes_recv;
15864bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                } else {
158754823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi                    /* The buffer filled; pass this on to the callback function.    */
15887ffd31ba2584359996e04cd3d4d92f810d651066Narayan Kamath                    cbret = picoSynthDoneCBPtr(userdata, 16000, TTS_AUDIO_FORMAT_PCM_16_BIT, 1, buffer,
15894bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                            bufused, TTS_SYNTH_PENDING);
15904bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                    if (cbret == TTS_CALLBACK_HALT) {
1591659851c7b5a2d0023266bf34634179ff8d08e3baSteve Block                        ALOGI("Halt requested by caller. Halting.");
1592b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen                        picoSynthAbort = 1;
15937bc39b0d41efe0d8733490d54e14bc392d9f0b6dJean-Michel Trivi                        ret = pico_resetEngine( picoEngine, PICO_RESET_SOFT );
1594b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen                        break;
15954bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                    }
1596b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen                    bufused = 0;
159739358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi                    memcpy(buffer, (int8_t *) outbuf, bytes_recv);
15984eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi                    bufused += bytes_recv;
1599b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen                }
16004bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            }
1601b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        } while (PICO_STEP_BUSY == ret);
16024eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
160339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        /* This chunk of synthesis is finished; pass the remaining samples.
160454823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi           Use 16 KHz, 16-bit samples.                                              */
16054bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (!picoSynthAbort) {
16067ffd31ba2584359996e04cd3d4d92f810d651066Narayan Kamath            picoSynthDoneCBPtr( userdata, 16000, TTS_AUDIO_FORMAT_PCM_16_BIT, 1, buffer, bufused,
16074bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                    TTS_SYNTH_PENDING);
1608b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        }
1609b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        picoSynthAbort = 0;
16104eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
16114bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi        if (ret != PICO_STEP_IDLE) {
1612de0498d852dc3f1517989ffa06593aa67f8b5d80Charles Chen            if (ret != 0){
161331a809cefabaafd5b82574df08615855f1019a43Steve Block                ALOGE("Error occurred during synthesis [%d]", ret);
1614de0498d852dc3f1517989ffa06593aa67f8b5d80Charles Chen            }
16154bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            if (local_text) {
16164bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                free(local_text);
16174bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            }
1618c659351ad768dbc200bafc80b422908771087280Steve Block            ALOGV("Synth loop: sending TTS_SYNTH_DONE after error");
16197ffd31ba2584359996e04cd3d4d92f810d651066Narayan Kamath            picoSynthDoneCBPtr( userdata, 16000, TTS_AUDIO_FORMAT_PCM_16_BIT, 1, buffer, bufused,
16204bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi                    TTS_SYNTH_DONE);
16217bc39b0d41efe0d8733490d54e14bc392d9f0b6dJean-Michel Trivi            pico_resetEngine( picoEngine, PICO_RESET_SOFT );
1622b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen            return TTS_FAILURE;
1623b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen        }
1624b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    }
16254bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi
162639358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    /* Synthesis is done; notify the caller */
1627c659351ad768dbc200bafc80b422908771087280Steve Block    ALOGV("Synth loop: sending TTS_SYNTH_DONE after all done, or was asked to stop");
16287ffd31ba2584359996e04cd3d4d92f810d651066Narayan Kamath    picoSynthDoneCBPtr( userdata, 16000, TTS_AUDIO_FORMAT_PCM_16_BIT, 1, buffer, bufused,
16294bbdb2d4013fa7deb73da0189e9a0e4819e69da9Jean-Michel Trivi            TTS_SYNTH_DONE);
16304eea6515d68b88ebd2215309283d467b3212aa2bJean-Michel Trivi
163139358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    if (local_text) {
163239358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi        free( local_text );
163339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivi    }
1634b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    return TTS_SUCCESS;
1635b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
1636b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
163754823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
163854823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
1639b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen/** stop
164054823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi *  Aborts the running synthesis.
1641b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen *  return tts_result
1642b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen*/
164339358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel Trivitts_result TtsEngine::stop( void )
1644b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
1645b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    picoSynthAbort = 1;
1646b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    return TTS_SUCCESS;
1647b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
1648b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
164954823983fdcb4ee88d9a6c4e680ff2064dd95929Jean-Michel Trivi
1650b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#ifdef __cplusplus
1651b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chenextern "C" {
1652b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#endif
1653b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
165439358f0dacad8cece6c2d3ef1055030f57090c79Jean-Michel TriviTtsEngine * getTtsEngine( void )
1655b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen{
1656b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen    return new TtsEngine();
1657b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
1658b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen
1659b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#ifdef __cplusplus
1660b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen}
1661b190149a69b110e6719ce0a41877a683f8db7ae7Charles Chen#endif
1662