diff --git a/src/engine/fileOps/it.cpp b/src/engine/fileOps/it.cpp index a60abdc7e..55c0d4660 100644 --- a/src/engine/fileOps/it.cpp +++ b/src/engine/fileOps/it.cpp @@ -187,13 +187,19 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { bool doesVibrato[64]; bool doesPanning[64]; bool doesVolSlide[64]; + bool doesPanSlide[64]; bool doesArp[64]; + bool doesTremolo[64]; + bool doesPanbrello[64]; memset(doesPitchSlide,0,64*sizeof(bool)); memset(doesVibrato,0,64*sizeof(bool)); memset(doesPanning,0,64*sizeof(bool)); memset(doesVolSlide,0,64*sizeof(bool)); + memset(doesPanSlide,0,64*sizeof(bool)); memset(doesArp,0,64*sizeof(bool)); + memset(doesTremolo,0,64*sizeof(bool)); + memset(doesPanbrello,0,64*sizeof(bool)); SafeReader reader=SafeReader(file,len); warnings=""; @@ -867,9 +873,18 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { doesVolSlide[chan]=true; doesPitchSlide[chan]=true; break; + case 'P': // pan slide + doesPanSlide[chan]=true; + break; + case 'R': // tremolo + doesTremolo[chan]=true; + break; case 'U': // fine vibrato doesVibrato[chan]=true; break; + case 'Y': // panbrello + doesPanbrello[chan]=true; + break; } } } @@ -895,6 +910,18 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { bool arpStatusChanged[64]; bool arping[64]; bool arpingOld[64]; + unsigned char panStatus[64]; + bool panStatusChanged[64]; + bool panning[64]; + bool panningOld[64]; + unsigned char tremStatus[64]; + bool tremStatusChanged[64]; + bool treming[64]; + bool tremingOld[64]; + unsigned char panSlideStatus[64]; + bool panSlideStatusChanged[64]; + bool panSliding[64]; + bool panSlidingOld[64]; bool did[64]; if (patPtr[i]==0) continue; @@ -926,6 +953,18 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { memset(arpStatusChanged,0,64*sizeof(bool)); memset(arping,0,64*sizeof(bool)); memset(arpingOld,0,64*sizeof(bool)); + memset(panStatus,0,64); + memset(panStatusChanged,0,64*sizeof(bool)); + memset(panning,0,64*sizeof(bool)); + memset(panningOld,0,64*sizeof(bool)); + memset(tremStatus,0,64); + memset(tremStatusChanged,0,64*sizeof(bool)); + memset(treming,0,64*sizeof(bool)); + memset(tremingOld,0,64*sizeof(bool)); + memset(panSlideStatus,0,64); + memset(panSlideStatusChanged,0,64*sizeof(bool)); + memset(panSliding,0,64*sizeof(bool)); + memset(panSlidingOld,0,64*sizeof(bool)); memset(did,0,64*sizeof(bool)); memset(mask,0,64); @@ -1023,6 +1062,33 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { p->data[readRow][effectCol[j]++]=0; } + if (treming[j]!=tremingOld[j] || tremStatusChanged[j]) { + p->data[readRow][effectCol[j]++]=0x07; + p->data[readRow][effectCol[j]++]=treming[j]?tremStatus[j]:0; + doesTremolo[j]=true; + } else if (doesTremolo[j] && mustCommitInitial) { + p->data[readRow][effectCol[j]++]=0x07; + p->data[readRow][effectCol[j]++]=0; + } + + if (panning[j]!=panningOld[j] || panStatusChanged[j]) { + p->data[readRow][effectCol[j]++]=0x84; + p->data[readRow][effectCol[j]++]=panning[j]?panStatus[j]:0; + doesPanbrello[j]=true; + } else if (doesPanbrello[j] && mustCommitInitial) { + p->data[readRow][effectCol[j]++]=0x84; + p->data[readRow][effectCol[j]++]=0; + } + + if (panSliding[j]!=panSlidingOld[j] || panSlideStatusChanged[j]) { + p->data[readRow][effectCol[j]++]=0x83; + p->data[readRow][effectCol[j]++]=panSliding[j]?panSlideStatus[j]:0; + doesPanSlide[j]=true; + } else if (doesPanSlide[j] && mustCommitInitial) { + p->data[readRow][effectCol[j]++]=0x83; + p->data[readRow][effectCol[j]++]=0; + } + if ((effectCol[j]>>1)-2>ds.subsong[0]->pat[j].effectCols) { ds.subsong[0]->pat[j].effectCols=(effectCol[j]>>1)-1; } @@ -1034,14 +1100,23 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { memcpy(volSlidingOld,volSliding,64*sizeof(bool)); memcpy(portingOld,porting,64*sizeof(bool)); memcpy(arpingOld,arping,64*sizeof(bool)); + memcpy(panningOld,panning,64*sizeof(bool)); + memcpy(tremingOld,treming,64*sizeof(bool)); + memcpy(panSlidingOld,panSliding,64*sizeof(bool)); memset(vibStatusChanged,0,64*sizeof(bool)); memset(volSlideStatusChanged,0,64*sizeof(bool)); memset(portaStatusChanged,0,64*sizeof(bool)); memset(arpStatusChanged,0,64*sizeof(bool)); + memset(panStatusChanged,0,64*sizeof(bool)); + memset(tremStatusChanged,0,64*sizeof(bool)); + memset(panSlideStatusChanged,0,64*sizeof(bool)); memset(vibing,0,64*sizeof(bool)); memset(volSliding,0,64*sizeof(bool)); memset(porting,0,64*sizeof(bool)); memset(arping,0,64*sizeof(bool)); + memset(panning,0,64*sizeof(bool)); + memset(treming,0,64*sizeof(bool)); + memset(panSliding,0,64*sizeof(bool)); memset(did,0,64); mustCommitInitial=false; if (readRow>=patRows) { @@ -1252,12 +1327,22 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { p->data[readRow][effectCol[chan]++]=effectVal[chan]; break; case 'P': // pan slide + if (effectVal[chan]!=0) { + panSlideStatus[chan]=effectVal[chan]; + panSlideStatusChanged[chan]=true; + } + panSliding[chan]=true; break; case 'Q': // retrigger p->data[readRow][effectCol[chan]++]=0x0c; p->data[readRow][effectCol[chan]++]=effectVal[chan]&15; break; case 'R': // tremolo + if (effectVal[chan]!=0) { + tremStatus[chan]=effectVal[chan]; + tremStatusChanged[chan]=true; + } + treming[chan]=true; break; case 'S': // special... switch (effectVal[chan]>>4) { @@ -1291,6 +1376,11 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { p->data[readRow][effectCol[chan]++]=effectVal[chan]; break; case 'Y': // panbrello + if (effectVal[chan]!=0) { + panStatus[chan]=effectVal[chan]; + panStatusChanged[chan]=true; + } + panning[chan]=true; break; case 'Z': // MIDI macro break; diff --git a/src/engine/fileOps/s3m.cpp b/src/engine/fileOps/s3m.cpp index a98c988fa..f30e6c89b 100644 --- a/src/engine/fileOps/s3m.cpp +++ b/src/engine/fileOps/s3m.cpp @@ -68,7 +68,10 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { bool doesVibrato[32]; bool doesPanning[32]; bool doesVolSlide[32]; + bool doesPanSlide[32]; bool doesArp[32]; + bool doesTremolo[32]; + bool doesPanbrello[32]; memset(chanSettings,0,32); memset(insPtr,0,256*sizeof(unsigned int)); @@ -82,7 +85,10 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { memset(doesVibrato,0,32*sizeof(bool)); memset(doesPanning,0,32*sizeof(bool)); memset(doesVolSlide,0,32*sizeof(bool)); + memset(doesPanSlide,0,32*sizeof(bool)); memset(doesArp,0,32*sizeof(bool)); + memset(doesTremolo,0,32*sizeof(bool)); + memset(doesPanbrello,0,32*sizeof(bool)); try { DivSong ds; @@ -672,6 +678,15 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { doesVolSlide[chan]=true; doesPitchSlide[chan]=true; break; + case 'P': // pan slide + doesPanSlide[chan]=true; + break; + case 'R': // tremolo + doesTremolo[chan]=true; + break; + case 'Y': // panbrello + doesPanbrello[chan]=true; + break; } } } @@ -697,6 +712,18 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { bool arpStatusChanged[32]; bool arping[32]; bool arpingOld[32]; + unsigned char panStatus[32]; + bool panStatusChanged[32]; + bool panning[32]; + bool panningOld[32]; + unsigned char tremStatus[32]; + bool tremStatusChanged[32]; + bool treming[32]; + bool tremingOld[32]; + unsigned char panSlideStatus[32]; + bool panSlideStatusChanged[32]; + bool panSliding[32]; + bool panSlidingOld[32]; bool did[32]; if (patPtr[i]==0) continue; @@ -736,6 +763,18 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { memset(arpStatusChanged,0,32*sizeof(bool)); memset(arping,0,32*sizeof(bool)); memset(arpingOld,0,32*sizeof(bool)); + memset(panStatus,0,32); + memset(panStatusChanged,0,32*sizeof(bool)); + memset(panning,0,32*sizeof(bool)); + memset(panningOld,0,32*sizeof(bool)); + memset(tremStatus,0,32); + memset(tremStatusChanged,0,32*sizeof(bool)); + memset(treming,0,32*sizeof(bool)); + memset(tremingOld,0,32*sizeof(bool)); + memset(panSlideStatus,0,32); + memset(panSlideStatusChanged,0,32*sizeof(bool)); + memset(panSliding,0,32*sizeof(bool)); + memset(panSlidingOld,0,32*sizeof(bool)); memset(did,0,32*sizeof(bool)); while (reader.tell()data[readRow][effectCol[j]++]=0; } + if (treming[j]!=tremingOld[j] || tremStatusChanged[j]) { + p->data[readRow][effectCol[j]++]=0x07; + p->data[readRow][effectCol[j]++]=treming[j]?tremStatus[j]:0; + doesTremolo[j]=true; + } else if (doesTremolo[j] && mustCommitInitial) { + p->data[readRow][effectCol[j]++]=0x07; + p->data[readRow][effectCol[j]++]=0; + } + + if (panning[j]!=panningOld[j] || panStatusChanged[j]) { + p->data[readRow][effectCol[j]++]=0x84; + p->data[readRow][effectCol[j]++]=panning[j]?panStatus[j]:0; + doesPanbrello[j]=true; + } else if (doesPanbrello[j] && mustCommitInitial) { + p->data[readRow][effectCol[j]++]=0x84; + p->data[readRow][effectCol[j]++]=0; + } + + if (panSliding[j]!=panSlidingOld[j] || panSlideStatusChanged[j]) { + p->data[readRow][effectCol[j]++]=0x83; + p->data[readRow][effectCol[j]++]=panSliding[j]?panSlideStatus[j]:0; + doesPanSlide[j]=true; + } else if (doesPanSlide[j] && mustCommitInitial) { + p->data[readRow][effectCol[j]++]=0x83; + p->data[readRow][effectCol[j]++]=0; + } + if (effectCol[j]>=4+8*2) { logE("oh crap!"); } @@ -990,12 +1056,22 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { p->data[readRow][effectCol[chan]++]=effectVal; break; case 'P': // pan slide (extension) + if (effectVal!=0) { + panSlideStatus[chan]=effectVal; + panSlideStatusChanged[chan]=true; + } + panSliding[chan]=true; break; case 'Q': // retrigger p->data[readRow][effectCol[chan]++]=0x0c; p->data[readRow][effectCol[chan]++]=effectVal&15; break; case 'R': // tremolo + if (effectVal!=0) { + tremStatus[chan]=effectVal; + tremStatusChanged[chan]=true; + } + treming[chan]=true; break; case 'S': // special... switch (effectVal>>4) { @@ -1031,6 +1107,11 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { } break; case 'Y': // panbrello (extension) + if (effectVal!=0) { + panStatus[chan]=effectVal; + panStatusChanged[chan]=true; + } + panning[chan]=true; break; case 'Z': // MIDI macro (extension) break; diff --git a/src/engine/fileOps/xm.cpp b/src/engine/fileOps/xm.cpp index a0555a8d0..b44369007 100644 --- a/src/engine/fileOps/xm.cpp +++ b/src/engine/fileOps/xm.cpp @@ -135,7 +135,10 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { bool doesVibrato[128]; bool doesPanning[128]; bool doesVolSlide[128]; + bool doesPanSlide[128]; bool doesArp[128]; + bool doesTremolo[128]; + bool doesPanbrello[128]; SafeReader reader=SafeReader(file,len); warnings=""; @@ -150,7 +153,10 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { memset(doesVibrato,0,128*sizeof(bool)); memset(doesPanning,0,128*sizeof(bool)); memset(doesVolSlide,0,128*sizeof(bool)); + memset(doesPanSlide,0,128*sizeof(bool)); memset(doesArp,0,128*sizeof(bool)); + memset(doesTremolo,0,128*sizeof(bool)); + memset(doesPanbrello,0,128*sizeof(bool)); try { DivSong ds; @@ -358,10 +364,10 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { doesPanning[k]=true; break; case 0xd: // pan slide left - doesPanning[k]=true; + doesPanSlide[k]=true; break; case 0xe: // pan slide right - doesPanning[k]=true; + doesPanSlide[k]=true; break; case 0xf: // porta doesPitchSlide[k]=true; @@ -394,6 +400,9 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { doesVibrato[k]=true; doesVolSlide[k]=true; break; + case 7: + doesTremolo[k]=true; + break; case 8: doesPanning[k]=true; break; @@ -401,11 +410,14 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { doesPanning[k]=true; break; case 0x19: // P - doesPanning[k]=true; + doesPanSlide[k]=true; break; case 0x21: // X doesPitchSlide[k]=true; break; + case 0x22: // Y + doesPanbrello[k]=true; + break; } } if (hasEffectVal) { @@ -665,6 +677,18 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { bool arpStatusChanged[128]; bool arping[128]; bool arpingOld[128]; + unsigned char panStatus[128]; + bool panStatusChanged[128]; + bool panning[128]; + bool panningOld[128]; + unsigned char tremStatus[128]; + bool tremStatusChanged[128]; + bool treming[128]; + bool tremingOld[128]; + unsigned char panSlideStatus[128]; + bool panSlideStatusChanged[128]; + bool panSliding[128]; + bool panSlidingOld[128]; unsigned char lastNote[128]; bool mustCommitInitial=true; @@ -687,6 +711,18 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { memset(arpStatusChanged,0,128*sizeof(bool)); memset(arping,0,128*sizeof(bool)); memset(arpingOld,0,128*sizeof(bool)); + memset(panStatus,0,128); + memset(panStatusChanged,0,128*sizeof(bool)); + memset(panning,0,128*sizeof(bool)); + memset(panningOld,0,128*sizeof(bool)); + memset(tremStatus,0,128); + memset(tremStatusChanged,0,128*sizeof(bool)); + memset(treming,0,128*sizeof(bool)); + memset(tremingOld,0,128*sizeof(bool)); + memset(panSlideStatus,0,128); + memset(panSlideStatusChanged,0,128*sizeof(bool)); + memset(panSliding,0,128*sizeof(bool)); + memset(panSlidingOld,0,128*sizeof(bool)); memset(lastNote,0,128); logV("pattern %d",i); @@ -856,8 +892,20 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { writePanning=false; break; case 0xd: // pan slide left + if ((vol&15)!=0) { + panSlideStatus[k]&=0x0f; + panSlideStatus[k]|=(vol&15)<<4; + panSlideStatusChanged[k]=true; + } + panSliding[k]=true; break; case 0xe: // pan slide right + if ((vol&15)!=0) { + panSlideStatus[k]&=0xf0; + panSlideStatus[k]|=vol&15; + panSlideStatusChanged[k]=true; + } + panSliding[k]=true; break; case 0xf: // porta break; @@ -946,6 +994,11 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { vibing[k]=true; break; case 7: // tremolo + if (effectVal!=0) { + tremStatus[k]=effectVal; + tremStatusChanged[k]=true; + } + treming[k]=true; break; case 8: // panning p->data[j][effectCol[k]++]=0x80; @@ -994,8 +1047,6 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { break; } break; - case 0x10: // G: global volume (!) - break; case 0xf: // speed/tempp if (effectVal>=0x20) { p->data[j][effectCol[k]++]=0xf0; @@ -1004,6 +1055,8 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { } p->data[j][effectCol[k]++]=effectVal; break; + case 0x10: // G: global volume (!) + break; case 0x11: // H: global volume slide (!) break; case 0x14: // K: key off @@ -1013,6 +1066,11 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { case 0x15: // L: set envelope position (!) break; case 0x19: // P: pan slide + if (effectVal!=0) { + panSlideStatus[k]=effectVal; + panSlideStatusChanged[k]=true; + } + panSliding[k]=true; break; case 0x1b: // R: retrigger p->data[j][effectCol[k]++]=0x0c; @@ -1022,6 +1080,13 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { break; case 0x21: // X: extra fine volume break; + case 0x22: // Y: panbrello (extension) + if (effectVal!=0) { + panStatus[k]=effectVal; + panStatusChanged[k]=true; + } + panning[k]=true; + break; } } @@ -1086,6 +1151,33 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { p->data[j][effectCol[k]++]=0; } + if (treming[k]!=tremingOld[k] || tremStatusChanged[k]) { + p->data[j][effectCol[k]++]=0x07; + p->data[j][effectCol[k]++]=treming[k]?tremStatus[k]:0; + doesTremolo[k]=true; + } else if (doesTremolo[k] && mustCommitInitial) { + p->data[j][effectCol[k]++]=0x07; + p->data[j][effectCol[k]++]=0; + } + + if (panning[k]!=panningOld[k] || panStatusChanged[k]) { + p->data[j][effectCol[k]++]=0x84; + p->data[j][effectCol[k]++]=panning[k]?panStatus[k]:0; + doesPanbrello[k]=true; + } else if (doesPanbrello[k] && mustCommitInitial) { + p->data[j][effectCol[k]++]=0x84; + p->data[j][effectCol[k]++]=0; + } + + if (panSliding[k]!=panSlidingOld[k] || panSlideStatusChanged[k]) { + p->data[j][effectCol[k]++]=0x83; + p->data[j][effectCol[k]++]=panSliding[k]?panSlideStatus[k]:0; + doesPanSlide[k]=true; + } else if (doesPanSlide[k] && mustCommitInitial) { + p->data[j][effectCol[k]++]=0x83; + p->data[j][effectCol[k]++]=0; + } + if ((effectCol[k]>>1)-2>ds.subsong[0]->pat[k].effectCols) { ds.subsong[0]->pat[k].effectCols=(effectCol[k]>>1)-1; }