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