mirror of
https://github.com/holub/mame
synced 2025-04-21 07:52:35 +03:00
nes_apu.cpp: Implement non linear mixer output, some misc fixes and improvements (#9258)
* nes_apu.cpp: Implement non linear mixer output, some misc fixes and improvements Fix Pulse channel duty behavior Fix triangle output behavior Fix noise output behavior Fix DMC output and clamp behavior - now DMC output is affects triangle and noise volume. Reference: https://wiki.nesdev.org/w/index.php?title=APU https://wiki.nesdev.org/w/index.php?title=APU_Pulse https://wiki.nesdev.org/w/index.php?title=APU_Triangle https://wiki.nesdev.org/w/index.php?title=APU_Noise https://wiki.nesdev.org/w/index.php?title=APU_DMC https://wiki.nesdev.org/w/index.php?title=APU_Mixer * nes_apu.cpp: Fix mixer output correction Reduce unnecessary variables Split channel update function and output variable Add notes
This commit is contained in:
parent
93ce4b3581
commit
1f99365bbd
@ -143,6 +143,48 @@ void nesapu_device::device_start()
|
||||
|
||||
calculate_rates();
|
||||
|
||||
// calculate mixer output
|
||||
/*
|
||||
pulse channel output:
|
||||
|
||||
95.88
|
||||
-----------------------
|
||||
8128
|
||||
----------------- + 100
|
||||
pulse 1 + pulse 2
|
||||
|
||||
*/
|
||||
for (int i = 0; i < 31; i++)
|
||||
{
|
||||
stream_buffer::sample_t pulse_out = (i == 0) ? 0.0 : 95.88 / ((8128.0 / i) + 100.0);
|
||||
m_square_lut[i] = pulse_out;
|
||||
}
|
||||
|
||||
/*
|
||||
triangle, noise, DMC channel output:
|
||||
|
||||
159.79
|
||||
-------------------------------
|
||||
1
|
||||
------------------------- + 100
|
||||
triangle noise dmc
|
||||
-------- + ----- + -----
|
||||
8227 12241 22638
|
||||
|
||||
*/
|
||||
for (int t = 0; t < 16; t++)
|
||||
{
|
||||
for (int n = 0; n < 16; n++)
|
||||
{
|
||||
for (int d = 0; d < 128; d++)
|
||||
{
|
||||
stream_buffer::sample_t tnd_out = (t / 8227.0) + (n / 12241.0) + (d / 22638.0);
|
||||
tnd_out = (tnd_out == 0.0) ? 0.0 : 159.79 / ((1.0 / tnd_out) + 100.0);
|
||||
m_tnd_lut[t][n][d] = tnd_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* register for save */
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
@ -150,12 +192,12 @@ void nesapu_device::device_start()
|
||||
save_item(NAME(m_APU.squ[i].vbl_length), i);
|
||||
save_item(NAME(m_APU.squ[i].freq), i);
|
||||
save_item(NAME(m_APU.squ[i].phaseacc), i);
|
||||
save_item(NAME(m_APU.squ[i].output_vol), i);
|
||||
save_item(NAME(m_APU.squ[i].env_phase), i);
|
||||
save_item(NAME(m_APU.squ[i].sweep_phase), i);
|
||||
save_item(NAME(m_APU.squ[i].adder), i);
|
||||
save_item(NAME(m_APU.squ[i].env_vol), i);
|
||||
save_item(NAME(m_APU.squ[i].enabled), i);
|
||||
save_item(NAME(m_APU.squ[i].output), i);
|
||||
}
|
||||
|
||||
save_item(NAME(m_APU.tri.regs));
|
||||
@ -163,30 +205,31 @@ void nesapu_device::device_start()
|
||||
save_item(NAME(m_APU.tri.vbl_length));
|
||||
save_item(NAME(m_APU.tri.write_latency));
|
||||
save_item(NAME(m_APU.tri.phaseacc));
|
||||
save_item(NAME(m_APU.tri.output_vol));
|
||||
save_item(NAME(m_APU.tri.adder));
|
||||
save_item(NAME(m_APU.tri.counter_started));
|
||||
save_item(NAME(m_APU.tri.enabled));
|
||||
save_item(NAME(m_APU.tri.output));
|
||||
save_item(NAME(m_APU.tri.output_next));
|
||||
|
||||
save_item(NAME(m_APU.noi.regs));
|
||||
save_item(NAME(m_APU.noi.seed));
|
||||
save_item(NAME(m_APU.noi.vbl_length));
|
||||
save_item(NAME(m_APU.noi.phaseacc));
|
||||
save_item(NAME(m_APU.noi.output_vol));
|
||||
save_item(NAME(m_APU.noi.env_phase));
|
||||
save_item(NAME(m_APU.noi.env_vol));
|
||||
save_item(NAME(m_APU.noi.enabled));
|
||||
save_item(NAME(m_APU.noi.output));
|
||||
|
||||
save_item(NAME(m_APU.dpcm.regs));
|
||||
save_item(NAME(m_APU.dpcm.address));
|
||||
save_item(NAME(m_APU.dpcm.length));
|
||||
save_item(NAME(m_APU.dpcm.bits_left));
|
||||
save_item(NAME(m_APU.dpcm.phaseacc));
|
||||
save_item(NAME(m_APU.dpcm.output_vol));
|
||||
save_item(NAME(m_APU.dpcm.cur_byte));
|
||||
save_item(NAME(m_APU.dpcm.enabled));
|
||||
save_item(NAME(m_APU.dpcm.irq_occurred));
|
||||
save_item(NAME(m_APU.dpcm.vol));
|
||||
save_item(NAME(m_APU.dpcm.output));
|
||||
|
||||
save_item(NAME(m_APU.regs));
|
||||
|
||||
@ -202,12 +245,11 @@ void nesapu_device::device_start()
|
||||
|
||||
/* TODO: sound channels should *ALL* have DC volume decay */
|
||||
|
||||
/* OUTPUT SQUARE WAVE SAMPLE (VALUES FROM -16 to +15) */
|
||||
s8 nesapu_device::apu_square(apu_t::square_t *chan)
|
||||
/* OUTPUT SQUARE WAVE SAMPLE (VALUES FROM 0 to +15) */
|
||||
void nesapu_device::apu_square(apu_t::square_t *chan)
|
||||
{
|
||||
int env_delay;
|
||||
int sweep_delay;
|
||||
s8 output;
|
||||
|
||||
/* reg0: 0-3=volume, 4=envelope, 5=hold, 6-7=duty cycle
|
||||
** reg1: 0-2=sweep shifts, 3=sweep inc/dec, 4-6=sweep length, 7=sweep on
|
||||
@ -215,11 +257,14 @@ s8 nesapu_device::apu_square(apu_t::square_t *chan)
|
||||
** reg3: 0-2=high freq, 7-4=vbl length counter
|
||||
*/
|
||||
|
||||
if (false == chan->enabled)
|
||||
return 0;
|
||||
if (!chan->enabled)
|
||||
{
|
||||
chan->output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* enveloping */
|
||||
env_delay = m_sync_times1[chan->regs[0] & 0x0F];
|
||||
env_delay = m_sync_times1[chan->regs[0] & 0x0f];
|
||||
|
||||
/* decay is at a rate of (env_regs + 1) / 240 secs */
|
||||
chan->env_phase -= 4;
|
||||
@ -233,11 +278,14 @@ s8 nesapu_device::apu_square(apu_t::square_t *chan)
|
||||
}
|
||||
|
||||
/* vbl length counter */
|
||||
if (chan->vbl_length > 0 && 0 == (chan->regs [0] & 0x20))
|
||||
if (chan->vbl_length > 0 && !(chan->regs[0] & 0x20))
|
||||
chan->vbl_length--;
|
||||
|
||||
if (0 == chan->vbl_length)
|
||||
return 0;
|
||||
if (!chan->vbl_length)
|
||||
{
|
||||
chan->output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* freqsweeps */
|
||||
if ((chan->regs[1] & 0x80) && (chan->regs[1] & 7))
|
||||
@ -254,47 +302,49 @@ s8 nesapu_device::apu_square(apu_t::square_t *chan)
|
||||
}
|
||||
}
|
||||
|
||||
if ((0 == (chan->regs[1] & 8) && (chan->freq >> 16) > freq_limit[chan->regs[1] & 7])
|
||||
if ((!(chan->regs[1] & 8) && (chan->freq >> 16) > freq_limit[chan->regs[1] & 7])
|
||||
|| (chan->freq >> 16) < 4)
|
||||
return 0;
|
||||
{
|
||||
chan->output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
chan->phaseacc -= 4;
|
||||
|
||||
while (chan->phaseacc < 0)
|
||||
{
|
||||
chan->phaseacc += (chan->freq >> 16);
|
||||
chan->adder = (chan->adder + 1) & 0x0F;
|
||||
chan->adder = (chan->adder + 1) & 0x0f;
|
||||
}
|
||||
|
||||
if (chan->regs[0] & 0x10) /* fixed volume */
|
||||
output = chan->regs[0] & 0x0F;
|
||||
chan->output = chan->regs[0] & 0x0f;
|
||||
else
|
||||
output = 0x0F - chan->env_vol;
|
||||
chan->output = 0x0f - chan->env_vol;
|
||||
|
||||
if (chan->adder < (duty_lut[chan->regs[0] >> 6]))
|
||||
output = -output;
|
||||
|
||||
return (s8) output;
|
||||
chan->output *= BIT(duty_lut[chan->regs[0] >> 6], 7 - BIT(chan->adder, 1, 3));
|
||||
}
|
||||
|
||||
/* OUTPUT TRIANGLE WAVE SAMPLE (VALUES FROM -16 to +15) */
|
||||
s8 nesapu_device::apu_triangle(apu_t::triangle_t *chan)
|
||||
/* OUTPUT TRIANGLE WAVE SAMPLE (VALUES FROM 0 to +15) */
|
||||
void nesapu_device::apu_triangle(apu_t::triangle_t *chan)
|
||||
{
|
||||
int freq;
|
||||
s8 output;
|
||||
/* reg0: 7=holdnote, 6-0=linear length counter
|
||||
** reg2: low 8 bits of frequency
|
||||
** reg3: 7-3=length counter, 2-0=high 3 bits of frequency
|
||||
*/
|
||||
|
||||
if (false == chan->enabled)
|
||||
return 0;
|
||||
if (!chan->enabled)
|
||||
{
|
||||
chan->output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (false == chan->counter_started && 0 == (chan->regs[0] & 0x80))
|
||||
if (!chan->counter_started && !(chan->regs[0] & 0x80))
|
||||
{
|
||||
if (chan->write_latency)
|
||||
chan->write_latency--;
|
||||
if (0 == chan->write_latency)
|
||||
if (!chan->write_latency)
|
||||
chan->counter_started = true;
|
||||
}
|
||||
|
||||
@ -302,56 +352,63 @@ s8 nesapu_device::apu_triangle(apu_t::triangle_t *chan)
|
||||
{
|
||||
if (chan->linear_length > 0)
|
||||
chan->linear_length--;
|
||||
if (chan->vbl_length && 0 == (chan->regs[0] & 0x80))
|
||||
if (chan->vbl_length && !(chan->regs[0] & 0x80))
|
||||
chan->vbl_length--;
|
||||
|
||||
if (0 == chan->vbl_length)
|
||||
return 0;
|
||||
if (!chan->vbl_length)
|
||||
{
|
||||
chan->output = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == chan->linear_length)
|
||||
return 0;
|
||||
if (!chan->linear_length)
|
||||
{
|
||||
chan->output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
freq = (((chan->regs[3] & 7) << 8) + chan->regs[2]) + 1;
|
||||
|
||||
if (freq < 4) /* inaudible */
|
||||
return 0;
|
||||
{
|
||||
chan->output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
chan->phaseacc -= 4;
|
||||
while (chan->phaseacc < 0)
|
||||
{
|
||||
chan->phaseacc += freq;
|
||||
chan->adder = (chan->adder + 1) & 0x1F;
|
||||
chan->adder = (chan->adder + 1) & 0x1f;
|
||||
|
||||
output = (chan->adder & 7) << 1;
|
||||
if (chan->adder & 8)
|
||||
output = 0x10 - output;
|
||||
if (chan->adder & 0x10)
|
||||
output = -output;
|
||||
|
||||
chan->output_vol = output;
|
||||
chan->output_next = chan->adder & 0xf;
|
||||
else
|
||||
chan->output_next = 0xf - (chan->adder & 0xf);
|
||||
}
|
||||
|
||||
return (s8) chan->output_vol;
|
||||
chan->output = chan->output_next;
|
||||
}
|
||||
|
||||
/* OUTPUT NOISE WAVE SAMPLE (VALUES FROM -16 to +15) */
|
||||
s8 nesapu_device::apu_noise(apu_t::noise_t *chan)
|
||||
/* OUTPUT NOISE WAVE SAMPLE (VALUES FROM 0 to +15) */
|
||||
void nesapu_device::apu_noise(apu_t::noise_t *chan)
|
||||
{
|
||||
int freq, env_delay;
|
||||
u8 outvol;
|
||||
u8 output;
|
||||
|
||||
/* reg0: 0-3=volume, 4=envelope, 5=hold
|
||||
** reg2: 7=small(93 byte) sample,3-0=freq lookup
|
||||
** reg3: 7-4=vbl length counter
|
||||
*/
|
||||
|
||||
if (false == chan->enabled)
|
||||
return 0;
|
||||
if (!chan->enabled)
|
||||
{
|
||||
chan->output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* enveloping */
|
||||
env_delay = m_sync_times1[chan->regs[0] & 0x0F];
|
||||
env_delay = m_sync_times1[chan->regs[0] & 0x0f];
|
||||
|
||||
/* decay is at a rate of (env_regs + 1) / 240 secs */
|
||||
chan->env_phase -= 4;
|
||||
@ -365,16 +422,19 @@ s8 nesapu_device::apu_noise(apu_t::noise_t *chan)
|
||||
}
|
||||
|
||||
/* length counter */
|
||||
if (0 == (chan->regs[0] & 0x20))
|
||||
if (!(chan->regs[0] & 0x20))
|
||||
{
|
||||
if (chan->vbl_length > 0)
|
||||
chan->vbl_length--;
|
||||
}
|
||||
|
||||
if (0 == chan->vbl_length)
|
||||
return 0;
|
||||
if (!chan->vbl_length)
|
||||
{
|
||||
chan->output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
freq = noise_freq[m_is_pal][chan->regs[2] & 0x0F];
|
||||
freq = noise_freq[m_is_pal][chan->regs[2] & 0x0f];
|
||||
chan->phaseacc -= 4;
|
||||
while (chan->phaseacc < 0)
|
||||
{
|
||||
@ -382,25 +442,22 @@ s8 nesapu_device::apu_noise(apu_t::noise_t *chan)
|
||||
chan->seed = (chan->seed >> 1) | ((BIT(chan->seed, 0) ^ BIT(chan->seed, (chan->regs[2] & 0x80) ? 6 : 1)) << 14);
|
||||
}
|
||||
|
||||
if (BIT(chan->seed, 0)) /* make it silence */
|
||||
{
|
||||
chan->output = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (chan->regs[0] & 0x10) /* fixed volume */
|
||||
outvol = chan->regs[0] & 0x0F;
|
||||
chan->output = chan->regs[0] & 0x0f;
|
||||
else
|
||||
outvol = 0x0F - chan->env_vol;
|
||||
|
||||
output = chan->seed & 0xff;
|
||||
if (output > outvol)
|
||||
output = outvol;
|
||||
|
||||
if (chan->seed & 0x80) /* make it negative */
|
||||
output = -output;
|
||||
|
||||
return (s8) output;
|
||||
chan->output = 0x0f - chan->env_vol;
|
||||
}
|
||||
|
||||
/* RESET DPCM PARAMETERS */
|
||||
static inline void apu_dpcmreset(apu_t::dpcm_t *chan)
|
||||
{
|
||||
chan->address = 0xC000 + u16(chan->regs[2] << 6);
|
||||
chan->address = 0xc000 + u16(chan->regs[2] << 6);
|
||||
chan->length = u16(chan->regs[3] << 4) + 1;
|
||||
chan->bits_left = chan->length << 3;
|
||||
chan->irq_occurred = false;
|
||||
@ -408,9 +465,9 @@ static inline void apu_dpcmreset(apu_t::dpcm_t *chan)
|
||||
chan->vol = 0; /* Fixed * DPCM DAC resets itself when restarted */
|
||||
}
|
||||
|
||||
/* OUTPUT DPCM WAVE SAMPLE (VALUES FROM -64 to +63) */
|
||||
/* OUTPUT DPCM WAVE SAMPLE (VALUES FROM 0 to +127) */
|
||||
/* TODO: centerline naughtiness */
|
||||
s8 nesapu_device::apu_dpcm(apu_t::dpcm_t *chan)
|
||||
void nesapu_device::apu_dpcm(apu_t::dpcm_t *chan)
|
||||
{
|
||||
int freq, bit_pos;
|
||||
|
||||
@ -422,17 +479,17 @@ s8 nesapu_device::apu_dpcm(apu_t::dpcm_t *chan)
|
||||
|
||||
if (chan->enabled)
|
||||
{
|
||||
freq = dpcm_clocks[m_is_pal][chan->regs[0] & 0x0F];
|
||||
freq = dpcm_clocks[m_is_pal][chan->regs[0] & 0x0f];
|
||||
chan->phaseacc -= 4;
|
||||
|
||||
while (chan->phaseacc < 0)
|
||||
{
|
||||
chan->phaseacc += freq;
|
||||
|
||||
if (0 == chan->length)
|
||||
if (!chan->length)
|
||||
{
|
||||
chan->enabled = false; /* Fixed * Proper DPCM channel ENABLE/DISABLE flag behaviour*/
|
||||
chan->vol=0; /* Fixed * DPCM DAC resets itself when restarted */
|
||||
chan->vol = 0; /* Fixed * DPCM DAC resets itself when restarted */
|
||||
if (chan->regs[0] & 0x40)
|
||||
apu_dpcmreset(chan);
|
||||
else
|
||||
@ -456,21 +513,16 @@ s8 nesapu_device::apu_dpcm(apu_t::dpcm_t *chan)
|
||||
chan->length--;
|
||||
}
|
||||
|
||||
if (chan->cur_byte & (1 << bit_pos))
|
||||
// chan->regs[1]++;
|
||||
chan->vol+=2; /* FIXED * DPCM channel only uses the upper 6 bits of the DAC */
|
||||
else
|
||||
// chan->regs[1]--;
|
||||
chan->vol-=2;
|
||||
if ((chan->cur_byte & (1 << bit_pos)) && (chan->vol <= 125))
|
||||
// chan->regs[1] += 2;
|
||||
chan->vol += 2; /* FIXED * DPCM channel only uses the upper 6 bits of the DAC */
|
||||
else if (chan->vol >= 2)
|
||||
// chan->regs[1] -= 2;
|
||||
chan->vol -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan->vol > 63)
|
||||
chan->vol = 63;
|
||||
else if (chan->vol < -64)
|
||||
chan->vol = -64;
|
||||
|
||||
return (s8) (chan->vol);
|
||||
chan->output = (u8)(chan->vol);
|
||||
}
|
||||
|
||||
/* WRITE REGISTER VALUE */
|
||||
@ -517,8 +569,8 @@ inline void nesapu_device::apu_regwrite(int address, u8 value)
|
||||
|
||||
if (m_APU.tri.enabled)
|
||||
{ /* ??? */
|
||||
if (false == m_APU.tri.counter_started)
|
||||
m_APU.tri.linear_length = m_sync_times2[value & 0x7F];
|
||||
if (!m_APU.tri.counter_started)
|
||||
m_APU.tri.linear_length = m_sync_times2[value & 0x7f];
|
||||
}
|
||||
|
||||
break;
|
||||
@ -557,7 +609,7 @@ inline void nesapu_device::apu_regwrite(int address, u8 value)
|
||||
{
|
||||
m_APU.tri.counter_started = false;
|
||||
m_APU.tri.vbl_length = m_vbl_times[value >> 3];
|
||||
m_APU.tri.linear_length = m_sync_times2[m_APU.tri.regs[0] & 0x7F];
|
||||
m_APU.tri.linear_length = m_sync_times2[m_APU.tri.regs[0] & 0x7f];
|
||||
}
|
||||
|
||||
break;
|
||||
@ -589,16 +641,15 @@ inline void nesapu_device::apu_regwrite(int address, u8 value)
|
||||
/* DMC */
|
||||
case apu_t::WRE0:
|
||||
m_APU.dpcm.regs[0] = value;
|
||||
if (0 == (value & 0x80)) {
|
||||
if (!(value & 0x80)) {
|
||||
m_irq_handler(false);
|
||||
m_APU.dpcm.irq_occurred = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case apu_t::WRE1: /* 7-bit DAC */
|
||||
//m_APU.dpcm.regs[1] = value - 0x40;
|
||||
m_APU.dpcm.regs[1] = value & 0x7F;
|
||||
m_APU.dpcm.vol = (m_APU.dpcm.regs[1]-64);
|
||||
m_APU.dpcm.regs[1] = value & 0x7f;
|
||||
m_APU.dpcm.vol = m_APU.dpcm.regs[1];
|
||||
break;
|
||||
|
||||
case apu_t::WRE2:
|
||||
@ -656,7 +707,7 @@ inline void nesapu_device::apu_regwrite(int address, u8 value)
|
||||
if (value & 0x10)
|
||||
{
|
||||
/* only reset dpcm values if DMA is finished */
|
||||
if (false == m_APU.dpcm.enabled)
|
||||
if (!m_APU.dpcm.enabled)
|
||||
{
|
||||
m_APU.dpcm.enabled = true;
|
||||
apu_dpcmreset(&m_APU.dpcm);
|
||||
@ -724,17 +775,20 @@ void nesapu_device::write(offs_t address, u8 value)
|
||||
|
||||
void nesapu_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
|
||||
{
|
||||
int accum;
|
||||
stream_buffer::sample_t accum = 0.0;
|
||||
auto &output = outputs[0];
|
||||
|
||||
for (int sampindex = 0; sampindex < output.samples(); sampindex++)
|
||||
{
|
||||
accum = apu_square(&m_APU.squ[0]);
|
||||
accum += apu_square(&m_APU.squ[1]);
|
||||
accum += apu_triangle(&m_APU.tri);
|
||||
accum += apu_noise(&m_APU.noi);
|
||||
accum += apu_dpcm(&m_APU.dpcm);
|
||||
apu_square(&m_APU.squ[0]);
|
||||
apu_square(&m_APU.squ[1]);
|
||||
apu_triangle(&m_APU.tri);
|
||||
apu_noise(&m_APU.noi);
|
||||
apu_dpcm(&m_APU.dpcm);
|
||||
|
||||
output.put_int_clamp(sampindex, accum, 128);
|
||||
accum = m_square_lut[m_APU.squ[0].output + m_APU.squ[1].output];
|
||||
accum += m_tnd_lut[m_APU.tri.output][m_APU.noi.output][m_APU.dpcm.output];
|
||||
|
||||
output.put(sampindex, accum);
|
||||
}
|
||||
}
|
||||
|
@ -79,16 +79,19 @@ private:
|
||||
u32 m_vbl_times[0x20]; /* VBL durations in samples */
|
||||
u32 m_sync_times1[SYNCS_MAX1]; /* Samples per sync table */
|
||||
u32 m_sync_times2[SYNCS_MAX2]; /* Samples per sync table */
|
||||
stream_buffer::sample_t m_square_lut[31]; // Non-linear Square wave output LUT
|
||||
stream_buffer::sample_t m_tnd_lut[16][16][128]; // Non-linear Triangle, Noise, DMC output LUT
|
||||
|
||||
sound_stream *m_stream;
|
||||
devcb_write_line m_irq_handler;
|
||||
devcb_read8 m_mem_read_cb;
|
||||
|
||||
void calculate_rates();
|
||||
void create_syncs(unsigned long sps);
|
||||
s8 apu_square(apu_t::square_t *chan);
|
||||
s8 apu_triangle(apu_t::triangle_t *chan);
|
||||
s8 apu_noise(apu_t::noise_t *chan);
|
||||
s8 apu_dpcm(apu_t::dpcm_t *chan);
|
||||
void apu_square(apu_t::square_t *chan);
|
||||
void apu_triangle(apu_t::triangle_t *chan);
|
||||
void apu_noise(apu_t::noise_t *chan);
|
||||
void apu_dpcm(apu_t::dpcm_t *chan);
|
||||
inline void apu_regwrite(int address, u8 value);
|
||||
};
|
||||
|
||||
|
@ -56,12 +56,12 @@ struct apu_t
|
||||
int vbl_length = 0;
|
||||
int freq = 0;
|
||||
float phaseacc = 0.0;
|
||||
float output_vol = 0.0;
|
||||
float env_phase = 0.0;
|
||||
float sweep_phase = 0.0;
|
||||
uint8 adder = 0;
|
||||
uint8 env_vol = 0;
|
||||
bool enabled = false;
|
||||
uint8 output = 0;
|
||||
};
|
||||
|
||||
/* Triangle Wave */
|
||||
@ -78,10 +78,11 @@ struct apu_t
|
||||
int vbl_length = 0;
|
||||
int write_latency = 0;
|
||||
float phaseacc = 0.0;
|
||||
float output_vol = 0.0;
|
||||
uint8 adder = 0;
|
||||
bool counter_started = false;
|
||||
bool enabled = false;
|
||||
uint8 output = 0;
|
||||
uint8 output_next = 0;
|
||||
};
|
||||
|
||||
/* Noise Wave */
|
||||
@ -97,10 +98,10 @@ struct apu_t
|
||||
u32 seed = 1;
|
||||
int vbl_length = 0;
|
||||
float phaseacc = 0.0;
|
||||
float output_vol = 0.0;
|
||||
float env_phase = 0.0;
|
||||
uint8 env_vol = 0;
|
||||
bool enabled = false;
|
||||
uint8 output = 0;
|
||||
};
|
||||
|
||||
/* DPCM Wave */
|
||||
@ -117,11 +118,11 @@ struct apu_t
|
||||
uint32 length = 0;
|
||||
int bits_left = 0;
|
||||
float phaseacc = 0.0;
|
||||
float output_vol = 0.0;
|
||||
uint8 cur_byte = 0;
|
||||
bool enabled = false;
|
||||
bool irq_occurred = false;
|
||||
signed char vol = 0;
|
||||
int16 vol = 0;
|
||||
uint8 output = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -225,7 +226,10 @@ static const int dpcm_clocks[2][16] =
|
||||
/* 2/16 = 12.5%, 4/16 = 25%, 8/16 = 50%, 12/16 = 75% */
|
||||
static const int duty_lut[4] =
|
||||
{
|
||||
2, 4, 8, 12
|
||||
0b01000000, // 01000000 (12.5%)
|
||||
0b01100000, // 01100000 (25%)
|
||||
0b01111000, // 01111000 (50%)
|
||||
0b10011111, // 10011111 (25% negated)
|
||||
};
|
||||
|
||||
#endif // MAME_SOUND_NES_DEFS_H
|
||||
|
Loading…
Reference in New Issue
Block a user