Fix pulse channel fails to clock lenght counter when silenced

- Backported implementation from Mednafen-NES
- Reference test roms:
https://forums.nesdev.com/viewtopic.php?t=15346
https://github.com/christopherpow/nes-test-roms/tree/master/apu_mixer
This commit is contained in:
retro-wertz
2018-12-08 19:56:31 +08:00
parent 3b2511a8fe
commit fd5c95e60c

View File

@@ -85,6 +85,9 @@ int32 nesincsize = 0;
uint32 soundtsinc = 0; uint32 soundtsinc = 0;
uint32 soundtsi = 0; uint32 soundtsi = 0;
static int32 sqacc[2]; static int32 sqacc[2];
static uint32 lq_tcout;
static int32 lq_triacc;
static int32 lq_noiseacc;
/* LQ variables segment ends. */ /* LQ variables segment ends. */
static int32 lengthcount[4]; static int32 lengthcount[4];
@@ -126,9 +129,9 @@ static const uint32 PALDMCTable[0x10] =
* $4013 - Size register: Size in bytes = (V+1)*64 * $4013 - Size register: Size in bytes = (V+1)*64
*/ */
/*static*/ int32 DMCacc = 1; static int32 DMCacc = 1;
static int32 DMCPeriod = 0; static int32 DMCPeriod = 0;
/*static*/ uint8 DMCBitCount = 0; static uint8 DMCBitCount = 0;
static uint8 DMCAddressLatch = 0, DMCSizeLatch = 0; /* writes to 4012 and 4013 */ static uint8 DMCAddressLatch = 0, DMCSizeLatch = 0; /* writes to 4012 and 4013 */
static uint8 DMCFormat = 0; /* Write to $4010 */ static uint8 DMCFormat = 0; /* Write to $4010 */
@@ -176,13 +179,8 @@ static int FASTAPASS(2) CheckFreq(uint32 cf, uint8 sr) {
} }
static void SQReload(int x, uint8 V) { static void SQReload(int x, uint8 V) {
if (EnabledChannels & (1 << x)) { if (EnabledChannels & (1 << x))
if (x)
DoSQ2();
else
DoSQ1();
lengthcount[x] = lengthtable[(V >> 3) & 0x1f]; lengthcount[x] = lengthtable[(V >> 3) & 0x1f];
}
curfreq[x] = curfreq[x] & 0xff | ((V & 7) << 8); curfreq[x] = curfreq[x] & 0xff | ((V & 7) << 8);
RectDutyCount[x] = 7; RectDutyCount[x] = 7;
@@ -211,6 +209,7 @@ static DECLFW(Write_PSG) {
curfreq[0] |= V; curfreq[0] |= V;
break; break;
case 0x3: case 0x3:
DoSQ1();
SQReload(0, V); SQReload(0, V);
break; break;
case 0x4: case 0x4:
@@ -231,6 +230,7 @@ static DECLFW(Write_PSG) {
curfreq[1] |= V; curfreq[1] |= V;
break; break;
case 0x7: case 0x7:
DoSQ2();
SQReload(1, V); SQReload(1, V);
break; break;
case 0xa: case 0xa:
@@ -532,13 +532,21 @@ static INLINE void RDoSQ(int x) {
int32 cf; int32 cf;
int32 rc; int32 rc;
if (curfreq[x] < 8 || curfreq[x] > 0x7ff) V = SOUNDTS - ChannelBC[x];
goto endit; cf = (curfreq[x] + 1) * 2;
if (!CheckFreq(curfreq[x], PSG[(x << 2) | 0x1])) rc = wlcount[x];
goto endit;
if (!lengthcount[x])
goto endit;
/* added 2018/12/08 */
/* when pulse channel is silenced, resets length counters but not
* duty cycle, instead of resetting both */
if ((curfreq[x] < 8 || curfreq[x] > 0x7ff) ||
!CheckFreq(curfreq[x], PSG[(x << 2) | 0x1]) ||
!lengthcount[x]) {
rc -= V;
if (rc <= 0) {
rc = cf - (-rc % cf);
}
} else {
if (EnvUnits[x].Mode & 0x1) if (EnvUnits[x].Mode & 0x1)
amp = EnvUnits[x].Speed; amp = EnvUnits[x].Speed;
else else
@@ -554,15 +562,9 @@ static INLINE void RDoSQ(int x) {
amp = (amp * FSettings.SquareVolume[x]) / 256; amp = (amp * FSettings.SquareVolume[x]) / 256;
amp <<= 24; amp <<= 24;
rthresh = RectDuties[(PSG[(x << 2)] & 0xC0) >> 6]; rthresh = RectDuties[(PSG[(x << 2)] & 0xC0) >> 6];
D = &WaveHi[ChannelBC[x]];
V = SOUNDTS - ChannelBC[x];
currdc = RectDutyCount[x]; currdc = RectDutyCount[x];
cf = (curfreq[x] + 1) * 2; D = &WaveHi[ChannelBC[x]];
rc = wlcount[x];
while (V > 0) { while (V > 0) {
if (currdc < rthresh) if (currdc < rthresh)
@@ -577,9 +579,9 @@ static INLINE void RDoSQ(int x) {
} }
RectDutyCount[x] = currdc; RectDutyCount[x] = currdc;
wlcount[x] = rc; }
endit: wlcount[x] = rc;
ChannelBC[x] = SOUNDTS; ChannelBC[x] = SOUNDTS;
} }
@@ -724,10 +726,6 @@ static void RDoTriangle(void) {
ChannelBC[2] = SOUNDTS; ChannelBC[2] = SOUNDTS;
} }
uint32 lq_tcout = 0;
int32 lq_triacc = 0;
int32 lq_noiseacc = 0;
static void RDoTriangleNoisePCMLQ(void) { static void RDoTriangleNoisePCMLQ(void) {
int32 V; int32 V;
int32 start, end; int32 start, end;