diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index c7e892a9f..7cd30cfd9 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -59,6 +59,7 @@ enum DivDispatchCmds { DIV_CMD_SAMPLE_FREQ, // (frequency) DIV_CMD_SAMPLE_BANK, // (bank) DIV_CMD_SAMPLE_POS, // (pos) + DIV_CMD_SAMPLE_DIR, // (direction) DIV_CMD_FM_HARD_RESET, // (enabled) DIV_CMD_FM_LFO, // (speed) @@ -222,6 +223,8 @@ struct DivRegWrite { * - data is the sample rate * - 0xffffxx02: stop sample playback * - xx is the instance ID + * - 0xffffxx03: set sample playback direction + * - x is the instance ID * - 0xffffffff: reset */ unsigned int addr; diff --git a/src/engine/engine.h b/src/engine/engine.h index 171c74248..bc95b7ad0 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -375,7 +375,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 isSecond); + void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond); // returns true if end of song. bool nextTick(bool noAccum=false, bool inhibitLowLat=false); bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal); diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index e4a041d83..ae507738c 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -125,6 +125,9 @@ const char* DivPlatformGenesis::getEffectName(unsigned char effect) { case 0x5f: return "5Fxx: Set decay 2 of operator 4 (0 to 1F)"; break; + case 0xdf: + return "DFxx: Set sample playback direction (0: normal; 1: reverse)"; + break; } return NULL; } @@ -148,12 +151,12 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s if (s->samples>0) { if (!isMuted[5]) { if (dacReady && writes.size()<16) { - urgentWrite(0x2a,(unsigned char)s->data8[dacPos]+0x80); + urgentWrite(0x2a,(unsigned char)s->data8[dacDirection?(s->samples-dacPos-1):dacPos]+0x80); dacReady=false; } } if (++dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + if (s->loopStart>=0 && s->loopStart<(int)s->samples && !dacDirection) { dacPos=s->loopStart; } else { dacSample=-1; @@ -228,12 +231,12 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si if (s->samples>0) { if (!isMuted[5]) { if (dacReady && writes.size()<16) { - urgentWrite(0x2a,(unsigned char)s->data8[dacPos]+0x80); + urgentWrite(0x2a,(unsigned char)s->data8[dacDirection?(s->samples-dacPos-1):dacPos]+0x80); dacReady=false; } } if (++dacPos>=s->samples) { - if (s->loopStart>=0 && s->loopStart<(int)s->samples) { + if (s->loopStart>=0 && s->loopStart<(int)s->samples && !dacDirection) { dacPos=s->loopStart; } else { dacSample=-1; @@ -770,6 +773,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) { sampleBank=parent->song.sample.size()/12; } break; + case DIV_CMD_SAMPLE_DIR: { + dacDirection=c.value; + if (dumpWrites) addWrite(0xffff0003,dacDirection); + break; + } case DIV_CMD_LEGATO: { if (c.chan==5 && chan[c.chan].furnaceDac && dacMode) { chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); @@ -1062,11 +1070,14 @@ void DivPlatformGenesis::reset() { dacDelay=0; dacReady=true; dacSample=-1; + dacDirection=false; sampleBank=0; lfoValue=8; extMode=false; + if (dumpWrites) addWrite(0xffff0003,dacDirection); + // LFO immWrite(0x22,lfoValue); diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 236e5c43f..abc765109 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -93,6 +93,7 @@ class DivPlatformGenesis: public DivDispatch { int dacSample; int dacDelay; bool dacReady; + bool dacDirection; unsigned char sampleBank; unsigned char lfoValue; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 47c2140a4..3b11ab494 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -63,6 +63,7 @@ const char* cmdName[]={ "SAMPLE_FREQ", "SAMPLE_BANK", "SAMPLE_POS", + "SAMPLE_DIR", "FM_HARD_RESET", "FM_LFO", @@ -556,6 +557,9 @@ void DivEngine::processRow(int i, bool afterDelay) { clockDrift=0; subticks=0; break; + case 0xdf: // set sample direction + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_DIR,i,effectVal)); + break; case 0xe0: // arp speed if (effectVal>0) { curSubSong->arpLen=effectVal; diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index f11cb7b5c..0ba6bd280 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -24,7 +24,7 @@ constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; -void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool isSecond) { +void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond) { unsigned char baseAddr1=isSecond?0xa0:0x50; unsigned char baseAddr2=isSecond?0x80:0; unsigned short baseAddr2S=isSecond?0x8000:0; @@ -502,8 +502,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(0x95); w->writeC(streamID); w->writeS(write.val); // sample number - w->writeC((sample->loopStart==0)); // flags - if (sample->loopStart>0) { + w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags + if (sample->loopStart>0 && !sampleDir[streamID]) { loopTimer[streamID]=sample->length8; loopSample[streamID]=write.val; } @@ -520,6 +520,9 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(streamID); loopSample[streamID]=-1; break; + case 3: // set sample direction + sampleDir[streamID]=write.val; + break; } return; } @@ -884,11 +887,13 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { double loopTimer[DIV_MAX_CHANS]; double loopFreq[DIV_MAX_CHANS]; int loopSample[DIV_MAX_CHANS]; + bool sampleDir[DIV_MAX_CHANS]; for (int i=0; i& writes=disCont[i].dispatch->getRegisterWrites(); for (DivRegWrite& j: writes) { - performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,isSecond[i]); + performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i]); writeCount++; } writes.clear(); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 2b9923d3f..1b7274cd3 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -394,7 +394,7 @@ const FurnaceGUIColors fxColors[256]={ GUI_COLOR_PATTERN_EFFECT_INVALID, GUI_COLOR_PATTERN_EFFECT_INVALID, GUI_COLOR_PATTERN_EFFECT_INVALID, - GUI_COLOR_PATTERN_EFFECT_INVALID, + GUI_COLOR_PATTERN_EFFECT_MISC, // DF // E0-FF extended effects GUI_COLOR_PATTERN_EFFECT_MISC, // E0