mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-23 04:55:13 +00:00
dev71 - more compatibility flags for .mod
This commit is contained in:
parent
ece34990e5
commit
bd36a4ffdc
7 changed files with 89 additions and 31 deletions
|
@ -29,6 +29,7 @@ furthermore, an `or reserved` indicates this field is always present, but is res
|
|||
|
||||
the format versions are:
|
||||
|
||||
- 71: Furnace dev71
|
||||
- 70: Furnace dev70
|
||||
- 69: Furnace dev69
|
||||
- 68: Furnace dev68
|
||||
|
@ -238,7 +239,10 @@ size | description
|
|||
| this is 2.0f for modules before 59
|
||||
--- | **extended compatibility flags** (>=70)
|
||||
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
|
||||
|
|
|
@ -144,7 +144,7 @@ void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) {
|
|||
effectVal=pat[k]->data[j][5+(l<<1)];
|
||||
if (effectVal<0) effectVal=0;
|
||||
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;
|
||||
nextRow=effectVal;
|
||||
}
|
||||
|
@ -957,6 +957,7 @@ void DivEngine::reset() {
|
|||
extValuePresent=0;
|
||||
speed1=song.speed1;
|
||||
speed2=song.speed2;
|
||||
firstTick=false;
|
||||
nextSpeed=speed1;
|
||||
divider=60;
|
||||
if (song.customTempo) {
|
||||
|
|
|
@ -42,8 +42,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev70"
|
||||
#define DIV_ENGINE_VERSION 70
|
||||
#define DIV_VERSION "dev71"
|
||||
#define DIV_ENGINE_VERSION 71
|
||||
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
|
@ -190,6 +190,7 @@ class DivEngine {
|
|||
bool forceMono;
|
||||
bool cmdStreamEnabled;
|
||||
bool softLocked;
|
||||
bool firstTick;
|
||||
int softLockCount;
|
||||
int ticks, curRow, curOrder, remainingLoops, nextSpeed;
|
||||
double divider;
|
||||
|
@ -682,7 +683,8 @@ class DivEngine {
|
|||
halted(false),
|
||||
forceMono(false),
|
||||
cmdStreamEnabled(false),
|
||||
softLocked(0),
|
||||
softLocked(false),
|
||||
firstTick(false),
|
||||
softLockCount(0),
|
||||
ticks(0),
|
||||
curRow(0),
|
||||
|
|
|
@ -145,6 +145,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.newInsTriggersInPorta=true;
|
||||
ds.arp0Reset=true;
|
||||
ds.brokenSpeedSel=true;
|
||||
ds.noSlidesOnFirstTick=false;
|
||||
ds.rowResetsArpPos=false;
|
||||
ds.ignoreJumpAtEnd=true;
|
||||
|
||||
// 1.1 compat flags
|
||||
if (ds.version>24) {
|
||||
|
@ -825,6 +828,11 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (ds.version<69) {
|
||||
ds.arp0Reset=false;
|
||||
}
|
||||
if (ds.version<71) {
|
||||
ds.noSlidesOnFirstTick=false;
|
||||
ds.rowResetsArpPos=false;
|
||||
ds.ignoreJumpAtEnd=true;
|
||||
}
|
||||
ds.isDMF=false;
|
||||
|
||||
reader.readS(); // reserved
|
||||
|
@ -1071,7 +1079,16 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (ds.version>=70) {
|
||||
// extended compat flags
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -1282,6 +1299,9 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
DivSong ds;
|
||||
ds.tuning=436.0;
|
||||
ds.version=DIV_VERSION_MOD;
|
||||
ds.noSlidesOnFirstTick=true;
|
||||
ds.rowResetsArpPos=true;
|
||||
ds.ignoreJumpAtEnd=false;
|
||||
|
||||
int insCount=31;
|
||||
bool bypassLimits=false;
|
||||
|
@ -1916,7 +1936,10 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
|
||||
// extended compat flags
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -821,7 +821,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
}
|
||||
break;
|
||||
case 0x0d: // next order
|
||||
if (changeOrd<0 && curOrder<(song.ordersLen-1)) {
|
||||
if (changeOrd<0 && (curOrder<(song.ordersLen-1) || !song.ignoreJumpAtEnd)) {
|
||||
changeOrd=-2;
|
||||
changePos=effectVal;
|
||||
}
|
||||
|
@ -1229,6 +1229,7 @@ void DivEngine::nextRow() {
|
|||
}
|
||||
|
||||
if (haltOn==DIV_HALT_ROW) halted=true;
|
||||
firstTick=true;
|
||||
}
|
||||
|
||||
bool DivEngine::nextTick(bool noAccum) {
|
||||
|
@ -1281,23 +1282,25 @@ bool DivEngine::nextTick(bool noAccum) {
|
|||
keyHit[i]=true;
|
||||
}
|
||||
}
|
||||
if (chan[i].volSpeed!=0) {
|
||||
chan[i].volume=(chan[i].volume&0xff)|(dispatchCmd(DivCommand(DIV_CMD_GET_VOLUME,i))<<8);
|
||||
chan[i].volume+=chan[i].volSpeed;
|
||||
if (chan[i].volume>chan[i].volMax) {
|
||||
chan[i].volume=chan[i].volMax;
|
||||
chan[i].volSpeed=0;
|
||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||
} else if (chan[i].volume<0) {
|
||||
chan[i].volSpeed=0;
|
||||
if (song.legacyVolumeSlides) {
|
||||
chan[i].volume=chan[i].volMax+1;
|
||||
if (!song.noSlidesOnFirstTick || !firstTick) {
|
||||
if (chan[i].volSpeed!=0) {
|
||||
chan[i].volume=(chan[i].volume&0xff)|(dispatchCmd(DivCommand(DIV_CMD_GET_VOLUME,i))<<8);
|
||||
chan[i].volume+=chan[i].volSpeed;
|
||||
if (chan[i].volume>chan[i].volMax) {
|
||||
chan[i].volume=chan[i].volMax;
|
||||
chan[i].volSpeed=0;
|
||||
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
|
||||
} else if (chan[i].volume<0) {
|
||||
chan[i].volSpeed=0;
|
||||
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 {
|
||||
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) {
|
||||
|
@ -1315,13 +1318,15 @@ bool DivEngine::nextTick(bool noAccum) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ((chan[i].keyOn || chan[i].keyOff) && 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].portaSpeed=0;
|
||||
chan[i].oldNote=chan[i].note;
|
||||
chan[i].note=chan[i].portaNote;
|
||||
chan[i].inPorta=false;
|
||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||
if (!song.noSlidesOnFirstTick || !firstTick) {
|
||||
if ((chan[i].keyOn || chan[i].keyOff) && 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].portaSpeed=0;
|
||||
chan[i].oldNote=chan[i].note;
|
||||
chan[i].note=chan[i].portaNote;
|
||||
chan[i].inPorta=false;
|
||||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].cut>0) {
|
||||
|
@ -1354,6 +1359,9 @@ bool DivEngine::nextTick(bool noAccum) {
|
|||
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
|
||||
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].arpTicks<1) {
|
||||
chan[i].arpTicks=song.arpLen;
|
||||
|
@ -1377,6 +1385,8 @@ bool DivEngine::nextTick(bool noAccum) {
|
|||
}
|
||||
}
|
||||
|
||||
firstTick=false;
|
||||
|
||||
// system tick
|
||||
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->tick();
|
||||
|
||||
|
|
|
@ -302,6 +302,9 @@ struct DivSong {
|
|||
bool newInsTriggersInPorta;
|
||||
bool arp0Reset;
|
||||
bool brokenSpeedSel;
|
||||
bool noSlidesOnFirstTick;
|
||||
bool rowResetsArpPos;
|
||||
bool ignoreJumpAtEnd;
|
||||
|
||||
DivOrders orders;
|
||||
std::vector<DivInstrument*> ins;
|
||||
|
@ -375,7 +378,10 @@ struct DivSong {
|
|||
oneTickCut(false),
|
||||
newInsTriggersInPorta(true),
|
||||
arp0Reset(true),
|
||||
brokenSpeedSel(false) {
|
||||
brokenSpeedSel(false),
|
||||
noSlidesOnFirstTick(false),
|
||||
rowResetsArpPos(false),
|
||||
ignoreJumpAtEnd(false) {
|
||||
for (int i=0; i<32; i++) {
|
||||
system[i]=DIV_SYSTEM_NULL;
|
||||
systemVol[i]=64;
|
||||
|
|
|
@ -85,6 +85,18 @@ void FurnaceGUI::drawCompatFlags() {
|
|||
if (ImGui::IsItemHovered()) {
|
||||
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:");
|
||||
if (ImGui::RadioButton("Reset channels",e->song.loopModality==0)) {
|
||||
|
|
Loading…
Reference in a new issue