From 0c8ec07633475a8c12270d64d2b2a0a9351fc0e0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 25 Jan 2022 03:12:53 -0500 Subject: [PATCH] VGM export: kind of implement sample loop for PCE, NES and Genesis kinda glitchy --- src/engine/engine.cpp | 64 +++++++++++++++++++++++++++++++++++++------ src/engine/engine.h | 2 +- src/engine/sample.h | 3 +- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 5780c941..a91b3fc2 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1909,24 +1909,33 @@ SafeWriter* DivEngine::saveDMF() { return w; } -void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff) { +void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample) { if (write.addr>=0xffff0000) { // Furnace special command unsigned char streamID=streamOff+((write.addr&0xff00)>>8); switch (write.addr&0xff) { case 0: // play sample - w->writeC(0x95); - w->writeC(streamID); - w->writeS(write.val); // sample number - w->writeC(0); // flags + if (write.valwriteC(0x95); + w->writeC(streamID); + w->writeS(write.val); // sample number + w->writeC((sample->loopStart==0)); // flags + if (sample->loopStart>0) { + loopTimer[streamID]=sample->rendLength; + loopSample[streamID]=write.val; + } + } break; case 1: // set sample freq w->writeC(0x92); w->writeC(streamID); w->writeI(write.val); + loopFreq[streamID]=write.val; break; case 2: // stop sample w->writeC(0x94); w->writeC(streamID); + loopSample[streamID]=-1; break; } return; @@ -2082,6 +2091,15 @@ SafeWriter* DivEngine::saveVGM() { bool willExport[32]; int streamIDs[32]; + double loopTimer[DIV_MAX_CHANS]; + double loopFreq[DIV_MAX_CHANS]; + int loopSample[DIV_MAX_CHANS]; + + for (int i=0; irendOffContiguous=sampleSeek; + sampleSeek+=sample->rendLength; + } + if (writeDACSamples) for (int i=0; iwriteC(0x67); @@ -2460,14 +2486,36 @@ SafeWriter* DivEngine::saveVGM() { for (int i=0; i& writes=disCont[i].dispatch->getRegisterWrites(); for (DivRegWrite& j: writes) { - performVGMWrite(w,song.system[i],j,streamIDs[i]); + performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample); } writes.clear(); } + // check whether we need to loop + int totalWait=cycles>>MASTER_CLOCK_PREC; + for (int i=0; i=0) { + loopTimer[i]-=(loopFreq[i]/44100.0)*(double)totalWait; + if (loopTimer[i]<0) { + if (loopSample[i]loopStart<(int)sample->rendLength) { + //logW("inserting LOOP: %d\n",sample->rendOffContiguous); + w->writeC(0x93); + w->writeC(i); + w->writeI(sample->rendOffContiguous+sample->loopStart); + w->writeC(0x81); + w->writeI(sample->rendLength-sample->loopStart); + } + } + loopSample[i]=-1; + } + } + } // write wait w->writeC(0x61); - w->writeS(cycles>>MASTER_CLOCK_PREC); - tickCount+=cycles>>MASTER_CLOCK_PREC; + w->writeS(totalWait); + tickCount+=totalWait; } for (int i=0; i