dev95 - multiple songs in a single file (READ)
experimental feature! proceed with caution. if you experience song corruption or crashes, report issue immediately! files with multiple songs will be readable in older versions of Furnace, but only the first song will be read in those versions. issue #199
This commit is contained in:
parent
14053f70cb
commit
c5786b61fb
24 changed files with 974 additions and 545 deletions
|
|
@ -30,7 +30,7 @@ constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
|
|||
void DivEngine::nextOrder() {
|
||||
curRow=0;
|
||||
if (repeatPattern) return;
|
||||
if (++curOrder>=song.ordersLen) {
|
||||
if (++curOrder>=curSubSong->ordersLen) {
|
||||
endOfSong=true;
|
||||
curOrder=0;
|
||||
}
|
||||
|
|
@ -266,11 +266,11 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
void DivEngine::processRow(int i, bool afterDelay) {
|
||||
int whatOrder=afterDelay?chan[i].delayOrder:curOrder;
|
||||
int whatRow=afterDelay?chan[i].delayRow:curRow;
|
||||
DivPattern* pat=song.pat[i].getPattern(song.orders.ord[i][whatOrder],false);
|
||||
DivPattern* pat=curPat[i].getPattern(curOrders->ord[i][whatOrder],false);
|
||||
// pre effects
|
||||
if (!afterDelay) {
|
||||
bool returnAfterPre=false;
|
||||
for (int j=0; j<song.pat[i].effectCols; j++) {
|
||||
for (int j=0; j<curPat[i].effectCols; j++) {
|
||||
short effect=pat->data[whatRow][4+(j<<1)];
|
||||
short effectVal=pat->data[whatRow][5+(j<<1)];
|
||||
|
||||
|
|
@ -290,7 +290,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
}
|
||||
break;
|
||||
case 0x0d: // next order
|
||||
if (changeOrd<0 && (curOrder<(song.ordersLen-1) || !song.ignoreJumpAtEnd)) {
|
||||
if (changeOrd<0 && (curOrder<(curSubSong->ordersLen-1) || !song.ignoreJumpAtEnd)) {
|
||||
changeOrd=-2;
|
||||
changePos=effectVal;
|
||||
}
|
||||
|
|
@ -405,7 +405,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
bool panChanged=false;
|
||||
|
||||
// effects
|
||||
for (int j=0; j<song.pat[i].effectCols; j++) {
|
||||
for (int j=0; j<curPat[i].effectCols; j++) {
|
||||
short effect=pat->data[whatRow][4+(j<<1)];
|
||||
short effectVal=pat->data[whatRow][5+(j<<1)];
|
||||
|
||||
|
|
@ -548,7 +548,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
break;
|
||||
case 0xe0: // arp speed
|
||||
if (effectVal>0) {
|
||||
song.arpLen=effectVal;
|
||||
curSubSong->arpLen=effectVal;
|
||||
}
|
||||
break;
|
||||
case 0xe1: // portamento up
|
||||
|
|
@ -727,7 +727,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
chan[i].noteOnInhibit=false;
|
||||
|
||||
// post effects
|
||||
for (int j=0; j<song.pat[i].effectCols; j++) {
|
||||
for (int j=0; j<curPat[i].effectCols; j++) {
|
||||
short effect=pat->data[whatRow][4+(j<<1)];
|
||||
short effectVal=pat->data[whatRow][5+(j<<1)];
|
||||
|
||||
|
|
@ -745,10 +745,10 @@ void DivEngine::nextRow() {
|
|||
strcpy(pb1,"");
|
||||
strcpy(pb3,"");
|
||||
for (int i=0; i<chans; i++) {
|
||||
snprintf(pb,4095," %.2x",song.orders.ord[i][curOrder]);
|
||||
snprintf(pb,4095," %.2x",curOrders->ord[i][curOrder]);
|
||||
strcat(pb1,pb);
|
||||
|
||||
DivPattern* pat=song.pat[i].getPattern(song.orders.ord[i][curOrder],false);
|
||||
DivPattern* pat=curPat[i].getPattern(curOrders->ord[i][curOrder],false);
|
||||
snprintf(pb2,4095,"\x1b[37m %s",
|
||||
formatNote(pat->data[curRow][0],pat->data[curRow][1]));
|
||||
strcat(pb3,pb2);
|
||||
|
|
@ -764,7 +764,7 @@ void DivEngine::nextRow() {
|
|||
snprintf(pb2,4095,"\x1b[0;36m%.2x",pat->data[curRow][2]);
|
||||
strcat(pb3,pb2);
|
||||
}
|
||||
for (int j=0; j<song.pat[i].effectCols; j++) {
|
||||
for (int j=0; j<curPat[i].effectCols; j++) {
|
||||
if (pat->data[curRow][4+(j<<1)]==-1) {
|
||||
strcat(pb3,"\x1b[m--");
|
||||
} else {
|
||||
|
|
@ -796,32 +796,32 @@ void DivEngine::nextRow() {
|
|||
if (changeOrd==-2) changeOrd=curOrder+1;
|
||||
if (changeOrd<=curOrder) endOfSong=true;
|
||||
curOrder=changeOrd;
|
||||
if (curOrder>=song.ordersLen) {
|
||||
if (curOrder>=curSubSong->ordersLen) {
|
||||
curOrder=0;
|
||||
endOfSong=true;
|
||||
}
|
||||
changeOrd=-1;
|
||||
}
|
||||
if (haltOn==DIV_HALT_PATTERN) halted=true;
|
||||
} else if (playing) if (++curRow>=song.patLen) {
|
||||
} else if (playing) if (++curRow>=curSubSong->patLen) {
|
||||
nextOrder();
|
||||
if (haltOn==DIV_HALT_PATTERN) halted=true;
|
||||
}
|
||||
|
||||
if (song.brokenSpeedSel) {
|
||||
if ((song.patLen&1) && curOrder&1) {
|
||||
ticks=((curRow&1)?speed2:speed1)*(song.timeBase+1);
|
||||
if ((curSubSong->patLen&1) && curOrder&1) {
|
||||
ticks=((curRow&1)?speed2:speed1)*(curSubSong->timeBase+1);
|
||||
nextSpeed=(curRow&1)?speed1:speed2;
|
||||
} else {
|
||||
ticks=((curRow&1)?speed1:speed2)*(song.timeBase+1);
|
||||
ticks=((curRow&1)?speed1:speed2)*(curSubSong->timeBase+1);
|
||||
nextSpeed=(curRow&1)?speed2:speed1;
|
||||
}
|
||||
} else {
|
||||
if (speedAB) {
|
||||
ticks=speed2*(song.timeBase+1);
|
||||
ticks=speed2*(curSubSong->timeBase+1);
|
||||
nextSpeed=speed1;
|
||||
} else {
|
||||
ticks=speed1*(song.timeBase+1);
|
||||
ticks=speed1*(curSubSong->timeBase+1);
|
||||
nextSpeed=speed2;
|
||||
}
|
||||
speedAB=!speedAB;
|
||||
|
|
@ -829,7 +829,7 @@ void DivEngine::nextRow() {
|
|||
|
||||
// post row details
|
||||
for (int i=0; i<chans; i++) {
|
||||
DivPattern* pat=song.pat[i].getPattern(song.orders.ord[i][curOrder],false);
|
||||
DivPattern* pat=curPat[i].getPattern(curOrders->ord[i][curOrder],false);
|
||||
if (!(pat->data[curRow][0]==0 && pat->data[curRow][1]==0)) {
|
||||
if (pat->data[curRow][0]!=100 && pat->data[curRow][0]!=101 && pat->data[curRow][0]!=102) {
|
||||
if (!chan[i].legato) {
|
||||
|
|
@ -838,7 +838,7 @@ void DivEngine::nextRow() {
|
|||
if (song.oneTickCut) {
|
||||
bool doPrepareCut=true;
|
||||
|
||||
for (int j=0; j<song.pat[i].effectCols; j++) {
|
||||
for (int j=0; j<curPat[i].effectCols; j++) {
|
||||
if (pat->data[curRow][4+(j<<1)]==0x03) {
|
||||
doPrepareCut=false;
|
||||
break;
|
||||
|
|
@ -1007,7 +1007,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
}
|
||||
if (chan[i].arp!=0 && !chan[i].arpYield && chan[i].portaSpeed<1) {
|
||||
if (--chan[i].arpTicks<1) {
|
||||
chan[i].arpTicks=song.arpLen;
|
||||
chan[i].arpTicks=curSubSong->arpLen;
|
||||
chan[i].arpStage++;
|
||||
if (chan[i].arpStage>2) chan[i].arpStage=0;
|
||||
switch (chan[i].arpStage) {
|
||||
|
|
@ -1048,7 +1048,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
|||
}
|
||||
}
|
||||
|
||||
if (consoleMode && subticks<=1) fprintf(stderr,"\x1b[2K> %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000,curOrder,song.ordersLen,curRow,song.patLen,cmdsPerSecond);
|
||||
if (consoleMode && subticks<=1) fprintf(stderr,"\x1b[2K> %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000,curOrder,curSubSong->ordersLen,curRow,curSubSong->patLen,cmdsPerSecond);
|
||||
}
|
||||
|
||||
if (haltOn==DIV_HALT_TICK) halted=true;
|
||||
|
|
@ -1240,11 +1240,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
if (!freelance && stepPlay!=-1 && subticks==1) {
|
||||
unsigned int realPos=size-(runLeftG>>MASTER_CLOCK_PREC);
|
||||
if (realPos>=size) realPos=size-1;
|
||||
if (song.hilightA>0) {
|
||||
if ((curRow%song.hilightA)==0 && ticks==1) metroTick[realPos]=1;
|
||||
if (curSubSong->hilightA>0) {
|
||||
if ((curRow%curSubSong->hilightA)==0 && ticks==1) metroTick[realPos]=1;
|
||||
}
|
||||
if (song.hilightB>0) {
|
||||
if ((curRow%song.hilightB)==0 && ticks==1) metroTick[realPos]=2;
|
||||
if (curSubSong->hilightB>0) {
|
||||
if ((curRow%curSubSong->hilightB)==0 && ticks==1) metroTick[realPos]=2;
|
||||
}
|
||||
}
|
||||
if (nextTick()) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue