1.1 .DMF saving

as of now you're given a choice between 1.1 and 1.0 module
This commit is contained in:
tildearrow 2022-02-20 03:18:20 -05:00
parent 2326c4250e
commit fa363384aa
6 changed files with 96 additions and 29 deletions

View File

@ -267,7 +267,7 @@ class DivEngine {
// load a file.
bool load(unsigned char* f, size_t length);
// save as .dmf.
SafeWriter* saveDMF();
SafeWriter* saveDMF(unsigned char version);
// save as .fur.
SafeWriter* saveFur();
// build a ROM file (TODO).

View File

@ -53,6 +53,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
ds.nullWave.data[i]=15;
}
ds.isDMF=true;
if (!reader.seek(16,SEEK_SET)) {
logE("premature end of file!\n");
lastError="incomplete file";
@ -724,6 +726,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (ds.version<50) {
ds.ignoreDuplicateSlides=false;
}
ds.isDMF=false;
reader.readS(); // reserved
int infoSeek=reader.readI();
@ -1148,6 +1151,9 @@ SafeWriter* DivEngine::saveFur() {
size_t ptrSeek;
warnings="";
song.isDMF=false;
song.version=DIV_ENGINE_VERSION;
SafeWriter* w=new SafeWriter;
w->init();
/// HEADER
@ -1375,19 +1381,34 @@ SafeWriter* DivEngine::saveFur() {
return w;
}
SafeWriter* DivEngine::saveDMF() {
// fail if more than one system
if (song.systemLen!=1) {
logE("cannot save multiple systems in this format!\n");
lastError="multiple systems not possible on .dmf";
SafeWriter* DivEngine::saveDMF(unsigned char version) {
// fail if version is not supported
if (version<24 || version>25) {
logE("cannot save in this version!\n");
lastError="invalid version to save in! this is a bug!";
return NULL;
}
// fail if more than one system
// TODO: fix this mess for the flattening in 0.6
if (!(song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL)) {
if (song.systemLen!=1) {
logE("cannot save multiple systems in this format!\n");
lastError="multiple systems not possible on .dmf";
return NULL;
}
}
// fail if this is an YMU759 song
if (song.system[0]==DIV_SYSTEM_YMU759) {
logE("cannot save YMU759 song!\n");
lastError="YMU759 song saving is not supported";
return NULL;
}
// fail if the system is SMS+OPLL and version<25
if (version<25 && song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL) {
logE("Master System FM expansion not supported in 1.0/legacy .dmf!\n");
lastError="Master System FM expansion not supported in 1.0/legacy .dmf!";
return NULL;
}
// fail if the system is Furnace-exclusive
if (systemToFile(song.system[0])&0x80) {
logE("cannot save Furnace-exclusive system song!\n");
@ -1395,14 +1416,23 @@ SafeWriter* DivEngine::saveDMF() {
return NULL;
}
warnings="";
song.version=version;
song.isDMF=true;
SafeWriter* w=new SafeWriter;
w->init();
// write magic
w->write(DIV_DMF_MAGIC,16);
// version
w->writeC(24);
w->writeC(systemToFile(song.system[0]));
w->writeC(version);
DivSystem sys=DIV_SYSTEM_NULL;
if (song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL) {
w->writeC(systemToFile(DIV_SYSTEM_SMS_OPLL));
sys=DIV_SYSTEM_SMS_OPLL;
} else {
w->writeC(systemToFile(song.system[0]));
sys=song.system[0];
}
// song info
w->writeString(song.name,true);
@ -1425,10 +1455,14 @@ SafeWriter* DivEngine::saveDMF() {
for (int i=0; i<chans; i++) {
for (int j=0; j<song.ordersLen; j++) {
w->writeC(song.orders.ord[i][j]);
if (version>=25) {
DivPattern* pat=song.pat[i].getPattern(j,false);
w->writeString(pat->name,true);
}
}
}
if (song.system[0]==DIV_SYSTEM_C64_6581 || song.system[0]==DIV_SYSTEM_C64_8580) {
if (sys==DIV_SYSTEM_C64_6581 || sys==DIV_SYSTEM_C64_8580) {
addWarning("absolute duty/cutoff macro not available in .dmf!");
addWarning("duty precision will be lost");
}
@ -1452,10 +1486,10 @@ SafeWriter* DivEngine::saveDMF() {
w->writeString(i->name,true);
// safety check
if (!isFMSystem(song.system[0]) && i->mode) {
if (!isFMSystem(sys) && i->mode) {
i->mode=0;
}
if (!isSTDSystem(song.system[0]) && i->mode==0) {
if (!isSTDSystem(sys) && i->mode==0) {
i->mode=1;
}
@ -1475,14 +1509,25 @@ SafeWriter* DivEngine::saveDMF() {
w->writeC(op.rr);
w->writeC(op.sl);
w->writeC(op.tl);
w->writeC(op.dt2);
w->writeC(op.rs);
w->writeC(op.dt);
w->writeC(op.d2r);
w->writeC(op.ssgEnv);
if (sys==DIV_SYSTEM_SMS_OPLL && j==0) {
w->writeC(i->fm.opllPreset);
} else {
w->writeC(op.dt2);
}
if (sys==DIV_SYSTEM_SMS_OPLL) {
w->writeC(op.ksr);
w->writeC(op.vib);
w->writeC(op.ksl);
w->writeC(op.ssgEnv);
} else {
w->writeC(op.rs);
w->writeC(op.dt);
w->writeC(op.d2r);
w->writeC(op.ssgEnv);
}
}
} else { // STD
if (song.system[0]!=DIV_SYSTEM_GB) {
if (sys!=DIV_SYSTEM_GB) {
w->writeC(i->std.volMacroLen);
w->write(i->std.volMacro,4*i->std.volMacroLen);
if (i->std.volMacroLen>0) {
@ -1515,7 +1560,7 @@ SafeWriter* DivEngine::saveDMF() {
w->writeC(i->std.waveMacroLoop);
}
if (song.system[0]==DIV_SYSTEM_C64_6581 || song.system[0]==DIV_SYSTEM_C64_8580) {
if (sys==DIV_SYSTEM_C64_6581 || sys==DIV_SYSTEM_C64_8580) {
w->writeC(i->c64.triOn);
w->writeC(i->c64.sawOn);
w->writeC(i->c64.pulseOn);
@ -1544,7 +1589,7 @@ SafeWriter* DivEngine::saveDMF() {
w->writeC(i->c64.ch3off);
}
if (song.system[0]==DIV_SYSTEM_GB) {
if (sys==DIV_SYSTEM_GB) {
w->writeC(i->gb.envVol);
w->writeC(i->gb.envDir);
w->writeC(i->gb.envLen);
@ -1559,7 +1604,7 @@ SafeWriter* DivEngine::saveDMF() {
w->write(i->data,4*i->len);
}
for (int i=0; i<getChannelCount(song.system[0]); i++) {
for (int i=0; i<getChannelCount(sys); i++) {
w->writeC(song.pat[i].effectRows);
for (int j=0; j<song.ordersLen; j++) {

View File

@ -140,6 +140,7 @@ struct DivSong {
// - basic format, no system number, 16 instruments, one speed, YMU759-only
// - if somebody manages to find a version 2 or even 1 module, please tell me as it will be worth more than a luxury vehicle
unsigned short version;
bool isDMF;
// system
DivSystem system[32];
@ -267,7 +268,8 @@ struct DivSong {
void unload();
DivSong():
version(24),
version(0),
isDMF(false),
systemLen(1),
name(""),
author(""),

View File

@ -650,6 +650,7 @@ const char* DivEngine::getSystemNameJ(DivSystem sys) {
bool DivEngine::isFMSystem(DivSystem sys) {
return (sys==DIV_SYSTEM_GENESIS ||
sys==DIV_SYSTEM_GENESIS_EXT ||
sys==DIV_SYSTEM_SMS_OPLL ||
sys==DIV_SYSTEM_ARCADE ||
sys==DIV_SYSTEM_YM2610 ||
sys==DIV_SYSTEM_YM2610_EXT ||

View File

@ -2892,7 +2892,7 @@ void FurnaceGUI::doAction(int what) {
if (curFileName=="") {
openFileDialog(GUI_FILE_SAVE);
} else {
if (save(curFileName)>0) {
if (save(curFileName,e->song.isDMF?e->song.version:0)>0) {
showError(fmt::sprintf("Error while saving file! (%s)",lastError));
}
}
@ -3809,7 +3809,10 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Open File","compatible files{.fur,.dmf},.*",workingDir);
break;
case GUI_FILE_SAVE:
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Save File","Furnace song{.fur},DefleMask module{.dmf}",workingDir,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite);
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Save File","Furnace song{.fur},DefleMask 1.1 module{.dmf}",workingDir,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite);
break;
case GUI_FILE_SAVE_DMF_LEGACY:
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Save File","DefleMask 1.0/legacy module{.dmf}",workingDir,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite);
break;
case GUI_FILE_INS_OPEN:
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Load Instrument","compatible files{.fui,.dmp},.*",workingDir);
@ -3857,10 +3860,10 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
#define FURNACE_ZLIB_COMPRESS
int FurnaceGUI::save(String path) {
int FurnaceGUI::save(String path, int dmfVersion) {
SafeWriter* w;
if (path.rfind(".dmf")==path.size()-4) {
w=e->saveDMF();
if (dmfVersion) {
w=e->saveDMF(dmfVersion);
} else {
w=e->saveFur();
}
@ -4305,7 +4308,7 @@ bool FurnaceGUI::loop() {
if (curFileName=="") {
openFileDialog(GUI_FILE_SAVE);
} else {
if (save(curFileName)>0) {
if (save(curFileName,e->song.isDMF?e->song.version:0)>0) {
showError(fmt::sprintf("Error while saving file! (%s)",lastError));
}
}
@ -4313,6 +4316,9 @@ bool FurnaceGUI::loop() {
if (ImGui::MenuItem("save as...",BIND_FOR(GUI_ACTION_SAVE_AS))) {
openFileDialog(GUI_FILE_SAVE);
}
if (ImGui::MenuItem("save as .dmf (1.0/legacy)...",BIND_FOR(GUI_ACTION_SAVE_AS))) {
openFileDialog(GUI_FILE_SAVE_DMF_LEGACY);
}
ImGui::Separator();
if (ImGui::BeginMenu("export audio...")) {
if (ImGui::MenuItem("one file")) {
@ -4796,7 +4802,19 @@ bool FurnaceGUI::loop() {
break;
case GUI_FILE_SAVE:
printf("saving: %s\n",copyOfName.c_str());
if (save(copyOfName)>0) {
if (ImGuiFileDialog::Instance()->GetCurrentFilter()=="Furnace song") {
if (save(copyOfName,0)>0) {
showError(fmt::sprintf("Error while saving file! (%s)",lastError));
}
} else {
if (save(copyOfName,25)>0) {
showError(fmt::sprintf("Error while saving file! (%s)",lastError));
}
}
break;
case GUI_FILE_SAVE_DMF_LEGACY:
printf("saving: %s\n",copyOfName.c_str());
if (save(copyOfName,24)>0) {
showError(fmt::sprintf("Error while saving file! (%s)",lastError));
}
break;

View File

@ -132,6 +132,7 @@ enum FurnaceGUIWindows {
enum FurnaceGUIFileDialogs {
GUI_FILE_OPEN,
GUI_FILE_SAVE,
GUI_FILE_SAVE_DMF_LEGACY,
GUI_FILE_INS_OPEN,
GUI_FILE_INS_SAVE,
GUI_FILE_WAVE_OPEN,
@ -690,7 +691,7 @@ class FurnaceGUI {
void keyUp(SDL_Event& ev);
void openFileDialog(FurnaceGUIFileDialogs type);
int save(String path);
int save(String path, int dmfVersion);
int load(String path);
void exportAudio(String path, DivAudioExportModes mode);