/native/external/espeak/platforms/riscos/cpp/speak_riscos

http://eyes-free.googlecode.com/ · #! · 1212 lines · 962 code · 250 blank · 0 comment · 0 complexity · f19876894682e2edd0b74e25dbf9e97f MD5 · raw file

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