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_riscos 29KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399
  1. /***************************************************************************
  2. * Copyright (C) 2005 to 2013 by Jonathan Duddington *
  3. * email: [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 3 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 see: *
  17. * <http://www.gnu.org/licenses/>. *
  18. ***************************************************************************/
  19. #define USE_MODULE
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <ctype.h>
  24. #include <locale.h>
  25. #include "kernel.h"
  26. #include <math.h>
  27. #include "speech.h"
  28. #include "speak_lib.h"
  29. #include "phoneme.h"
  30. #include "synthesize.h"
  31. #include "voice.h"
  32. #include "translate.h"
  33. #define os_X 0x20000
  34. // interface to the assembler section
  35. extern "C" {
  36. extern void DMA_Handler(void);
  37. // used from the cmhgfile
  38. extern _kernel_oserror *user_init(char *cmd_fail, int podule_base, void *pw);
  39. extern _kernel_oserror *swi_handler(int swi_no, int *r, void *pw);
  40. extern _kernel_oserror *command_handler(char *arg_string, int argc, int cmd_no, void *pw);
  41. extern int callback_handler(_kernel_swi_regs *r, void *pw);
  42. extern int callback_entry(_kernel_swi_regs *r, void *pw);
  43. extern int sound_handler(_kernel_swi_regs *r, void *pw);
  44. extern int sound_entry(_kernel_swi_regs *r, void *pw);
  45. }
  46. extern int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume);
  47. extern void RiscosOpenSound();
  48. extern int WcmdqUsed();
  49. extern void FreePhData();
  50. extern void FreeDictionary();
  51. extern void Write4Bytes(FILE *f, int value);
  52. extern int wcmdq_head;
  53. extern int wcmdq_tail;
  54. extern int current_source_index;
  55. FILE *f_text;
  56. FILE *f_wave = NULL;
  57. int (* uri_callback)(int, const char *, const char *) = NULL;
  58. int (* phoneme_callback)(const char *) = NULL;
  59. int amp = 8; // default
  60. char path_home[N_PATH_HOME] = "";
  61. char wavefile[120];
  62. char textbuffile[L_tmpnam];
  63. int sample_rate_index; // current value
  64. int current_voice_num=0;
  65. int n_voice_files = 0;
  66. int n_voice_variant_files = 0;
  67. // output sound buffer, 2 bytes per sample
  68. static unsigned short SoundBuf[4096];
  69. static void *module_data;
  70. static int callback_inhibit = 0;
  71. static int more_text=0;
  72. #define N_VOICE_NAMES 60
  73. #define N_VOICE_VARIANT_NAMES 30
  74. static char *voice_names[N_VOICE_NAMES];
  75. static char *voice_variant_names[N_VOICE_VARIANT_NAMES];
  76. #define N_STATIC_BUF 8000
  77. static char static_buf[N_STATIC_BUF];
  78. static _kernel_oserror errblk;
  79. USHORT voice_pcnt[N_PEAKS+1][3];
  80. static const char *help_text =
  81. "\nspeak [options] [\"<words>\"]\n\n"
  82. "-f <text file> Text file to speak\n"
  83. //"--stdin Read text input from stdin instead of a file\n\n"
  84. "If neither -f nor --stdin, <words> are spoken, or if none then text is\n"
  85. "spoken from stdin, each line separately.\n\n"
  86. "-a <integer>\n"
  87. "\t Amplitude, 0 to 200, default is 100\n"
  88. "-g <integer>\n"
  89. "\t Word gap. Pause between words, units of 10mS at the default speed\n"
  90. "-l <integer>\n"
  91. "\t Line length. If not zero (which is the default), consider\n"
  92. "\t lines less than this length as end-of-clause\n"
  93. "-p <integer>\n"
  94. "\t Pitch adjustment, 0 to 99, default is 50\n"
  95. "-s <integer>\n"
  96. "\t Speed in words per minute 80 to 390, default is 170\n"
  97. "-v <voice name>\n"
  98. "\t Use voice file of this name from espeak-data/voices\n"
  99. "-w <wave file name>\n"
  100. "\t Write output to this WAV file, rather than speaking it directly\n"
  101. "-b\t Input text is 8-bit encoding\n"
  102. "-m\t Interpret SSML markup, and ignore other < > tags\n"
  103. "-q\t Quiet, don't produce any speech (may be useful with -x)\n"
  104. "-x\t Write phoneme mnemonics to stdout\n"
  105. "-X\t Write phonemes mnemonics and translation trace to stdout\n"
  106. //"--stdout Write speech output to stdout\n"
  107. "--compile=<voice name>\n"
  108. "\t Compile the pronunciation rules and dictionary in the current\n"
  109. "\t directory. =<voice name> is optional and specifies which language\n"
  110. "--punct=\"<characters>\"\n"
  111. "\t Speak the names of punctuation characters during speaking. If\n"
  112. "\t =<characters> is omitted, all punctuation is spoken.\n"
  113. "--voices=<language>\n"
  114. "\t List the available voices for the specified language.\n"
  115. "\t If <language> is omitted, then list all voices.\n"
  116. "-k <integer>\n"
  117. "\t Indicate capital letters with: 1=sound, 2=the word \"capitals\",\n"
  118. "\t higher values = a pitch increase (try -k20).\n";
  119. int GetFileLength(const char *filename)
  120. {//====================================
  121. int length=0;
  122. int type;
  123. _kernel_swi_regs regs;
  124. _kernel_oserror *error;
  125. regs.r[0] = 5;
  126. regs.r[1] = (int)filename;
  127. regs.r[2] = 0;
  128. regs.r[3] = 0;
  129. regs.r[4] = 0;
  130. regs.r[5] = 0;
  131. error = _kernel_swi(0x20008,&regs,&regs);
  132. if(error)
  133. return(0);
  134. type = regs.r[0];
  135. length = regs.r[4];
  136. if(type==2)
  137. return(-2); // a directory
  138. if((type!=1) && (type!=3))
  139. return(0); /* not a file */
  140. return(length);
  141. } /* end of GetFileLength */
  142. void MarkerEvent(int type, unsigned int char_position, int value, int value2, unsigned char *out_ptr)
  143. {
  144. }
  145. void ReadVoiceNames2(char *directory)
  146. {//==================================
  147. int len;
  148. int path_len;
  149. int *type;
  150. char *p;
  151. _kernel_swi_regs regs;
  152. _kernel_oserror *error;
  153. char buf[80];
  154. char directory2[sizeof(path_home)+100];
  155. regs.r[0] = 10;
  156. regs.r[1] = (int)directory;
  157. regs.r[2] = (int)buf;
  158. regs.r[3] = 1;
  159. regs.r[4] = 0;
  160. regs.r[5] = sizeof(buf);
  161. regs.r[6] = 0;
  162. path_len = strlen(directory);
  163. while(regs.r[3] > 0)
  164. {
  165. error = _kernel_swi(0x0c+os_X,&regs,&regs); /* OS_GBPB 10, read directory entries */
  166. if((error != NULL) || (regs.r[3] == 0))
  167. {
  168. break;
  169. }
  170. type = (int *)(&buf[16]);
  171. len = strlen(&buf[20]);
  172. if(*type == 2)
  173. {
  174. // a sub-directory
  175. sprintf(directory2,"%s.%s",directory,&buf[20]);
  176. ReadVoiceNames2(directory2);
  177. }
  178. else
  179. {
  180. p = (char *)malloc(len+1);
  181. strcpy(p,&buf[20]);
  182. if(strcmp(&directory[path_len-3],".!v")==0)
  183. {
  184. if(n_voice_variant_files >= (N_VOICE_VARIANT_NAMES-1))
  185. continue;
  186. voice_variant_names[n_voice_variant_files++] = p;
  187. }
  188. else
  189. if(strcmp(p, "default") != 0)
  190. {
  191. if(n_voice_files >= (N_VOICE_NAMES-1))
  192. continue;
  193. voice_names[n_voice_files++] = p;
  194. }
  195. }
  196. }
  197. }
  198. void ReadVoiceNames()
  199. {//===================
  200. char directory[sizeof(path_home)+20];
  201. n_voice_files = 0;
  202. n_voice_variant_files = 0;
  203. sprintf(directory,"%s.voices.default", path_home);
  204. if(GetFileLength(directory) > 0)
  205. {
  206. // put the 'default' voice at the start of the list
  207. voice_names[n_voice_files++] = "default";
  208. }
  209. sprintf(directory,"%s.voices",path_home);
  210. ReadVoiceNames2(directory);
  211. voice_names[n_voice_files] = NULL;
  212. voice_variant_names[n_voice_variant_files] = NULL;
  213. }
  214. #ifdef USE_MODULE
  215. char *Alloc(int size)
  216. /*******************/
  217. { // version of malloc() for use in RISC_OS module
  218. _kernel_swi_regs regs;
  219. regs.r[0] = 6;
  220. regs.r[3] = size;
  221. _kernel_swi(0x1e, &regs, &regs); /* OS_Module 6 claim memory */
  222. return(char *)regs.r[2];
  223. } /* end of module_malloc */
  224. void Free(void *ptr)
  225. /*******************/
  226. { // version of free() for use in RISC_OS module
  227. _kernel_swi_regs regs;
  228. if(ptr == NULL)
  229. return;
  230. regs.r[0] = 7;
  231. regs.r[2] = (int)(ptr);
  232. _kernel_swi(0x1e, &regs, &regs); /* OS_Module 7 free memory */
  233. } /* end of Free */
  234. #else
  235. char *Alloc(int size)
  236. {//==================
  237. char *p;
  238. if((p = (char *)malloc(size)) == NULL)
  239. fprintf(stderr,"Can't allocate memory\n");
  240. return(p);
  241. }
  242. void Free(void **ptr)
  243. {//=================
  244. if(ptr != NULL)
  245. {
  246. free(ptr);
  247. }
  248. }
  249. #endif
  250. static int OpenWaveFile(const char *path, int rate)
  251. //=================================================
  252. {
  253. // Set the length of 0x7fffffff for --stdout
  254. // This will be changed to the correct length for -w (write to file)
  255. static unsigned char wave_hdr[44] = {
  256. 'R','I','F','F',0,0,0,0,'W','A','V','E','f','m','t',' ',
  257. 0x10,0,0,0,1,0,1,0, 9,0x3d,0,0,0x12,0x7a,0,0,
  258. 2,0,0x10,0,'d','a','t','a', 0xff,0xff,0xff,0x7f};
  259. if(path == NULL)
  260. return(2);
  261. if(strcmp(path,"stdout")==0)
  262. f_wave = stdout;
  263. else
  264. f_wave = fopen(path,"wb");
  265. if(f_wave != NULL)
  266. {
  267. fwrite(wave_hdr,1,24,f_wave);
  268. Write4Bytes(f_wave,rate);
  269. Write4Bytes(f_wave,rate * 2);
  270. fwrite(&wave_hdr[32],1,12,f_wave);
  271. return(0);
  272. }
  273. return(1);
  274. } // end of OpenWaveFile
  275. static void CloseWaveFile(int rate)
  276. //=================================
  277. {
  278. unsigned int pos;
  279. if((f_wave == NULL) || (f_wave == stdout))
  280. return;
  281. fflush(f_wave);
  282. pos = ftell(f_wave);
  283. fseek(f_wave,4,SEEK_SET);
  284. Write4Bytes(f_wave,pos - 8);
  285. fseek(f_wave,40,SEEK_SET);
  286. Write4Bytes(f_wave,pos - 44);
  287. fclose(f_wave);
  288. f_wave = NULL;
  289. } // end of CloseWaveFile
  290. void MarkerEvent(int type, unsigned int char_position, int value, unsigned char *out_ptr)
  291. {//======================================================================================
  292. // Do nothing in the command-line version.
  293. } // end of MarkerEvent
  294. static int WavegenFile(void)
  295. {//=========================
  296. int finished;
  297. unsigned char wav_outbuf[1024];
  298. out_ptr = out_start = wav_outbuf;
  299. out_end = wav_outbuf + sizeof(wav_outbuf);
  300. finished = WavegenFill(0);
  301. if(f_wave != NULL)
  302. {
  303. fwrite(wav_outbuf, 1, out_ptr - wav_outbuf, f_wave);
  304. }
  305. return(finished);
  306. } // end of WavegenFile
  307. void FillSoundBuf(int size)
  308. {//========================
  309. // Fill the buffer with output sound
  310. // size is number of samples*4
  311. size = size;
  312. if(size > sizeof(SoundBuf))
  313. size = sizeof(SoundBuf);
  314. out_ptr = (unsigned char *)(&SoundBuf[0]);
  315. out_end = (unsigned char *)(&SoundBuf[size]);
  316. WavegenFill(1);
  317. }
  318. int initialise(void)
  319. {//=================
  320. char buf[N_PATH_HOME];
  321. _kernel_swi_regs regs;
  322. _kernel_oserror *error;
  323. buf[0] = 0;
  324. regs.r[0] = (int)"eSpeak$Dir";
  325. regs.r[1] = (int)buf;
  326. regs.r[2] = sizeof(buf);
  327. regs.r[3] = 0;
  328. regs.r[4] = 0;
  329. regs.r[5] = 0;
  330. error = _kernel_swi(0x20023,&regs,&regs); // OS_ReadVarVal
  331. buf[regs.r[2]] = 0;
  332. sprintf(path_home,"%s.espeak-data",buf);
  333. if(GetFileLength(path_home) != -2)
  334. {
  335. // not found, try the 10 character version of the directory name
  336. sprintf(path_home,"%s.espeak-dat",buf);
  337. }
  338. if(GetFileLength(path_home) != -2)
  339. {
  340. // still can't find data directory
  341. sprintf(errblk.errmess,"Speak: Can't find data directory: '%s'\n",path_home);
  342. return(-1);
  343. }
  344. WavegenInit(22050,0);
  345. LoadPhData(NULL);
  346. SetVoiceStack(NULL, "");
  347. SynthesizeInit();
  348. return(0);
  349. }
  350. void speak_text_string(char *data, int terminator, int len, int wait, int voice_num)
  351. /**********************************************************************************/
  352. /* 'wait' indictes wait until speaking is finished before returning */
  353. {
  354. int c;
  355. int ix;
  356. static static_length=0;
  357. static int user_token=0; /* increment for each call of translate() */
  358. _kernel_swi_regs regs;
  359. regs.r[0] = (int)callback_entry;
  360. regs.r[1] = (int)module_data;
  361. _kernel_swi(0x5f, &regs, &regs);
  362. option_endpause = 1;
  363. if((voice_num >= 0) && (voice_num != current_voice_num) && (voice_num < N_VOICE_NAMES))
  364. {
  365. SetVoiceByName(voice_names[voice_num]);
  366. WavegenSetVoice(voice);
  367. }
  368. current_voice_num = voice_num;
  369. /* don't count CR as terminator if length is specified */
  370. if(len > 0) terminator = 0;
  371. ix = 0;
  372. if(more_text == 0)
  373. static_length = 0;
  374. else
  375. {
  376. strcat(&static_buf[static_length]," \n ");
  377. static_length+=3;
  378. }
  379. if(terminator == 0)
  380. {
  381. while(((c = data[ix++]) != 0) && (static_length < N_STATIC_BUF-4))
  382. {
  383. static_buf[static_length++] = c;
  384. if(ix == len)
  385. break;
  386. }
  387. }
  388. else
  389. {
  390. while(((c = data[ix++]) != '\r') && (c != '\n') && (c != 0) && (static_length < N_STATIC_BUF-3))
  391. {
  392. static_buf[static_length++] = c;
  393. if(ix == len)
  394. break;
  395. }
  396. }
  397. static_buf[static_length] = 0;
  398. if(option_waveout==0)
  399. {
  400. if(more_text == 0)
  401. {
  402. InitText(0);
  403. RiscosOpenSound();
  404. more_text = SpeakNextClause(NULL,(void *)static_buf,0);
  405. }
  406. while(wait)
  407. {
  408. if((more_text==0) && (wcmdq_head == wcmdq_tail))
  409. break;
  410. //we need to block to allow the callback handler to run
  411. regs.r[0] = 129; // wait for key press
  412. regs.r[1] = 10;
  413. regs.r[2] = 0;
  414. _kernel_swi(0x06, &regs, &regs); // OS_Byte
  415. }
  416. }
  417. else
  418. {
  419. more_text = 0;
  420. SpeakNextClause(NULL,(void *)static_buf,0);
  421. for(;;)
  422. {
  423. if(WavegenFile() != 0)
  424. break; // finished, wavegen command queue is empty
  425. if(Generate(phoneme_list,&n_phoneme_list,1)==0)
  426. SpeakNextClause(NULL,NULL,1);
  427. }
  428. CloseWaveFile(samplerate);
  429. }
  430. } /* end of speak_text_string */
  431. void speak_file(char *fname)
  432. {//=========================
  433. FILE *f_in;
  434. char buf[120];
  435. f_in = fopen(fname,"r");
  436. if(f_in == NULL)
  437. {
  438. fprintf(stderr,"Can't read file: '%s'",fname);
  439. return;
  440. }
  441. more_text = 1;
  442. if(option_waveout == 0)
  443. {
  444. RiscosOpenSound();
  445. SpeakNextClause(f_in,NULL,0);
  446. }
  447. else
  448. {
  449. more_text = 0;
  450. SpeakNextClause(f_in,NULL,0);
  451. for(;;)
  452. {
  453. if(WavegenFile() != 0)
  454. break; // finished, wavegen command queue is empty
  455. if(Generate(phoneme_list,&n_phoneme_list,1)==0)
  456. SpeakNextClause(NULL,NULL,1);
  457. }
  458. CloseWaveFile(samplerate);
  459. }
  460. }
  461. void set_say_options(int reg2, int reg3)
  462. /**************************************/
  463. /* Sets options from information in 'say' SWI */
  464. /* R3 bits 0-7 stress indicator character
  465. bit 8 inhibit unpronouncable check */
  466. {
  467. option_linelength = 0;
  468. option_phonemes = 0;
  469. option_waveout = 0;
  470. option_multibyte = 0; // auto
  471. option_capitals = 0;
  472. option_punctuation = 0;
  473. option_punctlist[0] = 0;
  474. } /* end of set_say_options */
  475. void jsd_swi_functions(int *r)
  476. /****************************/
  477. {
  478. int use_ipa;
  479. espeak_VOICE voice_select;
  480. switch(r[0])
  481. {
  482. case 0: /* major version */
  483. r[0] = 4;
  484. r[1] = 347;
  485. break;
  486. case 1: /* register user */
  487. break;
  488. case 2: /* deregister user */
  489. break;
  490. case 3:
  491. // translate into phonemes
  492. use_ipa = 0;
  493. if((r[2] >= 1) && (use_ipa <= 3))
  494. use_ipa = r[2];
  495. TranslateClause(translator,NULL,(char *)r[1],NULL,NULL);
  496. GetTranslatedPhonemeString(translator->phon_out, sizeof(translator->phon_out), use_ipa);
  497. r[0] = (int)translator->phon_out;
  498. break;
  499. case 4:
  500. // r[0] = reload_word_dict(NULL);
  501. break;
  502. case 5: /* get table of voice names */
  503. r[0] = (int)voice_names;
  504. r[1] = (int)voice_variant_names;
  505. break;
  506. case 6: /* update voice data, r1 = voice_number */
  507. if(r[1] < N_VOICE_NAMES)
  508. {
  509. SetVoiceByName(voice_names[r[1]]);
  510. current_voice_num = r[1];
  511. WavegenSetVoice(voice);
  512. }
  513. break;
  514. case 7: /* load voice data */
  515. // init_voice((char *)r[1]);
  516. break;
  517. case 8:
  518. // list voices, r[1] contains optional language name (or "variant")
  519. voice_select.languages = (char *)r[1];
  520. voice_select.age = 0;
  521. voice_select.gender = 0;
  522. voice_select.name = NULL;
  523. r[0] = (int)espeak_ListVoices(&voice_select);
  524. break;
  525. default:
  526. r[0] = 0;
  527. r[1] = 0;
  528. break;
  529. }
  530. } /* end of jsd_swi_functions */
  531. _kernel_oserror *swi_handler(int swi_no, int *r, void *pw)
  532. /*********************************************************/
  533. {
  534. int value;
  535. int value2;
  536. int q_length;
  537. value = r[0];
  538. switch(swi_no)
  539. {
  540. case 0: // ready ?
  541. // returns the index into the source text of the currently speaking word
  542. if(current_source_index > 0)
  543. r[1] = current_source_index-1;
  544. else
  545. r[1] = current_source_index; /* source index */
  546. r[2] = 0; /* source tag */
  547. r[3] = 0; /* for future expansion */
  548. r[4] = 0;
  549. r[5] = 0;
  550. if(WcmdqUsed() < 5)
  551. {
  552. r[0] = -1; /* ready, or nearly */
  553. }
  554. else
  555. {
  556. r[0] = 0;
  557. }
  558. break;
  559. case 1: /* restore old sound channel. DO NOTHING */
  560. break;
  561. case 2: /* miscellaneous functions */
  562. jsd_swi_functions(r);
  563. break;
  564. case 3: /* speak text */
  565. // _kernel_irqs_on();
  566. set_say_options(r[2],r[3]);
  567. speak_text_string((char *)r[0],'\r',r[1],0,r[2]);
  568. break;
  569. case 4: /* speak text and wait */
  570. // _kernel_irqs_on(); /* enable interrupts */
  571. set_say_options(r[2],r[3]);
  572. speak_text_string((char *)r[0],'\r',r[1],1,r[2]);
  573. break;
  574. case 5: /* stop speaking */
  575. SpeakNextClause(NULL,NULL,2);
  576. more_text = 0;
  577. break;
  578. case 7: /* pitch */
  579. value = (value * 50)/128;
  580. SetParameter(espeakPITCH, value, 0);
  581. break;
  582. case 8: // speed, convert to range 80 to 400, mid-value=180
  583. if(value < 128)
  584. value2 = 80 + (value*100)/128; // linear range for 0-127 -> 80-179
  585. else
  586. value2 = 80 + pow((float)value/128.0, 1.75)*100;
  587. SetParameter(espeakRATE,value2,0);
  588. break;
  589. case 9: /* word_gap */
  590. if(value >= 128)
  591. value = value - 128;
  592. if(value > 1)
  593. value = (value-1) * 5;
  594. SetParameter(espeakWORDGAP,value,0);
  595. break;
  596. case 10: /* pitch_range */
  597. value = (value * 50)/128;
  598. SetParameter(espeakRANGE, value, 0);
  599. break;
  600. case 12: /* reset */
  601. // not implemented
  602. break;
  603. case 13: /* volume */
  604. // convert to range 6-255 to 10-400, mid-value=100
  605. if(value < 6)
  606. value2 = value + 4;
  607. else
  608. if(value < 128)
  609. {
  610. value2 = pow((float)(value+40)/168.0, 1.75)*100;
  611. }
  612. else
  613. value2 = pow((float)value/128.0, 2.0)*100;
  614. SetParameter(espeakVOLUME,value2,0);
  615. WavegenSetVoice(voice);
  616. break;
  617. case 14: // set voice by name
  618. SetVoiceByName((char *)r[0]);
  619. WavegenSetVoice(voice);
  620. break;
  621. }
  622. return(NULL);
  623. } /* end of swi_handler */
  624. void PitchAdjust(int pitch_adjustment)
  625. {//===================================
  626. int ix, factor;
  627. extern unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1];
  628. voice->pitch_base = (voice->pitch_base * pitch_adjust_tab[pitch_adjustment])/128;
  629. // adjust formants to give better results for a different voice pitch
  630. factor = 256 + (25 * (pitch_adjustment - 50))/50;
  631. for(ix=0; ix<=5; ix++)
  632. {
  633. voice->freq[ix] = (voice->freq2[ix] * factor)/256;
  634. }
  635. } // end of PitchAdjustment
  636. void DisplayVoices(FILE *f_out, char *language)
  637. {//============================================
  638. int ix;
  639. const char *p;
  640. int len;
  641. int count;
  642. int scores = 0;
  643. const espeak_VOICE *v;
  644. const char *lang_name;
  645. char age_buf[12];
  646. const espeak_VOICE **voices;
  647. espeak_VOICE voice_select;
  648. static char genders[4] = {' ','M','F',' '};
  649. if(language[0] == '=')
  650. {
  651. // display only voices for the specified language, in order of priority
  652. voice_select.languages = &language[1];
  653. voice_select.age = 0;
  654. voice_select.gender = 0;
  655. voice_select.name = NULL;
  656. voices = espeak_ListVoices(&voice_select);
  657. scores = 1;
  658. }
  659. else
  660. {
  661. voices = espeak_ListVoices(NULL);
  662. }
  663. fprintf(f_out,"Pty Language Age/Gender VoiceName File Other Langs\n");
  664. for(ix=0; (v = voices[ix]) != NULL; ix++)
  665. {
  666. count = 0;
  667. p = v->languages;
  668. while(*p != 0)
  669. {
  670. len = strlen(p+1);
  671. lang_name = p+1;
  672. if(v->age == 0)
  673. strcpy(age_buf," ");
  674. else
  675. sprintf(age_buf,"%3d",v->age);
  676. if(count==0)
  677. {
  678. fprintf(f_out,"%2d %-12s%s%c %-17s %-11s ",
  679. p[0],lang_name,age_buf,genders[v->gender],v->name,v->identifier);
  680. }
  681. else
  682. {
  683. fprintf(f_out,"(%s %d)",lang_name,p[0]);
  684. }
  685. count++;
  686. p += len+2;
  687. }
  688. // if(scores)
  689. // fprintf(f_out,"%3d ",v->score);
  690. fputc('\n',f_out);
  691. }
  692. } // end of DisplayVoices
  693. char *param_string(char **argp)
  694. {//============================
  695. char *p;
  696. int ix=0;
  697. static char buf[80];
  698. p = *argp;
  699. while(*p == ' ') p++;
  700. while(!isspace(*p))
  701. buf[ix++] = *p++;
  702. buf[ix]=0;
  703. *argp = p;
  704. return(buf);
  705. }
  706. int param_number(char **argp)
  707. {//==========================
  708. int value;
  709. char *p;
  710. p = *argp;
  711. while(*p == ' ') p++;
  712. value = atoi(p);
  713. while(!isspace(*p)) p++;
  714. *argp = p;
  715. return(value);
  716. }
  717. void PrintVersion()
  718. {//================
  719. char buf[120];
  720. printf("\nspeak text-to-speech: %s Data at: %s\n", version_string, path_home);
  721. }
  722. void command_line(char *arg_string, int wait)
  723. {//==========================================
  724. int option_index = 0;
  725. int c;
  726. int value;
  727. int speed;
  728. int amp;
  729. int wordgap;
  730. int speaking = 0;
  731. int flag_stdin = 0;
  732. int flag_compile = 0;
  733. int error;
  734. int pitch_adjustment = 50;
  735. char filename[80];
  736. char voicename[40];
  737. char command[80];
  738. char *p;
  739. int ix;
  740. int quiet;
  741. voicename[0] = 0;
  742. wavefile[0] = 0;
  743. filename[0] = 0;
  744. option_linelength = 0;
  745. option_phonemes = 0;
  746. option_waveout = 0;
  747. quiet = 0;
  748. option_multibyte = 0; // auto
  749. option_capitals = 0;
  750. option_punctuation = 0;
  751. option_punctlist[0] = 0;
  752. f_trans = stdout;
  753. p = arg_string;
  754. for(;;)
  755. {
  756. while(*p==' ') p++; // skip spaces
  757. if(*p == '\r') break; // end of line
  758. if(*p == '-')
  759. {
  760. // a command line argument
  761. p++;
  762. switch(*p++)
  763. {
  764. case 'b':
  765. option_multibyte = espeakCHARS_8BIT;
  766. break;
  767. case 'h':
  768. PrintVersion();
  769. printf("\n%s",help_text);
  770. return;
  771. case 'k':
  772. option_capitals = param_number(&p);
  773. SetParameter(espeakCAPITALS,option_capitals,0);
  774. break;
  775. case 'x':
  776. option_phonemes = 1;
  777. break;
  778. case 'X':
  779. option_phonemes = 2;
  780. break;
  781. case 'm':
  782. option_ssml = 1;
  783. break;
  784. case 'p':
  785. pitch_adjustment = param_number(&p);
  786. break;
  787. case 'q':
  788. quiet = 1;
  789. break;
  790. case 'f':
  791. strncpy0(filename,param_string(&p),sizeof(filename));
  792. break;
  793. case 'l':
  794. option_linelength = param_number(&p);
  795. break;
  796. case 'a':
  797. amp = param_number(&p);
  798. SetParameter(espeakVOLUME,amp,0);
  799. break;
  800. case 's':
  801. speed = param_number(&p);
  802. SetParameter(espeakRATE,speed,0);
  803. break;
  804. case 'g':
  805. wordgap = param_number(&p);
  806. SetParameter(espeakWORDGAP,wordgap,0);
  807. break;
  808. case 'v':
  809. strncpy0(voicename,param_string(&p),sizeof(voicename));
  810. break;
  811. case 'w':
  812. option_waveout=1;
  813. strncpy0(wavefile,param_string(&p),sizeof(wavefile));
  814. break;
  815. case '-':
  816. strncpy0(command,param_string(&p),sizeof(command));
  817. if(memcmp(command,"compile=",8)==0)
  818. {
  819. CompileDictionary(NULL,&command[8],NULL,NULL,0);
  820. return;
  821. }
  822. else
  823. if(memcmp(command,"voices",6)==0)
  824. {
  825. DisplayVoices(stdout,&command[6]);
  826. return;
  827. }
  828. else
  829. if(strcmp(command,"help")==0)
  830. {
  831. PrintVersion();
  832. printf("\n%s",help_text);
  833. return;
  834. }
  835. else
  836. if(memcmp(command,"punct",5)==0)
  837. {
  838. option_punctuation = 1;
  839. if((command[5]=='=') && (command[6]=='"'))
  840. {
  841. ix = 0;
  842. while((ix < N_PUNCTLIST) && ((option_punctlist[ix] = command[ix+7]) != 0)) ix++;
  843. option_punctlist[N_PUNCTLIST-1] = 0;
  844. option_punctuation = 2;
  845. }
  846. SetParameter(espeakPUNCTUATION,option_punctuation,0);
  847. }
  848. else
  849. if(memcmp(command,"version",7)==0)
  850. {
  851. PrintVersion();
  852. return;
  853. }
  854. else
  855. if(memcmp(command,"ipa",3)==0)
  856. {
  857. option_phonemes = 3;
  858. }
  859. else
  860. {
  861. printf("Command not recognised\n");
  862. }
  863. break;
  864. default:
  865. printf("Command not recognised\n");
  866. break;
  867. }
  868. }
  869. else
  870. {
  871. break;
  872. }
  873. }
  874. if((option_phonemes > 1) && !option_waveout)
  875. quiet = 1; // can't call sprintf() during callback
  876. SetVoiceByName(voicename);
  877. if((filename[0]==0) && (p[0]=='\r'))
  878. {
  879. // nothing to speak
  880. if(quiet)
  881. {
  882. SpeakNextClause(NULL,NULL,2); // stop speaking
  883. more_text = 0;
  884. }
  885. }
  886. if(option_waveout || quiet)
  887. {
  888. // write speech to a WAV file
  889. if(quiet)
  890. {
  891. OpenWaveFile(NULL,samplerate);
  892. option_waveout = 2;
  893. }
  894. else
  895. {
  896. if(OpenWaveFile(wavefile,samplerate) != 0)
  897. {
  898. fprintf(stderr,"Can't write to output file '%s'\n'",wavefile);
  899. return;
  900. }
  901. }
  902. }
  903. if(pitch_adjustment != 50)
  904. {
  905. PitchAdjust(pitch_adjustment);
  906. }
  907. WavegenSetVoice(voice);
  908. if(filename[0]==0)
  909. speak_text_string(p,'\r',0,wait,-1);
  910. else
  911. speak_file(filename);
  912. }
  913. _kernel_oserror *command_handler(char *arg_string, int argc, int cmd_no, void *pw)
  914. /********************************************************************************/
  915. {
  916. switch(cmd_no)
  917. {
  918. case 0: /* Say <string> */
  919. command_line(arg_string,0); // for compatibility with speak V2
  920. break;
  921. case 1: /* Sayw <string */
  922. command_line(arg_string,1);
  923. break;
  924. case 2: /* speak [options] [<string>] */
  925. command_line(arg_string,0);
  926. break;
  927. }
  928. return(NULL);
  929. } /* end of cmd_handler */
  930. // sound handler data
  931. int current_sound_handler=0;
  932. int prev_sound_handler=0;
  933. int prev_sound_data=0;
  934. int prev_sound_rate=13;
  935. int sound_handler_changed=0;
  936. void RiscosCloseSound()
  937. {//====================
  938. _kernel_swi_regs regs;
  939. if((sound_handler_changed) && (prev_sound_handler != (int)DMA_Handler))
  940. {
  941. // check whether current handler is ours
  942. regs.r[0]=0;
  943. _kernel_swi(0x40145,&regs,&regs);
  944. if(regs.r[1] == (int)DMA_Handler)
  945. {
  946. regs.r[0]=1;
  947. regs.r[1]=prev_sound_handler;
  948. regs.r[2]=prev_sound_data;
  949. _kernel_swi(0x40145,&regs,&regs); // Sound LinearHandler 1
  950. // reset to the previous sample rate
  951. regs.r[0]=3;
  952. regs.r[1]=prev_sound_rate;
  953. _kernel_swi(0x40146,&regs,&regs); // Sound_SampleRate 3
  954. current_sound_handler = prev_sound_handler;
  955. sound_handler_changed = 0;
  956. }
  957. }
  958. } // end of RiscosCloseSound
  959. void RiscosOpenSound()
  960. {//===================
  961. _kernel_swi_regs regs;
  962. if(current_sound_handler != (int)DMA_Handler)
  963. {
  964. // register the sound handler
  965. regs.r[0]=1;
  966. regs.r[1]=(int)DMA_Handler;
  967. regs.r[2]=(int)module_data;
  968. _kernel_swi(0x40145,&regs,&regs); // Sound_LinearHandler 1
  969. prev_sound_handler = regs.r[1];
  970. prev_sound_data = regs.r[2];
  971. // set the sample rate
  972. regs.r[0]=3;
  973. regs.r[1]=sample_rate_index;
  974. regs.r[2]=0;
  975. _kernel_swi(0x40146,&regs,&regs); // Sound_SampleRate
  976. prev_sound_rate = regs.r[1];
  977. current_sound_handler = (int)DMA_Handler;
  978. sound_handler_changed = 1;
  979. }
  980. } // end of RiscosOpenSound
  981. int callback_handler(_kernel_swi_regs *r, void *pw)
  982. /*************************************************/
  983. {
  984. if(Generate(phoneme_list,&n_phoneme_list,1)==0)
  985. {
  986. more_text = SpeakNextClause(NULL,NULL,1);
  987. }
  988. if((WcmdqUsed() == 0) && (more_text == 0))
  989. {
  990. RiscosCloseSound();
  991. }
  992. callback_inhibit = 0;
  993. return(1);
  994. } /* end of callback_handler */
  995. int sound_handler(_kernel_swi_regs *r, void *pw)
  996. /**********************************************/
  997. {
  998. int n_queue;
  999. int size;
  1000. int *dma_buf;
  1001. int x;
  1002. int ix;
  1003. module_data = (int *)pw;
  1004. dma_buf = (int *)r->r[1];
  1005. size = (r->r[2] - r->r[1])/4;
  1006. FillSoundBuf(size);
  1007. for(ix=0; ix<size; ix++)
  1008. {
  1009. x = SoundBuf[ix];
  1010. dma_buf[ix] = x + (x << 16);
  1011. }
  1012. n_queue = WcmdqUsed();
  1013. r->r[0] = 0;
  1014. if(callback_inhibit == 0)
  1015. {
  1016. // set a callback either:
  1017. // - queue is low and there is more text to be processed
  1018. // - queue is empty and no more text, so callback handler will remove the sound handler
  1019. if(((n_queue < 20) && (more_text != 0)) ||
  1020. ((n_queue==0) && (more_text == 0)))
  1021. {
  1022. callback_inhibit = 1;
  1023. r->r[0] = 1;
  1024. r->r[1] = (int)pw;
  1025. }
  1026. }
  1027. return(1);
  1028. }
  1029. int InitSound16(int sample_rate)
  1030. /******************************/
  1031. /* Find sample rate index */
  1032. {
  1033. int current_rate_index; // current value
  1034. int sound_mode;
  1035. int sound_config;
  1036. int srate;
  1037. int n_srix;
  1038. int ix;
  1039. _kernel_swi_regs regs;
  1040. _kernel_oserror *error;
  1041. sound_mode = 0;
  1042. regs.r[0] = 0;
  1043. error = _kernel_swi(0x40144+os_X,&regs,&regs);
  1044. sound_mode = regs.r[0];
  1045. sound_config = regs.r[1];
  1046. if((error == NULL) && (sound_mode == 1))
  1047. {
  1048. /* 16 bit sound, find sample rate index */
  1049. regs.r[0] = 0;
  1050. regs.r[1] = 0;
  1051. _kernel_swi(0x40146,&regs,&regs);
  1052. n_srix = regs.r[1];
  1053. regs.r[0] = 1;
  1054. regs.r[1] = 0;
  1055. _kernel_swi(0x40146,&regs,&regs);
  1056. current_rate_index = regs.r[1]; // current sample rate index
  1057. srate = regs.r[2];
  1058. for(ix=1; ix<=n_srix; ix++)
  1059. {
  1060. regs.r[0] = 2;
  1061. regs.r[1] = ix;
  1062. _kernel_swi(0x40146,&regs,&regs);
  1063. srate = regs.r[2];
  1064. if(srate >= (sample_rate*1024))
  1065. {
  1066. return(ix);
  1067. }
  1068. }
  1069. }
  1070. return(14); // this was the index for 22050
  1071. } // end of InitSound16
  1072. void RemoveCallback()
  1073. /*******************/
  1074. {
  1075. _kernel_swi_regs regs;
  1076. regs.r[0] = (int)callback_entry;
  1077. regs.r[1] = (int)module_data;
  1078. _kernel_swi(0x5f, &regs, &regs);
  1079. }
  1080. void terminate_module(void)
  1081. /*************************/
  1082. {
  1083. RiscosCloseSound();
  1084. RemoveCallback();
  1085. DeleteTranslator(translator);
  1086. FreePhData();
  1087. } /* end of terminate_module */
  1088. void kill_module(void)
  1089. /********************/
  1090. {
  1091. _kernel_swi_regs regs;
  1092. regs.r[0]=4;
  1093. regs.r[1]=(int)"Speak";
  1094. _kernel_swi(0x1e,&regs,&regs); /* RMKill */
  1095. }
  1096. _kernel_oserror *user_init(char *cmd_fail, int podule_base, void *pw)
  1097. /*******************************************************************/
  1098. {
  1099. _kernel_swi_regs regs;
  1100. _kernel_oserror *error;
  1101. int param;
  1102. // It seems that the wctype functions don't work until the locale has been set
  1103. // to something other than the default "C". Then, not only Latin1 but also the
  1104. // other characters give the correct results with iswalpha() etc.
  1105. static char *locale = "ISO8859-1";
  1106. setlocale(LC_CTYPE,locale);
  1107. module_data = pw;
  1108. sample_rate_index = InitSound16(22050);
  1109. if(initialise() < 0)
  1110. {
  1111. // exit module, errblk.errmess is set by initialise()
  1112. errblk.errnum = 0x101;
  1113. return(&errblk);
  1114. }
  1115. ReadVoiceNames();
  1116. SetVoiceByName("default");
  1117. for(param=0; param<N_SPEECH_PARAM; param++)
  1118. param_stack[0].parameter[param] = param_defaults[param];
  1119. SetParameter(espeakRATE,175,0);
  1120. SetParameter(espeakVOLUME,70,0);
  1121. WavegenSetVoice(voice);
  1122. atexit(terminate_module);
  1123. return(NULL);
  1124. } /* end of user_init */