eSpeak NG is an open source speech synthesizer that supports more than hundred languages and accents.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

speak_lib.cpp 27KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  1. /***************************************************************************
  2. * Copyright (C) 2005,2006 by Jonathan Duddington *
  3. * [email protected] *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 2 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program; if not, write to the *
  17. * Free Software Foundation, Inc., *
  18. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  19. ***************************************************************************/
  20. #include "StdAfx.h"
  21. #include "stdio.h"
  22. #include "ctype.h"
  23. #include "string.h"
  24. #include "stdlib.h"
  25. #include "wchar.h"
  26. #include "locale.h"
  27. #include <assert.h>
  28. #include <time.h>
  29. #include "speech.h"
  30. #include "sys/stat.h"
  31. #ifndef PLATFORM_WINDOWS
  32. #include <unistd.h>
  33. #endif
  34. #include "speak_lib.h"
  35. #include "voice.h"
  36. #include "phoneme.h"
  37. #include "synthesize.h"
  38. #include "translate.h"
  39. #include "debug.h"
  40. #include "fifo.h"
  41. #include "event.h"
  42. #include "wave.h"
  43. unsigned char *outbuf=NULL;
  44. extern espeak_VOICE *voice_selected;
  45. espeak_EVENT *event_list=NULL;
  46. int event_list_ix=0;
  47. int n_event_list;
  48. long count_samples;
  49. void* my_audio=NULL;
  50. static unsigned int my_unique_identifier=0;
  51. static void* my_user_data=NULL;
  52. static espeak_AUDIO_OUTPUT my_mode=AUDIO_OUTPUT_SYNCHRONOUS;
  53. static int synchronous_mode = 1;
  54. t_espeak_callback* synth_callback = NULL;
  55. int (* uri_callback)(int, const char *, const char *) = NULL;
  56. char path_home[120];
  57. voice_t voicedata;
  58. voice_t *voice = &voicedata;
  59. #ifdef USE_ASYNC
  60. static int dispatch_audio(short* outbuf, int length, espeak_EVENT* event)
  61. {//======================================================================
  62. ENTER("dispatch_audio");
  63. int a_wave_can_be_played = fifo_is_command_enabled();
  64. SHOW("*** dispatch_audio > uid=%d, [write=%p (%d bytes)], sample=%d, a_wave_can_be_played = %d\n",
  65. (event) ? event->unique_identifier : 0, wave_test_get_write_buffer(), 2*length,
  66. (event) ? event->sample : 0,
  67. a_wave_can_be_played);
  68. switch(my_mode)
  69. {
  70. case AUDIO_OUTPUT_PLAYBACK:
  71. {
  72. if (outbuf && length && a_wave_can_be_played)
  73. {
  74. wave_write (my_audio, (char*)outbuf, 2*length);
  75. }
  76. while(a_wave_can_be_played) {
  77. // TBD: some event are filtered here but some insight might be given
  78. // TBD: in synthesise.cpp for avoiding to create WORDs with size=0.
  79. // TBD: For example sentence "or ALT)." returns three words
  80. // "or", "ALT" and "".
  81. // TBD: the last one has its size=0.
  82. if (event && (event->type == espeakEVENT_WORD) && (event->length==0))
  83. {
  84. break;
  85. }
  86. espeak_ERROR a_error = event_declare(event);
  87. if (a_error != EE_BUFFER_FULL)
  88. {
  89. break;
  90. }
  91. SHOW_TIME("dispatch_audio > EE_BUFFER_FULL\n");
  92. usleep(10000);
  93. a_wave_can_be_played = fifo_is_command_enabled();
  94. }
  95. }
  96. break;
  97. case AUDIO_OUTPUT_RETRIEVAL:
  98. if (synth_callback)
  99. {
  100. synth_callback(outbuf, length, event);
  101. }
  102. break;
  103. case AUDIO_OUTPUT_SYNCHRONOUS:
  104. case AUDIO_OUTPUT_SYNCH_PLAYBACK:
  105. break;
  106. }
  107. if (!a_wave_can_be_played)
  108. {
  109. SHOW_TIME("dispatch_audio > synth must be stopped!\n");
  110. }
  111. SHOW_TIME("LEAVE dispatch_audio\n");
  112. return (a_wave_can_be_played==0); // 1 = stop synthesis
  113. }
  114. static int create_events(short* outbuf, int length, espeak_EVENT* event, uint32_t the_write_pos)
  115. {//=====================================================================
  116. int finished;
  117. int i=0;
  118. // The audio data are written to the output device.
  119. // The list of events in event_list (index: event_list_ix) is read:
  120. // Each event is declared to the "event" object which stores them internally.
  121. // The event object is responsible of calling the external callback
  122. // as soon as the relevant audio sample is played.
  123. do
  124. { // for each event
  125. espeak_EVENT* event;
  126. if (event_list_ix == 0)
  127. {
  128. event = NULL;
  129. }
  130. else
  131. {
  132. event = event_list + i;
  133. SHOW("Synthesize: event->sample(%d) + %d = %d\n", event->sample, the_write_pos, event->sample + the_write_pos);
  134. event->sample += the_write_pos;
  135. }
  136. SHOW("*** Synthesize: i=%d (event_list_ix=%d), length=%d\n",i,event_list_ix,length);
  137. finished = dispatch_audio((short *)outbuf, length, event);
  138. length = 0; // the wave data are played once.
  139. i++;
  140. } while((i < event_list_ix) && !finished);
  141. return finished;
  142. }
  143. int sync_espeak_terminated_msg( uint unique_identifier, void* user_data)
  144. {//=====================================================================
  145. ENTER("sync_espeak_terminated_msg");
  146. int finished=0;
  147. memset(event_list, 0, 2*sizeof(espeak_EVENT));
  148. event_list[0].type = espeakEVENT_MSG_TERMINATED;
  149. event_list[0].unique_identifier = unique_identifier;
  150. event_list[0].user_data = user_data;
  151. event_list[1].type = espeakEVENT_LIST_TERMINATED;
  152. if (my_mode==AUDIO_OUTPUT_PLAYBACK)
  153. {
  154. while(1)
  155. {
  156. espeak_ERROR a_error = event_declare(event_list);
  157. if (a_error != EE_BUFFER_FULL)
  158. {
  159. break;
  160. }
  161. SHOW_TIME("sync_espeak_terminated_msg > EE_BUFFER_FULL\n");
  162. usleep(10000);
  163. }
  164. }
  165. else
  166. {
  167. if (synth_callback)
  168. {
  169. finished=synth_callback(NULL,0,event_list);
  170. }
  171. }
  172. return finished;
  173. }
  174. #endif
  175. static void select_output(espeak_AUDIO_OUTPUT output_type)
  176. {//=======================================================
  177. my_mode = output_type;
  178. my_audio = NULL;
  179. synchronous_mode = 1;
  180. option_waveout = 1; // inhibit portaudio callback from wavegen.cpp
  181. switch(my_mode)
  182. {
  183. case AUDIO_OUTPUT_PLAYBACK:
  184. synchronous_mode = 0;
  185. #ifdef USE_ASYNC
  186. wave_init();
  187. wave_set_callback_is_output_enabled( fifo_is_command_enabled);
  188. my_audio = wave_open("alsa");
  189. event_init();
  190. #endif
  191. break;
  192. case AUDIO_OUTPUT_RETRIEVAL:
  193. synchronous_mode = 0;
  194. break;
  195. case AUDIO_OUTPUT_SYNCHRONOUS:
  196. break;
  197. case AUDIO_OUTPUT_SYNCH_PLAYBACK:
  198. option_waveout = 0;
  199. WavegenInitSound();
  200. break;
  201. }
  202. } // end of select_output
  203. int GetFileLength(const char *filename)
  204. {//====================================
  205. struct stat statbuf;
  206. if(stat(filename,&statbuf) != 0)
  207. return(0);
  208. if((statbuf.st_mode & S_IFMT) == S_IFDIR)
  209. // if(S_ISDIR(statbuf.st_mode))
  210. return(-2); // a directory
  211. return(statbuf.st_size);
  212. } // end of GetFileLength
  213. char *Alloc(int size)
  214. {//==================
  215. char *p;
  216. if((p = (char *)malloc(size)) == NULL)
  217. fprintf(stderr,"Can't allocate memory\n");
  218. return(p);
  219. }
  220. void Free(void *ptr)
  221. {//=================
  222. if(ptr != NULL)
  223. free(ptr);
  224. }
  225. static void init_path(const char *path)
  226. {//====================================
  227. #ifdef PLATFORM_WINDOWS
  228. HKEY RegKey;
  229. unsigned long size;
  230. unsigned long var_type;
  231. char *env;
  232. unsigned char buf[100];
  233. if(path != NULL)
  234. {
  235. sprintf(path_home,"%s/espeak-data",path);
  236. return;
  237. }
  238. if((env = getenv("espeak-path")) != NULL)
  239. {
  240. sprintf(path_home,"%s/espeak-data",env);
  241. if(GetFileLength(path_home) == -2)
  242. return; // an espeak-data directory exists
  243. }
  244. buf[0] = 0;
  245. RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Speech\\Voices\\Tokens\\eSpeak", 0, KEY_READ, &RegKey);
  246. size = sizeof(buf);
  247. var_type = REG_SZ;
  248. RegQueryValueEx(RegKey, "path", 0, &var_type, buf, &size);
  249. sprintf(path_home,"%s\\espeak-data",buf);
  250. #else
  251. char *env;
  252. if(path != NULL)
  253. {
  254. snprintf(path_home,sizeof(path_home),"%s/espeak-data",path);
  255. return;
  256. }
  257. if((env = getenv("ESPEAK-DATA-PATH")) != NULL)
  258. {
  259. snprintf(path_home,sizeof(path_home),"%s/espeak-data",env);
  260. if(GetFileLength(path_home) == -2)
  261. return; // an espeak-data directory exists
  262. }
  263. snprintf(path_home,sizeof(path_home),"%s/espeak-data",getenv("HOME"));
  264. if(access(path_home,R_OK) != 0)
  265. {
  266. strcpy(path_home,PATH_ESPEAK_DATA);
  267. }
  268. #endif
  269. }
  270. static int initialise(void)
  271. {//========================
  272. int param;
  273. int result;
  274. #ifndef __WIN32__
  275. LoadConfig(); // causes problem on Windows, don't know why
  276. #endif
  277. WavegenInit(22050,0); // 22050
  278. if((result = LoadPhData()) != 1)
  279. {
  280. if(result == -1)
  281. fprintf(stderr,"Failed to load espeak-data\n");
  282. else
  283. fprintf(stderr,"Wrong version of espeak-data 0x%x (expects 0x%x)\n",result,version_phdata);
  284. }
  285. voice_selected = NULL;
  286. SynthesizeInit();
  287. InitNamedata();
  288. for(param=0; param<N_SPEECH_PARAM; param++)
  289. param_stack[0].parameter[param] = param_defaults[param];
  290. return(0);
  291. }
  292. static espeak_ERROR Synthesize(unsigned int unique_identifier, const void *text, int flags)
  293. {//========================================================================================
  294. // Fill the buffer with output sound
  295. ENTER("Synthesize");
  296. int length;
  297. int finished = 0;
  298. int count_buffers = 0;
  299. uint32_t a_write_pos=0;
  300. #ifdef DEBUG_ENABLED
  301. if (text)
  302. {
  303. SHOW("Synthesize > uid=%d, flags=%d, >>>text=%s<<<\n", unique_identifier, flags, text);
  304. }
  305. #endif
  306. if((outbuf==NULL) || (event_list==NULL))
  307. return(EE_INTERNAL_ERROR); // espeak_Initialize() has not been called
  308. option_multibyte = flags & 7;
  309. option_ssml = flags & espeakSSML;
  310. option_phoneme_input = flags & espeakPHONEMES;
  311. option_endpause = flags & espeakENDPAUSE;
  312. count_samples = 0;
  313. #ifdef USE_ASYNC
  314. if(my_mode == AUDIO_OUTPUT_PLAYBACK)
  315. {
  316. a_write_pos = wave_get_write_position(my_audio);
  317. }
  318. #endif
  319. if(translator == NULL)
  320. {
  321. SetVoiceByName("default");
  322. }
  323. SpeakNextClause(NULL,text,0);
  324. if(my_mode == AUDIO_OUTPUT_SYNCH_PLAYBACK)
  325. {
  326. for(;;)
  327. {
  328. #ifdef PLATFORM_WINDOWS
  329. Sleep(300); // 0.3s
  330. #else
  331. #ifdef USE_NANOSLEEP
  332. struct timespec period;
  333. struct timespec remaining;
  334. period.tv_sec = 0;
  335. period.tv_nsec = 300000000; // 0.3 sec
  336. nanosleep(&period,&remaining);
  337. #else
  338. sleep(1);
  339. #endif
  340. #endif
  341. if(SynthOnTimer() != 0)
  342. break;
  343. }
  344. return(EE_OK);
  345. }
  346. for(;;)
  347. {
  348. SHOW("Synthesize > %s\n","for (next)");
  349. out_ptr = outbuf;
  350. out_end = &outbuf[outbuf_size];
  351. event_list_ix = 0;
  352. WavegenFill(0);
  353. length = (out_ptr - outbuf)/2;
  354. count_samples += length;
  355. event_list[event_list_ix].type = espeakEVENT_LIST_TERMINATED; // indicates end of event list
  356. count_buffers++;
  357. if (my_mode==AUDIO_OUTPUT_PLAYBACK)
  358. {
  359. #ifdef USE_ASYNC
  360. finished = create_events((short *)outbuf, length, event_list, a_write_pos);
  361. length = 0; // the wave data are played once.
  362. #endif
  363. }
  364. else
  365. {
  366. finished = synth_callback((short *)outbuf, length, event_list);
  367. }
  368. if(finished)
  369. {
  370. SpeakNextClause(NULL,0,2); // stop
  371. break;
  372. }
  373. if(Generate(phoneme_list,&n_phoneme_list,1)==0)
  374. {
  375. if(WcmdqUsed() == 0)
  376. {
  377. // don't process the next clause until the previous clause has finished generating speech.
  378. // This ensures that <audio> tag (which causes end-of-clause) is at a sound buffer boundary
  379. event_list[0].type = espeakEVENT_LIST_TERMINATED;
  380. if(SpeakNextClause(NULL,NULL,1)==0)
  381. {
  382. #ifdef USE_ASYNC
  383. if (my_mode==AUDIO_OUTPUT_PLAYBACK)
  384. {
  385. dispatch_audio(NULL, 0, NULL); // TBD: test case
  386. }
  387. else
  388. {
  389. synth_callback(NULL, 0, event_list); // NULL buffer ptr indicates end of data
  390. }
  391. #else
  392. synth_callback(NULL, 0, event_list); // NULL buffer ptr indicates end of data
  393. #endif
  394. break;
  395. }
  396. }
  397. }
  398. }
  399. return(EE_OK);
  400. } // end of Synthesize
  401. #ifdef DEBUG_ENABLED
  402. static const char* label[] = {
  403. "END_OF_EVENT_LIST",
  404. "WORD",
  405. "SENTENCE",
  406. "MARK",
  407. "PLAY",
  408. "END"};
  409. #endif
  410. void MarkerEvent(int type, unsigned int char_position, int value, unsigned char *out_ptr)
  411. {//======================================================================================
  412. // type: 1=word, 2=sentence, 3=named mark, 4=play audio, 5=end
  413. ENTER("MarkerEvent");
  414. espeak_EVENT *ep;
  415. double time;
  416. if((event_list == NULL) || (event_list_ix >= (n_event_list-2)))
  417. return;
  418. ep = &event_list[event_list_ix++];
  419. ep->type = (espeak_EVENT_TYPE)type;
  420. ep->unique_identifier = my_unique_identifier;
  421. ep->user_data = my_user_data;
  422. ep->text_position = char_position & 0xffff;
  423. ep->length = char_position >> 24;
  424. time = (double(count_samples + (out_ptr - out_start)/2)*1000.0)/samplerate;
  425. ep->audio_position = int(time);
  426. ep->sample = (count_samples + (out_ptr - out_start)/2);
  427. SHOW("MarkerEvent > count_samples=%d, out_ptr=%x, out_start=0x%x\n",count_samples, out_ptr, out_start);
  428. SHOW("*** MarkerEvent > type=%s, uid=%d, text_pos=%d, length=%d, audio_position=%d, sample=%d\n",
  429. label[ep->type], ep->unique_identifier, ep->text_position, ep->length,
  430. ep->audio_position, ep->sample);
  431. if((type == espeakEVENT_MARK) || (type == espeakEVENT_PLAY))
  432. ep->id.name = &namedata[value];
  433. else
  434. ep->id.number = value;
  435. } // end of MarkerEvent
  436. espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, size_t size,
  437. unsigned int position, espeak_POSITION_TYPE position_type,
  438. unsigned int end_position, unsigned int flags, void* user_data)
  439. {//===========================================================================
  440. ENTER("sync_espeak_Synth");
  441. SHOW("sync_espeak_Synth > position=%d, position_type=%d, end_position=%d, flags=%d, user_data=0x%x, text=%s\n", position, position_type, end_position, flags, user_data, text);
  442. espeak_ERROR aStatus;
  443. InitText(flags);
  444. my_unique_identifier = unique_identifier;
  445. my_user_data = user_data;
  446. switch(position_type)
  447. {
  448. case POS_CHARACTER:
  449. skip_characters = position;
  450. break;
  451. case POS_WORD:
  452. skip_words = position;
  453. break;
  454. case POS_SENTENCE:
  455. skip_sentences = position;
  456. break;
  457. }
  458. if(skip_characters || skip_words || skip_sentences)
  459. skipping_text = 1;
  460. end_character_position = end_position;
  461. aStatus = Synthesize(unique_identifier, text, flags);
  462. #ifdef USE_ASYNC
  463. wave_flush(my_audio);
  464. #endif
  465. SHOW_TIME("LEAVE sync_espeak_Synth");
  466. return aStatus;
  467. } // end of sync_espeak_Synth
  468. espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void *text, size_t size,
  469. const char *index_mark, unsigned int end_position,
  470. unsigned int flags, void* user_data)
  471. {//=========================================================================
  472. espeak_ERROR aStatus;
  473. InitText(flags);
  474. my_unique_identifier = unique_identifier;
  475. my_user_data = user_data;
  476. if(index_mark != NULL)
  477. {
  478. strncpy0(skip_marker, index_mark, sizeof(skip_marker));
  479. skipping_text = 1;
  480. }
  481. end_character_position = end_position;
  482. aStatus = Synthesize(unique_identifier, text, flags | espeakSSML);
  483. SHOW_TIME("LEAVE sync_espeak_Synth_Mark");
  484. return (aStatus);
  485. } // end of sync_espeak_Synth_Mark
  486. void sync_espeak_Key(const char *key)
  487. {//==================================
  488. // symbolic name, symbolicname_character - is there a system resource of symbolic names per language?
  489. my_unique_identifier = 0;
  490. my_user_data = NULL;
  491. Synthesize(0, key,0); // for now, just say the key name as passed
  492. }
  493. void sync_espeak_Char(wchar_t character)
  494. {//=====================================
  495. // is there a system resource of character names per language?
  496. char buf[80];
  497. my_unique_identifier = 0;
  498. my_user_data = NULL;
  499. sprintf(buf,"<say-as interpret-as=\"tts:char\">&#%d;</say-as>",character);
  500. Synthesize(0, buf,espeakSSML);
  501. }
  502. void sync_espeak_SetPunctuationList(const wchar_t *punctlist)
  503. {//==========================================================
  504. // Set the list of punctuation which are spoken for "some".
  505. my_unique_identifier = 0;
  506. my_user_data = NULL;
  507. wcsncpy(option_punctlist, punctlist, N_PUNCTLIST);
  508. option_punctlist[N_PUNCTLIST-1] = 0;
  509. } // end of sync_espeak_SetPunctuationList
  510. #pragma GCC visibility push(default)
  511. ESPEAK_API void espeak_SetSynthCallback(t_espeak_callback* SynthCallback)
  512. {//======================================================================
  513. ENTER("espeak_SetSynthCallback");
  514. synth_callback = SynthCallback;
  515. #ifdef USE_ASYNC
  516. event_set_callback(synth_callback);
  517. #endif
  518. }
  519. ESPEAK_API void espeak_SetUriCallback(int (* UriCallback)(int, const char*, const char *))
  520. {//=======================================================================================
  521. ENTER("espeak_SetUriCallback");
  522. uri_callback = UriCallback;
  523. }
  524. ESPEAK_API int espeak_Initialize(espeak_AUDIO_OUTPUT output_type, int buf_length, const char *path, int options)
  525. {//=============================================================================================================
  526. ENTER("espeak_Initialize");
  527. int param;
  528. // It seems that the wctype functions don't work until the locale has been set
  529. // to something other than the default "C". Then, not only Latin1 but also the
  530. // other characters give the correct results with iswalpha() etc.
  531. #ifdef PLATFORM_RISCOS
  532. setlocale(LC_CTYPE,"ISO8859-1");
  533. #else
  534. if(setlocale(LC_CTYPE,"en_US.UTF-8") == NULL)
  535. {
  536. if(setlocale(LC_CTYPE,"UTF-8") == NULL)
  537. setlocale(LC_CTYPE,"");
  538. }
  539. #endif
  540. init_path(path);
  541. initialise();
  542. select_output(output_type);
  543. // buflength is in mS, allocate 2 bytes per sample
  544. if(buf_length == 0)
  545. buf_length = 200;
  546. outbuf_size = (buf_length * samplerate)/500;
  547. outbuf = (unsigned char*)realloc(outbuf,outbuf_size);
  548. if((out_start = outbuf) == NULL)
  549. return(EE_INTERNAL_ERROR);
  550. // allocate space for event list. Allow 200 events per second
  551. n_event_list = (buf_length*200)/1000;
  552. if((event_list = (espeak_EVENT *)realloc(event_list,sizeof(espeak_EVENT) * n_event_list)) == NULL)
  553. return(EE_INTERNAL_ERROR);
  554. option_phonemes = 0;
  555. option_phoneme_events = (options & 1);
  556. SetVoiceByName("default");
  557. for(param=0; param<N_SPEECH_PARAM; param++)
  558. param_stack[0].parameter[param] = param_defaults[param];
  559. SetParameter(espeakRATE,170,0);
  560. SetParameter(espeakVOLUME,100,0);
  561. SetParameter(espeakCAPITALS,option_capitals,0);
  562. SetParameter(espeakPUNCTUATION,option_punctuation,0);
  563. WavegenSetVoice(voice);
  564. #ifdef USE_ASYNC
  565. fifo_init();
  566. #endif
  567. return(samplerate);
  568. }
  569. ESPEAK_API espeak_ERROR espeak_Synth(const void *text, size_t size,
  570. unsigned int position,
  571. espeak_POSITION_TYPE position_type,
  572. unsigned int end_position, unsigned int flags,
  573. unsigned int* unique_identifier, void* user_data)
  574. {//=====================================================================================
  575. ENTER("espeak_Synth");
  576. SHOW("espeak_Synth > position=%d, position_type=%d, end_position=%d, flags=%d, user_data=0x%x, text=%s\n", position, position_type, end_position, flags, user_data, text);
  577. espeak_ERROR a_error=EE_INTERNAL_ERROR;
  578. static unsigned int temp_identifier;
  579. if (unique_identifier == NULL)
  580. {
  581. unique_identifier = &temp_identifier;
  582. }
  583. *unique_identifier = 0;
  584. if(synchronous_mode)
  585. {
  586. return(sync_espeak_Synth(0,text,size,position,position_type,end_position,flags,user_data));
  587. }
  588. #ifdef USE_ASYNC
  589. // Create the text command
  590. t_espeak_command* c1 = create_espeak_text(text, size, position, position_type, end_position, flags, user_data);
  591. // Retrieve the unique identifier
  592. *unique_identifier = c1->u.my_text.unique_identifier;
  593. // Create the "terminated msg" command (same uid)
  594. t_espeak_command* c2 = create_espeak_terminated_msg(*unique_identifier, user_data);
  595. // Try to add these 2 commands (single transaction)
  596. if (c1 && c2)
  597. {
  598. a_error = fifo_add_commands(c1, c2);
  599. if (a_error != EE_OK)
  600. {
  601. delete_espeak_command(c1);
  602. delete_espeak_command(c2);
  603. c1=c2=NULL;
  604. }
  605. }
  606. else
  607. {
  608. delete_espeak_command(c1);
  609. delete_espeak_command(c2);
  610. }
  611. #endif
  612. return a_error;
  613. } // end of espeak_Synth
  614. ESPEAK_API espeak_ERROR espeak_Synth_Mark(const void *text, size_t size,
  615. const char *index_mark,
  616. unsigned int end_position,
  617. unsigned int flags,
  618. unsigned int* unique_identifier,
  619. void* user_data)
  620. {//=========================================================================
  621. ENTER("espeak_Synth_Mark");
  622. SHOW("espeak_Synth_Mark > index_mark=%s, end_position=%d, flags=%d, text=%s\n", index_mark, end_position, flags, text);
  623. espeak_ERROR a_error=EE_OK;
  624. static unsigned int temp_identifier;
  625. if (unique_identifier == NULL)
  626. {
  627. unique_identifier = &temp_identifier;
  628. }
  629. *unique_identifier = 0;
  630. if(synchronous_mode)
  631. {
  632. return(sync_espeak_Synth_Mark(0,text,size,index_mark,end_position,flags,user_data));
  633. }
  634. #ifdef USE_ASYNC
  635. // Create the mark command
  636. t_espeak_command* c1 = create_espeak_mark(text, size, index_mark, end_position,
  637. flags, user_data);
  638. // Retrieve the unique identifier
  639. *unique_identifier = c1->u.my_mark.unique_identifier;
  640. // Create the "terminated msg" command (same uid)
  641. t_espeak_command* c2 = create_espeak_terminated_msg(*unique_identifier, user_data);
  642. // Try to add these 2 commands (single transaction)
  643. if (c1 && c2)
  644. {
  645. a_error = fifo_add_commands(c1, c2);
  646. if (a_error != EE_OK)
  647. {
  648. delete_espeak_command(c1);
  649. delete_espeak_command(c2);
  650. c1=c2=NULL;
  651. }
  652. }
  653. else
  654. {
  655. delete_espeak_command(c1);
  656. delete_espeak_command(c2);
  657. }
  658. #endif
  659. return a_error;
  660. } // end of espeak_Synth_Mark
  661. ESPEAK_API espeak_ERROR espeak_Key(const char *key)
  662. {//================================================
  663. ENTER("espeak_Key");
  664. // symbolic name, symbolicname_character - is there a system resource of symbolicnames per language
  665. espeak_ERROR a_error = EE_OK;
  666. if(synchronous_mode)
  667. {
  668. sync_espeak_Key(key);
  669. return(EE_OK);
  670. }
  671. #ifdef USE_ASYNC
  672. t_espeak_command* c = create_espeak_key( key);
  673. a_error = fifo_add_command(c);
  674. if (a_error != EE_OK)
  675. {
  676. delete_espeak_command(c);
  677. }
  678. #endif
  679. return a_error;
  680. }
  681. ESPEAK_API espeak_ERROR espeak_Char(wchar_t character)
  682. {//===========================================
  683. ENTER("espeak_Char");
  684. // is there a system resource of character names per language?
  685. #ifdef USE_ASYNC
  686. espeak_ERROR a_error;
  687. if(synchronous_mode)
  688. {
  689. sync_espeak_Char(character);
  690. return(EE_OK);
  691. }
  692. t_espeak_command* c = create_espeak_char( character);
  693. a_error = fifo_add_command(c);
  694. if (a_error != EE_OK)
  695. {
  696. delete_espeak_command(c);
  697. }
  698. return a_error;
  699. #else
  700. sync_espeak_Char(character);
  701. return(EE_OK);
  702. #endif
  703. }
  704. ESPEAK_API espeak_ERROR espeak_SetVoiceByName(const char *name)
  705. {//===================================================
  706. ENTER("espeak_SetVoiceByName");
  707. #ifdef USE_ASYNC
  708. espeak_ERROR a_error;
  709. if(synchronous_mode)
  710. {
  711. return(SetVoiceByName(name));
  712. }
  713. t_espeak_command* c = create_espeak_voice_name(name);
  714. a_error = fifo_add_command(c);
  715. if (a_error != EE_OK)
  716. {
  717. delete_espeak_command(c);
  718. }
  719. return a_error;
  720. #else
  721. return(SetVoiceByName(name));
  722. #endif
  723. } // end of espeak_SetVoiceByName
  724. ESPEAK_API espeak_ERROR espeak_SetVoiceByProperties(espeak_VOICE *voice_selector)
  725. {//=====================================================================
  726. ENTER("espeak_SetVoiceByProperties");
  727. #ifdef USE_ASYNC
  728. espeak_ERROR a_error;
  729. if(synchronous_mode)
  730. {
  731. return(SetVoiceByProperties(voice_selector));
  732. }
  733. t_espeak_command* c = create_espeak_voice_spec( voice_selector);
  734. a_error = fifo_add_command(c);
  735. if (a_error != EE_OK)
  736. {
  737. delete_espeak_command(c);
  738. }
  739. return a_error;
  740. #else
  741. return(SetVoiceByProperties(voice_selector));
  742. #endif
  743. } // end of espeak_SetVoiceByProperties
  744. ESPEAK_API int espeak_GetParameter(espeak_PARAMETER parameter, int current)
  745. {//========================================================================
  746. ENTER("espeak_GetParameter");
  747. // current: 0=default value, 1=current value
  748. if(current)
  749. {
  750. return(param_stack[0].parameter[parameter]);
  751. }
  752. else
  753. {
  754. return(param_defaults[parameter]);
  755. }
  756. } // end of espeak_GetParameter
  757. ESPEAK_API espeak_ERROR espeak_SetParameter(espeak_PARAMETER parameter, int value, int relative)
  758. {//=============================================================================================
  759. ENTER("espeak_SetParameter");
  760. #ifdef USE_ASYNC
  761. espeak_ERROR a_error;
  762. if(synchronous_mode)
  763. {
  764. SetParameter(parameter,value,relative);
  765. return(EE_OK);
  766. }
  767. t_espeak_command* c = create_espeak_parameter(parameter, value, relative);
  768. a_error = fifo_add_command(c);
  769. if (a_error != EE_OK)
  770. {
  771. delete_espeak_command(c);
  772. }
  773. return a_error;
  774. #else
  775. SetParameter(parameter,value,relative);
  776. return(EE_OK);
  777. #endif
  778. }
  779. ESPEAK_API espeak_ERROR espeak_SetPunctuationList(const wchar_t *punctlist)
  780. {//================================================================
  781. ENTER("espeak_SetPunctuationList");
  782. // Set the list of punctuation which are spoken for "some".
  783. #ifdef USE_ASYNC
  784. espeak_ERROR a_error;
  785. if(synchronous_mode)
  786. {
  787. sync_espeak_SetPunctuationList(punctlist);
  788. return(EE_OK);
  789. }
  790. t_espeak_command* c = create_espeak_punctuation_list( punctlist);
  791. a_error = fifo_add_command(c);
  792. if (a_error != EE_OK)
  793. {
  794. delete_espeak_command(c);
  795. }
  796. return a_error;
  797. #else
  798. sync_espeak_SetPunctuationList(punctlist);
  799. return(EE_OK);
  800. #endif
  801. } // end of espeak_SetPunctuationList
  802. ESPEAK_API void espeak_SetPhonemeTrace(int value, FILE *stream)
  803. {//============================================================
  804. ENTER("espeak_SetPhonemes");
  805. /* Controls the output of phoneme symbols for the text
  806. value=0 No phoneme output (default)
  807. value=1 Output the translated phoneme symbols for the text
  808. value=2 as (1), but also output a trace of how the translation was done (matching rules and list entries)
  809. */
  810. option_phonemes = value;
  811. f_trans = stream;
  812. if(stream == NULL)
  813. f_trans = stdout;
  814. } // end of espeak_SetPhonemes
  815. ESPEAK_API void espeak_CompileDictionary(const char *path, FILE *log)
  816. {//==================================================================
  817. ENTER("espeak_CompileDictionary");
  818. CompileDictionary(path,dictionary_name,log,NULL);
  819. } // end of espeak_CompileDirectory
  820. ESPEAK_API espeak_ERROR espeak_Cancel(void)
  821. {//===============================
  822. #ifdef USE_ASYNC
  823. ENTER("espeak_Cancel");
  824. fifo_stop();
  825. event_clear_all();
  826. if(my_mode == AUDIO_OUTPUT_PLAYBACK)
  827. {
  828. wave_close(my_audio);
  829. }
  830. SHOW_TIME("espeak_Cancel > LEAVE");
  831. #endif
  832. return EE_OK;
  833. } // end of espeak_Cancel
  834. ESPEAK_API int espeak_IsPlaying(void)
  835. {//==================================
  836. // ENTER("espeak_IsPlaying");
  837. #ifdef USE_ASYNC
  838. if((my_mode == AUDIO_OUTPUT_PLAYBACK) && wave_is_busy(my_audio))
  839. return(1);
  840. return(fifo_is_busy());
  841. #else
  842. return(0);
  843. #endif
  844. } // end of espeak_IsPlaying
  845. ESPEAK_API espeak_ERROR espeak_Synchronize(void)
  846. {//=============================================
  847. #ifdef USE_ASYNC
  848. SHOW_TIME("espeak_Synchronize > ENTER");
  849. while (espeak_IsPlaying())
  850. {
  851. usleep(20000);
  852. }
  853. #endif
  854. SHOW_TIME("espeak_Synchronize > LEAVE");
  855. return EE_OK;
  856. } // end of espeak_Synchronize
  857. extern void FreePhData(void);
  858. ESPEAK_API espeak_ERROR espeak_Terminate(void)
  859. {//===========================================
  860. ENTER("espeak_Terminate");
  861. #ifdef USE_ASYNC
  862. fifo_stop();
  863. fifo_terminate();
  864. event_terminate();
  865. if(my_mode == AUDIO_OUTPUT_PLAYBACK)
  866. {
  867. wave_close(my_audio);
  868. wave_terminate();
  869. }
  870. #endif
  871. Free(event_list);
  872. event_list = NULL;
  873. Free(outbuf);
  874. outbuf = NULL;
  875. FreePhData();
  876. return EE_OK;
  877. } // end of espeak_Terminate
  878. ESPEAK_API const char *espeak_Info(void *)
  879. {//=======================================
  880. return(version_string);
  881. }
  882. #pragma GCC visibility pop