diff --git a/src/sound.c b/src/sound.c index 1c4d633..4eed69f 100644 --- a/src/sound.c +++ b/src/sound.c @@ -70,6 +70,7 @@ static int32 RectDutyCount[2]; static uint8 sweepon[2]; static int32 curfreq[2]; static uint8 SweepCount[2]; +static uint8 sweepReload[2]; static uint16 nreg = 0; @@ -84,6 +85,9 @@ int32 nesincsize = 0; uint32 soundtsinc = 0; uint32 soundtsi = 0; static int32 sqacc[2]; +static uint32 lq_tcout; +static int32 lq_triacc; +static int32 lq_noiseacc; /* LQ variables segment ends. */ static int32 lengthcount[4]; @@ -125,9 +129,9 @@ static const uint32 PALDMCTable[0x10] = * $4013 - Size register: Size in bytes = (V+1)*64 */ -/*static*/ int32 DMCacc = 1; +static int32 DMCacc = 1; 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 DMCFormat = 0; /* Write to $4010 */ @@ -175,21 +179,12 @@ static int FASTAPASS(2) CheckFreq(uint32 cf, uint8 sr) { } static void SQReload(int x, uint8 V) { - if (EnabledChannels & (1 << x)) { - if (x) - DoSQ2(); - else - DoSQ1(); + if (EnabledChannels & (1 << x)) lengthcount[x] = lengthtable[(V >> 3) & 0x1f]; - } - - sweepon[x] = PSG[(x << 2) | 1] & 0x80; - curfreq[x] = PSG[(x << 2) | 0x2] | ((V & 7) << 8); - SweepCount[x] = ((PSG[(x << 2) | 0x1] >> 4) & 7) + 1; + curfreq[x] = curfreq[x] & 0xff | ((V & 7) << 8); RectDutyCount[x] = 7; EnvUnits[x].reloaddec = 1; - /* reloadfreq[x]=1; */ } static DECLFW(Write_PSG) { @@ -204,7 +199,9 @@ static DECLFW(Write_PSG) { V = (V & 0x3F) | ((V & 0x80) >> 1) | ((V & 0x40) << 1); break; case 0x1: - sweepon[0] = V & 0x80; + DoSQ1(); + sweepReload[0] = 1; + sweepon[0] = (V & 0x80); break; case 0x2: DoSQ1(); @@ -212,6 +209,7 @@ static DECLFW(Write_PSG) { curfreq[0] |= V; break; case 0x3: + DoSQ1(); SQReload(0, V); break; case 0x4: @@ -222,7 +220,9 @@ static DECLFW(Write_PSG) { V = (V & 0x3F) | ((V & 0x80) >> 1) | ((V & 0x40) << 1); break; case 0x5: - sweepon[1] = V & 0x80; + DoSQ2(); + sweepReload[1] = 1; + sweepon[1] = (V & 0x80); break; case 0x6: DoSQ2(); @@ -230,6 +230,7 @@ static DECLFW(Write_PSG) { curfreq[1] |= V; break; case 0x7: + DoSQ2(); SQReload(1, V); break; case 0xa: @@ -288,17 +289,17 @@ static DECLFW(Write_DMCRegs) { break; case 0x01: DoPCM(); RawDALatch = V & 0x7F; - if (RawDALatch) - DMC_7bit = 1; + if (RawDALatch) + DMC_7bit = 1; break; case 0x02: - DMCAddressLatch = V; - if (V) + DMCAddressLatch = V; + if (V) DMC_7bit = 0; - break; + break; case 0x03: - DMCSizeLatch = V; - if (V) + DMCSizeLatch = V; + if (V) DMC_7bit = 0; break; } @@ -313,6 +314,7 @@ static DECLFW(StatusWrite) { DoTriangle(); DoNoise(); DoPCM(); + for (x = 0; x < 4; x++) if (!(V & (1 << x))) lengthcount[x] = 0; /* Force length counters to 0. */ @@ -336,9 +338,9 @@ static DECLFR(StatusRead) { for (x = 0; x < 4; x++) ret |= lengthcount[x] ? (1 << x) : 0; if (DMCSize) ret |= 0x10; - #ifdef FCEUDEF_DEBUGGER + #ifdef FCEUDEF_DEBUGGER if (!fceuindbg) - #endif + #endif { SIRQStat &= ~0x40; X6502_IRQEnd(FCEU_IQFCOUNT); @@ -371,34 +373,25 @@ static void FASTAPASS(1) FrameSoundStuff(int V) { /* Frequency Sweep Code Here */ /* xxxx 0000 */ /* xxxx = hz. 120/(x+1)*/ - if (sweepon[P]) { - int32 mod = 0; - - if (SweepCount[P] > 0) SweepCount[P]--; - if (SweepCount[P] <= 0) { - SweepCount[P] = ((PSG[(P << 2) + 0x1] >> 4) & 7) + 1; /* +1; */ + /* http://wiki.nesdev.com/w/index.php/APU_Sweep */ + if (SweepCount[P] > 0) SweepCount[P]--; + if (SweepCount[P] <= 0) { + uint32 sweepShift = (PSG[(P << 2) + 0x1] & 7); + if (sweepon[P] && sweepShift && curfreq[P] >= 8) { + int32 mod = (curfreq[P] >> sweepShift); if (PSG[(P << 2) + 0x1] & 0x8) { - mod -= (P ^ 1) + ((curfreq[P]) >> (PSG[(P << 2) + 0x1] & 7)); - if (curfreq[P] && (PSG[(P << 2) + 0x1] & 7) /* && sweepon[P]&0x80*/) { - curfreq[P] += mod; - } - } else { - mod = curfreq[P] >> (PSG[(P << 2) + 0x1] & 7); - if ((mod + curfreq[P]) & 0x800) { - sweepon[P] = 0; - curfreq[P] = 0; - } else { - if (curfreq[P] && (PSG[(P << 2) + 0x1] & 7) /* && sweepon[P]&0x80*/) { - curfreq[P] += mod; - } - } + curfreq[P] -= (mod + (P ^ 1)); + } else if ((mod + curfreq[P]) < 0x800) { + curfreq[P] += mod; } } - } else {/* Sweeping is disabled: */ -#if 0 - curfreq[P]&=0xFF00; - curfreq[P]|=PSG[(P<<2)|0x2]; /* |((PSG[(P<<2)|3]&7)<<8); */ -#endif + + SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1); + } + + if (sweepReload[P]) { + SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1); + sweepReload[P] = 0; } } } @@ -437,19 +430,21 @@ void FrameSoundUpdate(void) { * Length counter: Bit 4-7 of $4003, $4007, $400b, $400f */ - if (!fcnt && !(IRQFrameMode & 0x3)) { - SIRQStat |= 0x40; - X6502_IRQBegin(FCEU_IQFCOUNT); - } - if (fcnt == 3) { if (IRQFrameMode & 0x2) fhcnt += fhinc; } + FrameSoundStuff(fcnt); fcnt = (fcnt + 1) & 3; -} + /* has to be moved here to fix Dragon Warrior 4 + * after irq inhibit fix for $4017 */ + if (!fcnt && !(IRQFrameMode & 0x3)) { + SIRQStat |= 0x40; + X6502_IRQBegin(FCEU_IQFCOUNT); + } +} static INLINE void tester(void) { if (DMCBitCount == 0) { @@ -476,9 +471,10 @@ static INLINE void DMCDMA(void) { if (DMCFormat & 0x40) PrepDPCM(); else { - SIRQStat |= 0x80; - if (DMCFormat & 0x80) + if (DMCFormat & 0x80) { + SIRQStat |= 0x80; X6502_IRQBegin(FCEU_IQDPCM); + } } } } @@ -536,54 +532,56 @@ static INLINE void RDoSQ(int x) { int32 cf; int32 rc; - if (curfreq[x] < 8 || curfreq[x] > 0x7ff) - goto endit; - if (!CheckFreq(curfreq[x], PSG[(x << 2) | 0x1])) - goto endit; - if (!lengthcount[x]) - goto endit; - - if (EnvUnits[x].Mode & 0x1) - amp = EnvUnits[x].Speed; - else - amp = EnvUnits[x].decvolume; - /* printf("%d\n",amp); */ - - /* Modify Square wave volume based on channel volume modifiers - * Note: the formulat x = x * y /100 does not yield exact results, - * but is "close enough" and avoids the need for using double values - * or implicit cohersion which are slower (we need speed here) */ - /* TODO: Optimize this. */ - if (FSettings.SquareVolume[x] != 256) - amp = (amp * FSettings.SquareVolume[x]) / 256; - - amp <<= 24; - - rthresh = RectDuties[(PSG[(x << 2)] & 0xC0) >> 6]; - - D = &WaveHi[ChannelBC[x]]; V = SOUNDTS - ChannelBC[x]; - - currdc = RectDutyCount[x]; cf = (curfreq[x] + 1) * 2; rc = wlcount[x]; - while (V > 0) { - if (currdc < rthresh) - *D += amp; - rc--; - if (!rc) { - rc = cf; - currdc = (currdc + 1) & 7; + /* 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); } - V--; - D++; + } else { + if (EnvUnits[x].Mode & 0x1) + amp = EnvUnits[x].Speed; + else + amp = EnvUnits[x].decvolume; + /* printf("%d\n",amp); */ + + /* Modify Square wave volume based on channel volume modifiers + * Note: the formulat x = x * y /100 does not yield exact results, + * but is "close enough" and avoids the need for using double values + * or implicit cohersion which are slower (we need speed here) */ + /* TODO: Optimize this. */ + if (FSettings.SquareVolume[x] != 256) + amp = (amp * FSettings.SquareVolume[x]) / 256; + + amp <<= 24; + rthresh = RectDuties[(PSG[(x << 2)] & 0xC0) >> 6]; + currdc = RectDutyCount[x]; + D = &WaveHi[ChannelBC[x]]; + + while (V > 0) { + if (currdc < rthresh) + *D += amp; + rc--; + if (!rc) { + rc = cf; + currdc = (currdc + 1) & 7; + } + V--; + D++; + } + + RectDutyCount[x] = currdc; } - RectDutyCount[x] = currdc; wlcount[x] = rc; - - endit: ChannelBC[x] = SOUNDTS; } @@ -728,10 +726,6 @@ static void RDoTriangle(void) { ChannelBC[2] = SOUNDTS; } -uint32 lq_tcout = 0; -int32 lq_triacc = 0; -int32 lq_noiseacc = 0; - static void RDoTriangleNoisePCMLQ(void) { int32 V; int32 start, end; @@ -861,7 +855,6 @@ static void RDoTriangleNoisePCMLQ(void) { } } - static void RDoNoise(void) { uint32 V; int32 outo; @@ -932,10 +925,12 @@ DECLFW(Write_IRQFM) { fcnt = 0; if (V & 2) FrameSoundUpdate(); - fcnt = 1; + /* fcnt = 1; */ fhcnt = fhinc; - X6502_IRQEnd(FCEU_IQFCOUNT); - SIRQStat &= ~0x40; + if (V & 1) { + X6502_IRQEnd(FCEU_IQFCOUNT); + SIRQStat &= ~0x40; + } IRQFrameMode = V; }