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

@ -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);
}
}