YM2612: add reverse sample playback

This commit is contained in:
tildearrow 2022-05-27 02:47:44 -05:00
parent 9d6d84a87f
commit 0b7d27dc29
7 changed files with 34 additions and 10 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -93,6 +93,7 @@ class DivPlatformGenesis: public DivDispatch {
int dacSample;
int dacDelay;
bool dacReady;
bool dacDirection;
unsigned char sampleBank;
unsigned char lfoValue;

View file

@ -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;

View file

@ -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<DIV_MAX_CHANS; i++) {
loopTimer[i]=0;
loopFreq[i]=0;
loopSample[i]=-1;
sampleDir[i]=false;
}
bool writeDACSamples=false;
@ -1762,7 +1767,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
for (int i=0; i<song.systemLen; i++) {
std::vector<DivRegWrite>& 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();

View file

@ -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