1
//============================================================================
5
// SS tttttt eeee ll ll aaaa
6
// SSSS tt ee ee ll ll aa
7
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8
// SS SS tt ee ll ll aa aa
9
// SSSS ttt eeeee llll llll aaaaa
11
// Copyright (c) 1995-2008 by Bradford W. Mott and the Stella team
13
// See the file "license" for information on usage and redistribution of
14
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16
// $Id: SpeakJet.cxx,v 1.9 2008/03/31 00:59:30 stephena Exp $
17
//============================================================================
19
#ifdef SPEAKJET_EMULATION
21
#include "SpeakJet.hxx"
23
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
26
// Initialize output buffers. Each one points to the next element,
27
// except the last, which points back to the first.
28
SpeechBuffer *first = &outputBuffers[0];
29
SpeechBuffer *last = 0;
30
for(int i=0; i<SPEECH_BUFFERS; i++) {
31
SpeechBuffer *sb = &outputBuffers[i];
33
sb->lock = SDL_CreateSemaphore(1);
41
myCurrentOutputBuffer = ourCurrentWriteBuffer = first;
42
ourCurrentWritePosition = 0;
44
// Init rsynth library
45
darray_init(&rsynthSamples, sizeof(short), 2048);
48
rsynth = rsynth_init(samp_rate, mSec_per_frame,
49
rsynth_speaker(F0Hz, gain, Elements),
50
save_sample, flush_samples, &samples);
52
rsynth = rsynth_init(31400, 10.0,
53
rsynth_speaker(133.0, 57, Elements),
54
save_sample, flush_samples, &rsynthSamples);
58
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
63
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
64
void SpeakJet::spawnThread()
66
ourInputSemaphore = SDL_CreateSemaphore(1); // 1==unlocked
67
uInt32 sem = SDL_SemValue(ourInputSemaphore);
68
cerr << "before SDL_CreateThread(), sem==" << sem << endl;
69
ourThread = SDL_CreateThread(thread, 0);
70
sem = SDL_SemValue(ourInputSemaphore);
71
cerr << "after SDL_CreateThread(), sem==" << sem << endl;
74
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
75
int SpeakJet::thread(void *data) {
76
cerr << "rsynth thread spawned" << endl;
84
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
85
void SpeakJet::write(uInt8 code)
87
cerr << "SpeakJet: output byte " << ((int)(code)) << endl;
89
// TODO: clean up this mess.
90
const char *rsynthPhones = xlatePhoneme(code);
91
// cerr << "rsynth: \"" << rsynthPhones << "\"" << endl;
92
int len = strlen(rsynthPhones);
94
if(ourInputCount + len + 1 >= INPUT_BUFFER_SIZE) {
95
cerr << "phonemeBuffer is full, dropping" << endl;
99
uInt32 sem = SDL_SemValue(ourInputSemaphore);
100
// cerr << "write() waiting on semaphore (value " << sem << ")" << endl;
101
SDL_SemWait(ourInputSemaphore);
102
// cerr << "write() got semaphore" << endl;
103
for(int i=0; i<len; i++)
104
phonemeBuffer[ourInputCount++] = rsynthPhones[i];
105
phonemeBuffer[ourInputCount] = '\0';
106
// cerr << "phonemeBuffer contains \"" << phonemeBuffer << "\"" << endl;
107
// cerr << "write() releasing semaphore" << endl;
108
SDL_SemPost(ourInputSemaphore);
111
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
112
void SpeakJet::speak()
114
// TODO: clean up this mess.
115
static char myInput[INPUT_BUFFER_SIZE];
120
uInt32 sem = SDL_SemValue(ourInputSemaphore);
121
// cerr << "speak() waiting on semaphore (value " << sem << ")" << endl;
122
SDL_SemWait(ourInputSemaphore);
123
// cerr << "speak() got semaphore" << endl;
125
// begin locked section
127
bool foundSpace = false;
128
for(int i=0; i<ourInputCount; i++)
129
if( (myInput[i] = phonemeBuffer[i]) == ' ')
132
if(ourInputCount >= INPUT_BUFFER_SIZE - 5)
138
// end locked section
139
// cerr << "speak() releasing semaphore" << endl;
140
SDL_SemPost(ourInputSemaphore);
144
// Lock current buffer. save_sample will unlock it when it gets full.
145
SDL_SemWait(ourCurrentWriteBuffer->lock);
146
rsynth_phones(rsynth, myInput, strlen(myInput));
150
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
151
const char *SpeakJet::xlatePhoneme(uInt8 code)
156
if(code >= 128 && code <= 199)
157
return ourPhonemeTable[ code - 128 ];
162
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
163
uInt8 *SpeakJet::getSamples(int *count) {
164
static uInt8 contents[OUTPUT_BUFFER_SIZE];
165
SDL_sem *lock = myCurrentOutputBuffer->lock;
167
*count = myCurrentOutputBuffer->items;
168
for(int i=0; i<*count; i++)
169
contents[i] = myCurrentOutputBuffer->contents[i];
170
myCurrentOutputBuffer->items = 0;
171
myCurrentOutputBuffer = myCurrentOutputBuffer->next;
176
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
177
bool SpeakJet::chipReady()
182
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
183
void *SpeakJet::save_sample(void *user_data,
188
static long clip_max;
193
darray_t *buf = (darray_t *) user_data;
194
shortSamp = clip(&clip_max, sample, &peak);
195
darray_short(buf, shortSamp);
198
// output = (uInt8)( (((float)shortSamp) + 32768.0) / 256.0 );
199
double d = shortSamp + 32768.0;
200
output = (uInt8)(d/256.0);
201
// cerr << "Output sample: " << ((int)(output)) << endl;
204
ourCurrentWriteBuffer->contents[ourCurrentWritePosition++] = output;
205
ourCurrentWriteBuffer->items = ourCurrentWritePosition;
207
// If buffer is full, unlock it and use the next one.
208
if(ourCurrentWritePosition == OUTPUT_BUFFER_SIZE)
210
SDL_SemWait(ourCurrentWriteBuffer->next->lock);
211
SDL_SemPost(ourCurrentWriteBuffer->lock);
212
ourCurrentWriteBuffer = ourCurrentWriteBuffer->next;
213
ourCurrentWriteBuffer->items = ourCurrentWritePosition = 0;
218
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
219
void *SpeakJet::flush_samples(void *user_data,
223
darray_t *buf = (darray_t *) user_data;
225
for (;ourCurrentWritePosition < OUTPUT_BUFFER_SIZE; ourCurrentWritePosition++)
226
ourCurrentWriteBuffer->contents[ourCurrentWritePosition] = 0;
227
ourCurrentWritePosition = 0;
228
SDL_SemPost(ourCurrentWriteBuffer->lock);
229
ourCurrentWriteBuffer = ourCurrentWriteBuffer->next; // NOT locked
233
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
234
short SpeakJet::clip(long *clip_max, float input, float *peak)
236
long temp = (long) input;
237
float isq = input * input;
244
if (-temp > *clip_max)
246
if (temp > *clip_max)
251
else if (temp > 32767) {
258
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
261
Table of rsynth phonemes, indexed by SpeakJet phoneme code number.
262
Table is offset by 128 bytes (ourPhonemeTable[0] is code #128)
263
see rsynth/phones.def for definitions of rsynth phonemes.
264
We prefix a "'" to the rsynth phoneme for stress or a ","
266
FIXME: This will need a lot of tweaking, once I get a real
267
SpeakJet to test with.
270
const char *SpeakJet::ourPhonemeTable[] = {
271
//"rsynth phoneme(s) (phones.def)", // SJ phonemes (p. 16 in SJ manual)
272
"i:", // 128 IY See, Even, Feed
273
"I", // 129 IH Sit, Fix, Pin
274
"eI", // 130 EY Hair, Gate, Beige
275
"E", // 131 EH Met, Check, Red
276
"{", // 132 AY Hat, Fast, Fan
277
"A:", // 133 AX Cotten // maybe "@" instead?
278
"V", // 134 UX Luck, Up, Uncle
279
"Q", // 135 OH Hot, Clock, Fox
280
"A:", // 136 AW Father, Fall
281
"oU", // 137 OW Comb, Over, Hold
282
"U", // 138 UH Book, Could, Should
283
"u:", // 139 UW Food, June
284
"m", // 140 MM Milk, Famous,
285
"n", // 141 NE Nip, Danger, Thin
286
"n", // 142 NO No, Snow, On
287
"N", // 143 NGE Think, Ping
288
"N", // 144 NGO Hung, Song
289
"l", // 145 LE Lake, Alarm, Lapel
290
"l", // 146 LO Clock, Plus, Hello
291
"w", // 147 WW Wool, Sweat
292
"r", // 148 RR Ray, Brain, Over
293
"I@", // 149 IYRR Clear, Hear, Year
294
"e@", // 150 EYRR Hair, Stair, Repair
295
"3:", // 151 AXRR Fir, Bird, Burn
296
"A:", // 152 AWRR Part, Farm, Yarn
297
"Qr", // 153 OWRR Corn, Four, Your [*]
298
"eI", // 154 EYIY Gate, Ate, Ray
299
"aI", // 155 OHIY Mice, Fight, White
300
"OI", // 156 OWIY Boy, Toy, Voice
301
"aI", // 157 OHIH Sky, Five, I
302
"j", // 158 IYEH Yes, Yarn, Million
303
"el", // 159 EHLL Saddle, Angle, Spell [*]
304
"U@", // 160 IYUW Cute, Few // maybe u
305
"aU", // 161 AXUW Brown, Clown, Thousan
306
"U@", // 162 IHWW Two, New, Zoo
307
"aU", // 163 AYWW Our, Ouch, Owl
308
"@U", // 164 OWWW Go, Hello, Snow // maybe "oU"?
309
"dZ", // 165 JH Dodge, Jet, Savage
310
"v", // 166 VV Vest, Even,
311
"z", // 167 ZZ Zoo, Zap
312
"Z", // 168 ZH Azure, Treasure
313
"D", // 169 DH There, That, This
314
"b", // 170 BE Bear, Bird, Beed ???
315
"b", // 171 BO Bone, Book Brown ???
316
"b", // 172 EB Cab, Crib, Web ???
317
"b", // 173 OB Bob, Sub, Tub ???
318
"d", // 174 DE Deep, Date, Divide ???
319
"d", // 175 DO Do, Dust, Dog ???
320
"d", // 176 ED Could, Bird ???
321
"d", // 177 OD Bud, Food ???
322
"g", // 178 GE Get, Gate, Guest, ???
323
"g", // 179 GO Got, Glue, Goo ???
324
"g", // 180 EG Peg, Wig ???
325
"g", // 181 OG Dog, Peg ???
326
"tS", // 182 CH Church, Feature, March
327
"h", // 183 HE Help, Hand, Hair
328
"h", // 184 HO Hoe, Hot, Hug
329
"hw", // 185 WH Who, Whale, White [*]
330
"f", // 186 FF Food, Effort, Off
331
"s", // 187 SE See, Vest, Plus
332
"s", // 188 SO So, Sweat ???
333
"S", // 189 SH Ship, Fiction, Leash
334
"T", // 190 TH Thin, month
335
"t", // 191 TT Part, Little, Sit
336
"t", // 192 TU To, Talk, Ten
337
"ts", // 193 TS Parts, Costs, Robots
338
"k", // 194 KE Can't, Clown, Key
339
"k", // 195 KO Comb, Quick, Fox ???
340
"k", // 196 EK Speak, Task ???
341
"k", // 197 OK Book, Took, October ???
342
"p", // 198 PE People, Computer
343
"p" // 199 PO Paw, Copy ???