From 2343cdecc58f991c558ac3c81aef29d702448883 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 8 Feb 2023 19:25:03 -0500 Subject: [PATCH] VGM export: add "trailing ticks" option issue #695 --- src/engine/engine.h | 10 +++++- src/engine/playback.cpp | 2 ++ src/engine/vgmOps.cpp | 68 ++++++++++++++++++++++++++++++++++++----- src/gui/gui.cpp | 21 ++++++++++++- src/gui/gui.h | 1 + 5 files changed, 93 insertions(+), 9 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index d2627d75..b411b6df 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -100,6 +100,7 @@ struct DivChannelState { unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR; bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff; bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp; + bool wentThroughNote, goneThroughNote; int midiNote, curMidiNote, midiPitch; size_t midiAge; @@ -152,6 +153,8 @@ struct DivChannelState { wasShorthandPorta(false), noteOnInhibit(false), resetArp(false), + wentThroughNote(false), + goneThroughNote(false), midiNote(-1), curMidiNote(-1), midiPitch(-1), @@ -524,7 +527,12 @@ class DivEngine { // specify system to build ROM for. SafeWriter* buildROM(int sys); // dump to VGM. - SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171, bool patternHints=false, bool directStream=false); + // set trailingTicks to: + // - 0 to add one tick of trailing + // - 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); // dump to ZSM. SafeWriter* saveZSM(unsigned int zsmrate=60, bool loop=true); // dump command stream. diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 6837decf..af5be978 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -957,6 +957,8 @@ void DivEngine::processRow(int i, bool afterDelay) { } } else if (!chan[i].noteOnInhibit) { dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,chan[i].note,chan[i].volume>>8)); + chan[i].goneThroughNote=true; + chan[i].wentThroughNote=true; keyHit[i]=true; } } diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 8da86c76..f3ba3766 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -952,7 +952,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) { +SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool patternHints, bool directStream, int trailingTicks) { if (version<0x150) { lastError="VGM version is too low"; return NULL; @@ -1037,7 +1037,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p int chipAccounting=0; int loopPos=-1; - int loopTick=-1; + int loopTickSong=-1; + int songTick=0; unsigned int sampleOff8[256]; unsigned int sampleOffSegaPCM[256]; @@ -1063,6 +1064,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p std::vector delayedWrites[DIV_MAX_CHIPS]; std::vector> sortedWrites; std::vector tickPos; + std::vector tickSample; + + bool trailing=false; + bool beenOneLoopAlready=false; + int countDown=MAX(0,trailingTicks)+1; for (int i=0; itell()); - if (nextTick(false,true) || !playing) { + tickSample.push_back(tickCount); + if (nextTick(false,true)) { + if (trailing) beenOneLoopAlready=true; + trailing=true; + for (int i=0; i0 && !beenOneLoopAlready) { + loopTickSong++; + } + } + if (countDown<=0 || !playing || beenOneLoopAlready) { done=true; if (!loop) { for (int i=0; itell(); - loopTick=tickCount; + loopTickSong=songTick; } } // end of song @@ -2333,9 +2380,16 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p if (loopPos==-1) { w->writeI(0); w->writeI(0); + } else if (loopTickSong<0 || loopTickSong>(int)tickPos.size()) { + logW("loopTickSong out of range! %d>%d",loopTickSong,(int)tickPos.size()); + w->writeI(0); + w->writeI(0); } else { - w->writeI(loopPos-0x1c); - w->writeI(tickCount-loopTick); + int realLoopTick=tickSample[loopTickSong]; + int realLoopPos=tickPos[loopTickSong]; + logI("tickCount-realLoopTick: %d. realLoopPos: %d",tickCount-realLoopTick,realLoopPos); + w->writeI(realLoopPos-0x1c); + w->writeI(tickCount-realLoopTick); } } else { w->writeI(0); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index e120bea0..e239226e 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3530,6 +3530,24 @@ bool FurnaceGUI::loop() { ImGui::EndCombo(); } ImGui::Checkbox("loop",&vgmExportLoop); + if (vgmExportLoop && e->song.loopModality==2) { + ImGui::Text("trailing ticks:"); + if (ImGui::RadioButton("auto-detect",vgmExportTrailingTicks==-1)) { + vgmExportTrailingTicks=-1; + } + if (ImGui::RadioButton("one loop",vgmExportTrailingTicks==-2)) { + vgmExportTrailingTicks=-2; + } + if (ImGui::RadioButton("custom",vgmExportTrailingTicks>=0)) { + vgmExportTrailingTicks=0; + } + if (vgmExportTrailingTicks>=0) { + ImGui::SameLine(); + if (ImGui::InputInt("##TrailTicks",&vgmExportTrailingTicks,1,100)) { + if (vgmExportTrailingTicks<0) vgmExportTrailingTicks=0; + } + } + } ImGui::Checkbox("add pattern change hints",&vgmExportPatternHints); if (ImGui::IsItemHovered()) { ImGui::SetTooltip( @@ -4463,7 +4481,7 @@ bool FurnaceGUI::loop() { break; } case GUI_FILE_EXPORT_VGM: { - SafeWriter* w=e->saveVGM(willExport,vgmExportLoop,vgmExportVersion,vgmExportPatternHints,vgmExportDirectStream); + SafeWriter* w=e->saveVGM(willExport,vgmExportLoop,vgmExportVersion,vgmExportPatternHints,vgmExportDirectStream,vgmExportTrailingTicks); if (w!=NULL) { FILE* f=ps_fopen(copyOfName.c_str(),"wb"); if (f!=NULL) { @@ -5837,6 +5855,7 @@ FurnaceGUI::FurnaceGUI(): snesFilterHex(false), mobileEdit(false), vgmExportVersion(0x171), + vgmExportTrailingTicks(-1), drawHalt(10), zsmExportTickRate(60), macroPointSize(16), diff --git a/src/gui/gui.h b/src/gui/gui.h index b78480d5..cb7d950d 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1118,6 +1118,7 @@ class FurnaceGUI { bool mobileEdit; bool willExport[DIV_MAX_CHIPS]; int vgmExportVersion; + int vgmExportTrailingTicks; int drawHalt; int zsmExportTickRate; int macroPointSize;