diff options
author | Android (Google) Code Review <android-gerrit@google.com> | 2009-07-08 14:24:23 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-07-08 14:24:23 -0700 |
commit | 87d6d3be8666a9f55c388e325cebad55e590f3c1 (patch) | |
tree | 17a684428c8a3e741bac16ae433c560151eb8312 /pico | |
parent | 9ff6c8f6036ea7cfa745a15afb26223bfa20cbe9 (diff) | |
parent | 4bbdb2d4013fa7deb73da0189e9a0e4819e69da9 (diff) | |
download | external_svox-87d6d3be8666a9f55c388e325cebad55e590f3c1.zip external_svox-87d6d3be8666a9f55c388e325cebad55e590f3c1.tar.gz external_svox-87d6d3be8666a9f55c388e325cebad55e590f3c1.tar.bz2 |
Merge change 6491 into donut
* changes:
Integrate latest SVOX code drop, includes support for the phoneme tag. Reformat TtsEngine implementation to Android style.
Diffstat (limited to 'pico')
-rw-r--r-- | pico/tts/com_svox_picottsengine.cpp | 681 | ||||
-rwxr-xr-x | pico/tts/svox_ssml_parser.cpp | 1249 | ||||
-rwxr-xr-x | pico/tts/svox_ssml_parser.h | 7 |
3 files changed, 919 insertions, 1018 deletions
diff --git a/pico/tts/com_svox_picottsengine.cpp b/pico/tts/com_svox_picottsengine.cpp index 49c1f22..52ac781 100644 --- a/pico/tts/com_svox_picottsengine.cpp +++ b/pico/tts/com_svox_picottsengine.cpp @@ -13,39 +13,26 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - This is the Manager layer. It sits on top of the native Pico engine - and provides the interface to the defined Google TTS engine API. - The Google engine API is the boundary to allow a TTS engine to be swapped. - The Manager layer also provide the SSML tag interpretation. - The supported SSML tags are mapped to corresponding tags natively supported by Pico. - Native Pico functions always begin with picoXXX. - - In the Pico engine, the language cannot be changed indpendently of the voice. - If either the voice or locale/language are changed, a new resource is loaded. - - Only a subset of SSML 1.0 tags are supported. - Some SSML tags involve significant complexity. - If the language is changed through an SSML tag, there is a latency for the load. - - History: - 2009-07-01 -- clean up & documentation - 2009-06-29 -- integrated SSML parser and IPA to XSAMPA conversion - 2009-06-29 -- revised for C90 compliance - 2009-06-04 -- updated for new TtsEngine interface - 2009-05-18 -- initial version - - - ToDo: - - duplicate 'phoneme ph=' *** - - normalize IPA strings ** - - change voice as well as language * - Changing of voice/language is complex due to potentially multiple swaps - under SSML and the latent effects. This requires storing a history of tags/sets. + * + * This is the Manager layer. It sits on top of the native Pico engine + * and provides the interface to the defined Google TTS engine API. + * The Google engine API is the boundary to allow a TTS engine to be swapped. + * The Manager layer also provide the SSML tag interpretation. + * The supported SSML tags are mapped to corresponding tags natively supported by Pico. + * Native Pico functions always begin with picoXXX. + * + * In the Pico engine, the language cannot be changed indpendently of the voice. + * If either the voice or locale/language are changed, a new resource is loaded. + * + * Only a subset of SSML 1.0 tags are supported. + * Some SSML tags involve significant complexity. + * If the language is changed through an SSML tag, there is a latency for the load. + * */ #include <stdio.h> #include <unistd.h> +#include <stdlib.h> #define LOG_TAG "SVOX Pico Engine" @@ -86,6 +73,7 @@ const char * PICO_PITCH_CLOSE_TAG = "</pitch>"; const char * PICO_VOLUME_OPEN_TAG = "<volume level='%d'>"; const char * PICO_VOLUME_CLOSE_TAG = "</volume>"; const char * PICO_PHONEME_OPEN_TAG = "<phoneme ph='"; +const char * PICO_PHONEME_CLOSE_TAG = "'/>"; /* supported voices Pico does not seperately specify the voice and locale. */ @@ -139,34 +127,28 @@ static int checkForLocale( const char * locale ) int i; if (locale == NULL) { LOGE("checkForLanguage called with NULL language"); - return found; + return found; } /* Verify that the requested locale is a locale that we support. */ - for (i = 0; i < picoNumSupportedVocs; i ++) - { - if (strcmp(locale, picoSupportedLang[i]) == 0) /* in array */ - { + for (i = 0; i < picoNumSupportedVocs; i ++) { + if (strcmp(locale, picoSupportedLang[i]) == 0) { /* in array */ found = i; break; } }; /* The locale was not found. */ - if (found < 0) - { + if (found < 0) { /* We didn't find an exact match; it may have been specified with only the first 2 characters. This could overmatch ISO 639-3 language codes.%% */ - for (i = 0; i < picoNumSupportedVocs; i ++) - { - if (strncmp(locale, picoSupportedLang[i], 2) == 0) - { + for (i = 0; i < picoNumSupportedVocs; i ++) { + if (strncmp(locale, picoSupportedLang[i], 2) == 0) { found = i; break; } } - if (found < 0) - { + if (found < 0) { LOGE("TtsEngine::set language called with unsupported locale"); } }; @@ -179,24 +161,20 @@ static int checkForLocale( const char * locale ) */ static void cleanResources( void ) { - if (picoEngine) - { + if (picoEngine) { pico_disposeEngine( picoSystem, &picoEngine ); pico_releaseVoiceDefinition( picoSystem, (pico_Char *) PICO_VOICE_NAME ); picoEngine = NULL; } - if (picoUtppResource) - { + if (picoUtppResource) { pico_unloadResource( picoSystem, &picoUtppResource ); picoUtppResource = NULL; } - if (picoTaResource) - { + if (picoTaResource) { pico_unloadResource( picoSystem, &picoTaResource ); picoTaResource = NULL; } - if (picoSgResource) - { + if (picoSgResource) { pico_unloadResource( picoSystem, &picoSgResource ); picoSgResource = NULL; } @@ -209,44 +187,37 @@ static void cleanResources( void ) */ static void cleanFiles( void ) { - if (picoProp_currLang) - { + if (picoProp_currLang) { free( picoProp_currLang ); picoProp_currLang = NULL; } - if (picoTaFileName) - { + if (picoTaFileName) { free( picoTaFileName ); picoTaFileName = NULL; } - if (picoSgFileName) - { + if (picoSgFileName) { free( picoSgFileName ); picoSgFileName = NULL; } - if (picoUtppFileName) - { + if (picoUtppFileName) { free( picoUtppFileName ); picoUtppFileName = NULL; } - if (picoTaResourceName) - { + if (picoTaResourceName) { free( picoTaResourceName ); picoTaResourceName = NULL; } - if (picoSgResourceName) - { + if (picoSgResourceName) { free( picoSgResourceName ); picoSgResourceName = NULL; } - if (picoUtppResourceName) - { + if (picoUtppResourceName) { free( picoUtppResourceName ); picoUtppResourceName = NULL; } @@ -261,11 +232,11 @@ static void cleanFiles( void ) static bool hasResourcesForLanguage(int langIndex) { FILE * pFile; char* fileName = (char*)malloc(PICO_MAX_DATAPATH_NAME_SIZE + PICO_MAX_FILE_NAME_SIZE); - + strcpy((char*)fileName, PICO_LINGWARE_PATH); strcat((char*)fileName, (const char*)picoInternalTaLingware[langIndex]); - pFile = fopen(fileName,"r"); - if (pFile == NULL){ + pFile = fopen(fileName, "r"); + if (pFile == NULL) { free(fileName); return false; } else { @@ -298,8 +269,7 @@ static tts_result doLanguageSwitchFromLangIndex( int langIndex ) int ret; /* function result code */ /* If we already have a loaded locale, check whether it is the same one as requested. */ - if (picoProp_currLang && (strcmp(picoProp_currLang, picoSupportedLang[langIndex]) == 0)) - { + if (picoProp_currLang && (strcmp(picoProp_currLang, picoSupportedLang[langIndex]) == 0)) { LOGI("Language already loaded (%s == %s)", picoProp_currLang, picoSupportedLang[langIndex]); return TTS_SUCCESS; } @@ -327,8 +297,7 @@ static tts_result doLanguageSwitchFromLangIndex( int langIndex ) /* Load the text analysis Lingware resource file. */ ret = pico_loadResource( picoSystem, picoTaFileName, &picoTaResource ); - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to load textana resource for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); @@ -337,8 +306,7 @@ static tts_result doLanguageSwitchFromLangIndex( int langIndex ) /* Load the signal generation Lingware resource file. */ ret = pico_loadResource( picoSystem, picoSgFileName, &picoSgResource ); - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to load siggen resource for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); @@ -349,18 +317,16 @@ static tts_result doLanguageSwitchFromLangIndex( int langIndex ) and is currently not used. Loading is only attempted for future compatibility. If this file is not present the loading will still succeed. */ ret = pico_loadResource( picoSystem, picoUtppFileName, &picoUtppResource ); - if ((PICO_OK != ret) && (ret != PICO_EXC_CANT_OPEN_FILE)) - { + if ((PICO_OK != ret) && (ret != PICO_EXC_CANT_OPEN_FILE)) { LOGE("Failed to load utpp resource for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); return TTS_FAILURE; - } + } /* Get the text analysis resource name. */ ret = pico_getResourceName( picoSystem, picoTaResource, (char *) picoTaResourceName ); - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to get textana resource name for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); @@ -369,20 +335,17 @@ static tts_result doLanguageSwitchFromLangIndex( int langIndex ) /* Get the signal generation resource name. */ ret = pico_getResourceName( picoSystem, picoSgResource, (char *) picoSgResourceName ); - if (PICO_OK == ret && picoUtppResource != NULL) - { + if (PICO_OK == ret && picoUtppResource != NULL) { /* Get utpp resource name - optional: see note above. */ ret = pico_getResourceName( picoSystem, picoUtppResource, (char *) picoUtppResourceName ); - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to get utpp resource name for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); return TTS_FAILURE; } } - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to get siggen resource name for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); @@ -391,8 +354,7 @@ static tts_result doLanguageSwitchFromLangIndex( int langIndex ) /* Create a voice definition. */ ret = pico_createVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME ); - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to create voice for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); @@ -401,8 +363,7 @@ static tts_result doLanguageSwitchFromLangIndex( int langIndex ) /* Add the text analysis resource to the voice. */ ret = pico_addResourceToVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME, picoTaResourceName ); - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to add textana resource to voice for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); @@ -411,12 +372,10 @@ static tts_result doLanguageSwitchFromLangIndex( int langIndex ) /* Add the signal generation resource to the voice. */ ret = pico_addResourceToVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME, picoSgResourceName ); - if (PICO_OK == ret && picoUtppResource != NULL) - { + if (PICO_OK == ret && picoUtppResource != NULL) { /* Add utpp resource to voice - optional: see note above. */ ret = pico_addResourceToVoiceDefinition( picoSystem, (const pico_Char *) PICO_VOICE_NAME, picoUtppResourceName ); - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to add utpp resource to voice for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); @@ -424,8 +383,7 @@ static tts_result doLanguageSwitchFromLangIndex( int langIndex ) } } - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to add siggen resource to voice for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); @@ -433,8 +391,7 @@ static tts_result doLanguageSwitchFromLangIndex( int langIndex ) } ret = pico_newEngine( picoSystem, (const pico_Char *) PICO_VOICE_NAME, &picoEngine ); - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to create engine for %s [%d]", picoSupportedLang[langIndex], ret); cleanResources(); cleanFiles(); @@ -463,11 +420,10 @@ static tts_result doLanguageSwitch( const char * locale ) /* Load the new locale. */ loclIndex = checkForLocale( locale ); - if (loclIndex < 0) - { + if (loclIndex < 0) { LOGE("Tried to swith to non-supported locale %s", locale); return TTS_FAILURE; - } + } LOGI("Found supported locale %s", picoSupportedLang[loclIndex]); return doLanguageSwitchFromLangIndex( loclIndex ); } @@ -488,20 +444,17 @@ static char * doAddProperties( const char * str ) haspitch = 0; hasspeed = 0; hasvol = 0; textlen = strlen(str) + 1; - if (picoProp_currPitch != PICO_DEF_PITCH) /* non-default pitch */ - { + if (picoProp_currPitch != PICO_DEF_PITCH) { /* non-default pitch */ textlen += strlen(PICO_PITCH_OPEN_TAG) + 5; textlen += strlen(PICO_PITCH_CLOSE_TAG); haspitch = 1; } - if (picoProp_currRate != PICO_DEF_RATE) /* non-default rate */ - { + if (picoProp_currRate != PICO_DEF_RATE) { /* non-default rate */ textlen += strlen(PICO_SPEED_OPEN_TAG) + 5; textlen += strlen(PICO_SPEED_CLOSE_TAG); hasspeed = 1; } - if (picoProp_currVolume != PICO_DEF_VOLUME) /* non-default volume */ - { + if (picoProp_currVolume != PICO_DEF_VOLUME) { /* non-default volume */ textlen += strlen(PICO_VOLUME_OPEN_TAG) + 5; textlen += strlen(PICO_VOLUME_CLOSE_TAG); hasvol = 1; @@ -509,29 +462,25 @@ static char * doAddProperties( const char * str ) /* Compose the property strings. */ data = (char *) malloc( textlen ); /* allocate string */ - if (!data) - { + if (!data) { return NULL; } memset(data, 0, textlen); /* clear it */ - if (haspitch) - { + if (haspitch) { char* tmp = (char*)malloc(strlen(PICO_PITCH_OPEN_TAG) + strlen(PICO_PITCH_CLOSE_TAG) + 5); sprintf(tmp, PICO_PITCH_OPEN_TAG, picoProp_currPitch); strcat(data, tmp); free(tmp); } - if (hasspeed) - { + if (hasspeed) { char* tmp = (char*)malloc(strlen(PICO_SPEED_OPEN_TAG) + strlen(PICO_SPEED_CLOSE_TAG) + 5); sprintf(tmp, PICO_SPEED_OPEN_TAG, picoProp_currRate); strcat(data, tmp); free(tmp); } - if (hasvol) - { + if (hasvol) { char* tmp = (char*)malloc(strlen(PICO_VOLUME_OPEN_TAG) + strlen(PICO_VOLUME_CLOSE_TAG) + 5); sprintf(tmp, PICO_VOLUME_OPEN_TAG, picoProp_currVolume); strcat(data, tmp); @@ -540,18 +489,15 @@ static char * doAddProperties( const char * str ) strcat(data, str); - if (hasvol) - { + if (hasvol) { strcat(data, PICO_VOLUME_CLOSE_TAG); } - if (hasspeed) - { + if (hasspeed) { strcat(data, PICO_SPEED_CLOSE_TAG); } - if (haspitch) - { + if (haspitch) { strcat(data, PICO_PITCH_CLOSE_TAG); } @@ -567,71 +513,64 @@ static char * doAddProperties( const char * str ) * @length - length of the input string * return new string with tags applied */ -static char * createPhonemeString( const char * xsampa, int length ) +extern char * createPhonemeString( const char * xsampa, int length ) { char * convstring = NULL; int origStrLen = strlen(xsampa); int numWords = 1; int start, totalLength, i, j; - for (i = 0; i < origStrLen; i ++) - { - if (xsampa[i] == ' ') - numWords ++; - } + for (i = 0; i < origStrLen; i ++) { + if (xsampa[i] == ' ') numWords++; + } - if (numWords == 1) - { + if (numWords == 1) { convstring = new char[origStrLen + 17]; convstring[0] = '\0'; - strcat(convstring, "<phoneme ph='"); + strcat(convstring, PICO_PHONEME_OPEN_TAG); strcat(convstring, xsampa); - strcat(convstring, "'/>"); - } - else - { + strcat(convstring, PICO_PHONEME_CLOSE_TAG); + } + else { char * words[numWords]; start = 0; totalLength = 0; i = 0; j = 0; - for (i=0, j=0; i < origStrLen; i ++) - { - if (xsampa[i] == ' ') - { + for (i=0, j=0; i < origStrLen; i++) { + if (xsampa[i] == ' ') { words[j] = new char[i+1-start+17]; words[j][0] = '\0'; - strcat( words[j], "<phoneme ph='"); + strcat( words[j], PICO_PHONEME_OPEN_TAG); strncat(words[j], xsampa+start, i-start); - strcat( words[j], "'/>"); + strcat( words[j], PICO_PHONEME_CLOSE_TAG); start = i + 1; - j ++; + j++; totalLength += strlen(words[j-1]); - } } + } words[j] = new char[i+1-start+17]; words[j][0] = '\0'; - strcat(words[j], "<phoneme ph='"); + strcat(words[j], PICO_PHONEME_OPEN_TAG); strcat(words[j], xsampa+start); - strcat(words[j], "'/>"); + strcat(words[j], PICO_PHONEME_CLOSE_TAG); totalLength += strlen(words[j]); convstring = new char[totalLength + 1]; convstring[0] = '\0'; - for (i=0; i < numWords; i ++) - { - strcat(convstring, words[i]); - delete [] words[i]; - } + for (i=0; i < numWords; i++) { + strcat(convstring, words[i]); + delete [] words[i]; } + } + return convstring; } - -/* The XSAMPA uses as many as 4 characters to represent a single IPA code. */ +/* The XSAMPA uses as many as 5 characters to represent a single IPA code. */ typedef struct tagPhnArr - { +{ char16_t strIPA; /* IPA Unicode symbol */ - char strXSAMPA[5]; /* SAMPA sequence */ - } PArr; + char strXSAMPA[6]; /* SAMPA sequence */ +} PArr; -#define phn_cnt (133) +#define phn_cnt (134) PArr PhnAry[phn_cnt] = { @@ -658,51 +597,51 @@ PArr PhnAry[phn_cnt] = { {0x0250, "6"}, {0x00E6, "{"}, {0x025C, "3"}, - {0x025A, "@'"}, - {0x025E, "3\\"}, - {0x0258, "@\\"}, + {0x025A, "@`"}, + {0x025E, "3\\\\"}, + {0x0258, "@\\\\"}, /* Consonants (60) complete */ - {0x0288, "t'"}, - {0x0256, "d'"}, - {0x025F, "J\\"}, + {0x0288, "t`"}, + {0x0256, "d`"}, + {0x025F, "J\\\\"}, {0x0261, "g"}, - {0x0262, "G\\"}, + {0x0262, "G\\\\"}, {0x0294, "?"}, {0x0271, "F"}, - {0x0273, "n'"}, + {0x0273, "n`"}, {0x0272, "J"}, {0x014B, "N"}, - {0x0274, "N\\"}, - {0x0299, "B\\"}, - {0x0280, "R\\"}, + {0x0274, "N\\\\"}, + {0x0299, "B\\\\"}, + {0x0280, "R\\\\"}, {0x027E, "4"}, - {0x027D, "r'"}, - {0x0278, "p\\"}, + {0x027D, "r`"}, + {0x0278, "p\\\\"}, {0x03B2, "B"}, {0x03B8, "T"}, {0x00F0, "D"}, {0x0283, "S"}, {0x0292, "Z"}, - {0x0282, "s'"}, - {0x0290, "z'"}, + {0x0282, "s`"}, + {0x0290, "z`"}, {0x00E7, "C"}, - {0x029D, "j\\"}, + {0x029D, "j\\\\"}, {0x0263, "G"}, {0x03C7, "X"}, {0x0281, "R"}, - {0x0127, "X\\"}, - {0x0295, "?\\"}, - {0x0266, "h\\"}, + {0x0127, "X\\\\"}, + {0x0295, "?\\\\"}, + {0x0266, "h\\\\"}, {0x026C, "K"}, - {0x026E, "K\\"}, + {0x026E, "K\\\\"}, {0x028B, "P"}, - {0x0279, "r\\"}, - {0x027B, "r\\'"}, - {0x0270, "M\\"}, - {0x026D, "l'"}, + {0x0279, "r\\\\"}, + {0x027B, "r\\\\'"}, + {0x0270, "M\\\\"}, + {0x026D, "l`"}, {0x028E, "L"}, - {0x029F, "L\\"}, + {0x029F, "L\\\\"}, {0x0253, "b_<"}, {0x0257, "d_<"}, {0x0284, "J\\_<"}, @@ -710,18 +649,18 @@ PArr PhnAry[phn_cnt] = { {0x029B, "G\\_<"}, {0x028D, "W"}, {0x0265, "H"}, - {0x029C, "H\\"}, - {0x02A1, ">\\"}, - {0x02A2, "<\\"}, - {0x0298, "O\\"}, - {0x01C0, "|\\"}, - {0x01C3, "!\\"}, + {0x029C, "H\\\\"}, + {0x02A1, ">\\\\"}, + {0x02A2, "<\\\\"}, + {0x0298, "O\\\\"}, + {0x01C0, "|\\\\"}, + {0x01C3, "!\\\\"}, {0x01C2, "=\\"}, {0x01C1, "|\\|\\"}, - {0x027A, "l\\"}, - {0x0255, "s\\"}, - {0x0291, "z\\"}, - {0x0267, "x\\"}, + {0x027A, "l\\\\"}, + {0x0255, "s\\\\"}, + {0x0291, "z\\\\"}, + {0x0267, "x\\\\"}, {0x026B, "l_G"}, /* Diacritics (34) */ @@ -740,15 +679,15 @@ PArr PhnAry[phn_cnt] = { {0x031C, "_c"}, {0x031F, "_+"}, {0x0320, "_-"}, - {0x0308, "_"}, /* centralized %% */ + {0x0308, "_\""}, /* centralized */ {0x033D, "_x"}, {0x0318, "_A"}, {0x0319, "_q"}, - {0x02DE, "'"}, + {0x02DE, "`"}, {0x02B7, "_w"}, {0x02B2, "_j"}, {0x02E0, "_G"}, - {0x02E4, "_?\\"}, + {0x02E4, "_?\\\\"}, {0x0303, "~"}, {0x207F, "_n"}, {0x02E1, "_l"}, @@ -760,25 +699,26 @@ PArr PhnAry[phn_cnt] = { {0x032F, "_^"}, {0x02D0, ":"}, - /* Others (10) incomplete%% */ + /* Others (11) complete */ {0x0361, "_"}, {0x035C, "_"}, - {0x02C8, ""}, + {0x02C8, "\""}, {0x02CC, "%"}, - {0x02D1, ":\\"}, + {0x02D1, ":\\\\"}, {0x0306, "_X"}, {0x2016, "||"}, - {0x203F, "-\\"}, + {0x203F, "-\\\\"}, {0x2197, "<R>"}, {0x2198, "<F>"}, + {0x025D, "3`"}, /* Affricates (6) complete */ {0x02A3, "d_z"}, {0x02A4, "d_Z"}, - {0x02A5, "d_z\\"}, + {0x02A5, "d_z\\\\"}, {0x02A6, "t_s"}, {0x02A7, "t_S"}, - {0x02A8, "t_s\\"} + {0x02A8, "t_s\\\\"} }; @@ -786,7 +726,6 @@ void CnvIPAPnt( const char16_t IPnt, char * XPnt ) { char16_t ThisPnt = IPnt; /* local copy of single IPA codepoint */ int idx; /* index into table */ - /* Convert an individual IPA codepoint. A single IPA code could map to a string. Search the table. If it is not found, use the same character. @@ -795,12 +734,12 @@ void CnvIPAPnt( const char16_t IPnt, char * XPnt ) XPnt[0] = 0; /* clear the result string */ /* Search the table for the conversion. */ - for (idx = 0; idx < phn_cnt; idx ++) /* for each item in table */ - if (IPnt == PhnAry[idx].strIPA) /* matches IPA code */ - { - strcat( XPnt, (const char *)&(PhnAry[idx].strXSAMPA) ); /* copy the XSAMPA string */ - return; + for (idx = 0; idx < phn_cnt; idx ++) { /* for each item in table */ + if (IPnt == PhnAry[idx].strIPA) { /* matches IPA code */ + strcat( XPnt, (const char *)&(PhnAry[idx].strXSAMPA) ); /* copy the XSAMPA string */ + return; } + } strcat(XPnt, (const char *)&ThisPnt); /* just copy it */ } @@ -811,36 +750,33 @@ void CnvIPAPnt( const char16_t IPnt, char * XPnt ) * @outXsampaString - converted XSAMPA string is passed back in this parameter * return size of the new string */ -int cnvIpaToXsampa( const char16_t * ipaString, char ** outXsampaString ) + +int cnvIpaToXsampa( const char16_t * ipaString, size_t ipaStringSize, char ** outXsampaString ) { - size_t xsize; /* size of result */ - size_t ilen; /* input length */ - int ipidx; /* index into IPA string */ - char * XPnt; /* short XSAMPA char sequence */ + size_t xsize; /* size of result */ + int ipidx; /* index into IPA string */ + char * XPnt; /* short XSAMPA char sequence */ /* Convert an IPA string to an XSAMPA string and store the xsampa string in *outXsampaString. It is the responsibility of the caller to free the allocated string. Increment through the string. For each base & combination convert it to the XSAMP equivalent. Because of the XSAMPA limitations, not all IPA characters will be covered. */ XPnt = (char *) malloc(6); - xsize = (4 * strlen16(ipaString)) + 8; /* assume more than double size */ - + xsize = (4 * ipaStringSize) + 8; /* assume more than double size */ *outXsampaString = (char *) malloc( xsize ); /* allocate return string */ *outXsampaString[0] = 0; - xsize = 0; /* clear final */ - ilen = strlen16(ipaString); /* length of input UTF-16 */ - for (ipidx = 0; ipidx < ilen; ipidx ++) /* for each IPA code */ - { - CnvIPAPnt( ipaString[ipidx], XPnt ); /* get converted string */ - strcat((char *)*outXsampaString, XPnt ); /* concatenate XSAMPA */ - }; + xsize = 0; /* clear final */ + + for (ipidx = 0; ipidx < ipaStringSize; ipidx ++) { /* for each IPA code */ + CnvIPAPnt( ipaString[ipidx], XPnt ); /* get converted character */ + strcat((char *)*outXsampaString, XPnt ); /* concatenate XSAMPA */ + } free(XPnt); - xsize = strlen(*outXsampaString); /* get the final length */ + xsize = strlen(*outXsampaString); /* get the final length */ return xsize; } - /* Google Engine API function implementations */ /** init @@ -850,22 +786,19 @@ int cnvIpaToXsampa( const char16_t * ipaString, char ** outXsampaString ) */ tts_result TtsEngine::init( synthDoneCB_t synthDoneCBPtr ) { - if (synthDoneCBPtr == NULL) - { + if (synthDoneCBPtr == NULL) { LOGE("Callback pointer is NULL"); return TTS_FAILURE; } picoMemArea = malloc( PICO_MEM_SIZE ); - if (!picoMemArea) - { + if (!picoMemArea) { LOGE("Failed to allocate memory for Pico system"); return TTS_FAILURE; } pico_Status ret = pico_initialize( picoMemArea, PICO_MEM_SIZE, &picoSystem ); - if (PICO_OK != ret) - { + if (PICO_OK != ret) { LOGE("Failed to initialize Pico system"); free( picoMemArea ); picoMemArea = NULL; @@ -873,9 +806,9 @@ tts_result TtsEngine::init( synthDoneCB_t synthDoneCBPtr ) } picoSynthDoneCBPtr = synthDoneCBPtr; - + picoCurrentLangIndex = -1; - + return TTS_SUCCESS; } @@ -888,13 +821,11 @@ tts_result TtsEngine::shutdown( void ) { cleanResources(); - if (picoSystem) - { + if (picoSystem) { pico_terminate(&picoSystem); picoSystem = NULL; } - if (picoMemArea) - { + if (picoMemArea) { free(picoMemArea); picoMemArea = NULL; } @@ -1035,7 +966,7 @@ tts_support_result TtsEngine::isLanguageAvailable(const char *lang, const char * // check installation of matched language return (hasResourcesForLanguage(langIndex) ? TTS_LANG_AVAILABLE : TTS_LANG_MISSING_DATA); } - + // find a match on the country for (int i = langIndex; i < picoNumSupportedVocs; i++) { if ((strcmp(lang, picoSupportedLangIso3[i]) == 0) @@ -1054,7 +985,7 @@ tts_support_result TtsEngine::isLanguageAvailable(const char *lang, const char * // check installation of matched language + country return (hasResourcesForLanguage(langIndex) ? TTS_LANG_COUNTRY_AVAILABLE : TTS_LANG_MISSING_DATA); } - + // no variants supported in this library, TTS_LANG_COUNTRY_VAR_AVAILABLE cannot be returned. } @@ -1116,68 +1047,61 @@ tts_result TtsEngine::setProperty( const char * property, const char * value, co /* Set a specific property for the engine. Supported properties include: language (locale), rate, pitch, volume. */ /* Sanity check */ - if (property == NULL) - { + if (property == NULL) { LOGE("setProperty called with property NULL"); return TTS_PROPERTY_UNSUPPORTED; - } + } - if (value == NULL) - { + if (value == NULL) { LOGE("setProperty called with value NULL"); return TTS_VALUE_INVALID; - } + } - if (strncmp(property, "language", 8) == 0) - { + if (strncmp(property, "language", 8) == 0) { /* Verify it's in correct format. */ - if (strlen(value) != 2 && strlen(value) != 6) - { + if (strlen(value) != 2 && strlen(value) != 6) { LOGE("change language called with incorrect format"); return TTS_VALUE_INVALID; - } + } /* Try to switch to specified language. */ - if (doLanguageSwitch(value) == TTS_FAILURE) - { + if (doLanguageSwitch(value) == TTS_FAILURE) { LOGE("failed to load language"); return TTS_FAILURE; - } - else - { + } else { return TTS_SUCCESS; - } } - else if (strncmp(property, "rate", 4) == 0) - { + } else if (strncmp(property, "rate", 4) == 0) { rate = atoi(value); - if (rate < PICO_MIN_RATE) + if (rate < PICO_MIN_RATE) { rate = PICO_MIN_RATE; - if (rate > PICO_MAX_RATE) + } + if (rate > PICO_MAX_RATE) { rate = PICO_MAX_RATE; + } picoProp_currRate = rate; return TTS_SUCCESS; - } - else if (strncmp(property, "pitch", 5) == 0) - { + } else if (strncmp(property, "pitch", 5) == 0) { pitch = atoi(value); - if (pitch < PICO_MIN_PITCH) + if (pitch < PICO_MIN_PITCH) { pitch = PICO_MIN_PITCH; - if (pitch > PICO_MAX_PITCH) + } + if (pitch > PICO_MAX_PITCH) { pitch = PICO_MAX_PITCH; + } picoProp_currPitch = pitch; return TTS_SUCCESS; - } - else if (strncmp(property, "volume", 6) == 0) - { + } else if (strncmp(property, "volume", 6) == 0) { volume = atoi(value); - if (volume < PICO_MIN_VOLUME) + if (volume < PICO_MIN_VOLUME) { volume = PICO_MIN_VOLUME; - if (volume > PICO_MAX_VOLUME) + } + if (volume > PICO_MAX_VOLUME) { volume = PICO_MAX_VOLUME; + } picoProp_currVolume = volume; return TTS_SUCCESS; - } + } return TTS_PROPERTY_UNSUPPORTED; } @@ -1195,71 +1119,55 @@ tts_result TtsEngine::getProperty( const char * property, char * value, size_t * /* Get the property for the engine. This property was previously set by setProperty or by default. */ /* sanity check */ - if (property == NULL) - { + if (property == NULL) { LOGE("getProperty called with property NULL"); return TTS_PROPERTY_UNSUPPORTED; - } + } - if (value == NULL) - { + if (value == NULL) { LOGE("getProperty called with value NULL"); return TTS_VALUE_INVALID; - } + } - if (strncmp(property, "language", 8) == 0) - { - if (picoProp_currLang == NULL) - { + if (strncmp(property, "language", 8) == 0) { + if (picoProp_currLang == NULL) { strcpy(value, ""); - } - else - { - if (*iosize < strlen(picoProp_currLang)+1) - { + } else { + if (*iosize < strlen(picoProp_currLang)+1) { *iosize = strlen(picoProp_currLang) + 1; return TTS_PROPERTY_SIZE_TOO_SMALL; - } - strcpy(value, picoProp_currLang); } - return TTS_SUCCESS; + strcpy(value, picoProp_currLang); } - else if (strncmp(property, "rate", 4) == 0) - { + return TTS_SUCCESS; + } else if (strncmp(property, "rate", 4) == 0) { char tmprate[4]; sprintf(tmprate, "%d", picoProp_currRate); - if (*iosize < strlen(tmprate)+1) - { + if (*iosize < strlen(tmprate)+1) { *iosize = strlen(tmprate) + 1; return TTS_PROPERTY_SIZE_TOO_SMALL; } strcpy(value, tmprate); return TTS_SUCCESS; - } - else if (strncmp(property, "pitch", 5) == 0) - { + } else if (strncmp(property, "pitch", 5) == 0) { char tmppitch[4]; sprintf(tmppitch, "%d", picoProp_currPitch); - if (*iosize < strlen(tmppitch)+1) - { + if (*iosize < strlen(tmppitch)+1) { *iosize = strlen(tmppitch) + 1; return TTS_PROPERTY_SIZE_TOO_SMALL; } strcpy(value, tmppitch); return TTS_SUCCESS; - } - else if (strncmp(property, "volume", 6) == 0) - { + } else if (strncmp(property, "volume", 6) == 0) { char tmpvol[4]; sprintf(tmpvol, "%d", picoProp_currVolume); - if (*iosize < strlen(tmpvol)+1) - { + if (*iosize < strlen(tmpvol)+1) { *iosize = strlen(tmpvol) + 1; return TTS_PROPERTY_SIZE_TOO_SMALL; - } + } strcpy(value, tmpvol); return TTS_SUCCESS; - } + } /* Unknown property */ LOGE("Unsupported property"); @@ -1288,73 +1196,61 @@ tts_result TtsEngine::synthesizeText( const char * text, int8_t * buffer, size_t SvoxSsmlParser * parser = NULL; picoSynthAbort = 0; - if (text == NULL) - { + if (text == NULL) { LOGE("synthesizeText called with NULL string"); return TTS_FAILURE; - } + } - if (buffer == NULL) - { + if (buffer == NULL) { LOGE("synthesizeText called with NULL buffer"); return TTS_FAILURE; - } - - if ((strncmp(text, "<speak", 6) == 0) || - (strncmp(text, "<?xml", 5) == 0) ) - { - /* SSML input */ - parser = new SvoxSsmlParser(); - if (parser && parser->initSuccessful()) - { - err = parser->parseDocument(text, 1); - if (err == XML_STATUS_ERROR) - { - LOGI("Warning: SSML document parsed with errors"); - } - char * parsed_text = parser->getParsedDocument(); - if (parsed_text) - { - /* Add property tags to the string - if any. */ - local_text = (pico_Char *) doAddProperties( parsed_text ); - if (!local_text) - { - LOGE("Failed to allocate memory for text string"); - delete parser; - return TTS_FAILURE; - } - char * lang = parser->getParsedDocumentLanguage(); - if (doLanguageSwitch(lang) == TTS_FAILURE) - { - LOGE("Failed to switch to language specified in SSML document."); - delete parser; - return TTS_FAILURE; - } - delete parser; - } - else - { - LOGE("Failed to parse SSML document"); - delete parser; - return TTS_FAILURE; - } - } - else - { - LOGE("Failed to create SSML parser"); - if (parser) delete parser; - return TTS_FAILURE; - } } - else - { - /* Add property tags to the string - if any. */ - local_text = (pico_Char *) doAddProperties( text ); - if (!local_text) - { + + if ( (strncmp(text, "<speak", 6) == 0) || (strncmp(text, "<?xml", 5) == 0) ) { + /* SSML input */ + parser = new SvoxSsmlParser(); + if (parser && parser->initSuccessful()) { + err = parser->parseDocument(text, 1); + if (err == XML_STATUS_ERROR) { + /* Note: for some reason expat always thinks the input document has an error + at the end, even when the XML document is perfectly formed */ + LOGI("Warning: SSML document parsed with errors"); + } + char * parsed_text = parser->getParsedDocument(); + if (parsed_text) { + /* Add property tags to the string - if any. */ + local_text = (pico_Char *) doAddProperties( parsed_text ); + if (!local_text) { + LOGE("Failed to allocate memory for text string"); + delete parser; + return TTS_FAILURE; + } + char * lang = parser->getParsedDocumentLanguage(); + if (doLanguageSwitch(lang) == TTS_FAILURE) { + LOGE("Failed to switch to language specified in SSML document."); + delete parser; + return TTS_FAILURE; + } + delete parser; + } else { + LOGE("Failed to parse SSML document"); + delete parser; + return TTS_FAILURE; + } + } else { + LOGE("Failed to create SSML parser"); + if (parser) { + delete parser; + } + return TTS_FAILURE; + } + } else { + /* Add property tags to the string - if any. */ + local_text = (pico_Char *) doAddProperties( text ); + if (!local_text) { LOGE("Failed to allocate memory for text string"); - return TTS_FAILURE; - } + return TTS_FAILURE; + } } text_remaining = strlen((const char *) local_text) + 1; @@ -1364,79 +1260,76 @@ tts_result TtsEngine::synthesizeText( const char * text, int8_t * buffer, size_t size_t bufused = 0; /* synthesis loop */ - while (text_remaining) - { - if (picoSynthAbort) - { + while (text_remaining) { + + if (picoSynthAbort) { ret = pico_resetEngine( picoEngine ); break; - } + } /* Feed the text into the engine. */ ret = pico_putTextUtf8( picoEngine, inp, text_remaining, &bytes_sent ); - if (ret != PICO_OK) - { + if (ret != PICO_OK) { LOGE("Error synthesizing string '%s': [%d]", text, ret); - if (local_text) + if (local_text) { free( local_text ); - return TTS_FAILURE; } + return TTS_FAILURE; + } text_remaining -= bytes_sent; inp += bytes_sent; - do - { - if (picoSynthAbort) - { + do { + if (picoSynthAbort) { break; } /* Retrieve the samples and add them to the buffer. */ - ret = pico_getData( picoEngine, (void *) outbuf, MAX_OUTBUF_SIZE, &bytes_recv, &out_data_type ); - if (bytes_recv) - { - if ((bufused + bytes_recv) <= bufferSize) - { + ret = pico_getData( picoEngine, (void *) outbuf, MAX_OUTBUF_SIZE, &bytes_recv, + &out_data_type ); + if (bytes_recv) { + if ((bufused + bytes_recv) <= bufferSize) { memcpy(buffer+bufused, (int8_t *) outbuf, bytes_recv); bufused += bytes_recv; - } - else - { + } else { /* The buffer filled; pass this on to the callback function. */ - cbret = picoSynthDoneCBPtr(userdata, 16000, AudioSystem::PCM_16_BIT, 1, buffer, bufused, TTS_SYNTH_PENDING); - if (cbret == TTS_CALLBACK_HALT) - { + cbret = picoSynthDoneCBPtr(userdata, 16000, AudioSystem::PCM_16_BIT, 1, buffer, + bufused, TTS_SYNTH_PENDING); + if (cbret == TTS_CALLBACK_HALT) { LOGI("Halt requested by caller. Halting."); picoSynthAbort = 1; break; - } + } bufused = 0; memcpy(buffer, (int8_t *) outbuf, bytes_recv); bufused += bytes_recv; - } } + } } while (PICO_STEP_BUSY == ret); /* This chunk of synthesis is finished; pass the remaining samples. Use 16 KHz, 16-bit samples. */ - if (!picoSynthAbort) - { - picoSynthDoneCBPtr( userdata, 16000, AudioSystem::PCM_16_BIT, 1, buffer, bufused, TTS_SYNTH_PENDING); + if (!picoSynthAbort) { + picoSynthDoneCBPtr( userdata, 16000, AudioSystem::PCM_16_BIT, 1, buffer, bufused, + TTS_SYNTH_PENDING); } picoSynthAbort = 0; - if (ret != PICO_STEP_IDLE) - { + if (ret != PICO_STEP_IDLE) { LOGE("Error occurred during synthesis [%d]", ret); - if (local_text) free(local_text); + if (local_text) { + free(local_text); + } LOGV("Synth loop: sending TTS_SYNTH_DONE after error"); - picoSynthDoneCBPtr( userdata, 16000, AudioSystem::PCM_16_BIT, 1, buffer, bufused, TTS_SYNTH_DONE); + picoSynthDoneCBPtr( userdata, 16000, AudioSystem::PCM_16_BIT, 1, buffer, bufused, + TTS_SYNTH_DONE); return TTS_FAILURE; } } - + /* Synthesis is done; notify the caller */ LOGV("Synth loop: sending TTS_SYNTH_DONE after all done, or was asked to stop"); - picoSynthDoneCBPtr( userdata, 16000, AudioSystem::PCM_16_BIT, 1, buffer, bufused, TTS_SYNTH_DONE); + picoSynthDoneCBPtr( userdata, 16000, AudioSystem::PCM_16_BIT, 1, buffer, bufused, + TTS_SYNTH_DONE); if (local_text) { free( local_text ); diff --git a/pico/tts/svox_ssml_parser.cpp b/pico/tts/svox_ssml_parser.cpp index 53dc786..38d2f80 100755 --- a/pico/tts/svox_ssml_parser.cpp +++ b/pico/tts/svox_ssml_parser.cpp @@ -13,16 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * History: - * 2009-06-29 -- initial version - * - */ +*/ #include "svox_ssml_parser.h" #include <utils/Log.h> #include <cutils/jstring.h> #include <string.h> - +#include <utils/String16.h> #define SSML_PITCH_XLOW "50" #define SSML_PITCH_LOW "75" @@ -47,847 +44,861 @@ #define SSML_BREAK_STRONG "1s" #define SSML_BREAK_XSTRONG "3s" -//TODO JMT remove comment -//extern int cnvIpaToXsampa(const char16_t* ipaString, char** outXsampaString); +extern int cnvIpaToXsampa(const char16_t* ipaString, size_t ipaStringSize, char** outXsampaString); +extern char * createPhonemeString( const char * xsampa, int length ); SvoxSsmlParser::SvoxSsmlParser() : m_isInBreak(0), m_appendix(NULL), m_docLanguage(NULL) { - mParser = XML_ParserCreate("UTF-8"); - if (mParser) + mParser = XML_ParserCreate("UTF-8"); + if (mParser) { - XML_SetElementHandler(mParser, starttagHandler, endtagHandler); - XML_SetCharacterDataHandler(mParser, textHandler); - XML_SetUserData(mParser, (void*)this); - m_datasize = 512; - m_data = new char[m_datasize]; - m_data[0] = '\0'; + XML_SetElementHandler(mParser, starttagHandler, endtagHandler); + XML_SetCharacterDataHandler(mParser, textHandler); + XML_SetUserData(mParser, (void*)this); + m_datasize = 512; + m_data = new char[m_datasize]; + m_data[0] = '\0'; } } SvoxSsmlParser::~SvoxSsmlParser() { - if (mParser) - XML_ParserFree(mParser); - if (m_data) - delete [] m_data; - if (m_appendix) - delete [] m_appendix; - if (m_docLanguage) - delete [] m_docLanguage; + if (mParser) + XML_ParserFree(mParser); + if (m_data) + delete [] m_data; + if (m_appendix) + delete [] m_appendix; + if (m_docLanguage) + delete [] m_docLanguage; } int SvoxSsmlParser::initSuccessful() { - return (mParser && m_data); + return (mParser && m_data); } int SvoxSsmlParser::parseDocument(const char* ssmldoc, int isFinal) { - int doclen = (int)strlen(ssmldoc) + 1; - int status = XML_Parse(mParser, ssmldoc, doclen, isFinal); - if (status == XML_STATUS_ERROR) + int doclen = (int)strlen(ssmldoc) + 1; + int status = XML_Parse(mParser, ssmldoc, doclen, isFinal); + if (status == XML_STATUS_ERROR) { - /* Note: for some reason Expat almost always complains about invalid tokens, even when document is well formed */ - LOGI("Parser error at line %d: %s\n", (int)XML_GetCurrentLineNumber(mParser), XML_ErrorString(XML_GetErrorCode(mParser))); + /* Note: for some reason Expat almost always complains about invalid tokens, even when document is well formed */ + LOGI("Parser error at line %d: %s\n", (int)XML_GetCurrentLineNumber(mParser), XML_ErrorString(XML_GetErrorCode(mParser))); } - return status; + return status; } char* SvoxSsmlParser::getParsedDocument() { - return m_data; + return m_data; } char* SvoxSsmlParser::getParsedDocumentLanguage() { - return m_docLanguage; + return m_docLanguage; } void SvoxSsmlParser::starttagHandler(void* data, const XML_Char* element, const XML_Char** attributes) { - ((SvoxSsmlParser*)data)->startElement(element, attributes); + ((SvoxSsmlParser*)data)->startElement(element, attributes); } void SvoxSsmlParser::startElement(const XML_Char* element, const XML_Char** attributes) { - if (strcmp(element, "speak") == 0) + if (strcmp(element, "speak") == 0) { - if (strlen(m_data) > 0) - { - /* we have old data, get rid of it and reallocate memory */ - delete m_data; - m_data = NULL; - m_datasize = 512; - m_data = new char[m_datasize]; - if (!m_data) + if (strlen(m_data) > 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + /* we have old data, get rid of it and reallocate memory */ + delete m_data; + m_data = NULL; + m_datasize = 512; + m_data = new char[m_datasize]; + if (!m_data) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } } - } - /* the only attribute supported in the speak tag is xml:lang, all others are ignored */ - for (int i = 0; attributes[i]; i += 2) - { - if (strcmp(attributes[i], "xml:lang") == 0) - { - if (!m_docLanguage) + /* the only attribute supported in the speak tag is xml:lang, all others are ignored */ + for (int i = 0; attributes[i]; i += 2) { - m_docLanguage = new char[strlen(attributes[i+1])+1]; - } - strcpy(m_docLanguage, attributes[i+1]); - break; + if (strcmp(attributes[i], "xml:lang") == 0) + { + if (!m_docLanguage) + { + m_docLanguage = new char[strlen(attributes[i+1])+1]; + } + strcpy(m_docLanguage, attributes[i+1]); + break; + } } } - } - else if (strcmp(element, "p") == 0) /* currently no attributes are supported for <p> */ - { - if (strlen(m_data) + 4 > (size_t)m_datasize) + else if (strcmp(element, "p") == 0) /* currently no attributes are supported for <p> */ { - if (!growDataSize(100)) + if (strlen(m_data) + 4 > (size_t)m_datasize) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } } + strcat(m_data, "<p>"); } - strcat(m_data, "<p>"); - } - else if (strcmp(element, "s") == 0) /* currently no attributes are supported for <s> */ - { - if (strlen(m_data) + 4 > (size_t)m_datasize) + else if (strcmp(element, "s") == 0) /* currently no attributes are supported for <s> */ { - if (!growDataSize(100)) + if (strlen(m_data) + 4 > (size_t)m_datasize) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } } + strcat(m_data, "<s>"); } - strcat(m_data, "<s>"); - } - else if (strcmp(element, "phoneme") == 0) /* only ipa and xsampa alphabets are supported */ - { - if (strlen(m_data) + 9 > (size_t)m_datasize) + else if (strcmp(element, "phoneme") == 0) /* only ipa and xsampa alphabets are supported */ { - if (!growDataSize(100)) - { - LOGE("Error: failed to allocate memory for string!\n"); - return; - } - } - strcat(m_data, "<phoneme"); - - int alpha = 1; /* set to 1 if alphabet is ipa */ - char* ph = NULL; + int alpha = 1; /* set to 1 if alphabet is ipa */ + int tagComplete = 0; /* set to 1 if phoneme tag has already been added */ + char16_t* ph = NULL; + char* xsampastr = NULL; + size_t phsize = 0; + size_t xsampasize = 0; - for (int i = 0; attributes[i]; i += 2) - { - if (strcmp(attributes[i], "alphabet") == 0) - { - if (strcmp(attributes[i+1], "xsampa") == 0) - { - alpha = 0; - } - } - if (strcmp(attributes[i], "ph") == 0) - { - ph = new char[strlen(attributes[i+1]) + 1]; - strcpy(ph, attributes[i+1]); - } - } - if (alpha) - { - /* need to convert phoneme string to xsampa */ - size_t size = 0; - char16_t* ipastr = strdup8to16(ph, &size); - char16_t* xsampastr = NULL; - if (!ipastr) - { - LOGE("Error: failed to allocate memory for IPA string conversion"); - return; - } - //TODO JMT remove comment - //size = cnvIpaToXsampa(ipastr, &xsampastr); - free(ipastr); - char* xsampa = strndup16to8(xsampastr, size); - if (!xsampa) + for (int i = 0; attributes[i]; i += 2) { - LOGE("Error: failed to allocate memory for IPA string conversion"); - delete [] xsampastr; - return; + if (strcmp(attributes[i], "alphabet") == 0) + { + if (strcmp(attributes[i+1], "xsampa") == 0) + { + alpha = 0; + } + } + if (strcmp(attributes[i], "ph") == 0) + { + ph = new char16_t[strlen8to16(attributes[i+1]) + 1]; + ph = strdup8to16(attributes[i+1], &phsize); + } } - if (strlen(m_data) + strlen(xsampa) + 7 > (size_t)m_datasize) + if (!ph) { - if (!growDataSize(100)) - { - LOGE("Error: failed to allocate memory for string!"); - delete [] xsampastr; - free(xsampa); - return; - } + /* error, no phonetic string */ + LOGE("Error: bad SSML syntax, ph attribute not supplied."); + return; } - strcat(m_data, " ph='"); - strcat(m_data, xsampa); - delete [] xsampastr; - free(xsampa); - } - else - { - strcat(m_data, " ph='"); - strcat(m_data, ph); - } - if (ph) - delete [] ph; - if (strlen(m_data) + 3 > (size_t)m_datasize) - { - if (!growDataSize(100)) + if (alpha) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + /* need to convert phoneme string to xsampa */ + xsampasize = cnvIpaToXsampa(ph, phsize, &xsampastr); + delete [] ph; + if (!xsampastr) + { + LOGE("Error: failed to allocate memory for IPA string conversion"); + return; + } } - } - strcat(m_data, "'>"); - } - else if (strcmp(element, "break") == 0) - { - if (strlen(m_data) + 17 > (size_t)m_datasize) - { - if (!growDataSize(100)) + else { - LOGE("Error: failed to allocate memory for string!\n"); - return; + xsampastr = strndup16to8(ph, phsize); + xsampasize = strlen(xsampastr); + delete [] ph; } - } - strcat(m_data, "<break time='"); - char* time = NULL; - for (int i = 0; attributes[i]; i += 2) - { - if (strcmp(attributes[i], "time") == 0) - { - time = new char[strlen(attributes[i+1]) + 1]; - if (!time) - { - LOGE("Error: failed to allocate memory for string!\n"); - return; - } - strcpy(time, attributes[i+1]); - } - else if (strcmp(attributes[i], "strength") == 0 && !time) - { - time = convertBreakStrengthToTime(attributes[i+1]); + /* split XSAMPA string into multiple phonemes if needed */ + if (strstr(xsampastr, " ") || strstr(xsampastr, "#")) /* check again to see if we have multiple words */ + { + char* phonstr = createPhonemeString(xsampastr, strlen(xsampastr) + 1); + free(xsampastr); + xsampastr = NULL; + xsampastr = (char*)malloc(strlen(phonstr) + 1); + strcpy(xsampastr, phonstr); + free(phonstr); + phonstr = NULL; + tagComplete = 1; } - } - if (!time) - { - time = new char[6]; - if (!time) + + if (tagComplete) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + if (strlen(m_data) + strlen(xsampastr) + 1 > (size_t)m_datasize) + { + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!"); + free(xsampastr); + return; + } + } } - strcpy(time, SSML_BREAK_WEAK); /* if no time or strength attributes are specified, default to weak break */ - } - if (strlen(m_data) + strlen(time) + 4 > (size_t)m_datasize) - { - if (!growDataSize(100)) + else { - LOGE("Error: failed to allocate memory for string!\n"); - return; + if (strlen(m_data) + strlen(xsampastr) + 17 > (size_t)m_datasize) + { + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!"); + free(xsampastr); + return; + } + } + strcat(m_data, "<phoneme ph='"); } + + strcat(m_data, xsampastr); + free(xsampastr); + + if (!tagComplete) + { + if (strlen(m_data) + 4 > (size_t)m_datasize) + { + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + } + strcat(m_data, "'/>"); + } + + m_isInBreak = 1; /* set flag to indicate any text between open and close tag is to be discarded */ } - strcat(m_data, time); - strcat(m_data, "'/>"); - m_isInBreak = 1; - } - else if (strcmp(element, "prosody") == 0) /* only pitch, rate and volume attributes are supported */ - { - for (int i = 0; attributes[i]; i += 2) + else if (strcmp(element, "break") == 0) { - if (strcmp(attributes[i], "pitch") == 0) + if (strlen(m_data) + 17 > (size_t)m_datasize) { - char* svoxpitch = convertToSvoxPitch(attributes[i+1]); - if (!svoxpitch) - { - LOGE("Error: failed to allocate memory for string!\n"); - return; - } - if (!svoxpitch) - { - svoxpitch = new char[4]; - if (!svoxpitch) + if (!growDataSize(100)) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + LOGE("Error: failed to allocate memory for string!\n"); + return; } - strcpy(svoxpitch, "100"); - } - char* pitch = new char[17 + strlen(svoxpitch)]; - if (!pitch) - { - LOGE("Error: failed to allocate memory for string!\n"); - return; } - sprintf(pitch, "<pitch level='%s'>", svoxpitch); - if (strlen(m_data) + strlen(pitch) + 1 > (size_t)m_datasize) + strcat(m_data, "<break time='"); + char* time = NULL; + + for (int i = 0; attributes[i]; i += 2) { - if (!growDataSize(100)) + if (strcmp(attributes[i], "time") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + time = new char[strlen(attributes[i+1]) + 1]; + if (!time) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + strcpy(time, attributes[i+1]); } - } - strcat(m_data, pitch); - if (!m_appendix) - { - m_appendix = new char[30]; - m_appendix[0] = '\0'; - } - strcat(m_appendix, "</pitch>"); - delete [] svoxpitch; - delete [] pitch; - } - else if (strcmp(attributes[i], "rate") == 0) - { - char* svoxrate = convertToSvoxRate(attributes[i+1]); - if (!svoxrate) - { - svoxrate = new char[4]; - if (!svoxrate) + else if (strcmp(attributes[i], "strength") == 0 && !time) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + time = convertBreakStrengthToTime(attributes[i+1]); } - strcpy(svoxrate, "100"); } - char* rate = new char[17 + strlen(svoxrate)]; - if (!rate) + if (!time) { - LOGE("Error: failed to allocate memory for string!\n"); - return; - } - sprintf(rate, "<speed level='%s'>", svoxrate); - if (strlen(m_data) + strlen(rate) + 1 > (size_t)m_datasize) - { - if (!growDataSize(100)) + time = new char[6]; + if (!time) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + LOGE("Error: failed to allocate memory for string!\n"); + return; } + strcpy(time, SSML_BREAK_WEAK); /* if no time or strength attributes are specified, default to weak break */ } - strcat(m_data, rate); - if (!m_appendix) + if (strlen(m_data) + strlen(time) + 4 > (size_t)m_datasize) { - m_appendix = new char[30]; - if (!m_appendix) + if (!growDataSize(100)) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + LOGE("Error: failed to allocate memory for string!\n"); + return; } - m_appendix[0] = '\0'; - } - strcat(m_appendix, "</speed>"); - delete [] svoxrate; - delete [] rate; } - else if (strcmp(attributes[i], "volume") == 0) - { - char* svoxvol = convertToSvoxVolume(attributes[i+1]); - if (!svoxvol) + strcat(m_data, time); + strcat(m_data, "'/>"); + m_isInBreak = 1; /* set flag to indicate any text between open and close tag is to be discarded */ + } + else if (strcmp(element, "prosody") == 0) /* only pitch, rate and volume attributes are supported */ + { + for (int i = 0; attributes[i]; i += 2) { - svoxvol = new char[4]; - if (!svoxvol) + if (strcmp(attributes[i], "pitch") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + char* svoxpitch = convertToSvoxPitch(attributes[i+1]); + if (!svoxpitch) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + if (!svoxpitch) + { + svoxpitch = new char[4]; + if (!svoxpitch) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + strcpy(svoxpitch, "100"); + } + char* pitch = new char[17 + strlen(svoxpitch)]; + if (!pitch) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + sprintf(pitch, "<pitch level='%s'>", svoxpitch); + if (strlen(m_data) + strlen(pitch) + 1 > (size_t)m_datasize) + { + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + } + strcat(m_data, pitch); + if (!m_appendix) + { + m_appendix = new char[30]; + m_appendix[0] = '\0'; + } + strcat(m_appendix, "</pitch>"); + delete [] svoxpitch; + delete [] pitch; } - strcpy(svoxvol, "100"); - } - char* volume = new char[18 + strlen(svoxvol)]; - if (!volume) - { - LOGE("Error: failed to allocate memory for string!\n"); - return; - } - sprintf(volume, "<volume level='%s'>", svoxvol); - if (strlen(m_data) + strlen(volume) + 1 > (size_t)m_datasize) - { - if (!growDataSize(100)) + else if (strcmp(attributes[i], "rate") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + char* svoxrate = convertToSvoxRate(attributes[i+1]); + if (!svoxrate) + { + svoxrate = new char[4]; + if (!svoxrate) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + strcpy(svoxrate, "100"); + } + char* rate = new char[17 + strlen(svoxrate)]; + if (!rate) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + sprintf(rate, "<speed level='%s'>", svoxrate); + if (strlen(m_data) + strlen(rate) + 1 > (size_t)m_datasize) + { + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + } + strcat(m_data, rate); + if (!m_appendix) + { + m_appendix = new char[30]; + if (!m_appendix) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + m_appendix[0] = '\0'; + } + strcat(m_appendix, "</speed>"); + delete [] svoxrate; + delete [] rate; + } + else if (strcmp(attributes[i], "volume") == 0) + { + char* svoxvol = convertToSvoxVolume(attributes[i+1]); + if (!svoxvol) + { + svoxvol = new char[4]; + if (!svoxvol) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + strcpy(svoxvol, "100"); + } + char* volume = new char[18 + strlen(svoxvol)]; + if (!volume) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + sprintf(volume, "<volume level='%s'>", svoxvol); + if (strlen(m_data) + strlen(volume) + 1 > (size_t)m_datasize) + { + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + } + strcat(m_data, volume); + if (!m_appendix) + { + m_appendix = new char[30]; + m_appendix[0] = '\0'; + } + strcat(m_appendix, "</volume>"); + delete [] svoxvol; + delete [] volume; } - } - strcat(m_data, volume); - if (!m_appendix) - { - m_appendix = new char[30]; - m_appendix[0] = '\0'; - } - strcat(m_appendix, "</volume>"); - delete [] svoxvol; - delete [] volume; } } - } - else if (strcmp(element, "audio") == 0) /* only 16kHz 16bit wav files are supported as src */ - { - if (strlen(m_data) + 17 > (size_t)m_datasize) + else if (strcmp(element, "audio") == 0) /* only 16kHz 16bit wav files are supported as src */ { - if (!growDataSize(100)) + if (strlen(m_data) + 17 > (size_t)m_datasize) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } } - } - strcat(m_data, "<usesig file='"); + strcat(m_data, "<usesig file='"); - for (int i = 0; attributes[i]; i += 2) - { - if (strcmp(attributes[i], "src") == 0) - { - if (strlen(m_data) + strlen(attributes[i+1]) + 1 > (size_t)m_datasize) + for (int i = 0; attributes[i]; i += 2) { - if (!growDataSize(100)) + if (strcmp(attributes[i], "src") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + if (strlen(m_data) + strlen(attributes[i+1]) + 1 > (size_t)m_datasize) + { + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + } + strcat(m_data, attributes[i+1]); } } - strcat(m_data, attributes[i+1]); - } - } - strcat(m_data, "'>"); + strcat(m_data, "'>"); } } void SvoxSsmlParser::endtagHandler(void* data, const XML_Char* element) { - ((SvoxSsmlParser*)data)->endElement(element); + ((SvoxSsmlParser*)data)->endElement(element); } void SvoxSsmlParser::endElement(const XML_Char* element) { - if (strcmp(element, "speak") == 0) + if (strcmp(element, "speak") == 0) { - + /* do nothing */ } - else if (strcmp(element, "p") == 0) + else if (strcmp(element, "p") == 0) { - if (strlen(m_data) + 5 > (size_t)m_datasize) - { - if (!growDataSize(100)) + if (strlen(m_data) + 5 > (size_t)m_datasize) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } } + strcat(m_data, "</p>"); } - strcat(m_data, "</p>"); - } - else if (strcmp(element, "s") == 0) + else if (strcmp(element, "s") == 0) { - if (strlen(m_data) + 5 > (size_t)m_datasize) - { - if (!growDataSize(100)) + if (strlen(m_data) + 5 > (size_t)m_datasize) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } } + strcat(m_data, "</s>"); } - strcat(m_data, "</s>"); - } - else if (strcmp(element, "phoneme") == 0) - { - if (strlen(m_data) + 11 > (size_t)m_datasize) + else if (strcmp(element, "phoneme") == 0) { - if (!growDataSize(100)) - { - LOGE("Error: failed to allocate memory for string!\n"); - return; - } + m_isInBreak = 0; /* indicate we are no longer in phoneme tag */ } - strcat(m_data, "</phoneme>"); - } - else if (strcmp(element, "break") == 0) + else if (strcmp(element, "break") == 0) { - m_isInBreak = 0; /* indicate we are no longer in break tag */ + m_isInBreak = 0; /* indicate we are no longer in break tag */ } - else if (strcmp(element, "prosody") == 0) - { - if (m_appendix) + else if (strcmp(element, "prosody") == 0) { - if (strlen(m_data) + strlen(m_appendix) + 1 > (size_t)m_datasize) + if (m_appendix) { - if (!growDataSize(100)) - { - LOGE("Error: failed to allocate memory for string!\n"); - return; - } + if (strlen(m_data) + strlen(m_appendix) + 1 > (size_t)m_datasize) + { + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } + } + strcat(m_data, m_appendix); + delete [] m_appendix; + m_appendix = NULL; } - strcat(m_data, m_appendix); - delete [] m_appendix; - m_appendix = NULL; } - } - else if (strcmp(element, "audio") == 0) - { - if (strlen(m_data) + 10 > (size_t)m_datasize) + else if (strcmp(element, "audio") == 0) { - if (!growDataSize(100)) + if (strlen(m_data) + 10 > (size_t)m_datasize) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } } - } - strcat(m_data, "</usesig>"); + strcat(m_data, "</usesig>"); } } void SvoxSsmlParser::textHandler(void* data, const XML_Char* text, int length) { - ((SvoxSsmlParser*)data)->textElement(text, length); + ((SvoxSsmlParser*)data)->textElement(text, length); } void SvoxSsmlParser::textElement(const XML_Char* text, int length) { - if (m_isInBreak) + if (m_isInBreak) { - return; /* handles the case when someone has added text inside the break tag - this text is thrown away */ + return; /* handles the case when someone has added text inside the break or phoneme tag - this text is thrown away */ } - char* content = new char[length + 1]; - if (!content) + char* content = new char[length + 1]; + if (!content) { - LOGE("Error: failed to allocate memory for string!\n"); - return; + LOGE("Error: failed to allocate memory for string!\n"); + return; } - strncpy(content, text, length); - content[length] = '\0'; + strncpy(content, text, length); + content[length] = '\0'; - if (strlen(m_data) + strlen(content) + 1 > (size_t)m_datasize) - { - if (!growDataSize(100)) + if (strlen(m_data) + strlen(content) + 1 > (size_t)m_datasize) { - LOGE("Error: failed to allocate memory for string!\n"); - return; - } + if (!growDataSize(100)) + { + LOGE("Error: failed to allocate memory for string!\n"); + return; + } } - strcat(m_data, content); - delete [] content; + strcat(m_data, content); + delete [] content; } /** - convertToSvoxPitch - Converts SSML pitch labels to SVOX pitch levels +convertToSvoxPitch +Converts SSML pitch labels to SVOX pitch levels */ char* SvoxSsmlParser::convertToSvoxPitch(const char* value) { - char* converted = NULL; - if (strcmp(value, "x-low") == 0) + char* converted = NULL; + if (strcmp(value, "x-low") == 0) { - converted = new char[4]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_PITCH_XLOW); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_PITCH_XLOW); } - else if (strcmp(value, "low") == 0) + else if (strcmp(value, "low") == 0) { - converted = new char[4]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_PITCH_LOW); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_PITCH_LOW); } - else if (strcmp(value, "medium") == 0) + else if (strcmp(value, "medium") == 0) { - converted = new char[4]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_PITCH_MEDIUM); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_PITCH_MEDIUM); } - else if (strcmp(value, "default") == 0) - { - converted = new char[4]; - if (!converted) + else if (strcmp(value, "default") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_PITCH_MEDIUM); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_PITCH_MEDIUM); } - else if (strcmp(value, "high") == 0) - { - converted = new char[4]; - if (!converted) + else if (strcmp(value, "high") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_PITCH_HIGH); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_PITCH_HIGH); } - else if (strcmp(value, "x-high") == 0) - { - converted = new char[4]; - if (!converted) + else if (strcmp(value, "x-high") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_PITCH_XHIGH); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_PITCH_XHIGH); } - return converted; + return converted; } /** - convertToSvoxRate - Converts SSML rate labels to SVOX speed levels + convertToSvoxRate + Converts SSML rate labels to SVOX speed levels */ char* SvoxSsmlParser::convertToSvoxRate(const char* value) { - char* converted = NULL; - if (strcmp(value, "x-slow") == 0) - { - converted = new char[4]; - if (!converted) + char* converted = NULL; + if (strcmp(value, "x-slow") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_RATE_XSLOW); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_RATE_XSLOW); } - else if (strcmp(value, "slow") == 0) + else if (strcmp(value, "slow") == 0) { - converted = new char[4]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_RATE_SLOW); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_RATE_SLOW); } - else if (strcmp(value, "medium") == 0) + else if (strcmp(value, "medium") == 0) { - converted = new char[4]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_RATE_MEDIUM); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_RATE_MEDIUM); } - else if (strcmp(value, "default") == 0) + else if (strcmp(value, "default") == 0) { - converted = new char[4]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_RATE_MEDIUM); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_RATE_MEDIUM); } - else if (strcmp(value, "fast") == 0) + else if (strcmp(value, "fast") == 0) { - converted = new char[4]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_RATE_FAST); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_RATE_FAST); } - else if (strcmp(value, "x-fast") == 0) - { - converted = new char[4]; - if (!converted) + else if (strcmp(value, "x-fast") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_RATE_XFAST); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_RATE_XFAST); } - return converted; + return converted; } /** - convertToSvoxVolume - Converts SSML volume labels to SVOX volume levels +convertToSvoxVolume +Converts SSML volume labels to SVOX volume levels */ char* SvoxSsmlParser::convertToSvoxVolume(const char* value) { - char* converted = NULL; - if (strcmp(value, "silent") == 0) - { - converted = new char[4]; - if (!converted) + char* converted = NULL; + if (strcmp(value, "silent") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_VOLUME_SILENT); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_VOLUME_SILENT); } - else if (strcmp(value, "x-low") == 0) - { - converted = new char[4]; - if (!converted) + else if (strcmp(value, "x-low") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_VOLUME_XLOW); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_VOLUME_XLOW); } - else if (strcmp(value, "low") == 0) - { - converted = new char[4]; - if (!converted) + else if (strcmp(value, "low") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_VOLUME_LOW); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_VOLUME_LOW); } - else if (strcmp(value, "medium") == 0) + else if (strcmp(value, "medium") == 0) { - converted = new char[4]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_VOLUME_MEDIUM); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_VOLUME_MEDIUM); } - else if (strcmp(value, "default") == 0) + else if (strcmp(value, "default") == 0) { - converted = new char[4]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_VOLUME_MEDIUM); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_VOLUME_MEDIUM); } - else if (strcmp(value, "loud") == 0) + else if (strcmp(value, "loud") == 0) { - converted = new char[4]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_VOLUME_LOUD); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_VOLUME_LOUD); } - else if (strcmp(value, "x-loud") == 0) - { - converted = new char[4]; - if (!converted) + else if (strcmp(value, "x-loud") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_VOLUME_XLOUD); + converted = new char[4]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_VOLUME_XLOUD); } - return converted; + return converted; } /** - convertBreakStrengthToTime - Converts SSML break strength labels to SVOX break time +convertBreakStrengthToTime +Converts SSML break strength labels to SVOX break time */ char* SvoxSsmlParser::convertBreakStrengthToTime(const char* value) { - char* converted = NULL; - if (strcmp(value, "none") == 0) - { - converted = new char[6]; - if (!converted) + char* converted = NULL; + if (strcmp(value, "none") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_BREAK_NONE); + converted = new char[6]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_BREAK_NONE); } - else if (strcmp(value, "x-weak") == 0) - { - converted = new char[6]; - if (!converted) + else if (strcmp(value, "x-weak") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_BREAK_XWEAK); + converted = new char[6]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_BREAK_XWEAK); } - else if (strcmp(value, "weak") == 0) - { - converted = new char[6]; - if (!converted) + else if (strcmp(value, "weak") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_BREAK_WEAK); + converted = new char[6]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_BREAK_WEAK); } - else if (strcmp(value, "medium") == 0) + else if (strcmp(value, "medium") == 0) { - converted = new char[6]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_BREAK_MEDIUM); + converted = new char[6]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_BREAK_MEDIUM); } - else if (strcmp(value, "strong") == 0) + else if (strcmp(value, "strong") == 0) { - converted = new char[6]; - if (!converted) - { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_BREAK_STRONG); + converted = new char[6]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_BREAK_STRONG); } - else if (strcmp(value, "x-strong") == 0) - { - converted = new char[6]; - if (!converted) + else if (strcmp(value, "x-strong") == 0) { - LOGE("Error: failed to allocate memory for string!\n"); - return NULL; - } - strcpy(converted, SSML_BREAK_XSTRONG); + converted = new char[6]; + if (!converted) + { + LOGE("Error: failed to allocate memory for string!\n"); + return NULL; + } + strcpy(converted, SSML_BREAK_XSTRONG); } - return converted; + return converted; } /** - growDataSize - Increases the size of the internal text storage member +growDataSize +Increases the size of the internal text storage member */ int SvoxSsmlParser::growDataSize(int sizeToGrow) { - char* tmp = new char[m_datasize]; - if (!tmp) - return 0; - - strcpy(tmp, m_data); - delete [] m_data; - m_data = NULL; - m_data = new char[m_datasize + sizeToGrow]; - if (!m_data) - { - m_data = tmp; - return 0; - } - m_datasize += sizeToGrow; - strcpy(m_data, tmp); - delete [] tmp; - tmp = NULL; - return 1; + char* tmp = new char[m_datasize]; + if (!tmp) + return 0; + + strcpy(tmp, m_data); + delete [] m_data; + m_data = NULL; + m_data = new char[m_datasize + sizeToGrow]; + if (!m_data) + { + m_data = tmp; + return 0; + } + m_datasize += sizeToGrow; + strcpy(m_data, tmp); + delete [] tmp; + tmp = NULL; + return 1; } diff --git a/pico/tts/svox_ssml_parser.h b/pico/tts/svox_ssml_parser.h index cc83305..55708f0 100755 --- a/pico/tts/svox_ssml_parser.h +++ b/pico/tts/svox_ssml_parser.h @@ -13,9 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * History: - * 2009-06-29 -- initial version - * */ #include <stdio.h> @@ -51,7 +48,7 @@ class SvoxSsmlParser return 1 if successful, 0 otherwise */ int initSuccessful(); - + public: /* public members */ /** @@ -76,7 +73,7 @@ class SvoxSsmlParser return language code of SSML document, NULL if not set */ char* getParsedDocumentLanguage(); - + private: /* static callback functions */ /** |