/*---------------------------------------------------------------------------* * SWIslts.c * * * * Copyright 2007, 2008 Nuance Communciations, Inc. * * * * Licensed under the Apache License, Version 2.0 (the 'License'); * * you may not use this file except in compliance with the License. * * * * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an 'AS IS' BASIS, * * 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. * * * *---------------------------------------------------------------------------*/ #define _IN_SWI_SLTS__ #ifdef SWISLTS_USE_STATIC_API #define SWISLTS_FNEXPORT #else #ifdef WIN32 #include <windows.h> #define SWISLTS_FNEXPORT __declspec(dllexport) #else #define SWISLTS_FNEXPORT #endif #endif #include <stdlib.h> #include <string.h> #include "pmemory.h" #include "PFile.h" #include "plog.h" #include "SWIslts.h" #include "lts.h" /** * Phone map table */ typedef struct SLTS_PhoneMap_t{ LCHAR *src; LCHAR *des; } SLTS_PhoneMap; #define INF_SILENCE_OPTIONAL (const char *)"&" static const SLTS_PhoneMap g_aPhoneMap[] = { {"PS", "&"}, {"SS0", ""}, {"SS1", ""}, {"SS2", ""}, {"WS", "&"} }; static const int g_numPhones = sizeof(g_aPhoneMap) / sizeof(g_aPhoneMap[0]); #ifdef USE_STATIC_SLTS #define MAX_INPUT_LEN 255 static SLTS_Engine g_sltsEngine; static SWIsltsWrapper g_sltsWrapper; #endif #define MAX_PRON_LEN 255 #define MAX_PHONE_LEN 4 static SWIsltsResult GetPhoneStr(SLTS_Engine *pEng, char *apszPhones[], int num_phones, char *pszPhoneStr, size_t *len); SWISLTS_FNEXPORT SWIsltsResult SWIsltsGetWrapper(SWIsltsWrapper **ppLtsWrap) { if (ppLtsWrap != NULL) { #ifdef USE_STATIC_SLTS *ppLtsWrap = &g_sltsWrapper; #else *ppLtsWrap = MALLOC(sizeof(SWIsltsWrapper), MTAG); if (*ppLtsWrap == NULL) { return SWIsltsErrAllocResource; } #endif (*ppLtsWrap)->init = SWIsltsInit; (*ppLtsWrap)->term = SWIsltsTerm; (*ppLtsWrap)->open = SWIsltsOpen; (*ppLtsWrap)->close = SWIsltsClose; (*ppLtsWrap)->textToPhone = SWIsltsTextToPhone; } return SWIsltsSuccess; } SWISLTS_FNEXPORT SWIsltsResult SWIsltsReleaseWrapper(SWIsltsWrapper *pLtsWrap) { #ifndef USE_STATIC_SLTS if (pLtsWrap != NULL) { FREE(pLtsWrap); pLtsWrap = NULL; } #endif return SWIsltsSuccess; } /* External Core SLTS API implementation */ SWISLTS_FNEXPORT SWIsltsResult SWIsltsInit() { return SWIsltsSuccess; } SWISLTS_FNEXPORT SWIsltsResult SWIsltsTerm() { return SWIsltsSuccess; } /* create a new instance of SLTS */ SWISLTS_FNEXPORT SWIsltsResult SWIsltsOpen(SWIsltsHand *phLts, const char *data_filename) { SLTS_Engine * pEng; SWIsltsResult nRes = SWIsltsSuccess; if ((phLts == NULL) #ifndef USE_STATIC_SLTS || (data_filename == NULL) #endif ) { return SWIsltsInvalidParam; } #ifdef USE_STATIC_SLTS pEng = &g_sltsEngine; #else pEng = CALLOC(1, sizeof(SLTS_Engine), MTAG); if (pEng == NULL) { return SWIsltsErrAllocResource; } #endif /* initialize */ nRes = create_lts((char *)data_filename, &pEng->m_hLts); if (nRes != SWIsltsSuccess) { PLogError(L("create_lts with the model file (%s) fails with return code %d\n"), (char *)data_filename, nRes); goto CLEAN_UP; } *phLts = (SWIsltsHand)pEng; return SWIsltsSuccess; CLEAN_UP: if (*phLts != NULL) { SWIsltsClose(*phLts); } return nRes; } /* deletes given instance of SLTS */ SWISLTS_FNEXPORT SWIsltsResult SWIsltsClose(SWIsltsHand hLts) { SLTS_Engine *pEng = (SLTS_Engine *)hLts; if (pEng == NULL) { return SWIsltsInvalidParam; } /* clean up internal buffers and slts structure */ if (pEng->m_hLts) { free_lts(pEng->m_hLts); } pEng->m_hLts = NULL; #ifndef USE_STATIC_SLTS FREE(pEng); #endif pEng = NULL; return SWIsltsSuccess; } /* send phones to internal buffer */ SWISLTS_FNEXPORT SWIsltsResult SWIsltsTextToPhone(SWIsltsHand hLts, const char *text, char *output_phone_string[], int *output_phone_len, int max_phone_len) { int i; SWIsltsResult nRes = SWIsltsSuccess; #ifdef USE_STATIC_SLTS char new_text[MAX_INPUT_LEN]; #else char *new_text; #endif SLTS_Engine *pEng; if (hLts == NULL) { return SWIsltsInvalidParam; } if (text == NULL) { return SWIsltsInvalidParam; } /* check that the output phone string param is allocated */ for(i=0; i<max_phone_len; i++){ if(output_phone_string[i] == NULL) return SWIsltsInvalidParam; } pEng = (SLTS_Engine *)hLts; /* get rid newlines, tabs, and spaces, if any */ #ifdef USE_STATIC_SLTS if((strlen(text)+1) > MAX_INPUT_LEN){ return SWIsltsMaxInputExceeded; } #else new_text = MALLOC((strlen(text)+1)*sizeof(char), MTAG); if (new_text == NULL) { PLogError(L("SWISLTS_OUT_OF_MEMORY")); return SWIsltsErrAllocResource; } #endif strcpy(new_text, text); i = strlen(new_text)-1; while(new_text[i] == '\n' || new_text[i] == ' ' || new_text[i] == '\t') i--; new_text[i+1] = '\0'; /* now check if the input string is empty */ if(strlen(new_text) == 0){ *output_phone_len = 0; nRes = SWIsltsEmptyPhoneString; goto CLEAN_UP; } *output_phone_len = max_phone_len; nRes = run_lts(pEng->m_hLts, pEng->m_hDict, new_text, output_phone_string, output_phone_len); if (nRes != SWIsltsSuccess) { goto CLEAN_UP; } #ifndef USE_STATIC_SLTS if(new_text){ FREE(new_text); } new_text = NULL; #endif return SWIsltsSuccess; CLEAN_UP: #ifndef USE_STATIC_SLTS if(new_text){ FREE(new_text); } new_text = NULL; #endif return nRes; } SWISLTS_FNEXPORT SWIsltsResult SWIsltsG2PGetWordTranscriptions(SWIsltsHand hLts, const char *text, SWIsltsTranscription **ppTranscriptions, int *pnNbrOfTranscriptions) { SWIsltsResult nRes = SWIsltsSuccess; char PHONE_STRING[MAX_PRON_LEN][MAX_PHONE_LEN]; char * phone_string[MAX_PRON_LEN]; SLTS_Engine * pEng = (SLTS_Engine *)hLts; int i; int num_phones = 0; SWIsltsTranscription * pTranscription = NULL; int nNbrOfTranscriptions = 0; int * pnNbrOfTranscriptionsToSave = NULL; LCHAR * pBlock = NULL; for( i = 0; i < MAX_PRON_LEN; i++ ) { phone_string[i] = PHONE_STRING[i]; } nRes = SWIsltsTextToPhone(hLts, text, phone_string, &num_phones, MAX_PRON_LEN); if( nRes != SWIsltsSuccess ) { PLogError(L("SWIsltsTextToPhone( ) fails with return code %d\n"), nRes); goto CLEAN_UP; } #if DEBUG pfprintf(PSTDOUT,"number of phones: %d\n ", num_phones); for( i = 0; i < num_phones; i++ ) { pfprintf(PSTDOUT,"%s ", phone_string[i]); } pfprintf(PSTDOUT,"\n "); #endif /* only one transcription available from seti */ nNbrOfTranscriptions = 1; pBlock = (LCHAR *)CALLOC(sizeof(int) + nNbrOfTranscriptions * sizeof(SWIsltsTranscription), sizeof(LCHAR), MTAG); if (pBlock == NULL) { PLogError(L("SWISLTS_OUT_OF_MEMORY")); nRes = SWIsltsErrAllocResource; goto CLEAN_UP; } pnNbrOfTranscriptionsToSave = (int *)pBlock; pTranscription = (SWIsltsTranscription *)(pBlock + sizeof(int)); *ppTranscriptions = pTranscription; *pnNbrOfTranscriptions = *pnNbrOfTranscriptionsToSave = nNbrOfTranscriptions; /* extra +1 for double-null at the end */ pTranscription->pBuffer = MALLOC(MAX_PHONE_LEN * (num_phones + 1+1), MTAG); if( pTranscription->pBuffer == NULL ) { PLogError(L("SWISLTS_OUT_OF_MEMORY")); nRes = SWIsltsErrAllocResource; goto CLEAN_UP; } nRes = GetPhoneStr(pEng, phone_string, num_phones, (char *)pTranscription->pBuffer, &(pTranscription->nSizeOfBuffer)); if( nRes != SWIsltsSuccess ) { PLogError(L("SWIsltsInternalErr: GetPhoneStr( ) fails with return code %d\n"), nRes); goto CLEAN_UP; } return SWIsltsSuccess; CLEAN_UP: *ppTranscriptions = NULL; *pnNbrOfTranscriptions = 0; for( i = 0; i < nNbrOfTranscriptions; i++ ) { if(pTranscription[i].pBuffer) { FREE(pTranscription[i].pBuffer); } } FREE(pTranscription); return nRes; } SWISLTS_FNEXPORT SWIsltsResult SWIsltsG2PFreeWordTranscriptions(SWIsltsHand hLts, SWIsltsTranscription *pTranscriptions) { SWIsltsResult nRes = SWIsltsSuccess; int nNbrOfTranscriptions; int i; LCHAR * pBuffer = NULL; if( pTranscriptions == NULL ) { return SWIsltsInvalidParam; } pBuffer = ((LCHAR *)pTranscriptions - sizeof(int)); nNbrOfTranscriptions = (int)*pBuffer; for( i = 0; i < nNbrOfTranscriptions; i++ ) { if( pTranscriptions[i].pBuffer ) { FREE(pTranscriptions[i].pBuffer); } } FREE(pBuffer); return nRes; } static SWIsltsResult GetPhoneStr(SLTS_Engine *pEng, char *apszPhones[], int num_phones, char *pszPhoneStr, size_t *len) { int i, j; int nFound; SWIsltsResult nRes = SWIsltsSuccess; const char * pszLastPhone = NULL; *pszPhoneStr = '\0'; for( i = 0; i < num_phones; i++ ) { nFound = 0; for ( j = 0; j < g_numPhones && nFound == 0; j++ ) { if( strcmp(apszPhones[i], g_aPhoneMap[j].src) == 0 ) { nFound = 1; if( strcmp(g_aPhoneMap[j].des, INF_SILENCE_OPTIONAL) == 0 ) { if( *pszPhoneStr != '\0' && strcmp(pszLastPhone, INF_SILENCE_OPTIONAL) != 0 ) { strcat(pszPhoneStr, g_aPhoneMap[j].des); } } else if( g_aPhoneMap[j].des != '\0' ) { strcat(pszPhoneStr, g_aPhoneMap[j].des); } pszLastPhone = g_aPhoneMap[j].des; } } if( nFound == 0 ) { strcat(pszPhoneStr, apszPhones[i]); pszLastPhone = apszPhones[i]; } } *len = strlen(pszPhoneStr) + 1; // add the double-null per SREC/Vocon convention pszPhoneStr[ *len] = 0; return nRes; }