From 464ad5a825fbea188c7942a1bcda96bfee783d8b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 19 Feb 2022 02:52:53 -0500 Subject: [PATCH] preliminary 1.1 .dmf loading --- src/engine/fileOps.cpp | 45 +++++++++++++++++++++++++++++++++++------ src/engine/instrument.h | 2 +- src/engine/pattern.cpp | 5 +++++ src/engine/pattern.h | 2 ++ src/engine/song.h | 4 ++++ src/engine/sysDef.cpp | 23 +++++++++++++++++++++ src/gui/gui.cpp | 2 +- 7 files changed, 75 insertions(+), 8 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index b2b9a217..2004af57 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -19,6 +19,7 @@ #include "engine.h" #include "../ta-log.h" +#include "song.h" #include #include @@ -60,7 +61,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } ds.version=(unsigned char)reader.readC(); logI("module version %d (0x%.2x)\n",ds.version,ds.version); - if (ds.version>0x18) { + if (ds.version>0x19) { logE("this version is not supported by Furnace yet!\n"); lastError="this version is not supported by Furnace yet"; delete[] file; @@ -206,10 +207,17 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { addWarning("Yamaha YMU759 emulation is not currently possible!"); } + if (ds.system[0]==DIV_SYSTEM_SMS_OPLL) { + addWarning("Master System FM expansion is not emulated yet. wait for 0.6!"); + } + logI("reading pattern matrix (%d)...\n",ds.ordersLen); for (int i=0; i0x18) { // 1.1 pattern names + ds.pat[i].getPattern(j,true)->name=reader.readString((unsigned char)reader.readC()); + } } } @@ -249,6 +257,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->type=DIV_INS_PCE; ins->std.volMacroHeight=31; } + if (ds.system[0]==DIV_SYSTEM_SMS_OPLL) { + ins->type=DIV_INS_OPLL; + } if (ins->mode) { // FM ins->fm.alg=reader.readC(); @@ -301,13 +312,28 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->fm.op[j].vib=reader.readC(); ins->fm.op[j].ws=reader.readC(); } else { - ins->fm.op[j].dt2=reader.readC(); + if (ds.system[0]==DIV_SYSTEM_SMS_OPLL) { + if (j==0) { + ins->fm.opllPreset=reader.readC(); + } else { + reader.readC(); + } + } else { + ins->fm.op[j].dt2=reader.readC(); + } } if (ds.version>0x03) { - ins->fm.op[j].rs=reader.readC(); - ins->fm.op[j].dt=reader.readC(); - ins->fm.op[j].d2r=reader.readC(); - ins->fm.op[j].ssgEnv=reader.readC(); + if (ds.system[0]==DIV_SYSTEM_SMS_OPLL) { + ins->fm.op[j].ksr=reader.readC(); + ins->fm.op[j].vib=reader.readC(); + ins->fm.op[j].ksl=reader.readC(); + ins->fm.op[j].ssgEnv=reader.readC(); + } else { + ins->fm.op[j].rs=reader.readC(); + ins->fm.op[j].dt=reader.readC(); + ins->fm.op[j].d2r=reader.readC(); + ins->fm.op[j].ssgEnv=reader.readC(); + } } logD("OP%d: AM %d AR %d DAM %d DR %d DVB %d EGT %d KSL %d MULT %d RR %d SL %d SUS %d TL %d VIB %d WS %d RS %d DT %d D2R %d SSG-EG %d\n",j, @@ -610,6 +636,13 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } + // handle special systems + if (ds.system[0]==DIV_SYSTEM_SMS_OPLL) { + ds.systemLen=2; + ds.system[0]=DIV_SYSTEM_SMS; + ds.system[1]=DIV_SYSTEM_OPLL; + } + if (active) quitDispatch(); isBusy.lock(); song.unload(); diff --git a/src/engine/instrument.h b/src/engine/instrument.h index c7b1d897..45548a42 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -50,7 +50,7 @@ enum DivInstrumentType { }; struct DivInstrumentFM { - unsigned char alg, fb, fms, ams, ops; + unsigned char alg, fb, fms, ams, ops, opllPreset; struct Operator { unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759 diff --git a/src/engine/pattern.cpp b/src/engine/pattern.cpp index 848f69b7..91a4ecd4 100644 --- a/src/engine/pattern.cpp +++ b/src/engine/pattern.cpp @@ -49,6 +49,11 @@ void DivChannelData::wipePatterns() { } } +void DivPattern::copyOn(DivPattern *dest) { + dest->name=name; + memcpy(dest->data,data,sizeof(data)); +} + SafeReader* DivPattern::compile(int len, int fxRows) { SafeWriter w; w.init(); diff --git a/src/engine/pattern.h b/src/engine/pattern.h index 51950292..749431b2 100644 --- a/src/engine/pattern.h +++ b/src/engine/pattern.h @@ -20,7 +20,9 @@ #include "safeReader.h" struct DivPattern { + String name; short data[256][32]; + void copyOn(DivPattern* dest); SafeReader* compile(int len=256, int fxRows=1); DivPattern(); }; diff --git a/src/engine/song.h b/src/engine/song.h index 0607c351..2dddae52 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -37,6 +37,7 @@ enum DivSystem { DIV_SYSTEM_GENESIS, DIV_SYSTEM_GENESIS_EXT, DIV_SYSTEM_SMS, + DIV_SYSTEM_SMS_OPLL, DIV_SYSTEM_GB, DIV_SYSTEM_PCE, DIV_SYSTEM_NES, @@ -92,6 +93,9 @@ struct DivSong { // version number used for saving the song. // Furnace will save using the latest possible version, // known version numbers: + // - 25: v1.1 + // - adds pattern names (in a rather odd way) + // - introduces SMS+OPLL system // - 24: v0.12/0.13/1.0 // - current format version // - changes pattern length from char to int, probably to allow for size 256 diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 68deda34..ce13169a 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -18,6 +18,7 @@ */ #include "engine.h" +#include "song.h" DivSystem DivEngine::systemFromFile(unsigned char val) { switch (val) { @@ -41,6 +42,8 @@ DivSystem DivEngine::systemFromFile(unsigned char val) { return DIV_SYSTEM_YM2610; case 0x42: return DIV_SYSTEM_GENESIS_EXT; + case 0x43: + return DIV_SYSTEM_SMS_OPLL; case 0x47: return DIV_SYSTEM_C64_6581; case 0x49: @@ -152,6 +155,8 @@ unsigned char DivEngine::systemToFile(DivSystem val) { return 0x09; case DIV_SYSTEM_GENESIS_EXT: return 0x42; + case DIV_SYSTEM_SMS_OPLL: + return 0x43; case DIV_SYSTEM_C64_6581: return 0x47; case DIV_SYSTEM_YM2610_EXT: @@ -265,6 +270,7 @@ int DivEngine::getChannelCount(DivSystem sys) { case DIV_SYSTEM_ARCADE: case DIV_SYSTEM_GENESIS_EXT: case DIV_SYSTEM_YM2610: + case DIV_SYSTEM_SMS_OPLL: return 13; case DIV_SYSTEM_YM2610_EXT: return 16; @@ -367,6 +373,8 @@ const char* DivEngine::getSystemName(DivSystem sys) { return "Sega Genesis/Mega Drive"; case DIV_SYSTEM_SMS: return "Sega Master System"; + case DIV_SYSTEM_SMS_OPLL: + return "Sega Master System + FM Expansion"; case DIV_SYSTEM_GB: return "Game Boy"; case DIV_SYSTEM_PCE: @@ -480,6 +488,8 @@ const char* DivEngine::getSystemChips(DivSystem sys) { return "Yamaha YM2612 + TI SN76489"; case DIV_SYSTEM_SMS: return "TI SN76489"; + case DIV_SYSTEM_SMS_OPLL: + return "TI SN76489 + Yamaha YM2413"; case DIV_SYSTEM_GB: return "Game Boy"; case DIV_SYSTEM_PCE: @@ -592,6 +602,7 @@ const char* DivEngine::getSystemNameJ(DivSystem sys) { case DIV_SYSTEM_GENESIS: return "セガメガドライブ"; case DIV_SYSTEM_SMS: + case DIV_SYSTEM_SMS_OPLL: return "セガマスターシステム"; case DIV_SYSTEM_GB: return "ゲームボーイ"; @@ -835,6 +846,9 @@ const char* DivEngine::getChannelName(int chan) { case DIV_SYSTEM_SMS: return chanNames[3][dispatchChanOfChan[chan]]; break; + case DIV_SYSTEM_SMS_OPLL: // this is flattened to SMS + OPLL. + return "??"; + break; case DIV_SYSTEM_GB: return chanNames[4][dispatchChanOfChan[chan]]; break; @@ -962,6 +976,9 @@ const char* DivEngine::getChannelShortName(int chan) { case DIV_SYSTEM_SMS: return chanShortNames[3][dispatchChanOfChan[chan]]; break; + case DIV_SYSTEM_SMS_OPLL: // this is flattened to SMS + OPLL. + return "??"; + break; case DIV_SYSTEM_GB: return chanShortNames[4][dispatchChanOfChan[chan]]; break; @@ -1087,6 +1104,9 @@ int DivEngine::getChannelType(int chan) { case DIV_SYSTEM_SMS: return chanTypes[3][dispatchChanOfChan[chan]]; break; + case DIV_SYSTEM_SMS_OPLL: // this is flattened to SMS + OPLL. + return 0; + break; case DIV_SYSTEM_GB: return chanTypes[4][dispatchChanOfChan[chan]]; break; @@ -1212,6 +1232,9 @@ DivInstrumentType DivEngine::getPreferInsType(int chan) { case DIV_SYSTEM_SMS: return chanPrefType[3][dispatchChanOfChan[chan]]; break; + case DIV_SYSTEM_SMS_OPLL: // this is flattened to SMS + OPLL. + return DIV_INS_OPLL; + break; case DIV_SYSTEM_GB: return chanPrefType[4][dispatchChanOfChan[chan]]; break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 94bc2fb1..4e724370 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2275,7 +2275,7 @@ void FurnaceGUI::prepareUndo(ActionType action) { case GUI_UNDO_PATTERN_CUT: case GUI_UNDO_PATTERN_PASTE: for (int i=0; igetTotalChannelCount(); i++) { - memcpy(oldPat[i],e->song.pat[i].getPattern(e->song.orders.ord[i][order],false),sizeof(DivPattern)); + e->song.pat[i].getPattern(e->song.orders.ord[i][order],false)->copyOn(oldPat[i]); } break; }