diff --git a/NESEmulator/CNESEmulator.cpp b/NESEmulator/CNESEmulator.cpp index 40e3d7954..d34104858 100644 --- a/NESEmulator/CNESEmulator.cpp +++ b/NESEmulator/CNESEmulator.cpp @@ -132,8 +132,8 @@ bool emuSkipFrame = false; extern bool fdsSwitch; -bool apuCycleURDE(); uint32_t apuGetMaxBufSize(); +void apuResetPos(); uint8_t* ppuGetVRAM(); int audioUpdate() @@ -272,6 +272,7 @@ void CNESEmulator::InitializeEmulator() m_booVoice->start(); uint32_t apuBufSz = apuGetMaxBufSize(); m_audioBufBlock.reset(new u8[apuBufSz * NUM_AUDIO_BUFFERS]); + memset(m_audioBufBlock.get(), 0, apuBufSz * NUM_AUDIO_BUFFERS); for (int i=0 ; iload(textureImage, visibleImg); emuRenderFrame = false; -#if CATCHUP_SKIP - if (catchupFrames) - --catchupFrames; - else -#endif - break; + break; } ++loopCount; @@ -435,9 +439,9 @@ void CNESEmulator::NesEmuMainLoop(bool forceDraw) if(fm2playRunning()) fm2playUpdate(); #endif -#if (WINDOWS_BUILD && DEBUG_HZ) +#if DEBUG_HZ emuTimesCalled++; - DWORD end = GetTickCount(); + auto end = GetTickCount(); emuTotalElapsed += end - emuFrameStart; if(emuTotalElapsed >= 1000) { @@ -449,7 +453,10 @@ void CNESEmulator::NesEmuMainLoop(bool forceDraw) #endif //update audio before drawing if(!apuUpdate()) + { + apuResetPos(); break; + } //glutPostRedisplay(); #if 0 if(ppuDebugPauseFrame) @@ -461,19 +468,13 @@ void CNESEmulator::NesEmuMainLoop(bool forceDraw) #endif if(nesEmuNSFPlayback) nsfVsync(); + + //keep processing frames if audio buffers are underrunning + if (emuSkipFrame) + emuRenderFrame = false; + continue; } - -#if 0 - if (!forceDraw && (loopCount % 10000) == 0 && GetTickCount() - start >= 14) - { -#if CATCHUP_SKIP - if (catchupFrames < 50) - ++catchupFrames; -#endif - break; - } -#endif } while(true); diff --git a/NESEmulator/CNESEmulator.hpp b/NESEmulator/CNESEmulator.hpp index a2509f400..90ff03658 100644 --- a/NESEmulator/CNESEmulator.hpp +++ b/NESEmulator/CNESEmulator.hpp @@ -15,7 +15,7 @@ class IDvdRequest; namespace MP1 { -#define NUM_AUDIO_BUFFERS 3 +#define NUM_AUDIO_BUFFERS 4 class CNESEmulator final : public boo::IAudioVoiceCallback { @@ -51,10 +51,11 @@ private: std::unique_ptr m_audioBufBlock; u8* m_audioBufs[NUM_AUDIO_BUFFERS]; - int m_headBuf = 0; - int m_tailBuf = 0; - int m_procBufs = NUM_AUDIO_BUFFERS; - size_t m_posInBuf = 0; + uint32_t m_headBuf = 0; + uint32_t m_tailBuf = 0; + uint32_t m_procBufs = NUM_AUDIO_BUFFERS; + uint32_t m_posInHeadBuf = 0; + uint32_t m_posInTailBuf = 0; boo::ObjToken m_booVoice; //void* x4_loadBuf; diff --git a/NESEmulator/apu.c b/NESEmulator/apu.c index 9d0c4e7ad..9c83dc43c 100644 --- a/NESEmulator/apu.c +++ b/NESEmulator/apu.c @@ -1,320 +1,11 @@ #include "fixNES/apu.c" -/* - * Alternate apuCycle implementation to avoid processing multiple - * NES frames per URDE frame (costly and jarring to player). - * - * This implementation nominally fills 6/10 buffers, allowing - * emulation to "catch up" by having more buffer headroom available - * (and also reducing audio latency somewhat). - * - * URDE's NesEmuMainLoop uses emuSkipVsync as a signal to proceed - * with the emulation, allowing audio buffers to be pre-filled with - * generated tones independent of the emulated CPU. Granted, this - * compromises accuracy, but doesn't affect NEStroid's behavior and - * reduces audio discontinuities. - */ - -bool apuCycleURDE() -{ - if(apu.curBufPos == apu.BufSize) - { - int updateRes = audioUpdate(); - if(updateRes == 0) - { - emuSkipFrame = false; - emuSkipVsync = false; - return false; - } - if(updateRes > 6) - { - emuSkipVsync = true; - emuSkipFrame = true; - } - else - { - emuSkipFrame = false; - if(updateRes > 4) // 6 buffers filled, stop here - emuSkipVsync = true; - else - emuSkipVsync = false; - } - apu.curBufPos = 0; - } - - uint8_t aExp = audioExpansion; - if(!(apu.apuClock&7)) - { - if(apu.p1LengthCtr && (apu.reg[0x15] & P1_ENABLE)) - { - if(!apu.p1Sweep.mute && apu.freq1 >= 8 && apu.freq1 < 0x7FF) - apu.p1Out = apu.p1seq[apu.p1Cycle] ? (apu.p1Env.constant ? apu.p1Env.vol : apu.p1Env.decay) : 0; - } - if(apu.p2LengthCtr && (apu.reg[0x15] & P2_ENABLE)) - { - if(!apu.p2Sweep.mute && apu.freq2 >= 8 && apu.freq2 < 0x7FF) - apu.p2Out = apu.p2seq[apu.p2Cycle] ? (apu.p2Env.constant ? apu.p2Env.vol : apu.p2Env.decay) : 0; - } - if(apu.triLengthCtr && apu.triCurLinearCtr && (apu.reg[0x15] & TRI_ENABLE)) - { - if(apu.triFreq >= 2) - apu.triOut = apu.triSeq[apu.triCycle]; - } - if(apu.noiseLengthCtr && (apu.reg[0x15] & NOISE_ENABLE)) - { - if(apu.noiseFreq > 0) - apu.noiseOut = (apu.noiseShiftReg&1) == 0 ? (apu.noiseEnv.constant ? apu.noiseEnv.vol : apu.noiseEnv.decay) : 0; - } -#if AUDIO_FLOAT - float curIn = apu.pulseLookupTbl[apu.p1Out + apu.p2Out] + apu.tndLookupTbl[(3*apu.triOut) + (2*apu.noiseOut) + apu.dmcVol]; - uint8_t ampVolPos = 0; - //very rough still - if(aExp & EXP_VRC6) - { - vrc6AudioCycle(); - curIn += ((float)vrc6Out)*0.008f; - ampVolPos++; - } - if(aExp & EXP_FDS) - { - fdsAudioCycle(); - curIn += ((float)fdsOut)*0.00617f; - ampVolPos++; - } - if(aExp & EXP_MMC5) - { - mmc5AudioCycle(); - curIn += apu.pulseLookupTbl[mmc5Out]+(mmc5pcm*0.002f); - ampVolPos++; - } - if(aExp & EXP_VRC7) - { - curIn += (((float)(vrc7Out>>7))/32768.f); - ampVolPos++; - } - if(aExp & EXP_N163) - { - curIn += ((float)n163Out)*0.0008f; - ampVolPos++; - } - if(aExp & EXP_S5B) - { - s5BAudioCycle(); - curIn += ((float)s5BOut)/32768.f; - ampVolPos++; - } - //amplify input - curIn *= ampVol[ampVolPos]; - float curLPout = apu.lastLPOut+(apu.lpVal*(curIn-apu.lastLPOut)); - float curHPOut = apu.hpVal*(apu.lastHPOut+apu.lastLPOut-curLPout); - //set output - apu.OutBuf[apu.curBufPos] = curHPOut; - apu.lastLPOut = curLPout; - apu.lastHPOut = curHPOut; -#else - int32_t curIn = apu.pulseLookupTbl[apu.p1Out + apu.p2Out] + apu.tndLookupTbl[(3*apu.triOut) + (2*apu.noiseOut) + apu.dmcVol]; - uint8_t ampVolPos = 0; - //very rough still - if(aExp & EXP_VRC6) - { - vrc6AudioCycle(); - curIn += ((int32_t)vrc6Out)*262; - ampVolPos++; - } - if(aExp & EXP_FDS) - { - fdsAudioCycle(); - curIn += ((int32_t)fdsOut)*202; - ampVolPos++; - } - if(aExp & EXP_MMC5) - { - mmc5AudioCycle(); - curIn += apu.pulseLookupTbl[mmc5Out]+(mmc5pcm<<6); - ampVolPos++; - } - if(aExp & EXP_VRC7) - { - curIn += vrc7Out>>7; - ampVolPos++; - } - if(aExp & EXP_N163) - { - curIn += n163Out*26; - ampVolPos++; - } - if(aExp & EXP_S5B) - { - s5BAudioCycle(); - curIn += s5BOut; - ampVolPos++; - } - //amplify input - curIn *= apu.ampVol[ampVolPos]; - int32_t curOut; - //gen output - curOut = apu.lastLPOut+((apu.lpVal*((curIn>>6)-apu.lastLPOut))>>15); //Set Lowpass Output - curIn = (apu.lastHPOut+apu.lastLPOut-curOut); //Set Highpass Input - curIn += (curIn>>31)&1; //Add Sign Bit for proper Downshift later - apu.lastLPOut = curOut; //Save Lowpass Output - curOut = (apu.hpVal*curIn)>>15; //Set Highpass Output - apu.lastHPOut = curOut; //Save Highpass Output - //Save Clipped Highpass Output - apu.OutBuf[apu.curBufPos] = (curOut > 32767)?(32767):((curOut < -32768)?(-32768):curOut); -#endif - apu.OutBuf[apu.curBufPos+1] = apu.OutBuf[apu.curBufPos]; - apu.curBufPos+=2; - } - apu.apuClock++; - - if(apu.p1freqCtr == 0) - { - apu.p1freqCtr = (apu.freq1<<1)+1; - apu.p1Cycle = (apu.p1Cycle+1)&7; - } - else - apu.p1freqCtr--; - - if(apu.p2freqCtr == 0) - { - apu.p2freqCtr = (apu.freq2<<1)+1; - apu.p2Cycle = (apu.p2Cycle+1)&7; - } - else - apu.p2freqCtr--; - - if(apu.triFreqCtr == 0) - { - apu.triFreqCtr = apu.triFreq; - apu.triCycle = (apu.triCycle+1)&31; - } - else - apu.triFreqCtr--; - - if(apu.noiseFreqCtr == 0) - { - apu.noiseFreqCtr = apu.noiseFreq; - uint8_t cmpBit = apu.noiseMode1 ? (apu.noiseShiftReg>>6)&1 : (apu.noiseShiftReg>>1)&1; - uint8_t cmpRes = (apu.noiseShiftReg&1)^cmpBit; - apu.noiseShiftReg >>= 1; - apu.noiseShiftReg |= cmpRes<<14; - } - else - apu.noiseFreqCtr--; - - if(apu.dmcFreqCtr == 0) - { - apu.dmcFreqCtr = apu.dmcFreq; - if(apu.dmcenabled) - { - if(apu.dmcSampleBuf&1) - { - if(apu.dmcVol <= 125) - apu.dmcVol += 2; - } - else if(apu.dmcVol >= 2) - apu.dmcVol -= 2; - apu.dmcSampleBuf>>=1; - } - if(apu.dmcSampleRemain == 0) - { - if(apu.dmcready) - { - apu.dmcSampleBuf = apu.dmcCpuBuf; - apu.dmcenabled = true; - apu.dmcready = false; - } - else - apu.dmcenabled = false; - apu.dmcSampleRemain = 7; - } - else - apu.dmcSampleRemain--; - } - else - apu.dmcFreqCtr--; - if(!apu.dmcready && !cpuInDMC_DMA() && apu.dmcCurLen) - { - cpuDoDMC_DMA(apu.dmcCurAddr); - apu.dmcCurLen--; - } - - if(aExp&EXP_VRC7) - { - if(apu.vrc7Clock == vrc7CycleTimer) - { - vrc7AudioCycle(); - apu.vrc7Clock = 1; - } - else - apu.vrc7Clock++; - } - if(aExp&EXP_FDS) - fdsAudioMasterUpdate(); - if(aExp&EXP_MMC5) - mmc5AudioLenCycle(); - - if(apu.mode_change) - apuChangeMode(); - - if(apu.mode5 == false) - { - if(apu.modeCurCtr == 0) - { - if(apu.modePos == 5) - apu.modePos = 0; - else - apu.modePos++; - apu.modeCurCtr = apu.mode4Ctr[apu.modePos]-1; - if(apu.modePos == 3 || apu.modePos == 5) - { - if(apu.enable_irq) - apu.irq = 1; - } - else - { - if(apu.modePos == 1) - apuClockA(); - else if(apu.modePos == 4) - { - apuClockA(); - if(apu.enable_irq) - { - apu.irq = 1; - //actually set for cpu - interrupt |= APU_IRQ; - } - } - apuClockB(); - } - } - else - apu.modeCurCtr--; - } - else - { - if(apu.modeCurCtr == 0) - { - if(apu.modePos == 5) - apu.modePos = 0; - else - apu.modePos++; - apu.modeCurCtr = apu.mode5Ctr[apu.modePos]-1; - if(apu.modePos != 1 && apu.modePos != 5) - { - if(apu.modePos == 0 || apu.modePos == 3) - apuClockA(); - apuClockB(); - } - } - else - apu.modeCurCtr--; - } - - return true; -} - uint32_t apuGetMaxBufSize() { return apu.BufSizeBytes; } + +void apuResetPos() +{ + apu.curBufPos = 0; +} diff --git a/NESEmulator/ppu.c b/NESEmulator/ppu.c index 408490484..8897266ba 100644 --- a/NESEmulator/ppu.c +++ b/NESEmulator/ppu.c @@ -6,7 +6,7 @@ */ /* - * URDE modification to generate RGBA8 framebuffer rather than BGR565 + * URDE modifications to generate RGBA8 framebuffer rather than BGR565 */ #include diff --git a/Runtime/World/ScriptObjectSupport.cpp b/Runtime/World/ScriptObjectSupport.cpp index 6126f6acc..db95b676f 100644 --- a/Runtime/World/ScriptObjectSupport.cpp +++ b/Runtime/World/ScriptObjectSupport.cpp @@ -5,7 +5,6 @@ using namespace std::literals; namespace urde { -#ifndef NDEBUG std::string_view ScriptObjectTypeToStr(EScriptObjectType type) { switch (type) @@ -238,6 +237,5 @@ std::string_view ScriptObjectMessageToStr(EScriptObjectMessage message) default: return "..."sv; } } -#endif } diff --git a/Runtime/World/ScriptObjectSupport.hpp b/Runtime/World/ScriptObjectSupport.hpp index b35611488..788f112b6 100644 --- a/Runtime/World/ScriptObjectSupport.hpp +++ b/Runtime/World/ScriptObjectSupport.hpp @@ -230,11 +230,9 @@ enum class EScriptObjectMessage SuspendedMove = 48 }; -#ifndef NDEBUG std::string_view ScriptObjectTypeToStr(EScriptObjectType type); std::string_view ScriptObjectStateToStr(EScriptObjectState state); std::string_view ScriptObjectMessageToStr(EScriptObjectMessage message); -#endif }