dev103 - store system name and other info in song

This commit is contained in:
tildearrow 2022-07-23 17:02:03 -05:00
parent d004629a58
commit 8d88ac766c
12 changed files with 146 additions and 69 deletions

View File

@ -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`

View File

@ -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

View File

@ -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;
}

View File

@ -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<int>& desc);
std::vector<int> 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);

View File

@ -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<numberOfSubSongs; i++) {
subSongPtr[i]=reader.readI();
}
}
// additional metadata
if (ds.version>=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<numberOfSubSongs; i++) {
ds.subsong.push_back(new DivSubSong);
if (!reader.seek(subSongPtr[i],SEEK_SET)) {
@ -1865,26 +1882,33 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
}
if (memcmp(magic,"M.K.",4)==0 || memcmp(magic,"M!K!",4)==0 || memcmp(magic,"M&K!",4)==0) {
logD("detected a ProTracker module");
ds.systemName="Amiga";
chCount=4;
} else if (memcmp(magic,"CD81",4)==0 || memcmp(magic,"OKTA",4)==0 || memcmp(magic,"OCTA",4)==0) {
logD("detected an Oktalyzer/Octalyzer/OctaMED module");
ds.systemName="Amiga (8-channel)";
chCount=8;
} else if (memcmp(magic+1,"CHN",3)==0 && magic[0]>='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);

View File

@ -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(""),

View File

@ -54,14 +54,14 @@ std::vector<DivInstrumentType>& 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; i<song.systemLen; i++) {
for (int i=0; i<ds.systemLen; i++) {
if (i>0) 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]);
}
}

View File

@ -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

View File

@ -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());

View File

@ -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;

View File

@ -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="";

View File

@ -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();