pattern data refactor, part 1

this first stage changes the way notes are encoded
instead of note/octave, it is just note
This commit is contained in:
tildearrow 2025-10-14 05:07:35 -05:00
parent 7d7d95a97d
commit d4ecf4045b
10 changed files with 447 additions and 465 deletions

View file

@ -2293,6 +2293,63 @@ 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;
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);

View file

@ -721,7 +721,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.
@ -927,6 +927,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);

View file

@ -811,25 +811,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
octave--;
}
if (note==100) {
pat->newData[k][DIV_PAT_NOTE]=DIV_NOTE_OFF;
} else if (note==101) {
pat->newData[k][DIV_PAT_NOTE]=DIV_NOTE_REL;
} else if (note==102) {
pat->newData[k][DIV_PAT_NOTE]=DIV_MACRO_REL;
} else if (note==0 && octave!=0) {
// "BUG" note!
pat->newData[k][DIV_PAT_NOTE]=DIV_NOTE_NULL_PAT;
} else if (note==0 && octave==0) {
pat->newData[k][DIV_PAT_NOTE]=-1;
} else {
int seek=(note+(signed char)octave*12)+60;
if (seek<0 || seek>=180) {
pat->newData[k][DIV_PAT_NOTE]=DIV_NOTE_NULL_PAT;
} else {
pat->newData[k][DIV_PAT_NOTE]=seek;
}
}
pat->newData[k][DIV_PAT_NOTE]=splitNoteToNote(note,octave);
// volume
pat->newData[k][DIV_PAT_VOL]=reader.readS();
@ -844,7 +826,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
if (ds.version<0x12) {
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->newData[k][DIV_PAT_VOL]=(pat->data[k][DIV_PAT_VOL]&3)*5;
pat->newData[k][DIV_PAT_VOL]=(pat->newData[k][DIV_PAT_VOL]&3)*5;
}
}
for (int l=0; l<chan.effectCols; l++) {
@ -879,33 +861,35 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
}
}
} 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;
}
}
}
@ -1650,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) {
@ -1663,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
}
}
}

View file

@ -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]+60;
// 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]+60;
// 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];
}
}
}

View file

@ -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);
}
}
@ -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;
}
}
}

View file

@ -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(1)+k]!=-1) mask|=16;
} else if (k<8) {
if (pat->newData[j][DIV_PAT_FX(0)+k]!=-1 || pat->newData[j][DIV_PAT_FXVAL(1)+k]!=-1) mask|=32;
} else {
if (pat->newData[j][DIV_PAT_FX(0)+k]!=-1 || pat->newData[j][DIV_PAT_FXVAL(1)+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(1)+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);

View file

@ -1139,82 +1139,82 @@ 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) {
@ -1250,8 +1250,8 @@ 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;
@ -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;

View file

@ -185,21 +185,21 @@ 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;
// TODO: refactor test
dstrowN[DIV_PAT_NOTE]=note+60;
if (period<114) {
bypassLimits=true;
}
@ -207,8 +207,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 +256,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 +264,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 +293,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 +331,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 +387,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]);
}
}

View file

@ -811,82 +811,82 @@ 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) {

View file

@ -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():