Merge branch 'master' into newMixer
This commit is contained in:
commit
678a095822
96 changed files with 2015 additions and 1491 deletions
|
|
@ -58,6 +58,9 @@ bool DivConfig::save(const char* path, bool redundancy) {
|
|||
reportError(fmt::sprintf("could not write config file! %s",strerror(errno)));
|
||||
return false;
|
||||
}
|
||||
if (redundancy) {
|
||||
fputs("!DIV_CONFIG_START!\n",f);
|
||||
}
|
||||
for (auto& i: conf) {
|
||||
String toWrite=fmt::sprintf("%s=%s\n",i.first,i.second);
|
||||
if (fwrite(toWrite.c_str(),1,toWrite.size(),f)!=toWrite.size()) {
|
||||
|
|
@ -69,6 +72,9 @@ bool DivConfig::save(const char* path, bool redundancy) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (redundancy) {
|
||||
fputs("~DIV_CONFIG_END~\n",f);
|
||||
}
|
||||
fclose(f);
|
||||
logD("config file written successfully.");
|
||||
return true;
|
||||
|
|
@ -124,8 +130,12 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc
|
|||
if (redundancy) {
|
||||
unsigned char* readBuf=new unsigned char[CHECK_BUF_SIZE];
|
||||
size_t readBufLen=0;
|
||||
bool weRescued=false;
|
||||
for (int i=0; i<REDUNDANCY_NUM_ATTEMPTS; i++) {
|
||||
bool viable=false;
|
||||
bool startCheck=true;
|
||||
bool hasStartMarker=false;
|
||||
unsigned char endMarker[18];
|
||||
if (i>0) {
|
||||
snprintf(line,4095,"%s.%d",path,i);
|
||||
} else {
|
||||
|
|
@ -143,15 +153,27 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc
|
|||
|
||||
// check whether there's something
|
||||
while (!feof(f)) {
|
||||
bool willBreak=false;
|
||||
readBufLen=fread(readBuf,1,CHECK_BUF_SIZE,f);
|
||||
if (ferror(f)) {
|
||||
logV("fread(): %s",strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (startCheck) {
|
||||
if (readBufLen>=19) {
|
||||
if (memcmp(readBuf,"!DIV_CONFIG_START!\n",19)==0) {
|
||||
hasStartMarker=true;
|
||||
logV("start marker found");
|
||||
}
|
||||
}
|
||||
startCheck=false;
|
||||
}
|
||||
|
||||
for (size_t j=0; j<readBufLen; j++) {
|
||||
if (readBuf[j]==0) {
|
||||
viable=false;
|
||||
willBreak=true;
|
||||
logW("a zero?");
|
||||
break;
|
||||
}
|
||||
|
|
@ -160,7 +182,30 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc
|
|||
}
|
||||
}
|
||||
|
||||
if (viable) break;
|
||||
if (readBufLen>=18) {
|
||||
memcpy(endMarker,&readBuf[readBufLen-18],18);
|
||||
} else if (readBufLen>0) {
|
||||
// shift buffer left
|
||||
for (size_t j=0, k=readBufLen; j<readBufLen && k<18; j++, k++) {
|
||||
endMarker[j]=endMarker[k];
|
||||
}
|
||||
|
||||
// copy to end
|
||||
memcpy(&endMarker[18-readBufLen],readBuf,readBufLen);
|
||||
}
|
||||
|
||||
if (willBreak) break;
|
||||
}
|
||||
|
||||
// check for end marker if start marker is present
|
||||
if (hasStartMarker) {
|
||||
if (memcmp(endMarker,"\n~DIV_CONFIG_END~\n",18)!=0) {
|
||||
// file is incomplete
|
||||
viable=false;
|
||||
logV("end marker NOT found!");
|
||||
reportError("saved from an incomplete config.\nyeah! for a second I thought you were going to lose it.");
|
||||
weRescued=true;
|
||||
}
|
||||
}
|
||||
|
||||
// there's something
|
||||
|
|
@ -184,6 +229,9 @@ bool DivConfig::loadFromFile(const char* path, bool createOnFail, bool redundanc
|
|||
logD("config does not exist");
|
||||
if (createOnFail) {
|
||||
logI("creating default config.");
|
||||
if (weRescued) {
|
||||
reportError("what the FUCK is that supposed to mean?!");
|
||||
}
|
||||
//reportError(fmt::sprintf("Creating default config: %s",strerror(errno)));
|
||||
return save(path,redundancy);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,22 @@
|
|||
#define DIV_MAX_COLS 32
|
||||
#define DIV_MAX_EFFECTS 8
|
||||
|
||||
// pattern fields
|
||||
#define DIV_PAT_NOTE 0
|
||||
#define DIV_PAT_INS 1
|
||||
#define DIV_PAT_VOL 2
|
||||
#define DIV_PAT_FX(_x) (3+((_x)<<1))
|
||||
#define DIV_PAT_FXVAL(_x) (4+((_x)<<1))
|
||||
|
||||
// column type checks
|
||||
#define DIV_PAT_IS_EFFECT(_x) ((_x)>DIV_PAT_VOL && (!((_x)&1)))
|
||||
#define DIV_PAT_IS_EFFECT_VAL(_x) ((_x)>DIV_PAT_VOL && ((_x)&1))
|
||||
|
||||
#define DIV_NOTE_NULL_PAT 252
|
||||
#define DIV_NOTE_OFF 253
|
||||
#define DIV_NOTE_REL 254
|
||||
#define DIV_MACRO_REL 255
|
||||
|
||||
// sample related
|
||||
#define DIV_MAX_SAMPLE_TYPE 4
|
||||
|
||||
|
|
|
|||
|
|
@ -947,8 +947,8 @@ void DivEngine::delUnusedIns() {
|
|||
for (int k=0; k<DIV_MAX_PATTERNS; k++) {
|
||||
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
|
||||
for (int l=0; l<song.subsong[j]->patLen; l++) {
|
||||
if (song.subsong[j]->pat[i].data[k]->data[l][2]>=0 && song.subsong[j]->pat[i].data[k]->data[l][2]<256) {
|
||||
isUsed[song.subsong[j]->pat[i].data[k]->data[l][2]]=true;
|
||||
if (song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]>=0 && song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]<256) {
|
||||
isUsed[song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]]=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1033,38 +1033,6 @@ void DivEngine::delUnusedSamples() {
|
|||
}
|
||||
}
|
||||
|
||||
// scan in pattern (legacy sample mode)
|
||||
// disabled because it is unreliable
|
||||
/*
|
||||
for (DivSubSong* i: song.subsong) {
|
||||
for (int j=0; j<getTotalChannelCount(); j++) {
|
||||
bool is17On=false;
|
||||
int bank=0;
|
||||
for (int k=0; k<i->ordersLen; k++) {
|
||||
DivPattern* p=i->pat[j].getPattern(i->orders.ord[j][k],false);
|
||||
for (int l=0; l<i->patLen; l++) {
|
||||
for (int m=0; m<i->pat[j].effectCols; m++) {
|
||||
if (p->data[l][4+(m<<1)]==0x17) {
|
||||
is17On=(p->data[l][5+(m<<1)]>0);
|
||||
}
|
||||
if (p->data[l][4+(m<<1)]==0xeb) {
|
||||
bank=p->data[l][5+(m<<1)];
|
||||
if (bank==-1) bank=0;
|
||||
}
|
||||
}
|
||||
if (is17On) {
|
||||
if (p->data[l][1]!=0 || p->data[l][0]!=0) {
|
||||
if (p->data[l][0]<=12) {
|
||||
int note=(12*bank)+(p->data[l][0]%12);
|
||||
if (note<256) isUsed[note]=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// delete
|
||||
for (int i=0; i<song.sampleLen; i++) {
|
||||
if (!isUsed[i]) {
|
||||
|
|
@ -2293,6 +2261,64 @@ int DivEngine::getEffectiveSampleRate(int rate) {
|
|||
return rate;
|
||||
}
|
||||
|
||||
short DivEngine::splitNoteToNote(short note, short octave) {
|
||||
if (note==100) {
|
||||
return DIV_NOTE_OFF;
|
||||
} else if (note==101) {
|
||||
return DIV_NOTE_REL;
|
||||
} else if (note==102) {
|
||||
return DIV_MACRO_REL;
|
||||
} else if (note==0 && octave!=0) {
|
||||
// "BUG" note!
|
||||
return DIV_NOTE_NULL_PAT;
|
||||
} else if (note==0 && octave==0) {
|
||||
return -1;
|
||||
} else {
|
||||
int seek=(note+(signed char)octave*12)+60;
|
||||
if (seek<0 || seek>=180) {
|
||||
return DIV_NOTE_NULL_PAT;
|
||||
} else {
|
||||
return seek;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DivEngine::noteToSplitNote(short note, short& outNote, short& outOctave) {
|
||||
switch (note) {
|
||||
case DIV_NOTE_OFF:
|
||||
outNote=100;
|
||||
outOctave=0;
|
||||
break;
|
||||
case DIV_NOTE_REL:
|
||||
outNote=101;
|
||||
outOctave=0;
|
||||
break;
|
||||
case DIV_MACRO_REL:
|
||||
outNote=102;
|
||||
outOctave=0;
|
||||
break;
|
||||
case DIV_NOTE_NULL_PAT:
|
||||
// "BUG" note!
|
||||
outNote=0;
|
||||
outOctave=1;
|
||||
break;
|
||||
case -1:
|
||||
outNote=0;
|
||||
outOctave=0;
|
||||
break;
|
||||
default:
|
||||
outNote=note%12;
|
||||
outOctave=(unsigned char)(note-60)/12;
|
||||
if (outNote==0) {
|
||||
outNote=12;
|
||||
outOctave--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DivEngine::previewSample(int sample, int note, int pStart, int pEnd) {
|
||||
BUSY_BEGIN;
|
||||
previewSampleNoLock(sample,note,pStart,pEnd);
|
||||
|
|
@ -2749,8 +2775,8 @@ void DivEngine::delInstrumentUnsafe(int index) {
|
|||
for (int k=0; k<DIV_MAX_PATTERNS; k++) {
|
||||
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
|
||||
for (int l=0; l<song.subsong[j]->patLen; l++) {
|
||||
if (song.subsong[j]->pat[i].data[k]->data[l][2]>index) {
|
||||
song.subsong[j]->pat[i].data[k]->data[l][2]--;
|
||||
if (song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]>index) {
|
||||
song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3111,7 +3137,7 @@ void DivEngine::deepCloneOrder(int pos, bool where) {
|
|||
order[i]=j;
|
||||
DivPattern* oldPat=curPat[i].getPattern(origOrd,false);
|
||||
DivPattern* pat=curPat[i].getPattern(j,true);
|
||||
memcpy(pat->data,oldPat->data,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
memcpy(pat->newData,oldPat->newData,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
logD("found at %d",j);
|
||||
didNotFind=false;
|
||||
break;
|
||||
|
|
@ -3217,10 +3243,10 @@ void DivEngine::exchangeIns(int one, int two) {
|
|||
for (int k=0; k<DIV_MAX_PATTERNS; k++) {
|
||||
if (song.subsong[j]->pat[i].data[k]==NULL) continue;
|
||||
for (int l=0; l<song.subsong[j]->patLen; l++) {
|
||||
if (song.subsong[j]->pat[i].data[k]->data[l][2]==one) {
|
||||
song.subsong[j]->pat[i].data[k]->data[l][2]=two;
|
||||
} else if (song.subsong[j]->pat[i].data[k]->data[l][2]==two) {
|
||||
song.subsong[j]->pat[i].data[k]->data[l][2]=one;
|
||||
if (song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]==one) {
|
||||
song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]=two;
|
||||
} else if (song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]==two) {
|
||||
song.subsong[j]->pat[i].data[k]->newData[l][DIV_PAT_INS]=one;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ class DivWorkPool;
|
|||
|
||||
#define DIV_UNSTABLE
|
||||
|
||||
#define DIV_VERSION "dev233"
|
||||
#define DIV_ENGINE_VERSION 233
|
||||
#define DIV_VERSION "dev235"
|
||||
#define DIV_ENGINE_VERSION 235
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
@ -140,7 +140,7 @@ struct DivChannelState {
|
|||
int panDepth, panRate, panPos, panSpeed;
|
||||
int sampleOff;
|
||||
unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta, cutType;
|
||||
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff, releasing;
|
||||
bool doNote, legato, portaStop, keyOn, keyOff, stopOnOff, releasing;
|
||||
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp, sampleOffSet;
|
||||
bool wentThroughNote, goneThroughNote;
|
||||
|
||||
|
|
@ -197,7 +197,6 @@ struct DivChannelState {
|
|||
portaStop(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
nowYouCanStop(true),
|
||||
stopOnOff(false),
|
||||
releasing(false),
|
||||
arpYield(false),
|
||||
|
|
@ -723,7 +722,7 @@ class DivEngine {
|
|||
SafeWriter* saveDMF(unsigned char version);
|
||||
// save as .fur.
|
||||
// if notPrimary is true then the song will not be altered
|
||||
SafeWriter* saveFur(bool notPrimary=false, bool newPatternFormat=true);
|
||||
SafeWriter* saveFur(bool notPrimary=false);
|
||||
// return a ROM exporter.
|
||||
DivROMExport* buildROM(DivROMExportOptions sys);
|
||||
// dump to VGM.
|
||||
|
|
@ -929,6 +928,10 @@ class DivEngine {
|
|||
// get effective sample rate
|
||||
int getEffectiveSampleRate(int rate);
|
||||
|
||||
// convert between old and new note/octave format
|
||||
short splitNoteToNote(short note, short octave);
|
||||
void noteToSplitNote(short note, short& outNote, short& outOctave);
|
||||
|
||||
// is FM system
|
||||
bool isFMSystem(DivSystem sys);
|
||||
|
||||
|
|
|
|||
|
|
@ -783,109 +783,113 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
DivPattern* pat=chan.getPattern(ds.subsong[0]->orders.ord[i][j],true);
|
||||
if (ds.version>0x08) { // current pattern format
|
||||
for (int k=0; k<ds.subsong[0]->patLen; k++) {
|
||||
// note
|
||||
pat->data[k][0]=reader.readS();
|
||||
// octave
|
||||
pat->data[k][1]=reader.readS();
|
||||
if (ds.system[0]==DIV_SYSTEM_SMS && ds.version<0x0e && pat->data[k][1]>0) {
|
||||
short note=reader.readS();
|
||||
short octave=reader.readS();
|
||||
if (ds.system[0]==DIV_SYSTEM_SMS && ds.version<0x0e && octave>0) {
|
||||
// apparently it was up one octave before
|
||||
pat->data[k][1]--;
|
||||
} else if (ds.system[0]==DIV_SYSTEM_GENESIS && ds.version<0x0e && pat->data[k][1]>0 && i>5) {
|
||||
octave--;
|
||||
} else if (ds.system[0]==DIV_SYSTEM_GENESIS && ds.version<0x0e && octave>0 && i>5) {
|
||||
// ditto
|
||||
pat->data[k][1]--;
|
||||
} else if (ds.system[0]==DIV_SYSTEM_MSX2 && pat->data[k][1]>0 && i<3) {
|
||||
octave--;
|
||||
} else if (ds.system[0]==DIV_SYSTEM_MSX2 && octave>0 && i<3) {
|
||||
// why the hell?
|
||||
pat->data[k][1]++;
|
||||
octave++;
|
||||
}
|
||||
if (ds.version<0x12) {
|
||||
if (ds.system[0]==DIV_SYSTEM_GB && i==3 && pat->data[k][1]>0) {
|
||||
if (ds.system[0]==DIV_SYSTEM_GB && i==3 && octave>0) {
|
||||
// back then noise was 2 octaves lower
|
||||
pat->data[k][1]-=2;
|
||||
octave-=2;
|
||||
}
|
||||
}
|
||||
if (ds.system[0]==DIV_SYSTEM_YMU759 && pat->data[k][0]!=0) {
|
||||
if (ds.system[0]==DIV_SYSTEM_YMU759 && note!=0) {
|
||||
// apparently YMU759 is stored 2 octaves lower
|
||||
pat->data[k][1]+=2;
|
||||
octave+=2;
|
||||
}
|
||||
if (pat->data[k][0]==0 && pat->data[k][1]!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]);
|
||||
pat->data[k][0]=12;
|
||||
pat->data[k][1]--;
|
||||
if (note==0 && octave!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",i,j,k,note,octave);
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
|
||||
pat->newData[k][DIV_PAT_NOTE]=splitNoteToNote(note,octave);
|
||||
|
||||
// volume
|
||||
pat->data[k][3]=reader.readS();
|
||||
pat->newData[k][DIV_PAT_VOL]=reader.readS();
|
||||
if (ds.version<0x0a) {
|
||||
// back then volume was stored as 00-ff instead of 00-7f/0-f
|
||||
if (i>5) {
|
||||
pat->data[k][3]>>=4;
|
||||
pat->newData[k][DIV_PAT_VOL]>>=4;
|
||||
} else {
|
||||
pat->data[k][3]>>=1;
|
||||
pat->newData[k][DIV_PAT_VOL]>>=1;
|
||||
}
|
||||
}
|
||||
if (ds.version<0x12) {
|
||||
if (ds.system[0]==DIV_SYSTEM_GB && i==2 && pat->data[k][3]>0) {
|
||||
if (ds.system[0]==DIV_SYSTEM_GB && i==2 && pat->newData[k][DIV_PAT_VOL]>0) {
|
||||
// volume range of GB wave channel was 0-3 rather than 0-F
|
||||
pat->data[k][3]=(pat->data[k][3]&3)*5;
|
||||
pat->newData[k][DIV_PAT_VOL]=(pat->newData[k][DIV_PAT_VOL]&3)*5;
|
||||
}
|
||||
}
|
||||
for (int l=0; l<chan.effectCols; l++) {
|
||||
// effect
|
||||
pat->data[k][4+(l<<1)]=reader.readS();
|
||||
pat->data[k][5+(l<<1)]=reader.readS();
|
||||
pat->newData[k][DIV_PAT_FX(l)]=reader.readS();
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=reader.readS();
|
||||
|
||||
if (ds.version<0x14) {
|
||||
if (pat->data[k][4+(l<<1)]==0xe5 && pat->data[k][5+(l<<1)]!=-1) {
|
||||
pat->data[k][5+(l<<1)]=128+((pat->data[k][5+(l<<1)]-128)/4);
|
||||
// the range of E5xx was different back then
|
||||
if (pat->newData[k][DIV_PAT_FX(l)]==0xe5 && pat->newData[k][DIV_PAT_FXVAL(l)]!=-1) {
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=128+((pat->newData[k][DIV_PAT_FXVAL(l)]-128)/4);
|
||||
}
|
||||
}
|
||||
}
|
||||
// instrument
|
||||
pat->data[k][2]=reader.readS();
|
||||
pat->newData[k][DIV_PAT_INS]=reader.readS();
|
||||
|
||||
// this is sad
|
||||
if (ds.system[0]==DIV_SYSTEM_NES_FDS) {
|
||||
if (i==5 && pat->data[k][2]!=-1) {
|
||||
if (pat->data[k][2]>=0 && pat->data[k][2]<ds.insLen) {
|
||||
ds.ins[pat->data[k][2]]->type=DIV_INS_FDS;
|
||||
if (i==5 && pat->newData[k][DIV_PAT_INS]!=-1) {
|
||||
if (pat->newData[k][DIV_PAT_INS]>=0 && pat->newData[k][DIV_PAT_INS]<ds.insLen) {
|
||||
ds.ins[pat->newData[k][DIV_PAT_INS]]->type=DIV_INS_FDS;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ds.system[0]==DIV_SYSTEM_MSX2) {
|
||||
if (i>=3 && pat->data[k][2]!=-1) {
|
||||
if (pat->data[k][2]>=0 && pat->data[k][2]<ds.insLen) {
|
||||
ds.ins[pat->data[k][2]]->type=DIV_INS_SCC;
|
||||
if (i>=3 && pat->newData[k][DIV_PAT_INS]!=-1) {
|
||||
if (pat->newData[k][DIV_PAT_INS]>=0 && pat->newData[k][DIV_PAT_INS]<ds.insLen) {
|
||||
ds.ins[pat->newData[k][DIV_PAT_INS]]->type=DIV_INS_SCC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // historic pattern format
|
||||
if (i<16) pat->data[0][2]=historicColIns[i];
|
||||
if (i<16) pat->newData[0][DIV_PAT_INS]=historicColIns[i];
|
||||
for (int k=0; k<ds.subsong[0]->patLen; k++) {
|
||||
// note
|
||||
pat->data[k][0]=reader.readC();
|
||||
// octave
|
||||
pat->data[k][1]=reader.readC();
|
||||
if (pat->data[k][0]!=0) {
|
||||
short note=reader.readC();
|
||||
short octave=reader.readC();
|
||||
|
||||
if (note!=0) {
|
||||
// YMU759 is stored 2 octaves lower
|
||||
pat->data[k][1]+=2;
|
||||
octave+=2;
|
||||
}
|
||||
if (pat->data[k][0]==0 && pat->data[k][1]!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]);
|
||||
pat->data[k][0]=12;
|
||||
pat->data[k][1]--;
|
||||
if (note==0 && octave!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",i,j,k,note,octave);
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
|
||||
pat->newData[k][DIV_PAT_NOTE]=splitNoteToNote(note,octave);
|
||||
|
||||
// volume and effect
|
||||
unsigned char vol=reader.readC();
|
||||
unsigned char fx=reader.readC();
|
||||
unsigned char fxVal=reader.readC();
|
||||
pat->data[k][3]=(vol==0x80 || vol==0xff)?-1:vol;
|
||||
pat->newData[k][DIV_PAT_VOL]=(vol==0x80 || vol==0xff)?-1:vol;
|
||||
// effect
|
||||
pat->data[k][4]=(fx==0x80 || fx==0xff)?-1:fx;
|
||||
pat->data[k][5]=(fxVal==0x80 || fx==0xff)?-1:fxVal;
|
||||
pat->newData[k][DIV_PAT_FX(0)]=(fx==0x80 || fx==0xff)?-1:fx;
|
||||
pat->newData[k][DIV_PAT_FXVAL(0)]=(fxVal==0x80 || fx==0xff)?-1:fxVal;
|
||||
// instrument
|
||||
if (ds.version>0x05) {
|
||||
pat->data[k][2]=reader.readC();
|
||||
if (pat->data[k][2]==0x80 || pat->data[k][2]==0xff) pat->data[k][2]=-1;
|
||||
pat->newData[k][DIV_PAT_INS]=reader.readC();
|
||||
if (pat->newData[k][DIV_PAT_INS]==0x80 || pat->newData[k][DIV_PAT_INS]==0xff) pat->newData[k][DIV_PAT_INS]=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1630,12 +1634,13 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
bool relWarning=false;
|
||||
|
||||
for (int i=0; i<getChannelCount(sys); i++) {
|
||||
short note, octave;
|
||||
w->writeC(curPat[i].effectCols);
|
||||
|
||||
for (int j=0; j<curSubSong->ordersLen; j++) {
|
||||
DivPattern* pat=curPat[i].getPattern(curOrders->ord[i][j],false);
|
||||
for (int k=0; k<curSubSong->patLen; k++) {
|
||||
if ((pat->data[k][0]==101 || pat->data[k][0]==102) && pat->data[k][1]==0) {
|
||||
if (pat->newData[k][DIV_PAT_NOTE]==DIV_NOTE_REL || pat->newData[k][DIV_PAT_NOTE]==DIV_MACRO_REL) {
|
||||
w->writeS(100);
|
||||
w->writeS(0);
|
||||
if (!relWarning) {
|
||||
|
|
@ -1643,18 +1648,19 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
addWarning("note/macro release will be converted to note off!");
|
||||
}
|
||||
} else {
|
||||
w->writeS(pat->data[k][0]); // note
|
||||
w->writeS(pat->data[k][1]); // octave
|
||||
noteToSplitNote(pat->newData[k][DIV_PAT_NOTE],note,octave);
|
||||
w->writeS(note); // note
|
||||
w->writeS(octave); // octave
|
||||
}
|
||||
w->writeS(pat->data[k][3]); // volume
|
||||
w->writeS(pat->newData[k][DIV_PAT_VOL]); // volume
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
for (int l=0; l<curPat[i].effectCols*2; l++) {
|
||||
w->writeS(pat->data[k][4+l]);
|
||||
w->writeS(pat->newData[k][DIV_PAT_FX(0)+l]);
|
||||
}
|
||||
#else
|
||||
w->write(&pat->data[k][4],2*curPat[i].effectCols*2); // effects
|
||||
w->write(&pat->newData[k][DIV_PAT_FX(0)],2*curPat[i].effectCols*2); // effects
|
||||
#endif
|
||||
w->writeS(pat->data[k][2]); // instrument
|
||||
w->writeS(pat->newData[k][DIV_PAT_INS]); // instrument
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -418,8 +418,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->orders.ord[j][i]=i;
|
||||
DivPattern* p=ds.subsong[0]->pat[j].getPattern(i,true);
|
||||
if (j==3 && seq[i].speed) {
|
||||
p->data[0][6]=0x0f;
|
||||
p->data[0][7]=seq[i].speed;
|
||||
p->newData[0][DIV_PAT_FX(1)]=0x0f;
|
||||
p->newData[0][DIV_PAT_FXVAL(1)]=seq[i].speed;
|
||||
}
|
||||
|
||||
bool ignoreNext=false;
|
||||
|
|
@ -428,80 +428,65 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
FCPattern& fp=pat[seq[i].pat[j]];
|
||||
if (fp.note[k]>0 && fp.note[k]<0x49) {
|
||||
lastNote[j]=fp.note[k];
|
||||
short note=(fp.note[k]+seq[i].transpose[j])%12;
|
||||
short octave=2+((fp.note[k]+seq[i].transpose[j])/12);
|
||||
if (fp.note[k]>=0x3d) octave-=6;
|
||||
if (note==0) {
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
octave&=0xff;
|
||||
p->data[k][0]=note;
|
||||
p->data[k][1]=octave;
|
||||
p->newData[k][DIV_PAT_NOTE]=fp.note[k]+seq[i].transpose[j]+84;
|
||||
// wrap-around if the note is too high
|
||||
if (fp.note[k]>=0x3d) p->newData[k][DIV_PAT_NOTE]-=6*12;
|
||||
if (isSliding[j]) {
|
||||
isSliding[j]=false;
|
||||
p->data[k][4]=2;
|
||||
p->data[k][5]=0;
|
||||
p->newData[k][DIV_PAT_FX(0)]=2;
|
||||
p->newData[k][DIV_PAT_FXVAL(0)]=0;
|
||||
}
|
||||
} else if (fp.note[k]==0x49) {
|
||||
if (k>0) {
|
||||
p->data[k-1][4]=0x0d;
|
||||
p->data[k-1][5]=0;
|
||||
p->newData[k-1][DIV_PAT_FX(0)]=0x0d;
|
||||
p->newData[k-1][DIV_PAT_FXVAL(0)]=0;
|
||||
}
|
||||
} else if (k==0 && lastTranspose[j]!=seq[i].transpose[j]) {
|
||||
p->data[0][2]=lastIns[j];
|
||||
p->data[0][4]=0x03;
|
||||
p->data[0][5]=0xff;
|
||||
p->newData[0][DIV_PAT_INS]=lastIns[j];
|
||||
p->newData[0][DIV_PAT_FX(0)]=0x03;
|
||||
p->newData[0][DIV_PAT_FXVAL(0)]=0xff;
|
||||
lastTranspose[j]=seq[i].transpose[j];
|
||||
|
||||
short note=(lastNote[j]+seq[i].transpose[j])%12;
|
||||
short octave=2+((lastNote[j]+seq[i].transpose[j])/12);
|
||||
if (lastNote[j]>=0x3d) octave-=6;
|
||||
if (note==0) {
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
octave&=0xff;
|
||||
p->data[k][0]=note;
|
||||
p->data[k][1]=octave;
|
||||
p->newData[k][DIV_PAT_NOTE]=lastNote[j]+seq[i].transpose[j]+84;
|
||||
// wrap-around if the note is too high
|
||||
if (lastNote[j]>=0x3d) p->newData[k][DIV_PAT_NOTE]-=6*12;
|
||||
}
|
||||
if (fp.val[k]) {
|
||||
if (ignoreNext) {
|
||||
ignoreNext=false;
|
||||
} else {
|
||||
if (fp.val[k]==0xf0) {
|
||||
p->data[k][0]=100;
|
||||
p->data[k][1]=0;
|
||||
p->data[k][2]=-1;
|
||||
p->newData[k][DIV_PAT_NOTE]=DIV_NOTE_OFF;
|
||||
p->newData[k][DIV_PAT_INS]=-1;
|
||||
} else if (fp.val[k]&0xe0) {
|
||||
if (fp.val[k]&0x40) {
|
||||
p->data[k][4]=2;
|
||||
p->data[k][5]=0;
|
||||
p->newData[k][DIV_PAT_FX(0)]=2;
|
||||
p->newData[k][DIV_PAT_FXVAL(0)]=0;
|
||||
isSliding[j]=false;
|
||||
} else if (fp.val[k]&0x80) {
|
||||
isSliding[j]=true;
|
||||
if (k<31) {
|
||||
if (fp.val[k+1]&0x20) {
|
||||
p->data[k][4]=2;
|
||||
p->data[k][5]=fp.val[k+1]&0x1f;
|
||||
p->newData[k][DIV_PAT_FX(0)]=2;
|
||||
p->newData[k][DIV_PAT_FXVAL(0)]=fp.val[k+1]&0x1f;
|
||||
} else {
|
||||
p->data[k][4]=1;
|
||||
p->data[k][5]=fp.val[k+1]&0x1f;
|
||||
p->newData[k][DIV_PAT_FX(0)]=1;
|
||||
p->newData[k][DIV_PAT_FXVAL(0)]=fp.val[k+1]&0x1f;
|
||||
}
|
||||
ignoreNext=true;
|
||||
} else {
|
||||
p->data[k][4]=2;
|
||||
p->data[k][5]=0;
|
||||
p->newData[k][DIV_PAT_FX(0)]=2;
|
||||
p->newData[k][DIV_PAT_FXVAL(0)]=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p->data[k][2]=(fp.val[k]+seq[i].offsetIns[j])&0x3f;
|
||||
lastIns[j]=p->data[k][2];
|
||||
p->newData[k][DIV_PAT_INS]=(fp.val[k]+seq[i].offsetIns[j])&0x3f;
|
||||
lastIns[j]=p->newData[k][DIV_PAT_INS];
|
||||
}
|
||||
}
|
||||
} else if (fp.note[k]>0 && fp.note[k]<0x49) {
|
||||
p->data[k][2]=seq[i].offsetIns[j];
|
||||
lastIns[j]=p->data[k][2];
|
||||
p->newData[k][DIV_PAT_INS]=seq[i].offsetIns[j];
|
||||
lastIns[j]=p->newData[k][DIV_PAT_INS];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ int convert_vrc6_duties[4] = {1, 3, 7, 3};
|
|||
|
||||
int findEmptyFx(short* data) {
|
||||
for (int i=0; i<7; i++) {
|
||||
if (data[4+i*2]==-1) return i;
|
||||
if (data[DIV_PAT_FX(i)]==-1) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -1752,17 +1752,13 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
|
||||
if (map_channels[ch] != 0xff) {
|
||||
if (nextNote == 0x0d) {
|
||||
pat->data[row][0] = 101;
|
||||
pat->newData[row][DIV_PAT_NOTE] = DIV_NOTE_REL;
|
||||
} else if (nextNote == 0x0e) {
|
||||
pat->data[row][0] = 100;
|
||||
} else if (nextNote == 0x01) {
|
||||
pat->data[row][0] = 12;
|
||||
pat->data[row][1] = nextOctave - 1;
|
||||
pat->newData[row][DIV_PAT_NOTE] = DIV_NOTE_OFF;
|
||||
} else if (nextNote == 0) {
|
||||
pat->data[row][0] = 0;
|
||||
pat->newData[row][DIV_PAT_NOTE] = -1;
|
||||
} else if (nextNote < 0x0d) {
|
||||
pat->data[row][0] = nextNote - 1;
|
||||
pat->data[row][1] = nextOctave;
|
||||
pat->newData[row][DIV_PAT_NOTE] = nextOctave*12 + (nextNote - 1) + 60;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1770,27 +1766,27 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
// TODO: you sure about 0xff?
|
||||
if (map_channels[ch] != 0xff) {
|
||||
if (nextIns < 0x40 && nextNote != 0x0d && nextNote != 0x0e) {
|
||||
pat->data[row][2] = nextIns;
|
||||
pat->newData[row][DIV_PAT_INS] = nextIns;
|
||||
} else {
|
||||
pat->data[row][2] = -1;
|
||||
pat->newData[row][DIV_PAT_INS] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char nextVol = reader.readC();
|
||||
if (map_channels[ch] != 0xff) {
|
||||
if (nextVol < 0x10) {
|
||||
pat->data[row][3] = nextVol;
|
||||
pat->newData[row][DIV_PAT_VOL] = nextVol;
|
||||
if (map_channels[ch] == vrc6_saw_chan) // scale volume
|
||||
{
|
||||
// TODO: shouldn't it be 32?
|
||||
pat->data[row][3] = (pat->data[row][3] * 42) / 15;
|
||||
pat->newData[row][DIV_PAT_VOL] = (pat->newData[row][DIV_PAT_VOL] * 42) / 15;
|
||||
}
|
||||
|
||||
if (map_channels[ch] == fds_chan) {
|
||||
pat->data[row][3] = (pat->data[row][3] * 31) / 15;
|
||||
pat->newData[row][DIV_PAT_VOL] = (pat->newData[row][DIV_PAT_VOL] * 31) / 15;
|
||||
}
|
||||
} else {
|
||||
pat->data[row][3] = -1;
|
||||
pat->newData[row][DIV_PAT_VOL] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1829,15 +1825,15 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (nextEffect == FT_EF_SPEED && nextEffectVal < 20)
|
||||
nextEffectVal++;
|
||||
|
||||
if (pat->data[row][3] == 0)
|
||||
pat->data[row][3] = 0xf;
|
||||
if (pat->newData[row][DIV_PAT_VOL] == 0)
|
||||
pat->newData[row][DIV_PAT_VOL] = 0xf;
|
||||
else {
|
||||
pat->data[row][3]--;
|
||||
pat->data[row][3] &= 0x0F;
|
||||
pat->newData[row][DIV_PAT_VOL]--;
|
||||
pat->newData[row][DIV_PAT_VOL] &= 0x0F;
|
||||
}
|
||||
|
||||
if (pat->data[row][0] == 0)
|
||||
pat->data[row][2] = -1;
|
||||
if (pat->newData[row][DIV_PAT_NOTE] == -1)
|
||||
pat->newData[row][DIV_PAT_INS] = -1;
|
||||
}
|
||||
|
||||
if (blockVersion == 3) {
|
||||
|
|
@ -1902,43 +1898,43 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
|
||||
if (map_channels[ch] != 0xff) {
|
||||
if (nextEffect == 0 && nextEffectVal == 0) {
|
||||
pat->data[row][4 + (j * 2)] = -1;
|
||||
pat->data[row][5 + (j * 2)] = -1;
|
||||
pat->newData[row][DIV_PAT_FX(j)] = -1;
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] = -1;
|
||||
} else {
|
||||
if ((eft && nextEffect<eftEffectMapSize) || (!eft && nextEffect<ftEffectMapSize)) {
|
||||
if (eft) {
|
||||
pat->data[row][4 + (j * 2)] = eftEffectMap[nextEffect];
|
||||
pat->data[row][5 + (j * 2)] = eftEffectMap[nextEffect] == -1 ? -1 : nextEffectVal;
|
||||
pat->newData[row][DIV_PAT_FX(j)] = eftEffectMap[nextEffect];
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] = eftEffectMap[nextEffect] == -1 ? -1 : nextEffectVal;
|
||||
|
||||
if (pat->data[row][4 + (j * 2)] == 0x100) {
|
||||
pat->data[row][3] += pat->data[row][5 + (j * 2)] ? 0x10 : 0; // extra volume bit for AY8930
|
||||
pat->data[row][4 + (j * 2)] = -1;
|
||||
pat->data[row][5 + (j * 2)] = -1;
|
||||
if (pat->newData[row][DIV_PAT_FX(j)] == 0x100) {
|
||||
pat->newData[row][DIV_PAT_VOL] += pat->newData[row][DIV_PAT_FXVAL(j)] ? 0x10 : 0; // extra volume bit for AY8930
|
||||
pat->newData[row][DIV_PAT_FX(j)] = -1;
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] = -1;
|
||||
}
|
||||
|
||||
if (eftEffectMap[nextEffect] == 0x0f && nextEffectVal > 0x1f) {
|
||||
pat->data[row][4 + (j * 2)] = 0xfd; // BPM speed change!
|
||||
pat->newData[row][DIV_PAT_FX(j)] = 0xfd; // BPM speed change!
|
||||
}
|
||||
|
||||
if ((eftEffectMap[nextEffect] == 0xe1 || eftEffectMap[nextEffect] == 0xe2) && (nextEffectVal & 0xf0) == 0) {
|
||||
pat->data[row][5 + (j * 2)] |= 0x10; // in FamiTracker if e1/e2 commands speed is 0 the portamento still has some speed!
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] |= 0x10; // in FamiTracker if e1/e2 commands speed is 0 the portamento still has some speed!
|
||||
}
|
||||
} else {
|
||||
pat->data[row][4 + (j * 2)] = ftEffectMap[nextEffect];
|
||||
pat->data[row][5 + (j * 2)] = ftEffectMap[nextEffect] == -1 ? -1 : nextEffectVal;
|
||||
pat->newData[row][DIV_PAT_FX(j)] = ftEffectMap[nextEffect];
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] = ftEffectMap[nextEffect] == -1 ? -1 : nextEffectVal;
|
||||
|
||||
if (ftEffectMap[nextEffect] == 0x0f && nextEffectVal > 0x1f) {
|
||||
pat->data[row][4 + (j * 2)] = 0xfd; // BPM speed change!
|
||||
pat->newData[row][DIV_PAT_FX(j)] = 0xfd; // BPM speed change!
|
||||
}
|
||||
|
||||
if ((ftEffectMap[nextEffect] == 0xe1 || ftEffectMap[nextEffect] == 0xe2) && (nextEffectVal & 0xf0) == 0) {
|
||||
pat->data[row][5 + (j * 2)] |= 0x10; // in FamiTracker if e1/e2 commands speed is 0 the portamento still has some speed!
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] |= 0x10; // in FamiTracker if e1/e2 commands speed is 0 the portamento still has some speed!
|
||||
}
|
||||
}
|
||||
for (int v = 0; v < 8; v++) {
|
||||
if (map_channels[ch] == n163_chans[v]) {
|
||||
if (pat->data[row][4 + (j * 2)] == 0x12) {
|
||||
pat->data[row][4 + (j * 2)] = 0x110; // N163 wave change (we'll map this later)
|
||||
if (pat->newData[row][DIV_PAT_FX(j)] == 0x12) {
|
||||
pat->newData[row][DIV_PAT_FX(j)] = 0x110; // N163 wave change (we'll map this later)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1947,23 +1943,24 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
{
|
||||
if (map_channels[ch] == vrc7_chans[vrr])
|
||||
{
|
||||
if (pat->data[row][4 + (j * 2)] == 0x12)
|
||||
if (pat->newData[row][DIV_PAT_FX(j)] == 0x12)
|
||||
{
|
||||
pat->data[row][4 + (j * 2)] = 0x10; // set VRC7 patch
|
||||
pat->newData[row][DIV_PAT_FX(j)] = 0x10; // set VRC7 patch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int v = 0; v < 3; v++) {
|
||||
if (map_channels[ch] == s5b_chans[v] || map_channels[ch] == ay8930_chans[v]) {
|
||||
if (pat->data[row][4 + (j * 2)] == 0x22 && (pat->data[row][5 + (j * 2)] & 0xf0) != 0) {
|
||||
pat->data[row][4 + (7 * 2)] = -666; //marker
|
||||
if (pat->newData[row][DIV_PAT_FX(j)] == 0x22 && (pat->newData[row][DIV_PAT_FXVAL(j)] & 0xf0) != 0) {
|
||||
// TODO: in the second stage of pattern refactor this will have to change.
|
||||
pat->newData[row][DIV_PAT_FX(7)] = -666; //marker
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pat->data[row][4 + (j * 2)] = -1;
|
||||
pat->data[row][5 + (j * 2)] = -1;
|
||||
pat->newData[row][DIV_PAT_FX(j)] = -1;
|
||||
pat->newData[row][DIV_PAT_FXVAL(j)] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2438,8 +2435,8 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (ds.subsong[j]->pat[ii].data[k] == NULL)
|
||||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] > index) {
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][2]--;
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] > index) {
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2456,12 +2453,12 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (ds.subsong[j]->pat[ii].data[k] == NULL)
|
||||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][4 + 7*2] == -666) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FX(7)] == -666) {
|
||||
bool converted = false;
|
||||
// for()? if()? THESE ARE NOT FUNCTIONS!
|
||||
for (int hh = 0; hh < 7; hh++) { // oh and now you 1TBS up. oh man...
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][4 + hh*2] == 0x22 && !converted) {
|
||||
int slot = findEmptyFx(ds.subsong[j]->pat[ii].data[k]->data[l]);
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FX(hh)] == 0x22 && !converted) {
|
||||
int slot = findEmptyFx(ds.subsong[j]->pat[ii].data[k]->newData[l]);
|
||||
if (slot != -1) {
|
||||
// space your comments damn it!
|
||||
// Hxy - Envelope automatic pitch
|
||||
|
|
@ -2469,7 +2466,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
// Sets envelope period to the note period shifted by x and envelope type y.
|
||||
// Approximate envelope frequency is note frequency * (2^|x - 8|) / 32.
|
||||
|
||||
int ftAutoEnv = (ds.subsong[j]->pat[ii].data[k]->data[l][5 + hh*2] >> 4) & 15;
|
||||
int ftAutoEnv = (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FXVAL(hh)] >> 4) & 15;
|
||||
int autoEnvDen = 16; // ???? with 32 it's an octave lower...
|
||||
int autoEnvNum = (1 << (abs(ftAutoEnv - 8)));
|
||||
|
||||
|
|
@ -2479,18 +2476,18 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
}
|
||||
|
||||
if (autoEnvDen < 16 && autoEnvNum < 16) {
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][4 + slot*2] = 0x29;
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][5 + slot*2] = (autoEnvNum << 4) | autoEnvDen;
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FX(slot)] = 0x29;
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FXVAL(slot)] = (autoEnvNum << 4) | autoEnvDen;
|
||||
}
|
||||
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][5 + hh*2] = (ds.subsong[j]->pat[ii].data[k]->data[l][5 + hh*2] & 0xf) << 4;
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FXVAL(hh)] = (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FXVAL(hh)] & 0xf) << 4;
|
||||
|
||||
converted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][4 + (7 * 2)] = -1; //delete marker
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_FX(7)] = -1; //delete marker
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2506,10 +2503,10 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
for (int p = 0; p < s->ordersLen; p++) {
|
||||
for (int r = 0; r < s->patLen; r++) {
|
||||
DivPattern* pat = s->pat[c].getPattern(s->orders.ord[c][p], true);
|
||||
short* s_row_data = pat->data[r];
|
||||
short* s_row_data = pat->newData[r];
|
||||
|
||||
for (int eff = 0; eff < DIV_MAX_EFFECTS - 1; eff++) {
|
||||
if (s_row_data[4 + 2 * eff] != -1 && eff + 1 > num_fx) {
|
||||
if (s_row_data[DIV_PAT_FX(eff)] != -1 && eff + 1 > num_fx) {
|
||||
num_fx = eff + 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -2556,7 +2553,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
// 1TBS > GNU
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == i) { // instrument
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == i) { // instrument
|
||||
DivInstrument* ins = ds.ins[i];
|
||||
bool go_to_end = false;
|
||||
|
||||
|
|
@ -2606,7 +2603,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (ds.subsong[j]->pat[ii].data[k] == NULL)
|
||||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == i) // instrument
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == i) // instrument
|
||||
{
|
||||
DivInstrument* ins = ds.ins[i];
|
||||
bool go_to_end = false;
|
||||
|
|
@ -2658,7 +2655,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (ds.subsong[j]->pat[ii].data[k] == NULL)
|
||||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == i) // instrument
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == i) // instrument
|
||||
{
|
||||
DivInstrument* ins = ds.ins[i];
|
||||
bool go_to_end = false;
|
||||
|
|
@ -2729,17 +2726,17 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
if (ds.subsong[j]->pat[ii].data[k] == NULL)
|
||||
continue;
|
||||
for (int l = 0; l < ds.subsong[j]->patLen; l++) {
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == ins_vrc6_conv[i][0] && (ii == vrc6_chans[0] || ii == vrc6_chans[1])) // change ins index
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == ins_vrc6_conv[i][0] && (ii == vrc6_chans[0] || ii == vrc6_chans[1])) // change ins index
|
||||
{
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][2] = ins_vrc6_conv[i][1];
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] = ins_vrc6_conv[i][1];
|
||||
}
|
||||
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == ins_vrc6_saw_conv[i][0] && ii == vrc6_saw_chan) {
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][2] = ins_vrc6_saw_conv[i][1];
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == ins_vrc6_saw_conv[i][0] && ii == vrc6_saw_chan) {
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] = ins_vrc6_saw_conv[i][1];
|
||||
}
|
||||
|
||||
if (ds.subsong[j]->pat[ii].data[k]->data[l][2] == ins_nes_conv[i][0] && (ii == mmc5_chans[0] || ii == mmc5_chans[1] || ii < 5)) {
|
||||
ds.subsong[j]->pat[ii].data[k]->data[l][2] = ins_nes_conv[i][1];
|
||||
if (ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] == ins_nes_conv[i][0] && (ii == mmc5_chans[0] || ii == mmc5_chans[1] || ii < 5)) {
|
||||
ds.subsong[j]->pat[ii].data[k]->newData[l][DIV_PAT_INS] = ins_nes_conv[i][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2785,19 +2782,19 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
|
|||
DivPattern* p=i->pat[j].getPattern(i->orders.ord[j][k],true);
|
||||
for (int l=0; l<i->patLen; l++) {
|
||||
// check for instrument change
|
||||
if (p->data[l][2]!=-1) {
|
||||
curWaveOff=n163WaveOff[p->data[l][2]&127];
|
||||
if (p->newData[l][DIV_PAT_INS]!=-1) {
|
||||
curWaveOff=n163WaveOff[p->newData[l][DIV_PAT_INS]&127];
|
||||
}
|
||||
|
||||
// check effect columns for 0x110 (dummy wave change)
|
||||
for (int m=0; m<i->pat[j].effectCols; m++) {
|
||||
if (p->data[l][4+(m<<1)]==0x110) {
|
||||
if (p->newData[l][DIV_PAT_FX(m)]==0x110) {
|
||||
// map wave
|
||||
p->data[l][4+(m<<1)]=0x10;
|
||||
if (p->data[l][5+(m<<1)]==-1) {
|
||||
p->data[l][5+(m<<1)]=curWaveOff&0xff;
|
||||
p->newData[l][DIV_PAT_FX(m)]=0x10;
|
||||
if (p->newData[l][DIV_PAT_FXVAL(m)]==-1) {
|
||||
p->newData[l][DIV_PAT_FXVAL(m)]=curWaveOff&0xff;
|
||||
} else {
|
||||
p->data[l][5+(m<<1)]=(p->data[l][5+(m<<1)]+curWaveOff)&0xff;
|
||||
p->newData[l][DIV_PAT_FXVAL(m)]=(p->newData[l][DIV_PAT_FXVAL(m)]+curWaveOff)&0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1778,32 +1778,28 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
|
|||
|
||||
if (mask&1) { // note
|
||||
unsigned char note=reader.readC();
|
||||
// TODO: PAT2 format with new off/===/rel values!
|
||||
if (note==180) {
|
||||
pat->data[j][0]=100;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][0]=DIV_NOTE_OFF;
|
||||
} else if (note==181) {
|
||||
pat->data[j][0]=101;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][0]=DIV_NOTE_REL;
|
||||
} else if (note==182) {
|
||||
pat->data[j][0]=102;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][0]=DIV_MACRO_REL;
|
||||
} else if (note<180) {
|
||||
pat->data[j][0]=newFormatNotes[note];
|
||||
pat->data[j][1]=newFormatOctaves[note];
|
||||
pat->newData[j][DIV_PAT_NOTE]=note;
|
||||
} else {
|
||||
pat->data[j][0]=0;
|
||||
pat->data[j][1]=0;
|
||||
pat->newData[j][0]=-1;
|
||||
}
|
||||
}
|
||||
if (mask&2) { // instrument
|
||||
pat->data[j][2]=(unsigned char)reader.readC();
|
||||
pat->newData[j][DIV_PAT_INS]=(unsigned char)reader.readC();
|
||||
}
|
||||
if (mask&4) { // volume
|
||||
pat->data[j][3]=(unsigned char)reader.readC();
|
||||
pat->newData[j][DIV_PAT_VOL]=(unsigned char)reader.readC();
|
||||
}
|
||||
for (unsigned char k=0; k<16; k++) {
|
||||
if (effectMask&(1<<k)) {
|
||||
pat->data[j][4+k]=(unsigned char)reader.readC();
|
||||
pat->newData[j][DIV_PAT_FX(0)+k]=(unsigned char)reader.readC();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1844,18 +1840,20 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
|
|||
|
||||
DivPattern* pat=ds.subsong[subs]->pat[chan].getPattern(index,true);
|
||||
for (int j=0; j<ds.subsong[subs]->patLen; j++) {
|
||||
pat->data[j][0]=reader.readS();
|
||||
pat->data[j][1]=reader.readS();
|
||||
pat->data[j][2]=reader.readS();
|
||||
pat->data[j][3]=reader.readS();
|
||||
for (int k=0; k<ds.subsong[subs]->pat[chan].effectCols; k++) {
|
||||
pat->data[j][4+(k<<1)]=reader.readS();
|
||||
pat->data[j][5+(k<<1)]=reader.readS();
|
||||
short note=reader.readS();
|
||||
short octave=reader.readS();
|
||||
if (note==0 && octave!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",chan,i,j,note,octave);
|
||||
note=12;
|
||||
octave--;
|
||||
}
|
||||
if (pat->data[j][0]==0 && pat->data[j][1]!=0) {
|
||||
logD("what? %d:%d:%d note %d octave %d",chan,i,j,pat->data[j][0],pat->data[j][1]);
|
||||
pat->data[j][0]=12;
|
||||
pat->data[j][1]--;
|
||||
pat->newData[j][DIV_PAT_NOTE]=splitNoteToNote(note,octave);
|
||||
|
||||
pat->newData[j][DIV_PAT_INS]=reader.readS();
|
||||
pat->newData[j][DIV_PAT_VOL]=reader.readS();
|
||||
for (int k=0; k<ds.subsong[subs]->pat[chan].effectCols; k++) {
|
||||
pat->newData[j][DIV_PAT_FX(k)]=reader.readS();
|
||||
pat->newData[j][DIV_PAT_FXVAL(k)]=reader.readS();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2171,7 +2169,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) {
|
|||
return true;
|
||||
}
|
||||
|
||||
SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) {
|
||||
SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
||||
saveLock.lock();
|
||||
std::vector<int> subSongPtr;
|
||||
std::vector<int> sysFlagsPtr;
|
||||
|
|
@ -2622,133 +2620,100 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) {
|
|||
DivPattern* pat=song.subsong[i.subsong]->pat[i.chan].getPattern(i.pat,false);
|
||||
patPtr.push_back(w->tell());
|
||||
|
||||
if (newPatternFormat) {
|
||||
w->write("PATN",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
w->write("PATN",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
|
||||
w->writeC(i.subsong);
|
||||
w->writeC(i.chan);
|
||||
w->writeS(i.pat);
|
||||
w->writeString(pat->name,false);
|
||||
w->writeC(i.subsong);
|
||||
w->writeC(i.chan);
|
||||
w->writeS(i.pat);
|
||||
w->writeString(pat->name,false);
|
||||
|
||||
unsigned char emptyRows=0;
|
||||
unsigned char emptyRows=0;
|
||||
|
||||
for (int j=0; j<song.subsong[i.subsong]->patLen; j++) {
|
||||
unsigned char mask=0;
|
||||
unsigned char finalNote=255;
|
||||
unsigned short effectMask=0;
|
||||
for (int j=0; j<song.subsong[i.subsong]->patLen; j++) {
|
||||
unsigned char mask=0;
|
||||
unsigned char finalNote=255;
|
||||
unsigned short effectMask=0;
|
||||
|
||||
if (pat->data[j][0]==100) {
|
||||
finalNote=180;
|
||||
} else if (pat->data[j][0]==101) { // note release
|
||||
finalNote=181;
|
||||
} else if (pat->data[j][0]==102) { // macro release
|
||||
finalNote=182;
|
||||
} else if (pat->data[j][1]==0 && pat->data[j][0]==0) {
|
||||
finalNote=255;
|
||||
} else {
|
||||
int seek=(pat->data[j][0]+(signed char)pat->data[j][1]*12)+60;
|
||||
if (seek<0 || seek>=180) {
|
||||
finalNote=255;
|
||||
} else {
|
||||
finalNote=seek;
|
||||
}
|
||||
}
|
||||
|
||||
if (finalNote!=255) mask|=1; // note
|
||||
if (pat->data[j][2]!=-1) mask|=2; // instrument
|
||||
if (pat->data[j][3]!=-1) mask|=4; // volume
|
||||
for (int k=0; k<song.subsong[i.subsong]->pat[i.chan].effectCols*2; k+=2) {
|
||||
if (k==0) {
|
||||
if (pat->data[j][4+k]!=-1) mask|=8;
|
||||
if (pat->data[j][5+k]!=-1) mask|=16;
|
||||
} else if (k<8) {
|
||||
if (pat->data[j][4+k]!=-1 || pat->data[j][5+k]!=-1) mask|=32;
|
||||
} else {
|
||||
if (pat->data[j][4+k]!=-1 || pat->data[j][5+k]!=-1) mask|=64;
|
||||
}
|
||||
|
||||
if (pat->data[j][4+k]!=-1) effectMask|=(1<<k);
|
||||
if (pat->data[j][5+k]!=-1) effectMask|=(2<<k);
|
||||
}
|
||||
|
||||
if (mask==0) {
|
||||
emptyRows++;
|
||||
if (emptyRows>127) {
|
||||
w->writeC(128|(emptyRows-2));
|
||||
emptyRows=0;
|
||||
}
|
||||
} else {
|
||||
if (emptyRows>1) {
|
||||
w->writeC(128|(emptyRows-2));
|
||||
emptyRows=0;
|
||||
} else if (emptyRows) {
|
||||
w->writeC(0);
|
||||
emptyRows=0;
|
||||
}
|
||||
|
||||
w->writeC(mask);
|
||||
|
||||
if (mask&32) w->writeC(effectMask&0xff);
|
||||
if (mask&64) w->writeC((effectMask>>8)&0xff);
|
||||
|
||||
if (mask&1) w->writeC(finalNote);
|
||||
if (mask&2) w->writeC(pat->data[j][2]);
|
||||
if (mask&4) w->writeC(pat->data[j][3]);
|
||||
if (mask&8) w->writeC(pat->data[j][4]);
|
||||
if (mask&16) w->writeC(pat->data[j][5]);
|
||||
if (mask&32) {
|
||||
if (effectMask&4) w->writeC(pat->data[j][6]);
|
||||
if (effectMask&8) w->writeC(pat->data[j][7]);
|
||||
if (effectMask&16) w->writeC(pat->data[j][8]);
|
||||
if (effectMask&32) w->writeC(pat->data[j][9]);
|
||||
if (effectMask&64) w->writeC(pat->data[j][10]);
|
||||
if (effectMask&128) w->writeC(pat->data[j][11]);
|
||||
}
|
||||
if (mask&64) {
|
||||
if (effectMask&256) w->writeC(pat->data[j][12]);
|
||||
if (effectMask&512) w->writeC(pat->data[j][13]);
|
||||
if (effectMask&1024) w->writeC(pat->data[j][14]);
|
||||
if (effectMask&2048) w->writeC(pat->data[j][15]);
|
||||
if (effectMask&4096) w->writeC(pat->data[j][16]);
|
||||
if (effectMask&8192) w->writeC(pat->data[j][17]);
|
||||
if (effectMask&16384) w->writeC(pat->data[j][18]);
|
||||
if (effectMask&32768) w->writeC(pat->data[j][19]);
|
||||
}
|
||||
}
|
||||
if (pat->newData[j][DIV_PAT_NOTE]==DIV_NOTE_OFF) { // note off
|
||||
finalNote=180;
|
||||
} else if (pat->newData[j][DIV_PAT_NOTE]==DIV_NOTE_REL) { // note release
|
||||
finalNote=181;
|
||||
} else if (pat->newData[j][DIV_PAT_NOTE]==DIV_MACRO_REL) { // macro release
|
||||
finalNote=182;
|
||||
} else if (pat->newData[j][DIV_PAT_NOTE]==-1) { // empty
|
||||
finalNote=255;
|
||||
} else {
|
||||
finalNote=pat->newData[j][DIV_PAT_NOTE];
|
||||
}
|
||||
|
||||
// stop
|
||||
w->writeC(0xff);
|
||||
} else {
|
||||
w->write("PATR",4);
|
||||
blockStartSeek=w->tell();
|
||||
w->writeI(0);
|
||||
|
||||
w->writeS(i.chan);
|
||||
w->writeS(i.pat);
|
||||
w->writeS(i.subsong);
|
||||
|
||||
w->writeS(0); // reserved
|
||||
|
||||
for (int j=0; j<song.subsong[i.subsong]->patLen; j++) {
|
||||
w->writeS(pat->data[j][0]); // note
|
||||
w->writeS(pat->data[j][1]); // octave
|
||||
w->writeS(pat->data[j][2]); // instrument
|
||||
w->writeS(pat->data[j][3]); // volume
|
||||
#ifdef TA_BIG_ENDIAN
|
||||
for (int k=0; k<song.subsong[i.subsong]->pat[i.chan].effectCols*2; k++) {
|
||||
w->writeS(pat->data[j][4+k]);
|
||||
if (finalNote!=255) mask|=1; // note
|
||||
if (pat->newData[j][DIV_PAT_INS]!=-1) mask|=2; // instrument
|
||||
if (pat->newData[j][DIV_PAT_VOL]!=-1) mask|=4; // volume
|
||||
for (int k=0; k<song.subsong[i.subsong]->pat[i.chan].effectCols*2; k+=2) {
|
||||
if (k==0) {
|
||||
if (pat->newData[j][DIV_PAT_FX(0)+k]!=-1) mask|=8;
|
||||
if (pat->newData[j][DIV_PAT_FXVAL(0)+k]!=-1) mask|=16;
|
||||
} else if (k<8) {
|
||||
if (pat->newData[j][DIV_PAT_FX(0)+k]!=-1 || pat->newData[j][DIV_PAT_FXVAL(0)+k]!=-1) mask|=32;
|
||||
} else {
|
||||
if (pat->newData[j][DIV_PAT_FX(0)+k]!=-1 || pat->newData[j][DIV_PAT_FXVAL(0)+k]!=-1) mask|=64;
|
||||
}
|
||||
#else
|
||||
w->write(&pat->data[j][4],2*song.subsong[i.subsong]->pat[i.chan].effectCols*2); // effects
|
||||
#endif
|
||||
|
||||
if (pat->newData[j][DIV_PAT_FX(0)+k]!=-1) effectMask|=(1<<k);
|
||||
if (pat->newData[j][DIV_PAT_FXVAL(0)+k]!=-1) effectMask|=(2<<k);
|
||||
}
|
||||
|
||||
w->writeString(pat->name,false);
|
||||
if (mask==0) {
|
||||
emptyRows++;
|
||||
if (emptyRows>127) {
|
||||
w->writeC(128|(emptyRows-2));
|
||||
emptyRows=0;
|
||||
}
|
||||
} else {
|
||||
if (emptyRows>1) {
|
||||
w->writeC(128|(emptyRows-2));
|
||||
emptyRows=0;
|
||||
} else if (emptyRows) {
|
||||
w->writeC(0);
|
||||
emptyRows=0;
|
||||
}
|
||||
|
||||
w->writeC(mask);
|
||||
|
||||
if (mask&32) w->writeC(effectMask&0xff);
|
||||
if (mask&64) w->writeC((effectMask>>8)&0xff);
|
||||
|
||||
if (mask&1) w->writeC(finalNote);
|
||||
if (mask&2) w->writeC(pat->newData[j][DIV_PAT_INS]);
|
||||
if (mask&4) w->writeC(pat->newData[j][DIV_PAT_VOL]);
|
||||
if (mask&8) w->writeC(pat->newData[j][DIV_PAT_FX(0)]);
|
||||
if (mask&16) w->writeC(pat->newData[j][DIV_PAT_FXVAL(0)]);
|
||||
if (mask&32) {
|
||||
if (effectMask&4) w->writeC(pat->newData[j][DIV_PAT_FX(1)]);
|
||||
if (effectMask&8) w->writeC(pat->newData[j][DIV_PAT_FXVAL(1)]);
|
||||
if (effectMask&16) w->writeC(pat->newData[j][DIV_PAT_FX(2)]);
|
||||
if (effectMask&32) w->writeC(pat->newData[j][DIV_PAT_FXVAL(2)]);
|
||||
if (effectMask&64) w->writeC(pat->newData[j][DIV_PAT_FX(3)]);
|
||||
if (effectMask&128) w->writeC(pat->newData[j][DIV_PAT_FXVAL(3)]);
|
||||
}
|
||||
if (mask&64) {
|
||||
if (effectMask&256) w->writeC(pat->newData[j][DIV_PAT_FX(4)]);
|
||||
if (effectMask&512) w->writeC(pat->newData[j][DIV_PAT_FXVAL(4)]);
|
||||
if (effectMask&1024) w->writeC(pat->newData[j][DIV_PAT_FX(5)]);
|
||||
if (effectMask&2048) w->writeC(pat->newData[j][DIV_PAT_FXVAL(5)]);
|
||||
if (effectMask&4096) w->writeC(pat->newData[j][DIV_PAT_FX(6)]);
|
||||
if (effectMask&8192) w->writeC(pat->newData[j][DIV_PAT_FXVAL(6)]);
|
||||
if (effectMask&16384) w->writeC(pat->newData[j][DIV_PAT_FX(7)]);
|
||||
if (effectMask&32768) w->writeC(pat->newData[j][DIV_PAT_FXVAL(7)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stop
|
||||
w->writeC(0xff);
|
||||
|
||||
blockEndSeek=w->tell();
|
||||
w->seek(blockStartSeek,SEEK_SET);
|
||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||
|
|
|
|||
|
|
@ -1062,7 +1062,7 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
int readRow=0;
|
||||
bool mustCommitInitial=true;
|
||||
|
||||
memset(effectCol,4,64);
|
||||
memset(effectCol,0,64);
|
||||
memset(vibStatus,0,64);
|
||||
memset(vibStatusChanged,0,64*sizeof(bool));
|
||||
memset(vibing,0,64*sizeof(bool));
|
||||
|
|
@ -1139,86 +1139,86 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
for (int j=0; j<64; j++) {
|
||||
DivPattern* p=ds.subsong[0]->pat[j].getPattern(i,true);
|
||||
if (vibing[j]!=vibingOld[j] || vibStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x04;
|
||||
p->data[readRow][effectCol[j]++]=vibing[j]?vibStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=vibing[j]?vibStatus[j]:0;
|
||||
doesVibrato[j]=true;
|
||||
} else if (doesVibrato[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x04;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (volSliding[j]!=volSlidingOld[j] || volSlideStatusChanged[j]) {
|
||||
if (volSlideStatus[j]>=0xf1 && volSliding[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0xf9;
|
||||
p->data[readRow][effectCol[j]++]=volSlideStatus[j]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xf9;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSlideStatus[j]&15;
|
||||
volSliding[j]=false;
|
||||
} else if ((volSlideStatus[j]&15)==15 && volSlideStatus[j]>=0x10 && volSliding[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0xf8;
|
||||
p->data[readRow][effectCol[j]++]=volSlideStatus[j]>>4;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xf8;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSlideStatus[j]>>4;
|
||||
volSliding[j]=false;
|
||||
} else {
|
||||
p->data[readRow][effectCol[j]++]=0xfa;
|
||||
p->data[readRow][effectCol[j]++]=volSliding[j]?volSlideStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xfa;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSliding[j]?volSlideStatus[j]:0;
|
||||
}
|
||||
doesVolSlide[j]=true;
|
||||
} else if (doesVolSlide[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0xfa;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xfa;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (porting[j]!=portingOld[j] || portaStatusChanged[j]) {
|
||||
if (portaStatus[j]>=0xe0 && portaType[j]!=3 && porting[j]) {
|
||||
p->data[readRow][effectCol[j]++]=portaType[j]|0xf0;
|
||||
p->data[readRow][effectCol[j]++]=(portaStatus[j]&15)*((portaStatus[j]>=0xf0)?1:1);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=portaType[j]|0xf0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=(portaStatus[j]&15)*((portaStatus[j]>=0xf0)?1:1);
|
||||
porting[j]=false;
|
||||
} else {
|
||||
p->data[readRow][effectCol[j]++]=portaType[j];
|
||||
p->data[readRow][effectCol[j]++]=porting[j]?portaStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=portaType[j];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=porting[j]?portaStatus[j]:0;
|
||||
}
|
||||
doesPitchSlide[j]=true;
|
||||
} else if (doesPitchSlide[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x01;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x01;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (arping[j]!=arpingOld[j] || arpStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x00;
|
||||
p->data[readRow][effectCol[j]++]=arping[j]?arpStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=arping[j]?arpStatus[j]:0;
|
||||
doesArp[j]=true;
|
||||
} else if (doesArp[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x00;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x84;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x84;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x83;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x83;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if ((effectCol[j]>>1)-2>ds.subsong[0]->pat[j].effectCols) {
|
||||
ds.subsong[0]->pat[j].effectCols=(effectCol[j]>>1)-1;
|
||||
if ((effectCol[j]>>1)>=ds.subsong[0]->pat[j].effectCols) {
|
||||
ds.subsong[0]->pat[j].effectCols=(effectCol[j]>>1)+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1250,16 +1250,16 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
if (readRow>0) {
|
||||
// place end of pattern marker
|
||||
DivPattern* p=ds.subsong[0]->pat[0].getPattern(i,true);
|
||||
p->data[readRow-1][effectCol[0]++]=0x0d;
|
||||
p->data[readRow-1][effectCol[0]++]=0;
|
||||
p->newData[readRow-1][DIV_PAT_FX(0)+effectCol[0]++]=0x0d;
|
||||
p->newData[readRow-1][DIV_PAT_FX(0)+effectCol[0]++]=0;
|
||||
|
||||
if ((effectCol[0]>>1)-2>ds.subsong[0]->pat[0].effectCols) {
|
||||
ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)-1;
|
||||
if ((effectCol[0]>>1)>=ds.subsong[0]->pat[0].effectCols) {
|
||||
ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)+1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
memset(effectCol,4,64);
|
||||
memset(effectCol,0,64);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1302,25 +1302,17 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
|
||||
if (hasNote) {
|
||||
if (note[chan]==255) { // note release
|
||||
p->data[readRow][0]=101;
|
||||
p->data[readRow][1]=0;
|
||||
p->newData[readRow][DIV_PAT_NOTE]=DIV_NOTE_REL;
|
||||
} else if (note[chan]==254) { // note off
|
||||
p->data[readRow][0]=100;
|
||||
p->data[readRow][1]=0;
|
||||
p->newData[readRow][DIV_PAT_NOTE]=DIV_NOTE_OFF;
|
||||
} else if (note[chan]<120) {
|
||||
p->data[readRow][0]=note[chan]%12;
|
||||
p->data[readRow][1]=note[chan]/12;
|
||||
if (p->data[readRow][0]==0) {
|
||||
p->data[readRow][0]=12;
|
||||
p->data[readRow][1]--;
|
||||
}
|
||||
p->newData[readRow][DIV_PAT_NOTE]=note[chan]+60;
|
||||
} else { // note fade, but Furnace does not support that
|
||||
p->data[readRow][0]=102;
|
||||
p->data[readRow][1]=0;
|
||||
p->newData[readRow][DIV_PAT_NOTE]=DIV_MACRO_REL;
|
||||
}
|
||||
}
|
||||
if (hasIns) {
|
||||
p->data[readRow][2]=ins[chan]-1;
|
||||
p->newData[readRow][DIV_PAT_INS]=ins[chan]-1;
|
||||
if ((note[chan]<120 || ds.insLen==0) && ins[chan]>0) {
|
||||
unsigned char targetPan=0;
|
||||
if (ds.insLen==0) {
|
||||
|
|
@ -1332,26 +1324,26 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
}
|
||||
}
|
||||
if (targetPan&128) {
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=CLAMP((targetPan&127)<<2,0,255);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=CLAMP((targetPan&127)<<2,0,255);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNote && (note[chan]<120 || ds.insLen==0) && ins[chan]>0) {
|
||||
if (ds.insLen==0) {
|
||||
p->data[readRow][3]=defVol[(ins[chan]-1)&255];
|
||||
p->newData[readRow][DIV_PAT_VOL]=defVol[(ins[chan]-1)&255];
|
||||
} else {
|
||||
p->data[readRow][3]=defVol[noteMap[(ins[chan]-1)&255][note[chan]]];
|
||||
p->newData[readRow][DIV_PAT_VOL]=defVol[noteMap[(ins[chan]-1)&255][note[chan]]];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasVol) {
|
||||
if (vol[chan]<=64) {
|
||||
p->data[readRow][3]=vol[chan];
|
||||
p->newData[readRow][DIV_PAT_VOL]=vol[chan];
|
||||
} else { // effects in volume column
|
||||
if (vol[chan]>=128 && vol[chan]<=192) { // panning
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=CLAMP((vol[chan]-128)<<2,0,255);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=CLAMP((vol[chan]-128)<<2,0,255);
|
||||
} else if (vol[chan]>=65 && vol[chan]<=74) { // fine vol up
|
||||
} else if (vol[chan]>=75 && vol[chan]<=84) { // fine vol down
|
||||
} else if (vol[chan]>=85 && vol[chan]<=94) { // vol slide up
|
||||
|
|
@ -1398,16 +1390,16 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
if (hasEffect) {
|
||||
switch (effect[chan]+'A'-1) {
|
||||
case 'A': // speed
|
||||
p->data[readRow][effectCol[chan]++]=0x0f;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0f;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan];
|
||||
break;
|
||||
case 'B': // go to order
|
||||
p->data[readRow][effectCol[chan]++]=0x0b;
|
||||
p->data[readRow][effectCol[chan]++]=orders[effectVal[chan]];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0b;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=orders[effectVal[chan]];
|
||||
break;
|
||||
case 'C': // next order
|
||||
p->data[readRow][effectCol[chan]++]=0x0d;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0d;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan];
|
||||
break;
|
||||
case 'D': // vol slide
|
||||
if (effectVal[chan]!=0) {
|
||||
|
|
@ -1490,8 +1482,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
case 'N': // channel vol slide
|
||||
break;
|
||||
case 'O': // offset
|
||||
p->data[readRow][effectCol[chan]++]=0x91;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x91;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan];
|
||||
break;
|
||||
case 'P': // pan slide
|
||||
if (effectVal[chan]!=0) {
|
||||
|
|
@ -1504,8 +1496,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
if (effectVal[chan]!=0) {
|
||||
lastRetrig[chan]=effectVal[chan];
|
||||
}
|
||||
p->data[readRow][effectCol[chan]++]=0x0c;
|
||||
p->data[readRow][effectCol[chan]++]=lastRetrig[chan]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0c;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=lastRetrig[chan]&15;
|
||||
break;
|
||||
case 'R': // tremolo
|
||||
if (effectVal[chan]!=0) {
|
||||
|
|
@ -1519,77 +1511,77 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
case 0x3: // vibrato waveform
|
||||
switch (effectVal[chan]&3) {
|
||||
case 0x0: // sine
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x00;
|
||||
break;
|
||||
case 0x1: // ramp down
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x05;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x05;
|
||||
break;
|
||||
case 0x2: // square
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x06;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x06;
|
||||
break;
|
||||
case 0x3: // random
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x07;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x7:
|
||||
switch (effectVal[chan]&15) {
|
||||
case 0x7: // volume envelope off
|
||||
p->data[readRow][effectCol[chan]++]=0xf5;
|
||||
p->data[readRow][effectCol[chan]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf5;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x00;
|
||||
break;
|
||||
case 0x8: // volume envelope on
|
||||
p->data[readRow][effectCol[chan]++]=0xf6;
|
||||
p->data[readRow][effectCol[chan]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf6;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x00;
|
||||
break;
|
||||
case 0x9: // panning envelope off
|
||||
p->data[readRow][effectCol[chan]++]=0xf5;
|
||||
p->data[readRow][effectCol[chan]++]=0x0c;
|
||||
p->data[readRow][effectCol[chan]++]=0xf5;
|
||||
p->data[readRow][effectCol[chan]++]=0x0d;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf5;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0c;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf5;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0d;
|
||||
break;
|
||||
case 0xa: // panning envelope on
|
||||
p->data[readRow][effectCol[chan]++]=0xf6;
|
||||
p->data[readRow][effectCol[chan]++]=0x0c;
|
||||
p->data[readRow][effectCol[chan]++]=0xf6;
|
||||
p->data[readRow][effectCol[chan]++]=0x0d;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf6;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0c;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf6;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0d;
|
||||
break;
|
||||
case 0xb: // pitch envelope off
|
||||
p->data[readRow][effectCol[chan]++]=0xf5;
|
||||
p->data[readRow][effectCol[chan]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf5;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x04;
|
||||
break;
|
||||
case 0xc: //pitch envelope on
|
||||
p->data[readRow][effectCol[chan]++]=0xf6;
|
||||
p->data[readRow][effectCol[chan]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf6;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x04;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x8: // panning
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=(effectVal[chan]&15)<<4;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=(effectVal[chan]&15)<<4;
|
||||
break;
|
||||
case 0xa: // offset (high nibble)
|
||||
p->data[readRow][effectCol[chan]++]=0x92;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x92;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan]&15;
|
||||
break;
|
||||
case 0xc: // note cut
|
||||
p->data[readRow][effectCol[chan]++]=0xec;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xec;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan]&15;
|
||||
break;
|
||||
case 0xd: // note delay
|
||||
p->data[readRow][effectCol[chan]++]=0xed;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xed;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan]&15;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'T': // tempo
|
||||
if (effectVal[chan]>=0x20) {
|
||||
p->data[readRow][effectCol[chan]++]=0xf0;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan];
|
||||
}
|
||||
break;
|
||||
case 'U': // fine vibrato
|
||||
|
|
@ -1604,8 +1596,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
case 'W': // global volume slide (!)
|
||||
break;
|
||||
case 'X': // panning
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal[chan];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal[chan];
|
||||
break;
|
||||
case 'Y': // panbrello
|
||||
if (effectVal[chan]!=0) {
|
||||
|
|
@ -1690,18 +1682,18 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
|
|||
for (int j=0; j<maxChan; j++) {
|
||||
DivPattern* p=ds.subsong[i]->pat[j].getPattern(ds.subsong[i]->orders.ord[j][0],true);
|
||||
for (int k=0; k<DIV_MAX_EFFECTS; k++) {
|
||||
if (p->data[0][4+(k<<1)]==0x80) {
|
||||
if (p->newData[0][DIV_PAT_FX(k)]==0x80) {
|
||||
// give up if there's a panning effect already
|
||||
break;
|
||||
}
|
||||
if (p->data[0][4+(k<<1)]==-1) {
|
||||
if (p->newData[0][DIV_PAT_FX(k)]==-1) {
|
||||
if ((chanPan[j]&127)==100) {
|
||||
// should be surround...
|
||||
p->data[0][4+(k<<1)]=0x80;
|
||||
p->data[0][5+(k<<1)]=0x80;
|
||||
p->newData[0][DIV_PAT_FX(k)]=0x80;
|
||||
p->newData[0][DIV_PAT_FXVAL(k)]=0x80;
|
||||
} else {
|
||||
p->data[0][4+(k<<1)]=0x80;
|
||||
p->data[0][5+(k<<1)]=CLAMP((chanPan[j]&127)<<2,0,255);
|
||||
p->newData[0][DIV_PAT_FX(k)]=0x80;
|
||||
p->newData[0][DIV_PAT_FXVAL(k)]=CLAMP((chanPan[j]&127)<<2,0,255);
|
||||
}
|
||||
if (ds.subsong[i]->pat[j].effectCols<=k) ds.subsong[i]->pat[j].effectCols=k+1;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -185,21 +185,20 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
}
|
||||
for (int row=0; row<64; row++) {
|
||||
for (int ch=0; ch<chCount; ch++) {
|
||||
short* dstrow=chpats[ch]->data[row];
|
||||
short* dstrowN=chpats[ch]->newData[row];
|
||||
unsigned char data[4];
|
||||
reader.read(&data,4);
|
||||
// instrument
|
||||
short ins=(data[0]&0xf0)|(data[2]>>4);
|
||||
if (ins>0) {
|
||||
dstrow[2]=ins-1;
|
||||
dstrow[3]=defaultVols[ins-1];
|
||||
dstrowN[DIV_PAT_INS]=ins-1;
|
||||
dstrowN[DIV_PAT_VOL]=defaultVols[ins-1];
|
||||
}
|
||||
// note
|
||||
int period=data[1]+((data[0]&0x0f)<<8);
|
||||
if (period>0 && period<0x0fff) {
|
||||
short note=(short)round(log2(3424.0/period)*12);
|
||||
dstrow[0]=((note+11)%12)+1;
|
||||
dstrow[1]=(note-1)/12+1;
|
||||
dstrowN[DIV_PAT_NOTE]=note+72;
|
||||
if (period<114) {
|
||||
bypassLimits=true;
|
||||
}
|
||||
|
|
@ -207,8 +206,8 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
// effects are done later
|
||||
short fxtyp=data[2]&0x0f;
|
||||
short fxval=data[3];
|
||||
dstrow[4]=fxtyp;
|
||||
dstrow[5]=fxval;
|
||||
dstrowN[DIV_PAT_FX(0)]=fxtyp;
|
||||
dstrowN[DIV_PAT_FXVAL(0)]=fxval;
|
||||
switch (fxtyp) {
|
||||
case 0:
|
||||
if (fxval!=0) fxUsage[ch][0]=true;
|
||||
|
|
@ -256,7 +255,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
for (int ch=0; ch<=chCount; ch++) {
|
||||
unsigned char fxCols=1;
|
||||
for (int pat=0; pat<=patMax; pat++) {
|
||||
auto* data=ds.subsong[0]->pat[ch].getPattern(pat,true)->data;
|
||||
auto* newData=ds.subsong[0]->pat[ch].getPattern(pat,true)->newData;
|
||||
short lastPitchEffect=-1;
|
||||
short lastEffectState[5]={-1,-1,-1,-1,-1};
|
||||
short setEffectState[5]={-1,-1,-1,-1,-1};
|
||||
|
|
@ -264,11 +263,11 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
const short fxUsageTyp[5]={0x00,0x01,0x04,0x07,0xFA};
|
||||
short effectState[5]={0,0,0,0,0};
|
||||
unsigned char curFxCol=0;
|
||||
short fxTyp=data[row][4];
|
||||
short fxVal=data[row][5];
|
||||
auto writeFxCol=[data,row,&curFxCol](short typ, short val) {
|
||||
data[row][4+curFxCol*2]=typ;
|
||||
data[row][5+curFxCol*2]=val;
|
||||
short fxTyp=newData[row][DIV_PAT_FX(0)];
|
||||
short fxVal=newData[row][DIV_PAT_FXVAL(0)];
|
||||
auto writeFxCol=[newData,row,&curFxCol](short typ, short val) {
|
||||
newData[row][DIV_PAT_FX(curFxCol)]=typ;
|
||||
newData[row][DIV_PAT_FXVAL(curFxCol)]=val;
|
||||
curFxCol++;
|
||||
};
|
||||
writeFxCol(-1,-1);
|
||||
|
|
@ -293,7 +292,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
effectState[1]=fxVal;
|
||||
if ((effectState[1]!=lastEffectState[1]) ||
|
||||
(fxTyp!=lastPitchEffect) ||
|
||||
(effectState[1]!=0 && data[row][0]>0)) {
|
||||
(effectState[1]!=0 && newData[row][DIV_PAT_NOTE]>-1)) {
|
||||
writeFxCol(fxTyp,fxVal);
|
||||
}
|
||||
lastPitchEffect=fxTyp;
|
||||
|
|
@ -331,7 +330,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
writeFxCol(fxTyp,fxVal);
|
||||
break;
|
||||
case 12: // set vol
|
||||
data[row][3]=MIN(0x40,fxVal);
|
||||
newData[row][DIV_PAT_VOL]=MIN(0x40,fxVal);
|
||||
break;
|
||||
case 13: // break to row (BCD)
|
||||
writeFxCol(fxTyp,((fxVal>>4)*10)+(fxVal&15));
|
||||
|
|
@ -387,7 +386,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
for (int i=0; i<5; i++) {
|
||||
// pitch slide and volume slide needs to be kept active on new note
|
||||
// even after target/max is reached
|
||||
if (fxUsage[ch][i] && (effectState[i]!=lastEffectState[i] || (effectState[i]!=0 && i==4 && data[row][3]>=0))) {
|
||||
if (fxUsage[ch][i] && (effectState[i]!=lastEffectState[i] || (effectState[i]!=0 && i==4 && newData[row][DIV_PAT_VOL]>=0))) {
|
||||
writeFxCol(fxUsageTyp[i],effectState[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -771,7 +771,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
|
||||
bool mustCommitInitial=true;
|
||||
|
||||
memset(effectCol,4,32);
|
||||
memset(effectCol,0,32);
|
||||
memset(vibStatus,0,32);
|
||||
memset(vibStatusChanged,0,32*sizeof(bool));
|
||||
memset(vibing,0,32*sizeof(bool));
|
||||
|
|
@ -811,95 +811,95 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
for (int j=0; j<32; j++) {
|
||||
DivPattern* p=ds.subsong[0]->pat[chanMap[j]].getPattern(i,true);
|
||||
if (vibing[j]!=vibingOld[j] || vibStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x04;
|
||||
p->data[readRow][effectCol[j]++]=vibing[j]?vibStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=vibing[j]?vibStatus[j]:0;
|
||||
doesVibrato[j]=true;
|
||||
} else if (doesVibrato[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x04;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x04;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (volSliding[j]!=volSlidingOld[j] || volSlideStatusChanged[j]) {
|
||||
if (volSlideStatus[j]>=0xf1 && volSliding[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0xf9;
|
||||
p->data[readRow][effectCol[j]++]=volSlideStatus[j]&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xf9;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSlideStatus[j]&15;
|
||||
volSliding[j]=false;
|
||||
} else if ((volSlideStatus[j]&15)==15 && volSlideStatus[j]>=0x10 && volSliding[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0xf8;
|
||||
p->data[readRow][effectCol[j]++]=volSlideStatus[j]>>4;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xf8;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSlideStatus[j]>>4;
|
||||
volSliding[j]=false;
|
||||
} else {
|
||||
p->data[readRow][effectCol[j]++]=0xfa;
|
||||
p->data[readRow][effectCol[j]++]=volSliding[j]?volSlideStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xfa;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=volSliding[j]?volSlideStatus[j]:0;
|
||||
}
|
||||
doesVolSlide[j]=true;
|
||||
} else if (doesVolSlide[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0xfa;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0xfa;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (porting[j]!=portingOld[j] || portaStatusChanged[j]) {
|
||||
if (portaStatus[j]>=0xe0 && portaType[j]!=3 && porting[j]) {
|
||||
p->data[readRow][effectCol[j]++]=portaType[j]|0xf0;
|
||||
p->data[readRow][effectCol[j]++]=(portaStatus[j]&15)*((portaStatus[j]>=0xf0)?1:1);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=portaType[j]|0xf0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=(portaStatus[j]&15)*((portaStatus[j]>=0xf0)?1:1);
|
||||
porting[j]=false;
|
||||
} else {
|
||||
p->data[readRow][effectCol[j]++]=portaType[j];
|
||||
p->data[readRow][effectCol[j]++]=porting[j]?portaStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=portaType[j];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=porting[j]?portaStatus[j]:0;
|
||||
}
|
||||
doesPitchSlide[j]=true;
|
||||
} else if (doesPitchSlide[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x01;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x01;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (arping[j]!=arpingOld[j] || arpStatusChanged[j]) {
|
||||
p->data[readRow][effectCol[j]++]=0x00;
|
||||
p->data[readRow][effectCol[j]++]=arping[j]?arpStatus[j]:0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=arping[j]?arpStatus[j]:0;
|
||||
doesArp[j]=true;
|
||||
} else if (doesArp[j] && mustCommitInitial) {
|
||||
p->data[readRow][effectCol[j]++]=0x00;
|
||||
p->data[readRow][effectCol[j]++]=0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x84;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x84;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x83;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+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;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0x83;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[j]++]=0;
|
||||
}
|
||||
|
||||
if (effectCol[j]>=4+8*2) {
|
||||
if (effectCol[j]>=8*2) {
|
||||
logE("oh crap!");
|
||||
}
|
||||
|
||||
if ((effectCol[j]>>1)-2>ds.subsong[0]->pat[j].effectCols) {
|
||||
ds.subsong[0]->pat[chanMap[j]].effectCols=(effectCol[j]>>1)-1;
|
||||
if ((effectCol[j]>>1)>=ds.subsong[0]->pat[j].effectCols) {
|
||||
ds.subsong[0]->pat[chanMap[j]].effectCols=(effectCol[j]>>1)+1;
|
||||
}
|
||||
}
|
||||
|
||||
readRow++;
|
||||
memset(effectCol,4,32);
|
||||
memset(effectCol,0,32);
|
||||
memcpy(vibingOld,vibing,32*sizeof(bool));
|
||||
memcpy(volSlidingOld,volSliding,32*sizeof(bool));
|
||||
memcpy(portingOld,porting,32*sizeof(bool));
|
||||
|
|
@ -935,22 +935,16 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
unsigned char ins=reader.readC();
|
||||
|
||||
if (note==254) { // note off
|
||||
p->data[readRow][0]=100;
|
||||
p->data[readRow][1]=0;
|
||||
p->newData[readRow][DIV_PAT_NOTE]=DIV_NOTE_OFF;
|
||||
} else if (note!=255) {
|
||||
p->data[readRow][0]=note&15;
|
||||
p->data[readRow][1]=note>>4;
|
||||
if ((note&15)==0) {
|
||||
p->data[readRow][0]=12;
|
||||
p->data[readRow][1]--;
|
||||
}
|
||||
p->newData[readRow][DIV_PAT_NOTE]=(note&15)+(note>>4)*12+60;
|
||||
}
|
||||
p->data[readRow][2]=(short)ins-1;
|
||||
p->newData[readRow][DIV_PAT_INS]=(short)ins-1;
|
||||
}
|
||||
if (hasVol) {
|
||||
unsigned char vol=reader.readC();
|
||||
if (vol==255) {
|
||||
p->data[readRow][3]=-1;
|
||||
p->newData[readRow][DIV_PAT_VOL]=-1;
|
||||
} else {
|
||||
// check for OPL channel
|
||||
if ((chanSettings[chan]&31)>=16) {
|
||||
|
|
@ -958,17 +952,17 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
} else {
|
||||
if (vol>64) vol=64;
|
||||
}
|
||||
p->data[readRow][3]=vol;
|
||||
p->newData[readRow][DIV_PAT_VOL]=vol;
|
||||
}
|
||||
} else if (p->data[readRow][2]!=-1) {
|
||||
} else if (p->newData[readRow][DIV_PAT_INS]!=-1) {
|
||||
// populate with instrument volume
|
||||
unsigned char vol=defVol[p->data[readRow][2]&255];
|
||||
unsigned char vol=defVol[p->newData[readRow][DIV_PAT_INS]&255];
|
||||
if ((chanSettings[chan]&31)>=16) {
|
||||
if (vol>63) vol=63;
|
||||
} else {
|
||||
if (vol>64) vol=64;
|
||||
}
|
||||
p->data[readRow][3]=vol;
|
||||
p->newData[readRow][DIV_PAT_VOL]=vol;
|
||||
}
|
||||
if (hasEffect) {
|
||||
unsigned char effect=reader.readC();
|
||||
|
|
@ -976,17 +970,17 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
|
||||
switch (effect+'A'-1) {
|
||||
case 'A': // speed
|
||||
p->data[readRow][effectCol[chan]++]=0x0f;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0f;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal;
|
||||
break;
|
||||
case 'B': // go to order
|
||||
p->data[readRow][effectCol[chan]++]=0x0b;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0b;
|
||||
logD("0B: %x %x",effectVal,orders[effectVal]);
|
||||
p->data[readRow][effectCol[chan]++]=orders[effectVal];
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=orders[effectVal];
|
||||
break;
|
||||
case 'C': // next order
|
||||
p->data[readRow][effectCol[chan]++]=0x0d;
|
||||
p->data[readRow][effectCol[chan]++]=(effectVal>>4)*10+(effectVal&15);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0d;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=(effectVal>>4)*10+(effectVal&15);
|
||||
break;
|
||||
case 'D': // vol slide
|
||||
if (effectVal!=0) {
|
||||
|
|
@ -1078,8 +1072,8 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
case 'N': // channel vol slide (extension)
|
||||
break;
|
||||
case 'O': // offset
|
||||
p->data[readRow][effectCol[chan]++]=0x91;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x91;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal;
|
||||
break;
|
||||
case 'P': // pan slide (extension)
|
||||
if (effectVal!=0) {
|
||||
|
|
@ -1089,8 +1083,8 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
panSliding[chan]=true;
|
||||
break;
|
||||
case 'Q': // retrigger
|
||||
p->data[readRow][effectCol[chan]++]=0x0c;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x0c;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal&15;
|
||||
break;
|
||||
case 'R': // tremolo
|
||||
if (effectVal!=0) {
|
||||
|
|
@ -1104,40 +1098,40 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
case 0x3: // vibrato waveform
|
||||
switch (effectVal&3) {
|
||||
case 0x0: // sine
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x00;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x00;
|
||||
break;
|
||||
case 0x1: // ramp down
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x05;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x05;
|
||||
break;
|
||||
case 0x2: // square
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x06;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x06;
|
||||
break;
|
||||
case 0x3: // random
|
||||
p->data[readRow][effectCol[chan]++]=0xe3;
|
||||
p->data[readRow][effectCol[chan]++]=0x07;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xe3;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x07;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x8: // panning
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=(effectVal&15)<<4;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=(effectVal&15)<<4;
|
||||
break;
|
||||
case 0xc: // note cut
|
||||
p->data[readRow][effectCol[chan]++]=0xec;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xec;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal&15;
|
||||
break;
|
||||
case 0xd: // note delay
|
||||
p->data[readRow][effectCol[chan]++]=0xed;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal&15;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xed;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal&15;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'T': // tempo
|
||||
p->data[readRow][effectCol[chan]++]=0xf0;
|
||||
p->data[readRow][effectCol[chan]++]=effectVal;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0xf0;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=effectVal;
|
||||
break;
|
||||
case 'U': // fine vibrato
|
||||
if (effectVal!=0) {
|
||||
|
|
@ -1152,8 +1146,8 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
break;
|
||||
case 'X': // panning (extension)
|
||||
if (effectVal<=0x80) {
|
||||
p->data[readRow][effectCol[chan]++]=0x80;
|
||||
p->data[readRow][effectCol[chan]++]=(effectVal&0x80)?0xff:(effectVal<<1);
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=0x80;
|
||||
p->newData[readRow][DIV_PAT_FX(0)+effectCol[chan]++]=(effectVal&0x80)?0xff:(effectVal<<1);
|
||||
}
|
||||
break;
|
||||
case 'Y': // panbrello (extension)
|
||||
|
|
@ -1193,16 +1187,16 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
for (int j=0; j<16; j++) {
|
||||
DivPattern* p=ds.subsong[i]->pat[chanMap[j]].getPattern(ds.subsong[i]->orders.ord[j][0],true);
|
||||
for (int k=0; k<DIV_MAX_EFFECTS; k++) {
|
||||
if (p->data[0][4+(k<<1)]==0x80) {
|
||||
if (p->newData[0][DIV_PAT_FX(k)]==0x80) {
|
||||
// give up if there's a panning effect already
|
||||
break;
|
||||
}
|
||||
if (p->data[0][4+(k<<1)]==-1) {
|
||||
p->data[0][4+(k<<1)]=0x80;
|
||||
if (p->newData[0][DIV_PAT_FX(k)]==-1) {
|
||||
p->newData[0][DIV_PAT_FX(k)]=0x80;
|
||||
if (chanPan[j]&16) {
|
||||
p->data[0][5+(k<<1)]=(j&1)?0xcc:0x33;
|
||||
p->newData[0][DIV_PAT_FXVAL(k)]=(j&1)?0xcc:0x33;
|
||||
} else {
|
||||
p->data[0][5+(k<<1)]=(chanPan[j]&15)|((chanPan[j]&15)<<4);
|
||||
p->newData[0][DIV_PAT_FXVAL(k)]=(chanPan[j]&15)|((chanPan[j]&15)<<4);
|
||||
}
|
||||
if (ds.subsong[i]->pat[chanMap[j]].effectCols<=k) ds.subsong[i]->pat[chanMap[j]].effectCols=k+1;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -321,9 +321,8 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
|
|||
|
||||
for (int l=0; l<chans; l++) {
|
||||
DivPattern* p=s->pat[l].getPattern(s->orders.ord[l][j],false);
|
||||
|
||||
int note=p->data[k][0];
|
||||
int octave=p->data[k][1];
|
||||
short note, octave;
|
||||
noteToSplitNote(p->newData[k][DIV_PAT_NOTE],note,octave);
|
||||
|
||||
if (note==0 && octave==0) {
|
||||
w->writeText("|... ");
|
||||
|
|
@ -344,28 +343,28 @@ SafeWriter* DivEngine::saveText(bool separatePatterns) {
|
|||
w->writeText(fmt::sprintf("|%s%d ",(octave<0)?notesNegative[note]:notes[note],(octave<0)?(-octave):octave));
|
||||
}
|
||||
|
||||
if (p->data[k][2]==-1) {
|
||||
if (p->newData[k][DIV_PAT_INS]==-1) {
|
||||
w->writeText(".. ");
|
||||
} else {
|
||||
w->writeText(fmt::sprintf("%.2X ",p->data[k][2]&0xff));
|
||||
w->writeText(fmt::sprintf("%.2X ",p->newData[k][DIV_PAT_INS]&0xff));
|
||||
}
|
||||
|
||||
if (p->data[k][3]==-1) {
|
||||
if (p->newData[k][DIV_PAT_VOL]==-1) {
|
||||
w->writeText("..");
|
||||
} else {
|
||||
w->writeText(fmt::sprintf("%.2X",p->data[k][3]&0xff));
|
||||
w->writeText(fmt::sprintf("%.2X",p->newData[k][DIV_PAT_VOL]&0xff));
|
||||
}
|
||||
|
||||
for (int m=0; m<s->pat[l].effectCols; m++) {
|
||||
if (p->data[k][4+(m<<1)]==-1) {
|
||||
if (p->newData[k][DIV_PAT_FX(m)]==-1) {
|
||||
w->writeText(" ..");
|
||||
} else {
|
||||
w->writeText(fmt::sprintf(" %.2X",p->data[k][4+(m<<1)]&0xff));
|
||||
w->writeText(fmt::sprintf(" %.2X",p->newData[k][DIV_PAT_FX(m)]&0xff));
|
||||
}
|
||||
if (p->data[k][5+(m<<1)]==-1) {
|
||||
if (p->newData[k][DIV_PAT_FXVAL(m)]==-1) {
|
||||
w->writeText("..");
|
||||
} else {
|
||||
w->writeText(fmt::sprintf("%.2X",p->data[k][5+(m<<1)]&0xff));
|
||||
w->writeText(fmt::sprintf("%.2X",p->newData[k][DIV_PAT_FXVAL(m)]&0xff));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,16 +254,10 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
if (patDataBuf[k]==0) continue;
|
||||
else if (patDataBuf[k]==1) {
|
||||
// note off
|
||||
pat->data[k][0]=100;
|
||||
pat->newData[k][DIV_PAT_NOTE]=DIV_NOTE_OFF;
|
||||
} else {
|
||||
unsigned char invertedNote=~patDataBuf[k];
|
||||
pat->data[k][0]=invertedNote%12;
|
||||
pat->data[k][1]=(invertedNote/12)-1;
|
||||
|
||||
if (pat->data[k][0]==0) {
|
||||
pat->data[k][0]=12;
|
||||
pat->data[k][1]--;
|
||||
}
|
||||
pat->newData[k][DIV_PAT_NOTE]=invertedNote+60;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,7 +267,7 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
logD("parsing volumes of pattern %d channel %d",i,j);
|
||||
for (int k=0; k<256; k++) {
|
||||
if (patDataBuf[k]==0) continue;
|
||||
else pat->data[k][3]=0x60+patDataBuf[k];
|
||||
else pat->newData[k][DIV_PAT_VOL]=0x60+patDataBuf[k];
|
||||
}
|
||||
|
||||
// instrument
|
||||
|
|
@ -282,7 +276,7 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
logD("parsing instruments of pattern %d channel %d",i,j);
|
||||
for (int k=0; k<256; k++) {
|
||||
if (patDataBuf[k]==0) continue;
|
||||
pat->data[k][2]=info.insNumMaps[patDataBuf[k]-1];
|
||||
pat->newData[k][DIV_PAT_INS]=info.insNumMaps[patDataBuf[k]-1];
|
||||
}
|
||||
|
||||
// effects
|
||||
|
|
@ -300,76 +294,76 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
case 0:
|
||||
// arpeggio or no effect (if effect val is 0)
|
||||
if (effectVal[k]==0) break;
|
||||
pat->data[k][4+(l*2)]=effectNum[k];
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=effectNum[k];
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 1:
|
||||
// pitch slide up
|
||||
case 2:
|
||||
// pitch slide down
|
||||
pat->data[k][4+(l*2)]=effectNum[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=effectNum[k];
|
||||
if (effectVal[k]) {
|
||||
lastSlide=effectVal[k];
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
} else {
|
||||
pat->data[k][5+(l*2)]=lastSlide;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=lastSlide;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// portamento
|
||||
case 4:
|
||||
// vibrato
|
||||
pat->data[k][5+(l*2)]=0;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=0;
|
||||
if (effectVal[k]&0xF0) {
|
||||
pat->data[k][5+(l*2)]|=effectVal[k]&0xF0;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]|=effectVal[k]&0xF0;
|
||||
} else {
|
||||
pat->data[k][5+(l*2)]|=lastVibrato&0xF0;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]|=lastVibrato&0xF0;
|
||||
}
|
||||
if (effectVal[k]&0x0F) {
|
||||
pat->data[k][5+(l*2)]|=effectVal[k]&0x0F;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]|=effectVal[k]&0x0F;
|
||||
} else {
|
||||
pat->data[k][5+(l*2)]|=lastVibrato&0x0F;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]|=lastVibrato&0x0F;
|
||||
}
|
||||
pat->data[k][4+(l*2)]=effectNum[k];
|
||||
lastVibrato=pat->data[k][5+(l*2)];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=effectNum[k];
|
||||
lastVibrato=pat->newData[k][DIV_PAT_FXVAL(l)];
|
||||
break;
|
||||
case 5:
|
||||
// poramento + volume slide
|
||||
pat->data[k][4+(l*2)]=0x06;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x06;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 6:
|
||||
// vibrato + volume slide
|
||||
pat->data[k][4+(l*2)]=0x05;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x05;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 8:
|
||||
// modify TL of operator 1
|
||||
pat->data[k][4+(l*2)]=0x12;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x12;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 9:
|
||||
// modify TL of operator 2
|
||||
pat->data[k][4+(l*2)]=0x13;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x13;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 10:
|
||||
// volume slide
|
||||
pat->data[k][4+(l*2)]=0xA;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0xA;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 11:
|
||||
// multi-frequency mode of CH3 control
|
||||
// TODO
|
||||
case 12:
|
||||
// modify TL of operator 3
|
||||
pat->data[k][4+(l*2)]=0x14;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x14;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 13:
|
||||
// modify TL of operator 4
|
||||
pat->data[k][4+(l*2)]=0x15;
|
||||
pat->data[k][5+(l*2)]=effectVal[k];
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x15;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=effectVal[k];
|
||||
break;
|
||||
case 14:
|
||||
switch (effectVal[k]>>4) {
|
||||
|
|
@ -378,18 +372,18 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
case 2:
|
||||
case 3:
|
||||
// modify multiplier of operators
|
||||
pat->data[k][4+(l*2)]=0x16;
|
||||
pat->data[k][5+(l*2)]=((effectVal[k]&0xF0)+0x100)|(effectVal[k]&0xF);
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x16;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=((effectVal[k]&0xF0)+0x100)|(effectVal[k]&0xF);
|
||||
break;
|
||||
case 8:
|
||||
// pan
|
||||
pat->data[k][4+(l*2)]=0x80;
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x80;
|
||||
if ((effectVal[k]&0xF)==1) {
|
||||
pat->data[k][5+(l*2)]=0;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=0;
|
||||
} else if ((effectVal[k]&0xF)==2) {
|
||||
pat->data[k][5+(l*2)]=0xFF;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=0xFF;
|
||||
} else {
|
||||
pat->data[k][5+(l*2)]=0x80;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=0x80;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -407,9 +401,9 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
speed.interleaveFactor=effectVal[k]&0xF;
|
||||
} else if ((effectVal[k]>>4)==(effectVal[k]&0xF)) {
|
||||
// if both speeds are equal
|
||||
pat->data[k][4+(l*2)]=0x0F;
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x0F;
|
||||
unsigned char speedSet=effectVal[k]>>4;
|
||||
pat->data[k][5+(l*2)]=speedSet;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=speedSet;
|
||||
break;
|
||||
} else {
|
||||
speed.speedEven=effectVal[k]>>4;
|
||||
|
|
@ -418,8 +412,8 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
|
||||
auto speedIndex = speeds.find(speed);
|
||||
if (speedIndex != speeds.end()) {
|
||||
pat->data[k][4+(l*2)]=0x09;
|
||||
pat->data[k][5+(l*2)]=speedIndex->second;
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x09;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=speedIndex->second;
|
||||
break;
|
||||
}
|
||||
if (speed.interleaveFactor>8) {
|
||||
|
|
@ -437,8 +431,8 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
info.ds->grooves.push_back(groove);
|
||||
speeds[speed]=speedGrooveIndex;
|
||||
|
||||
pat->data[k][4+(l*2)]=0x09;
|
||||
pat->data[k][5+(l*2)]=speedGrooveIndex;
|
||||
pat->newData[k][DIV_PAT_FX(l)]=0x09;
|
||||
pat->newData[k][DIV_PAT_FXVAL(l)]=speedGrooveIndex;
|
||||
speedGrooveIndex++;
|
||||
break;
|
||||
}
|
||||
|
|
@ -447,8 +441,8 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
|
||||
// put a "jump to next pattern" effect if the pattern is smaller than the maximum pattern length
|
||||
if (info.patLens[i]!=0 && info.patLens[i]<info.ds->subsong[0]->patLen) {
|
||||
pat->data[info.patLens[i]-1][4+(usedEffectsCol*4)]=0x0D;
|
||||
pat->data[info.patLens[i]-1][5+(usedEffectsCol*4)]=0x00;
|
||||
pat->newData[info.patLens[i]-1][DIV_PAT_FX(0)+(usedEffectsCol*4)]=0x0D;
|
||||
pat->newData[info.patLens[i]-1][DIV_PAT_FXVAL(0)+(usedEffectsCol*4)]=0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -473,28 +467,30 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
unsigned char truePatLen=(info.patLens[info.orderList[i]]<info.ds->subsong[0]->patLen) ? info.patLens[info.orderList[i]] : info.ds->subsong[0]->patLen;
|
||||
|
||||
// default instrument
|
||||
if (i==0 && pat->data[0][2]==-1) pat->data[0][2]=0;
|
||||
if (i==0 && pat->newData[0][DIV_PAT_INS]==-1) pat->newData[0][DIV_PAT_INS]=0;
|
||||
|
||||
for (int k=0; k<truePatLen; k++) {
|
||||
if (chArpeggio[j] && pat->data[k][4+(l*2)]!=0x00 && pat->data[k][0]!=-1) {
|
||||
pat->data[k][4+usedEffectsCol*2+(l*2)]=0x00;
|
||||
pat->data[k][5+usedEffectsCol*2+(l*2)]=0;
|
||||
// TODO: -1 check? does it still work after refactor?
|
||||
if (chArpeggio[j] && pat->newData[k][DIV_PAT_FX(l)]!=0x00 && pat->newData[k][DIV_PAT_NOTE]!=-1) {
|
||||
pat->newData[k][DIV_PAT_FX(usedEffectsCol)+(l*2)]=0x00;
|
||||
pat->newData[k][DIV_PAT_FXVAL(usedEffectsCol)+(l*2)]=0;
|
||||
chArpeggio[j]=false;
|
||||
} else if (chPorta[j] && pat->data[k][4+(l*2)]!=0x03 && pat->data[k][4+(l*2)]!=0x01 && pat->data[k][4+(l*2)]!=0x02) {
|
||||
pat->data[k][4+usedEffectsCol*2+(l*2)]=0x03;
|
||||
pat->data[k][5+usedEffectsCol*2+(l*2)]=0;
|
||||
} else if (chPorta[j] && pat->newData[k][DIV_PAT_FX(l)]!=0x03 && pat->newData[k][DIV_PAT_FX(l)]!=0x01 && pat->newData[k][DIV_PAT_FX(l)]!=0x02) {
|
||||
pat->newData[k][DIV_PAT_FX(usedEffectsCol)+(l*2)]=0x03;
|
||||
pat->newData[k][DIV_PAT_FXVAL(usedEffectsCol)+(l*2)]=0;
|
||||
chPorta[j]=false;
|
||||
} else if (chVibrato[j] && pat->data[k][4+(l*2)]!=0x04 && pat->data[k][0]!=-1) {
|
||||
pat->data[k][4+usedEffectsCol*2+(l*2)]=0x04;
|
||||
pat->data[k][5+usedEffectsCol*2+(l*2)]=0;
|
||||
} else if (chVibrato[j] && pat->newData[k][DIV_PAT_FX(l)]!=0x04 && pat->newData[k][DIV_PAT_NOTE]!=-1) {
|
||||
pat->newData[k][DIV_PAT_FX(usedEffectsCol)+(l*2)]=0x04;
|
||||
pat->newData[k][DIV_PAT_FXVAL(usedEffectsCol)+(l*2)]=0;
|
||||
chVibrato[j]=false;
|
||||
} else if (chVolumeSlide[j] && pat->data[k][4+(l*2)]!=0x0A) {
|
||||
pat->data[k][4+usedEffectsCol*2+(l*2)]=0x0A;
|
||||
pat->data[k][5+usedEffectsCol*2+(l*2)]=0;
|
||||
} else if (chVolumeSlide[j] && pat->newData[k][DIV_PAT_FX(l)]!=0x0A) {
|
||||
pat->newData[k][DIV_PAT_FX(usedEffectsCol)+(l*2)]=0x0A;
|
||||
pat->newData[k][DIV_PAT_FXVAL(usedEffectsCol)+(l*2)]=0;
|
||||
chVolumeSlide[j]=false;
|
||||
}
|
||||
|
||||
switch (pat->data[k][4+l]) {
|
||||
// TODO: looks like we have a bug here! it should be DIV_PAT_FX(l), right?
|
||||
switch (pat->newData[k][DIV_PAT_FX(0)+l]) {
|
||||
case 0:
|
||||
chArpeggio[j]=true;
|
||||
break;
|
||||
|
|
@ -527,16 +523,16 @@ void TFMParsePattern(struct TFMParsePatternInfo info) {
|
|||
lastPat->copyOn(newPat);
|
||||
|
||||
info.ds->subsong[0]->orders.ord[i][info.ds->subsong[0]->ordersLen - 1] = info.maxPat;
|
||||
newPat->data[info.patLens[lastPatNum]-1][4+(usedEffectsCol*4)] = 0x0B;
|
||||
newPat->data[info.patLens[lastPatNum]-1][5+(usedEffectsCol*4)] = info.loopPos;
|
||||
newPat->newData[info.patLens[lastPatNum]-1][DIV_PAT_FX(usedEffectsCol*2)] = 0x0B;
|
||||
newPat->newData[info.patLens[lastPatNum]-1][DIV_PAT_FXVAL(usedEffectsCol*2)] = info.loopPos;
|
||||
info.ds->subsong[0]->pat[i].data[info.maxPat] = newPat;
|
||||
}
|
||||
} else {
|
||||
for (int i=0;i<6;i++) {
|
||||
int lastPatNum=info.ds->subsong[0]->orders.ord[i][info.ds->subsong[0]->ordersLen - 1];
|
||||
DivPattern* lastPat=info.ds->subsong[0]->pat[i].getPattern(lastPatNum, false);
|
||||
lastPat->data[info.patLens[lastPatNum]-1][4+(usedEffectsCol*4)] = 0x0B;
|
||||
lastPat->data[info.patLens[lastPatNum]-1][5+(usedEffectsCol*4)] = info.loopPos;
|
||||
lastPat->newData[info.patLens[lastPatNum]-1][DIV_PAT_FX(usedEffectsCol*2)] = 0x0B;
|
||||
lastPat->newData[info.patLens[lastPatNum]-1][DIV_PAT_FXVAL(usedEffectsCol*2)] = info.loopPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -786,7 +786,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
|
||||
bool mustCommitInitial=true;
|
||||
|
||||
memset(effectCol,4,128);
|
||||
memset(effectCol,0,128);
|
||||
memset(vibStatus,0,128);
|
||||
memset(vibStatusChanged,0,128*sizeof(bool));
|
||||
memset(vibing,0,128*sizeof(bool));
|
||||
|
|
@ -901,32 +901,26 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
if (note!=0) {
|
||||
lastNote[k]=note;
|
||||
if (note>96) {
|
||||
p->data[j][0]=101;
|
||||
p->data[j][1]=0;
|
||||
p->newData[j][DIV_PAT_NOTE]=DIV_NOTE_REL;
|
||||
} else {
|
||||
note--;
|
||||
p->data[j][0]=note%12;
|
||||
p->data[j][1]=note/12;
|
||||
if (p->data[j][0]==0) {
|
||||
p->data[j][0]=12;
|
||||
p->data[j][1]=(unsigned char)(p->data[j][1]-1);
|
||||
}
|
||||
p->newData[j][DIV_PAT_NOTE]=note+60;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasIns) {
|
||||
ins=reader.readC();
|
||||
p->data[j][2]=((int)ins)-1;
|
||||
p->newData[j][DIV_PAT_INS]=((int)ins)-1;
|
||||
// default volume
|
||||
if (lastNote[k]<96 && ins>0) {
|
||||
p->data[j][3]=sampleVol[(((ins-1)&255)<<8)|(noteMap[(((ins-1)&255)<<7)|(lastNote[k]&127)])];
|
||||
p->newData[j][DIV_PAT_VOL]=sampleVol[(((ins-1)&255)<<8)|(noteMap[(((ins-1)&255)<<7)|(lastNote[k]&127)])];
|
||||
}
|
||||
writePanning=true;
|
||||
}
|
||||
if (hasVol) {
|
||||
vol=reader.readC();
|
||||
if (vol>=0x10 && vol<=0x50) {
|
||||
p->data[j][3]=vol-0x10;
|
||||
p->newData[j][DIV_PAT_VOL]=vol-0x10;
|
||||
} else { // effects in volume column
|
||||
switch (vol>>4) {
|
||||
case 0x6: // vol slide down
|
||||
|
|
@ -986,11 +980,11 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
vibing[k]=true;
|
||||
break;
|
||||
case 0xc: // panning
|
||||
p->data[j][effectCol[k]++]=0x80;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x80;
|
||||
if ((vol&15)==8) {
|
||||
p->data[j][effectCol[k]++]=0x80;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x80;
|
||||
} else {
|
||||
p->data[j][effectCol[k]++]=(vol&15)|((vol&15)<<4);
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=(vol&15)|((vol&15)<<4);
|
||||
}
|
||||
writePanning=false;
|
||||
break;
|
||||
|
|
@ -1113,14 +1107,14 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
treming[k]=true;
|
||||
break;
|
||||
case 8: // panning
|
||||
p->data[j][effectCol[k]++]=0x80;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x80;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
writePanning=false;
|
||||
break;
|
||||
case 9: // offset
|
||||
if (hasNote) {
|
||||
p->data[j][effectCol[k]++]=0x91;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x91;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
}
|
||||
break;
|
||||
case 0xa: // vol slide
|
||||
|
|
@ -1134,15 +1128,15 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
volSliding[k]=true;
|
||||
break;
|
||||
case 0xb: // go to order
|
||||
p->data[j][effectCol[k]++]=0x0b;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x0b;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
break;
|
||||
case 0xc: // set volume
|
||||
p->data[j][3]=effectVal;
|
||||
p->newData[j][DIV_PAT_VOL]=effectVal;
|
||||
break;
|
||||
case 0xd: // next order
|
||||
p->data[j][effectCol[k]++]=0x0d;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x0d;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
break;
|
||||
case 0xe: // special...
|
||||
// TODO: implement the rest
|
||||
|
|
@ -1150,27 +1144,27 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
case 0x4: // vibrato waveform
|
||||
switch (effectVal&3) {
|
||||
case 0x0: // sine
|
||||
p->data[j][effectCol[k]++]=0xe3;
|
||||
p->data[j][effectCol[k]++]=0x00;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xe3;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x00;
|
||||
break;
|
||||
case 0x1: // ramp down
|
||||
p->data[j][effectCol[k]++]=0xe3;
|
||||
p->data[j][effectCol[k]++]=0x05;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xe3;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x05;
|
||||
break;
|
||||
case 0x2: // square
|
||||
case 0x3:
|
||||
p->data[j][effectCol[k]++]=0xe3;
|
||||
p->data[j][effectCol[k]++]=0x06;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xe3;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x06;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x5: // fine tune
|
||||
p->data[j][effectCol[k]++]=0xe5;
|
||||
p->data[j][effectCol[k]++]=(effectVal&15)<<4;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xe5;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=(effectVal&15)<<4;
|
||||
break;
|
||||
case 0x9: // retrigger
|
||||
p->data[j][effectCol[k]++]=0x0c;
|
||||
p->data[j][effectCol[k]++]=(effectVal&15);
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x0c;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=(effectVal&15);
|
||||
break;
|
||||
case 0xa: // vol slide up (fine)
|
||||
volSlideStatus[k]=((effectVal&15)<<4)|0xf;
|
||||
|
|
@ -1189,32 +1183,32 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
volSliding[k]=true;
|
||||
break;
|
||||
case 0xc: // note cut
|
||||
p->data[j][effectCol[k]++]=0xdc;
|
||||
p->data[j][effectCol[k]++]=MAX(1,effectVal&15);
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xdc;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=MAX(1,effectVal&15);
|
||||
break;
|
||||
case 0xd: // note delay
|
||||
p->data[j][effectCol[k]++]=0xed;
|
||||
p->data[j][effectCol[k]++]=MAX(1,effectVal&15);
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xed;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=MAX(1,effectVal&15);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xf: // speed/tempo
|
||||
if (effectVal>=0x20) {
|
||||
p->data[j][effectCol[k]++]=0xf0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xf0;
|
||||
} else if (effectVal==0) {
|
||||
p->data[j][effectCol[k]++]=0xff;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xff;
|
||||
} else {
|
||||
p->data[j][effectCol[k]++]=0x0f;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x0f;
|
||||
}
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
break;
|
||||
case 0x10: // G: global volume (!)
|
||||
break;
|
||||
case 0x11: // H: global volume slide (!)
|
||||
break;
|
||||
case 0x14: // K: key off
|
||||
p->data[j][effectCol[k]++]=0xe7;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xe7;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
break;
|
||||
case 0x15: // L: set envelope position (!)
|
||||
break;
|
||||
|
|
@ -1226,8 +1220,8 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
panSliding[k]=true;
|
||||
break;
|
||||
case 0x1b: // R: retrigger
|
||||
p->data[j][effectCol[k]++]=0x0c;
|
||||
p->data[j][effectCol[k]++]=effectVal;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x0c;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=effectVal;
|
||||
break;
|
||||
case 0x1d: // T: tremor (!)
|
||||
break;
|
||||
|
|
@ -1244,8 +1238,8 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
}
|
||||
|
||||
if (writePanning && hasNote && note<96 && ins>0) {
|
||||
p->data[j][effectCol[k]++]=0x80;
|
||||
p->data[j][effectCol[k]++]=samplePan[(((ins-1)&255)<<8)|(noteMap[(((ins-1)&255)<<7)|(note&127)])];
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x80;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=samplePan[(((ins-1)&255)<<8)|(noteMap[(((ins-1)&255)<<7)|(note&127)])];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1253,80 +1247,80 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
for (int k=0; k<totalChans; k++) {
|
||||
DivPattern* p=ds.subsong[0]->pat[k].getPattern(i,true);
|
||||
if (vibing[k]!=vibingOld[k] || vibStatusChanged[k]) {
|
||||
p->data[j][effectCol[k]++]=0x04;
|
||||
p->data[j][effectCol[k]++]=vibing[k]?vibStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x04;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=vibing[k]?vibStatus[k]:0;
|
||||
doesVibrato[k]=true;
|
||||
} else if (doesVibrato[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0x04;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x04;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if (volSliding[k]!=volSlidingOld[k] || volSlideStatusChanged[k]) {
|
||||
if (volSlideStatus[k]>=0xf1 && volSliding[k]) {
|
||||
p->data[j][effectCol[k]++]=0xf9;
|
||||
p->data[j][effectCol[k]++]=volSlideStatus[k]&15;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xf9;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=volSlideStatus[k]&15;
|
||||
volSliding[k]=false;
|
||||
} else if ((volSlideStatus[k]&15)==15 && volSlideStatus[k]>=0x10 && volSliding[k]) {
|
||||
p->data[j][effectCol[k]++]=0xf8;
|
||||
p->data[j][effectCol[k]++]=volSlideStatus[k]>>4;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xf8;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=volSlideStatus[k]>>4;
|
||||
volSliding[k]=false;
|
||||
} else {
|
||||
p->data[j][effectCol[k]++]=0xfa;
|
||||
p->data[j][effectCol[k]++]=volSliding[k]?volSlideStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xfa;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=volSliding[k]?volSlideStatus[k]:0;
|
||||
}
|
||||
doesVolSlide[k]=true;
|
||||
} else if (doesVolSlide[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0xfa;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0xfa;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if (porting[k]!=portingOld[k] || portaStatusChanged[k]) {
|
||||
p->data[j][effectCol[k]++]=portaType[k];
|
||||
p->data[j][effectCol[k]++]=porting[k]?portaStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=portaType[k];
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=porting[k]?portaStatus[k]:0;
|
||||
doesPitchSlide[k]=true;
|
||||
} else if (doesPitchSlide[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0x01;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x01;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if (arping[k]!=arpingOld[k] || arpStatusChanged[k]) {
|
||||
p->data[j][effectCol[k]++]=0x00;
|
||||
p->data[j][effectCol[k]++]=arping[k]?arpStatus[k]:0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x00;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=arping[k]?arpStatus[k]:0;
|
||||
doesArp[k]=true;
|
||||
} else if (doesArp[k] && mustCommitInitial) {
|
||||
p->data[j][effectCol[k]++]=0x00;
|
||||
p->data[j][effectCol[k]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x00;
|
||||
p->newData[j][DIV_PAT_FX(0)+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;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x07;
|
||||
p->newData[j][DIV_PAT_FX(0)+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;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x07;
|
||||
p->newData[j][DIV_PAT_FX(0)+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;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x84;
|
||||
p->newData[j][DIV_PAT_FX(0)+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;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x84;
|
||||
p->newData[j][DIV_PAT_FX(0)+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;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x83;
|
||||
p->newData[j][DIV_PAT_FX(0)+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;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0x83;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[k]++]=0;
|
||||
}
|
||||
|
||||
if ((effectCol[k]>>1)-2>ds.subsong[0]->pat[k].effectCols) {
|
||||
ds.subsong[0]->pat[k].effectCols=(effectCol[k]>>1)-1;
|
||||
if ((effectCol[k]>>1)>=ds.subsong[0]->pat[k].effectCols) {
|
||||
ds.subsong[0]->pat[k].effectCols=(effectCol[k]>>1)+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1346,14 +1340,14 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) {
|
|||
if (j==totalRows-1) {
|
||||
// place end of pattern marker
|
||||
DivPattern* p=ds.subsong[0]->pat[0].getPattern(i,true);
|
||||
p->data[j][effectCol[0]++]=0x0d;
|
||||
p->data[j][effectCol[0]++]=0;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[0]++]=0x0d;
|
||||
p->newData[j][DIV_PAT_FX(0)+effectCol[0]++]=0;
|
||||
|
||||
if ((effectCol[0]>>1)-2>ds.subsong[0]->pat[0].effectCols) {
|
||||
ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)-1;
|
||||
if ((effectCol[0]>>1)>=ds.subsong[0]->pat[0].effectCols) {
|
||||
ds.subsong[0]->pat[0].effectCols=(effectCol[0]>>1)+1;
|
||||
}
|
||||
}
|
||||
memset(effectCol,4,64);
|
||||
memset(effectCol,0,64);
|
||||
}
|
||||
|
||||
logV("seeking to %x...",packedSeek);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ std::vector<std::pair<int,int>> DivChannelData::optimize() {
|
|||
for (int j=0; j<DIV_MAX_PATTERNS; j++) {
|
||||
if (j==i) continue;
|
||||
if (data[j]==NULL) continue;
|
||||
if (memcmp(data[i]->data,data[j]->data,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short))==0) {
|
||||
if (memcmp(data[i]->newData,data[j]->newData,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short))==0) {
|
||||
delete data[j];
|
||||
data[j]=NULL;
|
||||
logV("%d == %d",i,j);
|
||||
|
|
@ -86,15 +86,11 @@ void DivChannelData::wipePatterns() {
|
|||
|
||||
void DivPattern::copyOn(DivPattern* dest) {
|
||||
dest->name=name;
|
||||
memcpy(dest->data,data,sizeof(data));
|
||||
memcpy(dest->newData,newData,sizeof(newData));
|
||||
}
|
||||
|
||||
void DivPattern::clear() {
|
||||
memset(data,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
for (int i=0; i<DIV_MAX_ROWS; i++) {
|
||||
data[i][0]=0;
|
||||
data[i][1]=0;
|
||||
}
|
||||
memset(newData,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short));
|
||||
}
|
||||
|
||||
DivChannelData::DivChannelData():
|
||||
|
|
|
|||
|
|
@ -22,7 +22,22 @@
|
|||
|
||||
struct DivPattern {
|
||||
String name;
|
||||
short data[DIV_MAX_ROWS][DIV_MAX_COLS];
|
||||
/**
|
||||
* pattern data is stored in this order:
|
||||
* - 0 note: 0 (min) is C-(-5), 60 is C-0, and 179 (max) is B-9.
|
||||
252 is null/bug, 253 is note off, 254 is note release and
|
||||
255 is macro release.
|
||||
* - 1 instrument
|
||||
* - 2 volume
|
||||
* - 3 effect
|
||||
* - 4 effect value
|
||||
* - 5... (the rest of effects/effect values)
|
||||
*
|
||||
* use the DIV_PAT_* macros in defines.h for convenience.
|
||||
*
|
||||
* if a cell is -1, it means "empty".
|
||||
*/
|
||||
short newData[DIV_MAX_ROWS][DIV_MAX_COLS];
|
||||
|
||||
/**
|
||||
* clear the pattern.
|
||||
|
|
@ -39,14 +54,10 @@ struct DivPattern {
|
|||
|
||||
struct DivChannelData {
|
||||
unsigned char effectCols;
|
||||
// data goes as follows: data[ROW][TYPE]
|
||||
// TYPE is:
|
||||
// 0: note
|
||||
// 1: octave
|
||||
// 2: instrument
|
||||
// 3: volume
|
||||
// 4-5+: effect/effect value
|
||||
// do NOT access directly unless you know what you're doing!
|
||||
/**
|
||||
* do NOT access directly unless you know what you're doing!
|
||||
* use getPattern() instead.
|
||||
*/
|
||||
DivPattern* data[DIV_MAX_PATTERNS];
|
||||
|
||||
/**
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -543,7 +543,11 @@ bool DivSample::saveRaw(const char* path) {
|
|||
}
|
||||
|
||||
// 16-bit memory is padded to 512, to make things easier for ADPCM-A/B.
|
||||
bool DivSample::initInternal(DivSampleDepth d, unsigned int count) {
|
||||
bool DivSample::initInternal(DivSampleDepth d, int count) {
|
||||
if (count<0) {
|
||||
logE("initInternal(%d,%d) - NEGATIVE!",(int)d,count);
|
||||
return false;
|
||||
}
|
||||
logV("initInternal(%d,%d)",(int)d,count);
|
||||
switch (d) {
|
||||
case DIV_SAMPLE_DEPTH_1BIT: // 1-bit
|
||||
|
|
@ -650,8 +654,11 @@ bool DivSample::initInternal(DivSampleDepth d, unsigned int count) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DivSample::init(unsigned int count) {
|
||||
if (count>16777215) return false;
|
||||
bool DivSample::init(int count) {
|
||||
if (count<0 || count>16777215) {
|
||||
logE("tried to init sample with length %d!",count);
|
||||
return false;
|
||||
}
|
||||
if (!initInternal(depth,count)) return false;
|
||||
setSampleCount(count);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -236,14 +236,14 @@ struct DivSample {
|
|||
* @param count number of samples.
|
||||
* @return whether it was successful.
|
||||
*/
|
||||
bool initInternal(DivSampleDepth d, unsigned int count);
|
||||
bool initInternal(DivSampleDepth d, int count);
|
||||
|
||||
/**
|
||||
* initialize sample data. make sure you have set `depth` before doing so.
|
||||
* @param count number of samples.
|
||||
* @return whether it was successful.
|
||||
*/
|
||||
bool init(unsigned int count);
|
||||
bool init(int count);
|
||||
|
||||
/**
|
||||
* resize sample data. make sure the sample has been initialized before doing so.
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ bool DivSubSong::walk(int& loopOrder, int& loopRow, int& loopEnd, int chans, int
|
|||
}
|
||||
for (int k=0; k<chans; k++) {
|
||||
for (int l=0; l<pat[k].effectCols; l++) {
|
||||
effectVal=subPat[k]->data[j][5+(l<<1)];
|
||||
effectVal=subPat[k]->newData[j][DIV_PAT_FXVAL(l)];
|
||||
if (effectVal<0) effectVal=0;
|
||||
if (subPat[k]->data[j][4+(l<<1)]==0x0d) {
|
||||
if (subPat[k]->newData[j][DIV_PAT_FX(l)]==0x0d) {
|
||||
if (jumpTreatment==2) {
|
||||
if ((i<ordersLen-1 || !ignoreJumpAtEnd)) {
|
||||
nextOrder=i+1;
|
||||
|
|
@ -78,7 +78,7 @@ bool DivSubSong::walk(int& loopOrder, int& loopRow, int& loopEnd, int chans, int
|
|||
nextRow=effectVal;
|
||||
}
|
||||
}
|
||||
} else if (subPat[k]->data[j][4+(l<<1)]==0x0b) {
|
||||
} else if (subPat[k]->newData[j][DIV_PAT_FX(l)]==0x0b) {
|
||||
if (nextOrder==-1 || jumpTreatment==0) {
|
||||
nextOrder=effectVal;
|
||||
if (jumpTreatment==1 || jumpTreatment==2 || !jumpingOrder) {
|
||||
|
|
@ -160,10 +160,10 @@ void DivSubSong::findLength(int loopOrder, int loopRow, double fadeoutLen, int&
|
|||
}
|
||||
for (int k=0; k<chans; k++) {
|
||||
for (int l=0; l<pat[k].effectCols; l++) {
|
||||
effectVal=subPat[k]->data[j][5+(l<<1)];
|
||||
effectVal=subPat[k]->newData[j][DIV_PAT_FXVAL(l)];
|
||||
if (effectVal<0) effectVal=0;
|
||||
|
||||
if (subPat[k]->data[j][4+(l<<1)]==0xff) {
|
||||
if (subPat[k]->newData[j][DIV_PAT_FX(l)]==0xff) {
|
||||
hasFFxx=true;
|
||||
|
||||
// FFxx makes YOU SHALL NOT PASS!!! move
|
||||
|
|
@ -173,7 +173,7 @@ void DivSubSong::findLength(int loopOrder, int loopRow, double fadeoutLen, int&
|
|||
return;
|
||||
}
|
||||
|
||||
switch (subPat[k]->data[j][4+(l<<1)]) {
|
||||
switch (subPat[k]->newData[j][DIV_PAT_FX(l)]) {
|
||||
case 0x09: { // select groove pattern/speed 1
|
||||
if (grooves.empty()) {
|
||||
if (effectVal>0) curSpeeds.val[0]=effectVal;
|
||||
|
|
@ -208,7 +208,7 @@ void DivSubSong::findLength(int loopOrder, int loopRow, double fadeoutLen, int&
|
|||
}
|
||||
}
|
||||
|
||||
if (subPat[k]->data[j][4+(l<<1)]==0x0d) {
|
||||
if (subPat[k]->newData[j][DIV_PAT_FX(l)]==0x0d) {
|
||||
if (jumpTreatment==2) {
|
||||
if ((i<ordersLen-1 || !ignoreJumpAtEnd)) {
|
||||
nextOrder=i+1;
|
||||
|
|
@ -230,7 +230,7 @@ void DivSubSong::findLength(int loopOrder, int loopRow, double fadeoutLen, int&
|
|||
nextRow=effectVal;
|
||||
}
|
||||
}
|
||||
} else if (subPat[k]->data[j][4+(l<<1)]==0x0b) {
|
||||
} else if (subPat[k]->newData[j][DIV_PAT_FX(l)]==0x0b) {
|
||||
if (nextOrder==-1 || jumpTreatment==0) {
|
||||
nextOrder=effectVal;
|
||||
if (jumpTreatment==1 || jumpTreatment==2 || !jumpingOrder) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue