diff options
Diffstat (limited to 'src/mame/audio/polepos.c')
-rw-r--r-- | src/mame/audio/polepos.c | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/src/mame/audio/polepos.c b/src/mame/audio/polepos.c new file mode 100644 index 00000000000..1f912352753 --- /dev/null +++ b/src/mame/audio/polepos.c @@ -0,0 +1,344 @@ +/*************************************************************************** + polepos.c + Sound handler +****************************************************************************/ +#include "driver.h" +#include "streams.h" +#include "sound/filter.h" +#include "rescap.h" +#include "sound/custom.h" +#include "namco54.h" +#include "polepos.h" + +static int sample_msb = 0; +static int sample_lsb = 0; +static int sample_enable = 0; + +static sound_stream *stream; + +#define OUTPUT_RATE 24000 + +#define POLEPOS_R166 1000.0 +#define POLEPOS_R167 2200.0 +#define POLEPOS_R168 4700.0 +/* resistor values when shorted by 4066 running at 5V */ +#define POLEPOS_R166_SHUNT 1.0/(1.0/POLEPOS_R166 + 1.0/250) +#define POLEPOS_R167_SHUNT 1.0/(1.0/POLEPOS_R166 + 1.0/250) +#define POLEPOS_R168_SHUNT 1.0/(1.0/POLEPOS_R166 + 1.0/250) + +static double volume_table[8] = +{ + (POLEPOS_R168_SHUNT + POLEPOS_R167_SHUNT + POLEPOS_R166_SHUNT + 2200) / 10000, + (POLEPOS_R168_SHUNT + POLEPOS_R167_SHUNT + POLEPOS_R166 + 2200) / 10000, + (POLEPOS_R168_SHUNT + POLEPOS_R167 + POLEPOS_R166_SHUNT + 2200) / 10000, + (POLEPOS_R168_SHUNT + POLEPOS_R167 + POLEPOS_R166 + 2200) / 10000, + (POLEPOS_R168 + POLEPOS_R167_SHUNT + POLEPOS_R166_SHUNT + 2200) / 10000, + (POLEPOS_R168 + POLEPOS_R167_SHUNT + POLEPOS_R166 + 2200) / 10000, + (POLEPOS_R168 + POLEPOS_R167 + POLEPOS_R166_SHUNT + 2200) / 10000, + (POLEPOS_R168 + POLEPOS_R167 + POLEPOS_R166 + 2200) / 10000 +}; + +static filter2_context filter_engine[3]; + +static double r_filt_out[3] = {RES_K(4.7), RES_K(7.5), RES_K(10)}; +static double r_filt_total = 1.0 / (1.0/RES_K(4.7) + 1.0/RES_K(7.5) + 1.0/RES_K(10)); + +/************************************/ +/* Stream updater */ +/************************************/ +static void engine_sound_update(void *param, stream_sample_t **inputs, stream_sample_t **outputs, int length) +{ + static UINT32 current_position; + UINT32 step, clock, slot; + UINT8 *base; + double volume, i_total; + stream_sample_t *buffer = outputs[0]; + int loop; + + /* if we're not enabled, just fill with 0 */ + if (!sample_enable) + { + memset(buffer, 0, length * sizeof(*buffer)); + return; + } + + /* determine the effective clock rate */ + clock = (Machine->drv->cpu[0].clock / 16) * ((sample_msb + 1) * 64 + sample_lsb + 1) / (64*64); + step = (clock << 12) / OUTPUT_RATE; + + /* determine the volume */ + slot = (sample_msb >> 3) & 7; + volume = volume_table[slot]; + base = &memory_region(REGION_SOUND2)[slot * 0x800]; + + /* fill in the sample */ + while (length--) + { + filter_engine[0].x0 = (3.4 / 255 * base[(current_position >> 12) & 0x7ff] - 2) * volume; + filter_engine[1].x0 = filter_engine[0].x0; + filter_engine[2].x0 = filter_engine[0].x0; + + i_total = 0; + for (loop = 0; loop < 3; loop++) + { + filter2_step(&filter_engine[loop]); + /* The op-amp powered @ 5V will clip to 0V & 3.5V. + * Adjusted to vRef of 2V, we will clip as follows: */ + if (filter_engine[loop].y0 > 1.5) filter_engine[loop].y0 = 1.5; + if (filter_engine[loop].y0 < -2) filter_engine[loop].y0 = -2; + + i_total += filter_engine[loop].y0 / r_filt_out[loop]; + } + i_total *= r_filt_total * 32000/2; /* now contains voltage adjusted by final gain */ + + *buffer++ = (int)i_total; + current_position += step; + } +} + +/************************************/ +/* Sound handler start */ +/************************************/ +void *polepos_sh_start(int clock, const struct CustomSound_interface *config) +{ + stream = stream_create(0, 1, OUTPUT_RATE, NULL, engine_sound_update); + sample_msb = sample_lsb = 0; + sample_enable = 0; + + /* setup the filters */ + filter_opamp_m_bandpass_setup(RES_K(220), RES_K(33), RES_K(390), CAP_U(.01), CAP_U(.01), + &filter_engine[0]); + filter_opamp_m_bandpass_setup(RES_K(150), RES_K(22), RES_K(330), CAP_U(.0047), CAP_U(.0047), + &filter_engine[1]); + /* Filter 3 is a little different. Because of the input capacitor, it is + * a high pass filter. */ + filter2_setup(FILTER_HIGHPASS, 950, Q_TO_DAMP(.707), 1, + &filter_engine[2]); + + return auto_malloc(1); +} + +/************************************/ +/* Sound handler reset */ +/************************************/ +void polepos_sh_reset(void *token) +{ + int loop; + for (loop = 0; loop < 3; loop++) filter2_reset(&filter_engine[loop]); +} + +/************************************/ +/* Write LSB of engine sound */ +/************************************/ +WRITE8_HANDLER( polepos_engine_sound_lsb_w ) +{ + /* Update stream first so all samples at old frequency are updated. */ + stream_update(stream); + sample_lsb = data & 62; + sample_enable = data & 1; +} + +/************************************/ +/* Write MSB of engine sound */ +/************************************/ +WRITE8_HANDLER( polepos_engine_sound_msb_w ) +{ + stream_update(stream); + sample_msb = data & 63; +} + + +/************************************* + * + * Pole Position + * + * Discrete sound emulation: Feb 2007, D.R. + * + *************************************/ + +/* nodes - sounds */ +#define POLEPOS_CHANL1_SND NODE_11 +#define POLEPOS_CHANL2_SND NODE_12 +#define POLEPOS_CHANL3_SND NODE_13 +#define POLEPOS_CHANL4_SND NODE_14 + +#define POLEPOS_54XX_DAC_R (1.0 / (1.0 / RES_K(47) + 1.0 / RES_K(22) + 1.0 / RES_K(10) + 1.0 / RES_K(4.7))) +static const discrete_dac_r1_ladder polepos_54xx_dac = +{ + 4, /* number of DAC bits */ + /* 54XX_0 54XX_1 54XX_2 */ + { RES_K(47), /* R124, R136, R152 */ + RES_K(22), /* R120, R132, R142 */ + RES_K(10), /* R119, R131, R138 */ + RES_K(4.7)}, /* R118, R126, R103 */ + 0, 0, 0, 0 /* nothing extra */ +}; + +#define POLEPOS_52XX_DAC_R (1.0 / (1.0 / RES_K(100) + 1.0 / RES_K(47) + 1.0 / RES_K(22) + 1.0 / RES_K(10))) +static const discrete_dac_r1_ladder polepos_52xx_dac = +{ + 4, /* number of DAC bits */ + { RES_K(100), /* R160 */ + RES_K(47), /* R159 */ + RES_K(22), /* R155 */ + RES_K(10)}, /* R154 */ + 0, 0, 0, 0 /* nothing extra */ +}; + +/* R117 R116 R117 */ +#define POLEPOS_VREF (5.0 * (RES_K(1) / (RES_K(1.5) + RES_K(1)))) + +static const discrete_op_amp_filt_info polepos_chanl1_filt = +{ + POLEPOS_54XX_DAC_R + RES_K(22), /* R121 */ + 0, /* no second input */ + RES_K(12), /* R125 */ + 0, /* not used */ + RES_K(120), /* R122 */ + CAP_U(0.0022), /* C27 */ + CAP_U(0.0022), /* C28 */ + 0, /* not used */ + POLEPOS_VREF, /* vRef */ + 5, /* vP */ + 0 /* vN */ +}; + +static const discrete_op_amp_filt_info polepos_chanl2_filt = +{ + POLEPOS_54XX_DAC_R + RES_K(15), /* R133 */ + 0, /* no second input */ + RES_K(15), /* R137 */ + 0, /* not used */ + RES_K(120), /* R134 */ + CAP_U(0.022), /* C29 */ + CAP_U(0.022), /* C30 */ + 0, /* not used */ + POLEPOS_VREF, /* vRef */ + 5, /* vP */ + 0 /* vN */ +}; + +static const discrete_op_amp_filt_info polepos_chanl3_filt = +{ + POLEPOS_54XX_DAC_R + RES_K(22), /* R139 */ + 0, /* no second input */ + RES_K(22), /* R143 */ + 0, /* not used */ + RES_K(180), /* R140 */ + CAP_U(0.047), /* C33 */ + CAP_U(0.047), /* C34 */ + 0, /* not used */ + POLEPOS_VREF, /* vRef */ + 5, /* vP */ + 0 /* vN */ +}; + +DISCRETE_SOUND_START(polepos) + + /************************************************ + * Input register mapping + ************************************************/ + DISCRETE_INPUT_DATA(NAMCO_54XX_0_DATA) + DISCRETE_INPUT_DATA(NAMCO_54XX_1_DATA) + DISCRETE_INPUT_DATA(NAMCO_54XX_2_DATA) + DISCRETE_INPUT_DATA(NAMCO_52XX_P_DATA) + + /************************************************ + * CHANL1 sound + ************************************************/ + DISCRETE_DAC_R1(NODE_20, + 1, /* ENAB */ + NAMCO_54XX_2_DATA, + 4, /* 4V - unmeasured*/ + &polepos_54xx_dac) + DISCRETE_OP_AMP_FILTER(NODE_21, + 1, /* ENAB */ + NODE_20, /* INP0 */ + 0, /* INP1 - not used */ + DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &polepos_chanl1_filt) + /* fake it so 0 is now vRef */ + DISCRETE_ADDER2(POLEPOS_CHANL1_SND, + 1, /* ENAB */ + NODE_21, -POLEPOS_VREF) + + /************************************************ + * CHANL2 sound + ************************************************/ + DISCRETE_DAC_R1(NODE_30, + 1, /* ENAB */ + NAMCO_54XX_1_DATA, + 4, /* 4V - unmeasured*/ + &polepos_54xx_dac) + DISCRETE_OP_AMP_FILTER(NODE_31, + 1, /* ENAB */ + NODE_30, /* INP0 */ + 0, /* INP1 - not used */ + DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &polepos_chanl2_filt) + /* fake it so 0 is now vRef */ + DISCRETE_ADDER2(POLEPOS_CHANL2_SND, + 1, /* ENAB */ + NODE_31, -POLEPOS_VREF) + + /************************************************ + * CHANL3 sound + ************************************************/ + DISCRETE_DAC_R1(NODE_40, + 1, /* ENAB */ + NAMCO_54XX_0_DATA, + 4, /* 4V - unmeasured*/ + &polepos_54xx_dac) + DISCRETE_OP_AMP_FILTER(NODE_41, + 1, /* ENAB */ + NODE_40, /* INP0 */ + 0, /* INP1 - not used */ + DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &polepos_chanl3_filt) + /* fake it so 0 is now vRef */ + DISCRETE_ADDER2(POLEPOS_CHANL3_SND, + 1, /* ENAB */ + NODE_41, -POLEPOS_VREF) + + /************************************************ + * CHANL4 sound + ************************************************/ + /* disabled until 52XX is emulated */ + /* this circuit was simulated in SPICE and an equivalent filter circuit generated */ + DISCRETE_DAC_R1(NODE_50, + 0, /* ENAB */ + NAMCO_52XX_P_DATA, + 4, /* 4V - unmeasured*/ + &polepos_52xx_dac) + /* fake it so 0 is now vRef */ + DISCRETE_ADDER2(NODE_51, + 0, /* ENAB */ + NODE_50, -POLEPOS_VREF) + DISCRETE_FILTER2(NODE_52, + 0, /* ENAB */ + NODE_51, /* INP0 */ + 100, /* FREQ */ + 1.0 / 0.3, /* DAMP */ + DISC_FILTER_HIGHPASS) + DISCRETE_FILTER2(NODE_53, + 0, /* ENAB */ + NODE_52, /* INP0 */ + 1200, /* FREQ */ + 1.0 / 0.8, /* DAMP */ + DISC_FILTER_LOWPASS) + DISCRETE_GAIN(NODE_54, + NODE_53, /* IN0 */ + 0.5 /* overall filter GAIN */) + /* clamp to the maximum of the op-amp shifted by vRef */ + DISCRETE_CLAMP(POLEPOS_CHANL4_SND, + 0, /* ENAB */ + NODE_54, /* IN0 */ + 0, /* MIN */ + 5.0 - OP_AMP_VP_RAIL_OFFSET - POLEPOS_VREF, /* MAX */ + 0.0 - POLEPOS_VREF /* disabled CLAMP value */) + + /************************************************ + * Output + ************************************************/ + DISCRETE_OUTPUT(POLEPOS_CHANL1_SND, 32767/2) + DISCRETE_OUTPUT(POLEPOS_CHANL2_SND, 32767/2) + DISCRETE_OUTPUT(POLEPOS_CHANL3_SND, 32767/2) +// DISCRETE_OUTPUT(POLEPOS_CHANL4_SND, 32767/2) +DISCRETE_SOUND_END |