From fe454ee2df8a5d06d9630919b90bc377025ddac5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 6 Jun 2025 02:45:59 -0500 Subject: [PATCH] VGM export: add speed drift compensation setting it appears this is the only way to get exports to play at the correct speed in DeadFish's VGM player for Genesis --- src/engine/engine.h | 4 ++-- src/engine/vgmOps.cpp | 10 +++++----- src/gui/exportOptions.cpp | 10 ++++++++++ src/gui/gui.cpp | 3 ++- src/gui/gui.h | 1 + 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index f2187faf3..639da6773 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -583,7 +583,7 @@ class DivEngine { void processRow(int i, bool afterDelay); void nextOrder(); void nextRow(); - void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES); + void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES, int rateCorrection); // returns true if end of song. bool nextTick(bool noAccum=false, bool inhibitLowLat=false); bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal); @@ -726,7 +726,7 @@ class DivEngine { // - x to add x+1 ticks of trailing // - -1 to auto-determine trailing // - -2 to add a whole loop of trailing - SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171, bool patternHints=false, bool directStream=false, int trailingTicks=-1, bool dpcm07=false); + SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171, bool patternHints=false, bool directStream=false, int trailingTicks=-1, bool dpcm07=false, int correctedRate=44100); // dump to TIunA. SafeWriter* saveTiuna(const bool* sysToExport, const char* baseLabel, int firstBankSize, int otherBankSize); // dump command stream. diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index b704ccd84..09b06bb25 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -24,7 +24,7 @@ // this function is so long // may as well make it something else -void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES) { +void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable, bool dpcm07, DivDispatch** writeNES, int rateCorrection) { unsigned char baseAddr1=isSecond?0xa0:0x50; unsigned char baseAddr2=isSecond?0x80:0; unsigned short baseAddr2S=isSecond?0x8000:0; @@ -795,7 +795,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write break; case 1: { // set sample freq sampleStoppable[streamID]=true; - int realFreq=write.val; + int realFreq=(write.val*44100)/rateCorrection; if (realFreq<0) realFreq=0; if (realFreq>44100) realFreq=44100; w->writeC(0x92); @@ -1233,7 +1233,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write chipVol.push_back((_id)|(0x80000100)|(((unsigned int)_vol)<<16)); \ } -SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool patternHints, bool directStream, int trailingTicks, bool dpcm07) { +SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool patternHints, bool directStream, int trailingTicks, bool dpcm07, int correctedRate) { if (version<0x150) { lastError="VGM version is too low"; return NULL; @@ -1243,7 +1243,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p setOrder(0); BUSY_BEGIN_SOFT; double origRate=got.rate; - got.rate=44100; + got.rate=correctedRate; // determine loop point int loopOrder=0; int loopRow=0; @@ -2840,7 +2840,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p lastOne=i.second.time; } // write write - performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream,sampleStoppable,dpcm07,writeNES); + performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream,sampleStoppable,dpcm07,writeNES,correctedRate); writeCount++; } sortedWrites.clear(); diff --git a/src/gui/exportOptions.cpp b/src/gui/exportOptions.cpp index 6815b1039..71f0f90fa 100644 --- a/src/gui/exportOptions.cpp +++ b/src/gui/exportOptions.cpp @@ -239,6 +239,16 @@ void FurnaceGUI::drawExportVGM(bool onWindow) { } } + ImGui::Text(_("speed drift compensation:")); + if (ImGui::RadioButton(_("none"),vgmExportCorrectedRate==44100)) { + vgmExportCorrectedRate=44100; + } + // as tested on a Model 1 Genesis (VA6, USA): + // 0.97841613336995507871 slower, 1.02206000687632131440 longer + if (ImGui::RadioButton(_("DeadFish VgmPlay (1.02×)"),vgmExportCorrectedRate==43148)) { + vgmExportCorrectedRate=43148; + } + if (hasOneAtLeast) { if (onWindow) { ImGui::Separator(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 6f0aa455c..1bb9144b3 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -5654,7 +5654,7 @@ bool FurnaceGUI::loop() { break; } case GUI_FILE_EXPORT_VGM: { - SafeWriter* w=e->saveVGM(willExport,vgmExportLoop,vgmExportVersion,vgmExportPatternHints,vgmExportDirectStream,vgmExportTrailingTicks,vgmExportDPCM07); + SafeWriter* w=e->saveVGM(willExport,vgmExportLoop,vgmExportVersion,vgmExportPatternHints,vgmExportDirectStream,vgmExportTrailingTicks,vgmExportDPCM07,vgmExportCorrectedRate); if (w!=NULL) { FILE* f=ps_fopen(copyOfName.c_str(),"wb"); if (f!=NULL) { @@ -8478,6 +8478,7 @@ FurnaceGUI::FurnaceGUI(): debugFFT(false), vgmExportVersion(0x171), vgmExportTrailingTicks(-1), + vgmExportCorrectedRate(44100), drawHalt(10), macroPointSize(16), waveEditStyle(0), diff --git a/src/gui/gui.h b/src/gui/gui.h index 8d4b065b8..a50b21c92 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1687,6 +1687,7 @@ class FurnaceGUI { bool willExport[DIV_MAX_CHIPS]; int vgmExportVersion; int vgmExportTrailingTicks; + int vgmExportCorrectedRate; int cvHiScore; int drawHalt; int macroPointSize;