mirror of https://github.com/AxioDL/metaforce.git
Update fixNES integration
This commit is contained in:
parent
9f1e6736b2
commit
58c00b6c9c
|
@ -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 ; i<NUM_AUDIO_BUFFERS ; ++i)
|
||||
m_audioBufs[i] = m_audioBufBlock.get() + apuBufSz * i;
|
||||
|
||||
|
@ -340,12 +341,25 @@ int CNESEmulator::audioUpdate()
|
|||
uint8_t *data = apuGetBuf();
|
||||
if(data != NULL && m_procBufs)
|
||||
{
|
||||
--m_procBufs;
|
||||
memmove(m_audioBufs[m_headBuf], data, apuGetMaxBufSize());
|
||||
//printf("PUSH\n");
|
||||
++m_headBuf;
|
||||
if (m_headBuf == NUM_AUDIO_BUFFERS)
|
||||
m_headBuf = 0;
|
||||
uint32_t apuBufSz = apuGetMaxBufSize();
|
||||
uint32_t remBytes = apuGetBufSize();
|
||||
while (remBytes != 0)
|
||||
{
|
||||
size_t thisBytes = std::min(remBytes, apuBufSz - m_posInHeadBuf);
|
||||
memmove(m_audioBufs[m_headBuf] + m_posInHeadBuf, data, thisBytes);
|
||||
data += thisBytes;
|
||||
m_posInHeadBuf += thisBytes;
|
||||
if (m_posInHeadBuf == apuBufSz)
|
||||
{
|
||||
m_posInHeadBuf = 0;
|
||||
--m_procBufs;
|
||||
++m_headBuf;
|
||||
if (m_headBuf == NUM_AUDIO_BUFFERS)
|
||||
m_headBuf = 0;
|
||||
//printf("PUSH\n");
|
||||
}
|
||||
remBytes -= thisBytes;
|
||||
}
|
||||
}
|
||||
|
||||
//if (!origProcBufs)
|
||||
|
@ -354,19 +368,19 @@ int CNESEmulator::audioUpdate()
|
|||
return origProcBufs;
|
||||
}
|
||||
|
||||
static constexpr size_t AudioFrameSz = 2 * sizeof(int16_t);
|
||||
static constexpr uint32_t AudioFrameSz = 2 * sizeof(int16_t);
|
||||
|
||||
size_t CNESEmulator::supplyAudio(boo::IAudioVoice& voice, size_t frames, int16_t* data)
|
||||
{
|
||||
size_t remFrames = frames;
|
||||
uint32_t remFrames = uint32_t(frames);
|
||||
while (remFrames)
|
||||
{
|
||||
if (m_posInBuf == apuGetMaxBufSize())
|
||||
if (m_posInTailBuf == apuGetMaxBufSize())
|
||||
{
|
||||
++m_tailBuf;
|
||||
if (m_tailBuf == NUM_AUDIO_BUFFERS)
|
||||
m_tailBuf = 0;
|
||||
m_posInBuf = 0;
|
||||
m_posInTailBuf = 0;
|
||||
++m_procBufs;
|
||||
//printf("POP\n");
|
||||
}
|
||||
|
@ -378,20 +392,15 @@ size_t CNESEmulator::supplyAudio(boo::IAudioVoice& voice, size_t frames, int16_t
|
|||
return frames;
|
||||
}
|
||||
|
||||
size_t copySz = std::min(apuGetMaxBufSize() - m_posInBuf, remFrames * AudioFrameSz);
|
||||
memmove(data, m_audioBufs[m_tailBuf] + m_posInBuf, copySz);
|
||||
size_t copySz = std::min(apuGetMaxBufSize() - m_posInTailBuf, remFrames * AudioFrameSz);
|
||||
memmove(data, m_audioBufs[m_tailBuf] + m_posInTailBuf, copySz);
|
||||
data += copySz / sizeof(int16_t);
|
||||
m_posInBuf += copySz;
|
||||
m_posInTailBuf += copySz;
|
||||
remFrames -= copySz / AudioFrameSz;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
#define CATCHUP_SKIP 0
|
||||
#if CATCHUP_SKIP
|
||||
static int catchupFrames = 0;
|
||||
#endif
|
||||
|
||||
void CNESEmulator::NesEmuMainLoop(bool forceDraw)
|
||||
{
|
||||
//int start = GetTickCount();
|
||||
|
@ -406,12 +415,7 @@ void CNESEmulator::NesEmuMainLoop(bool forceDraw)
|
|||
//printf("LC RENDER: %d\n", loopCount);
|
||||
m_texture->load(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);
|
||||
|
||||
|
|
|
@ -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<u8[]> 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<boo::IAudioVoice> m_booVoice;
|
||||
|
||||
//void* x4_loadBuf;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* URDE modification to generate RGBA8 framebuffer rather than BGR565
|
||||
* URDE modifications to generate RGBA8 framebuffer rather than BGR565
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue