1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria, Dan Boris
3 /* from Andrew Scott (ascott@utkux.utcc.utk.edu) */
4
5 /*
6 updated by BUT
7 - corrected music tempo (not confirmed Satan of Saturn and clone)
8 - adjusted music freq (except Satan of Saturn and clone)
9 - adjusted music waveform
10 - support playing flag for music channel 0
11 - support HD38880 speech by samples
12 */
13
14
15 #include "emu.h"
16 #include "audio/snk6502.h"
17
18 #include "speaker.h"
19
20 #ifndef M_LN2
21 #define M_LN2 0.69314718055994530942
22 #endif
23
24 #define TONE_VOLUME 50
25
26 #define SAMPLE_RATE (48000)
27 #define FRAC_BITS 16
28 #define FRAC_ONE (1 << FRAC_BITS)
29 #define FRAC_MASK (FRAC_ONE - 1)
30
31 static const char *const sasuke_sample_names[] =
32 {
33 "*sasuke",
34
35 // SN76477 and discrete
36 "hit",
37 "boss_start",
38 "shot",
39 "boss_attack",
40
41 nullptr
42 };
43
44 static const char *const vanguard_sample_names[] =
45 {
46 "*vanguard",
47
48 // SN76477 and discrete
49 "fire",
50 "explsion",
51
52 // HD38880 speech
53 "vg_voi-0",
54 "vg_voi-1",
55 "vg_voi-2",
56 "vg_voi-3",
57 "vg_voi-4",
58 "vg_voi-5",
59 "vg_voi-6",
60 "vg_voi-7",
61 "vg_voi-8",
62 "vg_voi-9",
63 "vg_voi-a",
64 "vg_voi-b",
65 "vg_voi-c",
66 "vg_voi-d",
67 "vg_voi-e",
68 "vg_voi-f",
69
70 nullptr
71 };
72
73
74 static const char *const fantasy_sample_names[] =
75 {
76 "*fantasy",
77
78 // HD38880 speech
79 "ft_voi-0",
80 "ft_voi-1",
81 "ft_voi-2",
82 "ft_voi-3",
83 "ft_voi-4",
84 "ft_voi-5",
85 "ft_voi-6",
86 "ft_voi-7",
87 "ft_voi-8",
88 "ft_voi-9",
89 "ft_voi-a",
90 "ft_voi-b",
91
92 nullptr
93 };
94
95
96 /************************************************************************
97 * fantasy Sound System Analog emulation
98 * July 2008, D. Renaud
99 ************************************************************************/
100
101 static const discrete_op_amp_filt_info fantasy_filter =
102 {
103 RES_K(10.5), 0, RES_K(33), 0, RES_K(470), CAP_U(.01), CAP_U(.01), 0, 0, 12, -12
104 };
105
106 #define FANTASY_BOMB_EN NODE_01
107 #define FANTASY_NOISE_STREAM_IN NODE_02
108 #define FANTASY_NOISE_LOGIC NODE_03
109
110 static DISCRETE_SOUND_START( fantasy_discrete )
111
DISCRETE_INPUT_LOGIC(FANTASY_BOMB_EN)112 DISCRETE_INPUT_LOGIC (FANTASY_BOMB_EN)
113 DISCRETE_INPUT_STREAM(FANTASY_NOISE_STREAM_IN, 0)
114
115 /* This is not the perfect way to discharge, but it is good enough for now */
116 /* it does not take into acount that there is no discharge when noise is low */
117 DISCRETE_RCDISC2(NODE_10, FANTASY_BOMB_EN, 0, RES_K(10) + RES_K(33), DEFAULT_TTL_V_LOGIC_1 - 0.5, RES_K(1), CAP_U(1))
118 DISCRETE_CLAMP(FANTASY_NOISE_LOGIC, FANTASY_NOISE_STREAM_IN, 0, 1)
119 DISCRETE_SWITCH(NODE_11, 1, FANTASY_NOISE_LOGIC, 0, NODE_10)
120
121 DISCRETE_OP_AMP_FILTER(NODE_20, 1, NODE_11, 0, DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &fantasy_filter)
122 DISCRETE_RCFILTER(NODE_21, NODE_20, RES_K(22), CAP_U(.01))
123 DISCRETE_RCFILTER(NODE_22, NODE_21, RES_K(22) + RES_K(22), CAP_P(2200))
124 DISCRETE_RCFILTER(NODE_23, NODE_22, RES_K(22) + RES_K(22) + RES_K(22), CAP_U(.001))
125
126 DISCRETE_OUTPUT(NODE_23, 32760.0/12)
127 DISCRETE_SOUND_END
128
129
130 DEFINE_DEVICE_TYPE(SNK6502_SOUND, snk6502_sound_device, "snk6502_sound", "SNK6502 Custom Sound")
131 DEFINE_DEVICE_TYPE(VANGUARD_SOUND, vanguard_sound_device, "vanguard_sound", "SNK Vanguard Sound")
132 DEFINE_DEVICE_TYPE(FANTASY_SOUND, fantasy_sound_device, "fantasy_sound", "SNK Fantasy Sound")
133 DEFINE_DEVICE_TYPE(NIBBLER_SOUND, nibbler_sound_device, "nibbler_sound", "Rock-Ola Nibbler Sound")
134 DEFINE_DEVICE_TYPE(PBALLOON_SOUND, pballoon_sound_device, "pballoon_sound", "SNK Pioneer Balloon Sound")
135 DEFINE_DEVICE_TYPE(SASUKE_SOUND, sasuke_sound_device, "sasuke_sound", "SNK Sasuke Vs. Commander Sound")
136 DEFINE_DEVICE_TYPE(SATANSAT_SOUND, satansat_sound_device, "satansat_sound", "SNK Satan of Saturn Sound")
137
138
139 snk6502_sound_device::snk6502_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
140 : device_t(mconfig, SNK6502_SOUND, tag, owner, clock)
141 , device_sound_interface(mconfig, *this)
142 , m_tone_clock_expire(0)
143 , m_tone_clock(0)
144 , m_tone_stream(nullptr)
145 , m_samples(*this, "^samples")
146 , m_rom(*this, DEVICE_SELF_OWNER)
147 , m_sound0_stop_on_rollover(0)
148 , m_hd38880_cmd(0)
149 , m_hd38880_addr(0)
150 , m_hd38880_data_bytes(0)
151 , m_hd38880_speed(0)
152 {
153 }
154
155
156 //-------------------------------------------------
157 // device_start - device-specific startup
158 //-------------------------------------------------
159
device_start()160 void snk6502_sound_device::device_start()
161 {
162 // adjusted
163 set_music_freq(43000);
164
165 // 38.99 Hz update (according to schematic)
166 set_music_clock(M_LN2 * (RES_K(18) * 2 + RES_K(1)) * CAP_U(1));
167
168 m_tone_stream = stream_alloc(0, 1, SAMPLE_RATE);
169
170 for (int i = 0; i < NUM_CHANNELS; i++)
171 {
172 save_item(NAME(m_tone_channels[i].mute), i);
173 save_item(NAME(m_tone_channels[i].offset), i);
174 save_item(NAME(m_tone_channels[i].base), i);
175 save_item(NAME(m_tone_channels[i].mask), i);
176 save_item(NAME(m_tone_channels[i].sample_step), i);
177 save_item(NAME(m_tone_channels[i].sample_cur), i);
178 save_item(NAME(m_tone_channels[i].form), i);
179 }
180
181 save_item(NAME(m_tone_clock));
182 save_item(NAME(m_sound0_stop_on_rollover));
183 save_item(NAME(m_hd38880_cmd));
184 save_item(NAME(m_hd38880_addr));
185 save_item(NAME(m_hd38880_data_bytes));
186 save_item(NAME(m_hd38880_speed));
187 }
188
validate_tone_channel(int channel)189 inline void snk6502_sound_device::validate_tone_channel(int channel)
190 {
191 if (!m_tone_channels[channel].mute)
192 {
193 uint8_t romdata = m_rom->base()[m_tone_channels[channel].base + m_tone_channels[channel].offset];
194
195 if (romdata != 0xff)
196 m_tone_channels[channel].sample_step = m_tone_channels[channel].sample_rate / (256 - romdata);
197 else
198 m_tone_channels[channel].sample_step = 0;
199 }
200 }
201
sasuke_build_waveform(int mask)202 void snk6502_sound_device::sasuke_build_waveform(int mask)
203 {
204 const int bit0 = BIT(mask, 0);
205 const int bit1 = BIT(mask, 1);
206 const int bit2 = 1;
207 const int bit3 = BIT(mask, 2);
208 const int base = (bit0 + bit1 + bit2 + bit3 + 1) / 2;
209
210 for (int i = 0; i < 16; i++)
211 {
212 const int data = (bit0 & BIT(i, 0)) + (bit1 & BIT(i, 1)) + (bit2 & BIT(i, 2)) + (bit3 & BIT(i, 3));
213 m_tone_channels[0].form[i] = data - base;
214 }
215
216 for (int i = 0; i < 16; i++)
217 m_tone_channels[0].form[i] *= 65535 / 16;
218 }
219
satansat_build_waveform(int mask)220 void snk6502_sound_device::satansat_build_waveform(int mask)
221 {
222 //logerror("1: wave form = %d\n", mask);
223 const int bit0 = 1;
224 const int bit1 = 1;
225 const int bit2 = 1;
226 const int bit3 = BIT(mask, 0);
227 const int base = (bit0 + bit1 + bit2 + bit3 + 1) / 2;
228
229 for (int i = 0; i < 16; i++)
230 {
231 const int data = (bit0 & BIT(i, 0)) + (bit1 & BIT(i, 1)) + (bit2 & BIT(i, 2)) + (bit3 & BIT(i, 3));
232 m_tone_channels[1].form[i] = data - base;
233 }
234
235 for (int i = 0; i < 16; i++)
236 m_tone_channels[1].form[i] *= 65535 / 16;
237 }
238
build_waveform(int channel,int mask)239 void snk6502_sound_device::build_waveform(int channel, int mask)
240 {
241 //logerror("%d: wave form = %d\n", channel, mask);
242 int bit0 = 0;
243 int bit1 = 0;
244 int bit2 = 0;
245 int bit3 = 0;
246
247 // bit 3
248 if (BIT(mask, 0) || BIT(mask, 1))
249 bit3 = 8;
250 else if (BIT(mask, 2))
251 bit3 = 4;
252 else if (BIT(mask, 3))
253 bit3 = 2;
254
255 // bit 2
256 if (BIT(mask, 2))
257 bit2 = 8;
258 else if (BIT(mask, 1) || BIT(mask, 3))
259 bit2 = 4;
260
261 // bit 1
262 if (BIT(mask, 3))
263 bit1 = 8;
264 else if (BIT(mask, 2))
265 bit1 = 4;
266 else if (BIT(mask, 1))
267 bit1 = 2;
268
269 // bit 0
270 bit0 = bit1 >> 1;
271
272 if (bit0 + bit1 + bit2 + bit3 < 16)
273 {
274 bit0 <<= 1;
275 bit1 <<= 1;
276 bit2 <<= 1;
277 bit3 <<= 1;
278 }
279
280 const int base = (bit0 + bit1 + bit2 + bit3 + 1) / 2;
281
282 for (int i = 0; i < 16; i++)
283 {
284 /* special channel for fantasy */
285 if (channel == 2)
286 {
287 m_tone_channels[channel].form[i] = BIT(i, 3) ? 7 : -8;
288 }
289 else
290 {
291 const int data = (BIT(i, 0) ? bit0 : 0) + (BIT(i, 1) ? bit1 : 0) + (BIT(i, 2) ? bit2 : 0) + (BIT(i, 3) ? bit3 : 0);
292 m_tone_channels[channel].form[i] = data - base;
293 }
294 }
295
296 for (int i = 0; i < 16; i++)
297 m_tone_channels[channel].form[i] *= 65535 / 160;
298 }
299
set_music_freq(int freq)300 void snk6502_sound_device::set_music_freq(int freq)
301 {
302 for (int i = 0; i < NUM_CHANNELS; i++)
303 {
304 m_tone_channels[i].mute = 1;
305 m_tone_channels[i].offset = 0;
306 m_tone_channels[i].base = i * 0x800;
307 m_tone_channels[i].mask = 0xff;
308 m_tone_channels[i].sample_step = 0;
309 m_tone_channels[i].sample_cur = 0;
310 m_tone_channels[i].sample_rate = double(freq * 8) / SAMPLE_RATE * FRAC_ONE;
311
312 build_waveform(i, 1);
313 }
314 }
315
set_music_clock(double clock_time)316 void snk6502_sound_device::set_music_clock(double clock_time)
317 {
318 m_tone_clock_expire = clock_time * SAMPLE_RATE * FRAC_ONE;
319 m_tone_clock = 0;
320 }
321
READ_LINE_MEMBER(snk6502_sound_device::music0_playing)322 READ_LINE_MEMBER(snk6502_sound_device::music0_playing)
323 {
324 return m_tone_channels[0].mute ? 1 : 0;
325 }
326
set_channel_base(int channel,int base,int mask)327 void snk6502_sound_device::set_channel_base(int channel, int base, int mask)
328 {
329 m_tone_channels[channel].base = base;
330 m_tone_channels[channel].mask = mask;
331 }
332
mute_channel(int channel)333 void snk6502_sound_device::mute_channel(int channel)
334 {
335 m_tone_channels[channel].mute = 1;
336 m_tone_channels[channel].offset = 0;
337 }
338
unmute_channel(int channel)339 void snk6502_sound_device::unmute_channel(int channel)
340 {
341 if (m_tone_channels[channel].mute)
342 m_tone_channels[channel].offset = 0;
343 m_tone_channels[channel].mute = 0;
344 }
345
346
347 /*
348 Hitachi HD38880 speech synthesizer chip
349
350 I heard that this chip uses PARCOR coefficients but I don't know ROM data format.
351 How do I generate samples?
352 */
353
354
355 /* HD38880 command */
356 #define HD38880_ADSET 2
357 #define HD38880_READ 3
358 #define HD38880_INT1 4
359 #define HD38880_INT2 6
360 #define HD38880_SYSPD 8
361 #define HD38880_STOP 10
362 #define HD38880_CONDT 11
363 #define HD38880_START 12
364 #define HD38880_SSTART 14
365
366 /* HD38880 control bits */
367 #define HD38880_CTP 0x10
368 #define HD38880_CMV 0x20
369 #define HD68880_SYBS 0x0f
370
371
speech_w(uint8_t data,const uint16_t * table,int start)372 void snk6502_sound_device::speech_w(uint8_t data, const uint16_t *table, int start)
373 {
374 /*
375 bit description
376 0 SYBS1
377 1 SYBS2
378 2 SYBS3
379 3 SYBS4
380 4 CTP
381 5 CMV
382 6
383 7
384 */
385
386 if ((data & HD38880_CTP) && (data & HD38880_CMV))
387 {
388 data &= HD68880_SYBS;
389
390 switch (m_hd38880_cmd)
391 {
392 case 0:
393 switch (data)
394 {
395 case HD38880_START:
396 logerror("speech: START\n");
397
398 if (m_hd38880_data_bytes == 5 && !m_samples->playing(0))
399 {
400 for (int i = 0; i < 16; i++)
401 {
402 if (table[i] && table[i] == m_hd38880_addr)
403 {
404 m_samples->start(0, start + i);
405 break;
406 }
407 }
408 }
409 break;
410
411 case HD38880_SSTART:
412 logerror("speech: SSTART\n");
413 break;
414
415 case HD38880_STOP:
416 m_samples->stop(0);
417 logerror("speech: STOP\n");
418 break;
419
420 case HD38880_SYSPD:
421 m_hd38880_cmd = data;
422 break;
423
424 case HD38880_CONDT:
425 logerror("speech: CONDT\n");
426 break;
427
428 case HD38880_ADSET:
429 m_hd38880_cmd = data;
430 m_hd38880_addr = 0;
431 m_hd38880_data_bytes = 0;
432 break;
433
434 case HD38880_READ:
435 logerror("speech: READ\n");
436 break;
437
438 case HD38880_INT1:
439 m_hd38880_cmd = data;
440 break;
441
442 case HD38880_INT2:
443 m_hd38880_cmd = data;
444 break;
445
446 case 0:
447 // ignore it
448 break;
449
450 default:
451 logerror("speech: unknown command: 0x%x\n", data);
452 }
453 break;
454
455 case HD38880_INT1:
456 logerror("speech: INT1: 0x%x\n", data);
457
458 if (data & 8)
459 logerror("speech: triangular waveform\n");
460 else
461 logerror("speech: impulse waveform\n");
462
463 logerror("speech: %sable losing effect of vocal tract\n", data & 4 ? "en" : "dis");
464
465 if ((data & 2) && (data & 8))
466 logerror("speech: use external pitch control\n");
467
468 m_hd38880_cmd = 0;
469 break;
470
471 case HD38880_INT2:
472 logerror("speech: INT2: 0x%x\n", data);
473
474 logerror("speech: %d bits / frame\n", data & 8 ? 48 : 96);
475 logerror("speech: %d ms / frame\n", data & 4 ? 20 : 10);
476 logerror("speech: %sable repeat\n", data & 2 ? "en" : "dis");
477 logerror("speech: %d operations\n", ((data & 8) == 0) || (data & 1) ? 10 : 8);
478
479 m_hd38880_cmd = 0;
480 break;
481
482 case HD38880_SYSPD:
483 m_hd38880_speed = ((double)(data + 1)) / 10.0;
484 logerror("speech: SYSPD: %1.1f\n", m_hd38880_speed);
485 m_hd38880_cmd = 0;
486 break;
487
488 case HD38880_ADSET:
489 m_hd38880_addr |= (data << (m_hd38880_data_bytes++ * 4));
490 if (m_hd38880_data_bytes == 5)
491 {
492 logerror("speech: ADSET: 0x%05x\n", m_hd38880_addr);
493 m_hd38880_cmd = 0;
494 }
495 break;
496 }
497 }
498 }
499
500
501 /*
502 vanguard/fantasy speech
503
504 ROM data format (INT2 = 0xf):
505 48 bits / frame
506 20 ms / frame
507 enable repeat
508 10 operations
509 */
510
511 //-------------------------------------------------
512 // sound_stream_update - handle a stream update
513 //-------------------------------------------------
514
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)515 void snk6502_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
516 {
517 auto &buffer = outputs[0];
518
519 for (int i = 0; i < NUM_CHANNELS; i++)
520 validate_tone_channel(i);
521
522 for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
523 {
524 int32_t data = 0;
525
526 for (tone_t &voice : m_tone_channels)
527 {
528 int16_t const *const form = voice.form;
529
530 if (!voice.mute && voice.sample_step)
531 {
532 const int cur_pos = voice.sample_cur + voice.sample_step;
533 const int prev = form[(voice.sample_cur >> FRAC_BITS) & 15];
534 const int cur = form[(cur_pos >> FRAC_BITS) & 15];
535
536 /* interpolate */
537 data += (int32_t(prev) * (FRAC_ONE - (cur_pos & FRAC_MASK))
538 + int32_t(cur) * (cur_pos & FRAC_MASK)) >> FRAC_BITS;
539
540 voice.sample_cur = cur_pos;
541 }
542 }
543
544 buffer.put_int(sampindex, data, 3768);
545
546 m_tone_clock += FRAC_ONE;
547 if (m_tone_clock >= m_tone_clock_expire)
548 {
549 for (int i = 0; i < NUM_CHANNELS; i++)
550 {
551 m_tone_channels[i].offset++;
552 m_tone_channels[i].offset &= m_tone_channels[i].mask;
553
554 validate_tone_channel(i);
555 }
556
557 if (m_tone_channels[0].offset == 0 && m_sound0_stop_on_rollover)
558 m_tone_channels[0].mute = 1;
559
560 m_tone_clock -= m_tone_clock_expire;
561 }
562 }
563 }
564
565
vanguard_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)566 vanguard_sound_device::vanguard_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
567 : device_t(mconfig, VANGUARD_SOUND, tag, owner, clock)
568 , m_custom(*this, "custom")
569 , m_sn76477_2(*this, "sn76477.2")
570 , m_samples(*this, "samples")
571 , m_last_port1(0)
572 {
573 }
574
sound_w(offs_t offset,uint8_t data)575 void vanguard_sound_device::sound_w(offs_t offset, uint8_t data)
576 {
577 switch (offset)
578 {
579 case 0:
580 /*
581 bit description
582
583 0 MUSIC A10
584 1 MUSIC A9
585 2 MUSIC A8
586 3 LS05 PORT 1
587 4 LS04 PORT 2
588 5 SHOT A
589 6 SHOT B
590 7 BOMB
591 */
592
593 /* select musical tune in ROM based on sound command byte */
594 m_custom->set_channel_base(0, (data & 0x07) << 8);
595
596 m_custom->set_sound0_stop_on_rollover(1);
597
598 /* play noise samples requested by sound command byte */
599 /* SHOT A */
600 if (data & 0x20 && !(m_last_port1 & 0x20))
601 m_samples->start(1, 0);
602 else if (!(data & 0x20) && m_last_port1 & 0x20)
603 m_samples->stop(1);
604
605 /* BOMB */
606 if (data & 0x80 && !(m_last_port1 & 0x80))
607 m_samples->start(2, 1);
608
609 if (data & 0x08)
610 m_custom->mute_channel(0);
611
612 if (data & 0x10)
613 m_custom->unmute_channel(0);
614
615 /* SHOT B */
616 m_sn76477_2->enable_w((data & 0x40) ? 0 : 1);
617
618 m_last_port1 = data;
619 break;
620
621 case 1:
622 /*
623 bit description
624
625 0 MUSIC A10
626 1 MUSIC A9
627 2 MUSIC A8
628 3 LS04 PORT 3
629 4 EXTP A (HD38880 external pitch control A)
630 5 EXTP B (HD38880 external pitch control B)
631 6
632 7
633 */
634
635 /* select tune in ROM based on sound command byte */
636 m_custom->set_channel_base(1, 0x0800 | ((data & 0x07) << 8));
637
638 if (data & 0x08)
639 m_custom->unmute_channel(1);
640 else
641 m_custom->mute_channel(1);
642 break;
643
644 case 2:
645 /*
646 bit description
647
648 0 AS 1 (sound0 waveform)
649 1 AS 2 (sound0 waveform)
650 2 AS 4 (sound0 waveform)
651 3 AS 3 (sound0 waveform)
652 4 AS 5 (sound1 waveform)
653 5 AS 6 (sound1 waveform)
654 6 AS 7 (sound1 waveform)
655 7 AS 8 (sound1 waveform)
656 */
657
658 m_custom->build_waveform(0, (data & 0x3) | ((data & 4) << 1) | ((data & 8) >> 1));
659 m_custom->build_waveform(1, data >> 4);
660 }
661 }
662
speech_w(uint8_t data)663 void vanguard_sound_device::speech_w(uint8_t data)
664 {
665 static const uint16_t vanguard_table[16] =
666 {
667 0x04000,
668 0x04325,
669 0x044a2,
670 0x045b7,
671 0x046ee,
672 0x04838,
673 0x04984,
674 0x04b01,
675 0x04c38,
676 0x04de6,
677 0x04f43,
678 0x05048,
679 0x05160,
680 0x05289,
681 0x0539e,
682 0x054ce
683 };
684
685 m_custom->speech_w(data, vanguard_table, 2);
686 }
687
device_add_mconfig(machine_config & config)688 void vanguard_sound_device::device_add_mconfig(machine_config &config)
689 {
690 SPEAKER(config, "mono").front_center();
691
692 SNK6502_SOUND(config, m_custom, 0);
693 m_custom->add_route(ALL_OUTPUTS, "mono", 0.50);
694
695 SAMPLES(config, m_samples);
696 m_samples->set_channels(3);
697 m_samples->set_samples_names(vanguard_sample_names);
698 m_samples->add_route(ALL_OUTPUTS, "mono", 0.25);
699
700 sn76477_device &sn76477_1(SN76477(config, "sn76477.1"));
701 // SHOT A GND: 2,9,26,27 +5V: 15,25
702 sn76477_1.set_noise_params(RES_K(470), RES_M(1.5), CAP_P(220));
703 sn76477_1.set_decay_res(0);
704 sn76477_1.set_attack_params(0, 0);
705 sn76477_1.set_amp_res(RES_K(47));
706 sn76477_1.set_feedback_res(RES_K(4.7));
707 sn76477_1.set_vco_params(0, 0, 0);
708 sn76477_1.set_pitch_voltage(0);
709 sn76477_1.set_slf_params(0, 0);
710 sn76477_1.set_oneshot_params(0, 0);
711 sn76477_1.set_vco_mode(0);
712 sn76477_1.set_mixer_params(0, 1, 0);
713 sn76477_1.set_envelope_params(1, 1);
714 sn76477_1.set_enable(1);
715 sn76477_1.add_route(ALL_OUTPUTS, "mono", 0.50);
716
717 SN76477(config, m_sn76477_2);
718 // SHOT B GND: 1,2,26,27 +5V: 15,25,28
719 m_sn76477_2->set_noise_params(RES_K(10), RES_K(30), 0);
720 m_sn76477_2->set_decay_res(0);
721 m_sn76477_2->set_attack_params(0, 0);
722 m_sn76477_2->set_amp_res(RES_K(47));
723 m_sn76477_2->set_feedback_res(RES_K(4.7));
724 m_sn76477_2->set_vco_params(0, 0, 0);
725 m_sn76477_2->set_pitch_voltage(0);
726 m_sn76477_2->set_slf_params(0, 0);
727 m_sn76477_2->set_oneshot_params(0, 0);
728 m_sn76477_2->set_vco_mode(0);
729 m_sn76477_2->set_mixer_params(0, 1, 0);
730 m_sn76477_2->set_envelope_params(0, 1);
731 m_sn76477_2->set_enable(1);
732 m_sn76477_2->add_route(ALL_OUTPUTS, "mono", 0.25);
733 }
734
device_start()735 void vanguard_sound_device::device_start()
736 {
737 save_item(NAME(m_last_port1));
738 }
739
device_reset()740 void vanguard_sound_device::device_reset()
741 {
742 // 41.6 Hz update (measured)
743 m_custom->set_music_clock(1 / 41.6);
744 }
745
746
fantasy_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)747 fantasy_sound_device::fantasy_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
748 : fantasy_sound_device(mconfig, FANTASY_SOUND, tag, owner, clock)
749 {
750 }
751
fantasy_sound_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)752 fantasy_sound_device::fantasy_sound_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
753 : device_t(mconfig, type, tag, owner, clock)
754 , m_custom(*this, "custom")
755 , m_discrete(*this, "discrete")
756 , m_last_port1(0)
757 {
758 }
759
sound_w(offs_t offset,uint8_t data)760 void fantasy_sound_device::sound_w(offs_t offset, uint8_t data)
761 {
762 switch (offset)
763 {
764 case 0:
765 /*
766 bit description
767
768 0 MUSIC A10
769 1 MUSIC A9
770 2 MUSIC A8
771 3 LS04 PART 1
772 4 LS04 PART 2
773 5
774 6
775 7 BOMB
776 */
777
778 /* select musical tune in ROM based on sound command byte */
779 m_custom->set_channel_base(0, 0x0000 | ((data & 0x07) << 8));
780
781 m_custom->set_sound0_stop_on_rollover(0);
782
783 if (data & 0x08)
784 m_custom->unmute_channel(0);
785 else
786 m_custom->mute_channel(0);
787
788 if (data & 0x10)
789 m_custom->unmute_channel(2);
790 else
791 m_custom->mute_channel(2);
792
793 /* BOMB */
794 m_discrete->write(FANTASY_BOMB_EN, data & 0x80);
795
796 m_last_port1 = data;
797 break;
798
799 case 1:
800 /*
801 bit description
802
803 0 MUSIC A10
804 1 MUSIC A9
805 2 MUSIC A8
806 3 LS04 PART 3
807 4 EXT PA (HD38880 external pitch control A)
808 5 EXT PB (HD38880 external pitch control B)
809 6
810 7
811 */
812
813 /* select tune in ROM based on sound command byte */
814 m_custom->set_channel_base(1, 0x0800 | ((data & 0x07) << 8));
815
816 if (data & 0x08)
817 m_custom->unmute_channel(1);
818 else
819 m_custom->mute_channel(1);
820 break;
821
822 case 2:
823 /*
824 bit description
825
826 0 AS 1 (sound0 waveform)
827 1 AS 3 (sound0 waveform)
828 2 AS 2 (sound0 waveform)
829 3 AS 4 (sound0 waveform)
830 4 AS 5 (sound1 waveform)
831 5 AS 6 (sound1 waveform)
832 6 AS 7 (sound1 waveform)
833 7 AS 8 (sound1 waveform)
834 */
835
836 m_custom->build_waveform(0, (data & 0x9) | ((data & 2) << 1) | ((data & 4) >> 1));
837 m_custom->build_waveform(1, data >> 4);
838 break;
839
840 case 3:
841 /*
842 bit description
843
844 0 BC 1
845 1 BC 2
846 2 BC 3
847 3 MUSIC A10
848 4 MUSIC A9
849 5 MUSIC A8
850 6
851 7 INV
852 */
853
854 /* select tune in ROM based on sound command byte */
855 m_custom->set_channel_base(2, 0x1000 | ((data & 0x70) << 4));
856 break;
857 }
858 }
859
speech_w(uint8_t data)860 void fantasy_sound_device::speech_w(uint8_t data)
861 {
862 static const uint16_t fantasy_table[16] =
863 {
864 0x04000,
865 0x04297,
866 0x044b6,
867 0x04682,
868 0x04927,
869 0x04be0,
870 0x04cc2,
871 0x04e36,
872 0x05000,
873 0x05163,
874 0x052c9,
875 0x053fd,
876 0,
877 0,
878 0,
879 0
880 };
881
882 m_custom->speech_w(data, fantasy_table, 0);
883 }
884
device_add_mconfig(machine_config & config)885 void fantasy_sound_device::device_add_mconfig(machine_config &config)
886 {
887 SPEAKER(config, "mono").front_center();
888
889 SNK6502_SOUND(config, m_custom, 0);
890 m_custom->add_route(ALL_OUTPUTS, "mono", 0.50);
891
892 samples_device &samples(SAMPLES(config, "samples"));
893 samples.set_channels(1);
894 samples.set_samples_names(fantasy_sample_names);
895 samples.add_route(ALL_OUTPUTS, "mono", 0.5);
896
897 sn76477_device &sn76477_1(SN76477(config, "sn76477.1"));
898 // BOMB GND: 2,9,26,27 +5V: 15,25
899 sn76477_1.set_noise_params(RES_K(470), RES_M(1.5), CAP_P(220));
900 sn76477_1.set_decay_res(0);
901 sn76477_1.set_attack_params(0, 0);
902 sn76477_1.set_amp_res(RES_K(470));
903 sn76477_1.set_feedback_res(RES_K(4.7));
904 sn76477_1.set_vco_params(0, 0, 0);
905 sn76477_1.set_pitch_voltage(0);
906 sn76477_1.set_slf_params(0, 0);
907 sn76477_1.set_oneshot_params(0, 0);
908 sn76477_1.set_vco_mode(0);
909 sn76477_1.set_mixer_params(0, 1, 0);
910 // schematic does not show pin 1 grounded, but it must be.
911 // otherwise it is using the VCO for the envelope, but the VCO is not hooked up
912 sn76477_1.set_envelope_params(0, 1);
913 sn76477_1.set_enable(0);
914 sn76477_1.add_route(0, "discrete", 1.0, 0);
915
916 DISCRETE(config, m_discrete, fantasy_discrete);
917 m_discrete->add_route(ALL_OUTPUTS, "mono", 0.5);
918 }
919
device_start()920 void fantasy_sound_device::device_start()
921 {
922 save_item(NAME(m_last_port1));
923 }
924
device_reset()925 void fantasy_sound_device::device_reset()
926 {
927 // 41.6 Hz update (measured)
928 m_custom->set_music_clock(1 / 41.6);
929 }
930
931
nibbler_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)932 nibbler_sound_device::nibbler_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
933 : fantasy_sound_device(mconfig, NIBBLER_SOUND, tag, owner, clock)
934 {
935 }
936
device_add_mconfig(machine_config & config)937 void nibbler_sound_device::device_add_mconfig(machine_config &config)
938 {
939 fantasy_sound_device::device_add_mconfig(config);
940
941 config.device_remove("samples");
942 }
943
944
pballoon_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)945 pballoon_sound_device::pballoon_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
946 : fantasy_sound_device(mconfig, PBALLOON_SOUND, tag, owner, clock)
947 {
948 }
949
device_add_mconfig(machine_config & config)950 void pballoon_sound_device::device_add_mconfig(machine_config &config)
951 {
952 fantasy_sound_device::device_add_mconfig(config);
953
954 config.device_remove("samples");
955 }
956
device_reset()957 void pballoon_sound_device::device_reset()
958 {
959 // 40.3 Hz update (measured)
960 m_custom->set_music_clock(1 / 40.3);
961 }
962
963
sasuke_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)964 sasuke_sound_device::sasuke_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
965 : device_t(mconfig, SASUKE_SOUND, tag, owner, clock)
966 , m_custom(*this, "custom")
967 , m_samples(*this, "samples")
968 , m_last_port1(0)
969 {
970 }
971
sound_w(offs_t offset,uint8_t data)972 void sasuke_sound_device::sound_w(offs_t offset, uint8_t data)
973 {
974 switch (offset)
975 {
976 case 0:
977 /*
978 bit description
979
980 0 hit (ic52)
981 1 boss start (ic51)
982 2 shot
983 3 boss attack (ic48?)
984 4 ??
985 5
986 6
987 7 reset counter
988 */
989
990 if (BIT(~data & m_last_port1, 0))
991 m_samples->start(0, 0);
992 if (BIT(~data & m_last_port1, 1))
993 m_samples->start(1, 1);
994 if (BIT(~data & m_last_port1, 2))
995 m_samples->start(2, 2);
996 if (BIT(~data & m_last_port1, 3))
997 m_samples->start(3, 3);
998
999 if (BIT(data & ~m_last_port1, 7))
1000 {
1001 m_custom->reset_offset(0); // TODO: why is this the only game that needs this when unmuting?
1002 m_custom->unmute_channel(0);
1003 }
1004 else if (BIT(~data & m_last_port1, 7))
1005 m_custom->mute_channel(0);
1006
1007 m_last_port1 = data;
1008 break;
1009
1010 case 1:
1011 /*
1012 bit description
1013
1014 0
1015 1 wave form
1016 2 wave form
1017 3 wave form
1018 4 MUSIC A8
1019 5 MUSIC A9
1020 6 MUSIC A10
1021 7
1022 */
1023
1024 /* select tune in ROM based on sound command byte */
1025 m_custom->set_channel_base(0, 0x0000 | ((data & 0x70) << 4));
1026
1027 m_custom->set_sound0_stop_on_rollover(1);
1028
1029 /* bit 1-3 sound0 waveform control */
1030 m_custom->sasuke_build_waveform((data & 0x0e) >> 1);
1031 break;
1032 }
1033 }
1034
device_add_mconfig(machine_config & config)1035 void sasuke_sound_device::device_add_mconfig(machine_config &config)
1036 {
1037 SPEAKER(config, "mono").front_center();
1038
1039 SNK6502_SOUND(config, m_custom, 0);
1040 m_custom->add_route(ALL_OUTPUTS, "mono", 0.50);
1041
1042 samples_device &samples(SAMPLES(config, "samples"));
1043 samples.set_channels(4);
1044 samples.set_samples_names(sasuke_sample_names);
1045 samples.add_route(ALL_OUTPUTS, "mono", 0.12);
1046
1047 sn76477_device &sn76477_1(SN76477(config, "sn76477.1"));
1048 // ic48 GND: 2,22,26,27,28 +5V: 1,15,25
1049 sn76477_1.set_noise_params(RES_K(470), RES_K(150), CAP_P(4700));
1050 sn76477_1.set_decay_res(RES_K(22));
1051 sn76477_1.set_attack_params(CAP_U(10), RES_K(10));
1052 sn76477_1.set_amp_res(RES_K(100));
1053 sn76477_1.set_feedback_res(RES_K(47));
1054 sn76477_1.set_vco_params(0, 0, 0);
1055 sn76477_1.set_pitch_voltage(0);
1056 sn76477_1.set_slf_params(0, RES_K(10));
1057 sn76477_1.set_oneshot_params(CAP_U(2.2), RES_K(100));
1058 sn76477_1.set_vco_mode(0);
1059 sn76477_1.set_mixer_params(0, 1, 0);
1060 sn76477_1.set_envelope_params(1, 0);
1061 sn76477_1.set_enable(1);
1062 sn76477_1.add_route(ALL_OUTPUTS, "mono", 0.50);
1063
1064 sn76477_device &sn76477_2(SN76477(config, "sn76477.2"));
1065 // ic51 GND: 2,26,27 +5V: 1,15,22,25,28
1066 sn76477_2.set_noise_params(RES_K(340), RES_K(47), CAP_P(100));
1067 sn76477_2.set_decay_res(RES_K(470));
1068 sn76477_2.set_attack_params(CAP_U(4.7), RES_K(10));
1069 sn76477_2.set_amp_res(RES_K(100));
1070 sn76477_2.set_feedback_res(RES_K(47));
1071 sn76477_2.set_vco_params(0, CAP_P(220), RES_K(1000));
1072 sn76477_2.set_pitch_voltage(0);
1073 sn76477_2.set_slf_params(0, RES_K(220));
1074 sn76477_2.set_oneshot_params(CAP_U(22), RES_K(47));
1075 sn76477_2.set_vco_mode(1);
1076 sn76477_2.set_mixer_params(0, 1, 0);
1077 sn76477_2.set_envelope_params(1, 1);
1078 sn76477_2.set_enable(1);
1079 sn76477_2.add_route(ALL_OUTPUTS, "mono", 0.50);
1080
1081 sn76477_device &sn76477_3(SN76477(config, "sn76477.3"));
1082 // ic52 GND: 2,22,27,28 +5V: 1,15,25,26
1083 sn76477_3.set_noise_params(RES_K(330), RES_K(47), CAP_P(100));
1084 sn76477_3.set_decay_res(RES_K(1));
1085 sn76477_3.set_attack_params(0, RES_K(1));
1086 sn76477_3.set_amp_res(RES_K(100));
1087 sn76477_3.set_feedback_res(RES_K(47));
1088 sn76477_3.set_vco_params(0, CAP_P(1000), RES_K(1000));
1089 sn76477_3.set_pitch_voltage(0);
1090 sn76477_3.set_slf_params(CAP_U(1), RES_K(10));
1091 sn76477_3.set_oneshot_params(CAP_U(2.2), RES_K(150));
1092 sn76477_3.set_vco_mode(0);
1093 sn76477_3.set_mixer_params(1, 1, 0);
1094 sn76477_3.set_envelope_params(1, 0);
1095 sn76477_3.set_enable(1);
1096 sn76477_3.add_route(ALL_OUTPUTS, "mono", 0.50);
1097 }
1098
device_start()1099 void sasuke_sound_device::device_start()
1100 {
1101 save_item(NAME(m_last_port1));
1102 }
1103
device_reset()1104 void sasuke_sound_device::device_reset()
1105 {
1106 m_custom->set_music_clock(M_LN2 * (RES_K(18) + RES_K(1)) * CAP_U(1));
1107
1108 // adjusted (measured through audio recording of pcb)
1109 m_custom->set_music_freq(35300);
1110 }
1111
1112
satansat_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1113 satansat_sound_device::satansat_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1114 : device_t(mconfig, SATANSAT_SOUND, tag, owner, clock)
1115 , m_custom(*this, "custom")
1116 , m_samples(*this, "samples")
1117 , m_last_port1(0)
1118 {
1119 }
1120
sound_w(offs_t offset,uint8_t data)1121 void satansat_sound_device::sound_w(offs_t offset, uint8_t data)
1122 {
1123 switch (offset)
1124 {
1125 case 0:
1126 /*
1127 bit description
1128
1129 */
1130
1131 /* bit 0 = analog sound trigger */
1132
1133 /* bit 1 = to 76477 */
1134
1135 /* bit 2 = analog sound trigger */
1136 if (data & 0x04 && !(m_last_port1 & 0x04))
1137 m_samples->start(0, 1);
1138
1139 if (data & 0x08)
1140 m_custom->mute_channel(0);
1141
1142 /* bit 4-6 sound0 waveform control */
1143 m_custom->sasuke_build_waveform((data & 0x70) >> 4);
1144
1145 /* bit 7 sound1 waveform control */
1146 m_custom->satansat_build_waveform((data & 0x80) >> 7);
1147
1148 m_last_port1 = data;
1149 break;
1150
1151 case 1:
1152 /*
1153 bit description
1154
1155 */
1156
1157 /* select tune in ROM based on sound command byte */
1158 m_custom->set_channel_base(0, 0x0000 | ((data & 0x0e) << 7));
1159 m_custom->set_channel_base(1, 0x0800 | ((data & 0x60) << 4), 0x1ff);
1160
1161 m_custom->set_sound0_stop_on_rollover(1);
1162
1163 if (data & 0x01)
1164 m_custom->unmute_channel(0);
1165
1166 if (data & 0x10)
1167 m_custom->unmute_channel(1);
1168 else
1169 m_custom->mute_channel(1);
1170
1171 /* bit 7 = ? */
1172 break;
1173 }
1174 }
1175
device_add_mconfig(machine_config & config)1176 void satansat_sound_device::device_add_mconfig(machine_config &config)
1177 {
1178 SPEAKER(config, "mono").front_center();
1179
1180 SNK6502_SOUND(config, m_custom, 0);
1181 m_custom->add_route(ALL_OUTPUTS, "mono", 0.50);
1182
1183 samples_device &samples(SAMPLES(config, "samples"));
1184 samples.set_channels(3);
1185 samples.set_samples_names(vanguard_sample_names);
1186 samples.add_route(ALL_OUTPUTS, "mono", 0.25);
1187
1188 sn76477_device &sn76477_1(SN76477(config, "sn76477.1"));
1189 // ??? GND: 2,26,27 +5V: 15,25
1190 sn76477_1.set_noise_params(RES_K(470), RES_M(1.5), CAP_P(220));
1191 sn76477_1.set_decay_res(0);
1192 sn76477_1.set_attack_params(0, 0);
1193 sn76477_1.set_amp_res(RES_K(47));
1194 sn76477_1.set_feedback_res(RES_K(47));
1195 sn76477_1.set_vco_params(0, 0, 0);
1196 sn76477_1.set_pitch_voltage(0);
1197 sn76477_1.set_slf_params(0, 0);
1198 sn76477_1.set_oneshot_params(0, 0);
1199 sn76477_1.set_vco_mode(0);
1200 sn76477_1.set_mixer_params(0, 1, 0);
1201 sn76477_1.set_envelope_params(1, 1);
1202 sn76477_1.set_enable(1);
1203 sn76477_1.add_route(ALL_OUTPUTS, "mono", 1.0);
1204 }
1205
device_start()1206 void satansat_sound_device::device_start()
1207 {
1208 save_item(NAME(m_last_port1));
1209 }
1210
device_reset()1211 void satansat_sound_device::device_reset()
1212 {
1213 // same as sasuke (assumption?)
1214 // NOTE: this was set before sasuke was adjusted to a lower freq, please don't modify until measured/confirmed on pcb
1215 m_custom->set_music_freq(38000);
1216 }
1217