summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/msm5232.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/msm5232.cpp')
-rw-r--r--src/devices/sound/msm5232.cpp269
1 files changed, 117 insertions, 152 deletions
diff --git a/src/devices/sound/msm5232.cpp b/src/devices/sound/msm5232.cpp
index 7bcaf059d5d..1e05483b6e9 100644
--- a/src/devices/sound/msm5232.cpp
+++ b/src/devices/sound/msm5232.cpp
@@ -30,11 +30,9 @@ void msm5232_device::device_start()
int rate = clock()/CLOCK_RATE_DIVIDER;
int voicenum;
- m_gate_handler_cb.resolve();
-
init(clock(), rate);
- m_stream = machine().sound().stream_alloc(*this, 0, 11, rate);
+ m_stream = stream_alloc(0, 11, rate);
/* register with the save state system */
save_item(NAME(m_EN_out16));
@@ -80,12 +78,10 @@ void msm5232_device::device_start()
void msm5232_device::device_reset()
{
- int i;
-
- for (i=0; i<8; i++)
+ for (int i=0; i<8; i++)
{
- write(machine().dummy_space(), i, 0x80);
- write(machine().dummy_space(), i, 0x00);
+ write(i, 0x80);
+ write(i, 0x00);
}
m_noise_cnt = 0;
m_noise_rng = 1;
@@ -112,7 +108,7 @@ void msm5232_device::device_reset()
void msm5232_device::device_stop()
{
- #ifdef SAVE_SAMPLE
+#ifdef SAVE_SAMPLE
fclose(sample[8]);
#endif
#ifdef SAVE_SEPARATE_CHANNELS
@@ -129,22 +125,22 @@ void msm5232_device::device_stop()
void msm5232_device::set_capacitors(double cap1, double cap2, double cap3, double cap4, double cap5, double cap6, double cap7, double cap8)
{
- m_external_capacity[0] = cap1;
- m_external_capacity[1] = cap2;
- m_external_capacity[2] = cap3;
- m_external_capacity[3] = cap4;
- m_external_capacity[4] = cap5;
- m_external_capacity[5] = cap6;
- m_external_capacity[6] = cap7;
- m_external_capacity[7] = cap8;
+ m_external_capacitance[0] = cap1;
+ m_external_capacitance[1] = cap2;
+ m_external_capacitance[2] = cap3;
+ m_external_capacitance[3] = cap4;
+ m_external_capacitance[4] = cap5;
+ m_external_capacitance[5] = cap6;
+ m_external_capacitance[6] = cap7;
+ m_external_capacitance[7] = cap8;
}
-/* Default chip clock is 2119040 Hz */
-/* At this clock chip generates exactly 440.0 Hz signal on 8' output when pitch data=0x21 */
+// Default chip clock is 2119040 Hz
+// At this clock chip generates exactly 440.0 Hz signal on 8' output when pitch data=0x21
-/* ROM table to convert from pitch data into data for programmable counter and binary counter */
-/* Chip has 88x12bits ROM (addressing (in hex) from 0x00 to 0x57) */
+// ROM table to convert from pitch data into data for programmable counter and binary counter
+// Chip has 88x12bits ROM (addressing (in hex) from 0x00 to 0x57)
#define ROM(counter,bindiv) (counter|(bindiv<<9))
static const uint16_t MSM5232_ROM[88]={
@@ -201,87 +197,63 @@ static FILE *sample[9];
/*
- * resistance values are guesswork, default capacity is mentioned in the datasheets
+ * Resistance values are guesswork, default capacitance is mentioned in the datasheets
+ *
+ * Two errors in the datasheet, one probable, one certain
+ * - it mentions 0.39uF caps, but most boards have 1uF caps and expect datasheet timings
+ *
+ * - the 330ms timing of decay2 has been measured to be 250ms (which
+ * also matches the duty cycle information for the rest of the table)
+ *
+ * In both cases it ends up with smaller resistor values, which are
+ * easier to do on-die.
+ *
+ * The timings are for a 90% charge/discharge of the external
+ * capacitor through three possible resistors, one for attack, two for
+ * decay.
*
- * charges external capacitor (default is 0.39uF) via R51
- * in approx. 5*1400 * 0.39e-6
+ * Expected timings are 2ms, 40ms and 250ms respectively with a 1uF
+ * capacitor.
*
- * external capacitor is discharged through R52
- * in approx. 5*28750 * 0.39e-6
+ * exp(-t/(r*c)) = (100% - 90%) => r = -r/(log(0.1)*c)
+ *
+ * 2ms -> 870 ohms
+ * 40ms -> 17400 ohms
+ * 250ms -> 101000 ohms
*/
-#define R51 1400 /* charge resistance */
-#define R52 28750 /* discharge resistance */
-
-#if 0
-/*
- C24 = external capacity
-
- osd_printf_debug("Time constant T=R*C =%f sec.\n",R51*C24);
- osd_printf_debug("Cap fully charged after 5T=%f sec (sample=%f). Level=%f\n",(R51*C24)*5,(R51*C24)*5*sample_rate , VMAX*0.99326 );
- osd_printf_debug("Cap charged after 5T=%f sec (sample=%f). Level=%20.16f\n",(R51*C24)*5,(R51*C24)*5*sample_rate ,
- VMAX*(1.0-pow(2.718,-0.0748/(R51*C24))) );
-*/
-#endif
-
-
+static constexpr double R51 = 870; // attack resistance
+static constexpr double R52 = 17400; // decay 1 resistance
+static constexpr double R53 = 101000; // decay 2 resistance
void msm5232_device::init_tables()
{
- int i;
- double scale;
+ // sample rate = chip clock !!! But :
+ // highest possible frequency is chipclock/13/16 (pitch data=0x57)
+ // at 2MHz : 2000000/13/16 = 9615 Hz
- /* sample rate = chip clock !!! But : */
- /* highest possible frequency is chipclock/13/16 (pitch data=0x57) */
- /* at 2MHz : 2000000/13/16 = 9615 Hz */
+ m_UpdateStep = int(double(1 << STEP_SH) * double(m_rate) / double(m_chip_clock));
+ //logerror("clock=%i Hz rate=%i Hz, UpdateStep=%i\n", m_chip_clock, m_rate, m_UpdateStep);
- i = ((double)(1<<STEP_SH) * (double)m_rate) / (double)m_chip_clock;
- m_UpdateStep = i;
- /* logerror("clock=%i Hz rate=%i Hz, UpdateStep=%i\n",
- m_chip_clock, m_rate, m_UpdateStep); */
+ double const scale = double(m_chip_clock) / double(m_rate);
+ m_noise_step = ((1 << STEP_SH) / 128.0) * scale; // step of the rng reg in 16.16 format
+ //logerror("noise step=%8x\n", m_noise_step);
- scale = ((double)m_chip_clock) / (double)m_rate;
- m_noise_step = ((1<<STEP_SH)/128.0) * scale; /* step of the rng reg in 16.16 format */
- /* logerror("noise step=%8x\n", m_noise_step); */
-
-#if 0
-{
- /* rate tables (in milliseconds) */
- static const int ATBL[8] = { 2,4,8,16, 32,64, 32,64};
- static const int DTBL[16]= { 40,80,160,320, 640,1280, 640,1280,
- 333,500,1000,2000, 4000,8000, 4000,8000};
- for (i=0; i<8; i++)
+ for (int i = 0; i < 8; i++)
{
- double clockscale = (double)m_chip_clock / 2119040.0;
- double time = (ATBL[i] / 1000.0) / clockscale; /* attack time in seconds */
- m_ar_tbl[i] = 0.50 * ( (1.0/time) / (double)m_rate );
- /* logerror("ATBL[%i] = %20.16f time = %f s\n",i, m_ar_tbl[i], time); */
+ double const clockscale = double(m_chip_clock) / 2119040.0;
+ int const rcp_duty_cycle = 1 << ((i & 4) ? (i & ~2) : i); // bit 1 is ignored if bit 2 is set
+ m_ar_tbl[i] = (rcp_duty_cycle / clockscale) * R51;
}
- for (i=0; i<16; i++)
+ for (int i = 0; i < 8; i++)
{
- double clockscale = (double)m_chip_clock / 2119040.0;
- double time = (DTBL[i] / 1000.0) / clockscale; /* decay time in seconds */
- m_dr_tbl[i] = 0.50 * ( (1.0/time) / (double)m_rate );
- /* logerror("DTBL[%i] = %20.16f time = %f s\n",i, m_dr_tbl[i], time); */
- }
-}
-#endif
-
-
- for (i=0; i<8; i++)
- {
- double clockscale = (double)m_chip_clock / 2119040.0;
- m_ar_tbl[i] = ((1<<i) / clockscale) * (double)R51;
- }
-
- for (i=0; i<8; i++)
- {
- double clockscale = (double)m_chip_clock / 2119040.0;
- m_dr_tbl[i] = ( (1<<i) / clockscale) * (double)R52;
- m_dr_tbl[i+8] = (6.25*(1<<i) / clockscale) * (double)R52;
+ double const clockscale = double(m_chip_clock) / 2119040.0;
+ int const rcp_duty_cycle = 1 << ((i & 4) ? (i & ~2) : i); // bit 1 is ignored if bit 2 is set
+ m_dr_tbl[i] = (rcp_duty_cycle / clockscale) * R52;
+ m_dr_tbl[i + 8] = (rcp_duty_cycle / clockscale) * R53;
}
@@ -303,9 +275,9 @@ void msm5232_device::init_tables()
void msm5232_device::init_voice(int i)
{
- m_voi[i].ar_rate= m_ar_tbl[0] * m_external_capacity[i];
- m_voi[i].dr_rate= m_dr_tbl[0] * m_external_capacity[i];
- m_voi[i].rr_rate= m_dr_tbl[0] * m_external_capacity[i]; /* this is constant value */
+ m_voi[i].ar_rate= m_ar_tbl[0] * m_external_capacitance[i];
+ m_voi[i].dr_rate= m_dr_tbl[0] * m_external_capacitance[i];
+ m_voi[i].rr_rate= m_dr_tbl[0] * m_external_capacitance[i]; /* this is constant value */
m_voi[i].eg_sect= -1;
m_voi[i].eg = 0.0;
m_voi[i].eg_arm = 0;
@@ -317,7 +289,7 @@ void msm5232_device::gate_update()
{
int new_state = (m_control2 & 0x20) ? m_voi[7].GF : 0;
- if (m_gate != new_state && !m_gate_handler_cb.isnull())
+ if (m_gate != new_state)
{
m_gate = new_state;
m_gate_handler_cb(new_state);
@@ -341,24 +313,24 @@ void msm5232_device::init(int clock, int rate)
}
-WRITE8_MEMBER( msm5232_device::write )
+void msm5232_device::write(offs_t offset, uint8_t data)
{
if (offset > 0x0d)
return;
- m_stream->update ();
+ m_stream->update();
if (offset < 0x08) /* pitch */
{
- int ch = offset&7;
+ const int ch = offset & 7;
- m_voi[ch].GF = ((data&0x80)>>7);
+ m_voi[ch].GF = BIT(data, 7);
if (ch == 7)
gate_update();
- if(data&0x80)
+ if (data & 0x80)
{
- if(data >= 0xd8)
+ if (data >= 0xd8)
{
/*if ((data&0x7f) != 0x5f) logerror("MSM5232: WRONG PITCH CODE = %2x\n",data&0x7f);*/
m_voi[ch].mode = 1; /* noise mode */
@@ -366,30 +338,29 @@ WRITE8_MEMBER( msm5232_device::write )
}
else
{
- if ( m_voi[ch].pitch != (data&0x7f) )
+ if (m_voi[ch].pitch != (data & 0x7f))
{
int n;
- uint16_t pg;
- m_voi[ch].pitch = data&0x7f;
+ m_voi[ch].pitch = data & 0x7f;
- pg = MSM5232_ROM[ data&0x7f ];
+ const uint32_t pg = MSM5232_ROM[data & 0x7f];
m_voi[ch].TG_count_period = (pg & 0x1ff) * m_UpdateStep / 2;
- n = (pg>>9) & 7; /* n = bit number for 16' output */
+ n = (pg >> 9) & 7; /* n = bit number for 16' output */
m_voi[ch].TG_out16 = 1<<n;
/* for 8' it is bit n-1 (bit 0 if n-1<0) */
/* for 4' it is bit n-2 (bit 0 if n-2<0) */
/* for 2' it is bit n-3 (bit 0 if n-3<0) */
- n = (n>0)? n-1: 0;
- m_voi[ch].TG_out8 = 1<<n;
+ n = (n > 0) ? (n - 1) : 0;
+ m_voi[ch].TG_out8 = 1 << n;
- n = (n>0)? n-1: 0;
- m_voi[ch].TG_out4 = 1<<n;
+ n = (n > 0) ? (n - 1) : 0;
+ m_voi[ch].TG_out4 = 1 << n;
- n = (n>0)? n-1: 0;
- m_voi[ch].TG_out2 = 1<<n;
+ n = (n > 0) ? (n - 1) : 0;
+ m_voi[ch].TG_out2 = 1 << n;
}
m_voi[ch].mode = 0; /* tone mode */
m_voi[ch].eg_sect = 0; /* Key On */
@@ -397,35 +368,34 @@ WRITE8_MEMBER( msm5232_device::write )
}
else
{
- if ( !m_voi[ch].eg_arm ) /* arm = 0 */
+ if (!m_voi[ch].eg_arm) /* arm = 0 */
m_voi[ch].eg_sect = 2; /* Key Off -> go to release */
- else /* arm = 1 */
+ else /* arm = 1 */
m_voi[ch].eg_sect = 1; /* Key Off -> go to decay */
}
}
else
{
- int i;
switch(offset)
{
case 0x08: /* group1 attack */
- for (i=0; i<4; i++)
- m_voi[i].ar_rate = m_ar_tbl[data&0x7] * m_external_capacity[i];
+ for (int i = 0; i < 4; i++)
+ m_voi[i].ar_rate = m_ar_tbl[data & 0x7] * m_external_capacitance[i];
break;
case 0x09: /* group2 attack */
- for (i=0; i<4; i++)
- m_voi[i+4].ar_rate = m_ar_tbl[data&0x7] * m_external_capacity[i+4];
+ for (int i = 0; i < 4; i++)
+ m_voi[i + 4].ar_rate = m_ar_tbl[data & 0x7] * m_external_capacitance[i+4];
break;
case 0x0a: /* group1 decay */
- for (i=0; i<4; i++)
- m_voi[i].dr_rate = m_dr_tbl[data&0xf] * m_external_capacity[i];
+ for (int i = 0; i < 4; i++)
+ m_voi[i].dr_rate = m_dr_tbl[data & 0xf] * m_external_capacitance[i];
break;
case 0x0b: /* group2 decay */
- for (i=0; i<4; i++)
- m_voi[i+4].dr_rate = m_dr_tbl[data&0xf] * m_external_capacity[i+4];
+ for (int i = 0; i < 4; i++)
+ m_voi[i + 4].dr_rate = m_dr_tbl[data & 0xf] * m_external_capacitance[i + 4];
break;
case 0x0c: /* group1 control */
@@ -438,13 +408,17 @@ WRITE8_MEMBER( msm5232_device::write )
m_control1 = data;
- for (i=0; i<4; i++)
- m_voi[i].eg_arm = data&0x10;
+ for (int i = 0; i < 4; i++)
+ {
+ if ((data & 0x10) && (m_voi[i].eg_sect == 1))
+ m_voi[i].eg_sect = 0;
+ m_voi[i].eg_arm = data & 0x10;
+ }
- m_EN_out16[0] = (data&1) ? ~0:0;
- m_EN_out8[0] = (data&2) ? ~0:0;
- m_EN_out4[0] = (data&4) ? ~0:0;
- m_EN_out2[0] = (data&8) ? ~0:0;
+ m_EN_out16[0] = (data & 1) ? ~0 : 0;
+ m_EN_out8[0] = (data & 2) ? ~0 : 0;
+ m_EN_out4[0] = (data & 4) ? ~0 : 0;
+ m_EN_out2[0] = (data & 8) ? ~0 : 0;
break;
@@ -459,8 +433,12 @@ WRITE8_MEMBER( msm5232_device::write )
m_control2 = data;
gate_update();
- for (i=0; i<4; i++)
- m_voi[i+4].eg_arm = data&0x10;
+ for (int i = 0; i < 4; i++)
+ {
+ if ((data & 0x10) && (m_voi[i + 4].eg_sect == 1))
+ m_voi[i + 4].eg_sect = 0;
+ m_voi[i + 4].eg_arm = data & 0x10;
+ }
m_EN_out16[1] = (data&1) ? ~0:0;
m_EN_out8[1] = (data&2) ? ~0:0;
@@ -730,31 +708,18 @@ void msm5232_device::set_clock(int clock)
// sound_stream_update - handle a stream update
//-------------------------------------------------
-void msm5232_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+void msm5232_device::sound_stream_update(sound_stream &stream)
{
- stream_sample_t *buf1 = outputs[0];
- stream_sample_t *buf2 = outputs[1];
- stream_sample_t *buf3 = outputs[2];
- stream_sample_t *buf4 = outputs[3];
- stream_sample_t *buf5 = outputs[4];
- stream_sample_t *buf6 = outputs[5];
- stream_sample_t *buf7 = outputs[6];
- stream_sample_t *buf8 = outputs[7];
- stream_sample_t *bufsolo1 = outputs[8];
- stream_sample_t *bufsolo2 = outputs[9];
- stream_sample_t *bufnoise = outputs[10];
- int i;
-
- for (i=0; i<samples; i++)
+ for (int i=0; i<stream.samples(); i++)
{
/* calculate all voices' envelopes */
EG_voices_advance();
TG_group_advance(0); /* calculate tones group 1 */
- buf1[i] = o2;
- buf2[i] = o4;
- buf3[i] = o8;
- buf4[i] = o16;
+ stream.put_int(0, i, o2, 32768);
+ stream.put_int(1, i, o4, 32768);
+ stream.put_int(2, i, o8, 32768);
+ stream.put_int(3, i, o16, 32768);
SAVE_SINGLE_CHANNEL(0,o2)
SAVE_SINGLE_CHANNEL(1,o4)
@@ -762,13 +727,13 @@ void msm5232_device::sound_stream_update(sound_stream &stream, stream_sample_t *
SAVE_SINGLE_CHANNEL(3,o16)
TG_group_advance(1); /* calculate tones group 2 */
- buf5[i] = o2;
- buf6[i] = o4;
- buf7[i] = o8;
- buf8[i] = o16;
+ stream.put_int(4, i, o2, 32768);
+ stream.put_int(5, i, o4, 32768);
+ stream.put_int(6, i, o8, 32768);
+ stream.put_int(7, i, o16, 32768);
- bufsolo1[i] = solo8;
- bufsolo2[i] = solo16;
+ stream.put_int(8, i, solo8, 32768);
+ stream.put_int(9, i, solo16, 32768);
SAVE_SINGLE_CHANNEL(4,o2)
SAVE_SINGLE_CHANNEL(5,o4)
@@ -796,6 +761,6 @@ void msm5232_device::sound_stream_update(sound_stream &stream, stream_sample_t *
}
}
- bufnoise[i] = (m_noise_rng & (1<<16)) ? 32767 : 0;
+ stream.put(10, i, (m_noise_rng & (1<<16)) ? 1.0 : 0.0);
}
}