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.regs));
save_item(NAME(m_APU.tri.linear_length)); 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.vbl_length));
save_item(NAME(m_APU.tri.write_latency)); save_item(NAME(m_APU.tri.write_latency));
save_item(NAME(m_APU.tri.phaseacc)); 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.counter_started));
save_item(NAME(m_APU.tri.enabled)); save_item(NAME(m_APU.tri.enabled));
save_item(NAME(m_APU.tri.output)); 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.regs));
save_item(NAME(m_APU.noi.seed)); 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) */ /* OUTPUT TRIANGLE WAVE SAMPLE (VALUES FROM 0 to +15) */
void nesapu_device::apu_triangle(apu_t::triangle_t *chan) void nesapu_device::apu_triangle(apu_t::triangle_t *chan)
{ {
int freq;
/* reg0: 7=holdnote, 6-0=linear length counter /* reg0: 7=holdnote, 6-0=linear length counter
** reg2: low 8 bits of frequency ** reg2: low 8 bits of frequency
** reg3: 7-3=length counter, 2-0=high 3 bits of frequency ** reg3: 7-3=length counter, 2-0=high 3 bits of frequency
*/ */
if (!chan->enabled) if (!chan->enabled)
{
chan->output = 0;
return; 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) if (chan->write_latency)
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->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--; chan->linear_length--;
if (chan->vbl_length && !(chan->regs[0] & 0x80))
chan->vbl_length--;
if (!chan->vbl_length) if (not_held)
{ chan->linear_reload = false;
chan->output = 0;
return; if (chan->vbl_length && not_held)
} chan->vbl_length--;
} }
if (!chan->linear_length) if (!(chan->linear_length && chan->vbl_length))
{
chan->output = 0;
return; 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 */ // 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)
chan->output = 0;
return; return;
}
chan->phaseacc -= 4; chan->phaseacc -= 4;
while (chan->phaseacc < 0) while (chan->phaseacc < 0)
{ {
chan->phaseacc += freq; chan->phaseacc += freq;
chan->adder = (chan->adder + 1) & 0x1f; chan->adder++;
if (chan->adder & 0x10) chan->output = chan->adder & 0xf;
chan->output_next = chan->adder & 0xf; if (!BIT(chan->adder, 4))
else chan->output ^= 0xf;
chan->output_next = 0xf - (chan->adder & 0xf);
} }
chan->output = chan->output_next;
} }
/* OUTPUT NOISE WAVE SAMPLE (VALUES FROM 0 to +15) */ /* 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.counter_started = false;
m_APU.tri.vbl_length = m_vbl_times[value >> 3]; 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];
m_APU.tri.linear_reload = true;
} }
break; break;

View File

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