YM2612: add reverse sample playback
This commit is contained in:
parent
9d6d84a87f
commit
0b7d27dc29
|
@ -59,6 +59,7 @@ enum DivDispatchCmds {
|
||||||
DIV_CMD_SAMPLE_FREQ, // (frequency)
|
DIV_CMD_SAMPLE_FREQ, // (frequency)
|
||||||
DIV_CMD_SAMPLE_BANK, // (bank)
|
DIV_CMD_SAMPLE_BANK, // (bank)
|
||||||
DIV_CMD_SAMPLE_POS, // (pos)
|
DIV_CMD_SAMPLE_POS, // (pos)
|
||||||
|
DIV_CMD_SAMPLE_DIR, // (direction)
|
||||||
|
|
||||||
DIV_CMD_FM_HARD_RESET, // (enabled)
|
DIV_CMD_FM_HARD_RESET, // (enabled)
|
||||||
DIV_CMD_FM_LFO, // (speed)
|
DIV_CMD_FM_LFO, // (speed)
|
||||||
|
@ -222,6 +223,8 @@ struct DivRegWrite {
|
||||||
* - data is the sample rate
|
* - data is the sample rate
|
||||||
* - 0xffffxx02: stop sample playback
|
* - 0xffffxx02: stop sample playback
|
||||||
* - xx is the instance ID
|
* - xx is the instance ID
|
||||||
|
* - 0xffffxx03: set sample playback direction
|
||||||
|
* - x is the instance ID
|
||||||
* - 0xffffffff: reset
|
* - 0xffffffff: reset
|
||||||
*/
|
*/
|
||||||
unsigned int addr;
|
unsigned int addr;
|
||||||
|
|
|
@ -375,7 +375,7 @@ class DivEngine {
|
||||||
void processRow(int i, bool afterDelay);
|
void processRow(int i, bool afterDelay);
|
||||||
void nextOrder();
|
void nextOrder();
|
||||||
void nextRow();
|
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.
|
// returns true if end of song.
|
||||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||||
|
|
|
@ -125,6 +125,9 @@ const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
|
||||||
case 0x5f:
|
case 0x5f:
|
||||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||||
break;
|
break;
|
||||||
|
case 0xdf:
|
||||||
|
return "DFxx: Set sample playback direction (0: normal; 1: reverse)";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -148,12 +151,12 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s
|
||||||
if (s->samples>0) {
|
if (s->samples>0) {
|
||||||
if (!isMuted[5]) {
|
if (!isMuted[5]) {
|
||||||
if (dacReady && writes.size()<16) {
|
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;
|
dacReady=false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (++dacPos>=s->samples) {
|
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;
|
dacPos=s->loopStart;
|
||||||
} else {
|
} else {
|
||||||
dacSample=-1;
|
dacSample=-1;
|
||||||
|
@ -228,12 +231,12 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si
|
||||||
if (s->samples>0) {
|
if (s->samples>0) {
|
||||||
if (!isMuted[5]) {
|
if (!isMuted[5]) {
|
||||||
if (dacReady && writes.size()<16) {
|
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;
|
dacReady=false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (++dacPos>=s->samples) {
|
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;
|
dacPos=s->loopStart;
|
||||||
} else {
|
} else {
|
||||||
dacSample=-1;
|
dacSample=-1;
|
||||||
|
@ -770,6 +773,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
sampleBank=parent->song.sample.size()/12;
|
sampleBank=parent->song.sample.size()/12;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DIV_CMD_SAMPLE_DIR: {
|
||||||
|
dacDirection=c.value;
|
||||||
|
if (dumpWrites) addWrite(0xffff0003,dacDirection);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DIV_CMD_LEGATO: {
|
case DIV_CMD_LEGATO: {
|
||||||
if (c.chan==5 && chan[c.chan].furnaceDac && dacMode) {
|
if (c.chan==5 && chan[c.chan].furnaceDac && dacMode) {
|
||||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||||
|
@ -1062,11 +1070,14 @@ void DivPlatformGenesis::reset() {
|
||||||
dacDelay=0;
|
dacDelay=0;
|
||||||
dacReady=true;
|
dacReady=true;
|
||||||
dacSample=-1;
|
dacSample=-1;
|
||||||
|
dacDirection=false;
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
lfoValue=8;
|
lfoValue=8;
|
||||||
|
|
||||||
extMode=false;
|
extMode=false;
|
||||||
|
|
||||||
|
if (dumpWrites) addWrite(0xffff0003,dacDirection);
|
||||||
|
|
||||||
// LFO
|
// LFO
|
||||||
immWrite(0x22,lfoValue);
|
immWrite(0x22,lfoValue);
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ class DivPlatformGenesis: public DivDispatch {
|
||||||
int dacSample;
|
int dacSample;
|
||||||
int dacDelay;
|
int dacDelay;
|
||||||
bool dacReady;
|
bool dacReady;
|
||||||
|
bool dacDirection;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
unsigned char lfoValue;
|
unsigned char lfoValue;
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ const char* cmdName[]={
|
||||||
"SAMPLE_FREQ",
|
"SAMPLE_FREQ",
|
||||||
"SAMPLE_BANK",
|
"SAMPLE_BANK",
|
||||||
"SAMPLE_POS",
|
"SAMPLE_POS",
|
||||||
|
"SAMPLE_DIR",
|
||||||
|
|
||||||
"FM_HARD_RESET",
|
"FM_HARD_RESET",
|
||||||
"FM_LFO",
|
"FM_LFO",
|
||||||
|
@ -556,6 +557,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
||||||
clockDrift=0;
|
clockDrift=0;
|
||||||
subticks=0;
|
subticks=0;
|
||||||
break;
|
break;
|
||||||
|
case 0xdf: // set sample direction
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_DIR,i,effectVal));
|
||||||
|
break;
|
||||||
case 0xe0: // arp speed
|
case 0xe0: // arp speed
|
||||||
if (effectVal>0) {
|
if (effectVal>0) {
|
||||||
curSubSong->arpLen=effectVal;
|
curSubSong->arpLen=effectVal;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
|
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 baseAddr1=isSecond?0xa0:0x50;
|
||||||
unsigned char baseAddr2=isSecond?0x80:0;
|
unsigned char baseAddr2=isSecond?0x80:0;
|
||||||
unsigned short baseAddr2S=isSecond?0x8000: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(0x95);
|
||||||
w->writeC(streamID);
|
w->writeC(streamID);
|
||||||
w->writeS(write.val); // sample number
|
w->writeS(write.val); // sample number
|
||||||
w->writeC((sample->loopStart==0)); // flags
|
w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags
|
||||||
if (sample->loopStart>0) {
|
if (sample->loopStart>0 && !sampleDir[streamID]) {
|
||||||
loopTimer[streamID]=sample->length8;
|
loopTimer[streamID]=sample->length8;
|
||||||
loopSample[streamID]=write.val;
|
loopSample[streamID]=write.val;
|
||||||
}
|
}
|
||||||
|
@ -520,6 +520,9 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
w->writeC(streamID);
|
w->writeC(streamID);
|
||||||
loopSample[streamID]=-1;
|
loopSample[streamID]=-1;
|
||||||
break;
|
break;
|
||||||
|
case 3: // set sample direction
|
||||||
|
sampleDir[streamID]=write.val;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -884,11 +887,13 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
||||||
double loopTimer[DIV_MAX_CHANS];
|
double loopTimer[DIV_MAX_CHANS];
|
||||||
double loopFreq[DIV_MAX_CHANS];
|
double loopFreq[DIV_MAX_CHANS];
|
||||||
int loopSample[DIV_MAX_CHANS];
|
int loopSample[DIV_MAX_CHANS];
|
||||||
|
bool sampleDir[DIV_MAX_CHANS];
|
||||||
|
|
||||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||||
loopTimer[i]=0;
|
loopTimer[i]=0;
|
||||||
loopFreq[i]=0;
|
loopFreq[i]=0;
|
||||||
loopSample[i]=-1;
|
loopSample[i]=-1;
|
||||||
|
sampleDir[i]=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeDACSamples=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++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
||||||
for (DivRegWrite& j: writes) {
|
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++;
|
writeCount++;
|
||||||
}
|
}
|
||||||
writes.clear();
|
writes.clear();
|
||||||
|
|
|
@ -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_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_MISC, // DF
|
||||||
|
|
||||||
// E0-FF extended effects
|
// E0-FF extended effects
|
||||||
GUI_COLOR_PATTERN_EFFECT_MISC, // E0
|
GUI_COLOR_PATTERN_EFFECT_MISC, // E0
|
||||||
|
|
Loading…
Reference in a new issue