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