diff options
Diffstat (limited to 'src/mame')
2229 files changed, 1381381 insertions, 0 deletions
diff --git a/src/mame/audio/8080bw.c b/src/mame/audio/8080bw.c new file mode 100644 index 00000000000..929fff1efc2 --- /dev/null +++ b/src/mame/audio/8080bw.c @@ -0,0 +1,1112 @@ +/* 8080bw.c ********************************* + */ +#include "driver.h" +#include "8080bw.h" +#include "mw8080bw.h" +#include "sound/samples.h" +#include "sound/sn76477.h" +#include "sound/discrete.h" +#include "sound/speaker.h" + + +static emu_timer *schaser_effect_555_timer; +static attotime schaser_effect_555_time_remain; +static int schaser_effect_555_is_low; +static int schaser_explosion; +static UINT8 port_1_last = 0; +static UINT8 port_2_last = 0; +static UINT8 port_3_last = 0; + + +/*******************************************************/ +/* */ +/* Midway "Space Invaders Part II" */ +/* */ +/*******************************************************/ + +WRITE8_HANDLER( invadpt2_sh_port_1_w ) +{ + UINT8 rising_bits = data & ~port_1_last; + + SN76477_enable_w(0, !(data & 0x01)); /* SAUCER SOUND */ + + if (rising_bits & 0x02) sample_start_n(0, 0, 0, 0); /* MISSLE SOUND */ + if (rising_bits & 0x04) sample_start_n(0, 1, 1, 0); /* EXPLOSION */ + if (rising_bits & 0x08) sample_start_n(0, 2, 2, 0); /* INVADER HIT */ + if (rising_bits & 0x10) sample_start_n(0, 5, 8, 0); /* BONUS MISSILE BASE */ + + c8080bw_screen_red_w(data & 0x04); + + sound_global_enable(data & 0x20); + + port_1_last = data; + +} + +WRITE8_HANDLER( invadpt2_sh_port_2_w ) +{ + /* FLEET (movement) + + DO = 20K + 20K + D1 = 68K + D2 = 82K + D3 = 100K */ + + UINT8 rising_bits = data & ~port_2_last; + + if (rising_bits & 0x01) sample_start_n(0, 4, 3, 0); /* FLEET */ + if (rising_bits & 0x02) sample_start_n(0, 4, 4, 0); /* FLEET */ + if (rising_bits & 0x04) sample_start_n(0, 4, 5, 0); /* FLEET */ + if (rising_bits & 0x08) sample_start_n(0, 4, 6, 0); /* FLEET */ + if (rising_bits & 0x10) sample_start_n(0, 3, 7, 0); /* SAUCER HIT */ + + c8080bw_flip_screen_w(data & 0x20); + + port_2_last = data; +} + + +/*******************************************************/ +/* */ +/* Sanritsu "Space War" */ +/* */ +/*******************************************************/ + +WRITE8_HANDLER( spcewars_sh_port_w ) +{ + UINT8 rising_bits = data & ~port_1_last; + + SN76477_enable_w(0, !(data & 0x01)); /* Saucer Sound */ + + if (rising_bits & 0x02) sample_start(0, 0, 0); /* Shot Sound */ + if (rising_bits & 0x04) sample_start(1, 1, 0); /* Base Hit */ + if (rising_bits & 0x08) sample_start(2, 2, 0); /* Invader Hit */ + + speaker_level_w(0, (data & 0x10) ? 1 : 0); /* Various bitstream tunes */ + + port_1_last = data; +} + + +/*******************************************************/ +/* */ +/* lrescue, grescue, lrescuem, desterth */ +/* */ +/*******************************************************/ + +static const char *lrescue_sample_names[] = +{ + "*lrescue", + "alienexplosion.wav", + "rescueshipexplosion.wav", + "beamgun.wav", + "thrust.wav", + "bonus2.wav", + "bonus3.wav", + "shootingstar.wav", + "stepl.wav", + "steph.wav", + 0 +}; + +struct Samplesinterface lrescue_samples_interface = +{ + 4, /* 4 channels */ + lrescue_sample_names +}; + +WRITE8_HANDLER( lrescue_sh_port_1_w ) +{ + UINT8 rising_bits = data & ~port_1_last; + + if (rising_bits & 0x01) sample_start(0, 3, 0); /* Thrust */ + if (rising_bits & 0x02) sample_start(1, 2, 0); /* Shot Sound */ + if (rising_bits & 0x04) sample_start(0, 1, 0); /* Death */ + if (rising_bits & 0x08) sample_start(1, 0, 0); /* Alien Hit */ + if (rising_bits & 0x10) sample_start(2, 5, 0); /* Bonus Ship (not confirmed) */ + + sound_global_enable(data & 0x20); + + c8080bw_screen_red_w(data & 0x04); + + port_1_last = data; +} + +WRITE8_HANDLER( lrescue_sh_port_2_w ) +{ + UINT8 rising_bits = data & ~port_2_last; + + if (rising_bits & 0x01) sample_start(1, 8, 0); /* Footstep high tone */ + if (rising_bits & 0x02) sample_start(1, 7, 0); /* Footstep low tone */ + if (rising_bits & 0x04) sample_start(1, 4, 0); /* Bonus when counting men saved */ + + speaker_level_w(0, (data & 0x08) ? 1 : 0); /* Bitstream tunes - endlevel and bonus1 */ + + if (rising_bits & 0x10) sample_start(3, 6, 0); /* Shooting Star and Rescue Ship sounds */ + if (~data & 0x10 && port_2_last & 0x10) sample_stop (3); /* This makes the rescue ship sound beep on and off */ + + c8080bw_flip_screen_w(data & 0x20); + + port_2_last = data; +} + + +/*******************************************************/ +/* */ +/* Cosmo */ +/* */ +/*******************************************************/ + +WRITE8_HANDLER( cosmo_sh_port_2_w ) +{ + /* inverted flip screen bit */ + invadpt2_sh_port_2_w(offset, data ^ 0x20); +} + + +/*******************************************************/ +/* */ +/* Taito "Balloon Bomber" */ +/* The sounds are not the correct ones */ +/* */ +/*******************************************************/ + +WRITE8_HANDLER( ballbomb_sh_port_1_w ) +{ + UINT8 rising_bits = data & ~port_1_last; + + if (rising_bits & 0x01) sample_start(1, 2, 0); /* Hit a balloon */ + if (rising_bits & 0x02) sample_start(2, 0, 0); /* Shot Sound */ + if (rising_bits & 0x04) sample_start(2, 1, 0); /* Base Hit */ + if (rising_bits & 0x08) sample_start(1, 7, 0); /* Hit a Bomb */ + if (rising_bits & 0x10) sample_start(3, 8, 0); /* Bonus Base at 1500 points */ + + sound_global_enable(data & 0x20); + + c8080bw_screen_red_w(data & 0x04); + + port_1_last = data; +} + +WRITE8_HANDLER( ballbomb_sh_port_2_w ) +{ + UINT8 rising_bits = data & ~port_2_last; + + if (data & 0x01) sample_start(0, 7, 0); /* Indicates plane will drop bombs */ + if (data & 0x04) sample_start(0, 4, 0); /* Plane is dropping new balloons at start of level */ + if (rising_bits & 0x10) sample_start(2, 2, 0); /* Balloon hit and bomb drops */ + + c8080bw_flip_screen_w(data & 0x20); + + port_2_last = data; +} + + + +/*******************************************************/ +/* */ +/* Taito "Indian Battle" */ +/* Sept 2005, D.R. */ +/*******************************************************/ +static const discrete_dac_r1_ladder indianbt_music_dac = + {3, {0, RES_K(47), RES_K(12)}, 0, 0, 0, CAP_U(0.1)}; + +#define INDIANBT_MUSIC_CLK (7680.0*2*2*2) + +/* Nodes - Inputs */ +#define INDIANBT_MUSIC_DATA NODE_01 +/* Nodes - Sounds */ +#define INDIANBT_MUSIC NODE_11 + +DISCRETE_SOUND_START(indianbt) + + DISCRETE_INPUT_DATA (INDIANBT_MUSIC_DATA) + +/****************************************************************************** + * + * Music Generator + * + ******************************************************************************/ + DISCRETE_NOTE(NODE_20, 1, INDIANBT_MUSIC_CLK, INDIANBT_MUSIC_DATA, 255, 5, DISC_CLK_IS_FREQ) + + // Convert count to 7492 output + DISCRETE_TRANSFORM2(NODE_21, 1, NODE_20, 2, "01>0+") + + DISCRETE_DAC_R1(NODE_22, 1, NODE_21, DEFAULT_TTL_V_LOGIC_1, &indianbt_music_dac) + +/****************************************************************************** + * + * Final Mixing and Output + * + ******************************************************************************/ + DISCRETE_CRFILTER(NODE_90, 1, NODE_22, RES_K(10), CAP_U(0.1)) + + DISCRETE_OUTPUT(NODE_90, 21000) + +DISCRETE_SOUND_END + +WRITE8_HANDLER( indianbt_sh_port_1_w ) +{ + /* bit 4 occurs every 5.25 seconds during gameplay */ + + UINT8 rising_bits = data & ~port_1_last; + + if (rising_bits & 0x01) sample_start(1, 7, 0); /* Death */ + if (rising_bits & 0x02) sample_start(0, 1, 0); /* Shot Sound */ + if (rising_bits & 0x04) sample_start(2, 3, 0); /* Move */ + if (rising_bits & 0x08) sample_start(3, 2, 0); /* Hit */ + + sound_global_enable(data & 0x20); + + c8080bw_screen_red_w(data & 0x01); + + port_1_last = data; +} + +WRITE8_HANDLER( indianbt_sh_port_2_w ) +{ + UINT8 rising_bits = data & ~port_2_last; + + if (rising_bits & 0x01) sample_start(4, 0, 0); /* Bird dropped an egg, Lasso used */ + if (rising_bits & 0x02) sample_start(4, 2, 0); /* Egg hatches, egg shot */ + if (rising_bits & 0x08) sample_start(5, 0, 0); /* Grabber, Lasso caught something */ + if (rising_bits & 0x10) sample_start(3, 7, 0); /* Lasso sound */ + + port_2_last = data; +} + +WRITE8_HANDLER( indianbt_sh_port_3_w ) +{ + discrete_sound_w(INDIANBT_MUSIC_DATA, data); +} + + +/*******************************************************************/ +/* */ +/* Taito "Polaris" */ +/* */ +/* D.R. */ +/* The R/C values in the schematic may have no bearing in reality. */ +/* I have noted some differences from a real board. */ +/* */ +/*******************************************************************/ + +static const discrete_lfsr_desc polaris_lfsr={ + DISC_CLK_IS_FREQ, + 17, /* Bit Length */ + 0, /* Reset Value */ + 4, /* Use Bit 4 as XOR input 0 */ + 16, /* Use Bit 16 as XOR input 1 */ + DISC_LFSR_XOR, /* Feedback stage1 is XOR */ + DISC_LFSR_OR, /* Feedback stage2 is just stage 1 output OR with external feed */ + DISC_LFSR_REPLACE, /* Feedback stage3 replaces the shifted register contents */ + 0x000001, /* Everything is shifted into the first bit only */ + 0, /* Output is not inverted */ + 12 /* Output bit */ +}; + +static const discrete_dac_r1_ladder polaris_music_dac = + {2, {RES_K(47), RES_K(12), 0,0,0,0,0,0}, 0, 0, 0, CAP_P(180)}; + +static const discrete_op_amp_filt_info polaris_music_op_amp_filt_info = + {RES_K(580), 0, 0, RES_M(2.2), RES_M(1), CAP_U(.01), 0, 0, 0, 12, 0}; + +static const discrete_op_amp_filt_info polaris_nol_op_amp_filt_info = + {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}; + +static const discrete_op_amp_filt_info polaris_noh_op_amp_filt_info = + {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}; + +static const discrete_op_amp_osc_info polaris_sonar_vco_info = + {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}; + +static const discrete_op_amp_tvca_info polaris_sonar_tvca_info = + { 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, 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}; + +static const discrete_op_amp_osc_info polaris_boat_mod_info = + {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}; + +static const discrete_op_amp_osc_info polaris_boat_vco_info = + {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}; + +static const discrete_op_amp_tvca_info polaris_shot_tvca_info = + { 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, 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}; + +static const discrete_op_amp_tvca_info polaris_shiphit_tvca_info = + { 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, 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}; + +static const discrete_op_amp_tvca_info polaris_exp_tvca_info = + { 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, 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}; + +// The schematic shows a .22uF cap but Guru's board has a 1uF +static const discrete_op_amp_tvca_info polaris_hit_tvca_info = + { 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, 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}; + +// The schematic shows a 1uF cap but Guru's board has a 2.2uF +static const discrete_integrate_info polaris_plane_integrate_info = + {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}; + +// A bit of a cheat. The schematic show the cap as 47p, but that makes the frequency too high. +// Guru's board has a .01 cap, which would make the freq sub-sonic using the other schematic values. +// I will use 2000p until the proper values can be confirmed. +static const discrete_op_amp_osc_info polaris_plane_vco_info = + {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}; + +static const discrete_mixer_desc polaris_mixer_vr1_desc = + {DISC_MIXER_IS_RESISTOR, + {RES_K(66), RES_K(43), RES_K(20), RES_K(43)}, + {0}, // no variable resistors + {CAP_U(1), CAP_U(1), CAP_U(1), CAP_U(1)}, + 0, RES_K(50), 0, 0, 0, 1}; + +static const discrete_mixer_desc polaris_mixer_vr2_desc = + {DISC_MIXER_IS_RESISTOR, + {RES_K(66), RES_K(110)}, + {0}, // no variable resistors + {CAP_U(1), CAP_U(1)}, + 0, RES_K(50), 0, 0, 0, 1}; + +// Note: the final gain leaves the explosions (SX3) at a level +// where they clip. From the schematics, this is how they wanted it. +// This makes them have more bass and distortion. +static const discrete_mixer_desc polaris_mixer_vr4_desc = + {DISC_MIXER_IS_RESISTOR, + {RES_K(22), RES_K(20), RES_K(22), RES_K(22)}, + {0}, // no variable resistors + {0, CAP_U(1), 0, 0}, + 0, RES_K(50), 0, CAP_U(1), 0, 40000}; + +/* Nodes - Inputs */ +#define POLARIS_MUSIC_DATA NODE_01 +#define POLARIS_SX0_EN NODE_02 +#define POLARIS_SX1_EN NODE_03 +#define POLARIS_SX2_EN NODE_04 +#define POLARIS_SX3_EN NODE_05 +#define POLARIS_SX5_EN NODE_06 +#define POLARIS_SX6_EN NODE_07 +#define POLARIS_SX7_EN NODE_08 +#define POLARIS_SX9_EN NODE_09 +#define POLARIS_SX10_EN NODE_10 +/* Nodes - Sounds */ +#define POLARIS_MUSIC NODE_11 +#define POLARIS_NOISE_LO NODE_12 +#define POLARIS_NOISE_LO_FILT NODE_13 +#define POLARIS_NOISE_HI_FILT NODE_14 +#define POLARIS_SHOTSND NODE_15 +#define POLARIS_SHIP_HITSND NODE_16 +#define POLARIS_SHIPSND NODE_17 +#define POLARIS_EXPLOSIONSND NODE_18 +#define POLARIS_PLANESND NODE_19 +#define POLARIS_HITSND NODE_20 +#define POLARIS_SONARSND NODE_21 +/* Nodes - Adjust */ +#define POLARIS_ADJ_VR1 NODE_23 +#define POLARIS_ADJ_VR2 NODE_24 +#define POLARIS_ADJ_VR3 NODE_25 + +DISCRETE_SOUND_START(polaris) + + /************************************************/ + /* Polaris sound system: 8 Sound Sources */ + /* */ + /* Relative volumes are adjustable */ + /* */ + /************************************************/ + + /************************************************/ + /* Input register mapping for polaris */ + /************************************************/ + DISCRETE_INPUT_DATA (POLARIS_MUSIC_DATA) + DISCRETE_INPUT_LOGIC(POLARIS_SX0_EN) + DISCRETE_INPUT_LOGIC(POLARIS_SX1_EN) + DISCRETE_INPUT_LOGIC(POLARIS_SX2_EN) + DISCRETE_INPUT_LOGIC(POLARIS_SX3_EN) + DISCRETE_INPUT_LOGIC(POLARIS_SX5_EN) + DISCRETE_INPUT_LOGIC(POLARIS_SX6_EN) + DISCRETE_INPUT_LOGIC(POLARIS_SX7_EN) + DISCRETE_INPUT_LOGIC(POLARIS_SX9_EN) + DISCRETE_INPUT_LOGIC(POLARIS_SX10_EN) + + /* We will cheat and just use the controls to scale the amplitude. */ + /* It is the same as taking the (0 to 50k)/50k */ + DISCRETE_ADJUSTMENT_TAG(POLARIS_ADJ_VR1, 1, 0, 1, DISC_LINADJ, "VR1") + DISCRETE_ADJUSTMENT_TAG(POLARIS_ADJ_VR2, 1, 0, 1, DISC_LINADJ, "VR2") + /* Extra cheating for VR3. We will include the resistor scaling. */ + DISCRETE_ADJUSTMENT_TAG(POLARIS_ADJ_VR3, 1, 0, 0.5376, DISC_LINADJ, "VR3") + +/****************************************************************************** + * + * Music Generator + * + * This is a simulation of the following circuit: + * 555 Timer (Ra = 1k, Rb = 1k, C =.01uF) running at 48kHz. Connected to a + * 1 bit counter (/2) for 24kHz. But I will use the frequency measured by Guru. + * This is then sent to a preloadable 8 bit counter (4G & 4H), which loads the + * value from Port 2 when overflowing from 0xFF to 0x00. Therefore it divides + * by 2 (Port 2 = FE) to 256 (Port 2 = 00). + * This goes to a 2 bit counter (5H) which has a 47k resistor on Q0 and a 12k on Q1. + * This creates a sawtooth ramp of: 0%, 12/59%, 47/59%, 100% then back to 0% + * + * Note that there is no music disable line. When there is no music, the game + * sets the oscillator to 0Hz. (Port 2 = FF) + * + ******************************************************************************/ + DISCRETE_NOTE(NODE_30, 1, 23396, POLARIS_MUSIC_DATA, 255, 3, DISC_CLK_IS_FREQ) + DISCRETE_DAC_R1(NODE_31, 1, NODE_30, DEFAULT_TTL_V_LOGIC_1, &polaris_music_dac) + 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) + DISCRETE_MULTIPLY(POLARIS_MUSIC, 1, NODE_32, POLARIS_ADJ_VR3) + +/****************************************************************************** + * + * Background Sonar Sound + * + * This is a background sonar that plays at all times during the game. + * It is a VCO triangle wave genarator, that uses the Low frequency filtered + * noise source to modulate the frequency. + * This is then amplitude modulated, by some fancy clocking scheme. + * It is disabled during SX3. (No sonar when you die.) + * + * 5L pin 6 divides 60Hz by 16. This clocks the sonar. + * 5K pin 9 is inverted by 5F, and then the 0.1uF;1M;270k;1S1588 diode circuit + * makes a one shot pulse of approx. 15ms to keep the noise working. + * + ******************************************************************************/ + DISCRETE_SQUAREWFIX(NODE_40, 1, 60.0/16, 1, 50, 1.0/2, 0) // IC 5L, pin 6 + DISCRETE_COUNTER(NODE_41, 1, 0, NODE_40, 31, 1, 0, DISC_CLK_ON_F_EDGE) // IC 5L & 5F + DISCRETE_TRANSFORM2(NODE_42, 1, NODE_41, 4, "01&") // IC 5L, pin 9 + DISCRETE_TRANSFORM2(NODE_43, 1, NODE_41, 16, "01&!") // IC 5F, pin 8 + DISCRETE_ONESHOT(NODE_44, NODE_43, 1, 0.0015, DISC_ONESHOT_REDGE | DISC_ONESHOT_NORETRIG | DISC_OUT_ACTIVE_HIGH) + + DISCRETE_LOGIC_OR(NODE_45, 1, NODE_42, POLARIS_SX3_EN) + DISCRETE_LOGIC_DFLIPFLOP(NODE_46, 1, 1, 1, NODE_40, NODE_45) + + DISCRETE_OP_AMP_VCO1(NODE_47, 1, POLARIS_NOISE_LO_FILT, &polaris_sonar_vco_info) + DISCRETE_OP_AMP_TRIG_VCA(POLARIS_SONARSND, NODE_45, NODE_46, 0, NODE_47, 0, &polaris_sonar_tvca_info) + +/****************************************************************************** + * + * Noise sources + * + * The frequencies for the noise sources were Measured by Guru. + * + * The output of the shift register is buffered by an op-amp which limits + * the output to 0V and (12V - OP_AMP_NORTON_VBE) + * + ******************************************************************************/ + 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. + // Filtered Lo noise. 7K pin 5. + 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) + + 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 + // Filtered Hi noise. 6B pin 10. - This does not really do much. Sample rates of 98k+ are needed for this high of filtering. + 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) + +/****************************************************************************** + * + * Shot - SX0 (When player shoots) + * + * When Enabled it makes a low frequency RC filtered noise. As soon as it + * disables, it switches to a high frequency RC filtered noise with the volume + * decaying based on the RC values of 680k and 1uF. + * + ******************************************************************************/ + DISCRETE_OP_AMP_TRIG_VCA(POLARIS_SHOTSND, POLARIS_SX0_EN, 0, 0, POLARIS_NOISE_HI_FILT, POLARIS_NOISE_LO_FILT, &polaris_shot_tvca_info) + +/****************************************************************************** + * + * Ship Hit - SX1 (When sub is hit) + * + * When Enabled it makes a low frequency RC filtered noise. As soon as it + * disables, it's volume starts decaying based on the RC values of 680k and + * 1uF. Also as it decays, a decaying high frequency RC filtered noise is + * mixed in. + * + ******************************************************************************/ + 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) + +/****************************************************************************** + * + * Ship - SX2 (When boat moves across screen) + * + * This uses a 5.75Hz |\|\ sawtooth to modulate the frequency of a + * voltage controlled triangle wave oscillator. * + * + ******************************************************************************/ + DISCRETE_OP_AMP_OSCILLATOR(NODE_60, 1, &polaris_boat_mod_info) + DISCRETE_OP_AMP_VCO1(POLARIS_SHIPSND, POLARIS_SX2_EN, NODE_60, &polaris_boat_vco_info) + +/****************************************************************************** + * + * Explosion - SX3 (When player, boat or boss plane is hit) + * + * When Enabled it makes a low frequency noise. As soon as it disables, it's + * volume starts decaying based on the RC values of 680k and 0.33uF. The + * final output is RC filtered. + * + * Note that when this is triggered, the sonar sound clock is disabled. + * + ******************************************************************************/ + DISCRETE_OP_AMP_TRIG_VCA(NODE_70, POLARIS_SX3_EN, 0, 0, POLARIS_NOISE_LO, 0, &polaris_exp_tvca_info) + + DISCRETE_RCFILTER(NODE_71, 1, NODE_70, 560.0, CAP_U(.22)) + DISCRETE_RCFILTER(POLARIS_EXPLOSIONSND, 1, NODE_71, RES_K(6.8), CAP_U(.22)) + +/****************************************************************************** + * + * Plane Down - SX6 + * Plane Up - SX7 + * + * The oscillator is enabled when SX7 goes high. When SX6 is enabled the + * frequency lowers. When SX6 is disabled the frequency ramps back up. + * Also some NOISE_HI_FILT is mixed in so the frequency varies some. + * + ******************************************************************************/ + DISCRETE_INTEGRATE(NODE_80, POLARIS_SX6_EN, POLARIS_SX7_EN, &polaris_plane_integrate_info) + DISCRETE_OP_AMP_VCO2(POLARIS_PLANESND, POLARIS_SX7_EN, NODE_80, POLARIS_NOISE_HI_FILT, &polaris_plane_vco_info) + +/****************************************************************************** + * + * HIT - SX9 & SX10 + * + * Following the schematic, 3 different sounds are produced. + * SX10 SX9 Effect + * 0 0 no sound + * 0 1 NOISE_HI_FILT while enabled + * 1 0 NOISE_LO_FILT while enabled (When a regular plane is hit) + * 1 1 NOISE_HI_FILT & NOISE_LO_FILT decaying imediately @ 680k, 0.22uF + * + ******************************************************************************/ + 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) + +/****************************************************************************** + * + * Final Mixing and Output + * + ******************************************************************************/ + DISCRETE_MIXER4(NODE_90, 1, POLARIS_SHOTSND, POLARIS_SONARSND, POLARIS_HITSND, POLARIS_PLANESND, &polaris_mixer_vr1_desc) + DISCRETE_MULTIPLY(NODE_91, 1, NODE_90, POLARIS_ADJ_VR1) + DISCRETE_MIXER2(NODE_92, 1, POLARIS_SHIPSND, POLARIS_SHIP_HITSND, &polaris_mixer_vr2_desc) + DISCRETE_MULTIPLY(NODE_93, 1, NODE_92, POLARIS_ADJ_VR2) + DISCRETE_MIXER4(NODE_94, POLARIS_SX5_EN, NODE_91, POLARIS_EXPLOSIONSND, NODE_93, POLARIS_MUSIC, &polaris_mixer_vr4_desc) + + DISCRETE_OUTPUT(NODE_94, 1) + +DISCRETE_SOUND_END + +WRITE8_HANDLER( polaris_sh_port_1_w ) +{ + discrete_sound_w(POLARIS_MUSIC_DATA, data); +} + +WRITE8_HANDLER( polaris_sh_port_2_w ) +{ + /* 0x01 - SX0 - Shot */ + discrete_sound_w(POLARIS_SX0_EN, data & 0x01); + + /* 0x02 - SX1 - Ship Hit (Sub) */ + discrete_sound_w(POLARIS_SX1_EN, data & 0x02); + + /* 0x04 - SX2 - Ship */ + discrete_sound_w(POLARIS_SX2_EN, data & 0x04); + + /* 0x08 - SX3 - Explosion */ + discrete_sound_w(POLARIS_SX3_EN, data & 0x08); + + /* 0x10 - SX4 */ + + /* 0x20 - SX5 - Sound Enable */ + discrete_sound_w(POLARIS_SX5_EN, data & 0x20); +} + +WRITE8_HANDLER( polaris_sh_port_3_w ) +{ + coin_lockout_global_w(data & 0x04); /* SX8 */ + + c8080bw_flip_screen_w(data & 0x20); /* SX11 */ + + /* 0x01 - SX6 - Plane Down */ + discrete_sound_w(POLARIS_SX6_EN, data & 0x01); + + /* 0x02 - SX7 - Plane Up */ + discrete_sound_w(POLARIS_SX7_EN, data & 0x02); + + /* 0x08 - SX9 - Hit */ + discrete_sound_w(POLARIS_SX9_EN, data & 0x08); + + /* 0x10 - SX10 - Hit */ + discrete_sound_w(POLARIS_SX10_EN, data & 0x10); +} + + +/*******************************************************/ +/* */ +/* Taito "Space Chaser" */ +/* */ +/* The SN76477 still needs to be routed to the */ +/* discrete system for filtering. */ +/*******************************************************/ + +/* + * The dot sound is a square wave clocked by either the + * the 8V or 4V signals + * + * The frequencies are (for the 8V signal): + * + * 19.968 MHz crystal / 2 (Qa of 74160 #10) -> 9.984MHz + * / 2 (7474 #14) -> 4.992MHz + * / 256+16 (74161 #5 and #8) -> 18352.94Hz + * / 8 (8V) -> 2294.12 Hz + * / 2 the final freq. is 2 toggles -> 1147.06Hz + * + * for 4V, it's double at 2294.12Hz + */ +#define SCHASER_HSYNC 18352.94 +#define SCHASER_4V SCHASER_HSYNC /2 /4 +#define SCHASER_8V SCHASER_HSYNC /2 /8 + +struct SN76477interface schaser_sn76477_interface = +{ + RES_K( 47), /* 4 noise_res */ + RES_K(330), /* 5 filter_res */ + CAP_P(470), /* 6 filter_cap */ + RES_M(2.2), /* 7 decay_res */ + CAP_U(1.0), /* 8 attack_decay_cap */ + RES_K(4.7), /* 10 attack_res */ + 0, /* 11 amplitude_res (variable) */ + RES_K(33), /* 12 feedback_res */ + 0, /* 16 vco_voltage */ + CAP_U(0.1), /* 17 vco_cap */ + RES_K(39), /* 18 vco_res */ + 5.0, /* 19 pitch_voltage */ + RES_K(120), /* 20 slf_res */ + CAP_U(1.0), /* 21 slf_cap */ + CAP_U(0.1), /* 23 oneshot_cap */ + RES_K(220), /* 24 oneshot_res */ + 1, /* 22 vco */ + 0, /* 26 mixer A */ + 0, /* 25 mixer B */ + 0, /* 27 mixer C */ + 1, /* 1 envelope 1 */ + 0, /* 28 envelope 2 */ + 1 /* 9 enable (variable) */ +}; + +/* Nodes - Inputs */ +#define SCHASER_DOT_EN NODE_01 +#define SCHASER_DOT_SEL NODE_02 +#define SCHASER_EXP_STREAM NODE_03 +#define SCHASER_MUSIC_BIT NODE_04 +#define SCHASER_SND_EN NODE_05 +/* Nodes - Adjusters */ +#define SCHASER_VR1 NODE_07 +#define SCHASER_VR2 NODE_08 +#define SCHASER_VR3 NODE_09 +/* Nodes - Sounds */ +#define SCHASER_DOT_SND NODE_10 +#define SCHASER_EXP_SND NODE_11 +#define SCHASER_MUSIC_SND NODE_12 + +DISCRETE_SOUND_START(schaser) + /************************************************/ + /* Input register mapping for schaser */ + /************************************************/ + DISCRETE_INPUT_LOGIC (SCHASER_DOT_EN) + DISCRETE_INPUT_LOGIC (SCHASER_DOT_SEL) +// Change the constant to the stream input when working. + DISCRETE_CONSTANT(SCHASER_EXP_STREAM, 0) +// DISCRETE_INPUTX_STREAM(SCHASER_EXP_STREAM, 5.0/36764, 0) + DISCRETE_INPUTX_LOGIC (SCHASER_MUSIC_BIT, DEFAULT_TTL_V_LOGIC_1, 0, 0.0) + DISCRETE_INPUT_LOGIC (SCHASER_SND_EN) + + /************************************************/ + /* Volume adjusters. */ + /* We will set them to adjust the realitive */ + /* gains. */ + /************************************************/ + DISCRETE_ADJUSTMENT_TAG(SCHASER_VR1, 1, 0, RES_K(50)/(RES_K(50) + RES_K(470)), DISC_LINADJ, "VR1") + DISCRETE_ADJUSTMENT_TAG(SCHASER_VR2, 1, 0, RES_K(50)/(RES_K(50) + 560 + RES_K(6.8) + RES_K(2)), DISC_LINADJ, "VR2") + DISCRETE_ADJUSTMENT_TAG(SCHASER_VR3, 1, 0, RES_K(50)/(RES_K(50) + 560 + RES_K(6.8) + RES_K(10)), DISC_LINADJ, "VR3") + + /************************************************/ + /* Dot selection just selects between 4V and 8V */ + /************************************************/ + DISCRETE_SQUAREWFIX(NODE_20, 1, SCHASER_4V, DEFAULT_TTL_V_LOGIC_1, 50, 0, 0) + DISCRETE_SQUAREWFIX(NODE_21, 1, SCHASER_8V, DEFAULT_TTL_V_LOGIC_1, 50, 0, 0) + DISCRETE_SWITCH(NODE_22, SCHASER_DOT_EN, SCHASER_DOT_SEL, NODE_20, NODE_21) + DISCRETE_RCFILTER(NODE_23, 1, NODE_22, 560, CAP_U(.1)) + DISCRETE_RCFILTER(NODE_24, 1, NODE_23, RES_K(6.8) + 560, CAP_U(.1)) + DISCRETE_MULTIPLY(SCHASER_DOT_SND, 1, NODE_24, SCHASER_VR3) + + /************************************************/ + /* Explosion/Effect filtering */ + /************************************************/ + DISCRETE_RCFILTER(NODE_30, 1, SCHASER_EXP_STREAM, 560, CAP_U(.1)) + DISCRETE_RCFILTER(NODE_31, 1, NODE_30, RES_K(6.8) + 560, CAP_U(.1)) + DISCRETE_CRFILTER(NODE_32, 1, NODE_31, RES_K(6.8) + 560 + RES_K(2) + RES_K(50), CAP_U(1)) + DISCRETE_MULTIPLY(SCHASER_EXP_SND, 1, NODE_32, SCHASER_VR2) + + /************************************************/ + /* Music is just a 1 bit DAC */ + /************************************************/ + DISCRETE_CRFILTER(NODE_40, 1, SCHASER_MUSIC_BIT, RES_K(470) + RES_K(50), CAP_U(.01)) + DISCRETE_MULTIPLY(SCHASER_MUSIC_SND, 1, NODE_40, SCHASER_VR1) + + /************************************************/ + /* Final mix with gain */ + /************************************************/ + DISCRETE_ADDER3(NODE_90, SCHASER_SND_EN, SCHASER_DOT_SND, SCHASER_EXP_SND, SCHASER_MUSIC_SND) + + DISCRETE_OUTPUT(NODE_90, 60000) +DISCRETE_SOUND_END + +static const double schaser_effect_rc[8] = +{ + 0, + (RES_K(82) + RES_K(20)) * CAP_U(1), + (RES_K(39) + RES_K(20)) * CAP_U(1), + (1.0/ (1.0/RES_K(82) + 1.0/RES_K(39)) + RES_K(20)) * CAP_U(1), + (RES_K(15) + RES_K(20)) * CAP_U(1), + (1.0/ (1.0/RES_K(82) + 1.0/RES_K(15)) + RES_K(20)) * CAP_U(1), + (1.0/ (1.0/RES_K(39) + 1.0/RES_K(15)) + RES_K(20)) * CAP_U(1), + (1.0/ (1.0/RES_K(82) + 1.0/RES_K(39) + 1.0/RES_K(15)) + RES_K(20)) * CAP_U(1) +}; + +WRITE8_HANDLER( schaser_sh_port_1_w ) +{ + static int last_effect = 0; + int effect; + + /* bit 0 - Dot Sound Enable (SX0) + bit 1 - Dot Sound Pitch (SX1) + bit 2 - Effect Sound A (SX2) + bit 3 - Effect Sound B (SX3) + bit 4 - Effect Sound C (SX4) + bit 5 - Explosion (SX5) */ + + discrete_sound_w(SCHASER_DOT_EN, data & 0x01); + discrete_sound_w(SCHASER_DOT_SEL, data & 0x02); + + /* The effect is a variable rate 555 timer. A diode/resistor array is used to + * select the frequency. Because of the diode voltage drop, we can not use the + * standard 555 time formulas. Also, when effect=0, the charge resistor + * is disconnected. This causes the charge on the cap to slowly bleed off, but + * but the bleed time is so long, that we can just cheat and put the time on hold + * when effect = 0. */ + effect = (data >> 2) & 0x07; + if (last_effect != effect) + { + if (effect) + { + if (attotime_compare(schaser_effect_555_time_remain, attotime_zero) != 0) + { + /* timer re-enabled, use up remaining 555 high time */ + timer_adjust(schaser_effect_555_timer, schaser_effect_555_time_remain, effect, attotime_zero); + } + else if (!schaser_effect_555_is_low) + { + /* set 555 high time */ + attotime new_time = attotime_make(0, ATTOSECONDS_PER_SECOND * .8873 * schaser_effect_rc[effect]); + timer_adjust(schaser_effect_555_timer, new_time, effect, attotime_zero); + } + } + else + { + /* disable effect - stops at end of low cycle */ + if (!schaser_effect_555_is_low) + { + schaser_effect_555_time_remain = timer_timeleft(schaser_effect_555_timer); + timer_adjust(schaser_effect_555_timer, attotime_never, 0, attotime_never); + } + } + last_effect = effect; + } + + schaser_explosion = (data >> 5) & 0x01; + if (schaser_explosion) + { + SN76477_amplitude_res_w(0, 1.0 / (1.0/RES_K(200) + 1.0/RES_K(68))); + } + else + { + SN76477_amplitude_res_w(0, RES_K(200)); + } + SN76477_enable_w(0, !(schaser_effect_555_is_low || schaser_explosion)); + SN76477_one_shot_cap_voltage_w(0, !(schaser_effect_555_is_low || schaser_explosion) ? 0 : SN76477_EXTERNAL_VOLTAGE_DISCONNECT); + SN76477_mixer_b_w(0, schaser_explosion); +} + +WRITE8_HANDLER( schaser_sh_port_2_w ) +{ + /* bit 0 - Music (DAC) (SX6) + bit 1 - Sound Enable (SX7) + bit 2 - Coin Lockout (SX8) + bit 3 - Field Control A (SX9) + bit 4 - Field Control B (SX10) + bit 5 - Flip Screen */ + + discrete_sound_w(SCHASER_MUSIC_BIT, data & 0x01); + + discrete_sound_w(SCHASER_SND_EN, data & 0x02); + sound_global_enable(data & 0x02); + + coin_lockout_global_w(data & 0x04); + + schaser_background_control_w(data & 0x18); + + c8080bw_flip_screen_w(data & 0x20); +} + + +static TIMER_CALLBACK( schaser_effect_555_cb ) +{ + int effect = param; + attotime new_time; + /* Toggle 555 output */ + schaser_effect_555_is_low = !schaser_effect_555_is_low; + schaser_effect_555_time_remain = attotime_zero; + + if (schaser_effect_555_is_low) + new_time = attotime_div(PERIOD_OF_555_ASTABLE(0, RES_K(20), CAP_U(1)), 2); + else + { + if (effect) + new_time = attotime_make(0, ATTOSECONDS_PER_SECOND * .8873 * schaser_effect_rc[effect]); + else + new_time = attotime_never; + } + timer_adjust(schaser_effect_555_timer, new_time, effect, attotime_zero); + SN76477_enable_w(0, !(schaser_effect_555_is_low || schaser_explosion)); + SN76477_one_shot_cap_voltage_w(0, !(schaser_effect_555_is_low || schaser_explosion) ? 0 : SN76477_EXTERNAL_VOLTAGE_DISCONNECT); +} + + +MACHINE_START( schaser ) +{ + schaser_effect_555_timer = timer_alloc(schaser_effect_555_cb); + + machine_start_mw8080bw(machine); +} + + +MACHINE_RESET( schaser ) +{ + schaser_effect_555_is_low = 0; + timer_adjust(schaser_effect_555_timer, attotime_never, 0, attotime_never); + schaser_sh_port_1_w(0, 0); + schaser_sh_port_2_w(0, 0); + schaser_effect_555_time_remain = attotime_zero; + + machine_reset_mw8080bw(machine); +} + + +/****************************************************/ +/* Rolling Crash / Moon Base */ +/* - Moon Base uses same ports and bits as invaders */ +/* - Press Left or Right to choose game to play */ +/****************************************************/ + +WRITE8_HANDLER( rollingc_sh_port_w ) +{ + UINT8 rising_bits = data & ~port_3_last; + + if (rising_bits & 0x02) sample_start(4, 0, 0); /* Steering */ + if (rising_bits & 0x04) sample_start(0, 1, 0); /* Collision */ + if (rising_bits & 0x10) sample_start(1, 8, 0); /* Computer car is starting to move */ + + port_3_last = data; +} + + +/*************************************************************************************/ +/* Invader's Revenge preliminary sound */ +/* Correct samples not available */ +/* Notes: */ +/* Init sequence: 0x01 (20 times), 0x40 (20 times), 0x4c, 0x40, 0x44, 0x40 (9 times).*/ +/* Player 1 start sequence: 0x0c, 0x20, 0x22. */ +/* Start of Attract mode: 0x04. */ +/* Unknown codes: 0x28, 0x2a, 0x0c, 0x34, 0x2c, 0x2e, 0x1c. */ +/*************************************************************************************/ + + +WRITE8_HANDLER( invrvnge_sh_port_w ) +{ + switch (data) + { + case 0x06: + sample_start(1, 0, 0); /* Shoot */ + break; + + case 0x14: + sample_start(2, 2, 0); /* Hit Alien */ + break; + + case 0x16: + sample_start(2, 5, 0); /* Hit Asteroid */ + break; + + case 0x1e: + sample_start(3, 1, 0); /* Death (followed by 0x0a byte), also bit 4 of port 5 */ + break; + + case 0x18: /* Fuel Low */ + case 0x30: /* Fuel bar filling up */ + sample_start(4, 7, 0); + break; + + case 0x02: /* Coin */ + case 0x24: /* Alien dropping to steal fuel */ + case 0x26: /* Alien lifting with fuel */ + case 0x32: /* UFO drops a bomb */ + break; + + case 0x3a: /* Thrust, Docking, extra ship? */ + sample_start(0, 8, 0); + break; + } +} + + +/*****************************************/ +/* Lupin III preliminary sound */ +/* Correct samples not available */ +/*****************************************/ + +WRITE8_HANDLER( lupin3_sh_port_1_w ) +{ + UINT8 rising_bits = data & ~port_1_last; + + if (rising_bits & 0x01) sample_start(0, 6, 0); /* Walking, get money */ + + SN76477_enable_w(0, data & 0x02 ? 0:1); /* Helicopter */ + + if (rising_bits & 0x04) sample_start(0, 7, 0); /* Translocate */ + if (rising_bits & 0x08) sample_start(0, 1, 0); /* Jail */ + if (rising_bits & 0x10) sample_start(3, 8, 0); /* Bonus Man */ + + port_1_last = data; +} + +WRITE8_HANDLER( lupin3_sh_port_2_w ) +{ + UINT8 rising_bits = data & ~port_2_last; + + if (rising_bits & 0x01) sample_start(0, 3, 0); /* Lands on top of building, wife kicks man */ + if (rising_bits & 0x02) sample_start(1, 2, 0); /* deposit money, start intermission, end game */ + if (rising_bits & 0x04) sample_start(2, 5, 0); /* deposit money, start intermission, Slides down rope */ + if (rising_bits & 0x08) sample_start(3, 0, 0); /* start intermission, end game */ + //if (rising_bits & 0x10) sample_start(3, 9, 0); /* Dog barking */ + + c8080bw_flip_screen_w(data & 0x20); + + port_2_last = data; +} + + +/*****************************************/ +/* Space Chaser (CV) preliminary sound */ +/* Much more work needs to be done */ +/*****************************************/ + +WRITE8_HANDLER( schasrcv_sh_port_1_w ) +{ + + /* bit 2 = 2nd speedup + bit 3 = 1st speedup + Death is a stream of ff's with some fe's thrown in */ + + UINT8 rising_bits = data & ~port_1_last; + + if (rising_bits & 0x02) sample_start(1, 6, 0); /* Ran over a dot */ + if (rising_bits & 0x10) sample_start(0, 1, 0); /* Death */ + + port_1_last = data; +} + +WRITE8_HANDLER( schasrcv_sh_port_2_w ) +{ + speaker_level_w(0, (data & 0x01) ? 1 : 0); /* End-of-Level */ + + sound_global_enable(data & 0x10); + + c8080bw_flip_screen_w(data & 0x20); +} + + +/*******************************************************************/ +/* Yosakdon preliminary sound */ +/* No information available as what the correct sounds are */ +/*******************************************************************/ + +WRITE8_HANDLER( yosakdon_sh_port_1_w ) +{ + UINT8 rising_bits = data & ~port_1_last; + + if (rising_bits & 0x01) sample_start(0, 3, 0); /* Game Over */ + if (rising_bits & 0x02) sample_start(2, 0, 0); /* Bird dead */ + if (rising_bits & 0x04) sample_start(0, 1, 0); /* Rifle being fired */ + if (rising_bits & 0x08) sample_start(1, 2, 0); /* Man dead */ + if (rising_bits & 0x10) sample_start(5, 8, 0); /* Bonus Man? */ + + sound_global_enable(data & 0x20); + + port_1_last = data; +} + +WRITE8_HANDLER( yosakdon_sh_port_2_w ) +{ + UINT8 rising_bits = data & ~port_2_last; + + if (rising_bits & 0x01) sample_start(1, 6, 0); /* Ready? , Game Over */ + if (rising_bits & 0x04) sample_start(3, 7, 0); /* Big bird dead */ + + SN76477_enable_w(0, data & 0x08 ? 0:1); /* Big bird */ + + if (rising_bits & 0x10) sample_start(2, 7, 0); /* Game Over */ + + c8080bw_flip_screen_w(data & 0x20); + + port_2_last = data; +} + + +/*****************************************/ +/* shuttlei preliminary sound */ +/* Proper samples are unavailable */ +/*****************************************/ + +WRITE8_HANDLER( shuttlei_sh_port_1_w ) +{ + /* bit 3 is high while you are alive and playing */ + + UINT8 rising_bits = data & ~port_1_last; + + if (rising_bits & 0x01) sample_start(4, 4, 0); /* Fleet move */ + if (rising_bits & 0x02) sample_start(5, 8, 0); /* Extra Tank */ + + SN76477_enable_w(0, data & 0x04 ? 0:1); /* UFO */ + + port_1_last = data; +} + +WRITE8_HANDLER( shuttlei_sh_port_2_w ) +{ + switch (data) + { + case 0x23: + sample_start(2, 2, 0); /* Hit */ + break; + + case 0x2b: + sample_start(0, 0, 0); /* Shoot */ + break; + + case 0xa3: + sample_start(3, 7, 0); /* Hit UFO */ + break; + + case 0xab: + sample_start(1, 1, 0); /* Death */ + break; + } +} diff --git a/src/mame/audio/amiga.c b/src/mame/audio/amiga.c new file mode 100644 index 00000000000..1fd3e647061 --- /dev/null +++ b/src/mame/audio/amiga.c @@ -0,0 +1,280 @@ +/*************************************************************************** + + Amiga Computer / Arcadia Game System + + Driver by: + + Ernesto Corvi & Mariusz Wojcieszek + +***************************************************************************/ + +#include "driver.h" +#include "streams.h" +#include "includes/amiga.h" +#include "cpu/m68000/m68000.h" + + +/************************************* + * + * Debugging + * + *************************************/ + +#define LOG(x) +//#define LOG(x) logerror x + + + +/************************************* + * + * Constants + * + *************************************/ + +#define CLOCK_DIVIDER 16 + + + +/************************************* + * + * Type definitions + * + *************************************/ + +typedef struct _audio_channel audio_channel; +struct _audio_channel +{ + emu_timer * irq_timer; + UINT32 curlocation; + UINT16 curlength; + UINT16 curticks; + UINT8 index; + UINT8 dmaenabled; + UINT8 manualmode; + INT8 latched; +}; + + +typedef struct _amiga_audio amiga_audio; +struct _amiga_audio +{ + audio_channel channel[4]; + sound_stream * stream; +}; + + + +/************************************* + * + * Globals + * + *************************************/ + +static amiga_audio *audio_state; + + + +/************************************* + * + * DMA reload/IRQ signalling + * + *************************************/ + +static TIMER_CALLBACK( signal_irq ) +{ + amiga_custom_w(REG_INTREQ, 0x8000 | (0x80 << param), 0); +} + + +static void dma_reload(audio_channel *chan) +{ + chan->curlocation = CUSTOM_REG_LONG(REG_AUD0LCH + chan->index * 8); + chan->curlength = CUSTOM_REG(REG_AUD0LEN + chan->index * 8); + timer_adjust(chan->irq_timer, ATTOTIME_IN_HZ(15750), chan->index, attotime_zero); + LOG(("dma_reload(%d): offs=%05X len=%04X\n", chan->index, chan->curlocation, chan->curlength)); +} + + + +/************************************* + * + * Manual mode data writer + * + *************************************/ + +void amiga_audio_data_w(int which, UINT16 data) +{ + audio_state->channel[which].manualmode = TRUE; +} + + + +/************************************* + * + * Stream updater + * + *************************************/ + +void amiga_audio_update(void) +{ + stream_update(audio_state->stream); +} + + + +static void amiga_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int length) +{ + amiga_audio *audio = param; + int channum, sampoffs = 0; + + /* if all DMA off, disable all channels */ + if (!(CUSTOM_REG(REG_DMACON) & 0x0200)) + { + audio->channel[0].dmaenabled = + audio->channel[1].dmaenabled = + audio->channel[2].dmaenabled = + audio->channel[3].dmaenabled = FALSE; + + /* clear the sample data to 0 */ + for (channum = 0; channum < 4; channum++) + memset(outputs[channum], 0, sizeof(stream_sample_t) * length); + return; + } + + length *= CLOCK_DIVIDER; + + /* update the DMA states on each channel and reload if fresh */ + for (channum = 0; channum < 4; channum++) + { + audio_channel *chan = &audio->channel[channum]; + if (!chan->dmaenabled && ((CUSTOM_REG(REG_DMACON) >> channum) & 1)) + dma_reload(chan); + chan->dmaenabled = (CUSTOM_REG(REG_DMACON) >> channum) & 1; + } + + /* loop until done */ + while (length > 0) + { + int nextper, nextvol; + int ticks = length; + + /* determine the number of ticks we can do in this chunk */ + if (ticks > audio->channel[0].curticks) + ticks = audio->channel[0].curticks; + if (ticks > audio->channel[1].curticks) + ticks = audio->channel[1].curticks; + if (ticks > audio->channel[2].curticks) + ticks = audio->channel[2].curticks; + if (ticks > audio->channel[3].curticks) + ticks = audio->channel[3].curticks; + + /* loop over channels */ + nextper = nextvol = -1; + for (channum = 0; channum < 4; channum++) + { + int volume = (nextvol == -1) ? CUSTOM_REG(REG_AUD0VOL + channum * 8) : nextvol; + int period = (nextper == -1) ? CUSTOM_REG(REG_AUD0PER + channum * 8) : nextper; + audio_channel *chan = &audio->channel[channum]; + stream_sample_t sample; + int i; + + /* normalize the volume value */ + volume = (volume & 0x40) ? 64 : (volume & 0x3f); + volume *= 4; + + /* are we modulating the period of the next channel? */ + if ((CUSTOM_REG(REG_ADKCON) >> channum) & 0x10) + { + nextper = CUSTOM_REG(REG_AUD0DAT + channum * 8); + nextvol = -1; + sample = 0; + } + + /* are we modulating the volume of the next channel? */ + else if ((CUSTOM_REG(REG_ADKCON) >> channum) & 0x01) + { + nextper = -1; + nextvol = CUSTOM_REG(REG_AUD0DAT + channum * 8); + sample = 0; + } + + /* otherwise, we are generating data */ + else + { + nextper = nextvol = -1; + sample = chan->latched * volume; + } + + /* fill the buffer with the sample */ + for (i = 0; i < ticks; i += CLOCK_DIVIDER) + outputs[channum][(sampoffs + i) / CLOCK_DIVIDER] = sample; + + /* account for the ticks; if we hit 0, advance */ + chan->curticks -= ticks; + if (chan->curticks == 0) + { + /* reset the clock and ensure we're above the minimum ticks */ + chan->curticks = period; + if (chan->curticks < 124) + chan->curticks = 124; + + /* move forward one byte; if we move to an even byte, fetch new */ + if (chan->dmaenabled || chan->manualmode) + chan->curlocation++; + if (chan->dmaenabled && !(chan->curlocation & 1)) + { + CUSTOM_REG(REG_AUD0DAT + channum * 8) = amiga_chip_ram_r(chan->curlocation); + if (chan->curlength != 0) + chan->curlength--; + + /* if we run out of data, reload the dma */ + if (chan->curlength == 0) + dma_reload(chan); + } + + /* latch the next byte of the sample */ + if (!(chan->curlocation & 1)) + chan->latched = CUSTOM_REG(REG_AUD0DAT + channum * 8) >> 8; + else + chan->latched = CUSTOM_REG(REG_AUD0DAT + channum * 8) >> 0; + + /* if we're in manual mode, signal an interrupt once we latch the low byte */ + if (!chan->dmaenabled && chan->manualmode && (chan->curlocation & 1)) + { + signal_irq(Machine, channum); + chan->manualmode = FALSE; + } + } + } + + /* bump ourselves forward by the number of ticks */ + sampoffs += ticks; + length -= ticks; + } +} + + + +/************************************* + * + * Sound system startup + * + *************************************/ + +void *amiga_sh_start(int clock, const struct CustomSound_interface *config) +{ + int i; + + /* allocate a new audio state */ + audio_state = auto_malloc(sizeof(*audio_state)); + memset(audio_state, 0, sizeof(*audio_state)); + for (i = 0; i < 4; i++) + { + audio_state->channel[i].index = i; + audio_state->channel[i].irq_timer = timer_alloc(signal_irq); + } + + /* create the stream */ + audio_state->stream = stream_create(0, 4, clock / CLOCK_DIVIDER, audio_state, amiga_stream_update); + return audio_state; +} diff --git a/src/mame/audio/asteroid.c b/src/mame/audio/asteroid.c new file mode 100644 index 00000000000..1497e888d9e --- /dev/null +++ b/src/mame/audio/asteroid.c @@ -0,0 +1,323 @@ +/***************************************************************************** + * + * Asteroids Analog Sound system interface + * + *****************************************************************************/ + +#include <math.h> +#include "driver.h" +#include "sound/discrete.h" +#include "includes/asteroid.h" + +/************************************************************************/ +/* Asteroids Sound System Analog emulation by K.Wilkins Nov 2000 */ +/* Questions/Suggestions to mame@dysfunction.demon.co.uk */ +/************************************************************************/ + +static const discrete_lfsr_desc asteroid_lfsr = +{ + DISC_CLK_IS_FREQ, + 16, /* Bit Length */ + 0, /* Reset Value */ + 6, /* Use Bit 6 as XOR input 0 */ + 14, /* Use Bit 14 as XOR input 1 */ + DISC_LFSR_XNOR, /* Feedback stage1 is XNOR */ + DISC_LFSR_OR, /* Feedback stage2 is just stage 1 output OR with external feed */ + DISC_LFSR_REPLACE, /* Feedback stage3 replaces the shifted register contents */ + 0x000001, /* Everything is shifted into the first bit only */ + 0, /* Output is already inverted by XNOR */ + 16 /* Output bit is feedback bit */ +}; + +static const discrete_dac_r1_ladder asteroid_thump_dac1 = +{ + 4, // size of ladder + {RES_K(220), RES_K(100), RES_K(47), RES_K(22)}, //R44-R47 + 4.3, // 5v - diode junction + RES_K(6.8), // R49 + RES_K(47), // R44 + CAP_U(0.01) // C27 +}; + +static const discrete_555_cc_desc asteroid_thump_555cc = +{ + DISC_555_OUT_SQW | DISC_555_OUT_AC | DISCRETE_555_CC_TO_CAP, + 5, // B+ voltage of 555 + DEFAULT_555_VALUES, + 5, // B+ voltage of the Constant Current source + 0.8 // VBE 2N3906 (Si) +}; + +#define ASTEROID_SAUCER_SND_EN NODE_01 +#define ASTEROID_SAUCER_FIRE_EN NODE_02 +#define ASTEROID_SAUCER_SEL NODE_03 +#define ASTEROID_THRUST_EN NODE_04 +#define ASTEROID_SHIP_FIRE_EN NODE_05 +#define ASTEROID_LIFE_EN NODE_06 +#define ASTEROID_NOISE_RESET NODE_07 + +#define ASTEROID_THUMP_EN NODE_08 +#define ASTEROID_THUMP_DATA NODE_09 +#define ASTEROID_EXPLODE_DATA NODE_10 +#define ASTEROID_EXPLODE_PITCH NODE_11 + +#define ASTEROID_NOISE NODE_20 +#define ASTEROID_THUMP_SND NODE_21 +#define ASTEROID_SAUCER_SND NODE_22 +#define ASTEROID_LIFE_SND NODE_23 +#define ASTEROID_SAUCER_FIRE_SND NODE_24 +#define ASTEROID_SHIP_FIRE_SND NODE_25 +#define ASTEROID_EXPLODE_SND NODE_26 +#define ASTEROID_THRUST_SND NODE_27 + +DISCRETE_SOUND_START(asteroid) + /************************************************/ + /* Asteroid Effects Relataive Gain Table */ + /* */ + /* Effect V-ampIn Gain ratio Relative */ + /* Thump 5 1/47 131.6 */ + /* Saucer 2.4 1/39 76.1 */ + /* Life 3.8 1/47 100.0 */ + /* Saucer Fire 5-0.6 1/(100+10) 49.5 */ + /* Ship Fire 5-0.6 1/(100+2.7) 53.0 */ + /* Explode 3.8 1/4.7 1000.0 */ + /* Thrust 3.8 1/4.7 600.0 */ + /* NOTE: Thrust gain has to be tweaked, due to */ + /* the filter stage. */ + /************************************************/ + + /* NODE GAIN OFFSET INIT */ + DISCRETE_INPUT_LOGIC (ASTEROID_SAUCER_SND_EN) + DISCRETE_INPUT_LOGIC (ASTEROID_SAUCER_FIRE_EN) + DISCRETE_INPUT_LOGIC (ASTEROID_SAUCER_SEL) + DISCRETE_INPUT_LOGIC (ASTEROID_THRUST_EN) + DISCRETE_INPUT_LOGIC (ASTEROID_SHIP_FIRE_EN) + DISCRETE_INPUT_LOGIC (ASTEROID_LIFE_EN) + DISCRETE_INPUT_PULSE (ASTEROID_NOISE_RESET, 1) + + DISCRETE_INPUT_LOGIC (ASTEROID_THUMP_EN) + DISCRETE_INPUT_DATA (ASTEROID_THUMP_DATA) + + DISCRETE_INPUTX_DATA (ASTEROID_EXPLODE_DATA, 1000.0/15.0, 0.0, 0) + DISCRETE_INPUTX_DATA (ASTEROID_EXPLODE_PITCH, 1, 0, 12) + + /************************************************/ + /* Thump circuit is based on a VCO with the */ + /* VCO control fed from the 4 low order bits */ + /* from /THUMP bit 4 controls the osc enable. */ + /* A resistor ladder network is used to convert */ + /* the 4 bit value to an analog value. */ + /* */ + /* The VCO is implemented with a 555 timer and */ + /* an RC filter to perform smoothing on the */ + /* output */ + /************************************************/ + DISCRETE_DAC_R1(NODE_30, 1, ASTEROID_THUMP_DATA, 3.5, &asteroid_thump_dac1) // CMOS + DISCRETE_555_CC(NODE_31, ASTEROID_THUMP_EN, NODE_30, RES_K(22), CAP_U(0.22), 0, 0, RES_K(18), &asteroid_thump_555cc) + DISCRETE_RCFILTER(NODE_32, 1, NODE_31, RES_K(3.3), CAP_U(0.1)) + DISCRETE_GAIN(ASTEROID_THUMP_SND, NODE_32, 30) + + /************************************************/ + /* The SAUCER sound is based on two VCOs, a */ + /* slow VCO feed the input to a higher freq VCO */ + /* with the SAUCERSEL switch being used to move */ + /* the frequency ranges of both VCOs */ + /* */ + /* The slow VCO is implemented with a 555 timer */ + /* and a 566 is used for the higher VCO. */ + /* */ + /* The sound can be tweaked with the gain and */ + /* adder constants in the 2 lines below */ + /************************************************/ + // SAUCER_SEL = 1 - larger saucer + DISCRETE_MULTADD(NODE_40, 1, ASTEROID_SAUCER_SEL, -2.5, 8.25) // Saucer Warble rate (5.75 or 8.25Hz) + DISCRETE_TRIANGLEWAVE(NODE_41, 1, NODE_40, 920.0, 920.0/2, 0) // (amount of warble) + + DISCRETE_TRANSFORM4(NODE_42, 1, ASTEROID_SAUCER_SEL, -250, NODE_41, 750, "01*2+3+") // Large saucer is 250hz lower + + DISCRETE_TRIANGLEWAVE(NODE_43, ASTEROID_SAUCER_SND_EN, NODE_42, 76.1, 0, 0) + DISCRETE_RCFILTER(ASTEROID_SAUCER_SND, 1, NODE_43, 1, 1.0e-5) + + /************************************************/ + /* The Ship Fire sound is produced by a 555 */ + /* based VCO where the frequency rapidly decays */ + /* with time. */ + /************************************************/ + DISCRETE_RAMP(NODE_50, ASTEROID_SHIP_FIRE_EN, ASTEROID_SHIP_FIRE_EN, (820.0-110.0)/0.28, 820.0, 110.0, 0) /* Decay - Freq */ + DISCRETE_RCDISC(NODE_51, ASTEROID_SHIP_FIRE_EN, 53.0-7.0, 2700.0*3, 1e-5) /* Decay - Amplitude */ + DISCRETE_ADDER2(NODE_52, 1, NODE_51, 7.0) /* Amplitude */ + DISCRETE_TRANSFORM3(NODE_53, ASTEROID_SHIP_FIRE_EN, 4500, NODE_50, 67, "01/2+") /* Duty */ + DISCRETE_SQUAREWAVE(NODE_54, ASTEROID_SHIP_FIRE_EN, NODE_50, NODE_52, NODE_53, 0, 0) + DISCRETE_RCFILTER(ASTEROID_SHIP_FIRE_SND, 1, NODE_54, 1, 1.0e-5) + + /************************************************/ + /* The Saucer Fire sound is produced by a 555 */ + /* based VCO where the frequency rapidly decays */ + /* with time. */ + /************************************************/ + DISCRETE_RAMP(NODE_60, ASTEROID_SAUCER_FIRE_EN, ASTEROID_SAUCER_FIRE_EN, (830.0-630.0)/0.28, 830.0, 630.0, 0) /* Decay - Freq */ + DISCRETE_RCDISC(NODE_61, ASTEROID_SAUCER_FIRE_EN, 49.5-7.0, 10000.0*3, 1e-5) /* Decay - Amplitude */ + DISCRETE_ADDER2(NODE_62, 1, NODE_61, 7.0) /* Amplitude */ + DISCRETE_TRANSFORM3(NODE_63, ASTEROID_SAUCER_FIRE_EN, 4500, NODE_60, 67, "01/2+") /* Duty */ + DISCRETE_SQUAREWAVE(NODE_64, ASTEROID_SAUCER_FIRE_EN, NODE_60, NODE_62, NODE_63, 0, 0) + DISCRETE_RCFILTER(ASTEROID_SAUCER_FIRE_SND, 1, NODE_64, 2, 1.0e-5) + + /************************************************/ + /* Thrust noise is a gated noise source */ + /* fed into a filter network */ + /* It is an RC lowpass, followed by a */ + /* Sallen-Key bandpass, followed by an active */ + /* lowpass. */ + /************************************************/ + DISCRETE_LFSR_NOISE(ASTEROID_NOISE, ASTEROID_NOISE_RESET, ASTEROID_NOISE_RESET, 12000.0, 1.0, 0, 0, &asteroid_lfsr) + + DISCRETE_GAIN(NODE_70, ASTEROID_NOISE, 600.0*7.6) + DISCRETE_RCFILTER(NODE_71, ASTEROID_THRUST_EN, NODE_70, 2200, 1e-6) + /* TBD - replace this line with a Sallen-Key Bandpass macro */ + DISCRETE_FILTER2(NODE_72, 1, NODE_71, 89.5, (1.0 / 7.6), DISC_FILTER_BANDPASS) + /* TBD - replace this line with a Active Lowpass macro */ + DISCRETE_FILTER1(ASTEROID_THRUST_SND, 1, NODE_72, 160, DISC_FILTER_LOWPASS) + + /************************************************/ + /* Explosion generation circuit, pitch and vol */ + /* are variable. */ + /* The pitch divides using an overflow counter. */ + /* Meaning the duty cycle varies. The on time */ + /* is always the same (one 12Khz cycle). But */ + /* the off time varies. /12 = 11 off cycles */ + /* Then it is ANDed with the 12kHz to make a */ + /* shorter pulse. There is no real reason to */ + /* do this, as the D-Latch already triggers on */ + /* the rising edge. So we won't add the extra */ + /* nodes. */ + /************************************************/ + DISCRETE_DIVIDE(NODE_80, 1, 12000, ASTEROID_EXPLODE_PITCH) /* Frequency */ + DISCRETE_DIVIDE(NODE_81, 1, 100, ASTEROID_EXPLODE_PITCH) /* Duty */ + DISCRETE_SQUAREWFIX(NODE_82, 1, NODE_80, 1.0, NODE_81, 1.0/2, 0) /* Pitch clock */ + DISCRETE_SAMPLHOLD(NODE_83, 1, ASTEROID_NOISE, NODE_82, DISC_SAMPHOLD_REDGE) + DISCRETE_MULTIPLY(NODE_84, 1, NODE_83, ASTEROID_EXPLODE_DATA) + DISCRETE_RCFILTER(ASTEROID_EXPLODE_SND, 1, NODE_84, 3042, 1e-6) + + /************************************************/ + /* Life enable is just 3KHz tone from the clock */ + /* generation cct according to schematics */ + /************************************************/ + DISCRETE_SQUAREWFIX(ASTEROID_LIFE_SND, ASTEROID_LIFE_EN, 3000, 100.0, 50.0, 0, 0) + + /************************************************/ + /* Combine all 7 sound sources with a double */ + /* adder circuit */ + /************************************************/ + DISCRETE_ADDER4(NODE_90, 1, ASTEROID_THUMP_SND, ASTEROID_SAUCER_SND, ASTEROID_SHIP_FIRE_SND, ASTEROID_SAUCER_FIRE_SND) + DISCRETE_ADDER4(NODE_91, 1, ASTEROID_THRUST_SND, ASTEROID_EXPLODE_SND, ASTEROID_LIFE_SND, NODE_90) + + DISCRETE_OUTPUT(NODE_91, 65534.0 / (131.6+76.1+49.5+53.0+1000.0+600.0)) // Take the output from the mixer +DISCRETE_SOUND_END + + +DISCRETE_SOUND_START(astdelux) + /************************************************/ + /* Asteroid delux sound hardware is mostly done */ + /* in the Pokey chip except for the thrust and */ + /* explosion sounds that are a direct lift of */ + /* the asteroids hardware hence is a clone of */ + /* the circuit above apart from gain scaling. */ + /* */ + /* Note that the thrust enable signal is invert */ + /************************************************/ + /* NODE GAIN OFFSET INIT */ + DISCRETE_INPUT_LOGIC (ASTEROID_THRUST_EN) + DISCRETE_INPUT_PULSE (ASTEROID_NOISE_RESET, 1) + + DISCRETE_INPUTX_DATA (ASTEROID_EXPLODE_DATA, 1000.0/15.0, 0.0, 0) + DISCRETE_INPUTX_DATA (ASTEROID_EXPLODE_PITCH, 1, 0, 12) + + /************************************************/ + /* Thrust noise is a gated noise source */ + /* fed into a filter network */ + /* It is an RC lowpass, followed by a */ + /* Sallen-Key bandpass, followed by an active */ + /* lowpass. */ + /************************************************/ + DISCRETE_LFSR_NOISE(ASTEROID_NOISE, ASTEROID_NOISE_RESET, ASTEROID_NOISE_RESET, 12000.0, 1.0, 0, 0, &asteroid_lfsr) + + DISCRETE_GAIN(NODE_70, ASTEROID_NOISE, 1000.0*7.6) + DISCRETE_RCFILTER(NODE_71, ASTEROID_THRUST_EN, NODE_70, 2200, 1e-6) + /* TBD - replace this line with a Sallen-Key Bandpass macro */ + DISCRETE_FILTER2(NODE_72, 1, NODE_71, 89.5, (1.0 / 7.6), DISC_FILTER_BANDPASS) + /* TBD - replace this line with a Active Lowpass macro */ + DISCRETE_FILTER1(ASTEROID_THRUST_SND, 1, NODE_72, 160, DISC_FILTER_LOWPASS) + + /************************************************/ + /* Explosion generation circuit, pitch and vol */ + /* are variable. */ + /* The pitch divides using an overflow counter. */ + /* Meaning the duty cycle varies. The on time */ + /* is always the same (one 12Khz cycle). But */ + /* the off time varies. /12 = 11 off cycles */ + /* Then it is ANDed with the 12kHz to make a */ + /* shorter pulse. There is no real reason to */ + /* do this, as the D-Latch already triggers on */ + /* the rising edge. So we won't add the extra */ + /* nodes. */ + /************************************************/ + DISCRETE_DIVIDE(NODE_80, 1, 12000, ASTEROID_EXPLODE_PITCH) /* Frequency */ + DISCRETE_DIVIDE(NODE_81, 1, 100, ASTEROID_EXPLODE_PITCH) /* Duty */ + DISCRETE_SQUAREWFIX(NODE_82, 1, NODE_80, 1.0, NODE_81, 1.0/2, 0) /* Pitch clock */ + DISCRETE_SAMPLHOLD(NODE_83, 1, ASTEROID_NOISE, NODE_82, DISC_SAMPHOLD_REDGE) + DISCRETE_MULTIPLY(NODE_84, 1, NODE_83, ASTEROID_EXPLODE_DATA) + DISCRETE_RCFILTER(ASTEROID_EXPLODE_SND, 1, NODE_84, 3042, 1e-6) + + /************************************************/ + /* Combine all 7 sound sources with a double */ + /* adder circuit */ + /************************************************/ + DISCRETE_ADDER2(NODE_90, 1, ASTEROID_THRUST_SND, ASTEROID_EXPLODE_SND) + + DISCRETE_OUTPUT(NODE_90, 65534.0/(1000+600)) // Take the output from the mixer +DISCRETE_SOUND_END + + +WRITE8_HANDLER( asteroid_explode_w ) +{ + discrete_sound_w(ASTEROID_EXPLODE_DATA,(data&0x3c)>>2); // Volume + /* We will modify the pitch data to send the divider value. */ + switch ((data&0xc0)) + { + case 0x00: + data = 12; + break; + case 0x40: + data = 6; + break; + case 0x80: + data = 3; + break; + case 0xc0: + data = 5; + break; + } + discrete_sound_w(ASTEROID_EXPLODE_PITCH, data); +} + +WRITE8_HANDLER( asteroid_thump_w ) +{ + discrete_sound_w(ASTEROID_THUMP_EN, data & 0x10); + discrete_sound_w(ASTEROID_THUMP_DATA, data & 0x0f); +} + +WRITE8_HANDLER( asteroid_sounds_w ) +{ + discrete_sound_w(ASTEROID_SAUCER_SND_EN + offset, data & 0x80); +} + +WRITE8_HANDLER( astdelux_sounds_w ) +{ + /* Only ever activates the thrusters in Astdelux */ + discrete_sound_w(ASTEROID_THRUST_EN, data & 0x80); +} + +WRITE8_HANDLER( asteroid_noise_reset_w ) +{ + discrete_sound_w(ASTEROID_NOISE_RESET, 0); +} diff --git a/src/mame/audio/astinvad.c b/src/mame/audio/astinvad.c new file mode 100644 index 00000000000..47d384d9710 --- /dev/null +++ b/src/mame/audio/astinvad.c @@ -0,0 +1,138 @@ +/*********************************** + updated: 1997-04-09 08:46 TT + updated 20-3-1998 LT Added colour changes on base explosion + updated 02-6-1998 HJB copied from 8080bw and removed unneeded code + * + * Author : Tormod Tjaberg + * Created : 1997-04-09 + * Description : Sound routines for the 'astinvad' games + * + * The samples were taken from Michael Strutt's (mstrutt@pixie.co.za) + * excellent space invader emulator and converted to signed samples so + * they would work under SEAL. The port info was also gleaned from + * his emulator. These sounds should also work on all the invader games. + * + */ + +#include "driver.h" +#include "sound/samples.h" +#include "includes/astinvad.h" + +static const char *astinvad_sample_names[] = +{ + "*invaders", + "0.wav", + "1.wav", + "2.wav", + "3.wav", + "4.wav", + "5.wav", + "6.wav", + "7.wav", + "8.wav", + 0 +}; + +/* sample sound IDs - must match sample file name table above */ +enum +{ + SND_UFO = 0, + SND_SHOT, + SND_BASEHIT, + SND_INVADERHIT, + SND_FLEET1, + SND_FLEET2, + SND_FLEET3, + SND_FLEET4, + SND_UFOHIT +}; + + +struct Samplesinterface astinvad_samples_interface = +{ + 6, /* channels */ + astinvad_sample_names +}; + + +WRITE8_HANDLER( astinvad_sound1_w ) +{ + static int state; + + int bitsGoneHi = data & ~state; + + sound_global_enable(data & 0x20); + + if (!(data & 1)) + { + sample_stop(0); + } + + if (bitsGoneHi & 0x01) sample_start(0, SND_UFO, 1); + if (bitsGoneHi & 0x02) sample_start(1, SND_SHOT, 0); + if (bitsGoneHi & 0x04) sample_start(2, SND_BASEHIT, 0); + if (bitsGoneHi & 0x08) sample_start(3, SND_INVADERHIT, 0); + + astinvad_set_screen_red(data & 0x04); + + state = data; +} + + +WRITE8_HANDLER( astinvad_sound2_w ) +{ + static int state; + + int bitsGoneHi = data & ~state; + + if (bitsGoneHi & 0x01) sample_start(5, SND_FLEET1, 0); + if (bitsGoneHi & 0x02) sample_start(5, SND_FLEET2, 0); + if (bitsGoneHi & 0x04) sample_start(5, SND_FLEET3, 0); + if (bitsGoneHi & 0x08) sample_start(5, SND_FLEET4, 0); + if (bitsGoneHi & 0x10) sample_start(4, SND_UFOHIT, 0); + + flip_screen_set(readinputport(3) & data & 0x20); + + state = data; +} + + +WRITE8_HANDLER( spaceint_sound1_w ) +{ + static int state; + + int bitsGoneHi = data & ~state; + + if (!(data & 0x08)) + { + sample_stop(0); + } + + if (bitsGoneHi & 0x01) sample_start(1, SND_SHOT, 0); + if (bitsGoneHi & 0x02) sample_start(2, SND_BASEHIT, 0); + if (bitsGoneHi & 0x04) sample_start(4, SND_UFOHIT, 0); + if (bitsGoneHi & 0x08) sample_start(0, SND_UFO, 1); + + if (bitsGoneHi & 0x10) sample_start(5, SND_FLEET1, 0); + if (bitsGoneHi & 0x20) sample_start(5, SND_FLEET2, 0); + if (bitsGoneHi & 0x40) sample_start(5, SND_FLEET3, 0); + if (bitsGoneHi & 0x80) sample_start(5, SND_FLEET4, 0); + + state = data; +} + + +WRITE8_HANDLER( spaceint_sound2_w ) +{ + static int state; + + int bitsGoneHi = data & ~state; + + sound_global_enable(data & 0x02); + + if (bitsGoneHi & 0x04) sample_start(3, SND_INVADERHIT, 0); + + flip_screen_set(readinputport(3) & data & 0x80); + + state = data; +} diff --git a/src/mame/audio/astrof.c b/src/mame/audio/astrof.c new file mode 100644 index 00000000000..6e480a2d8a9 --- /dev/null +++ b/src/mame/audio/astrof.c @@ -0,0 +1,255 @@ +/*************************************************************************** + + Astro Fighter hardware + +****************************************************************************/ + +#include "driver.h" +#include "sound/samples.h" +#include "sound/sn76477.h" +#include "includes/astrof.h" + + + +/************************************* + * + * Globals + * + *************************************/ + +static UINT8 port_1_last; +static UINT8 port_2_last; +static UINT8 astrof_start_explosion; +static UINT8 astrof_death_playing; +static UINT8 astrof_bosskill_playing; + + + +/************************************* + * + * Machine setup + * + *************************************/ + + +MACHINE_START( astrof_audio ) +{ + /* setup for save states */ + state_save_register_global(port_1_last); + state_save_register_global(port_2_last); + state_save_register_global(astrof_start_explosion); + state_save_register_global(astrof_death_playing); + state_save_register_global(astrof_bosskill_playing); +} + + + +/************************************* + * + * Astro Fighter + * + *************************************/ + +#define SAMPLE_FIRE 0 +#define SAMPLE_EKILLED 1 +#define SAMPLE_WAVE 2 +#define SAMPLE_BOSSFIRE 6 +#define SAMPLE_FUEL 7 +#define SAMPLE_DEATH 8 +#define SAMPLE_BOSSHIT 9 +#define SAMPLE_BOSSKILL 10 + +#define CHANNEL_FIRE 0 +#define CHANNEL_EXPLOSION 1 +#define CHANNEL_WAVE 2 /* background humm */ +#define CHANNEL_BOSSFIRE 2 /* there is no background humm on the boss level */ +#define CHANNEL_FUEL 3 + + +WRITE8_HANDLER( astrof_audio_1_w ) +{ + UINT8 rising_bits = data & ~port_1_last; + + if (astrof_death_playing) + astrof_death_playing = sample_playing(CHANNEL_EXPLOSION); + + if (astrof_bosskill_playing) + astrof_bosskill_playing = sample_playing(CHANNEL_EXPLOSION); + + /* D2 - explosion */ + if (rising_bits & 0x04) + { + /* I *know* that the effect select port will be written shortly + after this one, so this works */ + astrof_start_explosion = 1; + } + + /* D0,D1,D3 - background noise */ + if ((data & 0x08) && (~port_1_last & 0x08)) + { + int sample = SAMPLE_WAVE + (data & 3); + sample_start(CHANNEL_WAVE, sample, 1); + } + + if ((~data & 0x08) && (port_1_last & 0x08)) + sample_stop(CHANNEL_WAVE); + + /* D4 - boss laser */ + if ((rising_bits & 0x10) && !astrof_bosskill_playing) + sample_start(CHANNEL_BOSSFIRE, SAMPLE_BOSSFIRE, 0); + + /* D5 - fire */ + if ((rising_bits & 0x20) && !astrof_bosskill_playing) + sample_start(CHANNEL_FIRE, SAMPLE_FIRE, 0); + + /* D6 - don't know. Probably something to do with the explosion sounds */ + + /* D7 - sound enable bit */ + sound_global_enable(data & 0x80); + + port_1_last = data; +} + + +WRITE8_HANDLER( astrof_audio_2_w ) +{ + UINT8 rising_bits = data & ~port_2_last; + + /* D0-D2 - explosion select (triggered by D2 of the other port */ + if (astrof_start_explosion) + { + /* this is really a compound effect, made up of I believe 3 sound + effects, but since our sample contains them all, disable playing + the other effects while the explosion is playing */ +logerror("Explosion: %x\n", data); + if (data & 0x04) + { + if (!astrof_bosskill_playing) + { + sample_start(CHANNEL_EXPLOSION, SAMPLE_BOSSKILL, 0); + + astrof_bosskill_playing = 1; + } + } + else if (data & 0x02) + sample_start(CHANNEL_EXPLOSION, SAMPLE_BOSSHIT, 0); + else if (data & 0x01) + sample_start(CHANNEL_EXPLOSION, SAMPLE_EKILLED, 0); + else + { + if (!astrof_death_playing) + { + sample_start(CHANNEL_EXPLOSION, SAMPLE_DEATH, 0); + + astrof_death_playing = 1; + } + } + + astrof_start_explosion = 0; + } + + /* D3 - low fuel warning */ + if (rising_bits & 0x08) + sample_start(CHANNEL_FUEL, SAMPLE_FUEL, 0); + + port_2_last = data; +} + + +static const char *astrof_sample_names[] = +{ + "*astrof", + "fire.wav", + "ekilled.wav", + "wave1.wav", + "wave2.wav", + "wave3.wav", + "wave4.wav", + "bossfire.wav", + "fuel.wav", + "death.wav", + "bosshit.wav", + "bosskill.wav", + 0 +}; + + +static struct Samplesinterface astrof_samples_interface = +{ + 4, /* 4 channels */ + astrof_sample_names +}; + + + +MACHINE_DRIVER_START( astrof_audio ) + MDRV_SPEAKER_STANDARD_MONO("mono") + MDRV_SOUND_ADD_TAG("samples", SAMPLES, 0) + MDRV_SOUND_CONFIG(astrof_samples_interface) + MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) +MACHINE_DRIVER_END + + + +/************************************* + * + * Tomahawk + * + *************************************/ + +WRITE8_HANDLER( tomahawk_audio_w ) +{ + /* D0 - sonar */ + + /* D1 - UFO explosion */ + + /* D2 - morse */ + + /* D3 - missile */ + + /* D4 - UFO */ + + /* D5 - UFO under water */ + SN76477_enable_w(0, (~data >> 5) & 0x01); + + /* D6 - explosion */ + + /* D7 - sound enable bit */ + sound_global_enable(data & 0x80); +} + + +static struct SN76477interface tomahawk_sn76477_interface = +{ + 0, /* 4 noise_res (N/C) */ + 0, /* 5 filter_res (N/C) */ + 0, /* 6 filter_cap (N/C) */ + 0, /* 7 decay_res (N/C) */ + 0, /* 8 attack_decay_cap (N/C) */ + 0, /* 10 attack_res (N/C) */ + RES_K(47), /* 11 amplitude_res */ + RES_K(47), /* 12 feedback_res */ + 0, /* 16 vco_voltage (N/C) */ + CAP_U(0.033), /* 17 vco_cap */ + RES_K(33), /* 18 vco_res */ + 5.0, /* 19 pitch_voltage */ + RES_K(47), /* 20 slf_res */ + CAP_U(2.2), /* 21 slf_cap */ + 0, /* 23 oneshot_cap (N/C) */ + 0, /* 24 oneshot_res (N/C) */ + 1, /* 22 vco */ + 0, /* 26 mixer A */ + 0, /* 25 mixer B */ + 0, /* 27 mixer C */ + 0, /* 1 envelope 1 */ + 0, /* 28 envelope 2 */ + 1 /* 9 enable (variable) */ +}; + + +MACHINE_DRIVER_START( tomahawk_audio ) + MDRV_SPEAKER_STANDARD_MONO("mono") + MDRV_SOUND_ADD(SN76477, 0) + MDRV_SOUND_CONFIG(tomahawk_sn76477_interface) + MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) +MACHINE_DRIVER_END diff --git a/src/mame/audio/atarifb.c b/src/mame/audio/atarifb.c new file mode 100644 index 00000000000..56f7e02dc16 --- /dev/null +++ b/src/mame/audio/atarifb.c @@ -0,0 +1,208 @@ +/************************************************************************* + + audio\atarifb.c + +*************************************************************************/ + +#include "driver.h" +#include "atarifb.h" +#include "sound/discrete.h" + + +/************************************************************************/ +/* atarifb Sound System Analog emulation */ +/* */ +/* Complete re-write Dec 2004, D. Renaud */ +/************************************************************************/ + +static const discrete_555_desc atarifbWhistl555 = +{ + DISC_555_OUT_CAP | DISC_555_OUT_DC, + 5, // B+ voltage of 555 + DEFAULT_555_VALUES +}; + +static const discrete_lfsr_desc atarifb_lfsr = +{ + DISC_CLK_IS_FREQ, + 16, /* Bit Length */ + 0, /* Reset Value */ + 0, /* Use Bit 0 as XOR input 0 */ + 14, /* Use Bit 14 as XOR input 1 */ + DISC_LFSR_XNOR, /* Feedback stage1 is XNOR */ + DISC_LFSR_OR, /* Feedback stage2 is just stage 1 output OR with external feed */ + DISC_LFSR_REPLACE, /* Feedback stage3 replaces the shifted register contents */ + 0x000001, /* Everything is shifted into the first bit only */ + 0, /* Output is already inverted by XNOR */ + 16 /* Output bit is feedback bit */ +}; + +static const discrete_dac_r1_ladder atarifb_crowd_r1_ladder = +{ + 4, + {RES_K(390), RES_K(220), RES_K(100), RES_K(56)}, // r17, r16, r14, r15 + 0, 0, // no bias + 0, // no rGnd + CAP_U(0.1) // c32 +}; + +static const discrete_op_amp_filt_info atarifb_crowd_filt = +{ + 1.0/(1.0/RES_K(390) + 1.0/RES_K(220) + 1.0/RES_K(100) + 1.0/RES_K(56)), // r17, r16, r14, r15 + 0, 0, 0, + RES_K(330), // r35 + CAP_U(.01), // c33 + CAP_U(.01), // c44 + 0, + 5, 12, 0 +}; + +static const discrete_mixer_desc atarifb_mixer = +{ + DISC_MIXER_IS_OP_AMP, + {RES_K(47), RES_K(47), RES_K(220)}, // r71, r70, r73 + {0}, // no rNodes + {CAP_U(.01), CAP_U(.01), CAP_U(.01)}, // c53, c52, c51 + 0, + RES_K(47), // r74 + CAP_U(.001), // c54 + CAP_U(0.1), // c57 + 5, + 40000 +}; + +/* Nodes - Sounds */ +#define ATARIFB_NOISE NODE_10 +#define ATARIFB_HIT_SND ATARIFB_HIT_EN +#define ATARIFB_WHISTLE_SND NODE_12 +#define ATARIFB_CROWD_SND NODE_13 + +DISCRETE_SOUND_START(atarifb) + /************************************************/ + /* Input register mapping for atarifb */ + /************************************************/ + /* NODE GAIN OFFSET INIT */ + DISCRETE_INPUT_LOGIC (ATARIFB_WHISTLE_EN) + DISCRETE_INPUT_DATA (ATARIFB_CROWD_DATA) + /* Hit is a trigger fed directly to the amp */ + DISCRETE_INPUTX_LOGIC(ATARIFB_HIT_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0.0) + DISCRETE_INPUT_NOT (ATARIFB_ATTRACT_EN) + DISCRETE_INPUT_LOGIC (ATARIFB_NOISE_EN) + + /************************************************/ + /* Crowd effect is variable amplitude, filtered */ + /* random noise. */ + /* LFSR clk = 256H = 15750.0Hz */ + /************************************************/ + DISCRETE_LFSR_NOISE(NODE_20, ATARIFB_NOISE_EN, ATARIFB_NOISE_EN, 15750.0, 1, 0, .5, &atarifb_lfsr) + DISCRETE_SWITCH(NODE_21, 1, NODE_20, 0, ATARIFB_CROWD_DATA) // enable data, gate D8 + DISCRETE_DAC_R1(NODE_22, 1, NODE_21, DEFAULT_TTL_V_LOGIC_1, &atarifb_crowd_r1_ladder) + DISCRETE_OP_AMP_FILTER(ATARIFB_CROWD_SND, 1, NODE_22, 0, DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &atarifb_crowd_filt) + + /************************************************/ + /* Whistle effect is a triggered 555 cap charge */ + /* Q10 is a buffer to make sure there is no */ + /* load on the cap. It shifts the voltage by */ + /* -0.5V */ + /************************************************/ + DISCRETE_555_ASTABLE(NODE_30, ATARIFB_WHISTLE_EN, + RES_K(2.2), RES_K(2.2), CAP_U(0.1), // r34, r33, c44 + &atarifbWhistl555) + DISCRETE_TRANSFORM3(ATARIFB_WHISTLE_SND, 1, NODE_30, .5, 0, "01-P2>*") // Q10 drop + + /************************************************/ + /* Mixing stage - A9 */ + /* We will diliberately drive the amp into */ + /* clipping. */ + /* This is what the original game did |