namco52 namco54 to mame091

This commit is contained in:
Grantonius maximus 2024-08-18 15:35:23 +01:00
parent 95806c35f7
commit b16dbc66e0
10 changed files with 521 additions and 120 deletions

View File

@ -1834,26 +1834,44 @@ static struct GfxDecodeInfo gfxdecodeinfo_digdug[] =
};
/* The resistance path of the namco sound is 16k compared to
* the 10k of the highest gain 54xx filter. Giving a 10/16 gain.
*/
static struct namco_interface namco_interface =
{
18432000/6/32, /* 96 kHz sample rate */
3, /* number of voices */
100, /* playback volume */
90*10/16, /* playback volume */
REGION_SOUND1 /* memory region */
};
/* Only used by bosco. After filtering the 4V 52xx output,
* the signal is 1V, or 25%. The relative volume between
* 52xx & 54xx is the same.
*/
static struct namco_52xx_interface namco_52xx_interface =
{
18432000/12, /* 1.536 MHz */
50, /* volume */
REGION_SOUND2 /* memory region */
90, /* volume */
REGION_SOUND2, /* memory region */
4000, /* Playback frequency - from 555 timer 6M */
80, /* High pass filter fc */
0.3, /* High pass filter Q */
2400, /* Low pass filter fc */
0.9, /* Low pass filter Q */
.25 /* Combined gain of both filters */
};
static struct namco_54xx_interface namco_54xx_interface =
{
18432000/12, /* 1.536 MHz */
{ 100, 100, 100 } /* volume of the three outputs */
90, /* volume */
{ RES_K(100), RES_K(47), RES_K(150) }, /* R24, R33, R42 */
{ RES_K(22), RES_K(10), RES_K(22) }, /* R23, R34, R41 */
{ RES_K(220), RES_K(150), RES_K(470) }, /* R22, R35, R40 */
{ RES_K(33), RES_K(33), RES_K(10)}, /* R21, R36, R37 */
{ CAP_U(.001), CAP_U(.01), CAP_U(.01) }, /* C31, C29, C27 */
{ CAP_U(.001), CAP_U(.01), CAP_U(.01) }, /* C30, C28, C26 */
};
static const char *bosco_sample_names[] =
@ -1865,8 +1883,8 @@ static const char *bosco_sample_names[] =
static struct Samplesinterface samples_interface_bosco =
{
1, /* 1 channel */
100, /* volume */
1, /* 3 channel1 */
95, /* volume */
bosco_sample_names
};

View File

@ -782,14 +782,26 @@ static struct namco_interface namco_interface =
static struct namco_52xx_interface namco_52xx_interface =
{
24576000/16, /* 1.536 MHz */
25, /* volume */
REGION_SOUND3 /* memory region */
80, /* volume */
REGION_SOUND3, /* memory region */
0, /* Use internal Playback frequency */
100, /* High pass filter fc */
0.3, /* High pass filter Q */
1200, /* Low pass filter fc */
0.8, /* Low pass filter Q */
.5 /* Combined gain of both filters */
};
static struct namco_54xx_interface namco_54xx_interface =
{
24576000/16, /* 1.536 MHz */
{ 100, 100, 100 } /* volume of the three outputs */
80, /* volume */
{ RES_K(22), RES_K(15), RES_K(22) }, /* R121, R133, R139 */
{ RES_K(12), RES_K(15), RES_K(22) }, /* R125, R137, R143 */
{ RES_K(120), RES_K(120), RES_K(180) }, /* R122, R134, R140 */
{ 470, 470, 470 }, /* R123, R135, R141 */
{ CAP_U(.0022), CAP_U(.022), CAP_U(.047) }, /* C27, C29, C33 */
{ CAP_U(.0022), CAP_U(.022), CAP_U(.047) }, /* C28, C30, C34 */
};
static struct CustomSound_interface custom_interface =

View File

