1 /****************************************************************************
2 *
3 * Phoenix sound hardware simulation - still very ALPHA!
4 *
5 * If you find errors or have suggestions, please mail me.
6 * Juergen Buchmueller <pullmoll@t-online.de>
7 *
8 ****************************************************************************/
9
10
11 #include <math.h>
12 #include "driver.h"
13
14 /****************************************************************************
15 * 4006
16 * Dual 4-bit and dual 5-bit serial-in serial-out shift registers.
17 *
18 * +----------+
19 * 1D5 |1 +--+ 14| VCC
20 * /1Q4 |2 13| 1Q1
21 * CLK |3 12| 2Q0
22 * 2D4 |4 4006 11| 2Q0
23 * 3D4 |5 10| 3Q0
24 * 4D5 |6 9| 4Q0
25 * GND |7 8| 4Q1
26 * +----------+
27 *
28 * [This information is part of the GIICM]
29 *
30 * Pin 8 and 9 are connected to an EXOR gate and the inverted
31 * output (EXNOR) is fed back to pin 1 (and the pseudo polynome output).
32 *
33 * 1D5 1Q1 2D4 2Q0 3D4 3Q0 4D5 4Q1 4Q0
34 * +--+--+--+--+--+ +--+--+--+--+ +--+--+--+--+ +--+--+--+--+--+
35 * +->| 0| 1| 2| 3| 4|->| 5| 6| 7| 8|->| 9|10|11|12|->|13|14|15|16|17|
36 * | +--+--+--+--+--+ +--+--+--+--+ +--+--+--+--+ +--+--+--+--+--+
37 * | ____ | |
38 * | / |------------+ |
39 * +-----------------------------------------|EXNOR| |
40 * \____|---------------+
41 *
42 ****************************************************************************/
43
44 #define VMIN 0
45 #define VMAX 32767
46
47 static int sound_latch_a;
48 static int sound_latch_b;
49
50 static int channel;
51
52 static int tone1_vco1_cap;
53 static int tone1_level;
54 static int tone2_level;
55
56 static UINT32 *poly18 = NULL;
57
tone1_vco1(int samplerate)58 static INLINE int tone1_vco1(int samplerate)
59 {
60 static int output, counter, level;
61 /*
62 * L447 (NE555): Ra=47k, Rb=100k, C = 0.01uF, 0.48uF, 1.01uF or 1.48uF
63 * charge times = 0.639*(Ra+Rb)*C = 0.0092s, 0.0451s, 0.0949s, 0.1390s
64 * discharge times = 0.639*Rb*C = 0.0064s, 0.0307s, 0.0645s, 0.0946s
65 */
66 #define C18a 0.01e-6
67 #define C18b 0.48e-6
68 #define C18c 1.01e-6
69 #define C18d 1.48e-6
70 #define R40 47000
71 #define R41 100000
72 static int rate[2][4] = {
73 {
74 VMAX*2/3/(0.693*(R40+R41)*C18a),
75 VMAX*2/3/(0.693*(R40+R41)*C18b),
76 VMAX*2/3/(0.693*(R40+R41)*C18c),
77 VMAX*2/3/(0.693*(R40+R41)*C18d)
78 },
79 {
80 VMAX*2/3/(0.693*R41*C18a),
81 VMAX*2/3/(0.693*R41*C18b),
82 VMAX*2/3/(0.693*R41*C18c),
83 VMAX*2/3/(0.693*R41*C18d)
84 }
85 };
86 if( output )
87 {
88 if (level > VMAX*1/3)
89 {
90 counter -= rate[1][tone1_vco1_cap];
91 if( counter <= 0 )
92 {
93 int steps = -counter / samplerate + 1;
94 counter += steps * samplerate;
95 if( (level -= steps) <= VMAX*1/3 )
96 {
97 level = VMAX*1/3;
98 output = 0;
99 }
100 }
101 }
102 }
103 else
104 {
105 if (level < VMAX*2/3)
106 {
107 counter -= rate[0][tone1_vco1_cap];
108 if( counter <= 0 )
109 {
110 int steps = -counter / samplerate + 1;
111 counter += steps * samplerate;
112 if( (level += steps) >= VMAX*2/3 )
113 {
114 level = VMAX*2/3;
115 output = 1;
116 }
117 }
118 }
119 }
120 return output;
121 }
122
tone1_vco2(int samplerate)123 static INLINE int tone1_vco2(int samplerate)
124 {
125 static int output, counter, level;
126
127 /*
128 * L517 (NE555): Ra=570k, Rb=570k, C=10uF
129 * charge time = 0.639*(Ra+Rb)*C = 7.9002s
130 * discharge time = 0.639*Rb*C = 3.9501s
131 */
132 #define C20 10.0e-6
133 #define R43 570000
134 #define R44 570000
135
136 if( output )
137 {
138 if (level > VMIN)
139 {
140 counter -= (int)(VMAX*2/3 / (0.693 * R44 * C20));
141 if( counter <= 0 )
142 {
143 int steps = -counter / samplerate + 1;
144 counter += steps * samplerate;
145 if( (level -= steps) <= VMAX*1/3 )
146 {
147 level = VMAX*1/3;
148 output = 0;
149 }
150 }
151 }
152 }
153 else
154 {
155 if (level < VMAX)
156 {
157 counter -= (int)(VMAX*2/3 / (0.693 * (R43 + R44) * C20));
158 if( counter <= 0 )
159 {
160 int steps = -counter / samplerate + 1;
161 counter += steps * samplerate;
162 if( (level += steps) >= VMAX*2/3 )
163 {
164 level = VMAX*2/3;
165 output = 1;
166 }
167 }
168 }
169 }
170
171 return output;
172 }
173
tone1_vco(int samplerate,int vco1,int vco2)174 static INLINE int tone1_vco(int samplerate, int vco1, int vco2)
175 {
176 static int counter, level, rate, charge;
177 int voltage;
178
179 if (level != charge)
180 {
181 /* charge or discharge C22 */
182 counter -= rate;
183 while( counter <= 0 )
184 {
185 counter += samplerate;
186 if( level < charge )
187 {
188 if( ++level == charge )
189 break;
190 }
191 else
192 {
193 if( --level == charge )
194 break;
195 }
196 }
197 }
198
199 if( vco2 )
200 {
201 #define C22 100.0e-6
202 #define R42 10000
203 #define R45 51000
204 #define R46 51000
205 #define RP 27777 /* R42+R46 parallel with R45 */
206 if( vco1 )
207 {
208 /* R42 10k
209 * +5V -/\/\/------------+
210 * 5V |
211 * +5V -/\/\/--+--/\/\/--+--> V/C
212 * R45 51k | R46 51k
213 * ---
214 * --- 100u
215 * |
216 * 0V
217 */
218 charge = VMAX;
219 rate = (int)((charge - level) / (RP * C22));
220 voltage = level + (VMAX-level) * R46 / (R46 + R42);
221 }
222 else
223 {
224 /* R42 10k
225 * 0V -/\/\/------------+
226 * 2.7V |
227 * +5V -/\/\/--+--/\/\/--+--> V/C
228 * R45 51k | R46 51k
229 * ---
230 * --- 100u
231 * |
232 * 0V
233 */
234 /* simplification: charge = (R42 + R46) / (R42 + R45 + R46); */
235 charge = VMAX * 27 / 50;
236 if (charge >= level)
237 rate = (int)((charge - level) / (R45 * C22));
238 else
239 rate = (int)((level - charge) / ((R46+R42) * C22));
240 voltage = level * R42 / (R46 + R42);
241 }
242 }
243 else
244 {
245 if( vco1 )
246 {
247 /* R42 10k
248 * +5V -/\/\/------------+
249 * 2.3V |
250 * 0V -/\/\/--+--/\/\/--+--> V/C
251 * R45 51k | R46 51k
252 * ---
253 * --- 100u
254 * |
255 * 0V
256 */
257 /* simplification: charge = VMAX * R45 / (R42 + R45 + R46); */
258 charge = VMAX * 23 / 50;
259 if (charge >= level)
260 rate = (int)((charge - level) / ((R42 + R46) * C22));
261 else
262 rate = (int)((level - charge) / (R45 * C22));
263 voltage = level + (VMAX - level) * R46 / (R42 + R46);
264 }
265 else
266 {
267 /* R42 10k
268 * 0V -/\/\/------------+
269 * 0V |
270 * 0V -/\/\/--+--/\/\/--+--> V/C
271 * R45 51k | R46 51k
272 * ---
273 * --- 100u
274 * |
275 * 0V
276 */
277 charge = VMIN;
278 rate = (int)((level - charge) / (RP * C22));
279 voltage = level * R42 / (R46 + R42);
280 }
281 }
282
283 /* L507 (NE555): Ra=20k, Rb=20k, C=0.001uF
284 * frequency 1.44/((Ra+2*Rb)*C) = 24kHz
285 */
286 return 24000*1/3 + 24000*2/3 * voltage / 32768;
287 }
288
tone1(int samplerate)289 static INLINE int tone1(int samplerate)
290 {
291 static int counter, divisor, output;
292 int vco1 = tone1_vco1(samplerate);
293 int vco2 = tone1_vco2(samplerate);
294 int frequency = tone1_vco(samplerate, vco1, vco2);
295
296 if( (sound_latch_a & 15) != 15 )
297 {
298 counter -= frequency;
299 while( counter <= 0 )
300 {
301 counter += samplerate;
302 if( ++divisor == 16 )
303 {
304 divisor = sound_latch_a & 15;
305 output ^= 1;
306 }
307 }
308 }
309
310 return output ? tone1_level : -tone1_level;
311 }
312
tone2_vco(int samplerate)313 static INLINE int tone2_vco(int samplerate)
314 {
315 static int counter, level;
316
317 /*
318 * This is how the tone2 part of the circuit looks like.
319 * I was having a hard time to guesstimate the results
320 * and they might still be wrong :(
321 *
322 * +12V
323 * |
324 * / R23
325 * \ 100k
326 * /
327 * !bit4 | /| R22 |
328 * 0V/5V >--|< |---/\/\/-----+-------+---> V C7
329 * | \| 47k | |
330 * D4 | _|_
331 * 6.8u --- \ / D5
332 * C7 --- ---
333 * | |
334 * | |
335 * 0V >-------------------+-/\/\/-+
336 * R24 33k
337 *
338 * V C7 min:
339 * 0.7V + (12V - 0.7V) * 19388 / (100000 + 19388) = 2.54V
340 * V C7 max:
341 * 0.7V + (12V - 0.7V) * 33000 / (100000 + 33000) +
342 * (12V - 5.7V) * 47000 / (100000 + 47000) = 5.51V
343 */
344
345 #define C7 6.8e-6
346 #define R23 100000
347 #define R22 47000
348 #define R24 33000
349 #define R22pR24 19388
350
351 #define C7_MIN (VMAX * 254 / 500)
352 #define C7_MAX (VMAX * 551 / 500)
353 #define C7_DIFF (C7_MAX - C7_MIN)
354
355 if( (sound_latch_b & 0x10) == 0 )
356 {
357 counter -= (C7_MAX - level) * 12 / (R23 * C7) / 5;
358 if( counter <= 0 )
359 {
360 int n = (-counter / samplerate) + 1;
361 counter += n * samplerate;
362 if( (level += n) > C7_MAX)
363 level = C7_MAX;
364 }
365 }
366 else
367 {
368 counter -= (level - C7_MIN) * 12 / (R22pR24 * C7) / 5;
369 if( counter <= 0 )
370 {
371 int n = (-counter / samplerate) + 1;
372 counter += n * samplerate;
373 if( (level -= n) < C7_MIN)
374 level = C7_MIN;
375 }
376 }
377 /*
378 * L487 (NE555):
379 * Ra = R25 (47k), Rb = R26 (47k), C = C8 (0.001uF)
380 * frequency 1.44/((Ra+2*Rb)*C) = 10212 Hz
381 */
382 return 10212 * level / 32768;
383 }
384
tone2(int samplerate)385 static INLINE int tone2(int samplerate)
386 {
387 static int counter, divisor, output;
388 int frequency = tone2_vco(samplerate);
389
390 if( (sound_latch_b & 15) != 15 )
391 {
392 counter -= frequency;
393 while( counter <= 0 )
394 {
395 counter += samplerate;
396 if( ++divisor == 16 )
397 {
398 divisor = sound_latch_b & 15;
399 output ^= 1;
400 }
401 }
402 }
403 return output ? tone2_level : -tone2_level;
404 }
405
update_c24(int samplerate)406 static INLINE int update_c24(int samplerate)
407 {
408 static int counter, level;
409 /*
410 * Noise frequency control (Port B):
411 * Bit 6 lo charges C24 (6.8u) via R51 (330) and when
412 * bit 6 is hi, C24 is discharged through R52 (20k)
413 * in approx. 20000 * 6.8e-6 = 0.136 seconds
414 */
415 #define C24 6.8e-6
416 #define R49 1000
417 #define R51 330
418 #define R52 20000
419 if( sound_latch_a & 0x40 )
420 {
421 if (level > VMIN)
422 {
423 counter -= (int)((level - VMIN) / (R52 * C24));
424 if( counter <= 0 )
425 {
426 int n = -counter / samplerate + 1;
427 counter += n * samplerate;
428 if( (level -= n) < VMIN)
429 level = VMIN;
430 }
431 }
432 }
433 else
434 {
435 if (level < VMAX)
436 {
437 counter -= (int)((VMAX - level) / ((R51+R49) * C24));
438 if( counter <= 0 )
439 {
440 int n = -counter / samplerate + 1;
441 counter += n * samplerate;
442 if( (level += n) > VMAX)
443 level = VMAX;
444 }
445 }
446 }
447 return VMAX - level;
448 }
449
update_c25(int samplerate)450 static INLINE int update_c25(int samplerate)
451 {
452 static int counter, level;
453 /*
454 * Bit 7 hi charges C25 (6.8u) over a R50 (1k) and R53 (330) and when
455 * bit 7 is lo, C25 is discharged through R54 (47k)
456 * in about 47000 * 6.8e-6 = 0.3196 seconds
457 */
458 #define C25 6.8e-6
459 #define R50 1000
460 #define R53 330
461 #define R54 47000
462
463 if( sound_latch_a & 0x80 )
464 {
465 if (level < VMAX)
466 {
467 counter -= (int)((VMAX - level) / ((R50+R53) * C25));
468 if( counter <= 0 )
469 {
470 int n = -counter / samplerate + 1;
471 counter += n * samplerate;
472 if( (level += n) > VMAX )
473 level = VMAX;
474 }
475 }
476 }
477 else
478 {
479 if (level > VMIN)
480 {
481 counter -= (int)((level - VMIN) / (R54 * C25));
482 if( counter <= 0 )
483 {
484 int n = -counter / samplerate + 1;
485 counter += n * samplerate;
486 if( (level -= n) < VMIN )
487 level = VMIN;
488 }
489 }
490 }
491 return level;
492 }
493
494
noise(int samplerate)495 static INLINE int noise(int samplerate)
496 {
497 static int counter, polyoffs, polybit, lowpass_counter, lowpass_polybit;
498 int vc24 = update_c24(samplerate);
499 int vc25 = update_c25(samplerate);
500 int sum = 0, level, frequency;
501
502 /*
503 * The voltage levels are added and control I(CE) of transistor TR1
504 * (NPN) which then controls the noise clock frequency (linearily?).
505 * level = voltage at the output of the op-amp controlling the noise rate.
506 */
507 if( vc24 < vc25 )
508 level = vc24 + (vc25 - vc24) / 2;
509 else
510 level = vc25 + (vc24 - vc25) / 2;
511
512 frequency = 588 + 6325 * level / 32768;
513
514 /*
515 * NE555: Ra=47k, Rb=1k, C=0.05uF
516 * minfreq = 1.44 / ((47000+2*1000) * 0.05e-6) = approx. 588 Hz
517 * R71 (2700 Ohms) parallel to R73 (47k Ohms) = approx. 2553 Ohms
518 * maxfreq = 1.44 / ((2553+2*1000) * 0.05e-6) = approx. 6325 Hz
519 */
520 counter -= frequency;
521 if( counter <= 0 )
522 {
523 int n = (-counter / samplerate) + 1;
524 counter += n * samplerate;
525 polyoffs = (polyoffs + n) & 0x3ffff;
526 polybit = (poly18[polyoffs>>5] >> (polyoffs & 31)) & 1;
527 }
528 if (!polybit)
529 sum += vc24;
530
531 /* 400Hz crude low pass filter: this is only a guess!! */
532 lowpass_counter -= 400;
533 if( lowpass_counter <= 0 )
534 {
535 lowpass_counter += samplerate;
536 lowpass_polybit = polybit;
537 }
538 if (!lowpass_polybit)
539 sum += vc25;
540
541 return sum;
542 }
543
phoenix_sound_update(int param,INT16 * buffer,int length)544 static void phoenix_sound_update(int param, INT16 *buffer, int length)
545 {
546 int samplerate = Machine->sample_rate;
547
548 while( length-- > 0 )
549 {
550 int sum = 0;
551 sum = (tone1(samplerate) + tone2(samplerate) + noise(samplerate)) / 4;
552 MAME_CLAMP_SAMPLE(sum);
553 *buffer++ = sum;
554 }
555 }
556
WRITE_HANDLER(phoenix_sound_control_a_w)557 WRITE_HANDLER( phoenix_sound_control_a_w )
558 {
559 if( data == sound_latch_a )
560 return;
561
562 stream_update(channel,0);
563 sound_latch_a = data;
564
565 tone1_vco1_cap = (sound_latch_a >> 4) & 3;
566 if( sound_latch_a & 0x20 )
567 tone1_level = VMAX * 10000 / (10000+10000);
568 else
569 tone1_level = VMAX;
570 }
571
WRITE_HANDLER(phoenix_sound_control_b_w)572 WRITE_HANDLER( phoenix_sound_control_b_w )
573 {
574 if( data == sound_latch_b )
575 return;
576
577 stream_update(channel,0);
578 sound_latch_b = data;
579
580 if( sound_latch_b & 0x20 )
581 tone2_level = VMAX * 10 / 11;
582 else
583 tone2_level = VMAX;
584
585 /* eventually change the tune that the MM6221AA is playing */
586 mm6221aa_tune_w(0, sound_latch_b >> 6);
587 }
588
phoenix_sh_start(const struct MachineSound * msound)589 int phoenix_sh_start(const struct MachineSound *msound)
590 {
591 int i, j;
592 UINT32 shiftreg;
593
594 poly18 = (UINT32 *)auto_malloc((1ul << (18-5)) * sizeof(UINT32));
595
596 if( !poly18 )
597 return 1;
598
599 shiftreg = 0;
600 for( i = 0; i < (1ul << (18-5)); i++ )
601 {
602 UINT32 bits = 0;
603 for( j = 0; j < 32; j++ )
604 {
605 bits = (bits >> 1) | (shiftreg << 31);
606 if( ((shiftreg >> 16) & 1) == ((shiftreg >> 17) & 1) )
607 shiftreg = (shiftreg << 1) | 1;
608 else
609 shiftreg <<= 1;
610 }
611 poly18[i] = bits;
612 }
613
614 channel = stream_init("Custom", 50, Machine->sample_rate, 0, phoenix_sound_update);
615 if( channel == -1 )
616 return 1;
617
618 return 0;
619 }
620
phoenix_sh_stop(void)621 void phoenix_sh_stop(void)
622 {
623 }
624
phoenix_sh_update(void)625 void phoenix_sh_update(void)
626 {
627 stream_update(channel, 0);
628 }
629