summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/mame/audio/tx1.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/mame/audio/tx1.c')
-rw-r--r--trunk/src/mame/audio/tx1.c612
1 files changed, 612 insertions, 0 deletions
diff --git a/trunk/src/mame/audio/tx1.c b/trunk/src/mame/audio/tx1.c
new file mode 100644
index 00000000000..37091a02503
--- /dev/null
+++ b/trunk/src/mame/audio/tx1.c
@@ -0,0 +1,612 @@
+/***************************************************************************
+
+ Tatsumi TX-1/Buggy Boy sound hardware
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sound/ay8910.h"
+#include "video/resnet.h"
+#include "includes/tx1.h"
+
+
+
+/*************************************
+ *
+ * 8253 Programmable Interval Timer
+ *
+ *************************************/
+struct _pit8253_state
+{
+ union
+ {
+#ifdef LSB_FIRST
+ struct { UINT8 LSB; UINT8 MSB; };
+#else
+ struct { UINT8 MSB; UINT8 LSB; };
+#endif
+ UINT16 val;
+ } counts[3];
+
+ int idx[3];
+};
+
+typedef struct _tx1_sound_state tx1_sound_state;
+struct _tx1_sound_state
+{
+ sound_stream *m_stream;
+ UINT32 m_freq_to_step;
+ UINT32 m_step0;
+ UINT32 m_step1;
+ UINT32 m_step2;
+
+ struct _pit8253_state m_pit8253;
+
+ UINT8 m_ay_outputa;
+ UINT8 m_ay_outputb;
+
+ stream_sample_t m_pit0;
+ stream_sample_t m_pit1;
+ stream_sample_t m_pit2;
+
+ double m_weights0[4];
+ double m_weights1[3];
+ double m_weights2[3];
+ int m_eng0[4];
+ int m_eng1[4];
+ int m_eng2[4];
+
+ int m_noise_lfsra;
+ int m_noise_lfsrb;
+ int m_noise_lfsrc;
+ int m_noise_lfsrd;
+ int m_noise_counter;
+ UINT8 m_ym1_outputa;
+ UINT8 m_ym2_outputa;
+ UINT8 m_ym2_outputb;
+ UINT16 m_eng_voltages[16];
+};
+
+INLINE tx1_sound_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == TX1 || device->type() == BUGGYBOY);
+
+ return (tx1_sound_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+WRITE8_DEVICE_HANDLER( tx1_pit8253_w )
+{
+ tx1_sound_state *state = get_safe_token(device);
+ state->m_stream->update();
+
+ if (offset < 3)
+ {
+ if (state->m_pit8253.idx[offset] == 0)
+ {
+ state->m_pit8253.counts[offset].LSB = data;
+ state->m_pit8253.idx[offset] = 1;
+ }
+ else
+ {
+ state->m_pit8253.counts[offset].MSB = data;
+ state->m_pit8253.idx[offset] = 0;
+ }
+ }
+ else
+ {
+ int mode = (data >> 1) & 7;
+
+ if (mode == 3)
+ {
+ int cntsel = (data >> 6) & 3;
+ state->m_pit8253.idx[cntsel] = 0;
+ state->m_pit8253.counts[cntsel].val = 0;
+ }
+ else
+ mame_printf_debug("PIT8253: Unsupported mode %d.\n", mode);
+ }
+}
+
+READ8_DEVICE_HANDLER( tx1_pit8253_r )
+{
+ mame_printf_debug("PIT R: %x", offset);
+ return 0;
+}
+
+/*************************************
+ *
+ * TX-1
+ *
+ *************************************/
+
+/* RC oscillator: 1785Hz */
+#define TX1_NOISE_CLOCK (1/(1000.0e-12 * 560000.0))
+#define TX1_PIT_CLOCK (TX1_PIXEL_CLOCK / 16)
+#define TX1_FRAC 30
+
+#define TX1_SHUNT (250.0)
+#define TX1_R0 (180000.0 + TX1_SHUNT)
+#define TX1_R1 (56000.0 + TX1_SHUNT)
+#define TX1_R2 (22000.0 + TX1_SHUNT)
+#define TX1_R (100000.0 + TX1_SHUNT)
+#define TX1_RI (180000.0)
+
+static const double tx1_engine_gains[16] =
+{
+ -( TX1_R )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_R0) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_R1) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_R1 + 1.0/TX1_R0) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_R2) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_R2 + 1.0/TX1_R0) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_R2 + 1.0/TX1_R1) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_R2 + 1.0/TX1_R1 + 1.0/TX1_R0) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_SHUNT ) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_SHUNT + 1.0/TX1_R0) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_SHUNT + 1.0/TX1_R1) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_SHUNT + 1.0/TX1_R1 + 1.0/TX1_R0) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_SHUNT + 1.0/TX1_R2) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_SHUNT + 1.0/TX1_R2 + 1.0/TX1_R0) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_SHUNT + 1.0/TX1_R2 + 1.0/TX1_R1) )/TX1_RI,
+ -( 1.0/(1.0/TX1_R + 1.0/TX1_SHUNT + 1.0/TX1_R2 + 1.0/TX1_R1 + 1.0/TX1_R0) )/TX1_RI
+};
+
+/***************************************************************************
+
+ AY-8910 port mappings:
+
+ Port A Port B
+ ======= ======
+
+ 0: Engine 0 gain #0 0: Engine 0 gain #8
+ 1: Engine 0 gain #1 1: Engine 0 gain #9
+ 2: Engine 0 gain #2 2: Engine 0 gain #10
+ 3: Engine 0 gain #3 3: Engine 0 gain #11
+ 4: Engine 0 gain #4 4: /Enable AY on speaker CR
+ 5: Engine 0 gain #5 5: /Enable Engines 1/2 on speakers LR/RR/CF
+ 6: Engine 0 gain #6 6: /Skid 0 enable
+ 7: Engine 0 gain #7 7: /Skid 1 enable
+
+***************************************************************************/
+
+WRITE8_DEVICE_HANDLER( tx1_ay8910_a_w )
+{
+ tx1_sound_state *state = get_safe_token(device);
+ state->m_stream->update();
+
+ /* All outputs inverted */
+ state->m_ay_outputa = ~data;
+}
+
+WRITE8_DEVICE_HANDLER( tx1_ay8910_b_w )
+{
+ tx1_sound_state *state = get_safe_token(device);
+ double gain;
+
+ state->m_stream->update();
+ /* Only B3-0 are inverted */
+ state->m_ay_outputb = data ^ 0xf;
+
+ /* It'll do until we get quadrophonic speaker support! */
+ gain = BIT(state->m_ay_outputb, 4) ? 1.5 : 2.0;
+ device_sound_interface *sound;
+ device->interface(sound);
+ sound->set_output_gain(0, gain);
+ sound->set_output_gain(1, gain);
+ sound->set_output_gain(2, gain);
+}
+
+/***************************************************************************
+
+ Engine sounds are produced by three of these 4013B chains:
+
+ +------------------
+ | +---------+
+ +-----+ | | +-----+ |
+ +-|D 1 Q|-+ +-|D 2 Q|-|-----
+ | |C /Q|-o----|C /Q|-+
+ | +-----+ | +-----+
+ +---------+
+
+ +----------+
+ | +-----+ | +-----+
+ | |C 3 Q|-+ |C 4 Q|-------
+ !&--|D /Q|------|D /Q|-+
+ | +-----+ +-----+ |
+ +-----------------------+
+
+ Common clocks omitted for clarity (all driven from an 8253 output pin).
+
+ Player: ES0, ES1, ES2
+ Opponent 2: ES2
+
+ ***************************************************************************/
+
+INLINE void update_engine(int eng[4])
+{
+ int p0 = eng[0];
+ int p1 = eng[1];
+ int p2 = eng[2];
+ int p3 = eng[3];
+
+ eng[0] = !p0;
+ if (p0 && !eng[0]) eng[1] = !p1;
+ eng[2] = !(p2 && !p3);
+ eng[3] = !p2;
+}
+
+
+static STREAM_UPDATE( tx1_stream_update )
+{
+ tx1_sound_state *state = get_safe_token(device);
+ UINT32 step_0, step_1, step_2;
+ double /*gain_0, gain_1,*/ gain_2, gain_3;
+
+ stream_sample_t *fl = &outputs[0][0];
+ stream_sample_t *fr = &outputs[1][0];
+
+ /* Clear the buffers */
+ memset(outputs[0], 0, samples * sizeof(*outputs[0]));
+ memset(outputs[1], 0, samples * sizeof(*outputs[1]));
+
+ /* 8253 outputs for the player/opponent engine sounds. */
+ step_0 = state->m_pit8253.counts[0].val ? (TX1_PIT_CLOCK / state->m_pit8253.counts[0].val) * state->m_freq_to_step : 0;
+ step_1 = state->m_pit8253.counts[1].val ? (TX1_PIT_CLOCK / state->m_pit8253.counts[1].val) * state->m_freq_to_step : 0;
+ step_2 = state->m_pit8253.counts[2].val ? (TX1_PIT_CLOCK / state->m_pit8253.counts[2].val) * state->m_freq_to_step : 0;
+
+ //gain_0 = tx1_engine_gains[state->m_ay_outputa & 0xf];
+ //gain_1 = tx1_engine_gains[state->m_ay_outputa >> 4];
+ gain_2 = tx1_engine_gains[state->m_ay_outputb & 0xf];
+ gain_3 = BIT(state->m_ay_outputb, 5) ? 1.0f : 1.5f;
+
+ while (samples--)
+ {
+ if (state->m_step0 & ((1 << TX1_FRAC)))
+ {
+ update_engine(state->m_eng0);
+ state->m_pit0 = combine_4_weights(state->m_weights0, state->m_eng0[0], state->m_eng0[1], state->m_eng0[2], state->m_eng0[3]);
+ state->m_step0 &= ((1 << TX1_FRAC) - 1);
+ }
+
+ if (state->m_step1 & ((1 << TX1_FRAC)))
+ {
+ update_engine(state->m_eng1);
+ state->m_pit1 = combine_3_weights(state->m_weights1, state->m_eng1[0], state->m_eng1[1], state->m_eng1[3]);
+ state->m_step1 &= ((1 << TX1_FRAC) - 1);
+ }
+
+ if (state->m_step2 & ((1 << TX1_FRAC)))
+ {
+ update_engine(state->m_eng2);
+ state->m_pit2 = combine_3_weights(state->m_weights2, state->m_eng2[0], state->m_eng2[1], state->m_eng2[3]);
+ state->m_step2 &= ((1 << TX1_FRAC) - 1);
+ }
+
+ *fl++ = (state->m_pit0 + state->m_pit1)*gain_3 + 2*state->m_pit2*gain_2;
+ *fr++ = (state->m_pit0 + state->m_pit1)*gain_3 + 2*state->m_pit2*gain_2;
+
+ state->m_step0 += step_0;
+ state->m_step1 += step_1;
+ state->m_step2 += step_2;
+ }
+}
+
+
+static DEVICE_START( tx1_sound )
+{
+ tx1_sound_state *state = get_safe_token(device);
+ running_machine &machine = device->machine();
+ static const int r0[4] = { 390e3, 180e3, 180e3, 180e3 };
+ static const int r1[3] = { 180e3, 390e3, 56e3 };
+ static const int r2[3] = { 390e3, 390e3, 180e3 };
+
+
+ /* Allocate the stream */
+ state->m_stream = device->machine().sound().stream_alloc(*device, 0, 2, machine.sample_rate(), NULL, tx1_stream_update);
+ state->m_freq_to_step = (double)(1 << TX1_FRAC) / (double)machine.sample_rate();
+
+ /* Compute the engine resistor weights */
+ compute_resistor_weights(0, 10000, -1.0,
+ 4, &r0[0], state->m_weights0, 0, 0,
+ 3, &r1[0], state->m_weights1, 0, 0,
+ 3, &r2[0], state->m_weights2, 0, 0);
+}
+
+static DEVICE_RESET( tx1_sound )
+{
+ tx1_sound_state *state = get_safe_token(device);
+
+ state->m_step0 = state->m_step1 = state->m_step2 = 0;
+}
+
+DEVICE_GET_INFO( tx1_sound )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(tx1_sound_state); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(tx1_sound); break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(tx1_sound); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "TX-1 Custom"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ }
+}
+
+
+/*************************************
+ *
+ * Buggy Boy
+ *
+ *************************************/
+
+#define BUGGYBOY_PIT_CLOCK (BUGGYBOY_ZCLK / 8)
+#define BUGGYBOY_NOISE_CLOCK (BUGGYBOY_PIT_CLOCK / 4)
+
+#define BUGGYBOY_R1 47000.0
+#define BUGGYBOY_R2 22000.0
+#define BUGGYBOY_R3 10000.0
+#define BUGGYBOY_R4 5600.0
+#define BUGGYBOY_SHUNT 250.0
+
+#define BUGGYBOY_R1S (1.0/(1.0/BUGGYBOY_R1 + 1.0/BUGGYBOY_SHUNT))
+#define BUGGYBOY_R2S (1.0/(1.0/BUGGYBOY_R2 + 1.0/BUGGYBOY_SHUNT))
+#define BUGGYBOY_R3S (1.0/(1.0/BUGGYBOY_R3 + 1.0/BUGGYBOY_SHUNT))
+#define BUGGYBOY_R4S (1.0/(1.0/BUGGYBOY_R4 + 1.0/BUGGYBOY_SHUNT))
+
+static const double bb_engine_gains[16] =
+{
+ -1.0/(1.0/(BUGGYBOY_R1 + BUGGYBOY_R2 + BUGGYBOY_R3 + BUGGYBOY_R4 ) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1 + BUGGYBOY_R2 + BUGGYBOY_R3 + BUGGYBOY_R4S) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1 + BUGGYBOY_R2 + BUGGYBOY_R3S + BUGGYBOY_R4 ) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1 + BUGGYBOY_R2 + BUGGYBOY_R3S + BUGGYBOY_R4S) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1 + BUGGYBOY_R2S + BUGGYBOY_R3 + BUGGYBOY_R4 ) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1 + BUGGYBOY_R2S + BUGGYBOY_R3 + BUGGYBOY_R4S) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1 + BUGGYBOY_R2S + BUGGYBOY_R3S + BUGGYBOY_R4 ) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1 + BUGGYBOY_R2S + BUGGYBOY_R3S + BUGGYBOY_R4S) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1S + BUGGYBOY_R2 + BUGGYBOY_R3 + BUGGYBOY_R4 ) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1S + BUGGYBOY_R2 + BUGGYBOY_R3 + BUGGYBOY_R4S) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1S + BUGGYBOY_R2 + BUGGYBOY_R3S + BUGGYBOY_R4 ) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1S + BUGGYBOY_R2 + BUGGYBOY_R3S + BUGGYBOY_R4S) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1S + BUGGYBOY_R2S + BUGGYBOY_R3 + BUGGYBOY_R4 ) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1S + BUGGYBOY_R2S + BUGGYBOY_R3 + BUGGYBOY_R4S) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1S + BUGGYBOY_R2S + BUGGYBOY_R3S + BUGGYBOY_R4 ) + 1.0/100e3)/100e3,
+ -1.0/(1.0/(BUGGYBOY_R1S + BUGGYBOY_R2S + BUGGYBOY_R3S + BUGGYBOY_R4S) + 1.0/100e3)/100e3,
+};
+
+
+
+/***************************************************************************
+
+ YM-2149, IC24 port mappings:
+
+ Port A Port B
+ ======= ======
+
+ 0: Engine 1 gain (FR) #0 0: *Coin Counter 1
+ 1: Engine 1 gain (FR) #1 1: *Coin Counter 2
+ 2: Engine 1 gain (FR) #2 2: *Coin Counter 3 (Unused)
+ 3: Engine 1 gain (FR) #3 3: *Engine 0 gain
+ 4: Engine 1 gain (FL) #0 4: Skid 0 enable
+ 5: Engine 1 gain (FL) #1 5: Skid 1 enable
+ 6: Engine 1 gain (FL) #2 6: Enable YM IC24 output on RR
+ 7: Engine 1 gain (FL) #3 7: Enable YM IC19 output on RL
+
+ (* Buggy Boy Junior only)
+
+ The engine sounds are generated by an 8253. There are two channels.
+
+ #0 is the player's buggy
+ #1 is the opponents' buggies
+
+ +------------> GAIN[1] +--> FL
+ | +--> FR
+ 8255 #0 --+--> BL
+ +--> BR
+
+ 8255 #1 --+--> GAIN[2] ---> FL
+ +--> GAIN[3] ---> FR
+
+
+ [1] is used to amplify sound during tunnel.
+ [2] and [3] are stereo fades
+
+***************************************************************************/
+
+WRITE8_DEVICE_HANDLER( bb_ym1_a_w )
+{
+ tx1_sound_state *state = get_safe_token(device);
+
+ state->m_stream->update();
+ state->m_ym1_outputa = data ^ 0xff;
+}
+
+WRITE8_DEVICE_HANDLER( bb_ym2_a_w )
+{
+ tx1_sound_state *state = get_safe_token(device);
+
+ state->m_stream->update();
+ state->m_ym2_outputa = data ^ 0xff;
+}
+
+WRITE8_DEVICE_HANDLER( bb_ym2_b_w )
+{
+ tx1_sound_state *state = get_safe_token(device);
+ device_t *ym1 = device->machine().device("ym1");
+ device_t *ym2 = device->machine().device("ym2");
+ double gain;
+
+ state->m_stream->update();
+
+ state->m_ym2_outputb = data ^ 0xff;
+
+ if (!strcmp(device->machine().system().name, "buggyboyjr"))
+ {
+ coin_counter_w(device->machine(), 0, data & 0x01);
+ coin_counter_w(device->machine(), 1, data & 0x02);
+ }
+
+ /*
+ Until we support > 2 speakers, double the gain of the front speakers
+
+ TODO: We do support more than 2 speakers but the output is downmixed to stereo.
+ */
+
+ /* Rear left speaker */
+ device_sound_interface *sound;
+ ym1->interface(sound);
+ gain = data & 0x80 ? 1.0 : 2.0;
+ sound->set_output_gain(0, gain);
+ sound->set_output_gain(1, gain);
+ sound->set_output_gain(2, gain);
+
+ /* Rear right speaker */
+ ym2->interface(sound);
+ gain = data & 0x40 ? 1.0 : 2.0;
+ sound->set_output_gain(0, gain);
+ sound->set_output_gain(1, gain);
+ sound->set_output_gain(2, gain);
+}
+
+/* This is admittedly a bit of a hack job... */
+static STREAM_UPDATE( buggyboy_stream_update )
+{
+ tx1_sound_state *state = get_safe_token(device);
+ UINT32 step_0, step_1;
+ int n1_en, n2_en;
+ double gain0, gain1_l, gain1_r;
+
+ stream_sample_t *fl = &outputs[0][0];
+ stream_sample_t *fr = &outputs[1][0];
+
+ /* Clear the buffers */
+ memset(outputs[0], 0, samples * sizeof(*outputs[0]));
+ memset(outputs[1], 0, samples * sizeof(*outputs[1]));
+
+ /* 8253 outputs for the player/opponent buggy engine sounds. */
+ step_0 = state->m_pit8253.counts[0].val ? (BUGGYBOY_PIT_CLOCK / state->m_pit8253.counts[0].val) * state->m_freq_to_step : 0;
+ step_1 = state->m_pit8253.counts[1].val ? (BUGGYBOY_PIT_CLOCK / state->m_pit8253.counts[1].val) * state->m_freq_to_step : 0;
+
+ if (!strcmp(device->machine().system().name, "buggyboyjr"))
+ gain0 = BIT(state->m_ym2_outputb, 3) ? 1.0 : 2.0;
+ else
+ gain0 = BIT(state->m_ym1_outputa, 3) ? 1.0 : 2.0;
+
+ n1_en = BIT(state->m_ym2_outputb, 4);
+ n2_en = BIT(state->m_ym2_outputb, 5);
+
+ gain1_l = bb_engine_gains[state->m_ym2_outputa >> 4] * 5;
+ gain1_r = bb_engine_gains[state->m_ym2_outputa & 0xf] * 5;
+
+ while (samples--)
+ {
+ int i;
+ stream_sample_t pit0, pit1, n1, n2;
+ pit0 = state->m_eng_voltages[(state->m_step0 >> 24) & 0xf];
+ pit1 = state->m_eng_voltages[(state->m_step1 >> 24) & 0xf];
+
+ /* Calculate the tyre screech noise source */
+ for (i = 0; i < BUGGYBOY_NOISE_CLOCK / device->machine().sample_rate(); ++i)
+ {
+ /* CD4006 is a 4-4-1-4-4-1 shift register */
+ int p13 = BIT(state->m_noise_lfsra, 3);
+ int p12 = BIT(state->m_noise_lfsrb, 4);
+ int p10 = BIT(state->m_noise_lfsrc, 3);
+ int p8 = BIT(state->m_noise_lfsrd, 3);
+
+ /* Update the register */
+ state->m_noise_lfsra = p12 | ((state->m_noise_lfsra << 1) & 0xf);
+ state->m_noise_lfsrb = (p8 ^ p12) | ((state->m_noise_lfsrb << 1) & 0x1f);
+ state->m_noise_lfsrc = p13 | ((state->m_noise_lfsrc << 1) & 0xf);
+ state->m_noise_lfsrd = p10 | ((state->m_noise_lfsrd << 1) & 0x1f);
+
+ /* 4040 12-bit counter is clocked on the falling edge of Q13 */
+ if ( !BIT(state->m_noise_lfsrc, 3) && p10 )
+ state->m_noise_counter = (state->m_noise_counter + 1) & 0x0fff;
+ }
+
+ if (n1_en)
+ {
+ n1 = !BIT(state->m_noise_counter, 7-1) * 16000;
+ if ( BIT(state->m_noise_counter, 11-1) ) n1 /=2;
+ }
+ else
+ n1 = 8192;
+
+ if (n2_en)
+ {
+ n2 = !BIT(state->m_noise_counter, 6-1) * 16000;
+ if ( BIT(state->m_noise_counter, 11-1) ) n2 /=2;
+ }
+ else
+ n2 = 8192;
+
+ *fl++ = n1 + n2 + (pit0 * gain0) + (pit1 * gain1_l);
+ *fr++ = n1 + n2 + (pit0 * gain0) + (pit1 * gain1_r);
+
+ state->m_step0 += step_0;
+ state->m_step1 += step_1;
+ }
+}
+
+static DEVICE_START( buggyboy_sound )
+{
+ tx1_sound_state *state = get_safe_token(device);
+ running_machine &machine = device->machine();
+ static const int resistors[4] = { 330000, 220000, 330000, 220000 };
+ double aweights[4];
+ int i;
+ static const int tmp[16] =
+ {
+ 0x0, 0x1, 0xe, 0xf, 0x8, 0x9, 0x6, 0x7, 0xc, 0xd, 0xe, 0xf, 0x4, 0x5, 0x6, 0x7
+ };
+
+ compute_resistor_weights(0, 16384, -1.0,
+ 4, &resistors[0], aweights, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0 );
+
+ for (i = 0; i < 16; i++)
+ state->m_eng_voltages[i] = combine_4_weights(aweights, BIT(tmp[i], 0), BIT(tmp[i], 1), BIT(tmp[i], 2), BIT(tmp[i], 3));
+
+ /* Allocate the stream */
+ state->m_stream = device->machine().sound().stream_alloc(*device, 0, 2, machine.sample_rate(), NULL, buggyboy_stream_update);
+ state->m_freq_to_step = (double)(1 << 24) / (double)machine.sample_rate();
+}
+
+static DEVICE_RESET( buggyboy_sound )
+{
+ tx1_sound_state *state = get_safe_token(device);
+
+ state->m_step0 = state->m_step1 = 0;
+
+ /* Reset noise LFSR */
+ state->m_noise_lfsra = 0;
+ state->m_noise_lfsrb = 1;
+ state->m_noise_lfsrc = 0;
+ state->m_noise_lfsrd = 0;
+}
+
+DEVICE_GET_INFO( buggyboy_sound )
+{
+ switch (state)
+ {
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(tx1_sound_state); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(buggyboy_sound); break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(buggyboy_sound); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Buggy Boy Custom"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ }
+}
+
+
+DEFINE_LEGACY_SOUND_DEVICE(BUGGYBOY, buggyboy_sound);
+DEFINE_LEGACY_SOUND_DEVICE(TX1, tx1_sound);