3 * Copyright 2012 Samsung Electronics Co., Ltd
\r
5 * Licensed under the Flora License, Version 1.0 (the License);
\r
6 * you may not use this file except in compliance with the License.
\r
7 * You may obtain a copy of the License at
\r
9 * http://floralicense.org/license/
\r
11 * Unless required by applicable law or agreed to in writing, software
\r
12 * distributed under the License is distributed on an AS IS BASIS,
\r
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
14 * See the License for the specific language governing permissions and
\r
15 * limitations under the License.
\r
18 #include "SMTApis.h"
\r
20 #include "_SlpSmtApis.h"
\r
25 #include <pthread.h>
\r
30 #define PCM_BUFFER_SIZE 640000
\r
32 // Not supported yet {
\r
33 #define TTSPE_LANG_CANTONESE "zh_HK"
\r
34 #define TTSPE_LANG_TAIWAN "zh_TW"
\r
35 #define TTSPE_LANG_RUSSIAN "ru_RU"
\r
36 #define TTSPE_LANG_JAPANESE "ja_JP"
\r
37 #define TTSPE_LANG_NETHERLANDS "nl_NL"
\r
38 #define TTSPE_LANG_PORTUGUESE "pt_PT"
\r
39 #define TTSPE_LANG_GREEK "el_GR"
\r
40 #define TTSPE_LANG_TURKEY "tr_TR"
\r
41 // Not supported yet }
\r
52 typedef struct __TypeVoiceInfo _TypeVoiceInfo;
\r
53 struct __TypeVoiceInfo
\r
55 char const * const pszLanguage;
\r
56 unsigned int const sszLanguage;
\r
57 ttsp_voice_type_e const eVoiceType;
\r
62 static char const _pszKorean [] = "ko_KR";
\r
63 static char const _pszUSEnglish [] = "en_US";
\r
64 static char const _pszChinese [] = "zh_CN";
\r
67 static char const _pszUKEnglish [] = "en_GB";
\r
68 static char const _pszGerman [] = "de_DE";
\r
69 static char const _pszSpanish [] = "es_ES";
\r
70 static char const _pszFrench [] = "fr_FR";
\r
71 static char const _pszItalian [] = "it_IT";
\r
73 static unsigned int const _sszKorean = sizeof(_pszKorean);
\r
74 static unsigned int const _sszUSEnglish = sizeof(_pszUSEnglish);
\r
75 static unsigned int const _sszChinese = sizeof(_pszChinese);
\r
76 static unsigned int const _sszUKEnglish = sizeof(_pszUKEnglish);
\r
77 static unsigned int const _sszGerman = sizeof(_pszGerman);
\r
78 static unsigned int const _sszSpanish = sizeof(_pszSpanish);
\r
79 static unsigned int const _sszFrench = sizeof(_pszFrench);
\r
80 static unsigned int const _sszItalian = sizeof(_pszItalian);
\r
83 static const _TypeVoiceInfo _pVoiceInfos[] =
\r
85 { _pszKorean , _sszKorean , TTSP_VOICE_TYPE_FEMALE },
\r
86 { _pszUSEnglish , _sszUSEnglish , TTSP_VOICE_TYPE_FEMALE },
\r
87 { _pszChinese , _sszChinese , TTSP_VOICE_TYPE_FEMALE },
\r
89 { _pszUKEnglish , _sszUKEnglish , TTSP_VOICE_TYPE_FEMALE },
\r
90 { _pszGerman , _sszGerman , TTSP_VOICE_TYPE_FEMALE },
\r
91 { _pszSpanish , _sszSpanish , TTSP_VOICE_TYPE_FEMALE },
\r
92 { _pszFrench , _sszFrench , TTSP_VOICE_TYPE_FEMALE },
\r
93 { _pszItalian , _sszItalian , TTSP_VOICE_TYPE_FEMALE },
\r
96 #define _nVoiceInfos (sizeof(_pVoiceInfos) / sizeof(_pVoiceInfos[0]))
\r
98 // index of VoiceInfos
\r
99 #define VOICE_INDEX_KOREAN_WOMAN 0
\r
100 #define VOICE_INDEX_USENGLISH_WOMAN 1
\r
101 #define VOICE_INDEX_CHINESE_WOMAN 2
\r
102 #define VOICE_INDEX_UKENGLISH_WOMAN 3
\r
103 #define VOICE_INDEX_GERMAN_WOMAN 4
\r
104 #define VOICE_INDEX_SPANISH_WOMAN 5
\r
105 #define VOICE_INDEX_FRENCH_WOMAN 6
\r
106 #define VOICE_INDEX_ITALIAN_WOMAN 7
\r
111 typedef struct _TypeThreadQueueNode TypeThreadQueueNode;
\r
112 struct _TypeThreadQueueNode
\r
115 char * pszTextUtf8;
\r
117 TypeThreadQueueNode * pNext;
\r
120 static struct _global
\r
122 ttspe_result_cb pfnCallback;
\r
123 ttsp_speed_e eSpeechSpeed;
\r
126 bool bSentenceDone;
\r
131 pthread_mutex_t ThreadLock;
\r
132 pthread_mutex_t MainThreadFinalizeLock;
\r
133 TypeThreadQueueNode* ThreadQueue_pHead;
\r
134 TypeThreadQueueNode* ThreadQueue_pTail;
\r
138 NULL , // pfnCallback
\r
140 TTSP_SPEED_NORMAL , // eSpeechSpeed
\r
141 -1 , // iVoiceInfo, initial value means INVALID INDEX
\r
143 true , // bSentenceDone
\r
147 PTHREAD_MUTEX_INITIALIZER, // ThreadLock
\r
148 PTHREAD_MUTEX_INITIALIZER, // MainThreadFinalizeLock
\r
149 NULL , // ThreadQueue_pHead
\r
150 NULL , // ThreadQueue_pTail
\r
153 static void _PushThreadData (int const iVoiceInfo, char const * pszTextUtf8, void* pUserParam);
\r
154 static TypeThreadQueueNode* _PopThreadData (void);
\r
155 static bool _bEmptyThreadData(void);
\r
156 static void _CleanThreadData(void);
\r
157 static void * _Synthesize (void* NotUsed); // Thread routine
\r
160 static int _ChangeVoice (int const iVoiceInfo);
\r
161 static void _SetSpeechSpeed (void);
\r
162 static void _CallBack (ttsp_result_event_e eEvent, unsigned int const nPCMs, void * pPCMs, void* pUserParam);
\r
163 static int _Synthesize_SamsungTTS(char const * const pszTextUtf8, void* pUserParam, int const FramePeriod);
\r
168 char const * SLPSMT_GetPszKorean (void) { return _pszKorean ; }
\r
169 char const * SLPSMT_GetPszUSEnglish (void) { return _pszUSEnglish ; }
\r
170 char const * SLPSMT_GetPszChinese (void) { return _pszChinese ; }
\r
171 char const * SLPSMT_GetPszUKEnglish (void) { return _pszUKEnglish ; }
\r
172 char const * SLPSMT_GetPszGerman (void) { return _pszGerman ; }
\r
173 char const * SLPSMT_GetPszSpanish (void) { return _pszSpanish ; }
\r
174 char const * SLPSMT_GetPszFrench (void) { return _pszFrench ; }
\r
175 char const * SLPSMT_GetPszItalian (void) { return _pszItalian ; }
\r
177 int SLPSMT_GetWorkingThreadId(void) { return _g.ThreadId; }
\r
182 int SLPSMT_StopSynthesis(void)
\r
184 printf(">> SLPSMT_StopSynthesis()\n");
\r
186 _g.bSentenceDone = true;
\r
187 _CleanThreadData();
\r
188 return TTSP_ERROR_NONE;
\r
191 int SLPSMT_SynthesizeText(int const iVoiceInfo, char const * pszTextUtf8, void * const pUserParam)
\r
193 if (! _g.pfnCallback) { return TTSP_ERROR_INVALID_STATE; }
\r
194 if (! pszTextUtf8 || ! *pszTextUtf8) { return TTSP_ERROR_INVALID_PARAMETER; }
\r
196 printf(">> SLPSMT_SynthesizeText()\n");
\r
197 printf(">>>> iVoiceInfo : %d\n", iVoiceInfo );
\r
198 printf(">>>> pszTextUtf8 : %s\n", pszTextUtf8);
\r
202 _PushThreadData(iVoiceInfo, pszTextUtf8, pUserParam);
\r
204 if (_g.ThreadId < 0)
\r
206 _g.ThreadId = pthread_create(& _g.Thread, NULL, _Synthesize, pUserParam);
\r
207 if (_g.ThreadId < 0)
\r
209 printf(">>> Fail to create thread\n");
\r
210 return TTSP_ERROR_OPERATION_FAILED;
\r
213 return TTSP_ERROR_NONE;
\r
222 ttspe_voice_info_s * _gpVoiceInfos = NULL;
\r
224 int SLPSMT_SetVoiceList(ttspe_voice_list_s * p)
\r
226 if (! _gpVoiceInfos)
\r
230 _gpVoiceInfos = (ttspe_voice_info_s*) calloc(_nVoiceInfos, sizeof(ttspe_voice_info_s));
\r
231 if (! _gpVoiceInfos) { return TTSP_ERROR_OUT_OF_MEMORY; }
\r
233 for (i=0 ; i<_nVoiceInfos ; i++)
\r
235 _gpVoiceInfos[i].lang = strdup(_pVoiceInfos[i].pszLanguage);
\r
236 _gpVoiceInfos[i].vctype = _pVoiceInfos[i].eVoiceType ;
\r
239 p->voice_info = _gpVoiceInfos;
\r
240 p->size = _nVoiceInfos;
\r
241 return TTSP_ERROR_NONE;
\r
244 void SLPSMT_SetSpeechSpeed(ttsp_speed_e const eSpeechSpeed)
\r
246 switch (eSpeechSpeed)
\r
248 case TTSP_SPEED_VERY_FAST :
\r
249 case TTSP_SPEED_FAST :
\r
250 case TTSP_SPEED_SLOW :
\r
251 case TTSP_SPEED_VERY_SLOW :
\r
252 case TTSP_SPEED_NORMAL : _g.eSpeechSpeed = eSpeechSpeed; break;
\r
253 default : _g.eSpeechSpeed = TTSP_SPEED_NORMAL; break;
\r
257 int SLPSMT_GetiVoiceInfo(char* const pszLanguage, ttsp_voice_type_e const eVoiceType)
\r
260 for (i=0 ; i<_nVoiceInfos ; i++)
\r
262 if ( eVoiceType == _pVoiceInfos[i].eVoiceType
\r
263 && ! strcmp(pszLanguage , _pVoiceInfos[i].pszLanguage)
\r
272 int SLPSMT_Initialize(ttspe_result_cb pfnCallBack)
\r
276 _g.pfnCallback = pfnCallBack;
\r
277 return TTSP_ERROR_NONE;
\r
279 return TTSP_ERROR_INVALID_STATE;
\r
282 int SLPSMT_Finalize(void)
\r
284 printf(">>>> SLPSMT_Finalize() called.\n");
\r
287 _CleanThreadData();
\r
289 pthread_mutex_lock (& _g.MainThreadFinalizeLock); // <---- lock
\r
291 pthread_mutex_unlock(& _g.MainThreadFinalizeLock); // <---- unlock
\r
296 for (i=0 ; i<_nVoiceInfos ; i++)
\r
298 if (_gpVoiceInfos[i].lang) { free(_gpVoiceInfos[i].lang); }
\r
300 free(_gpVoiceInfos);
\r
303 _g.pfnCallback = NULL;
\r
304 _g.eSpeechSpeed = TTSP_SPEED_NORMAL;
\r
305 _g.iVoiceInfo = -1;
\r
308 printf(">>>> SLPSMT_Finalize() returns.\n");
\r
309 return TTSP_ERROR_NONE;
\r
315 static void _PushThreadData(int const iVoiceInfo, char const * pszTextUtf8, void* pUserParam)
\r
316 // iVoiceInfo should be correct.
\r
317 // pszTextUtf8 should not be NULL.
\r
320 char * pszDuplicatedTextUtf8;
\r
322 pthread_mutex_lock (& _g.ThreadLock); // <---- lock
\r
324 pszDuplicatedTextUtf8 = strdup(pszTextUtf8);
\r
325 if (pszDuplicatedTextUtf8)
\r
327 TypeThreadQueueNode* p = (TypeThreadQueueNode*) calloc (1, sizeof(TypeThreadQueueNode));
\r
330 p->iVoiceInfo = iVoiceInfo;
\r
331 p->pszTextUtf8 = pszDuplicatedTextUtf8;
\r
332 p->pUserParam = pUserParam;
\r
333 if (! _g.ThreadQueue_pHead) { _g.ThreadQueue_pHead = p; }
\r
334 if ( _g.ThreadQueue_pTail) { _g.ThreadQueue_pTail->pNext = p; }
\r
335 _g.ThreadQueue_pTail = p;
\r
339 if (! b) { free(pszDuplicatedTextUtf8); }
\r
342 if (! b) { printf(">>>__PushThreadData, out of memory\n"); }
\r
344 pthread_mutex_unlock(& _g.ThreadLock); // <---- unlock
\r
347 static TypeThreadQueueNode* _PopThreadData(void)
\r
349 TypeThreadQueueNode* p;
\r
351 pthread_mutex_lock (& _g.ThreadLock); // <---- lock
\r
353 p = _g.ThreadQueue_pHead;
\r
354 if (_g.ThreadQueue_pHead) { _g.ThreadQueue_pHead = _g.ThreadQueue_pHead->pNext; }
\r
355 if (p == _g.ThreadQueue_pTail) { _g.ThreadQueue_pTail = NULL; }
\r
357 pthread_mutex_unlock(& _g.ThreadLock); // <---- unlock
\r
362 static bool _bEmptyThreadData(void)
\r
365 pthread_mutex_lock (& _g.ThreadLock); // <---- lock
\r
367 if (_g.ThreadQueue_pHead) { b = false; }
\r
369 pthread_mutex_unlock(& _g.ThreadLock); // <---- unlock
\r
374 static void _CleanThreadData(void)
\r
376 pthread_mutex_lock (& _g.ThreadLock); // <---- lock
\r
378 while (_g.ThreadQueue_pHead)
\r
380 TypeThreadQueueNode* const p = _g.ThreadQueue_pHead;
\r
381 _g.ThreadQueue_pHead = p->pNext;
\r
382 free(p->pszTextUtf8);
\r
385 _g.ThreadQueue_pHead = NULL;
\r
386 _g.ThreadQueue_pTail = NULL;
\r
388 pthread_mutex_unlock(& _g.ThreadLock); // <---- unlock
\r
391 static void * _Synthesize(void* NotUsed)
\r
393 unsigned int const FramePeriod = (unsigned int) SMTGetFramePeriod();
\r
394 TypeThreadQueueNode* p = _PopThreadData();
\r
396 for ( ; p ; p=_PopThreadData())
\r
398 int const iVoiceInfo = p->iVoiceInfo;
\r
399 char const * pszTextUtf8 = p->pszTextUtf8;
\r
400 void * pUserParam = p->pUserParam;
\r
402 if (_g.pfnCallback)
\r
404 int r = SMT_SUCCESS;
\r
406 printf(">>>> Thread, _Synthesize(), iVoiceInfo = %d\n", iVoiceInfo);
\r
407 printf(">>>>>> pszTextUtf8 = %s\n", pszTextUtf8);
\r
409 if (iVoiceInfo != _g.iVoiceInfo)
\r
411 r = _ChangeVoice(iVoiceInfo);
\r
412 printf(">>>>>> iVoiceInfo was changed.\n");
\r
415 if (r == SMT_SUCCESS)
\r
419 printf(">>>>>> Set speech-speed\n");
\r
421 pthread_mutex_lock (& _g.MainThreadFinalizeLock); // <---- lock
\r
423 r = _Synthesize_SamsungTTS(pszTextUtf8, pUserParam, FramePeriod);
\r
425 pthread_mutex_unlock(& _g.MainThreadFinalizeLock); // <---- unlock
\r
428 printf(">>>Thread, _Synthesize() done\n");
\r
431 free(p->pszTextUtf8);
\r
433 } // end of while loop
\r
442 // functions managing < Thread Queue >
\r
453 // functions managing < Engine Switching >
\r
458 static int _ChangeVoice(int const iVoiceInfo)
\r
461 bool bSamsungTTS = false;
\r
462 bool bSvoxTTS = false;
\r
463 char const * pszLanguage = NULL;
\r
464 char const * pszContury = NULL;
\r
466 switch (iVoiceInfo)
\r
468 case VOICE_INDEX_KOREAN_WOMAN : SMTSet_Language(eKOREAN , 1, 0); break;
\r
469 case VOICE_INDEX_USENGLISH_WOMAN : SMTSet_Language(eUSENGLISH , 1, 0); break;
\r
470 case VOICE_INDEX_CHINESE_WOMAN : SMTSet_Language(eCHINESE , 1, 0); break;
\r
472 case VOICE_INDEX_UKENGLISH_WOMAN : SMTSet_Language(eGBENGLISH , 1, 0); break;
\r
473 case VOICE_INDEX_GERMAN_WOMAN : SMTSet_Language(eGERMAN , 1, 0); break;
\r
474 case VOICE_INDEX_SPANISH_WOMAN : SMTSet_Language(eSPANISH , 1, 0); break;
\r
475 case VOICE_INDEX_FRENCH_WOMAN : SMTSet_Language(eFRENCH , 1, 0); break;
\r
476 case VOICE_INDEX_ITALIAN_WOMAN : SMTSet_Language(eITALIAN , 1, 0); break;
\r
478 default : break; // This case has already been checked.
\r
481 _g.iVoiceInfo = iVoiceInfo;
\r
484 r = SMTInitialize();
\r
486 if (r != SMT_SUCCESS) { printf(">>> _ChangeVoice() returns %d.\n", r); }
\r
491 static void _SetSpeechSpeed(void)
\r
493 switch (_g.eSpeechSpeed)
\r
495 case TTSP_SPEED_VERY_FAST : SMTSetSpeechSpeed(eSMTSpeechSpeed_VeryFast); break;
\r
496 case TTSP_SPEED_FAST : SMTSetSpeechSpeed(eSMTSpeechSpeed_Fast ); break;
\r
497 case TTSP_SPEED_SLOW : SMTSetSpeechSpeed(eSMTSpeechSpeed_Slow ); break;
\r
498 case TTSP_SPEED_VERY_SLOW : SMTSetSpeechSpeed(eSMTSpeechSpeed_VerySlow); break;
\r
499 case TTSP_SPEED_NORMAL : SMTSetSpeechSpeed(eSMTSpeechSpeed_Normal ); break;
\r
503 static void _CallBack(ttsp_result_event_e eEvent, unsigned int const nPCMs, void * pPCMs, void* pUserParam)
\r
505 unsigned int const n = nPCMs * sizeof(short);
\r
508 printf(">>> callback, pUserParam = 0x%x\n", (unsigned int) pUserParam);
\r
509 printf(">>> callback, event=");
\r
513 case TTSP_RESULT_EVENT_CONTINUE :
\r
514 if (_g.bSentenceDone)
\r
516 eEvent = TTSP_RESULT_EVENT_START;
\r
517 _g.bSentenceDone = false;
\r
521 case TTSP_RESULT_EVENT_FINISH :
\r
522 _g.bSentenceDone = true;
\r
529 static int iWave = 0;
\r
530 static char pszWave[100];
\r
532 printf("@@@ saving wave file @@@\n");
\r
533 sprintf(pszWave, "/mnt/nfs/tts/play%d.wav", iWave++);
\r
534 SMTSaveWave(pszWave, (short*) pPCMs, nPCMs * 2);
\r
540 case TTSP_RESULT_EVENT_START : printf("TTSPE_CBEVENT_SYNTH_START\n"); break;
\r
541 case TTSP_RESULT_EVENT_CONTINUE: printf("TTSPE_CBEVENT_SYNTH_CONTINUE\n"); break;
\r
542 case TTSP_RESULT_EVENT_FINISH : printf("TTSPE_CBEVENT_SYNTH_FINISH\n"); break;
\r
543 case TTSP_RESULT_EVENT_CANCEL : printf("TTSPE_CBEVENT_SYNTH_CANCEL\n"); break;
\r
544 case TTSP_RESULT_EVENT_FAIL : printf("TTSPE_CBEVENT_SYNTH_FAIL\n"); break;
\r
545 default : printf("invalid\n"); break;
\r
548 if (eEvent==TTSP_RESULT_EVENT_FINISH && ! _bEmptyThreadData())
\r
550 printf(">>> There is another input text.\n");
\r
551 printf(">>> TTSPE_CBEVENT_SYNTH_FINISH was chanage into TTSPE_CBEVENT_SYNTH_CONTINUE.\n");
\r
552 eEvent = TTSP_RESULT_EVENT_CONTINUE;
\r
555 printf(">>> data size = %d\n", n);
\r
556 printf(">> >> Here we jump into the callback function.\n");
\r
558 int const cbreturn = _g.pfnCallback(eEvent, pPCMs, n, pUserParam);
\r
559 printf(">> >> Here we return from the callback function.\n");
\r
560 printf(">> >> callback function return value = %d\n", cbreturn);
\r
561 if (-1 == cbreturn)
\r
563 printf(">>> Callback function returns TTS_CALLBACK_HALT.\n");
\r
565 _g.bSentenceDone = true;
\r
569 static int _Synthesize_SamsungTTS(char const * const pszTextUtf8, void* pUserParam, int const FramePeriod)
\r
571 static short pPcmBuffer[PCM_BUFFER_SIZE];
\r
573 int r = SMTInputText(pszTextUtf8);
\r
574 unsigned int i = 0;
\r
576 if (r != SMT_SUCCESS)
\r
578 _CleanThreadData();
\r
579 printf(">>> SMTInputText() returns %d.\n", r);
\r
583 while (r == SMT_SUCCESS)
\r
585 r = SMTSynthesize(& pPcmBuffer[i]);
\r
588 _CleanThreadData();
\r
589 _CallBack(TTSP_RESULT_EVENT_CANCEL, i, pPcmBuffer, pUserParam);
\r
596 case SMT_SYNTHESIS_FRAME_GENERATED:
\r
597 if (i + FramePeriod == PCM_BUFFER_SIZE)
\r
599 _CallBack(TTSP_RESULT_EVENT_CONTINUE, PCM_BUFFER_SIZE, pPcmBuffer, pUserParam);
\r
608 case SMT_SYNTHESIS_PAUSE_DONE :
\r
609 case SMT_SYNTHESIS_SENTENCE_DONE :
\r
613 case SMT_SYNTHESIS_ALL_DONE :
\r
614 _CallBack(TTSP_RESULT_EVENT_FINISH, i, pPcmBuffer, pUserParam);
\r
618 _CleanThreadData();
\r
620 printf(">>> SMTSynthesize() returns %d\n", r);
\r
622 _CallBack(TTSP_RESULT_EVENT_FAIL, i, pPcmBuffer, pUserParam);
\r
627 } // end of while loop
\r
635 // functions managing < Engine Switching >
\r