dev71 - more compatibility flags for .mod
This commit is contained in:
parent
ece34990e5
commit
bd36a4ffdc
|
@ -29,6 +29,7 @@ furthermore, an `or reserved` indicates this field is always present, but is res
|
||||||
|
|
||||||
the format versions are:
|
the format versions are:
|
||||||
|
|
||||||
|
- 71: Furnace dev71
|
||||||
- 70: Furnace dev70
|
- 70: Furnace dev70
|
||||||
- 69: Furnace dev69
|
- 69: Furnace dev69
|
||||||
- 68: Furnace dev68
|
- 68: Furnace dev68
|
||||||
|
@ -238,7 +239,10 @@ size | description
|
||||||
| this is 2.0f for modules before 59
|
| this is 2.0f for modules before 59
|
||||||
--- | **extended compatibility flags** (>=70)
|
--- | **extended compatibility flags** (>=70)
|
||||||
1 | broken speed selection
|
1 | broken speed selection
|
||||||
31 | reserved
|
1 | no slides on first tick (>=71) or reserved
|
||||||
|
1 | next row reset arp pos (>=71) or reserved
|
||||||
|
1 | ignore jump at end (>=71) or reserved
|
||||||
|
28 | reserved
|
||||||
```
|
```
|
||||||
|
|
||||||
# instrument
|
# instrument
|
||||||
|
|
|
@ -144,7 +144,7 @@ void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) {
|
||||||
effectVal=pat[k]->data[j][5+(l<<1)];
|
effectVal=pat[k]->data[j][5+(l<<1)];
|
||||||
if (effectVal<0) effectVal=0;
|
if (effectVal<0) effectVal=0;
|
||||||
if (pat[k]->data[j][4+(l<<1)]==0x0d) {
|
if (pat[k]->data[j][4+(l<<1)]==0x0d) {
|
||||||
if (nextOrder==-1 && i<song.ordersLen-1) {
|
if (nextOrder==-1 && (i<song.ordersLen-1 || !song.ignoreJumpAtEnd)) {
|
||||||
nextOrder=i+1;
|
nextOrder=i+1;
|
||||||
nextRow=effectVal;
|
nextRow=effectVal;
|
||||||
}
|
}
|
||||||
|
@ -957,6 +957,7 @@ void DivEngine::reset() {
|
||||||
extValuePresent=0;
|
extValuePresent=0;
|
||||||
speed1=song.speed1;
|
speed1=song.speed1;
|
||||||
speed2=song.speed2;
|
speed2=song.speed2;
|
||||||
|
firstTick=false;
|
||||||
nextSpeed=speed1;
|
nextSpeed=speed1;
|
||||||
divider=60;
|
divider=60;
|
||||||
if (song.customTempo) {
|
if (song.customTempo) {
|
||||||
|
|
|
@ -42,8 +42,8 @@
|
||||||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||||
|
|
||||||
#define DIV_VERSION "dev70"
|
#define DIV_VERSION "dev71"
|
||||||
#define DIV_ENGINE_VERSION 70
|
#define DIV_ENGINE_VERSION 71
|
||||||
|
|
||||||
// for imports
|
// for imports
|
||||||
#define DIV_VERSION_MOD 0xff01
|
#define DIV_VERSION_MOD 0xff01
|
||||||
|
@ -190,6 +190,7 @@ class DivEngine {
|
||||||
bool forceMono;
|
bool forceMono;
|
||||||
bool cmdStreamEnabled;
|
bool cmdStreamEnabled;
|
||||||
bool softLocked;
|
bool softLocked;
|
||||||
|
bool firstTick;
|
||||||
int softLockCount;
|
int softLockCount;
|
||||||
int ticks, curRow, curOrder, remainingLoops, nextSpeed;
|
int ticks, curRow, curOrder, remainingLoops, nextSpeed;
|
||||||
double divider;
|
double divider;
|
||||||
|
@ -682,7 +683,8 @@ class DivEngine {
|
||||||
halted(false),
|
halted(false),
|
||||||
forceMono(false),
|
forceMono(false),
|
||||||
cmdStreamEnabled(false),
|
cmdStreamEnabled(false),
|
||||||
softLocked(0),
|
softLocked(false),
|
||||||
|
firstTick(false),
|
||||||
softLockCount(0),
|
softLockCount(0),
|
||||||
ticks(0),
|
ticks(0),
|
||||||
curRow(0),
|
curRow(0),
|
||||||
|
|
|
@ -145,6 +145,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
||||||
ds.newInsTriggersInPorta=true;
|
ds.newInsTriggersInPorta=true;
|
||||||
ds.arp0Reset=true;
|
ds.arp0Reset=true;
|
||||||
ds.brokenSpeedSel=true;
|
ds.brokenSpeedSel=true;
|
||||||
|
ds.noSlidesOnFirstTick=false;
|
||||||
|
ds.rowResetsArpPos=false;
|
||||||
|
ds.ignoreJumpAtEnd=true;
|
||||||
|
|
||||||
// 1.1 compat flags
|
// 1.1 compat flags
|
||||||
if (ds.version>24) {
|
if (ds.version>24) {
|
||||||
|
@ -825,6 +828,11 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
if (ds.version<69) {
|
if (ds.version<69) {
|
||||||
ds.arp0Reset=false;
|
ds.arp0Reset=false;
|
||||||
}
|
}
|
||||||
|
if (ds.version<71) {
|
||||||
|
ds.noSlidesOnFirstTick=false;
|
||||||
|
ds.rowResetsArpPos=false;
|
||||||
|
ds.ignoreJumpAtEnd=true;
|
||||||
|
}
|
||||||
ds.isDMF=false;
|
ds.isDMF=false;
|
||||||
|
|
||||||
reader.readS(); // reserved
|
reader.readS(); // reserved
|
||||||
|
@ -1071,7 +1079,16 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
if (ds.version>=70) {
|
if (ds.version>=70) {
|
||||||
// extended compat flags
|
// extended compat flags
|
||||||
ds.brokenSpeedSel=reader.readC();
|
ds.brokenSpeedSel=reader.readC();
|
||||||
for (int i=0; i<31; i++) {
|
if (ds.version>=71) {
|
||||||
|
song.noSlidesOnFirstTick=reader.readC();
|
||||||
|
song.rowResetsArpPos=reader.readC();
|
||||||
|
song.ignoreJumpAtEnd=reader.readC();
|
||||||
|
} else {
|
||||||
|
reader.readC();
|
||||||
|
reader.readC();
|
||||||
|
reader.readC();
|
||||||
|
}
|
||||||
|
for (int i=0; i<28; i++) {
|
||||||
reader.readC();
|
reader.readC();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1282,6 +1299,9 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
||||||
DivSong ds;
|
DivSong ds;
|
||||||
ds.tuning=436.0;
|
ds.tuning=436.0;
|
||||||
ds.version=DIV_VERSION_MOD;
|
ds.version=DIV_VERSION_MOD;
|
||||||
|
ds.noSlidesOnFirstTick=true;
|
||||||
|
ds.rowResetsArpPos=true;
|
||||||
|
ds.ignoreJumpAtEnd=false;
|
||||||
|
|
||||||
int insCount=31;
|
int insCount=31;
|
||||||
bool bypassLimits=false;
|
bool bypassLimits=false;
|
||||||
|
@ -1916,7 +1936,10 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
||||||
|
|
||||||
// extended compat flags
|
// extended compat flags
|
||||||
w->writeC(song.brokenSpeedSel);
|
w->writeC(song.brokenSpeedSel);
|
||||||
for (int i=0; i<31; i++) {
|
w->writeC(song.noSlidesOnFirstTick);
|
||||||
|
w->writeC(song.rowResetsArpPos);
|
||||||
|
w->writeC(song.ignoreJumpAtEnd);
|
||||||
|
for (int i=0; i<28; i++) {
|
||||||
w->writeC(0);
|
w->writeC(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -821,7 +821,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0d: // next order
|
case 0x0d: // next order
|
||||||
if (changeOrd<0 && curOrder<(song.ordersLen-1)) {
|
if (changeOrd<0 && (curOrder<(song.ordersLen-1) || !song.ignoreJumpAtEnd)) {
|
||||||
changeOrd=-2;
|
changeOrd=-2;
|
||||||
changePos=effectVal;
|
changePos=effectVal;
|
||||||
}
|
}
|
||||||
|
@ -1229,6 +1229,7 @@ void DivEngine::nextRow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (haltOn==DIV_HALT_ROW) halted=true;
|
if (haltOn==DIV_HALT_ROW) halted=true;
|
||||||
|
firstTick=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivEngine::nextTick(bool noAccum) {
|
bool DivEngine::nextTick(bool noAccum) {
|
||||||
|
@ -1281,23 +1282,25 @@ bool DivEngine::nextTick(bool noAccum) {
|
||||||
keyHit[i]=true;
|
keyHit[i]=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chan[i].volSpeed!=0) {
|
if (!song.noSlidesOnFirstTick || !firstTick) {
|
||||||
chan[i].volume=(chan[i].volume&0xff)|(dispatchCmd(DivCommand(DIV_CMD_GET_VOLUME,i))<<8);
|
if (chan[i].volSpeed!=0) {
|
||||||
chan[i].volume+=chan[i].volSpeed;
|
chan[i].volume=(chan[i].volume&0xff)|(dispatchCmd(DivCommand(DIV_CMD_GET_VOLUME,i))<<8);
|
||||||
if (chan[i].volume>chan[i].volMax) {
|
chan[i].volume+=chan[i].volSpeed;
|
||||||
chan[i].volume=chan[i].volMax;
|
if (chan[i].volume>chan[i].volMax) {
|
||||||
chan[i].volSpeed=0;
|
chan[i].volume=chan[i].volMax;
|
||||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
chan[i].volSpeed=0;
|
||||||
} else if (chan[i].volume<0) {
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
chan[i].volSpeed=0;
|
} else if (chan[i].volume<0) {
|
||||||
if (song.legacyVolumeSlides) {
|
chan[i].volSpeed=0;
|
||||||
chan[i].volume=chan[i].volMax+1;
|
if (song.legacyVolumeSlides) {
|
||||||
|
chan[i].volume=chan[i].volMax+1;
|
||||||
|
} else {
|
||||||
|
chan[i].volume=0;
|
||||||
|
}
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
} else {
|
} else {
|
||||||
chan[i].volume=0;
|
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||||
}
|
}
|
||||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
|
||||||
} else {
|
|
||||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chan[i].vibratoDepth>0) {
|
if (chan[i].vibratoDepth>0) {
|
||||||
|
@ -1315,13 +1318,15 @@ bool DivEngine::nextTick(bool noAccum) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((chan[i].keyOn || chan[i].keyOff) && chan[i].portaSpeed>0) {
|
if (!song.noSlidesOnFirstTick || !firstTick) {
|
||||||
if (dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed,chan[i].portaNote))==2 && chan[i].portaStop && song.targetResetsSlides) {
|
if ((chan[i].keyOn || chan[i].keyOff) && chan[i].portaSpeed>0) {
|
||||||
chan[i].portaSpeed=0;
|
if (dispatchCmd(DivCommand(DIV_CMD_NOTE_PORTA,i,chan[i].portaSpeed,chan[i].portaNote))==2 && chan[i].portaStop && song.targetResetsSlides) {
|
||||||
chan[i].oldNote=chan[i].note;
|
chan[i].portaSpeed=0;
|
||||||
chan[i].note=chan[i].portaNote;
|
chan[i].oldNote=chan[i].note;
|
||||||
chan[i].inPorta=false;
|
chan[i].note=chan[i].portaNote;
|
||||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
chan[i].inPorta=false;
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chan[i].cut>0) {
|
if (chan[i].cut>0) {
|
||||||
|
@ -1354,6 +1359,9 @@ bool DivEngine::nextTick(bool noAccum) {
|
||||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||||
chan[i].resetArp=false;
|
chan[i].resetArp=false;
|
||||||
}
|
}
|
||||||
|
if (song.rowResetsArpPos && firstTick) {
|
||||||
|
chan[i].arpStage=-1;
|
||||||
|
}
|
||||||
if (chan[i].arp!=0 && !chan[i].arpYield && chan[i].portaSpeed<1) {
|
if (chan[i].arp!=0 && !chan[i].arpYield && chan[i].portaSpeed<1) {
|
||||||
if (--chan[i].arpTicks<1) {
|
if (--chan[i].arpTicks<1) {
|
||||||
chan[i].arpTicks=song.arpLen;
|
chan[i].arpTicks=song.arpLen;
|
||||||
|
@ -1377,6 +1385,8 @@ bool DivEngine::nextTick(bool noAccum) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
firstTick=false;
|
||||||
|
|
||||||
// system tick
|
// system tick
|
||||||
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->tick();
|
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->tick();
|
||||||
|
|
||||||
|
|
|
@ -302,6 +302,9 @@ struct DivSong {
|
||||||
bool newInsTriggersInPorta;
|
bool newInsTriggersInPorta;
|
||||||
bool arp0Reset;
|
bool arp0Reset;
|
||||||
bool brokenSpeedSel;
|
bool brokenSpeedSel;
|
||||||
|
bool noSlidesOnFirstTick;
|
||||||
|
bool rowResetsArpPos;
|
||||||
|
bool ignoreJumpAtEnd;
|
||||||
|
|
||||||
DivOrders orders;
|
DivOrders orders;
|
||||||
std::vector<DivInstrument*> ins;
|
std::vector<DivInstrument*> ins;
|
||||||
|
@ -375,7 +378,10 @@ struct DivSong {
|
||||||
oneTickCut(false),
|
oneTickCut(false),
|
||||||
newInsTriggersInPorta(true),
|
newInsTriggersInPorta(true),
|
||||||
arp0Reset(true),
|
arp0Reset(true),
|
||||||
brokenSpeedSel(false) {
|
brokenSpeedSel(false),
|
||||||
|
noSlidesOnFirstTick(false),
|
||||||
|
rowResetsArpPos(false),
|
||||||
|
ignoreJumpAtEnd(false) {
|
||||||
for (int i=0; i<32; i++) {
|
for (int i=0; i<32; i++) {
|
||||||
system[i]=DIV_SYSTEM_NULL;
|
system[i]=DIV_SYSTEM_NULL;
|
||||||
systemVol[i]=64;
|
systemVol[i]=64;
|
||||||
|
|
|
@ -85,6 +85,18 @@ void FurnaceGUI::drawCompatFlags() {
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("determines next speed based on whether the row is odd/even instead of alternating between speeds.");
|
ImGui::SetTooltip("determines next speed based on whether the row is odd/even instead of alternating between speeds.");
|
||||||
}
|
}
|
||||||
|
ImGui::Checkbox("Don't slide on the first tick of a row",&e->song.noSlidesOnFirstTick);
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("simulates ProTracker's behavior of not applying volume/pitch slides on the first tick of a row.");
|
||||||
|
}
|
||||||
|
ImGui::Checkbox("Reset arpeggio position on row change",&e->song.rowResetsArpPos);
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("simulates ProTracker's behavior of arpeggio being bound to the current tick of a row.");
|
||||||
|
}
|
||||||
|
ImGui::Checkbox("Ignore 0Dxx on the last order",&e->song.ignoreJumpAtEnd);
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("if this is on, a jump to next row effect will not take place when it is on the last order of a song.");
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Text("Loop modality:");
|
ImGui::Text("Loop modality:");
|
||||||
if (ImGui::RadioButton("Reset channels",e->song.loopModality==0)) {
|
if (ImGui::RadioButton("Reset channels",e->song.loopModality==0)) {
|
||||||
|
|
Loading…
Reference in a new issue