mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-26 22:43:01 +00:00
dev115 - automatic system detection
This commit is contained in:
parent
a17f499384
commit
e22d7484cb
11 changed files with 150 additions and 12 deletions
|
@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
|
|||
|
||||
the format versions are:
|
||||
|
||||
- 115: Furnace dev115
|
||||
- 114: Furnace dev114
|
||||
- 113: Furnace dev113
|
||||
- 112: Furnace dev112
|
||||
|
@ -342,7 +343,9 @@ size | description
|
|||
1 | SN periods under 8 are treated as 1 (>=108) or reserved
|
||||
1 | cut/delay effect policy (>=110) or reserved
|
||||
1 | 0B/0D effect treatment (>=113) or reserved
|
||||
4 | reserved
|
||||
1 | automatic system name detection (>=115) or reserved
|
||||
| - this one isn't a compatibility flag, but it's here for convenience...
|
||||
3 | reserved
|
||||
--- | **virtual tempo data**
|
||||
2 | virtual tempo numerator of first song (>=96) or reserved
|
||||
2 | virtual tempo denominator of first song (>=96) or reserved
|
||||
|
@ -499,7 +502,11 @@ size | description
|
|||
1 | ws
|
||||
1 | ksr
|
||||
1 | operator enabled (>=114) or reserved
|
||||
11 | reserved
|
||||
1 | KVS mode (>=115) or reserved
|
||||
| - 0: off
|
||||
| - 1: on
|
||||
| - 2: auto (depending on alg)
|
||||
10 | reserved
|
||||
--- | **Game Boy instrument data**
|
||||
1 | volume
|
||||
1 | direction
|
||||
|
|
|
@ -46,8 +46,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev114"
|
||||
#define DIV_ENGINE_VERSION 114
|
||||
#define DIV_VERSION "dev115"
|
||||
#define DIV_ENGINE_VERSION 115
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
|
@ -1085,6 +1085,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (ds.version<113) {
|
||||
ds.jumpTreatment=1;
|
||||
}
|
||||
if (ds.version<115) {
|
||||
ds.autoSystem=false;
|
||||
}
|
||||
ds.isDMF=false;
|
||||
|
||||
reader.readS(); // reserved
|
||||
|
@ -1512,7 +1515,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
if (ds.version>=115) {
|
||||
ds.autoSystem=reader.readC();
|
||||
} else {
|
||||
reader.readC();
|
||||
}
|
||||
for (int i=0; i<3; i++) {
|
||||
reader.readC();
|
||||
}
|
||||
}
|
||||
|
@ -1549,6 +1557,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
ds.categoryJ=reader.readString();
|
||||
} else {
|
||||
ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0));
|
||||
ds.autoSystem=true;
|
||||
}
|
||||
|
||||
// read subsongs
|
||||
|
@ -3751,7 +3760,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeC(song.snNoLowPeriods);
|
||||
w->writeC(song.delayBehavior);
|
||||
w->writeC(song.jumpTreatment);
|
||||
for (int i=0; i<4; i++) {
|
||||
w->writeC(song.autoSystem);
|
||||
for (int i=0; i<3; i++) {
|
||||
w->writeC(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -72,9 +72,10 @@ void DivInstrument::putInsData(SafeWriter* w) {
|
|||
w->writeC(op.ksr);
|
||||
|
||||
w->writeC(op.enable);
|
||||
w->writeC(op.kvs);
|
||||
|
||||
// reserved
|
||||
for (int k=0; k<11; k++) {
|
||||
for (int k=0; k<10; k++) {
|
||||
w->writeC(0);
|
||||
}
|
||||
}
|
||||
|
@ -724,8 +725,15 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
reader.readC();
|
||||
}
|
||||
|
||||
if (version>=115) {
|
||||
op.kvs=reader.readC();
|
||||
} else {
|
||||
op.kvs=2;
|
||||
reader.readC();
|
||||
}
|
||||
|
||||
// reserved
|
||||
for (int k=0; k<11; k++) reader.readC();
|
||||
for (int k=0; k<10; k++) reader.readC();
|
||||
}
|
||||
|
||||
// GB
|
||||
|
|
|
@ -87,6 +87,7 @@ struct DivInstrumentFM {
|
|||
bool enable;
|
||||
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/OPL/OPZ
|
||||
unsigned char kvs;
|
||||
Operator():
|
||||
enable(true),
|
||||
am(0),
|
||||
|
@ -108,7 +109,8 @@ struct DivInstrumentFM {
|
|||
sus(0),
|
||||
vib(0),
|
||||
ws(0),
|
||||
ksr(0) {}
|
||||
ksr(0),
|
||||
kvs(2) {}
|
||||
} op[4];
|
||||
DivInstrumentFM():
|
||||
alg(0),
|
||||
|
|
|
@ -511,6 +511,7 @@ struct DivSong {
|
|||
bool e1e2StopOnSameNote;
|
||||
bool brokenPortaArp;
|
||||
bool snNoLowPeriods;
|
||||
bool autoSystem;
|
||||
|
||||
std::vector<DivInstrument*> ins;
|
||||
std::vector<DivWavetable*> wave;
|
||||
|
@ -614,7 +615,8 @@ struct DivSong {
|
|||
brokenOutVol(false),
|
||||
e1e2StopOnSameNote(false),
|
||||
brokenPortaArp(false),
|
||||
snNoLowPeriods(false) {
|
||||
snNoLowPeriods(false),
|
||||
autoSystem(true) {
|
||||
for (int i=0; i<32; i++) {
|
||||
system[i]=DIV_SYSTEM_NULL;
|
||||
systemVol[i]=64;
|
||||
|
|
|
@ -584,6 +584,78 @@ void FurnaceGUI::updateWindowTitle() {
|
|||
if (sdlWin!=NULL) SDL_SetWindowTitle(sdlWin,title.c_str());
|
||||
}
|
||||
|
||||
void FurnaceGUI::autoDetectSystem() {
|
||||
std::map<DivSystem,int> sysCountMap;
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
try {
|
||||
sysCountMap.at(e->song.system[i])++;
|
||||
} catch (std::exception& ex) {
|
||||
sysCountMap[e->song.system[i]]=1;
|
||||
}
|
||||
}
|
||||
|
||||
logV("sysCountMap:");
|
||||
for (std::pair<DivSystem,int> k: sysCountMap) {
|
||||
logV("%s: %d",e->getSystemName(k.first),k.second);
|
||||
}
|
||||
|
||||
bool isMatch=false;
|
||||
std::map<DivSystem,int> defCountMap;
|
||||
for (FurnaceGUISysCategory& i: sysCategories) {
|
||||
for (FurnaceGUISysDef& j: i.systems) {
|
||||
defCountMap.clear();
|
||||
for (size_t k=0; k<j.definition.size(); k+=4) {
|
||||
if (j.definition[k]==0) break;
|
||||
try {
|
||||
defCountMap.at((DivSystem)j.definition[k])++;
|
||||
} catch (std::exception& ex) {
|
||||
defCountMap[(DivSystem)j.definition[k]]=1;
|
||||
}
|
||||
}
|
||||
if (defCountMap.size()!=sysCountMap.size()) continue;
|
||||
isMatch=true;
|
||||
logV("trying on defCountMap: %s",j.name);
|
||||
for (std::pair<DivSystem,int> k: defCountMap) {
|
||||
logV("- %s: %d",e->getSystemName(k.first),k.second);
|
||||
}
|
||||
for (std::pair<DivSystem,int> k: defCountMap) {
|
||||
try {
|
||||
if (sysCountMap.at(k.first)!=k.second) {
|
||||
isMatch=false;
|
||||
break;
|
||||
}
|
||||
} catch (std::exception& ex) {
|
||||
isMatch=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isMatch) {
|
||||
logV("match found!");
|
||||
e->song.systemName=j.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isMatch) break;
|
||||
}
|
||||
|
||||
if (!isMatch) {
|
||||
bool isFirst=true;
|
||||
e->song.systemName="";
|
||||
for (std::pair<DivSystem,int> k: sysCountMap) {
|
||||
if (!isFirst) e->song.systemName+=" + ";
|
||||
if (k.second>1) {
|
||||
e->song.systemName+=fmt::sprintf("%d×",k.second);
|
||||
}
|
||||
if (k.first==DIV_SYSTEM_N163) {
|
||||
e->song.systemName+=settings.c163Name;
|
||||
} else {
|
||||
e->song.systemName+=e->getSystemName(k.first);
|
||||
}
|
||||
isFirst=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImVec4 FurnaceGUI::channelColor(int ch) {
|
||||
switch (settings.channelColors) {
|
||||
case 0:
|
||||
|
@ -3262,6 +3334,9 @@ bool FurnaceGUI::loop() {
|
|||
showError("cannot add chip! ("+e->getLastError()+")");
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
if (e->song.autoSystem) {
|
||||
autoDetectSystem();
|
||||
}
|
||||
updateWindowTitle();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
|
@ -3282,6 +3357,9 @@ bool FurnaceGUI::loop() {
|
|||
DivSystem picked=systemPicker();
|
||||
if (picked!=DIV_SYSTEM_NULL) {
|
||||
e->changeSystem(i,picked,preserveChanPos);
|
||||
if (e->song.autoSystem) {
|
||||
autoDetectSystem();
|
||||
}
|
||||
updateWindowTitle();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
@ -3297,6 +3375,10 @@ bool FurnaceGUI::loop() {
|
|||
if (!e->removeSystem(i,preserveChanPos)) {
|
||||
showError("cannot remove chip! ("+e->getLastError()+")");
|
||||
}
|
||||
if (e->song.autoSystem) {
|
||||
autoDetectSystem();
|
||||
updateWindowTitle();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
|
@ -4415,6 +4497,10 @@ bool FurnaceGUI::loop() {
|
|||
case GUI_WARN_SYSTEM_DEL:
|
||||
if (ImGui::Button("Yes")) {
|
||||
e->removeSystem(sysToDelete,preserveChanPos);
|
||||
if (e->song.autoSystem) {
|
||||
autoDetectSystem();
|
||||
updateWindowTitle();
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
@ -5069,6 +5155,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
macroPointSize(16),
|
||||
waveEditStyle(0),
|
||||
mobileMenuPos(0.0f),
|
||||
autoButtonSize(0.0f),
|
||||
curSysSection(NULL),
|
||||
pendingRawSampleDepth(8),
|
||||
pendingRawSampleChannels(1),
|
||||
|
|
|
@ -1018,7 +1018,7 @@ class FurnaceGUI {
|
|||
int drawHalt;
|
||||
int macroPointSize;
|
||||
int waveEditStyle;
|
||||
float mobileMenuPos;
|
||||
float mobileMenuPos, autoButtonSize;
|
||||
const int* curSysSection;
|
||||
|
||||
String pendingRawSample;
|
||||
|
@ -1610,6 +1610,7 @@ class FurnaceGUI {
|
|||
bool CWVSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format="%d", ImGuiSliderFlags flags=0);
|
||||
|
||||
void updateWindowTitle();
|
||||
void autoDetectSystem();
|
||||
void prepareLayout();
|
||||
ImVec4 channelColor(int ch);
|
||||
ImVec4 channelTextColor(int ch);
|
||||
|
|
|
@ -77,11 +77,23 @@ void FurnaceGUI::drawSongInfo() {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::Text("System");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(avail);
|
||||
ImGui::SetNextItemWidth(MAX(16.0f*dpiScale,avail-autoButtonSize-ImGui::GetStyle().ItemSpacing.x));
|
||||
if (ImGui::InputText("##SystemName",&e->song.systemName)) {
|
||||
MARK_MODIFIED;
|
||||
updateWindowTitle();
|
||||
e->song.autoSystem=false;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
pushToggleColors(e->song.autoSystem);
|
||||
if (ImGui::Button("Auto")) {
|
||||
e->song.autoSystem=!e->song.autoSystem;
|
||||
if (e->song.autoSystem) {
|
||||
autoDetectSystem();
|
||||
updateWindowTitle();
|
||||
}
|
||||
}
|
||||
popToggleColors();
|
||||
autoButtonSize=ImGui::GetItemRectSize().x;
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
|
|
@ -765,6 +765,9 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
|
|||
if (copyOfFlags!=flags) {
|
||||
if (chan>=0) {
|
||||
e->setSysFlags(chan,copyOfFlags,restart);
|
||||
if (e->song.autoSystem) {
|
||||
autoDetectSystem();
|
||||
}
|
||||
updateWindowTitle();
|
||||
} else {
|
||||
flags=copyOfFlags;
|
||||
|
|
|
@ -82,6 +82,9 @@ void FurnaceGUI::drawSysManager() {
|
|||
DivSystem picked=systemPicker();
|
||||
if (picked!=DIV_SYSTEM_NULL) {
|
||||
e->changeSystem(i,picked,preserveChanPos);
|
||||
if (e->song.autoSystem) {
|
||||
autoDetectSystem();
|
||||
}
|
||||
updateWindowTitle();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
@ -110,6 +113,9 @@ void FurnaceGUI::drawSysManager() {
|
|||
if (!e->addSystem(picked)) {
|
||||
showError("cannot add chip! ("+e->getLastError()+")");
|
||||
}
|
||||
if (e->song.autoSystem) {
|
||||
autoDetectSystem();
|
||||
}
|
||||
updateWindowTitle();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue