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 */
48typedef struct SLTS_PhoneMap_t{
49    LCHAR *src;
50    LCHAR *des;
51} SLTS_PhoneMap;
52
53#define INF_SILENCE_OPTIONAL         (const char *)"&"
54
55static const SLTS_PhoneMap g_aPhoneMap[] = {
56     {"PS", "&"},
57     {"SS0", ""},
58     {"SS1", ""},
59     {"SS2", ""},
60     {"WS", "&"}
61};
62static const int g_numPhones = sizeof(g_aPhoneMap) / sizeof(g_aPhoneMap[0]);
63
64#ifdef USE_STATIC_SLTS
65#define MAX_INPUT_LEN 255
66static SLTS_Engine g_sltsEngine;
67static SWIsltsWrapper g_sltsWrapper;
68#endif
69
70#define MAX_PRON_LEN      255
71#define MAX_PHONE_LEN     4
72
73static SWIsltsResult GetPhoneStr(SLTS_Engine *pEng, char *apszPhones[], int num_phones, char *pszPhoneStr, size_t *len);
74
75SWISLTS_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
95SWISLTS_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 */
107SWISLTS_FNEXPORT SWIsltsResult SWIsltsInit()
108{
109  return SWIsltsSuccess;
110}
111
112SWISLTS_FNEXPORT SWIsltsResult SWIsltsTerm()
113{
114  return SWIsltsSuccess;
115}
116
117/* create a new instance of SLTS */
118SWISLTS_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 */
162SWISLTS_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 */
185SWISLTS_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
268SWISLTS_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
347SWISLTS_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
372static 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