mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-04 20:05:05 +00:00
1.1 .DMF saving
as of now you're given a choice between 1.1 and 1.0 module
This commit is contained in:
parent
2326c4250e
commit
fa363384aa
6 changed files with 96 additions and 29 deletions
|
@ -267,7 +267,7 @@ class DivEngine {
|
||||||
// load a file.
|
// load a file.
|
||||||
bool load(unsigned char* f, size_t length);
|
bool load(unsigned char* f, size_t length);
|
||||||
// save as .dmf.
|
// save as .dmf.
|
||||||
SafeWriter* saveDMF();
|
SafeWriter* saveDMF(unsigned char version);
|
||||||
// save as .fur.
|
// save as .fur.
|
||||||
SafeWriter* saveFur();
|
SafeWriter* saveFur();
|
||||||
// build a ROM file (TODO).
|
// build a ROM file (TODO).
|
||||||
|
|
|
@ -53,6 +53,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
||||||
ds.nullWave.data[i]=15;
|
ds.nullWave.data[i]=15;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ds.isDMF=true;
|
||||||
|
|
||||||
if (!reader.seek(16,SEEK_SET)) {
|
if (!reader.seek(16,SEEK_SET)) {
|
||||||
logE("premature end of file!\n");
|
logE("premature end of file!\n");
|
||||||
lastError="incomplete file";
|
lastError="incomplete file";
|
||||||
|
@ -724,6 +726,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
if (ds.version<50) {
|
if (ds.version<50) {
|
||||||
ds.ignoreDuplicateSlides=false;
|
ds.ignoreDuplicateSlides=false;
|
||||||
}
|
}
|
||||||
|
ds.isDMF=false;
|
||||||
|
|
||||||
reader.readS(); // reserved
|
reader.readS(); // reserved
|
||||||
int infoSeek=reader.readI();
|
int infoSeek=reader.readI();
|
||||||
|
@ -1148,6 +1151,9 @@ SafeWriter* DivEngine::saveFur() {
|
||||||
size_t ptrSeek;
|
size_t ptrSeek;
|
||||||
warnings="";
|
warnings="";
|
||||||
|
|
||||||
|
song.isDMF=false;
|
||||||
|
song.version=DIV_ENGINE_VERSION;
|
||||||
|
|
||||||
SafeWriter* w=new SafeWriter;
|
SafeWriter* w=new SafeWriter;
|
||||||
w->init();
|
w->init();
|
||||||
/// HEADER
|
/// HEADER
|
||||||
|
@ -1375,19 +1381,34 @@ SafeWriter* DivEngine::saveFur() {
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
SafeWriter* DivEngine::saveDMF() {
|
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
|
// 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) {
|
if (song.systemLen!=1) {
|
||||||
logE("cannot save multiple systems in this format!\n");
|
logE("cannot save multiple systems in this format!\n");
|
||||||
lastError="multiple systems not possible on .dmf";
|
lastError="multiple systems not possible on .dmf";
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// fail if this is an YMU759 song
|
// fail if this is an YMU759 song
|
||||||
if (song.system[0]==DIV_SYSTEM_YMU759) {
|
if (song.system[0]==DIV_SYSTEM_YMU759) {
|
||||||
logE("cannot save YMU759 song!\n");
|
logE("cannot save YMU759 song!\n");
|
||||||
lastError="YMU759 song saving is not supported";
|
lastError="YMU759 song saving is not supported";
|
||||||
return NULL;
|
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
|
// fail if the system is Furnace-exclusive
|
||||||
if (systemToFile(song.system[0])&0x80) {
|
if (systemToFile(song.system[0])&0x80) {
|
||||||
logE("cannot save Furnace-exclusive system song!\n");
|
logE("cannot save Furnace-exclusive system song!\n");
|
||||||
|
@ -1395,14 +1416,23 @@ SafeWriter* DivEngine::saveDMF() {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
warnings="";
|
warnings="";
|
||||||
|
song.version=version;
|
||||||
|
song.isDMF=true;
|
||||||
|
|
||||||
SafeWriter* w=new SafeWriter;
|
SafeWriter* w=new SafeWriter;
|
||||||
w->init();
|
w->init();
|
||||||
// write magic
|
// write magic
|
||||||
w->write(DIV_DMF_MAGIC,16);
|
w->write(DIV_DMF_MAGIC,16);
|
||||||
// version
|
// version
|
||||||
w->writeC(24);
|
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]));
|
w->writeC(systemToFile(song.system[0]));
|
||||||
|
sys=song.system[0];
|
||||||
|
}
|
||||||
|
|
||||||
// song info
|
// song info
|
||||||
w->writeString(song.name,true);
|
w->writeString(song.name,true);
|
||||||
|
@ -1425,10 +1455,14 @@ SafeWriter* DivEngine::saveDMF() {
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
for (int j=0; j<song.ordersLen; j++) {
|
for (int j=0; j<song.ordersLen; j++) {
|
||||||
w->writeC(song.orders.ord[i][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("absolute duty/cutoff macro not available in .dmf!");
|
||||||
addWarning("duty precision will be lost");
|
addWarning("duty precision will be lost");
|
||||||
}
|
}
|
||||||
|
@ -1452,10 +1486,10 @@ SafeWriter* DivEngine::saveDMF() {
|
||||||
w->writeString(i->name,true);
|
w->writeString(i->name,true);
|
||||||
|
|
||||||
// safety check
|
// safety check
|
||||||
if (!isFMSystem(song.system[0]) && i->mode) {
|
if (!isFMSystem(sys) && i->mode) {
|
||||||
i->mode=0;
|
i->mode=0;
|
||||||
}
|
}
|
||||||
if (!isSTDSystem(song.system[0]) && i->mode==0) {
|
if (!isSTDSystem(sys) && i->mode==0) {
|
||||||
i->mode=1;
|
i->mode=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1475,14 +1509,25 @@ SafeWriter* DivEngine::saveDMF() {
|
||||||
w->writeC(op.rr);
|
w->writeC(op.rr);
|
||||||
w->writeC(op.sl);
|
w->writeC(op.sl);
|
||||||
w->writeC(op.tl);
|
w->writeC(op.tl);
|
||||||
|
if (sys==DIV_SYSTEM_SMS_OPLL && j==0) {
|
||||||
|
w->writeC(i->fm.opllPreset);
|
||||||
|
} else {
|
||||||
w->writeC(op.dt2);
|
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.rs);
|
||||||
w->writeC(op.dt);
|
w->writeC(op.dt);
|
||||||
w->writeC(op.d2r);
|
w->writeC(op.d2r);
|
||||||
w->writeC(op.ssgEnv);
|
w->writeC(op.ssgEnv);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else { // STD
|
} else { // STD
|
||||||
if (song.system[0]!=DIV_SYSTEM_GB) {
|
if (sys!=DIV_SYSTEM_GB) {
|
||||||
w->writeC(i->std.volMacroLen);
|
w->writeC(i->std.volMacroLen);
|
||||||
w->write(i->std.volMacro,4*i->std.volMacroLen);
|
w->write(i->std.volMacro,4*i->std.volMacroLen);
|
||||||
if (i->std.volMacroLen>0) {
|
if (i->std.volMacroLen>0) {
|
||||||
|
@ -1515,7 +1560,7 @@ SafeWriter* DivEngine::saveDMF() {
|
||||||
w->writeC(i->std.waveMacroLoop);
|
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.triOn);
|
||||||
w->writeC(i->c64.sawOn);
|
w->writeC(i->c64.sawOn);
|
||||||
w->writeC(i->c64.pulseOn);
|
w->writeC(i->c64.pulseOn);
|
||||||
|
@ -1544,7 +1589,7 @@ SafeWriter* DivEngine::saveDMF() {
|
||||||
w->writeC(i->c64.ch3off);
|
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.envVol);
|
||||||
w->writeC(i->gb.envDir);
|
w->writeC(i->gb.envDir);
|
||||||
w->writeC(i->gb.envLen);
|
w->writeC(i->gb.envLen);
|
||||||
|
@ -1559,7 +1604,7 @@ SafeWriter* DivEngine::saveDMF() {
|
||||||
w->write(i->data,4*i->len);
|
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);
|
w->writeC(song.pat[i].effectRows);
|
||||||
|
|
||||||
for (int j=0; j<song.ordersLen; j++) {
|
for (int j=0; j<song.ordersLen; j++) {
|
||||||
|
|
|
@ -140,6 +140,7 @@ struct DivSong {
|
||||||
// - basic format, no system number, 16 instruments, one speed, YMU759-only
|
// - 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
|
// - 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;
|
unsigned short version;
|
||||||
|
bool isDMF;
|
||||||
|
|
||||||
// system
|
// system
|
||||||
DivSystem system[32];
|
DivSystem system[32];
|
||||||
|
@ -267,7 +268,8 @@ struct DivSong {
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
DivSong():
|
DivSong():
|
||||||
version(24),
|
version(0),
|
||||||
|
isDMF(false),
|
||||||
systemLen(1),
|
systemLen(1),
|
||||||
name(""),
|
name(""),
|
||||||
author(""),
|
author(""),
|
||||||
|
|
|
@ -650,6 +650,7 @@ const char* DivEngine::getSystemNameJ(DivSystem sys) {
|
||||||
bool DivEngine::isFMSystem(DivSystem sys) {
|
bool DivEngine::isFMSystem(DivSystem sys) {
|
||||||
return (sys==DIV_SYSTEM_GENESIS ||
|
return (sys==DIV_SYSTEM_GENESIS ||
|
||||||
sys==DIV_SYSTEM_GENESIS_EXT ||
|
sys==DIV_SYSTEM_GENESIS_EXT ||
|
||||||
|
sys==DIV_SYSTEM_SMS_OPLL ||
|
||||||
sys==DIV_SYSTEM_ARCADE ||
|
sys==DIV_SYSTEM_ARCADE ||
|
||||||
sys==DIV_SYSTEM_YM2610 ||
|
sys==DIV_SYSTEM_YM2610 ||
|
||||||
sys==DIV_SYSTEM_YM2610_EXT ||
|
sys==DIV_SYSTEM_YM2610_EXT ||
|
||||||
|
|
|
@ -2892,7 +2892,7 @@ void FurnaceGUI::doAction(int what) {
|
||||||
if (curFileName=="") {
|
if (curFileName=="") {
|
||||||
openFileDialog(GUI_FILE_SAVE);
|
openFileDialog(GUI_FILE_SAVE);
|
||||||
} else {
|
} 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));
|
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);
|
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Open File","compatible files{.fur,.dmf},.*",workingDir);
|
||||||
break;
|
break;
|
||||||
case GUI_FILE_SAVE:
|
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;
|
break;
|
||||||
case GUI_FILE_INS_OPEN:
|
case GUI_FILE_INS_OPEN:
|
||||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Load Instrument","compatible files{.fui,.dmp},.*",workingDir);
|
ImGuiFileDialog::Instance()->OpenModal("FileDialog","Load Instrument","compatible files{.fui,.dmp},.*",workingDir);
|
||||||
|
@ -3857,10 +3860,10 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
||||||
|
|
||||||
#define FURNACE_ZLIB_COMPRESS
|
#define FURNACE_ZLIB_COMPRESS
|
||||||
|
|
||||||
int FurnaceGUI::save(String path) {
|
int FurnaceGUI::save(String path, int dmfVersion) {
|
||||||
SafeWriter* w;
|
SafeWriter* w;
|
||||||
if (path.rfind(".dmf")==path.size()-4) {
|
if (dmfVersion) {
|
||||||
w=e->saveDMF();
|
w=e->saveDMF(dmfVersion);
|
||||||
} else {
|
} else {
|
||||||
w=e->saveFur();
|
w=e->saveFur();
|
||||||
}
|
}
|
||||||
|
@ -4305,7 +4308,7 @@ bool FurnaceGUI::loop() {
|
||||||
if (curFileName=="") {
|
if (curFileName=="") {
|
||||||
openFileDialog(GUI_FILE_SAVE);
|
openFileDialog(GUI_FILE_SAVE);
|
||||||
} else {
|
} 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));
|
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))) {
|
if (ImGui::MenuItem("save as...",BIND_FOR(GUI_ACTION_SAVE_AS))) {
|
||||||
openFileDialog(GUI_FILE_SAVE);
|
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();
|
ImGui::Separator();
|
||||||
if (ImGui::BeginMenu("export audio...")) {
|
if (ImGui::BeginMenu("export audio...")) {
|
||||||
if (ImGui::MenuItem("one file")) {
|
if (ImGui::MenuItem("one file")) {
|
||||||
|
@ -4796,7 +4802,19 @@ bool FurnaceGUI::loop() {
|
||||||
break;
|
break;
|
||||||
case GUI_FILE_SAVE:
|
case GUI_FILE_SAVE:
|
||||||
printf("saving: %s\n",copyOfName.c_str());
|
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));
|
showError(fmt::sprintf("Error while saving file! (%s)",lastError));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -132,6 +132,7 @@ enum FurnaceGUIWindows {
|
||||||
enum FurnaceGUIFileDialogs {
|
enum FurnaceGUIFileDialogs {
|
||||||
GUI_FILE_OPEN,
|
GUI_FILE_OPEN,
|
||||||
GUI_FILE_SAVE,
|
GUI_FILE_SAVE,
|
||||||
|
GUI_FILE_SAVE_DMF_LEGACY,
|
||||||
GUI_FILE_INS_OPEN,
|
GUI_FILE_INS_OPEN,
|
||||||
GUI_FILE_INS_SAVE,
|
GUI_FILE_INS_SAVE,
|
||||||
GUI_FILE_WAVE_OPEN,
|
GUI_FILE_WAVE_OPEN,
|
||||||
|
@ -690,7 +691,7 @@ class FurnaceGUI {
|
||||||
void keyUp(SDL_Event& ev);
|
void keyUp(SDL_Event& ev);
|
||||||
|
|
||||||
void openFileDialog(FurnaceGUIFileDialogs type);
|
void openFileDialog(FurnaceGUIFileDialogs type);
|
||||||
int save(String path);
|
int save(String path, int dmfVersion);
|
||||||
int load(String path);
|
int load(String path);
|
||||||
void exportAudio(String path, DivAudioExportModes mode);
|
void exportAudio(String path, DivAudioExportModes mode);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue