1 /*
2 vlm5030.c
3
4 VLM5030 emulator (preliminary)
5
6 Written by Tatsuyuki Satoh
7
8 note:
9 memory read cycle(sampling rate ?) = 122.9u(440clock)
10 interpolator (LC8109 = 2.5ms) = 20 * samples(125us)
11 frame time (20ms) = 8 * interpolator
12
13 ----------- command format (Analytical result) ----------
14
15 1)end of speech (8bit)
16 :00000011:
17
18 2)silent some frame (8bit)
19 :????LL01:
20
21 LL : number of silent frames
22 00 = 2 frame
23 01 = 4 frame
24 10 = 6 frame
25 11 = 8 frame
26
27 3)play one frame (48bit/frame)
28 : 1st : 2nd : 3rd : 4th : 5th : 6th :
29 :EEPPPPP0:99AAAEEE:67778889:44455566:22233334:11111112:
30
31 energy and pitch bits are MSB first.
32
33 EEEEE : energy ( volume 0=off,0x1f=max)
34 PPPPP : pitch (0=noize?, 1=fast,0x1f=slow)
35 1111111: stage 1?
36 2222 : stage 2?
37 3333 : stage 3?
38 4444 : stage 4?
39 555 : stage 5?
40 666 : stage 6?
41 777 : stage 7?
42 888 : stage 8?
43 999 : stage 9?
44 AAA : stage 10?
45
46 ---------- chirp table information ----------
47
48 digital filter sampling rate = 88 systemclock = 40.6KHz
49 sampling clock = 88systemclock(40.6KHz)
50 one chirp = 5 sampling clocks = 440systemclock(8.12KHz)
51
52 chirp 0 : volume 10- 8 : with filter
53 chirp 1 : volume 8- 6 : with filter
54 chirp 2 : volume 6- 4 : with filter
55 chirp 3 : volume 4 : no filter ??
56 chirp 4- 5: volume 4- 2 : with filter
57 chirp 6-11: volume 2- 0 : with filter
58 chirp 12-..: vokume 0 : silent
59
60 ---------- pitch table information ----------
61 0 = random
62 1 = 22stage(2700usec)
63 2-09 1stage(120usec)
64 0a-11 2stage(240usec)
65 12-19 4stage(480usec)
66 1A-1E 8stage(960usec)
67
68 */
69 #include "driver.h"
70 #include "vlm5030.h"
71
72 #define IP_SIZE 20 /* samples per interpolator */
73 #define FR_SIZE 8 /* interpolator per frame */
74
75 static const struct VLM5030interface *intf;
76
77 static int channel;
78 static int schannel;
79
80 static unsigned char *VLM5030_rom;
81 static int VLM5030_address_mask;
82 static int VLM5030_address;
83 static int pin_BSY;
84 static int pin_ST;
85 static int pin_RST;
86 static int latch_data = 0;
87 static int sampling_mode;
88
89 static int table_h;
90
91 #define PH_RESET 0
92 #define PH_IDLE 1
93 #define PH_SETUP 2
94 #define PH_WAIT 3
95 #define PH_RUN 4
96 #define PH_STOP 5
97 static int phase;
98
99 /* these contain data describing the current and previous voice frames */
100 static unsigned short old_energy = 0;
101 static unsigned short old_pitch = 0;
102 static int old_k[10] = {0,0,0,0,0,0,0,0,0,0};
103
104 static unsigned short new_energy = 0;
105 static unsigned short new_pitch = 0;
106 static int new_k[10] = {0,0,0,0,0,0,0,0,0,0};
107
108 /* these are all used to contain the current state of the sound generation */
109 static unsigned short current_energy = 0;
110 static unsigned short current_pitch = 0;
111 static int current_k[10] = {0,0,0,0,0,0,0,0,0,0};
112
113 static unsigned short target_energy = 0;
114 static unsigned short target_pitch = 0;
115 static int target_k[10] = {0,0,0,0,0,0,0,0,0,0};
116
117 static int interp_count = 0; /* number of interp periods (0-7) */
118 static int sample_count = 0; /* sample number within interp (0-19) */
119 static int pitch_count = 0;
120
121 static int u[11] = {0,0,0,0,0,0,0,0,0,0,0};
122 static int x[10] = {0,0,0,0,0,0,0,0,0,0};
123
124 /* ROM Tables */
125
126
127 /* This is the energy lookup table */
128 /* !!!!!!!!!! preliminary !!!!!!!!!! */
129 static unsigned short energytable[0x20];
130
131 /* This is the pitch lookup table */
132 static const unsigned char pitchtable [0x20]=
133 {
134 0, /* 0 : random mode */
135 22, /* 1 : start=22 */
136 23, 24, 25, 26, 27, 28, 29, 30, /* 2- 9 : 1step */
137 32, 34, 36, 38, 40, 42, 44, 46, /* 10-17 : 2step */
138 50, 54, 58, 62, 66, 70, 74, 78, /* 18-25 : 4step */
139 86, 94, 102,110,118, /* 26-30 : 8step */
140 255 /* 31 : only one time ?? */
141 };
142
143 /* These are the reflection coefficient lookup tables */
144 /* 2's comp. */
145
146 /* !!!!!!!!!! preliminary !!!!!!!!!! */
147
148 /* 7bit */
149 #define K1_RANGE 0x6000
150 /* 4bit */
151 #define K2_RANGE 0x4000
152 #define K3_RANGE 0x6000
153 #define K4_RANGE 0x4000
154 /* 3bit */
155 #define K5_RANGE 0x6000
156 #define K6_RANGE 0x6000
157 #define K7_RANGE 0x5000
158 #define K8_RANGE 0x4000
159 #define K9_RANGE 0x5000
160 #define K10_RANGE 0x4000
161
162 static int k1table[0x80];
163 static int k2table[0x10];
164 static int k3table[0x10];
165 static int k4table[0x10];
166 static int k5table[0x08];
167 static int k6table[0x08];
168 static int k7table[0x08];
169 static int k8table[0x08];
170 static int k9table[0x08];
171 static int k10table[0x08];
172
173 /* chirp table */
174 static unsigned char chirptable[12]=
175 {
176 0xff*9/10,
177 0xff*7/10,
178 0xff*5/10,
179 0xff*4/10, /* non digital filter ? */
180 0xff*3/10,
181 0xff*3/10,
182 0xff*1/10,
183 0xff*1/10,
184 0xff*1/10,
185 0xff*1/10,
186 0xff*1/10,
187 0xff*1/10
188 };
189
190 /* interpolation coefficients */
191 static int interp_coeff[8] = {
192 //8, 8, 8, 4, 4, 2, 2, 1
193 8, 8, 8, 4, 4, 2, 2, 1
194 };
195
196 /* //////////////////////////////////////////////////////// */
197
198 /* check sample file */
check_samplefile(int num)199 static int check_samplefile(int num)
200 {
201 if (Machine->samples == 0) return 0;
202 if (Machine->samples->total <= num ) return 0;
203 if (Machine->samples->sample[num] == 0) return 0;
204 /* sample file is found */
205 return 1;
206 }
207
get_bits(int sbit,int bits)208 static int get_bits(int sbit,int bits)
209 {
210 int offset = VLM5030_address + (sbit>>3);
211 int data;
212
213 data = VLM5030_rom[offset&VLM5030_address_mask] |
214 (((int)VLM5030_rom[(offset+1)&VLM5030_address_mask])<<8);
215 data >>= sbit;
216 data &= (0xff>>(8-bits));
217
218 return data;
219 }
220
221 /* get next frame */
parse_frame(void)222 static int parse_frame (void)
223 {
224 unsigned char cmd;
225
226 /* remember previous frame */
227 old_energy = new_energy;
228 old_pitch = new_pitch;
229 memcpy( old_k , new_k , sizeof(old_k) );
230 /* command byte check */
231 cmd = VLM5030_rom[VLM5030_address&VLM5030_address_mask];
232 if( cmd & 0x01 )
233 { /* extend frame */
234 new_energy = new_pitch = 0;
235 memset( new_k , 0 , sizeof(new_k));
236 VLM5030_address++;
237 if( cmd & 0x02 )
238 { /* end of speech */
239 logerror("VLM5030 %04X end \n",VLM5030_address );
240 return 0;
241 }
242 else
243 { /* silent frame */
244 int nums = ( (cmd>>2)+1 )*2;
245 logerror("VLM5030 %04X silent %d frame\n",VLM5030_address,nums );
246 return nums * FR_SIZE;
247 }
248 }
249 /* normal frame */
250
251 new_pitch = pitchtable[get_bits( 1,5)];
252 new_energy = energytable[get_bits( 6,5)] >> 6;
253
254 /* 10 K's */
255 new_k[9] = k10table[get_bits(11,3)];
256 new_k[8] = k9table[get_bits(14,3)];
257 new_k[7] = k8table[get_bits(17,3)];
258 new_k[6] = k7table[get_bits(20,3)];
259 new_k[5] = k6table[get_bits(23,3)];
260 new_k[4] = k5table[get_bits(26,3)];
261 new_k[3] = k4table[get_bits(29,4)];
262 new_k[2] = k3table[get_bits(33,4)];
263 new_k[1] = k2table[get_bits(37,4)];
264 new_k[0] = k1table[get_bits(41,7)];
265
266 VLM5030_address+=6;
267 logerror("VLM5030 %04X voice \n",VLM5030_address );
268 return FR_SIZE;
269 }
270
271 /* decode and buffering data */
vlm5030_update_callback(int num,INT16 * buffer,int length)272 static void vlm5030_update_callback(int num,INT16 *buffer, int length)
273 {
274 int buf_count=0;
275 int interp_effect;
276
277 /* running */
278 if( phase == PH_RUN )
279 {
280 /* playing speech */
281 while (length > 0)
282 {
283 int current_val;
284
285 /* check new interpolator or new frame */
286 if( sample_count == 0 )
287 {
288 sample_count = IP_SIZE;
289 /* interpolator changes */
290 if ( interp_count == 0 )
291 {
292 /* change to new frame */
293 interp_count = parse_frame(); /* with change phase */
294 if ( interp_count == 0 )
295 {
296 sample_count = 160; /* end -> stop time */
297 phase = PH_STOP;
298 goto phase_stop; /* continue to stop phase */
299 }
300 /* Set old target as new start of frame */
301 current_energy = old_energy;
302 current_pitch = old_pitch;
303 memcpy( current_k , old_k , sizeof(current_k) );
304 /* is this a zero energy frame? */
305 if (current_energy == 0)
306 {
307 /*printf("processing frame: zero energy\n");*/
308 target_energy = 0;
309 target_pitch = current_pitch;
310 memcpy( target_k , current_k , sizeof(target_k) );
311 }
312 else
313 {
314 /*printf("processing frame: Normal\n");*/
315 /*printf("*** Energy = %d\n",current_energy);*/
316 /*printf("proc: %d %d\n",last_fbuf_head,fbuf_head);*/
317 target_energy = new_energy;
318 target_pitch = new_pitch;
319 memcpy( target_k , new_k , sizeof(target_k) );
320 }
321 }
322 /* next interpolator */
323 /* Update values based on step values */
324 /*printf("\n");*/
325 interp_effect = (int)(interp_coeff[(FR_SIZE-1) - (interp_count%FR_SIZE)]);
326
327 current_energy += (target_energy - current_energy) / interp_effect;
328 if (old_pitch != 0)
329 current_pitch += (target_pitch - current_pitch) / interp_effect;
330 /*printf("*** Energy = %d\n",current_energy);*/
331 current_k[0] += (target_k[0] - current_k[0]) / interp_effect;
332 current_k[1] += (target_k[1] - current_k[1]) / interp_effect;
333 current_k[2] += (target_k[2] - current_k[2]) / interp_effect;
334 current_k[3] += (target_k[3] - current_k[3]) / interp_effect;
335 current_k[4] += (target_k[4] - current_k[4]) / interp_effect;
336 current_k[5] += (target_k[5] - current_k[5]) / interp_effect;
337 current_k[6] += (target_k[6] - current_k[6]) / interp_effect;
338 current_k[7] += (target_k[7] - current_k[7]) / interp_effect;
339 current_k[8] += (target_k[8] - current_k[8]) / interp_effect;
340 current_k[9] += (target_k[9] - current_k[9]) / interp_effect;
341 interp_count --;
342 }
343 /* calcrate digital filter */
344 if (old_energy == 0)
345 {
346 /* generate silent samples here */
347 current_val = 0x00;
348 }
349 else if (old_pitch == 0)
350 {
351 /* generate unvoiced samples here */
352 int randvol = (rand () % 10);
353 current_val = (randvol * current_energy) / 10;
354 }
355 else
356 {
357 /* generate voiced samples here */
358 if (pitch_count < sizeof (chirptable))
359 current_val = (chirptable[pitch_count] * current_energy) / 256;
360 else
361 current_val = 0x00;
362 }
363
364 /* Lattice filter here */
365 u[10] = current_val;
366 u[9] = u[10] - ((current_k[9] * x[9]) / 32768);
367 u[8] = u[ 9] - ((current_k[8] * x[8]) / 32768);
368 u[7] = u[ 8] - ((current_k[7] * x[7]) / 32768);
369 u[6] = u[ 7] - ((current_k[6] * x[6]) / 32768);
370 u[5] = u[ 6] - ((current_k[5] * x[5]) / 32768);
371 u[4] = u[ 5] - ((current_k[4] * x[4]) / 32768);
372 u[3] = u[ 4] - ((current_k[3] * x[3]) / 32768);
373 u[2] = u[ 3] - ((current_k[2] * x[2]) / 32768);
374 u[1] = u[ 2] - ((current_k[1] * x[1]) / 32768);
375 u[0] = u[ 1] - ((current_k[0] * x[0]) / 32768);
376
377 x[9] = x[8] + ((current_k[8] * u[8]) / 32768);
378 x[8] = x[7] + ((current_k[7] * u[7]) / 32768);
379 x[7] = x[6] + ((current_k[6] * u[6]) / 32768);
380 x[6] = x[5] + ((current_k[5] * u[5]) / 32768);
381 x[5] = x[4] + ((current_k[4] * u[4]) / 32768);
382 x[4] = x[3] + ((current_k[3] * u[3]) / 32768);
383 x[3] = x[2] + ((current_k[2] * u[2]) / 32768);
384 x[2] = x[1] + ((current_k[1] * u[1]) / 32768);
385 x[1] = x[0] + ((current_k[0] * u[0]) / 32768);
386 x[0] = u[0];
387 /* clipping, buffering */
388 if (u[0] > 511)
389 buffer[buf_count] = 127<<8;
390 else if (u[0] < -512)
391 buffer[buf_count] = -128<<8;
392 else
393 buffer[buf_count] = u[0] << 6;
394 buf_count++;
395
396 /* sample count */
397 sample_count--;
398 /* pitch */
399 pitch_count++;
400 if (pitch_count >= current_pitch )
401 pitch_count = 0;
402 /* size */
403 length--;
404 }
405 /* return;*/
406 }
407 /* stop phase */
408 phase_stop:
409 switch( phase )
410 {
411 case PH_SETUP:
412 sample_count -= length;
413 if( sample_count <= 0 )
414 {
415 logerror("VLM5030 BSY=H\n" );
416 /* pin_BSY = 1; */
417 phase = PH_WAIT;
418 }
419 break;
420 case PH_STOP:
421 sample_count -= length;
422 if( sample_count <= 0 )
423 {
424 logerror("VLM5030 BSY=L\n" );
425 pin_BSY = 0;
426 phase = PH_IDLE;
427 }
428 }
429 /* silent buffering */
430 while (length > 0)
431 {
432 buffer[buf_count++] = 0x00;
433 length--;
434 }
435 }
436
437 /* realtime update */
VLM5030_update(void)438 static void VLM5030_update(void)
439 {
440 if( !sampling_mode )
441 {
442 /* docode mode */
443 stream_update(channel,0);
444 }
445 else
446 {
447 /* sampling mode (check busy flag) */
448 if( pin_ST == 0 && pin_BSY == 1 )
449 {
450 if( !mixer_is_sample_playing(schannel) )
451 pin_BSY = 0;
452 }
453 }
454 }
455
456 /* set speech rom address */
VLM5030_set_rom(void * speech_rom)457 void VLM5030_set_rom(void *speech_rom)
458 {
459 VLM5030_rom = (unsigned char*)speech_rom;
460 }
461
462 /* get BSY pin level */
VLM5030_BSY(void)463 int VLM5030_BSY(void)
464 {
465 VLM5030_update();
466 return pin_BSY;
467 }
468
469 /* latch contoll data */
WRITE_HANDLER(VLM5030_data_w)470 WRITE_HANDLER( VLM5030_data_w )
471 {
472 latch_data = data;
473 }
474
475 /* set RST pin level : reset / set table address A8-A15 */
VLM5030_RST(int pin)476 void VLM5030_RST (int pin )
477 {
478 if( pin_RST )
479 {
480 if( !pin )
481 { /* H -> L : latch high address table */
482 pin_RST = 0;
483 /* table_h = latch_data * 256; */
484 table_h = 0;
485 }
486 }
487 else
488 {
489 if( pin )
490 { /* L -> H : reset chip */
491 pin_RST = 1;
492 if( pin_BSY )
493 {
494 if( sampling_mode )
495 mixer_stop_sample( schannel );
496 phase = PH_RESET;
497 pin_BSY = 0;
498 }
499 }
500 }
501 }
502
503 /* set VCU pin level : ?? unknown */
VLM5030_VCU(int pin)504 void VLM5030_VCU(int pin)
505 {
506 /* unknown */
507 /* intf->vcu = pin; */
508 return;
509 }
510
511 /* set ST pin level : set table address A0-A7 / start speech */
VLM5030_ST(int pin)512 void VLM5030_ST(int pin )
513 {
514 int table = table_h | latch_data;
515
516 if( pin_ST != pin )
517 {
518 /* pin level is change */
519 if( !pin )
520 { /* H -> L */
521 pin_ST = 0;
522 /* start speech */
523
524 if (Machine->sample_rate == 0)
525 {
526 pin_BSY = 0;
527 return;
528 }
529 /* set play mode samplingfile or emulate */
530 sampling_mode = check_samplefile(table/2);
531 if( !sampling_mode )
532 {
533 VLM5030_update();
534
535 logerror("VLM5030 %02X start adr=%04X\n",table/2,VLM5030_address );
536
537 /* docode mode */
538 VLM5030_address = (((int)VLM5030_rom[table&VLM5030_address_mask])<<8)
539 | VLM5030_rom[(table+1)&VLM5030_address_mask];
540 /* reset process status */
541 interp_count = sample_count = 0;
542 /* clear filter */
543 /* after 3 sampling start */
544 phase = PH_RUN;
545 }
546 else
547 {
548 /* sampling mode */
549 int num = table>>1;
550
551 mixer_play_sample(schannel,
552 Machine->samples->sample[num]->data,
553 Machine->samples->sample[num]->length,
554 Machine->samples->sample[num]->smpfreq,
555 0);
556 }
557 }
558 else
559 { /* L -> H */
560 pin_ST = 1;
561 /* setup speech , BSY on after 30ms? */
562 phase = PH_SETUP;
563 sample_count = 1; /* wait time for busy on */
564 pin_BSY = 1; /* */
565 }
566 }
567 }
568
569 /* start VLM5030 with sound rom */
570 /* speech_rom == 0 -> use sampling data mode */
VLM5030_sh_start(const struct MachineSound * msound)571 int VLM5030_sh_start(const struct MachineSound *msound)
572 {
573 int emulation_rate;
574
575 intf = (const struct VLM5030interface*)msound->sound_interface;
576
577 Machine->samples = readsamples(intf->samplenames,Machine->gamedrv->name);
578
579 emulation_rate = intf->baseclock / 440;
580 pin_BSY = pin_RST = pin_ST = 0;
581 phase = PH_IDLE;
582 /* VLM5030_VCU(intf->vcu); */
583
584 VLM5030_rom = memory_region(intf->memory_region);
585 /* memory size */
586 if( intf->memory_size == 0)
587 VLM5030_address_mask = memory_region_length(intf->memory_region)-1;
588 else
589 VLM5030_address_mask = intf->memory_size-1;
590
591 channel = stream_init("VLM5030",intf->volume,emulation_rate /* Machine->sample_rate */,
592 0,vlm5030_update_callback);
593 if (channel == -1) return 1;
594
595 schannel = mixer_allocate_channel(intf->volume);
596
597 #if 1
598 {
599 int i;
600
601 /* initialize energy table */
602 for(i=0;i<0x20;i++)
603 {
604 energytable[i]=0x7fff*i/0x1f;
605 }
606
607 /* initialize filter table */
608 for(i=-0x40 ; i<0x40 ; i++)
609 {
610 k1table[(i>=0) ? i : i+0x80] = i*K1_RANGE/0x40;
611 }
612 for(i=-0x08 ; i<0x08 ; i++)
613 {
614 k2table[(i>=0) ? i : i+0x10] = i*K2_RANGE/0x08;
615 k3table[(i>=0) ? i : i+0x10] = i*K3_RANGE/0x08;
616 k4table[(i>=0) ? i : i+0x10] = i*K4_RANGE/0x08;
617 }
618 for(i=-0x04 ; i<0x04 ; i++)
619 {
620 k5table[(i>=0) ? i : i+0x08] = i*K5_RANGE/0x04;
621 k6table[(i>=0) ? i : i+0x08] = i*K6_RANGE/0x04;
622 k7table[(i>=0) ? i : i+0x08] = i*K7_RANGE/0x04;
623 k8table[(i>=0) ? i : i+0x08] = i*K8_RANGE/0x04;
624 k9table[(i>=0) ? i : i+0x08] = i*K9_RANGE/0x04;
625 k10table[(i>=0) ? i : i+0x08] = i*K10_RANGE/0x04;
626 }
627
628 }
629 #endif
630 return 0;
631 }
632
633 /* update VLM5030 */
VLM5030_sh_update(void)634 void VLM5030_sh_update( void )
635 {
636 VLM5030_update();
637 }
638
639 /* stop VLM5030 */
VLM5030_sh_stop(void)640 void VLM5030_sh_stop( void )
641 {
642 }
643