dev113 - loop detection changes
This commit is contained in:
parent
ac0decd01b
commit
187653a70f
|
@ -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"
|
||||||
|
|
|
@ -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 -->
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
Loading…
Reference in New Issue