@ -3,6 +3,7 @@
Sound handler
****************************************************************************/
#include "driver.h"
#include "../sound/filter.h"
static int sample_msb = 0;
static int sample_lsb = 0;
@ -10,13 +11,30 @@ static int sample_enable = 0;
static int sound_stream;
#define AMP(r) (r*128/10100)
static int volume_table[8] =
#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] =
{
AMP(2200), AMP(3200), AMP(4400), AMP(5400),
AMP(6900), AMP(7900), AMP(9100), AMP(10100)
(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 struct 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 */
@ -24,9 +42,10 @@ static int volume_table[8] =
static void engine_sound_update(int num, INT16 *buffer, int length)
{
static UINT32 current_position;
UINT32 step, clock, slot, volume;
UINT32 step, clock, slot;
UINT8 *base;
double volume, i_total;
int loop;
/* if we're not enabled, just fill with 0 */
if (!sample_enable || Machine->sample_rate == 0)
@ -47,7 +66,24 @@ static void engine_sound_update(int num, INT16 *buffer, int length)
/* fill in the sample */
while (length--)
{
*buffer++ = (base[(current_position >> 12) & 0x7ff] * volume);
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;
}
}
@ -57,12 +93,32 @@ static void engine_sound_update(int num, INT16 *buffer, int length)
/************************************/
int polepos_sh_start(const struct MachineSound *msound)
{
sound_stream = stream_init("Engine Sound", 25, Machine->sample_rate, 0, engine_sound_update);
sound_stream = stream_init("Engine Sound", 77, Machine->sample_rate, 0, 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 0;
}
/************************************/
/* Sound handler reset */
/************************************/
void polepos_sh_reset(void)
{
int loop;
for (loop = 0; loop < 3; loop++) filter2_reset(&filter_engine[loop]);
}
/************************************/
/* Sound handler stop */
/************************************/
@ -75,6 +131,7 @@ void polepos_sh_stop(void)
/************************************/
WRITE_HANDLER( polepos_engine_sound_lsb_w )
{
/* Update stream first so all samples at old frequency are updated. */
stream_update(sound_stream, 0);
sample_lsb = data & 62;
sample_enable = data & 1;

View File

@ -1,4 +1,5 @@
#include "filter.h"
#include "driver.h"
#include <assert.h>
#include <math.h>
@ -132,3 +133,103 @@ filter* filter_lp_fir_alloc(double freq, int order) {
return f;
}
void filter2_setup(int type, double fc, double d, double gain,
struct filter2_context *filter)
{
double w; /* cutoff freq, in radians/sec */
double w_squared;
double den; /* temp variable */
double two_over_T = 2*Machine->sample_rate;
double two_over_T_squared = two_over_T * two_over_T;
/* calculate digital filter coefficents */
/*w = 2.0*M_PI*fc; no pre-warping */
w = Machine->sample_rate*2.0*tan(M_PI*fc/Machine->sample_rate); /* pre-warping */
w_squared = w*w;
den = two_over_T_squared + d*w*two_over_T + w_squared;
filter->a1 = 2.0*(-two_over_T_squared + w_squared)/den;
filter->a2 = (two_over_T_squared - d*w*two_over_T + w_squared)/den;
switch (type)
{
case FILTER_LOWPASS:
filter->b0 = filter->b2 = w_squared/den;
filter->b1 = 2.0*(filter->b0);
break;
case FILTER_BANDPASS:
filter->b0 = d*w*two_over_T/den;
filter->b1 = 0.0;
filter->b2 = -(filter->b0);
break;
case FILTER_HIGHPASS:
filter->b0 = filter->b2 = two_over_T_squared/den;
filter->b1 = -2.0*(filter->b0);
break;
default:
logerror("filter2_setup() - Invalid filter type for 2nd order filter.");
break;
}
filter->b0 *= gain;
filter->b1 *= gain;
filter->b2 *= gain;
}
/* Reset the input/output voltages to 0. */
void filter2_reset(struct filter2_context *filter)
{
filter->x0 = 0;
filter->x1 = 0;
filter->x2 = 0;
filter->y0 = 0;
filter->y1 = 0;
filter->y2 = 0;
}
/* Step the filter. */
void filter2_step(struct filter2_context *filter)
{
filter->y0 = -filter->a1 * filter->y1 - filter->a2 * filter->y2 +
filter->b0 * filter->x0 + filter->b1 * filter->x1 + filter->b2 * filter->x2;
filter->x2 = filter->x1;
filter->x1 = filter->x0;
filter->y2 = filter->y1;
filter->y1 = filter->y0;
}
/* Setup a filter2 structure based on an op-amp multipole bandpass circuit. */
void filter_opamp_m_bandpass_setup(double r1, double r2, double r3, double c1, double c2,
struct filter2_context *filter)
{
double r_in, fc, d, gain;
if (r1 == 0)
{
logerror("filter_opamp_m_bandpass_setup() - r1 can not be 0");
return; /* Filter can not be setup. Undefined results. */
}
if (r2 == 0)
{
gain = 1;
r_in = r1;
}
else
{
gain = r2 / (r1 + r2);
r_in = 1.0 / (1.0/r1 + 1.0/r2);
}
fc = 1.0 / (2 * M_PI * sqrt(r_in * r3 * c1 * c2));
d = (c1 + c2) / sqrt(r3 / r_in * c1 * c2);
gain *= -r3 / r_in * c2 / (c1 + c2);
filter2_setup(FILTER_BANDPASS, fc, d, gain, filter);
}

View File

@ -53,4 +53,64 @@ static INLINE void filter_insert(filter* f, filter_state* s, filter_real x) {
/* Compute the filter output */
filter_real filter_compute(filter* f, filter_state* s);
/* Filter types */
#define FILTER_LOWPASS 0
#define FILTER_HIGHPASS 1
#define FILTER_BANDPASS 2
#define Q_TO_DAMP(q) (1.0/q)
struct filter2_context
{
double x0, x1, x2; /* x[k], x[k-1], x[k-2], current and previous 2 input values */
double y0, y1, y2; /* y[k], y[k-1], y[k-2], current and previous 2 output values */
double a1, a2; /* digital filter coefficients, denominator */
double b0, b1, b2; /* digital filter coefficients, numerator */
};
/* Setup the filter context based on the passed filter type info.
* type - 1 of the 3 defined filter types
* fc - center frequency
* d - damp = 1/Q
* gain - overall filter gain. Set to 1 if not needed.
*/
void filter2_setup(int type, double fc, double d, double gain,
struct filter2_context *filter);
/* Reset the input/output voltages to 0. */
void filter2_reset(struct filter2_context *filter);
/* Step the filter.
* x0 is the new input, which needs to be set before stepping.
* y0 is the new filter output.
*/
void filter2_step(struct filter2_context *filter);
/* Setup a filter2 structure based on an op-amp multipole bandpass circuit.
* NOTE: If r2 is not used then set to 0.
* vRef is not needed to setup filter.
*
* .--------+---------.
* | | |
* --- c1 Z |
* --- Z r3 |
* | Z |
* r1 | c2 | |\ |
* In >----ZZZZ----+---------+--||----+ | \ |
* Z '--|- \ |
* Z r2 | >--+------> out
* Z .--|+ /
* | | | /
* gnd vRef >---' |/
*
*/
void filter_opamp_m_bandpass_setup(double r1, double r2, double r3, double c1, double c2,
struct filter2_context *filter);
#endif

View File

@ -34,83 +34,146 @@ OUT = sound output
GND|21 22|D0
+------+
[1] in polepos, GND; in bosco, output from a 555 timer
[1] in polepos, GND; in bosco, 4kHz output from a 555 timer
[2] in polepos, +5V; in bosco, GND
[3] in polepos, these are true address lines, in bosco they are chip select lines
(each one select one of the four ROM chips). Behaviour related to [2]?
TODO:
- the purpose of the 555 timer in bosco is unknown; maybe modulate the output?
Jan 12, 2005. The 555 is probably an external playback frequency.
***************************************************************************/
#include "driver.h"
#include "namco52.h"
/* macro to convert 4-bit unsigned samples to 8-bit signed samples */
#define SAMPLE_CONV4(a) (0x11*((a&0x0f))-0x80)
#include "filter.h"
static INT8 *samples; /* 4-bit samples will be unpacked to 8-bit here */
static int channel; /* channel assigned by the mixer */
static const struct namco_52xx_interface *intf; /* pointer to our config data */
static UINT8 *rom; /* pointer to sample ROM */
static UINT8 *rom; /* pointer to sample ROM */
static int rom_len;
static int stream; /* the output stream */
static double n52_pb_cycle; /* playback clock time based on machine sample rate */
static double n52_step; /* playback clock step based on machine sample rate */
/* n52_pb_cycle is incremented by n52_step every machine-sample.
* At every integer value of n52_pb_cycle the next 4bit value is used. */
static int n52_start; /* current effect start position in the ROM */
static int n52_end; /* current effect end position in the ROM */
static int n52_length; /* # of 4bit samples in current effect */
static int n52_pos; /* current 4bit sample of effect */
static struct filter2_context n52_hp_filter;
static struct filter2_context n52_lp_filter;
static void namco_52xx_stream_update_one(int num, INT16 *buffer, int length)
{
int i, rom_pos, whole_pb_cycles, buf;
if (n52_start >= n52_end)
{
memset(buffer, 0, length * sizeof(INT16));
return;
}
for (i = 0; i < length; i++)
{
n52_pb_cycle += n52_step;
if (n52_pb_cycle >= 1)
{
whole_pb_cycles = (int)n52_pb_cycle;
n52_pos += whole_pb_cycles;
n52_pb_cycle -= whole_pb_cycles;
}
if (n52_pos > n52_length)
{
/* sample done */
memset(&buffer[i], 0, (length - i) * sizeof(INT16));
i = length;
namco_52xx_sh_reset();
}
else
{
/* filter and fill the buffer */
rom_pos = n52_start + (n52_pos >> 1);
/* get the 4bit sample from rom and shift to +7/-8 value */
n52_hp_filter.x0 = (((n52_pos & 1) ? rom[rom_pos] >> 4 : rom[rom_pos]) & 0x0f) - 0x08;
filter2_step(&n52_hp_filter);
n52_lp_filter.x0 = n52_hp_filter.y0;
filter2_step(&n52_lp_filter);
/* convert 4bit filtered to 16bit allowing room for filter gain */
buf = (int)(n52_lp_filter.y0 * 0x0fff);
if (buf > 32767) buf = 32767;
if (buf < -32768) buf = -32768;
buffer[i] = buf;
}
}
}
void namco_52xx_sh_reset(void)
{
n52_pb_cycle = n52_start = n52_end = n52_length = n52_pos = 0;
filter2_reset(&n52_hp_filter);
filter2_reset(&n52_lp_filter);
}
int namco_52xx_sh_start(const struct MachineSound *msound)
{
int i;
unsigned char bits;
intf = msound->sound_interface;
rom = memory_region(intf->region);
rom_len = memory_region_length(intf->region);
channel = mixer_allocate_channel(intf->mixing_level);
mixer_set_name(channel,sound_name(msound));
samples = auto_malloc(2*rom_len);
if (!samples)
if (Machine->sample_rate == 0)
return 1;
/* decode the rom samples */
for (i = 0;i < rom_len;i++)
if (intf->play_rate == 0)
{
bits = rom[i] & 0x0f;
samples[2*i] = SAMPLE_CONV4(bits);
bits = (rom[i] & 0xf0) >> 4;
samples[2*i + 1] = SAMPLE_CONV4(bits);
/* If play clock is 0 (grounded) then default to internal clock */
n52_step = (double)(intf->baseclock) / 384 / Machine->sample_rate;
}
else
{
n52_step = intf->play_rate / Machine->sample_rate;
}
filter2_setup(FILTER_HIGHPASS, intf->hp_filt_fc, Q_TO_DAMP(intf->hp_filt_q), 1, &n52_hp_filter);
filter2_setup(FILTER_LOWPASS, intf->lp_filt_fc, Q_TO_DAMP(intf->lp_filt_q), intf->filt_gain, &n52_lp_filter);
stream = stream_init(sound_name(msound), intf->mixing_level, Machine->sample_rate, 0, namco_52xx_stream_update_one);
/* handle failure */
if (stream == -1)
osd_die("Namco 52xx - Stream init returned an error\n");
namco_52xx_sh_reset();
return 0;
}
void namco_52xx_sh_stop(void)
{
}
void namcoio_52XX_write(int data)
{
data &= 0x0f;
/*logerror("%04x: custom 52XX write %02x\n",activecpu_get_pc(),data); */
if (Machine->sample_rate == 0)
return;
if (data != 0)
{
int start = rom[data-1] + (rom[data-1+0x10] << 8);
int end = rom[data] + (rom[data+0x10] << 8);
stream_update(stream, 0);
if (end >= rom_len)
end = rom_len;
n52_start = rom[data-1] + (rom[data-1+0x10] << 8);
n52_end = rom[data] + (rom[data+0x10] << 8);
if (start < end)
mixer_play_sample(channel, samples + start * 2, (end - start) * 2, intf->baseclock/384, 0);
if (n52_end >= rom_len)
n52_end = rom_len;
n52_length = (n52_end - n52_start) * 2;
n52_pos = 0;
n52_pb_cycle= 0;
}
}
void namco_52xx_sh_stop(void)
{
}

View File

@ -1,16 +1,38 @@
#ifndef namco52_h
#define namco52_h
/* While a little confusing, this interface uses 2 gains.
*
* "mixing_level" is the relative level of the signal
* compared to other effects before entering the filter.
*
* "filt_gain" is the combined gain of the filters.
*
* If I did not do it this way, then the filters could
* cause the signal to go beyond the 16bit range.
*
* If "play_rate" is 0 (ground) then the sample clock rate
* defaults to the 52xx internal sample clock. (baseclock/384)
*/
struct namco_52xx_interface
{
int baseclock; /* clock */
int mixing_level; /* volume */
int region; /* memory region */
int baseclock; /* clock */
int mixing_level; /* volume */
int region; /* memory region */
double play_rate; /* Playback frequency */
double hp_filt_fc;
double hp_filt_q;
double lp_filt_fc;
double lp_filt_q;
double filt_gain;
};
int namco_52xx_sh_start(const struct MachineSound *msound);
void namco_52xx_sh_reset(void);
void namco_52xx_sh_stop(void);
void namcoio_52XX_write(int data);
#endif

View File

@ -71,6 +71,7 @@ TODO:
***************************************************************************/
#include "driver.h"
#include "filter.h"
static int fetch;
@ -233,10 +234,14 @@ static UINT8 release_table[16][8]=
{15,11,8,6,4,3,2,1}
};
static struct filter2_context filter54[3];
void namco_54xx_sh_reset(void)
{
int loop;
for (loop = 0; loop < 3; loop++) filter2_reset(&filter54[loop]);
fetch = 0;
fetchmode = 0;
@ -258,7 +263,7 @@ void namco_54xx_sh_reset(void)
noise_B_will_change = 0;
out_prev = 0;
/* wonder what are the default params after the reset ? */
//wonder what are the default params after the reset ?
}
@ -348,9 +353,8 @@ int i;
static INT16 calc_A(void)
{
/*if (type_A_active)
log_cb( RETRO_LOG_DEBUG,"calc a: env_state=%2i vol=%2i noise=%2i\n", type_A_state, type_A_curr_vol, noise_out_A);
*/
//if (type_A_active)
// logerror("calc a: env_state=%2i vol=%2i noise=%2i\n", type_A_state, type_A_curr_vol, noise_out_A);
switch (type_A_state)
{
@ -408,16 +412,16 @@ static void advance(void)
{
int i,v;
/* type A */
//type A
type_A_pos += type_A_add;
i = (type_A_pos >> PRECISION_SH);
type_A_pos &= PRECISION_MASK;
if (i)
{ /*switch to the next envelope state
{ //switch to the next envelope state
//logerror("type A switch, from mode=%2i\n",type_A_state);
log_cb( RETRO_LOG_DEBUG,"type A switch, from mode=%2i\n",type_A_state);
*/
switch(type_A_state)
{
case ENV_OFF:
@ -458,16 +462,16 @@ int i,v;
}
/* type B */
//type B
type_B_pos += type_B_add;
i = (type_B_pos >> PRECISION_SH);
type_B_pos &= PRECISION_MASK;
if (i)
{ /* switch to the next envelope state
{ //switch to the next envelope state
//logerror("type B switch, from mode=%2i\n",type_B_state);
log_cb( RETRO_LOG_DEBUG,"type B switch, from mode=%2i\n",type_B_state);
*/
switch(type_B_state)
{
case ENV_OFF:
@ -510,7 +514,7 @@ int i,v;
/* TODO type C */
//TODO type C
noise_step();
@ -521,7 +525,7 @@ int i,v;
void NAMCO54xxUpdateOne(int num, INT16 **buffers, int length)
{
int i;
int i, loop;
INT16 out1, out2, out3;
INT16 *buf1, *buf2, *buf3;
@ -531,25 +535,38 @@ void NAMCO54xxUpdateOne(int num, INT16 **buffers, int length)
for (i = 0; i < length; i++)
{
/* if (fetch) /* no sound is produced while waiting for the parameters */
//if (fetch) /* no sound is produced while waiting for the parameters */
out1 = calc_A(); /* pins 4-7 */
out2 = calc_B(); /* pins 8-11 */
out3 = calc_C(); /* pins 17-20 */
(buf1)[i] = out1 * 1024; /* with gain: 0 to 15K */
(buf2)[i] = out2 * 1024; /* with gain: 0 to 15K */
(buf3)[i] = out3 * 1024; /* with gain: 0 to 15K */
/* Convert the binary value to a voltage and filter it. */
/* I am assuming a 4V output when a bit is high. */
filter54[0].x0 = 4.0/15 * out1 - 2;
filter54[1].x0 = 4.0/15 * out2 - 2;
filter54[2].x0 = 4.0/15 * out3 - 2;
for (loop = 0; loop < 3; loop++)
{
filter2_step(&filter54[loop]);
/* The op-amp powered @ 5V will clip to 0V & 3.5V.
* Adjusted to vRef of 2V, we will clip as follows: */
if (filter54[loop].y0 > 1.5) filter54[loop].y0 = 1.5;
if (filter54[loop].y0 < -2) filter54[loop].y0 = -2;
}
(buf1)[i] = filter54[0].y0 * (32768/2);
(buf2)[i] = filter54[1].y0 * (32768/2);
(buf3)[i] = filter54[2].y0 * (32768/2);
advance();
}
}
void namcoio_54XX_write(int data)
{
log_cb( RETRO_LOG_DEBUG,"%04x: custom 54XX write %02x\n",activecpu_get_pc(),data);
logerror("%04x: custom 54XX write %02x\n",activecpu_get_pc(),data);
stream_update(stream, 0);
@ -599,7 +616,7 @@ void namcoio_54XX_write(int data)
case 0x50: /* type C, mode A, output sound on pins 17-20 only */
if (memcmp(type_C_par,"\x08\x04\x21\x00\xf1",5) == 0)
/* bosco */
// bosco
sample_start(0, 0, 0);
break;
@ -609,7 +626,7 @@ void namcoio_54XX_write(int data)
break;
case 0x70: /* type C, mode B, output sound on pins 17-20 only */
/* polepos */
// polepos
/* 0x7n = Screech sound. n = volume (if 0 then no sound) */
/* followed by 0x60 command */
#if 1
@ -641,11 +658,30 @@ int namco_54xx_sh_start(const struct MachineSound *msound)
const char *name[NAMCO54xx_NUMBUF];
int vol[NAMCO54xx_NUMBUF];
double scaler, c_value;
double scaler, c_value, r_in, r_min;
int i;
intf = msound->sound_interface;
/* setup the filters */
r_min = intf->r4[0];
for (i = 0; i < 3; i++)
{
r_in = intf->r1[i] + ( 1.0 / ( 1.0/4700 + 1.0/10000 + 1.0/22000 + 1.0/47000));
filter_opamp_m_bandpass_setup(r_in, intf->r2[i], intf->r3[i], intf->c1[i], intf->c2[i],
&filter54[i]);
if (intf->r4[i] < r_min) r_min = intf->r4[i];
}
/* setup relative gains */
for (i = 0; i < 3; i++)
{
scaler = r_min / intf->r4[i];
filter54[i].b0 *= scaler;
filter54[i].b1 *= scaler;
filter54[i].b2 *= scaler;
}
chip_clock = intf->baseclock;
chip_sampfreq = Machine->sample_rate;
@ -653,14 +689,14 @@ int namco_54xx_sh_start(const struct MachineSound *msound)
for (i = 0; i < NAMCO54xx_NUMBUF; i++)
{
vol[i] = intf->mixing_level[i];
vol[i] = intf->mixing_level;
name[i] = buf[i];
sprintf(buf[i],"%s Ch %d",sound_name(msound),i);
}
stream = stream_init_multi(NAMCO54xx_NUMBUF, name, vol, chip_sampfreq, 0, NAMCO54xxUpdateOne);
log_cb( RETRO_LOG_DEBUG,"Namco 54xx clock=%f sample rate=%f\n", chip_clock, chip_sampfreq);
logerror("Namco 54xx clock=%f sample rate=%f\n", chip_clock, chip_sampfreq);
/* calculate emulation tables */
scaler = chip_clock / chip_sampfreq;
@ -678,14 +714,14 @@ altogether which corresponds to 1254 chip clock cycles. 13 samples = 543 cycles,
c_value = ((double)(1<<PRECISION_SH)) / 209.0;
RNG_delay = c_value * scaler; /* scaled to our sample rate */
log_cb( RETRO_LOG_DEBUG,"rng_f_0 =%08x\n", RNG_f_0);
log_cb( RETRO_LOG_DEBUG,"rng_f_1 =%08x\n", RNG_f_1);
log_cb( RETRO_LOG_DEBUG,"rng_delay=%08x\n", RNG_delay);
logerror("rng_f_0 =%08x\n", RNG_f_0);
logerror("rng_f_1 =%08x\n", RNG_f_1);
logerror("rng_delay=%08x\n", RNG_delay);
/* 0 means no particular part so we allow 1 cycle */
c_value = ((double)(1<<PRECISION_SH)) / 1.0;
speeds[0] = c_value * scaler; /* scaled to our sample rate */
log_cb( RETRO_LOG_DEBUG,"speed[%2i]=%08x\n", 0, speeds[0]);
logerror("speed[%2i]=%08x\n", 0, speeds[0]);
for (i = 1; i < 256; i++)
{
@ -699,13 +735,13 @@ altogether which corresponds to 1254 chip clock cycles. 13 samples = 543 cycles,
}
c_value = ((double)(1<<PRECISION_SH)) / ((double)cycles_num);
speeds[i] = c_value * scaler; /* scaled to our sample rate */
log_cb( RETRO_LOG_DEBUG,"speed[%2i]=%08x\n", i, speeds[i]);
logerror("speed[%2i]=%08x\n", i, speeds[i]);
}
/* special case for sustain param =0, which takes 1003 cycles */
c_value = ((double)(1<<PRECISION_SH)) / 1003.0;
speeds[256] = c_value * scaler; /* scaled to our sample rate */
log_cb( RETRO_LOG_DEBUG,"speed[%2i]=%08x\n", 256, speeds[256]);
logerror("speed[%2i]=%08x\n", 256, speeds[256]);
namco_54xx_sh_reset();

View File

@ -1,13 +1,42 @@
#ifndef namco54_h
#define namco54_h
/*
* The 4 bit output of each channel is passed through a bandpass filter.
* D0 - D3 are probably TTL level. I will round it up to 4V until measured.
* R1, R2, R3, C1, C2 select the filter specs. R4 is for mixing.
*
* 4.7k
* D3 >--ZZZZ--. .--------+---------.
* | | | |
* 10k | --- c1 Z |
* D2 >--ZZZZ--+ --- Z r3 |
* | | Z |
* 22k | r1 | c2 | |\ 5V |
* D1 >--ZZZZ--+-----ZZZZ----+---------+--||----+ | \| |
* | Z '--|- \ | r4
* 47k | Z r2 | >--+----ZZZZ--> out
* D0 >--ZZZZ--' Z .--|+ /
* | | | /|
* gnd 2V >---' |/ gnd
*
*/
struct namco_54xx_interface
{
int baseclock; /* clock */
int mixing_level[3]; /* volume of the 3 output ports */
int baseclock; /* clock */
int mixing_level; /* volume */
double r1[3];
double r2[3];
double r3[3];
double r4[3];
double c1[3];
double c2[3];
};
int namco_54xx_sh_start(const struct MachineSound *msound);
void namco_54xx_sh_reset(void);
void namco_54xx_sh_stop(void);
void namcoio_54XX_write(int data);

View File

@ -25,10 +25,7 @@ static void (*stream_callback[MIXER_MAX_CHANNELS])(int param,INT16 *buffer,int l
static void (*stream_callback_multi[MIXER_MAX_CHANNELS])(int param,INT16 **buffer,int length);
static int memory[MIXER_MAX_CHANNELS];
static int r1[MIXER_MAX_CHANNELS];
static int r2[MIXER_MAX_CHANNELS];
static int r3[MIXER_MAX_CHANNELS];
static int c[MIXER_MAX_CHANNELS];
static int k[MIXER_MAX_CHANNELS];
/*
signal >--R1--+--R2--+
@ -42,43 +39,49 @@ signal >--R1--+--R2--+
/* set C = 0 to disable the filter */
void set_RC_filter(int channel,int R1,int R2,int R3,int C)
{
r1[channel] = R1;
r2[channel] = R2;
r3[channel] = R3;
c[channel] = C;
}
stream_update(channel, 0);
void apply_RC_filter(int channel,INT16 *buf,int len,int sample_rate)
{
float R1,R2,R3,C;
float f_R1,f_R2,f_R3,f_C;
float Req;
int K;
int i;
if (C == 0)
{
/* filter disabled */
k[channel] = 0;
return;
}
if (c[channel] == 0) return; /* filter disabled */
R1 = r1[channel];
R2 = r2[channel];
R3 = r3[channel];
C = (float)c[channel] * 1E-12; /* convert pF to F */
f_R1 = R1;
f_R2 = R2;
f_R3 = R3;
f_C = (float)C * 1E-12; /* convert pF to F */
/* Cut Frequency = 1/(2*Pi*Req*C) */
Req = (R1*(R2+R3))/(R1+R2+R3);
Req = (f_R1 * (f_R2 + f_R3)) / (f_R1 + f_R2 + f_R3);
K = 0x10000 * (1 - (exp(-1 / (Req * C) / sample_rate)));
/* k = (1-(EXP(-TIMEDELTA/RC))) */
k[channel] = 0x10000 * (1 - (exp(-1 / (Req * f_C) / stream_sample_rate[channel])));
}
buf[0] = buf[0] + (memory[channel] - buf[0]) * K / 0x10000;
void apply_RC_filter(int channel,int len)
{
int i;
INT16 *buf = stream_buffer[channel];
if (len == 0 || k[channel] == 0) return;
/* Next Value = PREV + (INPUT_VALUE - PREV) * k */
buf[0] = memory[channel] + ((int)(buf[0] - memory[channel]) * k[channel] / 0x10000);
for (i = 1;i < len;i++)
buf[i] = buf[i] + (buf[i-1] - buf[i]) * K / 0x10000;
buf[i] = buf[i-1] + ((int)(buf[i] - buf[i-1]) * k[channel] / 0x10000);
memory[channel] = buf[len-1];
}
int streams_sh_start(void)
{
int i;
@ -144,7 +147,7 @@ void streams_sh_update(void)
stream_buffer_pos[channel+i] = 0;
for (i = 0;i < stream_joined_channels[channel];i++)
apply_RC_filter(channel+i,stream_buffer[channel+i],buflen,stream_sample_rate[channel+i]);
apply_RC_filter(channel+i,buflen);
}
else
{
@ -160,7 +163,7 @@ void streams_sh_update(void)
stream_buffer_pos[channel] = 0;
apply_RC_filter(channel,stream_buffer[channel],buflen,stream_sample_rate[channel]);
apply_RC_filter(channel,buflen);
}
}
}