From e1746def3ac8728f13b4c74a86c8555fced10407 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 26 Jun 2024 04:03:49 -0500 Subject: [PATCH] better subsong detection for import --- src/engine/engine.cpp | 75 +------------- src/engine/fileOps/it.cpp | 4 +- src/engine/fileOps/mod.cpp | 2 +- src/engine/fileOps/s3m.cpp | 2 +- src/engine/fileOps/xm.cpp | 2 +- src/engine/song.cpp | 199 ++++++++++++++++++++++++++++++++++++- src/engine/song.h | 7 +- 7 files changed, 211 insertions(+), 80 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index df24c917d..1b89b34c6 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -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; iordersLen; i++) { - for (int j=0; jord[j][i],false); - } - if (i>lastSuspectedLoopEnd) { - lastSuspectedLoopEnd=i; - } - for (int j=nextRow; jpatLen; 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; kdata[j][5+(l<<1)]; - if (effectVal<0) effectVal=0; - if (pat[k]->data[j][4+(l<<1)]==0x0d) { - if (song.jumpTreatment==2) { - if ((iordersLen-1 || !song.ignoreJumpAtEnd)) { - nextOrder=i+1; - nextRow=effectVal; - jumpingOrder=true; - } - } else if (song.jumpTreatment==1) { - if (nextOrder==-1 && (iordersLen-1 || !song.ignoreJumpAtEnd)) { - nextOrder=i+1; - nextRow=effectVal; - jumpingOrder=true; - } - } else { - if ((iordersLen-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); } } diff --git a/src/engine/fileOps/it.cpp b/src/engine/fileOps/it.cpp index 20e751b2f..09e250f39 100644 --- a/src/engine/fileOps/it.cpp +++ b/src/engine/fileOps/it.cpp @@ -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; diff --git a/src/engine/fileOps/mod.cpp b/src/engine/fileOps/mod.cpp index 8cb3ea0c1..7198ca5c8 100644 --- a/src/engine/fileOps/mod.cpp +++ b/src/engine/fileOps/mod.cpp @@ -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; diff --git a/src/engine/fileOps/s3m.cpp b/src/engine/fileOps/s3m.cpp index 8ae357991..70ec42caa 100644 --- a/src/engine/fileOps/s3m.cpp +++ b/src/engine/fileOps/s3m.cpp @@ -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; diff --git a/src/engine/fileOps/xm.cpp b/src/engine/fileOps/xm.cpp index 3fb8cbab0..a451e7f1f 100644 --- a/src/engine/fileOps/xm.cpp +++ b/src/engine/fileOps/xm.cpp @@ -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; diff --git a/src/engine/song.cpp b/src/engine/song.cpp index 760692bb6..7d1215225 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -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; ilastSuspectedLoopEnd) { + lastSuspectedLoopEnd=i; + } + for (int j=nextRow; j>3))&8191]&(1<<(j&7))) { + loopOrder=i; + loopRow=j; + loopEnd=lastSuspectedLoopEnd; + return true; + } + for (int k=0; kdata[j][5+(l<<1)]; + if (effectVal<0) effectVal=0; + if (subPat[k]->data[j][4+(l<<1)]==0x0d) { + if (jumpTreatment==2) { + if ((idata[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 newSubSongs; + for (DivSubSong* i: subsong) { + std::vector subSongStart; + std::vector subSongEnd; + int loopOrder=0; + int loopRow=0; + int loopEnd=-1; + int curStart=-1; + + // find possible subsongs + logD("finding subsongs..."); + while (++curStartordersLen) { + 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; jname=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; lorders.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; kchanName[k]=i->chanName[k]; + theCopy->chanShortName[j]=i->chanShortName[k]; + + theCopy->pat[k].effectCols=i->pat[k].effectCols; + + for (int l=0; lpat[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; korders.ord[k][j]]=false; + } + } + + // then remove the rest + for (int j=0; jpat[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); + } } diff --git a/src/engine/song.h b/src/engine/song.h index f9e9bc740..8912ec4a1 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -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.