allow saving patterns in old format

This commit is contained in:
tildearrow 2023-05-26 01:29:49 -05:00
parent c3ccd74a15
commit 4947d02c68
5 changed files with 120 additions and 110 deletions

View file

@ -591,7 +591,7 @@ class DivEngine {
SafeWriter* saveDMF(unsigned char version); SafeWriter* saveDMF(unsigned char version);
// save as .fur. // save as .fur.
// if notPrimary is true then the song will not be altered // if notPrimary is true then the song will not be altered
SafeWriter* saveFur(bool notPrimary=false); SafeWriter* saveFur(bool notPrimary=false, bool newPatternFormat=true);
// build a ROM file (TODO). // build a ROM file (TODO).
// specify system to build ROM for. // specify system to build ROM for.
std::vector<DivROMExportOutput> buildROM(DivROMExportOptions sys); std::vector<DivROMExportOutput> buildROM(DivROMExportOptions sys);

View file

@ -5077,9 +5077,7 @@ DivDataErrors DivEngine::readAssetDirData(SafeReader& reader, std::vector<DivAss
return DIV_DATA_SUCCESS; return DIV_DATA_SUCCESS;
} }
#define NEW_PATTERN_FORMAT SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) {
SafeWriter* DivEngine::saveFur(bool notPrimary) {
saveLock.lock(); saveLock.lock();
std::vector<int> subSongPtr; std::vector<int> subSongPtr;
std::vector<int> sysFlagsPtr; std::vector<int> sysFlagsPtr;
@ -5514,132 +5512,132 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
DivPattern* pat=song.subsong[i.subsong]->pat[i.chan].getPattern(i.pat,false); DivPattern* pat=song.subsong[i.subsong]->pat[i.chan].getPattern(i.pat,false);
patPtr.push_back(w->tell()); patPtr.push_back(w->tell());
#ifdef NEW_PATTERN_FORMAT if (newPatternFormat) {
w->write("PATN",4); w->write("PATN",4);
blockStartSeek=w->tell(); blockStartSeek=w->tell();
w->writeI(0); w->writeI(0);
w->writeC(i.subsong); w->writeC(i.subsong);
w->writeC(i.chan); w->writeC(i.chan);
w->writeS(i.pat); w->writeS(i.pat);
w->writeString(pat->name,false); w->writeString(pat->name,false);
unsigned char emptyRows=0; unsigned char emptyRows=0;
for (int j=0; j<song.subsong[i.subsong]->patLen; j++) { for (int j=0; j<song.subsong[i.subsong]->patLen; j++) {
unsigned char mask=0; unsigned char mask=0;
unsigned char finalNote=255; unsigned char finalNote=255;
unsigned short effectMask=0; unsigned short effectMask=0;
if (pat->data[j][0]==100) { if (pat->data[j][0]==100) {
finalNote=180; finalNote=180;
} else if (pat->data[j][0]==101) { // note release } else if (pat->data[j][0]==101) { // note release
finalNote=181; finalNote=181;
} else if (pat->data[j][0]==102) { // macro release } else if (pat->data[j][0]==102) { // macro release
finalNote=182; finalNote=182;
} else if (pat->data[j][1]==0 && pat->data[j][0]==0) { } 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; finalNote=255;
} else { } else {
finalNote=seek; 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 (finalNote!=255) mask|=1; // note
if (pat->data[j][2]!=-1) mask|=2; // instrument if (pat->data[j][2]!=-1) mask|=2; // instrument
if (pat->data[j][3]!=-1) mask|=4; // volume 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) { for (int k=0; k<song.subsong[i.subsong]->pat[i.chan].effectCols*2; k+=2) {
if (k==0) { if (k==0) {
if (pat->data[j][4+k]!=-1) mask|=8; if (pat->data[j][4+k]!=-1) mask|=8;
if (pat->data[j][5+k]!=-1) mask|=16; if (pat->data[j][5+k]!=-1) mask|=16;
} else if (k<8) { } else if (k<8) {
if (pat->data[j][4+k]!=-1 || pat->data[j][5+k]!=-1) mask|=32; 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 { } else {
if (pat->data[j][4+k]!=-1 || pat->data[j][5+k]!=-1) mask|=64; if (emptyRows>1) {
} w->writeC(128|(emptyRows-2));
emptyRows=0;
} else if (emptyRows) {
w->writeC(0);
emptyRows=0;
}
if (pat->data[j][4+k]!=-1) effectMask|=(1<<k); w->writeC(mask);
if (pat->data[j][5+k]!=-1) effectMask|=(2<<k);
}
if (mask==0) { if (mask&32) w->writeC(effectMask&0xff);
emptyRows++; if (mask&64) w->writeC((effectMask>>8)&0xff);
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&1) w->writeC(finalNote);
if (mask&2) w->writeC(pat->data[j][2]);
if (mask&32) w->writeC(effectMask&0xff); if (mask&4) w->writeC(pat->data[j][3]);
if (mask&64) w->writeC((effectMask>>8)&0xff); if (mask&8) w->writeC(pat->data[j][4]);
if (mask&16) w->writeC(pat->data[j][5]);
if (mask&1) w->writeC(finalNote); if (mask&32) {
if (mask&2) w->writeC(pat->data[j][2]); if (effectMask&4) w->writeC(pat->data[j][6]);
if (mask&4) w->writeC(pat->data[j][3]); if (effectMask&8) w->writeC(pat->data[j][7]);
if (mask&8) w->writeC(pat->data[j][4]); if (effectMask&16) w->writeC(pat->data[j][8]);
if (mask&16) w->writeC(pat->data[j][5]); if (effectMask&32) w->writeC(pat->data[j][9]);
if (mask&32) { if (effectMask&64) w->writeC(pat->data[j][10]);
if (effectMask&4) w->writeC(pat->data[j][6]); if (effectMask&128) w->writeC(pat->data[j][11]);
if (effectMask&8) w->writeC(pat->data[j][7]); }
if (effectMask&16) w->writeC(pat->data[j][8]); if (mask&64) {
if (effectMask&32) w->writeC(pat->data[j][9]); if (effectMask&256) w->writeC(pat->data[j][12]);
if (effectMask&64) w->writeC(pat->data[j][10]); if (effectMask&512) w->writeC(pat->data[j][13]);
if (effectMask&128) w->writeC(pat->data[j][11]); if (effectMask&1024) w->writeC(pat->data[j][14]);
} if (effectMask&2048) w->writeC(pat->data[j][15]);
if (mask&64) { if (effectMask&4096) w->writeC(pat->data[j][16]);
if (effectMask&256) w->writeC(pat->data[j][12]); if (effectMask&8192) w->writeC(pat->data[j][17]);
if (effectMask&512) w->writeC(pat->data[j][13]); if (effectMask&16384) w->writeC(pat->data[j][18]);
if (effectMask&1024) w->writeC(pat->data[j][14]); if (effectMask&32768) w->writeC(pat->data[j][19]);
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]);
} }
} }
}
// stop // stop
w->writeC(0xff); w->writeC(0xff);
#else } else {
w->write("PATR",4); w->write("PATR",4);
blockStartSeek=w->tell(); blockStartSeek=w->tell();
w->writeI(0); w->writeI(0);
w->writeS(i.chan); w->writeS(i.chan);
w->writeS(i.pat); w->writeS(i.pat);
w->writeS(i.subsong); w->writeS(i.subsong);
w->writeS(0); // reserved w->writeS(0); // reserved
for (int j=0; j<song.subsong[i.subsong]->patLen; j++) { for (int j=0; j<song.subsong[i.subsong]->patLen; j++) {
w->writeS(pat->data[j][0]); // note w->writeS(pat->data[j][0]); // note
w->writeS(pat->data[j][1]); // octave w->writeS(pat->data[j][1]); // octave
w->writeS(pat->data[j][2]); // instrument w->writeS(pat->data[j][2]); // instrument
w->writeS(pat->data[j][3]); // volume w->writeS(pat->data[j][3]); // volume
#ifdef TA_BIG_ENDIAN #ifdef TA_BIG_ENDIAN
for (int k=0; k<song.subsong[i.subsong]->pat[i.chan].effectCols*2; k++) { for (int k=0; k<song.subsong[i.subsong]->pat[i.chan].effectCols*2; k++) {
w->writeS(pat->data[j][4+k]); w->writeS(pat->data[j][4+k]);
} }
#else #else
w->write(&pat->data[j][4],2*song.subsong[i.subsong]->pat[i.chan].effectCols*2); // effects w->write(&pat->data[j][4],2*song.subsong[i.subsong]->pat[i.chan].effectCols*2); // effects
#endif #endif
} }
w->writeString(pat->name,false); w->writeString(pat->name,false);
#endif }
blockEndSeek=w->tell(); blockEndSeek=w->tell();
w->seek(blockStartSeek,SEEK_SET); w->seek(blockStartSeek,SEEK_SET);

View file

@ -1975,7 +1975,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
if (dmfVersion<24) dmfVersion=24; if (dmfVersion<24) dmfVersion=24;
w=e->saveDMF(dmfVersion); w=e->saveDMF(dmfVersion);
} else { } else {
w=e->saveFur(); w=e->saveFur(false,settings.newPatternFormat);
} }
if (w==NULL) { if (w==NULL) {
lastError=e->getLastError(); lastError=e->getLastError();
@ -5674,7 +5674,7 @@ bool FurnaceGUI::loop() {
} }
} }
logD("saving backup..."); logD("saving backup...");
SafeWriter* w=e->saveFur(true); SafeWriter* w=e->saveFur(true,true);
logV("writing file..."); logV("writing file...");
if (w!=NULL) { if (w!=NULL) {

View file

@ -1425,6 +1425,7 @@ class FurnaceGUI {
int iCannotWait; int iCannotWait;
int orderButtonPos; int orderButtonPos;
int compress; int compress;
int newPatternFormat;
unsigned int maxUndoSteps; unsigned int maxUndoSteps;
String mainFontPath; String mainFontPath;
String patFontPath; String patFontPath;
@ -1571,6 +1572,7 @@ class FurnaceGUI {
iCannotWait(0), iCannotWait(0),
orderButtonPos(2), orderButtonPos(2),
compress(1), compress(1),
newPatternFormat(1),
maxUndoSteps(100), maxUndoSteps(100),
mainFontPath(""), mainFontPath(""),
patFontPath(""), patFontPath(""),

View file

@ -662,6 +662,13 @@ void FurnaceGUI::drawSettings() {
ImGui::SetTooltip("use zlib to compress saved songs."); ImGui::SetTooltip("use zlib to compress saved songs.");
} }
bool newPatternFormatB=settings.newPatternFormat;
if (ImGui::Checkbox("Use new pattern format when saving",&newPatternFormatB)) {
settings.newPatternFormat=newPatternFormatB;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("use a packed format which saves space when saving songs.\ndisable if you need compatibility with older Furnace and/or tools\nwhich do not support this format.");
}
bool cursorFollowsOrderB=settings.cursorFollowsOrder; bool cursorFollowsOrderB=settings.cursorFollowsOrder;
if (ImGui::Checkbox("Cursor follows current order when moving it",&cursorFollowsOrderB)) { if (ImGui::Checkbox("Cursor follows current order when moving it",&cursorFollowsOrderB)) {
@ -2683,6 +2690,7 @@ void FurnaceGUI::syncSettings() {
settings.iCannotWait=e->getConfInt("iCannotWait",0); settings.iCannotWait=e->getConfInt("iCannotWait",0);
settings.orderButtonPos=e->getConfInt("orderButtonPos",2); settings.orderButtonPos=e->getConfInt("orderButtonPos",2);
settings.compress=e->getConfInt("compress",1); settings.compress=e->getConfInt("compress",1);
settings.newPatternFormat=e->getConfInt("newPatternFormat",1);
clampSetting(settings.mainFontSize,2,96); clampSetting(settings.mainFontSize,2,96);
clampSetting(settings.patFontSize,2,96); clampSetting(settings.patFontSize,2,96);
@ -2804,6 +2812,7 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.iCannotWait,0,1); clampSetting(settings.iCannotWait,0,1);
clampSetting(settings.orderButtonPos,0,2); clampSetting(settings.orderButtonPos,0,2);
clampSetting(settings.compress,0,1); clampSetting(settings.compress,0,1);
clampSetting(settings.newPatternFormat,0,1);
if (settings.exportLoops<0.0) settings.exportLoops=0.0; if (settings.exportLoops<0.0) settings.exportLoops=0.0;
if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0; if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0;
@ -3020,6 +3029,7 @@ void FurnaceGUI::commitSettings() {
e->setConf("iCannotWait",settings.iCannotWait); e->setConf("iCannotWait",settings.iCannotWait);
e->setConf("orderButtonPos",settings.orderButtonPos); e->setConf("orderButtonPos",settings.orderButtonPos);
e->setConf("compress",settings.compress); e->setConf("compress",settings.compress);
e->setConf("newPatternFormat",settings.newPatternFormat);
// colors // colors
for (int i=0; i<GUI_COLOR_MAX; i++) { for (int i=0; i<GUI_COLOR_MAX; i++) {