1 /*---------------------------------------------------------------------------* 2 * SWIslts.c * 3 * * 4 * Copyright 2007, 2008 Nuance Communciations, Inc. * 5 * * 6 * Licensed under the Apache License, Version 2.0 (the 'License'); * 7 * you may not use this file except in compliance with the License. * 8 * * 9 * You may obtain a copy of the License at * 10 * http://www.apache.org/licenses/LICENSE-2.0 * 11 * * 12 * Unless required by applicable law or agreed to in writing, software * 13 * distributed under the License is distributed on an 'AS IS' BASIS, * 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 15 * See the License for the specific language governing permissions and * 16 * limitations under the License. * 17 * * 18 *---------------------------------------------------------------------------*/ 19 20 #define _IN_SWI_SLTS__ 21 22 #ifdef SWISLTS_USE_STATIC_API 23 #define SWISLTS_FNEXPORT 24 #else 25 #ifdef WIN32 26 #include <windows.h> 27 #define SWISLTS_FNEXPORT __declspec(dllexport) 28 #else 29 #define SWISLTS_FNEXPORT 30 #endif 31 #endif 32 33 #include <stdlib.h> 34 35 36 #include <string.h> 37 38 #include "pmemory.h" 39 #include "PFile.h" 40 #include "plog.h" 41 42 #include "SWIslts.h" 43 #include "lts.h" 44 45 /** 46 * Phone map table 47 */ 48 typedef struct SLTS_PhoneMap_t{ 49 LCHAR *src; 50 LCHAR *des; 51 } SLTS_PhoneMap; 52 53 #define INF_SILENCE_OPTIONAL (const char *)"&" 54 55 static const SLTS_PhoneMap g_aPhoneMap[] = { 56 {"PS", "&"}, 57 {"SS0", ""}, 58 {"SS1", ""}, 59 {"SS2", ""}, 60 {"WS", "&"} 61 }; 62 static const int g_numPhones = sizeof(g_aPhoneMap) / sizeof(g_aPhoneMap[0]); 63 64 #ifdef USE_STATIC_SLTS 65 #define MAX_INPUT_LEN 255 66 static SLTS_Engine g_sltsEngine; 67 static SWIsltsWrapper g_sltsWrapper; 68 #endif 69 70 #define MAX_PRON_LEN 255 71 #define MAX_PHONE_LEN 4 72 73 static SWIsltsResult GetPhoneStr(SLTS_Engine *pEng, char *apszPhones[], int num_phones, char *pszPhoneStr, size_t *len); 74 75 SWISLTS_FNEXPORT SWIsltsResult SWIsltsGetWrapper(SWIsltsWrapper **ppLtsWrap) 76 { 77 if (ppLtsWrap != NULL) { 78 #ifdef USE_STATIC_SLTS 79 *ppLtsWrap = &g_sltsWrapper; 80 #else 81 *ppLtsWrap = MALLOC(sizeof(SWIsltsWrapper), MTAG); 82 if (*ppLtsWrap == NULL) { 83 return SWIsltsErrAllocResource; 84 } 85 #endif 86 (*ppLtsWrap)->init = SWIsltsInit; 87 (*ppLtsWrap)->term = SWIsltsTerm; 88 (*ppLtsWrap)->open = SWIsltsOpen; 89 (*ppLtsWrap)->close = SWIsltsClose; 90 (*ppLtsWrap)->textToPhone = SWIsltsTextToPhone; 91 } 92 return SWIsltsSuccess; 93 } 94 95 SWISLTS_FNEXPORT SWIsltsResult SWIsltsReleaseWrapper(SWIsltsWrapper *pLtsWrap) 96 { 97 #ifndef USE_STATIC_SLTS 98 if (pLtsWrap != NULL) { 99 FREE(pLtsWrap); 100 pLtsWrap = NULL; 101 } 102 #endif 103 return SWIsltsSuccess; 104 } 105 106 /* External Core SLTS API implementation */ 107 SWISLTS_FNEXPORT SWIsltsResult SWIsltsInit() 108 { 109 return SWIsltsSuccess; 110 } 111 112 SWISLTS_FNEXPORT SWIsltsResult SWIsltsTerm() 113 { 114 return SWIsltsSuccess; 115 } 116 117 /* create a new instance of SLTS */ 118 SWISLTS_FNEXPORT SWIsltsResult SWIsltsOpen(SWIsltsHand *phLts, 119 const char *data_filename) 120 { 121 SLTS_Engine * pEng; 122 SWIsltsResult nRes = SWIsltsSuccess; 123 124 if ((phLts == NULL) 125 #ifndef USE_STATIC_SLTS 126 || (data_filename == NULL) 127 #endif 128 ) 129 { 130 return SWIsltsInvalidParam; 131 } 132 133 #ifdef USE_STATIC_SLTS 134 pEng = &g_sltsEngine; 135 #else 136 pEng = CALLOC(1, sizeof(SLTS_Engine), MTAG); 137 if (pEng == NULL) { 138 return SWIsltsErrAllocResource; 139 } 140 #endif 141 142 /* initialize */ 143 nRes = create_lts((char *)data_filename, &pEng->m_hLts); 144 if (nRes != SWIsltsSuccess) { 145 PLogError(L("create_lts with the model file (%s) fails with return code %d\n"), (char *)data_filename, nRes); 146 goto CLEAN_UP; 147 } 148 149 *phLts = (SWIsltsHand)pEng; 150 151 return SWIsltsSuccess; 152 153 CLEAN_UP: 154 if (*phLts != NULL) { 155 SWIsltsClose(*phLts); 156 } 157 158 return nRes; 159 } 160 161 /* deletes given instance of SLTS */ 162 SWISLTS_FNEXPORT SWIsltsResult SWIsltsClose(SWIsltsHand hLts) 163 { 164 SLTS_Engine *pEng = (SLTS_Engine *)hLts; 165 if (pEng == NULL) { 166 return SWIsltsInvalidParam; 167 } 168 169 /* clean up internal buffers and slts structure */ 170 if (pEng->m_hLts) { 171 free_lts(pEng->m_hLts); 172 } 173 pEng->m_hLts = NULL; 174 175 #ifndef USE_STATIC_SLTS 176 FREE(pEng); 177 #endif 178 179 pEng = NULL; 180 181 return SWIsltsSuccess; 182 } 183 184 /* send phones to internal buffer */ 185 SWISLTS_FNEXPORT SWIsltsResult SWIsltsTextToPhone(SWIsltsHand hLts, 186 const char *text, 187 char *output_phone_string[], 188 int *output_phone_len, 189 int max_phone_len) 190 { 191 int i; 192 SWIsltsResult nRes = SWIsltsSuccess; 193 #ifdef USE_STATIC_SLTS 194 char new_text[MAX_INPUT_LEN]; 195 #else 196 char *new_text; 197 #endif 198 199 SLTS_Engine *pEng; 200 if (hLts == NULL) { 201 return SWIsltsInvalidParam; 202 } 203 204 if (text == NULL) { 205 return SWIsltsInvalidParam; 206 } 207 208 /* check that the output phone string param is allocated */ 209 for(i=0; i<max_phone_len; i++){ 210 if(output_phone_string[i] == NULL) 211 return SWIsltsInvalidParam; 212 } 213 214 pEng = (SLTS_Engine *)hLts; 215 216 /* get rid newlines, tabs, and spaces, if any */ 217 #ifdef USE_STATIC_SLTS 218 if((strlen(text)+1) > MAX_INPUT_LEN){ 219 return SWIsltsMaxInputExceeded; 220 } 221 #else 222 new_text = MALLOC((strlen(text)+1)*sizeof(char), MTAG); 223 if (new_text == NULL) { 224 PLogError(L("SWISLTS_OUT_OF_MEMORY")); 225 return SWIsltsErrAllocResource; 226 } 227 #endif 228 229 strcpy(new_text, text); 230 i = strlen(new_text)-1; 231 while(new_text[i] == '\n' || new_text[i] == ' ' || new_text[i] == '\t') i--; 232 new_text[i+1] = '\0'; 233 234 /* now check if the input string is empty */ 235 if(strlen(new_text) == 0){ 236 *output_phone_len = 0; 237 nRes = SWIsltsEmptyPhoneString; 238 goto CLEAN_UP; 239 } 240 241 *output_phone_len = max_phone_len; 242 nRes = run_lts(pEng->m_hLts, pEng->m_hDict, new_text, output_phone_string, output_phone_len); 243 if (nRes != SWIsltsSuccess) { 244 goto CLEAN_UP; 245 } 246 247 #ifndef USE_STATIC_SLTS 248 if(new_text){ 249 FREE(new_text); 250 } 251 new_text = NULL; 252 #endif 253 254 return SWIsltsSuccess; 255 256 CLEAN_UP: 257 258 #ifndef USE_STATIC_SLTS 259 if(new_text){ 260 FREE(new_text); 261 } 262 new_text = NULL; 263 #endif 264 265 return nRes; 266 } 267 268 SWISLTS_FNEXPORT SWIsltsResult SWIsltsG2PGetWordTranscriptions(SWIsltsHand hLts, 269 const char *text, 270 SWIsltsTranscription **ppTranscriptions, 271 int *pnNbrOfTranscriptions) 272 { 273 SWIsltsResult nRes = SWIsltsSuccess; 274 char PHONE_STRING[MAX_PRON_LEN][MAX_PHONE_LEN]; 275 char * phone_string[MAX_PRON_LEN]; 276 SLTS_Engine * pEng = (SLTS_Engine *)hLts; 277 int i; 278 int num_phones = 0; 279 SWIsltsTranscription * pTranscription = NULL; 280 int nNbrOfTranscriptions = 0; 281 int * pnNbrOfTranscriptionsToSave = NULL; 282 LCHAR * pBlock = NULL; 283 284 for( i = 0; i < MAX_PRON_LEN; i++ ) { 285 phone_string[i] = PHONE_STRING[i]; 286 } 287 288 nRes = SWIsltsTextToPhone(hLts, text, phone_string, &num_phones, MAX_PRON_LEN); 289 if( nRes != SWIsltsSuccess ) { 290 PLogError(L("SWIsltsTextToPhone( ) fails with return code %d\n"), nRes); 291 goto CLEAN_UP; 292 } 293 #if DEBUG 294 pfprintf(PSTDOUT,"number of phones: %d\n ", num_phones); 295 for( i = 0; i < num_phones; i++ ) { 296 pfprintf(PSTDOUT,"%s ", phone_string[i]); 297 } 298 pfprintf(PSTDOUT,"\n "); 299 #endif 300 301 /* only one transcription available from seti */ 302 nNbrOfTranscriptions = 1; 303 pBlock = (LCHAR *)CALLOC(sizeof(int) + nNbrOfTranscriptions * sizeof(SWIsltsTranscription), sizeof(LCHAR), MTAG); 304 if (pBlock == NULL) { 305 PLogError(L("SWISLTS_OUT_OF_MEMORY")); 306 nRes = SWIsltsErrAllocResource; 307 goto CLEAN_UP; 308 } 309 pnNbrOfTranscriptionsToSave = (int *)pBlock; 310 pTranscription = (SWIsltsTranscription *)(pBlock + sizeof(int)); 311 312 *ppTranscriptions = pTranscription; 313 *pnNbrOfTranscriptions = *pnNbrOfTranscriptionsToSave = nNbrOfTranscriptions; 314 315 /* extra +1 for double-null at the end */ 316 pTranscription->pBuffer = MALLOC(MAX_PHONE_LEN * (num_phones + 1+1), MTAG); 317 if( pTranscription->pBuffer == NULL ) { 318 PLogError(L("SWISLTS_OUT_OF_MEMORY")); 319 nRes = SWIsltsErrAllocResource; 320 goto CLEAN_UP; 321 } 322 323 nRes = GetPhoneStr(pEng, phone_string, num_phones, (char *)pTranscription->pBuffer, &(pTranscription->nSizeOfBuffer)); 324 if( nRes != SWIsltsSuccess ) { 325 PLogError(L("SWIsltsInternalErr: GetPhoneStr( ) fails with return code %d\n"), nRes); 326 goto CLEAN_UP; 327 } 328 329 return SWIsltsSuccess; 330 331 CLEAN_UP: 332 333 *ppTranscriptions = NULL; 334 *pnNbrOfTranscriptions = 0; 335 336 for( i = 0; i < nNbrOfTranscriptions; i++ ) { 337 if(pTranscription[i].pBuffer) { 338 FREE(pTranscription[i].pBuffer); 339 } 340 } 341 FREE(pTranscription); 342 343 return nRes; 344 } 345 346 347 SWISLTS_FNEXPORT SWIsltsResult SWIsltsG2PFreeWordTranscriptions(SWIsltsHand hLts, 348 SWIsltsTranscription *pTranscriptions) 349 { 350 SWIsltsResult nRes = SWIsltsSuccess; 351 int nNbrOfTranscriptions; 352 int i; 353 LCHAR * pBuffer = NULL; 354 355 if( pTranscriptions == NULL ) { 356 return SWIsltsInvalidParam; 357 } 358 359 pBuffer = ((LCHAR *)pTranscriptions - sizeof(int)); 360 nNbrOfTranscriptions = (int)*pBuffer; 361 362 for( i = 0; i < nNbrOfTranscriptions; i++ ) { 363 if( pTranscriptions[i].pBuffer ) { 364 FREE(pTranscriptions[i].pBuffer); 365 } 366 } 367 FREE(pBuffer); 368 369 return nRes; 370 } 371 372 static SWIsltsResult GetPhoneStr(SLTS_Engine *pEng, char *apszPhones[], int num_phones, char *pszPhoneStr, size_t *len) 373 { 374 int i, j; 375 int nFound; 376 SWIsltsResult nRes = SWIsltsSuccess; 377 const char * pszLastPhone = NULL; 378 379 *pszPhoneStr = '\0'; 380 381 for( i = 0; i < num_phones; i++ ) { 382 nFound = 0; 383 for ( j = 0; j < g_numPhones && nFound == 0; j++ ) { 384 if( strcmp(apszPhones[i], g_aPhoneMap[j].src) == 0 ) { 385 nFound = 1; 386 if( strcmp(g_aPhoneMap[j].des, INF_SILENCE_OPTIONAL) == 0 ) { 387 if( *pszPhoneStr != '\0' && strcmp(pszLastPhone, INF_SILENCE_OPTIONAL) != 0 ) { 388 strcat(pszPhoneStr, g_aPhoneMap[j].des); 389 } 390 } 391 else if( g_aPhoneMap[j].des != '\0' ) { 392 strcat(pszPhoneStr, g_aPhoneMap[j].des); 393 } 394 pszLastPhone = g_aPhoneMap[j].des; 395 } 396 } 397 if( nFound == 0 ) { 398 strcat(pszPhoneStr, apszPhones[i]); 399 pszLastPhone = apszPhones[i]; 400 } 401 } 402 403 *len = strlen(pszPhoneStr) + 1; 404 // add the double-null per SREC/Vocon convention 405 pszPhoneStr[ *len] = 0; 406 407 return nRes; 408 } 409