1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria, Tormod Tjaberg, Mirko Buffoni,Lee Taylor, Valerio Verrando, Zsolt Vasvari,Aaron Giles,Jonathan Gevaryahu,hap,Robbbert
3 // thanks-to:Michael Strutts, Marco Cassili
4 /* 8080bw.c *******************************************/
5 
6 #include "emu.h"
7 #include "includes/8080bw.h"
8 
9 #include "sound/samples.h"
10 #include "sound/discrete.h"
11 #include "speaker.h"
12 
13 #include <cmath>
14 
15 //#define VERBOSE 1
16 #include "logmacro.h"
17 
18 
19 /*******************************************************/
20 /*                                                     */
21 /* Global state registration                           */
22 /*                                                     */
23 /*******************************************************/
24 
MACHINE_START_MEMBER(_8080bw_state,extra_8080bw_sh)25 MACHINE_START_MEMBER(_8080bw_state,extra_8080bw_sh)
26 {
27 	save_item(NAME(m_port_1_last_extra));
28 	save_item(NAME(m_port_2_last_extra));
29 	save_item(NAME(m_port_3_last_extra));
30 }
31 
32 /*************************************
33  *
34  *  Device type globals
35  *
36  *************************************/
37 
38 DEFINE_DEVICE_TYPE(CANE_AUDIO,  cane_audio_device,  "cane_audio",  "Model Racing Cane Audio")
39 
40 
41 /*************************************
42  *
43  *  Space Invaders
44  *
45  *  Author      : Tormod Tjaberg
46  *  Created     : 1997-04-09
47  *  Description : Sound routines for the 'invaders' games
48  *
49  *  Note:
50  *  The samples were taken from Michael Strutt's (mstrutt@pixie.co.za)
51  *  excellent space invader emulator and converted to signed samples so
52  *  they would work under SEAL. The port info was also gleaned from
53  *  his emulator. These sounds should also work on all the invader games.
54  *
55  *************************************/
56 
57 static const char *const invaders_sample_names[] =
58 {
59 	"*invaders",
60 	"1",        /* shot/missle */
61 	"2",        /* base hit/explosion */
62 	"3",        /* invader hit */
63 	"4",        /* fleet move 1 */
64 	"5",        /* fleet move 2 */
65 	"6",        /* fleet move 3 */
66 	"7",        /* fleet move 4 */
67 	"8",        /* UFO/saucer hit */
68 	"9",        /* bonus base */
69 	nullptr
70 };
71 
72 
73 /* left in for all games that hack into invaders samples for audio */
invaders_samples_audio(machine_config & config)74 void _8080bw_state::invaders_samples_audio(machine_config &config)
75 {
76 	SPEAKER(config, "mono").front_center();
77 
78 	SN76477(config, m_sn);
79 	m_sn->set_noise_params(0, 0, 0);
80 	m_sn->set_decay_res(0);
81 	m_sn->set_attack_params(0, RES_K(100));
82 	m_sn->set_amp_res(RES_K(56));
83 	m_sn->set_feedback_res(RES_K(10));
84 	m_sn->set_vco_params(0, CAP_U(0.1), RES_K(8.2));
85 	m_sn->set_pitch_voltage(5.0);
86 	m_sn->set_slf_params(CAP_U(1.0), RES_K(120));
87 	m_sn->set_oneshot_params(0, 0);
88 	m_sn->set_vco_mode(1);
89 	m_sn->set_mixer_params(0, 0, 0);
90 	m_sn->set_envelope_params(1, 0);
91 	m_sn->set_enable(1);
92 	m_sn->add_route(ALL_OUTPUTS, "mono", 0.5);
93 
94 	SAMPLES(config, m_samples);
95 	m_samples->set_channels(6);
96 	m_samples->set_samples_names(invaders_sample_names);
97 	m_samples->add_route(ALL_OUTPUTS, "mono", 1.0);
98 }
99 
100 
101 
102 /*******************************************************/
103 /*                                                     */
104 /* Midway "Space Invaders Part II"                     */
105 /*                                                     */
106 /*******************************************************/
107 
invadpt2_sh_port_1_w(uint8_t data)108 void _8080bw_state::invadpt2_sh_port_1_w(uint8_t data)
109 {
110 	uint8_t rising_bits = data & ~m_port_1_last_extra;
111 
112 	m_sn->enable_w(!(data & 0x01));         /* SAUCER SOUND */
113 
114 	if (rising_bits & 0x02) m_samples->start(0, 0);     /* MISSLE SOUND */
115 	if (rising_bits & 0x04) m_samples->start(1, 1);     /* EXPLOSION */
116 	if (rising_bits & 0x08) m_samples->start(2, 2);     /* INVADER HIT */
117 	if (rising_bits & 0x10) m_samples->start(5, 8);     /* BONUS MISSILE BASE */
118 
119 	m_screen_red = data & 0x04;
120 
121 	machine().sound().system_enable(data & 0x20);
122 
123 	m_port_1_last_extra = data;
124 }
125 
invadpt2_sh_port_2_w(uint8_t data)126 void _8080bw_state::invadpt2_sh_port_2_w(uint8_t data)
127 {
128 	/* FLEET (movement)
129 
130 	   DO = 20K + 20K
131 	   D1 = 68K
132 	   D2 = 82K
133 	   D3 = 100K */
134 
135 	uint8_t rising_bits = data & ~m_port_2_last_extra;
136 
137 	if (rising_bits & 0x01) m_samples->start(4, 3);     /* FLEET */
138 	if (rising_bits & 0x02) m_samples->start(4, 4);     /* FLEET */
139 	if (rising_bits & 0x04) m_samples->start(4, 5);     /* FLEET */
140 	if (rising_bits & 0x08) m_samples->start(4, 6);     /* FLEET */
141 	if (rising_bits & 0x10) m_samples->start(3, 7);     /* SAUCER HIT */
142 
143 	m_flip_screen = BIT(data, 5) & ioport(CABINET_PORT_TAG)->read();
144 	m_color_map = BIT(data, 5);
145 
146 	m_port_2_last_extra = data;
147 }
148 
149 
150 
151 /*******************************************************/
152 /*                                                     */
153 /* Space Ranger                                        */
154 /*                                                     */
155 /*******************************************************/
156 
spacerng_sh_port_2_w(uint8_t data)157 void _8080bw_state::spacerng_sh_port_2_w(uint8_t data)
158 {
159 	uint8_t rising_bits = data & ~m_port_2_last_extra;
160 
161 	if (rising_bits & 0x01) m_samples->start(4, 3);     /* FLEET */
162 	if (rising_bits & 0x02) m_samples->start(4, 4);     /* FLEET */
163 	if (rising_bits & 0x04) m_samples->start(4, 5);     /* FLEET */
164 	if (rising_bits & 0x08) m_samples->start(4, 6);     /* FLEET */
165 	if (rising_bits & 0x10) m_samples->start(3, 7);     /* SAUCER HIT */
166 
167 	m_flip_screen = BIT(~data, 5) & ioport(CABINET_PORT_TAG)->read();
168 
169 	m_port_2_last_extra = data;
170 }
171 
172 /*******************************************************/
173 /*                                                     */
174 /* Sanritsu "Space War"                                */
175 /*                                                     */
176 /*******************************************************/
177 
spcewars_sh_port_w(uint8_t data)178 void _8080bw_state::spcewars_sh_port_w(uint8_t data)
179 {
180 	uint8_t rising_bits = data & ~m_port_1_last_extra;
181 
182 	m_sn->enable_w(!(data & 0x01));         /* Saucer Sound */
183 
184 	if (rising_bits & 0x02) m_samples->start(0, 0);     /* Shot Sound */
185 	if (rising_bits & 0x04) m_samples->start(1, 1);     /* Base Hit */
186 	if (rising_bits & 0x08) m_samples->start(2, 2);     /* Invader Hit */
187 
188 	m_speaker->level_w(BIT(data, 4));      /* Various bitstream tunes */
189 
190 	m_port_1_last_extra = data;
191 }
192 
193 
194 
195 /*******************************************************/
196 /*                                                     */
197 /* lrescue, grescue, lrescuem, desterth                */
198 /*                                                     */
199 /*******************************************************/
200 
201 const char *const lrescue_sample_names[] =
202 {
203 	"*lrescue",
204 	"alienexplosion",
205 	"rescueshipexplosion",
206 	"beamgun",
207 	"thrust",
208 	"bonus2",
209 	"bonus3",
210 	"shootingstar",
211 	"stepl",
212 	"steph",
213 	nullptr
214 };
215 
lrescue_sh_port_1_w(uint8_t data)216 void _8080bw_state::lrescue_sh_port_1_w(uint8_t data)
217 {
218 	uint8_t rising_bits = data & ~m_port_1_last_extra;
219 
220 	if (rising_bits & 0x01) m_samples->start(0, 3);     /* Thrust */
221 	if (rising_bits & 0x02) m_samples->start(1, 2);     /* Shot Sound */
222 	if (rising_bits & 0x04) m_samples->start(0, 1);     /* Death */
223 	if (rising_bits & 0x08) m_samples->start(1, 0);     /* Alien Hit */
224 	if (rising_bits & 0x10) m_samples->start(2, 5);     /* Bonus Ship (not confirmed) */
225 
226 	machine().sound().system_enable(data & 0x20);
227 
228 	m_screen_red = data & 0x04;
229 
230 	m_port_1_last_extra = data;
231 }
232 
lrescue_sh_port_2_w(uint8_t data)233 void _8080bw_state::lrescue_sh_port_2_w(uint8_t data)
234 {
235 	uint8_t rising_bits = data & ~m_port_2_last_extra;
236 
237 	if (rising_bits & 0x01) m_samples->start(1, 8);     /* Footstep high tone */
238 	if (rising_bits & 0x02) m_samples->start(1, 7);     /* Footstep low tone */
239 	if (rising_bits & 0x04) m_samples->start(1, 4);     /* Bonus when counting men saved */
240 
241 	m_speaker->level_w(BIT(data, 3));                   /* Bitstream tunes - endlevel and bonus1 */
242 
243 	if (rising_bits & 0x10) m_samples->start(3, 6);     /* Shooting Star and Rescue Ship sounds */
244 	if ((~data & 0x10) && (m_port_2_last_extra & 0x10)) m_samples->stop(3); /* This makes the rescue ship sound beep on and off */
245 
246 	m_flip_screen = BIT(data, 5) & ioport(CABINET_PORT_TAG)->read();
247 
248 	m_port_2_last_extra = data;
249 }
250 
251 
252 
253 /*******************************************************/
254 /*                                                     */
255 /* Cosmo                                               */
256 /*                                                     */
257 /*******************************************************/
258 
cosmo_sh_port_2_w(uint8_t data)259 void _8080bw_state::cosmo_sh_port_2_w(uint8_t data)
260 {
261 	/* inverted flip screen bit */
262 	invadpt2_sh_port_2_w(data ^ 0x20);
263 }
264 
265 
266 
267 /*******************************************************/
268 /*                                                     */
269 /* Taito "Balloon Bomber"                              */
270 /*   The sounds are not the correct ones               */
271 /*                                                     */
272 /*******************************************************/
273 
274 /*************************************
275  *
276  *  Discrete Sound
277  * (copied from indianbt)
278  *
279  *************************************/
280 
281 static const discrete_dac_r1_ladder ballbomb_music_dac =
282 	{3, {0, RES_K(47), RES_K(12)}, 0, 0, 0, CAP_U(0.1)};
283 
284 #define BALLBOMB_MUSIC_CLK      (3993.6*2*2*2)
285 
286 /* Nodes - Inputs */
287 #define BALLBOMB_MUSIC_DATA     NODE_01
288 /* Nodes - Sounds */
289 #define BALLBOMB_MUSIC          NODE_11
290 
291 DISCRETE_SOUND_START(ballbomb_discrete)
292 
DISCRETE_INPUT_DATA(BALLBOMB_MUSIC_DATA)293 	DISCRETE_INPUT_DATA (BALLBOMB_MUSIC_DATA)
294 
295 /******************************************************************************
296  *
297  * Music Generator
298  *
299  ******************************************************************************/
300 	DISCRETE_NOTE(NODE_20, 1, BALLBOMB_MUSIC_CLK, BALLBOMB_MUSIC_DATA, 255, 5, DISC_CLK_IS_FREQ)
301 
302 	// Convert count to 7492 output
303 	DISCRETE_TRANSFORM2(NODE_21, NODE_20, 2, "01>0+")
304 
305 	DISCRETE_DAC_R1(NODE_22, NODE_21, DEFAULT_TTL_V_LOGIC_1, &ballbomb_music_dac)
306 
307 /******************************************************************************
308  *
309  * Final Mixing and Output
310  *
311  ******************************************************************************/
312 	DISCRETE_CRFILTER(NODE_90, NODE_22, RES_K(10), CAP_U(0.1))
313 
314 	DISCRETE_OUTPUT(NODE_90, 21000)
315 
316 DISCRETE_SOUND_END
317 
318 void _8080bw_state::ballbomb_01_w(uint8_t data)
319 {
320 	m_discrete->write(BALLBOMB_MUSIC_DATA, data|0x80);
321 }
322 
ballbomb_sh_port_1_w(uint8_t data)323 void _8080bw_state::ballbomb_sh_port_1_w(uint8_t data)
324 {
325 	uint8_t rising_bits = data & ~m_port_1_last_extra;
326 
327 	if (rising_bits & 0x01) m_samples->start(1, 2);     /* Hit a balloon */
328 	if (rising_bits & 0x02) m_samples->start(2, 0);     /* Shot Sound */
329 	if (rising_bits & 0x04) m_samples->start(2, 1);     /* Base Hit */
330 	if (rising_bits & 0x08) m_samples->start(1, 7);     /* Hit a Bomb */
331 	if (rising_bits & 0x10) m_samples->start(3, 8);     /* Bonus Base at 1500 points */
332 
333 	machine().sound().system_enable(data & 0x20);
334 
335 	m_screen_red = data & 0x04;
336 
337 	m_port_1_last_extra = data;
338 }
339 
ballbomb_sh_port_2_w(uint8_t data)340 void _8080bw_state::ballbomb_sh_port_2_w(uint8_t data)
341 {
342 	uint8_t rising_bits = data & ~m_port_2_last_extra;
343 
344 	if (data & 0x01) m_samples->start(0, 7);        /* Indicates plane will drop bombs */
345 	if (data & 0x04) m_samples->start(0, 4);        /* Plane is dropping new balloons at start of level */
346 	if (rising_bits & 0x10) m_samples->start(2, 2);     /* Balloon hit and bomb drops */
347 
348 	m_flip_screen = BIT(data, 5) & ioport(CABINET_PORT_TAG)->read();
349 
350 	m_port_2_last_extra = data;
351 }
352 
353 
354 
355 /*******************************************************/
356 /*                                                     */
357 /* Taito "Indian Battle"                               */
358 /* Sept 2005, D.R.                                     */
359 /*******************************************************/
360 
361 static const discrete_dac_r1_ladder indianbt_music_dac =
362 	{3, {0, RES_K(47), RES_K(12)}, 0, 0, 0, CAP_U(0.1)};
363 
364 #define INDIANBT_MUSIC_CLK      (7680.0*2*2*2)
365 
366 /* Nodes - Inputs */
367 #define INDIANBT_MUSIC_DATA     NODE_01
368 /* Nodes - Sounds */
369 #define INDIANBT_MUSIC          NODE_11
370 
371 DISCRETE_SOUND_START(indianbt_discrete)
372 
DISCRETE_INPUT_DATA(INDIANBT_MUSIC_DATA)373 	DISCRETE_INPUT_DATA (INDIANBT_MUSIC_DATA)
374 
375 /******************************************************************************
376  *
377  * Music Generator
378  *
379  ******************************************************************************/
380 	DISCRETE_NOTE(NODE_20, 1, INDIANBT_MUSIC_CLK, INDIANBT_MUSIC_DATA, 255, 5, DISC_CLK_IS_FREQ)
381 
382 	// Convert count to 7492 output
383 	DISCRETE_TRANSFORM2(NODE_21, NODE_20, 2, "01>0+")
384 
385 	DISCRETE_DAC_R1(NODE_22, NODE_21, DEFAULT_TTL_V_LOGIC_1, &indianbt_music_dac)
386 
387 /******************************************************************************
388  *
389  * Final Mixing and Output
390  *
391  ******************************************************************************/
392 	DISCRETE_CRFILTER(NODE_90, NODE_22, RES_K(10), CAP_U(0.1))
393 
394 	DISCRETE_OUTPUT(NODE_90, 21000)
395 
396 DISCRETE_SOUND_END
397 
398 void _8080bw_state::indianbt_sh_port_1_w(uint8_t data)
399 {
400 	/* bit 4 occurs every 5.25 seconds during gameplay */
401 	uint8_t rising_bits = data & ~m_port_1_last_extra;
402 
403 	if (rising_bits & 0x01) m_samples->start(1, 7);     /* Death */
404 	if (rising_bits & 0x02) m_samples->start(0, 1);     /* Shot Sound */
405 	if (rising_bits & 0x04) m_samples->start(2, 3);     /* Move */
406 	if (rising_bits & 0x08) m_samples->start(3, 2);     /* Hit */
407 
408 	machine().sound().system_enable(data & 0x20);
409 
410 	m_port_1_last_extra = data;
411 }
412 
indianbt_sh_port_2_w(uint8_t data)413 void _8080bw_state::indianbt_sh_port_2_w(uint8_t data)
414 {
415 	uint8_t rising_bits = data & ~m_port_2_last_extra;
416 
417 	if (rising_bits & 0x01) m_samples->start(4, 0);     /* Bird dropped an egg, Lasso used */
418 	if (rising_bits & 0x02) m_samples->start(4, 2);     /* Egg hatches, egg shot */
419 	if (rising_bits & 0x08) m_samples->start(5, 0);     /* Grabber, Lasso caught something */
420 	if (rising_bits & 0x10) m_samples->start(3, 7);     /* Lasso sound */
421 
422 	m_flip_screen = BIT(data, 5) & ioport(CABINET_PORT_TAG)->read();
423 
424 	m_port_2_last_extra = data;
425 }
426 
indianbt_sh_port_3_w(uint8_t data)427 void _8080bw_state::indianbt_sh_port_3_w(uint8_t data)
428 {
429 	m_discrete->write(INDIANBT_MUSIC_DATA, data);
430 }
431 
indianbtbr_sh_port_1_w(uint8_t data)432 void _8080bw_state::indianbtbr_sh_port_1_w(uint8_t data)
433 {
434 	uint8_t rising_bits = data & ~m_port_1_last_extra;
435 
436 	if (rising_bits & 0x01) m_samples->start(4, 7);     /* Lasso */
437 	if (rising_bits & 0x04) m_samples->start(0, 1);     /* Shot Sound */
438 	if (rising_bits & 0x08) m_samples->start(3, 2);     /* Hit */
439 
440 	machine().sound().system_enable(data & 0x20);
441 
442 	m_port_1_last_extra = data;
443 }
444 
indianbtbr_sh_port_2_w(uint8_t data)445 void _8080bw_state::indianbtbr_sh_port_2_w(uint8_t data)
446 {
447 	uint8_t rising_bits = data & ~m_port_2_last_extra;
448 
449 	if (rising_bits & 0x08) m_samples->start(2, 3);     /* Move */
450 	if (rising_bits & 0x10) m_samples->start(3, 7);     /* Death */
451 
452 	m_flip_screen = BIT(data, 5) & ioport(CABINET_PORT_TAG)->read();
453 
454 	m_port_2_last_extra = data;
455 }
456 
457 
458 
459 /*******************************************************************/
460 /*                                                                 */
461 /* Taito "Polaris"                                                 */
462 /*                                                                 */
463 /* D.R.                                                            */
464 /* The R/C values in the schematic may have no bearing in reality. */
465 /* I have noted some differences from a real board.                */
466 /*                                                                 */
467 /*******************************************************************/
468 
469 static const discrete_lfsr_desc polaris_lfsr={
470 	DISC_CLK_IS_FREQ,
471 	17,         /* Bit Length */
472 	0,          /* Reset Value */
473 	4,          /* Use Bit 4 as XOR input 0 */
474 	16,         /* Use Bit 16 as XOR input 1 */
475 	DISC_LFSR_XOR,      /* Feedback stage1 is XOR */
476 	DISC_LFSR_OR,       /* Feedback stage2 is just stage 1 output OR with external feed */
477 	DISC_LFSR_REPLACE,  /* Feedback stage3 replaces the shifted register contents */
478 	0x000001,       /* Everything is shifted into the first bit only */
479 	0,          /* Output is not inverted */
480 	12          /* Output bit */
481 };
482 
483 static const discrete_dac_r1_ladder polaris_music_dac =
484 	{2, {RES_K(47), RES_K(12), 0,0,0,0,0,0}, 0, 0, 0, CAP_P(180)};
485 
486 static const discrete_op_amp_filt_info polaris_music_op_amp_filt_info =
487 	{RES_K(580), 0, 0, RES_M(2.2), RES_M(1), CAP_U(.01), 0, 0, 0, 12, 0};
488 
489 static const discrete_op_amp_filt_info polaris_nol_op_amp_filt_info =
490 	{560, RES_K(6.8), RES_K(1002), RES_M(2.2), RES_M(1), CAP_U(.22), CAP_U(.22), CAP_U(1), 0, 12, 0};
491 
492 static const discrete_op_amp_filt_info polaris_noh_op_amp_filt_info =
493 	{560, RES_K(6.8), RES_K(1002), RES_M(2.2), RES_M(1), CAP_U(.001), CAP_U(.001), CAP_U(.01), 0, 12, 0};
494 
495 static const discrete_op_amp_osc_info polaris_sonar_vco_info =
496 	{DISC_OP_AMP_OSCILLATOR_VCO_1 | DISC_OP_AMP_IS_NORTON | DISC_OP_AMP_OSCILLATOR_OUT_CAP, RES_M(1), RES_K(680), RES_K(680), RES_M(1), RES_M(1), RES_K(120), RES_M(1), 0, CAP_P(180), 12};
497 
498 static const discrete_op_amp_tvca_info polaris_sonar_tvca_info =
499 	{ RES_M(2.7), RES_K(680), 0, RES_K(680), RES_K(1), RES_K(120), RES_K(560), 0, 0, 0, 0, CAP_U(1), 0, 0, 0, 12, 12, 12, 12, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_TRG1, DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE};
500 
501 static const discrete_op_amp_osc_info polaris_boat_mod_info =
502 	{DISC_OP_AMP_OSCILLATOR_1 | DISC_OP_AMP_IS_NORTON | DISC_OP_AMP_OSCILLATOR_OUT_CAP, RES_M(1), RES_K(10), RES_K(100), RES_K(120), RES_M(1), 0, 0, 0, CAP_U(.22), 12};
503 
504 static const discrete_op_amp_osc_info polaris_boat_vco_info =
505 	{DISC_OP_AMP_OSCILLATOR_VCO_1 | DISC_OP_AMP_IS_NORTON | DISC_OP_AMP_OSCILLATOR_OUT_CAP, RES_M(1), RES_K(680), RES_K(680), RES_M(1), RES_M(1), 0, 0, 0, CAP_P(180), 12};
506 
507 static const discrete_op_amp_tvca_info polaris_shot_tvca_info =
508 	{ RES_M(2.7), RES_K(680), RES_K(680), RES_K(680), RES_K(1), 0, RES_K(680), 0, 0, 0, 0, CAP_U(1), 0, 0, 0, 12, 12, 12, 12, DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV, DISC_OP_AMP_TRIGGER_FUNCTION_TRG0, DISC_OP_AMP_TRIGGER_FUNCTION_TRG0, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE};
509 
510 static const discrete_op_amp_tvca_info polaris_shiphit_tvca_info =
511 	{ RES_M(2.7), RES_K(680), RES_K(680), RES_K(680), RES_K(1), 0, RES_K(680), 0, 0, 0, 0, CAP_U(1), 0, 0, 0, 12, 12, 12, 12, DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_TRG0, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE};
512 
513 static const discrete_op_amp_tvca_info polaris_exp_tvca_info =
514 	{ RES_M(2.7), RES_K(680), 0, RES_K(680), RES_K(1), 0, RES_K(680), 0, 0, 0, 0, CAP_U(.33), 0, 0, 0, 12, 12, 12, 12, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_TRG0, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE};
515 
516 // The schematic shows a .22uF cap but Guru's board has a 1uF
517 static const discrete_op_amp_tvca_info polaris_hit_tvca_info =
518 	{ RES_M(2.7), RES_K(1360), RES_K(1360), RES_K(680), RES_K(1), 0, RES_K(680), 0, 0, 0, 0, CAP_U(1), 0, 0, 0, 12, 12, 12, 12, DISC_OP_AMP_TRIGGER_FUNCTION_TRG0, DISC_OP_AMP_TRIGGER_FUNCTION_TRG1, DISC_OP_AMP_TRIGGER_FUNCTION_TRG01_NAND, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE, DISC_OP_AMP_TRIGGER_FUNCTION_NONE};
519 
520 // The schematic shows a 1uF cap but Guru's board has a 2.2uF
521 static const discrete_integrate_info polaris_plane_integrate_info =
522 	{DISC_INTEGRATE_OP_AMP_2 | DISC_OP_AMP_IS_NORTON, RES_K(1001), RES_K(1001), RES_K(101), CAP_U(2.2), 12, 12, DISC_OP_AMP_TRIGGER_FUNCTION_TRG0, DISC_OP_AMP_TRIGGER_FUNCTION_TRG0_INV, DISC_OP_AMP_TRIGGER_FUNCTION_TRG1_INV};
523 
524 // A bit of a cheat.  The schematic show the cap as 47p, but that makes the frequency too high.
525 // Guru's board has a .01 cap, which would make the freq sub-sonic using the other schematic values.
526 // I will use 2000p until the proper values can be confirmed.
527 static const discrete_op_amp_osc_info polaris_plane_vco_info =
528 	{DISC_OP_AMP_OSCILLATOR_VCO_1 | DISC_OP_AMP_IS_NORTON | DISC_OP_AMP_OSCILLATOR_OUT_CAP, RES_M(1), RES_K(680), RES_K(680), RES_M(1), RES_M(1), RES_K(100), RES_K(10), RES_K(100), CAP_U(0.002), 12};
529 
530 static const discrete_mixer_desc polaris_mixer_vr1_desc =
531 	{DISC_MIXER_IS_RESISTOR,
532 		{RES_K(66), RES_K(43), RES_K(20), RES_K(43)},
533 		{0},    // no variable resistors
534 		{CAP_U(1), CAP_U(1), CAP_U(1), CAP_U(1)},
535 		0, RES_K(50), 0, 0, 0, 1};
536 
537 static const discrete_mixer_desc polaris_mixer_vr2_desc =
538 	{DISC_MIXER_IS_RESISTOR,
539 		{RES_K(66), RES_K(110)},
540 		{0},    // no variable resistors
541 		{CAP_U(1), CAP_U(1)},
542 		0, RES_K(50), 0, 0, 0, 1};
543 
544 // Note: the final gain leaves the explosions (SX3) at a level
545 // where they clip.  From the schematics, this is how they wanted it.
546 // This makes them have more bass and distortion.
547 static const discrete_mixer_desc polaris_mixer_vr4_desc =
548 	{DISC_MIXER_IS_RESISTOR,
549 		{RES_K(22), RES_K(20), RES_K(22), RES_K(22)},
550 		{0},    // no variable resistors
551 		{0, CAP_U(1), 0, 0},
552 		0, RES_K(50), 0, CAP_U(1), 0, 40000};
553 
554 /* Nodes - Inputs */
555 #define POLARIS_MUSIC_DATA      NODE_01
556 #define POLARIS_SX0_EN          NODE_02
557 #define POLARIS_SX1_EN          NODE_03
558 #define POLARIS_SX2_EN          NODE_04
559 #define POLARIS_SX3_EN          NODE_05
560 #define POLARIS_SX5_EN          NODE_06
561 #define POLARIS_SX6_EN          NODE_07
562 #define POLARIS_SX7_EN          NODE_08
563 #define POLARIS_SX9_EN          NODE_09
564 #define POLARIS_SX10_EN         NODE_10
565 /* Nodes - Sounds */
566 #define POLARIS_MUSIC           NODE_11
567 #define POLARIS_NOISE_LO        NODE_12
568 #define POLARIS_NOISE_LO_FILT   NODE_13
569 #define POLARIS_NOISE_HI_FILT   NODE_14
570 #define POLARIS_SHOTSND         NODE_15
571 #define POLARIS_SHIP_HITSND     NODE_16
572 #define POLARIS_SHIPSND         NODE_17
573 #define POLARIS_EXPLOSIONSND    NODE_18
574 #define POLARIS_PLANESND        NODE_19
575 #define POLARIS_HITSND          NODE_20
576 #define POLARIS_SONARSND        NODE_21
577 /* Nodes - Adjust */
578 #define POLARIS_ADJ_VR1         NODE_23
579 #define POLARIS_ADJ_VR2         NODE_24
580 #define POLARIS_ADJ_VR3         NODE_25
581 
582 DISCRETE_SOUND_START(polaris_discrete)
583 
584 	/************************************************/
585 	/* Polaris sound system: 8 Sound Sources        */
586 	/*                                              */
587 	/* Relative volumes are adjustable              */
588 	/*                                              */
589 	/************************************************/
590 
591 	/************************************************/
592 	/* Input register mapping for polaris           */
593 	/************************************************/
DISCRETE_INPUT_DATA(POLARIS_MUSIC_DATA)594 	DISCRETE_INPUT_DATA (POLARIS_MUSIC_DATA)
595 	DISCRETE_INPUT_LOGIC(POLARIS_SX0_EN)
596 	DISCRETE_INPUT_LOGIC(POLARIS_SX1_EN)
597 	DISCRETE_INPUT_LOGIC(POLARIS_SX2_EN)
598 	DISCRETE_INPUT_LOGIC(POLARIS_SX3_EN)
599 	DISCRETE_INPUT_LOGIC(POLARIS_SX5_EN)
600 	DISCRETE_INPUT_LOGIC(POLARIS_SX6_EN)
601 	DISCRETE_INPUT_LOGIC(POLARIS_SX7_EN)
602 	DISCRETE_INPUT_LOGIC(POLARIS_SX9_EN)
603 	DISCRETE_INPUT_LOGIC(POLARIS_SX10_EN)
604 
605 	/* We will cheat and just use the controls to scale the amplitude. */
606 	/* It is the same as taking the (0 to 50k)/50k */
607 	DISCRETE_ADJUSTMENT(POLARIS_ADJ_VR1, 0, 1, DISC_LINADJ, "VR1")
608 	DISCRETE_ADJUSTMENT(POLARIS_ADJ_VR2, 0, 1, DISC_LINADJ, "VR2")
609 	/* Extra cheating for VR3.  We will include the resistor scaling. */
610 	DISCRETE_ADJUSTMENT(POLARIS_ADJ_VR3, 0, 0.5376, DISC_LINADJ, "VR3")
611 
612 /******************************************************************************
613  *
614  * Music Generator
615  *
616  * This is a simulation of the following circuit:
617  * 555 Timer (Ra = 1k, Rb = 1k, C =.01uF) running at 48kHz.  Connected to a
618  * 1 bit counter (/2) for 24kHz.  But I will use the frequency measured by Guru.
619  * This is then sent to a preloadable 8 bit counter (4G & 4H), which loads the
620  * value from Port 2 when overflowing from 0xFF to 0x00.  Therefore it divides
621  * by 2 (Port 2 = FE) to 256 (Port 2 = 00).
622  * This goes to a 2 bit counter (5H) which has a 47k resistor on Q0 and a 12k on Q1.
623  * This creates a sawtooth ramp of: 0%, 12/59%, 47/59%, 100% then back to 0%
624  *
625  * Note that there is no music disable line.  When there is no music, the game
626  * sets the oscillator to 0Hz.  (Port 2 = FF)
627  *
628  ******************************************************************************/
629 	DISCRETE_NOTE(NODE_30, 1, 23396, POLARIS_MUSIC_DATA, 255, 3, DISC_CLK_IS_FREQ)
630 	DISCRETE_DAC_R1(NODE_31, NODE_30, DEFAULT_TTL_V_LOGIC_1, &polaris_music_dac)
631 	DISCRETE_OP_AMP_FILTER(NODE_32, 1, NODE_31, 0, DISC_OP_AMP_FILTER_IS_HIGH_PASS_0 | DISC_OP_AMP_IS_NORTON, &polaris_music_op_amp_filt_info)
632 	DISCRETE_MULTIPLY(POLARIS_MUSIC, NODE_32, POLARIS_ADJ_VR3)
633 
634 /******************************************************************************
635  *
636  * Background Sonar Sound
637  *
638  * This is a background sonar that plays at all times during the game.
639  * It is a VCO triangle wave genarator, that uses the Low frequency filtered
640  * noise source to modulate the frequency.
641  * This is then amplitude modulated, by some fancy clocking scheme.
642  * It is disabled during SX3.  (No sonar when you die.)
643  *
644  * 5L pin 6 divides 60Hz by 16.  This clocks the sonar.
645  * 5K pin 9 is inverted by 5F, and then the 0.1uF;1M;270k;1S1588 diode circuit
646  * makes a one shot pulse of approx. 15ms to keep the noise working.
647  *
648  ******************************************************************************/
649 	DISCRETE_SQUAREWFIX(NODE_40, 1, 60.0/16, 1, 50, 1.0/2, 0)   // IC 5L, pin 6
650 	DISCRETE_COUNTER(NODE_41, 1, 0, NODE_40, 0, 31, 1, 0, DISC_CLK_ON_F_EDGE)   // IC 5L & 5F
651 	DISCRETE_TRANSFORM2(NODE_42, NODE_41, 4, "01&")         // IC 5L, pin 9
652 	DISCRETE_TRANSFORM2(NODE_43, NODE_41, 16, "01&!")       // IC 5F, pin 8
653 	DISCRETE_ONESHOT(NODE_44, NODE_43, 1, 0.0015, DISC_ONESHOT_REDGE | DISC_ONESHOT_NORETRIG | DISC_OUT_ACTIVE_HIGH)
654 
655 	DISCRETE_LOGIC_OR(NODE_45, NODE_42, POLARIS_SX3_EN)
656 	DISCRETE_LOGIC_DFLIPFLOP(NODE_46, 1, 1, NODE_40, NODE_45)
657 
658 	DISCRETE_OP_AMP_VCO1(NODE_47, 1, POLARIS_NOISE_LO_FILT, &polaris_sonar_vco_info)
659 	DISCRETE_OP_AMP_TRIG_VCA(POLARIS_SONARSND, NODE_45, NODE_46, 0, NODE_47, 0, &polaris_sonar_tvca_info)
660 
661 /******************************************************************************
662  *
663  * Noise sources
664  *
665  * The frequencies for the noise sources were Measured by Guru.
666  *
667  * The output of the shift register is buffered by an op-amp which limits
668  * the output to 0V and (12V - OP_AMP_NORTON_VBE)
669  *
670  ******************************************************************************/
671 	DISCRETE_LFSR_NOISE(POLARIS_NOISE_LO, 1, 1, 800.8, (12.0 - OP_AMP_NORTON_VBE), NODE_44, (12.0 - OP_AMP_NORTON_VBE)/2, &polaris_lfsr)  // Unfiltered Lo noise. 7K pin 4.
672 	// Filtered Lo noise.  7K pin 5.
673 	DISCRETE_OP_AMP_FILTER(POLARIS_NOISE_LO_FILT, 1, POLARIS_NOISE_LO, 0, DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON, &polaris_nol_op_amp_filt_info)
674 
675 	DISCRETE_LFSR_NOISE(NODE_50, 1, 1, 23396, (12.0 - OP_AMP_NORTON_VBE), NODE_44, (12.0 - OP_AMP_NORTON_VBE)/2, &polaris_lfsr) // 7K pin 10
676 	// Filtered Hi noise.  6B pin 10. - This does not really do much.  Sample rates of 98k+ are needed for this high of filtering.
677 	DISCRETE_OP_AMP_FILTER(POLARIS_NOISE_HI_FILT, 1, NODE_50, 0, DISC_OP_AMP_FILTER_IS_BAND_PASS_0 | DISC_OP_AMP_IS_NORTON, &polaris_noh_op_amp_filt_info)
678 
679 /******************************************************************************
680  *
681  * Shot - SX0 (When player shoots)
682  *
683  * When Enabled it makes a low frequency RC filtered noise.  As soon as it
684  * disables, it switches to a high frequency RC filtered noise with the volume
685  * decaying based on the RC values of 680k and 1uF.
686  *
687  ******************************************************************************/
688 	DISCRETE_OP_AMP_TRIG_VCA(POLARIS_SHOTSND, POLARIS_SX0_EN, 0, 0, POLARIS_NOISE_HI_FILT, POLARIS_NOISE_LO_FILT, &polaris_shot_tvca_info)
689 
690 /******************************************************************************
691  *
692  * Ship Hit - SX1 (When sub is hit)
693  *
694  * When Enabled it makes a low frequency RC filtered noise.  As soon as it
695  * disables, it's  volume starts decaying based on the RC values of 680k and
696  * 1uF.  Also as it decays, a decaying high frequency RC filtered noise is
697  * mixed in.
698  *
699  ******************************************************************************/
700 	DISCRETE_OP_AMP_TRIG_VCA(POLARIS_SHIP_HITSND, POLARIS_SX1_EN, 0, 0, POLARIS_NOISE_HI_FILT, POLARIS_NOISE_LO_FILT, &polaris_shiphit_tvca_info)
701 
702 /******************************************************************************
703  *
704  * Ship - SX2 (When boat moves across screen)
705  *
706  * This uses a 5.75Hz |\|\ sawtooth to modulate the frequency of a
707  * voltage controlled triangle wave oscillator. *
708  *
709  ******************************************************************************/
710 	DISCRETE_OP_AMP_OSCILLATOR(NODE_60, 1, &polaris_boat_mod_info)
711 	DISCRETE_OP_AMP_VCO1(POLARIS_SHIPSND, POLARIS_SX2_EN, NODE_60, &polaris_boat_vco_info)
712 
713 /******************************************************************************
714  *
715  * Explosion - SX3 (When player, boat or boss plane is hit)
716  *
717  * When Enabled it makes a low frequency noise.  As soon as it disables, it's
718  * volume starts decaying based on the RC values of 680k and 0.33uF.  The
719  * final output is RC filtered.
720  *
721  * Note that when this is triggered, the sonar sound clock is disabled.
722  *
723  ******************************************************************************/
724 	DISCRETE_OP_AMP_TRIG_VCA(NODE_70, POLARIS_SX3_EN, 0, 0, POLARIS_NOISE_LO, 0, &polaris_exp_tvca_info)
725 
726 	DISCRETE_RCFILTER(NODE_71, NODE_70, 560.0, CAP_U(.22))
727 	DISCRETE_RCFILTER(POLARIS_EXPLOSIONSND, NODE_71, RES_K(6.8), CAP_U(.22))
728 
729 /******************************************************************************
730  *
731  * Plane Down - SX6
732  * Plane Up   - SX7
733  *
734  * The oscillator is enabled when SX7 goes high. When SX6 is enabled the
735  * frequency lowers.  When SX6 is disabled the frequency ramps back up.
736  * Also some NOISE_HI_FILT is mixed in so the frequency varies some.
737  *
738  ******************************************************************************/
739 	DISCRETE_INTEGRATE(NODE_80, POLARIS_SX6_EN, POLARIS_SX7_EN, &polaris_plane_integrate_info)
740 	DISCRETE_OP_AMP_VCO2(POLARIS_PLANESND, POLARIS_SX7_EN, NODE_80, POLARIS_NOISE_HI_FILT, &polaris_plane_vco_info)
741 
742 /******************************************************************************
743  *
744  * HIT - SX9 & SX10
745  *
746  * Following the schematic, 3 different sounds are produced.
747  * SX10  SX9  Effect
748  *  0     0   no sound
749  *  0     1   NOISE_HI_FILT while enabled
750  *  1     0   NOISE_LO_FILT while enabled (When a regular plane is hit)
751  *  1     1   NOISE_HI_FILT & NOISE_LO_FILT decaying immediately @ 680k, 0.22uF
752  *
753  ******************************************************************************/
754 	DISCRETE_OP_AMP_TRIG_VCA(POLARIS_HITSND, POLARIS_SX10_EN, POLARIS_SX9_EN, 0, POLARIS_NOISE_LO_FILT, POLARIS_NOISE_HI_FILT, &polaris_hit_tvca_info)
755 
756 /******************************************************************************
757  *
758  * Final Mixing and Output
759  *
760  ******************************************************************************/
761 	DISCRETE_MIXER4(NODE_90, 1, POLARIS_SHOTSND, POLARIS_SONARSND, POLARIS_HITSND, POLARIS_PLANESND, &polaris_mixer_vr1_desc)
762 	DISCRETE_MULTIPLY(NODE_91, NODE_90, POLARIS_ADJ_VR1)
763 	DISCRETE_MIXER2(NODE_92, 1, POLARIS_SHIPSND, POLARIS_SHIP_HITSND, &polaris_mixer_vr2_desc)
764 	DISCRETE_MULTIPLY(NODE_93, NODE_92, POLARIS_ADJ_VR2)
765 	DISCRETE_MIXER4(NODE_94, POLARIS_SX5_EN, NODE_91, POLARIS_EXPLOSIONSND, NODE_93, POLARIS_MUSIC, &polaris_mixer_vr4_desc)
766 
767 	DISCRETE_OUTPUT(NODE_94, 1)
768 
769 DISCRETE_SOUND_END
770 
771 void _8080bw_state::polaris_sh_port_1_w(uint8_t data)
772 {
773 	m_discrete->write(POLARIS_MUSIC_DATA, data);
774 }
775 
polaris_sh_port_2_w(uint8_t data)776 void _8080bw_state::polaris_sh_port_2_w(uint8_t data)
777 {
778 	/* 0x01 - SX0 - Shot */
779 	m_discrete->write(POLARIS_SX0_EN, data & 0x01);
780 
781 	/* 0x02 - SX1 - Ship Hit (Sub) */
782 	m_discrete->write(POLARIS_SX1_EN, data & 0x02);
783 
784 	/* 0x04 - SX2 - Ship */
785 	m_discrete->write(POLARIS_SX2_EN, data & 0x04);
786 
787 	/* 0x08 - SX3 - Explosion */
788 	m_discrete->write(POLARIS_SX3_EN, data & 0x08);
789 
790 	/* 0x10 - SX4 */
791 
792 	/* 0x20 - SX5 - Sound Enable */
793 	m_discrete->write(POLARIS_SX5_EN, data & 0x20);
794 }
795 
polaris_sh_port_3_w(uint8_t data)796 void _8080bw_state::polaris_sh_port_3_w(uint8_t data)
797 {
798 	machine().bookkeeping().coin_lockout_global_w(data & 0x04);  /* SX8 */
799 
800 	m_flip_screen = BIT(data, 5) & BIT(ioport("IN2")->read(), 2); /* SX11 */
801 
802 	/* 0x01 - SX6 - Plane Down */
803 	m_discrete->write(POLARIS_SX6_EN, data & 0x01);
804 
805 	/* 0x02 - SX7 - Plane Up */
806 	m_discrete->write(POLARIS_SX7_EN, data & 0x02);
807 
808 	/* 0x08 - SX9 - Hit */
809 	m_discrete->write(POLARIS_SX9_EN, data & 0x08);
810 
811 	/* 0x10 - SX10 - Hit */
812 	m_discrete->write(POLARIS_SX10_EN, data & 0x10);
813 }
814 
815 
816 
817 /*******************************************************/
818 /*                                                     */
819 /* Taito "Space Chaser"                                */
820 /*                                                     */
821 /* The SN76477 still needs to be routed to the         */
822 /* discrete system for filtering.                      */
823 /*******************************************************/
824 
825 /*
826  *  The dot sound is a square wave clocked by either the
827  *  the 8V or 4V signals
828  *
829  *  The frequencies are (for the 8V signal):
830  *
831  *  19.968 MHz crystal / 2 (Qa of 74160 #10) -> 9.984MHz
832  *                     / 2 (7474 #14) -> 4.992MHz
833  *                     / 256+16 (74161 #5 and #8) -> 18352.94Hz
834  *                     / 8 (8V) -> 2294.12 Hz
835  *                     / 2 the final freq. is 2 toggles -> 1147.06Hz
836  *
837  *  for 4V, it's double at 2294.12Hz
838  */
839 #define SCHASER_HSYNC   18352.94
840 #define SCHASER_4V      SCHASER_HSYNC /2 /4
841 #define SCHASER_8V      SCHASER_HSYNC /2 /8
842 
843 
844 /* Nodes - Inputs */
845 #define SCHASER_DOT_EN      NODE_01
846 #define SCHASER_DOT_SEL     NODE_02
847 #define SCHASER_EXP_STREAM  NODE_03
848 #define SCHASER_MUSIC_BIT   NODE_04
849 #define SCHASER_SND_EN      NODE_05
850 /* Nodes - Adjusters */
851 #define SCHASER_VR1         NODE_07
852 #define SCHASER_VR2         NODE_08
853 #define SCHASER_VR3         NODE_09
854 /* Nodes - Sounds */
855 #define SCHASER_DOT_SND     NODE_10
856 #define SCHASER_EXP_SND     NODE_11
857 #define SCHASER_MUSIC_SND   NODE_12
858 
859 DISCRETE_SOUND_START(schaser_discrete)
860 	/************************************************/
861 	/* Input register mapping for schaser           */
862 	/************************************************/
863 	DISCRETE_INPUT_LOGIC  (SCHASER_DOT_EN)
864 	DISCRETE_INPUT_LOGIC  (SCHASER_DOT_SEL)
865 	// scale to 0-3.5V
866 	DISCRETE_INPUTX_STREAM(SCHASER_EXP_STREAM, 0, 1.0/14100,             2.323)
867 	DISCRETE_INPUTX_LOGIC (SCHASER_MUSIC_BIT,    DEFAULT_TTL_V_LOGIC_1,  0,      0.0)
868 	DISCRETE_INPUT_LOGIC  (SCHASER_SND_EN)
869 
870 	/************************************************/
871 	/* Volume adjusters.                            */
872 	/* We will set them to adjust the realitive     */
873 	/* gains.                                       */
874 	/************************************************/
875 	DISCRETE_ADJUSTMENT(SCHASER_VR1, 0, RES_K(50)/(RES_K(50) + RES_K(470)), DISC_LINADJ, "VR1")
876 	DISCRETE_ADJUSTMENT(SCHASER_VR2, 0, RES_K(50)/(RES_K(50) + 560 + RES_K(6.8) + RES_K(2)), DISC_LINADJ, "VR2")
877 	DISCRETE_ADJUSTMENT(SCHASER_VR3, 0, RES_K(50)/(RES_K(50) + 560 + RES_K(6.8) + RES_K(10)), DISC_LINADJ, "VR3")
878 
879 	/************************************************/
880 	/* Dot selection just selects between 4V and 8V */
881 	/************************************************/
882 	DISCRETE_SQUAREWFIX(NODE_20, 1, SCHASER_4V, DEFAULT_TTL_V_LOGIC_1, 50, 0, 0)
883 	DISCRETE_SQUAREWFIX(NODE_21, 1, SCHASER_8V, DEFAULT_TTL_V_LOGIC_1, 50, 0, 0)
884 	DISCRETE_SWITCH(NODE_22, SCHASER_DOT_EN, SCHASER_DOT_SEL, NODE_20, NODE_21)
885 	DISCRETE_RCFILTER(NODE_23, NODE_22, 560, CAP_U(.1))
886 	DISCRETE_RCFILTER(NODE_24, NODE_23, RES_K(6.8) + 560, CAP_U(.1))
887 	DISCRETE_MULTIPLY(SCHASER_DOT_SND, NODE_24, SCHASER_VR3)
888 
889 	/************************************************/
890 	/* Explosion/Effect filtering                   */
891 	/************************************************/
892 	DISCRETE_RCFILTER(NODE_30, SCHASER_EXP_STREAM, 560, CAP_U(.1))
893 	DISCRETE_RCFILTER(NODE_31, NODE_30, RES_K(6.8) + 560, CAP_U(.1))
894 	DISCRETE_CRFILTER(NODE_32, NODE_31, RES_K(6.8) + 560 + RES_K(2) + RES_K(50), CAP_U(1))
895 	DISCRETE_MULTIPLY(SCHASER_EXP_SND, NODE_32, SCHASER_VR2)
896 
897 	/************************************************/
898 	/* Music is just a 1 bit DAC                    */
899 	/************************************************/
900 	DISCRETE_CRFILTER(NODE_40, SCHASER_MUSIC_BIT, RES_K(470) + RES_K(50), CAP_U(.01))
901 	DISCRETE_MULTIPLY(SCHASER_MUSIC_SND, NODE_40, SCHASER_VR1)
902 
903 	/************************************************/
904 	/* Final mix with gain                          */
905 	/************************************************/
906 	DISCRETE_ADDER3(NODE_90, SCHASER_SND_EN, SCHASER_DOT_SND, SCHASER_EXP_SND, SCHASER_MUSIC_SND)
907 
908 	DISCRETE_OUTPUT(NODE_90, 33080)
909 DISCRETE_SOUND_END
910 
911 static const double schaser_effect_rc[8] =
912 {
913 	0,
914 	(RES_K(15) + RES_K(20)) * CAP_U(1),
915 	(RES_K(39) + RES_K(20)) * CAP_U(1),
916 	(1.0/ (1.0/RES_K(15) + 1.0/RES_K(39)) + RES_K(20)) * CAP_U(1),
917 	(RES_K(82) + RES_K(20)) * CAP_U(1),
918 	(1.0/ (1.0/RES_K(15) + 1.0/RES_K(82)) + RES_K(20)) * CAP_U(1),
919 	(1.0/ (1.0/RES_K(15) + 1.0/RES_K(82)) + RES_K(20)) * CAP_U(1),
920 	(1.0/ (1.0/RES_K(15) + 1.0/RES_K(39) + 1.0/RES_K(82)) + RES_K(20)) * CAP_U(1)
921 };
922 
schaser_sh_port_1_w(uint8_t data)923 void _8080bw_state::schaser_sh_port_1_w(uint8_t data)
924 {
925 	int effect;
926 
927 	/* bit 0 - Dot Sound Enable (SX0)
928 	   bit 1 - Dot Sound Pitch (SX1)
929 	   bit 2 - Effect Sound A (SX2)
930 	   bit 3 - Effect Sound B (SX3)
931 	   bit 4 - Effect Sound C (SX4)
932 	   bit 5 - Explosion (SX5)
933 
934 	    Note that the schematic has SX2 and SX4 the wrong way around.
935 	    See MT 2662 for video proof. */
936 
937 	m_discrete->write(SCHASER_DOT_EN, data & 0x01);
938 	m_discrete->write(SCHASER_DOT_SEL, data & 0x02);
939 
940 	/* The effect is a variable rate 555 timer.  A diode/resistor array is used to
941 	 * select the frequency.  Because of the diode voltage drop, we can not use the
942 	 * standard 555 time formulas.  Also, when effect=0, the charge resistor
943 	 * is disconnected.  This causes the charge on the cap to slowly bleed off, but
944 	 * but the bleed time is so long, that we can just cheat and put the time on hold
945 	 * when effect = 0. */
946 	effect = (data >> 2) & 0x07;
947 	if (m_schaser_last_effect != effect)
948 	{
949 		if (effect)
950 		{
951 			if (m_schaser_effect_555_time_remain != attotime::zero)
952 			{
953 				/* timer re-enabled, use up remaining 555 high time */
954 				m_schaser_effect_555_timer->adjust(m_schaser_effect_555_time_remain, effect);
955 			}
956 			else if (!m_schaser_effect_555_is_low)
957 			{
958 				/* set 555 high time */
959 				attotime new_time = attotime(0, ATTOSECONDS_PER_SECOND * .8873 * schaser_effect_rc[effect]);
960 				m_schaser_effect_555_timer->adjust(new_time, effect);
961 			}
962 		}
963 		else
964 		{
965 			/* disable effect - stops at end of low cycle */
966 			if (!m_schaser_effect_555_is_low)
967 			{
968 				m_schaser_effect_555_time_remain = m_schaser_effect_555_timer->time_left();
969 				m_schaser_effect_555_time_remain_savable = m_schaser_effect_555_time_remain.as_double();
970 				m_schaser_effect_555_timer->adjust(attotime::never);
971 			}
972 		}
973 		m_schaser_last_effect = effect;
974 	}
975 
976 	m_schaser_explosion = BIT(data, 5);
977 	if (m_schaser_explosion)
978 	{
979 		m_sn->amplitude_res_w(1.0 / (1.0/RES_K(200) + 1.0/RES_K(68)));
980 	}
981 	else
982 	{
983 		m_sn->amplitude_res_w(RES_K(200));
984 	}
985 	m_sn->enable_w(!(m_schaser_effect_555_is_low || m_schaser_explosion));
986 	m_sn->one_shot_cap_voltage_w(!(m_schaser_effect_555_is_low || m_schaser_explosion) ? 0 : sn76477_device::EXTERNAL_VOLTAGE_DISCONNECT);
987 	m_sn->mixer_b_w(m_schaser_explosion);
988 }
989 
schaser_sh_port_2_w(uint8_t data)990 void _8080bw_state::schaser_sh_port_2_w(uint8_t data)
991 {
992 	/* bit 0 - Music (DAC) (SX6)
993 	   bit 1 - Sound Enable (SX7)
994 	   bit 2 - Coin Lockout (SX8)
995 	   bit 3 - Field Control A (SX9)
996 	   bit 4 - Field Control B (SX10)
997 	   bit 5 - Flip Screen */
998 
999 	m_discrete->write(SCHASER_MUSIC_BIT, BIT(data, 0));
1000 
1001 	m_discrete->write(SCHASER_SND_EN, BIT(data, 1));
1002 	machine().sound().system_enable(BIT(data, 1));
1003 
1004 	machine().bookkeeping().coin_lockout_global_w(BIT(data, 2));
1005 
1006 	m_schaser_background_disable = BIT(data, 3);
1007 	m_schaser_background_select = BIT(data, 4);
1008 
1009 	m_flip_screen = BIT(data, 5) & BIT(ioport("IN2")->read(), 6);
1010 
1011 	m_port_2_last_extra = data;
1012 }
1013 
1014 
TIMER_DEVICE_CALLBACK_MEMBER(_8080bw_state::schaser_effect_555_cb)1015 TIMER_DEVICE_CALLBACK_MEMBER(_8080bw_state::schaser_effect_555_cb)
1016 {
1017 	int effect = param;
1018 	attotime new_time;
1019 
1020 	/* Toggle 555 output */
1021 	m_schaser_effect_555_is_low = !m_schaser_effect_555_is_low;
1022 	m_schaser_effect_555_time_remain = attotime::zero;
1023 	m_schaser_effect_555_time_remain_savable = m_schaser_effect_555_time_remain.as_double();
1024 
1025 	if (m_schaser_effect_555_is_low)
1026 		new_time = PERIOD_OF_555_ASTABLE(0, RES_K(20), CAP_U(1)) / 2;
1027 	else
1028 	{
1029 		if (effect)
1030 			new_time = attotime(0, ATTOSECONDS_PER_SECOND * .8873 * schaser_effect_rc[effect]);
1031 		else
1032 			new_time = attotime::never;
1033 	}
1034 	m_schaser_effect_555_timer->adjust(new_time, effect);
1035 	m_sn->enable_w(!(m_schaser_effect_555_is_low || m_schaser_explosion));
1036 	m_sn->one_shot_cap_voltage_w(!(m_schaser_effect_555_is_low || m_schaser_explosion) ? 0 : sn76477_device::EXTERNAL_VOLTAGE_DISCONNECT);
1037 }
1038 
1039 
schaser_reinit_555_time_remain()1040 void _8080bw_state::schaser_reinit_555_time_remain()
1041 {
1042 	m_schaser_effect_555_time_remain = attotime::from_double(m_schaser_effect_555_time_remain_savable);
1043 	schaser_sh_port_2_w(m_port_2_last_extra);
1044 }
1045 
1046 
MACHINE_START_MEMBER(_8080bw_state,schaser_sh)1047 MACHINE_START_MEMBER(_8080bw_state,schaser_sh)
1048 {
1049 	save_item(NAME(m_schaser_explosion));
1050 	save_item(NAME(m_schaser_effect_555_is_low));
1051 	save_item(NAME(m_schaser_effect_555_time_remain_savable));
1052 	save_item(NAME(m_port_2_last_extra));
1053 	machine().save().register_postload(save_prepost_delegate(FUNC(_8080bw_state::schaser_reinit_555_time_remain), this));
1054 }
1055 
1056 
MACHINE_RESET_MEMBER(_8080bw_state,schaser_sh)1057 MACHINE_RESET_MEMBER(_8080bw_state,schaser_sh)
1058 {
1059 	m_schaser_effect_555_is_low = 0;
1060 	m_schaser_effect_555_timer->adjust(attotime::never);
1061 	schaser_sh_port_1_w(0);
1062 	schaser_sh_port_2_w(0);
1063 	m_schaser_effect_555_time_remain = attotime::zero;
1064 	m_schaser_effect_555_time_remain_savable = m_schaser_effect_555_time_remain.as_double();
1065 }
1066 
1067 
1068 
1069 /*******************************************************/
1070 /*                                                     */
1071 /* Zenitone Microsec "Invaders Revenge"                */
1072 /*                                                     */
1073 /*******************************************************/
1074 
invrvnge_port03_w(uint8_t data)1075 void _8080bw_state::invrvnge_port03_w(uint8_t data)
1076 {
1077 	m_sound_data = data;
1078 }
1079 
invrvnge_port05_w(uint8_t data)1080 void _8080bw_state::invrvnge_port05_w(uint8_t data)
1081 {
1082 	/*
1083 	    00 - normal play
1084 	    0A, 0E - alternate during play/attract at about once per second (invrvngegw only) purpose unknown
1085 	    01 - briefly at boot time
1086 	    10 - different colour map (or screen red) when you die
1087 	    20 - flip screen */
1088 
1089 	m_screen_red = BIT(data, 4);
1090 	m_flip_screen = BIT(data, 5) & ioport(CABINET_PORT_TAG)->read();
1091 
1092 		// no sound-related writes?
1093 }
1094 
1095 // The timer frequency controls the speed of the sounds
TIMER_DEVICE_CALLBACK_MEMBER(_8080bw_state::nmi_timer)1096 TIMER_DEVICE_CALLBACK_MEMBER(_8080bw_state::nmi_timer)
1097 {
1098 	m_timer_state ^= 1;
1099 	m_audiocpu->set_input_line(INPUT_LINE_NMI, m_timer_state ? ASSERT_LINE : CLEAR_LINE );
1100 }
1101 
1102 
1103 /****************************************************/
1104 /* Rolling Crash / Moon Base                        */
1105 /* - Moon Base uses same ports and bits as invaders */
1106 /* - Press Left or Right to choose game to play     */
1107 /****************************************************/
1108 
rollingc_sh_port_w(uint8_t data)1109 void _8080bw_state::rollingc_sh_port_w(uint8_t data)
1110 {
1111 	uint8_t rising_bits = data & ~m_port_3_last_extra;
1112 
1113 	if (rising_bits & 0x02) m_samples->start(4, 0); /* Steering */
1114 	if (rising_bits & 0x04) m_samples->start(0, 1); /* Collision */
1115 	if (rising_bits & 0x10) m_samples->start(1, 8); /* Computer car is starting to move */
1116 
1117 	m_port_3_last_extra = data;
1118 }
1119 
1120 
1121 
1122 /*****************************************/
1123 /* Lupin III preliminary sound           */
1124 /* Correct samples not available         */
1125 /*****************************************/
1126 
1127 const char *const lupin3_sample_names[] =
1128 {
1129 	"*lupin3",
1130 	"cap",      /* go to jail */
1131 	"bark",     /* dog barking */
1132 	"walk1",        /* walk, get money */
1133 	"walk2",        /* walk, get money */
1134 	"warp",     /* translocate, deposit money */
1135 	"extend",       /* bonus man */
1136 	"kick",     /* lands on top of building, wife kicks man */
1137 	nullptr
1138 };
1139 
lupin3_00_w(uint8_t data)1140 void  _8080bw_state::lupin3_00_w (uint8_t data)
1141 {
1142 	m_discrete->write(INDIANBT_MUSIC_DATA, data);
1143 }
1144 
lupin3_sh_port_1_w(uint8_t data)1145 void _8080bw_state::lupin3_sh_port_1_w(uint8_t data)
1146 {
1147 	uint8_t rising_bits = data & ~m_port_1_last_extra;
1148 	static uint8_t lupin3_step = 2;
1149 
1150 	if (rising_bits & 0x01)
1151 	{
1152 		m_samples->start(0, lupin3_step);           /* Walking, steal money */
1153 		lupin3_step ^= 1;
1154 	}
1155 
1156 	m_sn->enable_w(data & 0x02 ? 0:1);          /* Helicopter */
1157 
1158 	if (rising_bits & 0x04) m_samples->start(1, 4);     /* Translocate */
1159 	if (rising_bits & 0x08) m_samples->start(0, 0);     /* Jail */
1160 	if (rising_bits & 0x10) m_samples->start(2, 5);     /* Bonus Man */
1161 
1162 	//machine().sound().system_enable(data & 0x20);
1163 
1164 	//machine().bookkeeping().coin_lockout_global_w(data & 0x80);
1165 
1166 	m_port_1_last_extra = data;
1167 }
1168 
lupin3_sh_port_2_w(uint8_t data)1169 void _8080bw_state::lupin3_sh_port_2_w(uint8_t data)
1170 {
1171 	uint8_t rising_bits = data & ~m_port_2_last_extra;
1172 
1173 	if (rising_bits & 0x01) m_samples->start(0, 6);     /* Lands on top of building, wife kicks man */
1174 	//if (rising_bits & 0x02) m_samples->start(3, 7);       /* deposit money, start intermission, end game */
1175 	//if (rising_bits & 0x04) m_samples->start(4, 7);       /* deposit money, start intermission, Slides down rope */
1176 	//if (rising_bits & 0x08) m_samples->start(5, 7);       /* start intermission, end game */
1177 	if (rising_bits & 0x10) m_samples->start(3, 1);        /* Dog barking */
1178 
1179 	m_color_map = data & 0x40;
1180 
1181 	m_flip_screen = BIT(data, 5) & BIT(ioport("IN2")->read(), 2);
1182 
1183 	m_port_2_last_extra = data;
1184 }
1185 
1186 
1187 
1188 /*****************************************/
1189 /* Space Chaser (CV) preliminary sound   */
1190 /* Much more work needs to be done       */
1191 /*****************************************/
1192 
schasercv_sh_port_1_w(uint8_t data)1193 void _8080bw_state::schasercv_sh_port_1_w(uint8_t data)
1194 {
1195 	/* bit 2 = 2nd speedup
1196 	   bit 3 = 1st speedup
1197 	   Death is a stream of ff's with some fe's thrown in */
1198 
1199 	uint8_t rising_bits = data & ~m_port_1_last_extra;
1200 
1201 	if (rising_bits & 0x02) m_samples->start(1, 6);     /* Ran over a dot */
1202 	if (rising_bits & 0x10) m_samples->start(0, 1);     /* Death */
1203 
1204 	m_port_1_last_extra = data;
1205 }
1206 
schasercv_sh_port_2_w(uint8_t data)1207 void _8080bw_state::schasercv_sh_port_2_w(uint8_t data)
1208 {
1209 	m_speaker->level_w(BIT(data, 0));      /* End-of-Level */
1210 
1211 	machine().sound().system_enable(data & 0x10);
1212 
1213 	m_flip_screen = BIT(data, 5) & ioport(CABINET_PORT_TAG)->read();
1214 }
1215 
1216 
1217 
1218 /*****************************************/
1219 /* Crash Road preliminary sound          */
1220 /* Much more work needs to be done       */
1221 /*****************************************/
1222 
crashrd_port03_w(uint8_t data)1223 void _8080bw_state::crashrd_port03_w(uint8_t data)
1224 {
1225 	int effect;
1226 
1227 	/* bit 0 - Dot Sound Pitch (SX1)
1228 	   bit 2 - Explosion (SX5)
1229 	   bit 4 - Dot Sound Enable (SX0)
1230 	   bit 5 - Effect Sound C (SX4) */
1231 
1232 	m_discrete->write(SCHASER_SND_EN, BIT(data,5));
1233 	machine().sound().system_enable(BIT(data,5));
1234 	m_discrete->write(SCHASER_DOT_EN, BIT(data, 4));
1235 	m_discrete->write(SCHASER_DOT_SEL, BIT(data, 0));
1236 
1237 	/* The effect is a variable rate 555 timer.  A diode/resistor array is used to
1238 	 * select the frequency.  Because of the diode voltage drop, we can not use the
1239 	 * standard 555 time formulas.  Also, when effect=0, the charge resistor
1240 	 * is disconnected.  This causes the charge on the cap to slowly bleed off, but
1241 	 * but the bleed time is so long, that we can just cheat and put the time on hold
1242 	 * when effect = 0. */
1243 	effect = 0; //(data >> 2) & 0x07;
1244 	if (m_schaser_last_effect != effect)
1245 	{
1246 		if (effect)
1247 		{
1248 			if (m_schaser_effect_555_time_remain != attotime::zero)
1249 			{
1250 				/* timer re-enabled, use up remaining 555 high time */
1251 				m_schaser_effect_555_timer->adjust(m_schaser_effect_555_time_remain, effect);
1252 			}
1253 			else if (!m_schaser_effect_555_is_low)
1254 			{
1255 				/* set 555 high time */
1256 				attotime new_time = attotime(0, ATTOSECONDS_PER_SECOND * .8873 * schaser_effect_rc[effect]);
1257 				m_schaser_effect_555_timer->adjust(new_time, effect);
1258 			}
1259 		}
1260 		else
1261 		{
1262 			/* disable effect - stops at end of low cycle */
1263 			if (!m_schaser_effect_555_is_low)
1264 			{
1265 				m_schaser_effect_555_time_remain = m_schaser_effect_555_timer->time_left();
1266 				m_schaser_effect_555_time_remain_savable = m_schaser_effect_555_time_remain.as_double();
1267 				m_schaser_effect_555_timer->adjust(attotime::never);
1268 			}
1269 		}
1270 		m_schaser_last_effect = effect;
1271 	}
1272 
1273 	m_schaser_explosion = BIT(data, 2);
1274 	if (m_schaser_explosion)
1275 	{
1276 		m_sn->amplitude_res_w(1.0 / (1.0/RES_K(200) + 1.0/RES_K(68)));
1277 	}
1278 	else
1279 	{
1280 		m_sn->amplitude_res_w(RES_K(200));
1281 	}
1282 	m_sn->enable_w(!(m_schaser_effect_555_is_low || m_schaser_explosion));
1283 	m_sn->one_shot_cap_voltage_w(!(m_schaser_effect_555_is_low || m_schaser_explosion) ? 0 : sn76477_device::EXTERNAL_VOLTAGE_DISCONNECT);
1284 	m_sn->mixer_b_w(m_schaser_explosion);
1285 }
1286 
crashrd_port05_w(uint8_t data)1287 void _8080bw_state::crashrd_port05_w(uint8_t data)
1288 {
1289 	// bit 0 = bitstream audio
1290 	// bit 4 = not sure
1291 	m_discrete->write(SCHASER_MUSIC_BIT, BIT(data, 0));
1292 }
1293 
1294 
1295 
1296 /*******************************************************************/
1297 /* Yosakdon preliminary sound                                      */
1298 /* No information available as what the correct sounds are         */
1299 /*******************************************************************/
1300 
yosakdon_sh_port_1_w(uint8_t data)1301 void _8080bw_state::yosakdon_sh_port_1_w(uint8_t data)
1302 {
1303 	uint8_t rising_bits = data & ~m_port_1_last_extra;
1304 
1305 	if (rising_bits & 0x01) m_samples->start(0, 3);         /* Game Over */
1306 	if (rising_bits & 0x02) m_samples->start(2, 0);         /* Bird dead */
1307 	if (rising_bits & 0x04) m_samples->start(0, 1);         /* Rifle being fired */
1308 	if (rising_bits & 0x08) m_samples->start(1, 2);         /* Man dead */
1309 	if (rising_bits & 0x10) m_samples->start(5, 8);         /* Bonus Man? */
1310 
1311 	machine().sound().system_enable(data & 0x20);
1312 
1313 	m_port_1_last_extra = data;
1314 }
1315 
yosakdon_sh_port_2_w(uint8_t data)1316 void _8080bw_state::yosakdon_sh_port_2_w(uint8_t data)
1317 {
1318 	uint8_t rising_bits = data & ~m_port_2_last_extra;
1319 
1320 	if (rising_bits & 0x01) m_samples->start(1, 6);         /* Ready? , Game Over */
1321 	if (rising_bits & 0x04) m_samples->start(3, 7);         /* Big bird dead */
1322 
1323 	m_sn->enable_w(data & 0x08 ? 0:1);              /* Big bird */
1324 
1325 	if (rising_bits & 0x10) m_samples->start(2, 7);         /* Game Over */
1326 
1327 	m_flip_screen = BIT(data, 5) & ioport(CABINET_PORT_TAG)->read();
1328 
1329 	m_port_2_last_extra = data;
1330 }
1331 
1332 
1333 
1334 /*****************************************/
1335 /* shuttlei preliminary sound            */
1336 /* Proper samples are unavailable        */
1337 /*****************************************/
1338 
shuttlei_sh_port_1_w(uint8_t data)1339 void _8080bw_state::shuttlei_sh_port_1_w(uint8_t data)
1340 {
1341 	/* bit 3 is high while you are alive and playing */
1342 	uint8_t rising_bits = data & ~m_port_1_last_extra;
1343 
1344 	if (rising_bits & 0x01) m_samples->start(4, 4);         /* Fleet move */
1345 	if (rising_bits & 0x02) m_samples->start(5, 8);         /* Extra Tank */
1346 
1347 	m_sn->enable_w(data & 0x04 ? 0:1);              /* UFO */
1348 
1349 	m_port_1_last_extra = data;
1350 }
1351 
shuttlei_sh_port_2_w(uint8_t data)1352 void _8080bw_state::shuttlei_sh_port_2_w(uint8_t data)
1353 {
1354 	switch (data)
1355 	{
1356 		case 0x23:
1357 			m_samples->start(2, 2);             /* Hit */
1358 			break;
1359 
1360 		case 0x2b:
1361 			m_samples->start(0, 0);             /* Shoot */
1362 			break;
1363 
1364 		case 0xa3:
1365 			m_samples->start(3, 7);             /* Hit UFO */
1366 			break;
1367 
1368 		case 0xab:
1369 			m_samples->start(1, 1);             /* Death */
1370 			break;
1371 	}
1372 }
1373 
1374 
1375 /*****************************************/
1376 /* "Darth Vader" preliminary sound       */
1377 /* Proper samples are unavailable        */
1378 /*****************************************/
1379 
darthvdr_00_w(uint8_t data)1380 void _8080bw_state::darthvdr_00_w(uint8_t data)
1381 {
1382 	m_flip_screen = BIT(data, 0) & ioport(CABINET_PORT_TAG)->read();
1383 }
1384 
darthvdr_08_w(uint8_t data)1385 void _8080bw_state::darthvdr_08_w(uint8_t data)
1386 {
1387 	uint8_t rising_bits = data & ~m_port_1_last_extra;
1388 
1389 	machine().sound().system_enable(data & 0x01);
1390 
1391 	if (rising_bits & 0x02) m_samples->start(0, 0);     /* Shoot */
1392 	if (rising_bits & 0x04) m_samples->start(3, 7);     /* Hit UFO */
1393 	if (rising_bits & 0x10) m_samples->start(5, 8);     /* Bonus */
1394 
1395 	m_sn->enable_w(data & 0x20 ? 0:1);          /* UFO */
1396 
1397 	if (rising_bits & 0x40) m_samples->start(1, 1);     /* Death */
1398 	if (rising_bits & 0x80) m_samples->start(2, 2);     /* Hit */
1399 
1400 	if (rising_bits & 0x08)
1401 	{
1402 		m_samples->start(4, m_fleet_step);          /* Fleet move in 4 steps */
1403 		m_fleet_step++;
1404 		if (m_fleet_step > 6) m_fleet_step = 3;
1405 	}
1406 
1407 	m_port_1_last_extra = data;
1408 }
1409 
1410 
1411 /*********************************************************/
1412 /*                                                       */
1413 /* Model Racing "Cane" (Slightly based on Claybuster hw) */
1414 /*                                                       */
1415 /*********************************************************/
1416 #define CANE_CLOCK   (19968000.0)
1417 #define CANE_H64     CANE_CLOCK /2 /2 /4
1418 
1419 /* Nodes - Sound enable */
1420 #define CANE_SND_EN        NODE_05
1421 
1422 /* Nodes - Adjusters */
1423 #define CANE_VR1           NODE_07  // Gain for 76477
1424 #define CANE_VR2           NODE_08  // VR attached to the output of the TOS
1425 #define CANE_VR3           NODE_09  // VR for SFX generated by the 555
1426 
1427 /* Nodes - sn76477 Sounds */
1428 #define CANE_EXP_STREAM    NODE_03
1429 #define CANE_EXP_SND       NODE_11
1430 
1431 /* Nodes - BGM */
1432 #define CANE_MUSIC_DATA    NODE_06
1433 #define CANE_MUSIC_NOTE    NODE_40
1434 #define CANE_MUSIC_NOTE_PF NODE_01
1435 #define CANE_MUSIC_SND     NODE_12
1436 
1437 /* Nodes - 555 sfx */
1438 #define CANE_76477_PIN6    NODE_13
1439 #define CANE_555_CLAMPED   NODE_14
1440 #define CANE_555_ONESHOT   NODE_15
1441 #define CANE_555_EN        NODE_16
1442 #define CANE_TMP_SND       NODE_17
1443 #define CANE_SFX_SND       NODE_18
1444 
1445 /* Node output */
1446 #define CANE_SOUND_OUT     NODE_90
1447 
1448 static INPUT_PORTS_START( cane_audio )
1449 	PORT_START("VR1")
1450 	PORT_ADJUSTER( 80, "VR1 - SFX from 76477" )
1451 
1452 	PORT_START("VR2")
1453 	PORT_ADJUSTER( 90, "VR2 - TOS music" )
1454 
1455 	PORT_START("VR3")
1456 	PORT_ADJUSTER( 70, "VR3 - Shoot SFX from 555" )
1457 INPUT_PORTS_END
1458 
cane_audio_device(machine_config const & mconfig,char const * tag,device_t * owner,u32 clock)1459 cane_audio_device::cane_audio_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
1460 	device_t(mconfig, CANE_AUDIO, tag, owner, clock),
1461 	m_vco_timer(*this, "vco_timer"),
1462 	m_sn(*this, "snsnd"),
1463 	m_discrete(*this, "discrete"),
1464 	m_vco_rc_chargetime(attotime::never)
1465 {
1466 }
1467 
device_add_mconfig(machine_config & config)1468 void cane_audio_device::device_add_mconfig(machine_config &config)
1469 {
1470 	TIMER(config, m_vco_timer).configure_generic(FUNC(cane_audio_device::vco_voltage_timer));
1471 
1472 	SPEAKER(config, "mono").front_center();
1473 
1474 	SN76477(config, m_sn);
1475 	// Amplitude res in the schematic is connected to a 470K potentiometer, so from the schematic is impossible to know the real res.
1476 	// This parameter drives the amp just before the audio output pin 13.
1477 	m_sn->set_amp_res(100+RES_K(20));
1478 	m_sn->set_noise_params(RES_K(39), RES_K(1), CAP_P(1000));
1479 	m_sn->set_decay_res(RES_M(1));
1480 	m_sn->set_attack_params(CAP_U(1.0), RES_K(47));
1481 	m_sn->set_feedback_res(RES_K(4.7));
1482 	m_sn->set_vco_params(0, CAP_P(3300), RES_K(100));
1483 	m_sn->set_pitch_voltage(5.0);
1484 	m_sn->set_slf_params(CAP_U(1.0), RES_K(33));
1485 	m_sn->set_oneshot_params(CAP_U(10), RES_K(100));
1486 	m_sn->set_vco_mode(0);
1487 	m_sn->set_mixer_params(0, 0, 0);
1488 	m_sn->set_envelope_params(1, 0);
1489 	m_sn->set_enable(0);
1490 	m_sn->add_route(0, "discrete", 1.0, 0);
1491 
1492 	DISCRETE(config, m_discrete, cane_discrete);
1493 	m_discrete->add_route(ALL_OUTPUTS, "mono", 1.0);
1494 }
1495 
device_input_ports() const1496 ioport_constructor cane_audio_device::device_input_ports() const
1497 {
1498 	return INPUT_PORTS_NAME(cane_audio);
1499 }
1500 
device_start()1501 void cane_audio_device::device_start()
1502 {
1503 	// provare a commentare
1504 	m_vco_rc_chargetime = attotime::never;
1505 
1506 	save_item(NAME(m_vco_rc_chargetime));
1507 }
1508 
sh_port_1_w(u8 data)1509 void cane_audio_device::sh_port_1_w(u8 data)
1510 {
1511 	/*
1512 	    bit 0 - SX0 - Sound enable on mixer
1513 	    bit 1 - SX1 - SN76477 - Mixer select C - pin 27
1514 	    bit 2 - SX2 - SN76477 - Mixer select A - pin 26
1515 	    bit 3 - SX3 - SN76477 - Mixer select B - pin 25
1516 	    bit 4 - SX4 - NE555 - Trigger (Step, high output level for 1.1*RC = 1.1*100K*0.47u = 51.7 ms)
1517 	*/
1518 
1519 	m_discrete->write(CANE_SND_EN, data & 0x01); // BIT(data, 0) - bit 0 - SX0 - Sound enable on mixer
1520 	m_discrete->write(CANE_555_EN, data & 0x10); // BIT(data, 4) - bit 4 - SX4 - NE555 - Trigger
1521 
1522 	// 76477 enable bit is connected to the select line of the out port 3 (inverted).
1523 	m_sn->enable_w(1);
1524 	m_sn->set_mixer_params(BIT(data, 2), BIT(data, 3), BIT(data, 1));
1525 
1526 	m_vco_timer->adjust(attotime::zero, m_vco_timer->param(), attotime::from_hz(1000));
1527 	m_vco_rc_chargetime = m_vco_timer->start_time();
1528 
1529 	// Little hack...
1530 	// To be precise I should enable the 76477 every time the CPU reads or write to a port different from port 3
1531 	// and disable it every time the CPU read/write from/to port 3.
1532 	// Actually this can not be done easily so I decided to enable it preemptively here after every port 3 access
1533 	m_sn->enable_w(0);
1534 }
1535 
music_w(u8 data)1536 void cane_audio_device::music_w(u8 data)
1537 {
1538 	m_sn->enable_w(1);
1539 	m_discrete->write(CANE_MUSIC_DATA, data);
1540 }
1541 
sn76477_en_w(u8 data)1542 void cane_audio_device::sn76477_en_w(u8 data)
1543 {
1544 	m_sn->enable_w(0);
1545 }
1546 
sn76477_dis_w(u8 data)1547 void cane_audio_device::sn76477_dis_w(u8 data)
1548 {
1549 	m_sn->enable_w(1);
1550 }
1551 
1552 /*******************************************************************************************************************************************************/
1553 /* Cane discrete implementation, slightly based on Claybuster hw.                                                                                      */
1554 /* This implementation doesn't pretend to be accurate thus trying to be at least functionally similar.                                                 */
1555 /*                                                                                                                                                     */
1556 /*                                                                       Port 1 - SX4              CANE_VR3                       Port 1 - SX0         */
1557 /*                                                                            |                        |                               |               */
1558 /*                                                                       CANE_555_EN                   |                               |               */
1559 /*                                                                            |                        |                               |               */
1560 /*                                                                  +------------------+               |                               |               */
1561 /*                                                                  | CANE_555_ONESHOT |               |                               |               */
1562 /*                                                                  +------------------+               |                               |               */
1563 /*                                                                            |                        |                               |               */
1564 /*                                                                            v                        v                               |               */
1565 /*                                    sn76477 pin 6   +------------------+  +---+  +--------------+  +---+  +--------------+           |               */
1566 /*                                     CLAMP(0, 5V) ->| CANE_555_CLAMPED |->| * |->| CANE_TMP_SND |->| * |->| CANE_SFX_SND |       CANE_SND_EN         */
1567 /*                                 (DISCRETE_NOISE)   +------------------+  +---+  +--------------+  +---+  +--------------+           |               */
1568 /*                                                                                                                       |             |               */
1569 /*                                                                                          CANE_VR1                     |             |               */
1570 /*                                                                                              |                        |             |               */
1571 /*                                                                                              v                        v             v               */
1572 /*                                                      sn76477 output   +-----------------+  +---+  +--------------+  +---+  +----------------+       */
1573 /*                                              DISCRETE_INPUTX_STREAM ->| CANE_EXP_STREAM |->| * |->| CANE_EXP_SND |->| + |->| CANE_SOUND_OUT |->OUT  */
1574 /*                                                                       +-----------------+  +---+  +--------------+  +---+  +----------------+       */
1575 /*                                                                                                                       ^                             */
1576 /*                                                                                                                       |                             */
1577 /*                   CANE_MUSIC_DATA   +--------------------+  +-----------+  +-----------------+  +---+  +----------------+                           */
1578 /* Port 5 data---DISCRETE_INPUT_DATA ->| CANE_MUSIC_NOTE_PF |->| CR_FILTER |->| CANE_MUSIC_NOTE |->| * |->| CANE_MUSIC_SND |                           */
1579 /*                     DISCRETE_NOTE   +--------------------+  +-----------+  +-----------------+  +---+  +----------------+                           */
1580 /*                                                                RES_K(10)                          ^                                                 */
1581 /*                                                               CAP_U(0.1)                          |                                                 */
1582 /*                                                                                               CANE_VR2                                              */
1583 /*                                                                                                                                                     */
1584 /*                                                                                                                                                     */
1585 /*******************************************************************************************************************************************************/
1586 DISCRETE_SOUND_START(cane_discrete)
1587 	/************************************************/
1588 	/* Input register mapping for cane           */
1589 	/************************************************/
DISCRETE_INPUT_DATA(CANE_MUSIC_DATA)1590 	DISCRETE_INPUT_DATA (CANE_MUSIC_DATA)
1591 
1592 	DISCRETE_INPUT_LOGIC  (CANE_555_EN)
1593 
1594 	// scale to 0-2.5V
1595 	DISCRETE_INPUTX_STREAM(CANE_EXP_STREAM, 0, 0.5, 0)
1596 
1597 	DISCRETE_INPUT_LOGIC  (CANE_SND_EN)
1598 
1599 	/************************************************/
1600 	/* Volume adjusters.                            */
1601 	/* We will set them to adjust the realitive     */
1602 	/* gains.                                       */
1603 	/************************************************/
1604 	DISCRETE_ADJUSTMENT(CANE_VR1, 0, 0.33*6, DISC_LINADJ, "VR1")      // Gain for 76477
1605 	DISCRETE_ADJUSTMENT(CANE_VR2, 0, 0.33*60000, DISC_LINADJ, "VR2")  // VR attached to the output of the TOS
1606 	DISCRETE_ADJUSTMENT(CANE_VR3, 0, 0.33*60000, DISC_LINADJ, "VR3")  // VR for SFX generated by the 555
1607 
1608 	/************************************************/
1609 	/* From 555                                     */
1610 	/************************************************/
1611 	/* TODO: find real noise freq and amplitude */
1612 	/* width was simulated with ltspice using Claybuster schematic as a source and it's value is about 51ms */
1613 	DISCRETE_NOISE(CANE_76477_PIN6,
1614 				1,                          /* ENAB */
1615 				1280,                       /* FREQ - Guessed */
1616 				1,                          /* AMP  */
1617 				0)                          /* BIAS - fake AC is fine*/
1618 	DISCRETE_CLAMP(CANE_555_CLAMPED,
1619 				CANE_76477_PIN6,            /* input node */
1620 				0.0,                        /* minimum */
1621 				5.0)                        /* maximum */
1622 	DISCRETE_ONESHOT(CANE_555_ONESHOT,
1623 					 CANE_555_EN,           /* trigger node */
1624 					 1,                     /* amplitude node or static value */
1625 					 0.05,                  /* width (in seconds) node or static value - 50 ms*/
1626 					 DISC_ONESHOT_FEDGE | DISC_ONESHOT_RETRIG)  /* type of oneshot static value */
1627 
1628 	DISCRETE_MULTIPLY(CANE_TMP_SND, CANE_555_CLAMPED, CANE_555_ONESHOT)
1629 	DISCRETE_MULTIPLY(CANE_SFX_SND, CANE_TMP_SND, CANE_VR3)
1630 
1631 /*****************************************************************************
1632 *
1633 * Music Generator (TOS)
1634 *
1635 * Values for this section of the sound hardware where derived from comments
1636 * in the source code and the analysis of TOS.ED sources.
1637 *
1638 * For further info look at the relevant comments reported into
1639 * drivers/8080bw.cpp
1640 *
1641 ******************************************************************************/
1642 	DISCRETE_NOTE(CANE_MUSIC_NOTE_PF, 1, CANE_H64, CANE_MUSIC_DATA, 255, 1, DISC_CLK_IS_FREQ)
1643 	DISCRETE_CRFILTER(CANE_MUSIC_NOTE, CANE_MUSIC_NOTE_PF, RES_K(10), CAP_U(0.1))  // high pass filter
1644 	DISCRETE_MULTIPLY(CANE_MUSIC_SND, CANE_MUSIC_NOTE, CANE_VR2)
1645 
1646 /******************************************************************************
1647 *
1648 * From 76477 output
1649 *
1650 ******************************************************************************/
1651 	DISCRETE_MULTIPLY(CANE_EXP_SND, CANE_EXP_STREAM, CANE_VR1)
1652 
1653 /******************************************************************************
1654 *
1655 * Final Mixing and Output
1656 *
1657 ******************************************************************************/
1658 	DISCRETE_ADDER3(CANE_SOUND_OUT, CANE_SND_EN, CANE_SFX_SND, CANE_EXP_SND, CANE_MUSIC_SND)
1659 	DISCRETE_OUTPUT(CANE_SOUND_OUT, 1)
1660 
1661 //LOG
1662 /*
1663     DISCRETE_WAVLOG1(CANE_EXP_STREAM, 1)
1664     DISCRETE_WAVLOG1(CANE_EXP_SND, 1)
1665     DISCRETE_WAVLOG1(CANE_TMP_SND, 1)
1666     DISCRETE_WAVLOG1(CANE_SFX_SND, 1)
1667     DISCRETE_WAVLOG1(CANE_MUSIC_NOTE, 1)
1668     DISCRETE_WAVLOG1(CANE_MUSIC_SND, 1)
1669     DISCRETE_WAVLOG1(CANE_SOUND_OUT, 1)
1670 */
1671 DISCRETE_SOUND_END
1672 
1673 TIMER_DEVICE_CALLBACK_MEMBER(cane_audio_device::vco_voltage_timer)
1674 {
1675 	const double delta = (m_vco_timer->fire_time() - m_vco_rc_chargetime).as_double();
1676 	const double voltage = 5 * (1 - std::exp(-delta / 47));
1677 
1678 	LOG("t = %d\n", delta);
1679 	LOG("vco_voltage = %d\n", voltage);
1680 
1681 	m_sn->vco_voltage_w(voltage);
1682 }
1683