summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/mame/audio/asteroid.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/mame/audio/asteroid.c')
-rw-r--r--trunk/src/mame/audio/asteroid.c323
1 files changed, 323 insertions, 0 deletions
diff --git a/trunk/src/mame/audio/asteroid.c b/trunk/src/mame/audio/asteroid.c
new file mode 100644
index 00000000000..5927d192052
--- /dev/null
+++ b/trunk/src/mame/audio/asteroid.c
@@ -0,0 +1,323 @@
+/*****************************************************************************
+ *
+ * Asteroids Analog Sound system interface
+ *
+ *****************************************************************************/
+
+#include "emu.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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, NODE_70, 2200, 1e-6)
+ DISCRETE_MULTIPLY(NODE_72, NODE_71, ASTEROID_THRUST_EN)
+ /* TBD - replace this line with a Sallen-Key Bandpass macro */
+ DISCRETE_FILTER2(NODE_73, 1, NODE_72, 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_73, 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, ASTEROID_NOISE, NODE_82, DISC_SAMPHOLD_REDGE)
+ DISCRETE_MULTIPLY(NODE_84, NODE_83, ASTEROID_EXPLODE_DATA)
+ DISCRETE_RCFILTER(ASTEROID_EXPLODE_SND, 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, NODE_70, 2200, 1e-6)
+ DISCRETE_MULTIPLY(NODE_72, NODE_71, ASTEROID_THRUST_EN)
+ /* TBD - replace this line with a Sallen-Key Bandpass macro */
+ DISCRETE_FILTER2(NODE_73, 1, NODE_72, 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_73, 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, ASTEROID_NOISE, NODE_82, DISC_SAMPHOLD_REDGE)
+ DISCRETE_MULTIPLY(NODE_84, NODE_83, ASTEROID_EXPLODE_DATA)
+ DISCRETE_RCFILTER(ASTEROID_EXPLODE_SND, 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_DEVICE_HANDLER( asteroid_explode_w )
+{
+ discrete_sound_w(device,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(device,ASTEROID_EXPLODE_PITCH, data);
+}
+
+WRITE8_DEVICE_HANDLER( asteroid_thump_w )
+{
+ discrete_sound_w(device, ASTEROID_THUMP_EN, data & 0x10);
+ discrete_sound_w(device, ASTEROID_THUMP_DATA, data & 0x0f);
+}
+
+WRITE8_DEVICE_HANDLER( asteroid_sounds_w )
+{
+ discrete_sound_w(device, NODE_RELATIVE(ASTEROID_SAUCER_SND_EN, offset), data & 0x80);
+}
+
+WRITE8_DEVICE_HANDLER( astdelux_sounds_w )
+{
+ /* Only ever activates the thrusters in Astdelux */
+ discrete_sound_w(device, ASTEROID_THRUST_EN, data & 0x80);
+}
+
+WRITE8_DEVICE_HANDLER( asteroid_noise_reset_w )
+{
+ discrete_sound_w(device, ASTEROID_NOISE_RESET, 0);
+}