~ubuntu-branches/ubuntu/oneiric/espeak/oneiric

« back to all changes in this revision

Viewing changes to riscos/cpp/speak_riscos

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2006-06-23 08:49:03 UTC
  • Revision ID: james.westby@ubuntu.com-20060623084903-04isef34x9vkavtf
Tags: upstream-1.10
ImportĀ upstreamĀ versionĀ 1.10

Show diffs side-by-side

added added

removed removed

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