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 28KB

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