nes_apu.cpp: Improvements for triangle channel. (#9310)

- Don't set output level to zero, it is always determined by sequencer, which cannot be reset. This eliminates most of the popping, hopefully.
- Raised artificial frequency cutoff to about 18KHz instead of 11KHz.
- Added linear counter reload flag.
This commit is contained in:
0kmg 2022-02-17 17:39:55 -09:00 committed by GitHub
parent 2db924e5ec
commit 50668b5d5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 31 deletions

View File

@ -202,6 +202,7 @@ void nesapu_device::device_start()
save_item(NAME(m_APU.tri.regs));
save_item(NAME(m_APU.tri.linear_length));
save_item(NAME(m_APU.tri.linear_reload));
save_item(NAME(m_APU.tri.vbl_length));
save_item(NAME(m_APU.tri.write_latency));
save_item(NAME(m_APU.tri.phaseacc));
@ -209,7 +210,6 @@ void nesapu_device::device_start()
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));
@ -328,19 +328,17 @@ void nesapu_device::apu_square(apu_t::square_t *chan)
/* OUTPUT TRIANGLE WAVE SAMPLE (VALUES FROM 0 to +15) */
void nesapu_device::apu_triangle(apu_t::triangle_t *chan)
{
int freq;
/* 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 (!chan->enabled)
{
chan->output = 0;
return;
}
if (!chan->counter_started && !(chan->regs[0] & 0x80))
bool not_held = !BIT(chan->regs[0], 7);
if (!chan->counter_started && not_held)
{
if (chan->write_latency)
chan->write_latency--;
@ -350,45 +348,37 @@ void nesapu_device::apu_triangle(apu_t::triangle_t *chan)
if (chan->counter_started)
{
if (chan->linear_length > 0)
if (chan->linear_reload)
chan->linear_length = m_sync_times2[chan->regs[0] & 0x7f];
else if (chan->linear_length > 0)
chan->linear_length--;
if (chan->vbl_length && !(chan->regs[0] & 0x80))
chan->vbl_length--;
if (!chan->vbl_length)
{
chan->output = 0;
return;
}
if (not_held)
chan->linear_reload = false;
if (chan->vbl_length && not_held)
chan->vbl_length--;
}
if (!chan->linear_length)
{
chan->output = 0;
if (!(chan->linear_length && chan->vbl_length))
return;
}
freq = (((chan->regs[3] & 7) << 8) + chan->regs[2]) + 1;
int freq = ((chan->regs[3] & 7) << 8) + chan->regs[2] + 1;
if (freq < 4) /* inaudible */
{
chan->output = 0;
// FIXME: This halts ultrasonic frequencies. On hardware there should be some popping noise? Crash Man's stage in Mega Man 2 is an example. This can probably be removed if hardware filters are implemented (they vary by machine, NES, FC, VS, etc).
if (freq < 2)
return;
}
chan->phaseacc -= 4;
while (chan->phaseacc < 0)
{
chan->phaseacc += freq;
chan->adder = (chan->adder + 1) & 0x1f;
chan->adder++;
if (chan->adder & 0x10)
chan->output_next = chan->adder & 0xf;
else
chan->output_next = 0xf - (chan->adder & 0xf);
chan->output = chan->adder & 0xf;
if (!BIT(chan->adder, 4))
chan->output ^= 0xf;
}
chan->output = chan->output_next;
}
/* OUTPUT NOISE WAVE SAMPLE (VALUES FROM 0 to +15) */
@ -610,6 +600,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_reload = true;
}
break;

View File

@ -75,6 +75,7 @@ struct apu_t
uint8 regs[4]; /* regs[1] unused */
int linear_length = 0;
bool linear_reload = false;
int vbl_length = 0;
int write_latency = 0;
float phaseacc = 0.0;
@ -82,7 +83,6 @@ struct apu_t
bool counter_started = false;
bool enabled = false;
uint8 output = 0;
uint8 output_next = 0;
};
/* Noise Wave */