better subsong detection for import

This commit is contained in:
tildearrow 2024-06-26 04:03:49 -05:00
parent 40a24d6c01
commit e1746def3a
7 changed files with 211 additions and 80 deletions

View file

@ -188,79 +188,8 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
}
void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) {
loopOrder=0;
loopRow=0;
loopEnd=-1;
int nextOrder=-1;
int nextRow=0;
int effectVal=0;
int lastSuspectedLoopEnd=-1;
DivPattern* pat[DIV_MAX_CHANS];
unsigned char wsWalked[8192];
memset(wsWalked,0,8192);
for (int i=0; i<curSubSong->ordersLen; i++) {
for (int j=0; j<chans; j++) {
pat[j]=curPat[j].getPattern(curOrders->ord[j][i],false);
}
if (i>lastSuspectedLoopEnd) {
lastSuspectedLoopEnd=i;
}
for (int j=nextRow; j<curSubSong->patLen; j++) {
nextRow=0;
bool changingOrder=false;
bool jumpingOrder=false;
if (wsWalked[((i<<5)+(j>>3))&8191]&(1<<(j&7))) {
loopOrder=i;
loopRow=j;
loopEnd=lastSuspectedLoopEnd;
return;
}
for (int k=0; k<chans; k++) {
for (int l=0; l<curPat[k].effectCols; l++) {
effectVal=pat[k]->data[j][5+(l<<1)];
if (effectVal<0) effectVal=0;
if (pat[k]->data[j][4+(l<<1)]==0x0d) {
if (song.jumpTreatment==2) {
if ((i<curSubSong->ordersLen-1 || !song.ignoreJumpAtEnd)) {
nextOrder=i+1;
nextRow=effectVal;
jumpingOrder=true;
}
} else if (song.jumpTreatment==1) {
if (nextOrder==-1 && (i<curSubSong->ordersLen-1 || !song.ignoreJumpAtEnd)) {
nextOrder=i+1;
nextRow=effectVal;
jumpingOrder=true;
}
} else {
if ((i<curSubSong->ordersLen-1 || !song.ignoreJumpAtEnd)) {
if (!changingOrder) {
nextOrder=i+1;
}
jumpingOrder=true;
nextRow=effectVal;
}
}
} else if (pat[k]->data[j][4+(l<<1)]==0x0b) {
if (nextOrder==-1 || song.jumpTreatment==0) {
nextOrder=effectVal;
if (song.jumpTreatment==1 || song.jumpTreatment==2 || !jumpingOrder) {
nextRow=0;
}
changingOrder=true;
}
}
}
}
wsWalked[((i<<5)+(j>>3))&8191]|=1<<(j&7);
if (nextOrder!=-1) {
i=nextOrder-1;
nextOrder=-1;
break;
}
}
if (curSubSong!=NULL) {
curSubSong->walk(loopOrder,loopRow,loopEnd,chans,song.jumpTreatment,song.ignoreJumpAtEnd);
}
}

View file

@ -1031,7 +1031,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
logV("maxChan: %d",maxChan);
// set channel visibility
for (int i=maxChan+1; i<((maxChan+32)&(~31)); i++) {
for (int i=maxChan; i<((maxChan+32)&(~31)); i++) {
ds.subsong[0]->chanShow[i]=false;
ds.subsong[0]->chanShowChanOsc[i]=false;
}
@ -1085,7 +1085,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
ds.systemLen=(maxChan+32)>>5;
// find subsongs
ds.findSubSongs();
ds.findSubSongs(maxChan);
if (active) quitDispatch();
BUSY_BEGIN_SOFT;

View file

@ -419,7 +419,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
ds.insLen=ds.ins.size();
// find subsongs
ds.findSubSongs();
ds.findSubSongs(chCount);
if (active) quitDispatch();
BUSY_BEGIN_SOFT;

View file

@ -1026,7 +1026,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
}
// find subsongs
ds.findSubSongs();
ds.findSubSongs(DIV_MAX_CHANS);
if (active) quitDispatch();
BUSY_BEGIN_SOFT;

View file

@ -371,7 +371,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
ds.sampleLen=ds.sample.size();
// find subsongs
ds.findSubSongs();
ds.findSubSongs(totalChans);
if (active) quitDispatch();
BUSY_BEGIN_SOFT;

View file

@ -20,6 +20,88 @@
#include "song.h"
#include "../ta-log.h"
bool DivSubSong::walk(int& loopOrder, int& loopRow, int& loopEnd, int chans, int jumpTreatment, int ignoreJumpAtEnd, int firstPat) {
loopOrder=0;
loopRow=0;
loopEnd=-1;
int nextOrder=-1;
int nextRow=0;
int effectVal=0;
int lastSuspectedLoopEnd=-1;
DivPattern* subPat[DIV_MAX_CHANS];
unsigned char wsWalked[8192];
memset(wsWalked,0,8192);
if (firstPat>0) {
memset(wsWalked,255,32*firstPat);
}
for (int i=firstPat; i<ordersLen; i++) {
for (int j=0; j<chans; j++) {
subPat[j]=pat[j].getPattern(orders.ord[j][i],false);
}
if (i>lastSuspectedLoopEnd) {
lastSuspectedLoopEnd=i;
}
for (int j=nextRow; j<patLen; j++) {
nextRow=0;
bool changingOrder=false;
bool jumpingOrder=false;
if (wsWalked[((i<<5)+(j>>3))&8191]&(1<<(j&7))) {
loopOrder=i;
loopRow=j;
loopEnd=lastSuspectedLoopEnd;
return true;
}
for (int k=0; k<chans; k++) {
for (int l=0; l<pat[k].effectCols; l++) {
effectVal=subPat[k]->data[j][5+(l<<1)];
if (effectVal<0) effectVal=0;
if (subPat[k]->data[j][4+(l<<1)]==0x0d) {
if (jumpTreatment==2) {
if ((i<ordersLen-1 || !ignoreJumpAtEnd)) {
nextOrder=i+1;
nextRow=effectVal;
jumpingOrder=true;
}
} else if (jumpTreatment==1) {
if (nextOrder==-1 && (i<ordersLen-1 || !ignoreJumpAtEnd)) {
nextOrder=i+1;
nextRow=effectVal;
jumpingOrder=true;
}
} else {
if ((i<ordersLen-1 || !ignoreJumpAtEnd)) {
if (!changingOrder) {
nextOrder=i+1;
}
jumpingOrder=true;
nextRow=effectVal;
}
}
} else if (subPat[k]->data[j][4+(l<<1)]==0x0b) {
if (nextOrder==-1 || jumpTreatment==0) {
nextOrder=effectVal;
if (jumpTreatment==1 || jumpTreatment==2 || !jumpingOrder) {
nextRow=0;
}
changingOrder=true;
}
}
}
}
wsWalked[((i<<5)+(j>>3))&8191]|=1<<(j&7);
if (nextOrder!=-1) {
i=nextOrder-1;
nextOrder=-1;
break;
}
}
}
return false;
}
void DivSubSong::clearData() {
for (int i=0; i<DIV_MAX_CHANS; i++) {
pat[i].wipePatterns();
@ -128,7 +210,122 @@ void DivSubSong::makePatUnique() {
}
}
void DivSong::findSubSongs() {
void DivSong::findSubSongs(int chans) {
std::vector<DivSubSong*> newSubSongs;
for (DivSubSong* i: subsong) {
std::vector<int> subSongStart;
std::vector<int> subSongEnd;
int loopOrder=0;
int loopRow=0;
int loopEnd=-1;
int curStart=-1;
// find possible subsongs
logD("finding subsongs...");
while (++curStart<i->ordersLen) {
if (!i->walk(loopOrder,loopRow,loopEnd,chans,jumpTreatment,ignoreJumpAtEnd,curStart)) break;
// make sure we don't pick the same range twice
if (!subSongEnd.empty()) {
if (subSongEnd.back()==loopEnd) continue;
}
logV("found a subsong: %d-%d",curStart,loopEnd);
subSongStart.push_back(curStart);
subSongEnd.push_back(loopEnd);
}
// if this is the only song, quit
if (subSongStart.size()<2) {
subSongStart.clear();
subSongEnd.clear();
newSubSongs.clear();
continue;
}
// now copy the song
bool isTouched[DIV_MAX_CHANS][DIV_MAX_PATTERNS];
memset(isTouched,0,DIV_MAX_CHANS*DIV_MAX_PATTERNS*sizeof(bool));
for (size_t j=1; j<subSongStart.size(); j++) {
bool isUsed[DIV_MAX_CHANS][DIV_MAX_PATTERNS];
int start=subSongStart[j];
int end=subSongEnd[j];
DivSubSong* theCopy=new DivSubSong;
theCopy->name=i->name;
theCopy->notes=i->notes;
theCopy->hilightA=i->hilightA;
theCopy->hilightB=i->hilightB;
theCopy->timeBase=i->timeBase;
theCopy->arpLen=i->arpLen;
theCopy->speeds=i->speeds;
theCopy->virtualTempoN=i->virtualTempoN;
theCopy->virtualTempoD=i->virtualTempoD;
theCopy->hz=i->hz;
theCopy->patLen=i->patLen;
// copy orders
memset(isUsed,0,DIV_MAX_CHANS*DIV_MAX_PATTERNS*sizeof(bool));
for (int k=start, kIndex=0; k<=end; k++, kIndex++) {
for (int l=0; l<DIV_MAX_CHANS; l++) {
theCopy->orders.ord[l][kIndex]=i->orders.ord[l][k];
isUsed[l][i->orders.ord[l][k]]=true;
isTouched[l][i->orders.ord[l][k]]=true;
}
}
theCopy->ordersLen=end-start+1;
memcpy(theCopy->chanShow,i->chanShow,DIV_MAX_CHANS*sizeof(bool));
memcpy(theCopy->chanShowChanOsc,i->chanShowChanOsc,DIV_MAX_CHANS*sizeof(bool));
memcpy(theCopy->chanCollapse,i->chanCollapse,DIV_MAX_CHANS);
for (int k=0; k<DIV_MAX_CHANS; k++) {
theCopy->chanName[k]=i->chanName[k];
theCopy->chanShortName[j]=i->chanShortName[k];
theCopy->pat[k].effectCols=i->pat[k].effectCols;
for (int l=0; l<DIV_MAX_PATTERNS; l++) {
if (i->pat[k].data[l]==NULL) continue;
if (!isUsed[k][l]) continue;
DivPattern* origPat=i->pat[k].getPattern(l,false);
DivPattern* copyPat=theCopy->pat[k].getPattern(l,true);
origPat->copyOn(copyPat);
}
}
newSubSongs.push_back(theCopy);
}
// and cut this one
i->ordersLen=subSongEnd[0]+1;
// remove taken patterns as well, as long as they're not used in the original subsong
// first unmark patterns which are used
for (int j=subSongStart[0]; j<=subSongEnd[0]; j++) {
for (int k=0; k<DIV_MAX_CHANS; k++) {
isTouched[k][i->orders.ord[k][j]]=false;
}
}
// then remove the rest
for (int j=0; j<DIV_MAX_CHANS; j++) {
for (int k=0; k<DIV_MAX_PATTERNS; k++) {
if (isTouched[j][k]) {
if (i->pat[j].data[k]!=NULL) {
delete i->pat[j].data[k];
i->pat[j].data[k]=NULL;
}
}
}
}
}
// append every subsong we found
for (DivSubSong* i: newSubSongs) {
subsong.push_back(i);
}
}

View file

@ -178,6 +178,11 @@ struct DivSubSong {
String chanName[DIV_MAX_CHANS];
String chanShortName[DIV_MAX_CHANS];
/**
* walk through the song and determine loop position.
*/
bool walk(int& loopOrder, int& loopRow, int& loopEnd, int chans, int jumpTreatment, int ignoreJumpAtEnd, int firstPat=0);
void clearData();
void optimizePatterns();
void rearrangePatterns();
@ -356,7 +361,7 @@ struct DivSong {
/**
* find data past 0Bxx effects and place that into new sub-songs.
*/
void findSubSongs();
void findSubSongs(int chans);
/**
* clear orders and patterns.