dev113 - loop detection changes

This commit is contained in:
tildearrow 2022-09-10 01:39:42 -05:00
parent ac0decd01b
commit 187653a70f
9 changed files with 87 additions and 16 deletions

View File

@ -15,8 +15,8 @@ android {
} }
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 26 targetSdkVersion 26
versionCode 112 versionCode 113
versionName "dev112" versionName "dev113"
externalNativeBuild { externalNativeBuild {
cmake { cmake {
arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static" arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static"

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.tildearrow.furnace" package="org.tildearrow.furnace"
android:versionCode="112" android:versionCode="113"
android:versionName="dev112" android:versionName="dev113"
android:installLocation="auto"> android:installLocation="auto">
<!-- OpenGL ES 2.0 --> <!-- OpenGL ES 2.0 -->

View File

@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
the format versions are: the format versions are:
- 113: Furnace dev113
- 112: Furnace dev112 - 112: Furnace dev112
- 111: Furnace dev111 - 111: Furnace dev111
- 110: Furnace dev110 - 110: Furnace dev110
@ -338,7 +339,8 @@ size | description
1 | broken initial position of porta after arp (>=101) or reserved 1 | broken initial position of porta after arp (>=101) or reserved
1 | SN periods under 8 are treated as 1 (>=108) or reserved 1 | SN periods under 8 are treated as 1 (>=108) or reserved
1 | cut/delay effect policy (>=110) or reserved 1 | cut/delay effect policy (>=110) or reserved
5 | reserved 1 | 0B/0D effect treatment (>=113) or reserved
4 | reserved
--- | **virtual tempo data** --- | **virtual tempo data**
2 | virtual tempo numerator of first song (>=96) or reserved 2 | virtual tempo numerator of first song (>=96) or reserved
2 | virtual tempo denominator of first song (>=96) or reserved 2 | virtual tempo denominator of first song (>=96) or reserved

View File

@ -1658,6 +1658,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
speedAB=false; speedAB=false;
playing=true; playing=true;
skipping=true; skipping=true;
memset(walked,0,8192);
for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(true); for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(true);
while (playing && curOrder<goal) { while (playing && curOrder<goal) {
if (nextTick(preserveDrift)) { if (nextTick(preserveDrift)) {

View File

@ -46,9 +46,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 "dev112" #define DIV_VERSION "dev113"
#define DIV_ENGINE_VERSION 112 #define DIV_ENGINE_VERSION 113
// for imports // for imports
#define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02 #define DIV_VERSION_FC 0xff02
@ -358,6 +357,8 @@ class DivEngine {
double exportFadeOut; double exportFadeOut;
std::map<String,String> conf; std::map<String,String> conf;
std::deque<DivNoteEvent> pendingNotes; std::deque<DivNoteEvent> pendingNotes;
// bitfield
unsigned char walked[8192];
bool isMuted[DIV_MAX_CHANS]; bool isMuted[DIV_MAX_CHANS];
std::mutex isBusy, saveLock; std::mutex isBusy, saveLock;
String configPath; String configPath;
@ -1072,6 +1073,7 @@ class DivEngine {
memset(reversePitchTable,0,4096*sizeof(int)); memset(reversePitchTable,0,4096*sizeof(int));
memset(pitchTable,0,4096*sizeof(int)); memset(pitchTable,0,4096*sizeof(int));
memset(sysDefs,0,256*sizeof(void*)); memset(sysDefs,0,256*sizeof(void*));
memset(walked,0,8192);
for (int i=0; i<256; i++) { for (int i=0; i<256; i++) {
sysFileMapFur[i]=DIV_SYSTEM_NULL; sysFileMapFur[i]=DIV_SYSTEM_NULL;

View File

@ -179,6 +179,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
ds.brokenPortaArp=false; ds.brokenPortaArp=false;
ds.snNoLowPeriods=true; ds.snNoLowPeriods=true;
ds.delayBehavior=0; ds.delayBehavior=0;
ds.jumpTreatment=2;
// 1.1 compat flags // 1.1 compat flags
if (ds.version>24) { if (ds.version>24) {
@ -1081,6 +1082,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (ds.version<110) { if (ds.version<110) {
ds.delayBehavior=1; ds.delayBehavior=1;
} }
if (ds.version<113) {
ds.jumpTreatment=1;
}
ds.isDMF=false; ds.isDMF=false;
reader.readS(); // reserved reader.readS(); // reserved
@ -1503,7 +1507,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
} else { } else {
reader.readC(); reader.readC();
} }
for (int i=0; i<5; i++) { if (ds.version>=113) {
ds.jumpTreatment=reader.readC();
} else {
reader.readC();
}
for (int i=0; i<4; i++) {
reader.readC(); reader.readC();
} }
} }
@ -3747,7 +3756,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
w->writeC(song.brokenPortaArp); w->writeC(song.brokenPortaArp);
w->writeC(song.snNoLowPeriods); w->writeC(song.snNoLowPeriods);
w->writeC(song.delayBehavior); w->writeC(song.delayBehavior);
for (int i=0; i<5; i++) { w->writeC(song.jumpTreatment);
for (int i=0; i<4; i++) {
w->writeC(0); w->writeC(0);
} }

View File

@ -31,7 +31,9 @@ void DivEngine::nextOrder() {
curRow=0; curRow=0;
if (repeatPattern) return; if (repeatPattern) return;
if (++curOrder>=curSubSong->ordersLen) { if (++curOrder>=curSubSong->ordersLen) {
logV("end of orders reached");
endOfSong=true; endOfSong=true;
memset(walked,0,8192);
curOrder=0; curOrder=0;
} }
} }
@ -348,15 +350,31 @@ void DivEngine::processRow(int i, bool afterDelay) {
if (effectVal>0) speed2=effectVal; if (effectVal>0) speed2=effectVal;
break; break;
case 0x0b: // change order case 0x0b: // change order
if (changeOrd==-1) { if (changeOrd==-1 || song.jumpTreatment==0) {
changeOrd=effectVal; changeOrd=effectVal;
changePos=0; if (song.jumpTreatment==1 || song.jumpTreatment==2) {
changePos=0;
}
} }
break; break;
case 0x0d: // next order case 0x0d: // next order
if (changeOrd<0 && (curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd)) { if (song.jumpTreatment==2) {
changeOrd=-2; if ((curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd)) {
changePos=effectVal; changeOrd=-2;
changePos=effectVal;
}
} else if (song.jumpTreatment==1) {
if (changeOrd<0 && (curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd)) {
changeOrd=-2;
changePos=effectVal;
}
} else {
if (curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd) {
if (changeOrd<0) {
changeOrd=-2;
}
changePos=effectVal;
}
} }
break; break;
case 0xed: // delay case 0xed: // delay
@ -911,18 +929,23 @@ void DivEngine::nextRow() {
processRow(i,false); processRow(i,false);
} }
walked[((curOrder<<5)+(curRow>>3))&8191]|=1<<(curRow&7);
if (changeOrd!=-1) { if (changeOrd!=-1) {
if (repeatPattern) { if (repeatPattern) {
curRow=0; curRow=0;
changeOrd=-1; changeOrd=-1;
} else { } else {
curRow=changePos; curRow=changePos;
changePos=0;
if (changeOrd==-2) changeOrd=curOrder+1; if (changeOrd==-2) changeOrd=curOrder+1;
if (changeOrd<=curOrder) endOfSong=true; // old loop detection routine
//if (changeOrd<=curOrder) endOfSong=true;
curOrder=changeOrd; curOrder=changeOrd;
if (curOrder>=curSubSong->ordersLen) { if (curOrder>=curSubSong->ordersLen) {
curOrder=0; curOrder=0;
endOfSong=true; endOfSong=true;
memset(walked,0,8192);
} }
changeOrd=-1; changeOrd=-1;
} }
@ -932,6 +955,13 @@ void DivEngine::nextRow() {
if (haltOn==DIV_HALT_PATTERN) halted=true; if (haltOn==DIV_HALT_PATTERN) halted=true;
} }
// new loop detection routine
if (!endOfSong && walked[((curOrder<<5)+(curRow>>3))&8191]&(1<<(curRow&7))) {
logV("loop reached");
endOfSong=true;
memset(walked,0,8192);
}
if (song.brokenSpeedSel) { if (song.brokenSpeedSel) {
if ((curSubSong->patLen&1) && curOrder&1) { if ((curSubSong->patLen&1) && curOrder&1) {
ticks=((curRow&1)?speed2:speed1)*(curSubSong->timeBase+1); ticks=((curRow&1)?speed2:speed1)*(curSubSong->timeBase+1);

View File

@ -468,6 +468,11 @@ struct DivSong {
// 1: broken (don't allow value higher than speed) // 1: broken (don't allow value higher than speed)
// 2: lax (allow value higher than speed) // 2: lax (allow value higher than speed)
unsigned char delayBehavior; unsigned char delayBehavior;
// 0B/0D treatment
// 0: normal (0B/0D accepted)
// 1: old Furnace (first one accepted)
// 2: DefleMask (0D takes priority over 0B)
unsigned char jumpTreatment;
bool properNoiseLayout; bool properNoiseLayout;
bool waveDutyIsVol; bool waveDutyIsVol;
bool resetMacroOnPorta; bool resetMacroOnPorta;
@ -571,6 +576,7 @@ struct DivSong {
pitchSlideSpeed(4), pitchSlideSpeed(4),
loopModality(2), loopModality(2),
delayBehavior(2), delayBehavior(2),
jumpTreatment(0),
properNoiseLayout(true), properNoiseLayout(true),
waveDutyIsVol(false), waveDutyIsVol(false),
resetMacroOnPorta(false), resetMacroOnPorta(false),

View File

@ -213,6 +213,26 @@ void FurnaceGUI::drawCompatFlags() {
ImGui::SetTooltip("no checks (like FamiTracker)"); ImGui::SetTooltip("no checks (like FamiTracker)");
} }
ImGui::Text("Simultaneous jump (0B+0D) treatment:");
if (ImGui::RadioButton("Normal",e->song.jumpTreatment==0)) {
e->song.jumpTreatment=0;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("accept 0B+0D to jump to a specific row of an order");
}
if (ImGui::RadioButton("Old Furnace",e->song.jumpTreatment==1)) {
e->song.jumpTreatment=1;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("only accept the first jump effect");
}
if (ImGui::RadioButton("DefleMask",e->song.jumpTreatment==2)) {
e->song.jumpTreatment=2;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("only accept 0Dxx");
}
ImGui::Separator(); ImGui::Separator();
ImGui::TextWrapped("the following flags are for compatibility with older Furnace versions."); ImGui::TextWrapped("the following flags are for compatibility with older Furnace versions.");