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