better subsong detection for import
This commit is contained in:
parent
40a24d6c01
commit
e1746def3a
|
@ -188,79 +188,8 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) {
|
void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) {
|
||||||
loopOrder=0;
|
if (curSubSong!=NULL) {
|
||||||
loopRow=0;
|
curSubSong->walk(loopOrder,loopRow,loopEnd,chans,song.jumpTreatment,song.ignoreJumpAtEnd);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1031,7 +1031,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
||||||
logV("maxChan: %d",maxChan);
|
logV("maxChan: %d",maxChan);
|
||||||
|
|
||||||
// set channel visibility
|
// 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]->chanShow[i]=false;
|
||||||
ds.subsong[0]->chanShowChanOsc[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;
|
ds.systemLen=(maxChan+32)>>5;
|
||||||
|
|
||||||
// find subsongs
|
// find subsongs
|
||||||
ds.findSubSongs();
|
ds.findSubSongs(maxChan);
|
||||||
|
|
||||||
if (active) quitDispatch();
|
if (active) quitDispatch();
|
||||||
BUSY_BEGIN_SOFT;
|
BUSY_BEGIN_SOFT;
|
||||||
|
|
|
@ -419,7 +419,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
||||||
ds.insLen=ds.ins.size();
|
ds.insLen=ds.ins.size();
|
||||||
|
|
||||||
// find subsongs
|
// find subsongs
|
||||||
ds.findSubSongs();
|
ds.findSubSongs(chCount);
|
||||||
|
|
||||||
if (active) quitDispatch();
|
if (active) quitDispatch();
|
||||||
BUSY_BEGIN_SOFT;
|
BUSY_BEGIN_SOFT;
|
||||||
|
|
|
@ -1026,7 +1026,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// find subsongs
|
// find subsongs
|
||||||
ds.findSubSongs();
|
ds.findSubSongs(DIV_MAX_CHANS);
|
||||||
|
|
||||||
if (active) quitDispatch();
|
if (active) quitDispatch();
|
||||||
BUSY_BEGIN_SOFT;
|
BUSY_BEGIN_SOFT;
|
||||||
|
|
|
@ -371,7 +371,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
||||||
ds.sampleLen=ds.sample.size();
|
ds.sampleLen=ds.sample.size();
|
||||||
|
|
||||||
// find subsongs
|
// find subsongs
|
||||||
ds.findSubSongs();
|
ds.findSubSongs(totalChans);
|
||||||
|
|
||||||
if (active) quitDispatch();
|
if (active) quitDispatch();
|
||||||
BUSY_BEGIN_SOFT;
|
BUSY_BEGIN_SOFT;
|
||||||
|
|
|
@ -20,6 +20,88 @@
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
#include "../ta-log.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() {
|
void DivSubSong::clearData() {
|
||||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||||
pat[i].wipePatterns();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -178,6 +178,11 @@ struct DivSubSong {
|
||||||
String chanName[DIV_MAX_CHANS];
|
String chanName[DIV_MAX_CHANS];
|
||||||
String chanShortName[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 clearData();
|
||||||
void optimizePatterns();
|
void optimizePatterns();
|
||||||
void rearrangePatterns();
|
void rearrangePatterns();
|
||||||
|
@ -356,7 +361,7 @@ struct DivSong {
|
||||||
/**
|
/**
|
||||||
* find data past 0Bxx effects and place that into new sub-songs.
|
* find data past 0Bxx effects and place that into new sub-songs.
|
||||||
*/
|
*/
|
||||||
void findSubSongs();
|
void findSubSongs(int chans);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clear orders and patterns.
|
* clear orders and patterns.
|
||||||
|
|
Loading…
Reference in a new issue