From 8d88ac766c109872114e7055988a819e9f62478e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Jul 2022 17:02:03 -0500 Subject: [PATCH] dev103 - store system name and other info in song --- TODO.md | 3 -- papers/format.md | 9 +++++ src/engine/engine.cpp | 13 ++++++- src/engine/engine.h | 8 ++-- src/engine/fileOps.cpp | 32 ++++++++++++++++ src/engine/song.h | 5 ++- src/engine/sysDef.cpp | 86 +++++++++++++++++++++--------------------- src/engine/vgmOps.cpp | 24 +++++------- src/gui/gui.cpp | 4 +- src/gui/gui.h | 1 + src/gui/newSong.cpp | 3 +- src/gui/songInfo.cpp | 27 +++++++++++++ 12 files changed, 146 insertions(+), 69 deletions(-) diff --git a/TODO.md b/TODO.md index 5032ea32e..46773705a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,5 @@ # to-do for 0.6pre1.5-0.6pre2 -- rewrite the system name detection function anyway - - this involves the addition of a new "system" field in the song (which solves the problem) - - songs made in older versions will go through old system name detection for compatibility - Game Boy envelope macro/sequence - volume commands should work on Game Boy - ability to customize `OFF`, `===` and `REL` diff --git a/papers/format.md b/papers/format.md index 080914c1e..537150215 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 103: Furnace dev103 +- 102: Furnace 0.6pre1 (dev102) - 101: Furnace 0.6pre1 (dev101) - 100: Furnace 0.6pre1 - 99: Furnace dev99 @@ -334,6 +336,13 @@ size | description 1 | number of additional subsongs 3 | reserved 4?? | pointers to subsong data + --- | **additional metadata** (>=103) + STR | system name + STR | album/category/game name + STR | song name (Japanese) + STR | song author (Japanese) + STR | system name (Japanese) + STR | album/category/game name (Japanese) ``` # subsong diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 659ea6b9a..f1e8dc043 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -842,7 +842,7 @@ void DivEngine::initSongWithDesc(const int* description) { } } -void DivEngine::createNew(const int* description) { +void DivEngine::createNew(const int* description, String sysName) { quitDispatch(); BUSY_BEGIN; saveLock.lock(); @@ -852,6 +852,11 @@ void DivEngine::createNew(const int* description) { if (description!=NULL) { initSongWithDesc(description); } + if (sysName=="") { + song.systemName=getSongSystemLegacyName(song,getConfInt("noMultiSystem",0)); + } else { + song.systemName=sysName; + } recalcChans(); saveLock.unlock(); BUSY_END; @@ -3197,6 +3202,12 @@ bool DivEngine::init() { preset.push_back(0); initSongWithDesc(preset.data()); } + String sysName=getConfString("initialSysName",""); + if (sysName=="") { + song.systemName=getSongSystemLegacyName(song,getConfInt("noMultiSystem",0)); + } else { + song.systemName=sysName; + } hasLoadedSomething=true; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 21fde0a70..f6567dd3a 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -45,8 +45,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "0.6pre1 (dev102)" -#define DIV_ENGINE_VERSION 102 +#define DIV_VERSION "dev103" +#define DIV_ENGINE_VERSION 103 // for imports #define DIV_VERSION_MOD 0xff01 @@ -454,7 +454,7 @@ class DivEngine { String encodeSysDesc(std::vector& desc); std::vector decodeSysDesc(String desc); // start fresh - void createNew(const int* description); + void createNew(const int* description, String sysName); // load a file. bool load(unsigned char* f, size_t length); // save as .dmf. @@ -576,7 +576,7 @@ class DivEngine { DivInstrumentType getPreferInsSecondType(int ch); // get song system name - String getSongSystemName(bool isMultiSystemAcceptable=true); + String getSongSystemLegacyName(DivSong& ds, bool isMultiSystemAcceptable=true); // get sys name const char* getSystemName(DivSystem sys); diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 110259050..e66e2c8d9 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -907,6 +907,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.system[1]=DIV_SYSTEM_FDS; } + ds.systemName=getSongSystemLegacyName(ds,getConfInt("noMultiSystem",0)); + if (active) quitDispatch(); BUSY_BEGIN_SOFT; saveLock.lock(); @@ -1482,7 +1484,22 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { for (int i=0; i=103) { + ds.systemName=reader.readString(); + ds.category=reader.readString(); + ds.nameJ=reader.readString(); + ds.authorJ=reader.readString(); + ds.systemNameJ=reader.readString(); + ds.categoryJ=reader.readString(); + } else { + ds.systemName=getSongSystemLegacyName(ds,getConfInt("noMultiSystem",0)); + } + + // read subsongs + if (ds.version>=95) { for (int i=0; i='1' && magic[0]<='9') { logD("detected a FastTracker module"); + ds.systemName="PC"; chCount=magic[0]-'0'; } else if (memcmp(magic,"FLT",3)==0 && magic[3]>='1' && magic[3]<='9') { logD("detected a Fairlight module"); + ds.systemName="Amiga"; chCount=magic[3]-'0'; } else if (memcmp(magic,"TDZ",3)==0 && magic[3]>='1' && magic[3]<='9') { logD("detected a TakeTracker module"); + ds.systemName="PC"; chCount=magic[3]-'0'; } else if ((memcmp(magic+2,"CH",2)==0 || memcmp(magic+2,"CN",2)==0) && (magic[0]>='1' && magic[0]<='9' && magic[1]>='0' && magic[1]<='9')) { logD("detected a Fast/TakeTracker module"); + ds.systemName="PC"; chCount=((magic[0]-'0')*10)+(magic[1]-'0'); } else { insCount=15; logD("possibly a Soundtracker module"); + ds.systemName="Amiga"; chCount=4; } @@ -2976,6 +3000,14 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeI(0); } + // additional metadata + w->writeString(song.systemName,false); + w->writeString(song.category,false); + w->writeString(song.nameJ,false); + w->writeString(song.authorJ,false); + w->writeString(song.systemNameJ,false); + w->writeString(song.categoryJ,false); + blockEndSeek=w->tell(); w->seek(blockStartSeek,SEEK_SET); w->writeI(blockEndSeek-blockStartSeek-4); diff --git a/src/engine/song.h b/src/engine/song.h index 26640fdd4..8375fc561 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -428,7 +428,7 @@ struct DivSong { unsigned int systemFlags[32]; // song information - String name, author; + String name, author, systemName; // legacy song information // those will be stored in .fur and mapped to VGM as: @@ -438,7 +438,7 @@ struct DivSong { String carrier, composer, vendor, category, writer, arranger, copyright, manGroup, manInfo, createdDate, revisionDate; // more VGM specific stuff - String nameJ, authorJ, categoryJ; + String nameJ, authorJ, categoryJ, systemNameJ; // other things String notes; @@ -541,6 +541,7 @@ struct DivSong { systemLen(2), name(""), author(""), + systemName(""), carrier(""), composer(""), vendor(""), diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 25e35227f..813e409e5 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -54,14 +54,14 @@ std::vector& DivEngine::getPossibleInsTypes() { return possibleInsTypes; } -// TODO: deprecate when I add "system name" field in the file. -String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { - switch (song.systemLen) { +// for pre-dev103 modules +String DivEngine::getSongSystemLegacyName(DivSong& ds, bool isMultiSystemAcceptable) { + switch (ds.systemLen) { case 0: return "help! what's going on!"; case 1: - if (song.system[0]==DIV_SYSTEM_AY8910) { - switch (song.systemFlags[0]&0x3f) { + if (ds.system[0]==DIV_SYSTEM_AY8910) { + switch (ds.systemFlags[0]&0x3f) { case 0: // AY-3-8910, 1.79MHz case 1: // AY-3-8910, 1.77MHz case 2: // AY-3-8910, 1.75MHz @@ -88,116 +88,116 @@ String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { return "Intellivision (PAL)"; default: - if ((song.systemFlags[0]&0x30)==0x00) { + if ((ds.systemFlags[0]&0x30)==0x00) { return "AY-3-8910"; - } else if ((song.systemFlags[0]&0x30)==0x10) { + } else if ((ds.systemFlags[0]&0x30)==0x10) { return "Yamaha YM2149"; - } else if ((song.systemFlags[0]&0x30)==0x20) { + } else if ((ds.systemFlags[0]&0x30)==0x20) { return "Overclocked Sunsoft 5B"; - } else if ((song.systemFlags[0]&0x30)==0x30) { + } else if ((ds.systemFlags[0]&0x30)==0x30) { return "Intellivision"; } } - } else if (song.system[0]==DIV_SYSTEM_SMS) { - switch (song.systemFlags[0]&0x0f) { + } else if (ds.system[0]==DIV_SYSTEM_SMS) { + switch (ds.systemFlags[0]&0x0f) { case 0: case 1: return "Sega Master System"; case 6: return "BBC Micro"; } - } else if (song.system[0]==DIV_SYSTEM_YM2612) { - switch (song.systemFlags[0]&3) { + } else if (ds.system[0]==DIV_SYSTEM_YM2612) { + switch (ds.systemFlags[0]&3) { case 2: return "FM Towns"; } - } else if (song.system[0]==DIV_SYSTEM_YM2151) { - switch (song.systemFlags[0]&3) { + } else if (ds.system[0]==DIV_SYSTEM_YM2151) { + switch (ds.systemFlags[0]&3) { case 2: return "Sharp X68000"; } - } else if (song.system[0]==DIV_SYSTEM_SAA1099) { - switch (song.systemFlags[0]&3) { + } else if (ds.system[0]==DIV_SYSTEM_SAA1099) { + switch (ds.systemFlags[0]&3) { case 0: return "SAM Coupé"; } } - return getSystemName(song.system[0]); + return getSystemName(ds.system[0]); case 2: - if (song.system[0]==DIV_SYSTEM_YM2612 && song.system[1]==DIV_SYSTEM_SMS) { + if (ds.system[0]==DIV_SYSTEM_YM2612 && ds.system[1]==DIV_SYSTEM_SMS) { return "Sega Genesis/Mega Drive"; } - if (song.system[0]==DIV_SYSTEM_YM2612_EXT && song.system[1]==DIV_SYSTEM_SMS) { + if (ds.system[0]==DIV_SYSTEM_YM2612_EXT && ds.system[1]==DIV_SYSTEM_SMS) { return "Sega Genesis Extended Channel 3"; } - if (song.system[0]==DIV_SYSTEM_OPLL && song.system[1]==DIV_SYSTEM_SMS) { + if (ds.system[0]==DIV_SYSTEM_OPLL && ds.system[1]==DIV_SYSTEM_SMS) { return "NTSC-J Sega Master System"; } - if (song.system[0]==DIV_SYSTEM_OPLL_DRUMS && song.system[1]==DIV_SYSTEM_SMS) { + if (ds.system[0]==DIV_SYSTEM_OPLL_DRUMS && ds.system[1]==DIV_SYSTEM_SMS) { return "NTSC-J Sega Master System + drums"; } - if (song.system[0]==DIV_SYSTEM_OPLL && song.system[1]==DIV_SYSTEM_AY8910) { + if (ds.system[0]==DIV_SYSTEM_OPLL && ds.system[1]==DIV_SYSTEM_AY8910) { return "MSX-MUSIC"; } - if (song.system[0]==DIV_SYSTEM_OPLL_DRUMS && song.system[1]==DIV_SYSTEM_AY8910) { + if (ds.system[0]==DIV_SYSTEM_OPLL_DRUMS && ds.system[1]==DIV_SYSTEM_AY8910) { return "MSX-MUSIC + drums"; } - if (song.system[0]==DIV_SYSTEM_C64_6581 && song.system[1]==DIV_SYSTEM_C64_6581) { + if (ds.system[0]==DIV_SYSTEM_C64_6581 && ds.system[1]==DIV_SYSTEM_C64_6581) { return "Commodore 64 with dual 6581"; } - if (song.system[0]==DIV_SYSTEM_C64_8580 && song.system[1]==DIV_SYSTEM_C64_8580) { + if (ds.system[0]==DIV_SYSTEM_C64_8580 && ds.system[1]==DIV_SYSTEM_C64_8580) { return "Commodore 64 with dual 8580"; } - if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM_COMPAT) { + if (ds.system[0]==DIV_SYSTEM_YM2151 && ds.system[1]==DIV_SYSTEM_SEGAPCM_COMPAT) { return "YM2151 + SegaPCM Arcade (compatibility)"; } - if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_SEGAPCM) { + if (ds.system[0]==DIV_SYSTEM_YM2151 && ds.system[1]==DIV_SYSTEM_SEGAPCM) { return "YM2151 + SegaPCM Arcade"; } - if (song.system[0]==DIV_SYSTEM_SAA1099 && song.system[1]==DIV_SYSTEM_SAA1099) { + if (ds.system[0]==DIV_SYSTEM_SAA1099 && ds.system[1]==DIV_SYSTEM_SAA1099) { return "Creative Music System"; } - if (song.system[0]==DIV_SYSTEM_GB && song.system[1]==DIV_SYSTEM_AY8910) { + if (ds.system[0]==DIV_SYSTEM_GB && ds.system[1]==DIV_SYSTEM_AY8910) { return "Game Boy with AY expansion"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC6) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_VRC6) { return "Famicom + Konami VRC6"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC7) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_VRC7) { return "Famicom + Konami VRC7"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_OPLL) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_OPLL) { return "Family Noraebang"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_FDS) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_FDS) { return "Famicom Disk System"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_N163) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_N163) { String ret="Famicom + "; ret+=getConfString("c163Name","Namco C163"); return ret; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_MMC5) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_MMC5) { return "Famicom + MMC5"; } - if (song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_AY8910) { + if (ds.system[0]==DIV_SYSTEM_NES && ds.system[1]==DIV_SYSTEM_AY8910) { return "Famicom + Sunsoft 5B"; } - if (song.system[0]==DIV_SYSTEM_AY8910 && song.system[1]==DIV_SYSTEM_AY8910) { + if (ds.system[0]==DIV_SYSTEM_AY8910 && ds.system[1]==DIV_SYSTEM_AY8910) { return "Bally Midway MCR"; } - if (song.system[0]==DIV_SYSTEM_YM2151 && song.system[1]==DIV_SYSTEM_VERA) { + if (ds.system[0]==DIV_SYSTEM_YM2151 && ds.system[1]==DIV_SYSTEM_VERA) { return "Commander X16"; } break; case 3: - if (song.system[0]==DIV_SYSTEM_AY8910 && song.system[1]==DIV_SYSTEM_AY8910 && song.system[2]==DIV_SYSTEM_BUBSYS_WSG) { + if (ds.system[0]==DIV_SYSTEM_AY8910 && ds.system[1]==DIV_SYSTEM_AY8910 && ds.system[2]==DIV_SYSTEM_BUBSYS_WSG) { return "Konami Bubble System"; } break; @@ -205,12 +205,12 @@ String DivEngine::getSongSystemName(bool isMultiSystemAcceptable) { if (isMultiSystemAcceptable) return "multi-system"; String ret=""; - for (int i=0; i0) ret+=" + "; - if (song.system[i]==DIV_SYSTEM_N163) { + if (ds.system[i]==DIV_SYSTEM_N163) { ret+=getConfString("c163Name","Namco C163"); } else { - ret+=getSystemName(song.system[i]); + ret+=getSystemName(ds.system[i]); } } diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index ef1c5dc37..a500b4848 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -1920,24 +1920,20 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { WString ws; ws=utf8To16(song.name.c_str()); w->writeWString(ws,false); // name - w->writeS(0); // japanese name - w->writeS(0); // game name - w->writeS(0); // japanese game name - if (song.systemLen>1) { - ws=L"Multiple Systems"; - } else { - ws=utf8To16(getSystemName(song.system[0])); - } + ws=utf8To16(song.nameJ.c_str()); + w->writeWString(ws,false); // japanese name + ws=utf8To16(song.category.c_str()); + w->writeWString(ws,false); // game name + ws=utf8To16(song.categoryJ.c_str()); + w->writeWString(ws,false); // japanese game name + ws=utf8To16(song.systemName.c_str()); w->writeWString(ws,false); // system name - if (song.systemLen>1) { - ws=L"複数システム"; - } else { - ws=utf8To16(getSystemNameJ(song.system[0])); - } + ws=utf8To16(song.systemNameJ.c_str()); w->writeWString(ws,false); // japanese system name ws=utf8To16(song.author.c_str()); w->writeWString(ws,false); // author name - w->writeS(0); // japanese author name + ws=utf8To16(song.authorJ.c_str()); + w->writeWString(ws,false); // japanese author name w->writeS(0); // date w->writeWString(L"Furnace Tracker",false); // ripper w->writeS(0); // notes diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 90925b934..97c1d78e1 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -551,7 +551,9 @@ void FurnaceGUI::updateWindowTitle() { } if (settings.titleBarSys) { - title+=fmt::sprintf(" (%s)",e->getSongSystemName(!settings.noMultiSystem)); + if (e->song.systemName!="") { + title+=fmt::sprintf(" (%s)",e->song.systemName); + } } if (sdlWin!=NULL) SDL_SetWindowTitle(sdlWin,title.c_str()); diff --git a/src/gui/gui.h b/src/gui/gui.h index 851e10aa1..c267fcab5 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1230,6 +1230,7 @@ class FurnaceGUI { float patChanX[DIV_MAX_CHANS+1]; float patChanSlideY[DIV_MAX_CHANS+1]; const int* nextDesc; + String nextDescName; OperationMask opMaskDelete, opMaskPullDelete, opMaskInsert, opMaskPaste, opMaskTransposeNote, opMaskTransposeValue; OperationMask opMaskInterpolate, opMaskFade, opMaskInvertVal, opMaskScale; diff --git a/src/gui/newSong.cpp b/src/gui/newSong.cpp index 0dea772b7..26fddf9fb 100644 --- a/src/gui/newSong.cpp +++ b/src/gui/newSong.cpp @@ -65,6 +65,7 @@ void FurnaceGUI::drawNewSong() { ImGui::TableNextColumn(); if (ImGui::Selectable(i.name,false,ImGuiSelectableFlags_DontClosePopups)) { nextDesc=i.definition.data(); + nextDescName=i.name; accepted=true; } } @@ -97,7 +98,7 @@ void FurnaceGUI::drawNewSong() { } if (accepted) { - e->createNew(nextDesc); + e->createNew(nextDesc,nextDescName); undoHist.clear(); redoHist.clear(); curFileName=""; diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index e90043b7a..b823d085c 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -207,6 +207,33 @@ void FurnaceGUI::drawSongInfo() { } ImGui::EndTable(); } + + if (ImGui::TreeNode("Additional Information")) { + if (ImGui::BeginTable("ExtraData",2,ImGuiTableFlags_SizingStretchProp)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Album"); + ImGui::TableNextColumn(); + float avail=ImGui::GetContentRegionAvail().x; + ImGui::SetNextItemWidth(avail); + if (ImGui::InputText("##Category",&e->song.category)) { + MARK_MODIFIED; + } + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("System"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(avail); + if (ImGui::InputText("##SystemName",&e->song.systemName)) { + MARK_MODIFIED; + updateWindowTitle(); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SONG_INFO; ImGui::End();