mirror of
https://github.com/tildearrow/furnace.git
synced 2024-12-03 17:57:26 +00:00
YM2612: add reverse sample playback
This commit is contained in:
parent
9d6d84a87f
commit
0b7d27dc29
7 changed files with 34 additions and 10 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
int dacSample;
|
||||
int dacDelay;
|
||||
bool dacReady;
|
||||
bool dacDirection;
|
||||
unsigned char sampleBank;
|
||||
unsigned char lfoValue;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue