From 4894cc121c040c0a5f4294a7e31fd6b844cd1c98 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 02:30:53 -0500 Subject: [PATCH 01/48] SMS: why does this break so many songs --- src/engine/platform/sms.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index d55e9349c..14427072d 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -249,9 +249,9 @@ int DivPlatformSMS::dispatch(DivCommand c) { chan[c.chan].actualNote=c.value; } chan[c.chan].active=true; - if (!parent->song.brokenOutVol2) { + //if (!parent->song.brokenOutVol2) { rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); - } + //} chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; From d4638f886da17461e28f205291d913fc90521168 Mon Sep 17 00:00:00 2001 From: N-SPC700 Date: Mon, 7 Nov 2022 03:20:03 -0500 Subject: [PATCH 02/48] add more info for the systems it's used in --- papers/doc/7-systems/ay8930.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/ay8930.md b/papers/doc/7-systems/ay8930.md index 6d5200cac..0d471bcaf 100644 --- a/papers/doc/7-systems/ay8930.md +++ b/papers/doc/7-systems/ay8930.md @@ -3,7 +3,7 @@ a backwards-compatible successor to the AY-3-8910, with increased volume resolution, duty cycle control, three envelopes and highly configurable noise generator. sadly, this soundchip has only ever observed minimal success, and has remained rather obscure since. -it is known for being used in the Covox Sound Master, which didn't sell well either. +it is best known for being used in the Covox Sound Master, which didn't sell well either. It also observed very minimal success in Merit's CRT-250 machines, but only as a replacement for the AY-3-8910. emulation of this chip in Furnace is now complete thanks to community efforts and hardware testing, which an MSX board called Darky has permitted. From c2f3501b83813f396501af3755ddcfa6deefffb0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 03:46:30 -0500 Subject: [PATCH 03/48] add SeeingRed.fur by TakuikaNinja --- demos/SeeingRed.fur | Bin 0 -> 3204 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/SeeingRed.fur diff --git a/demos/SeeingRed.fur b/demos/SeeingRed.fur new file mode 100644 index 0000000000000000000000000000000000000000..e7c95a535868e8f3e469455efbf7c05918542280 GIT binary patch literal 3204 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 oa9z3nU==k`3eL@s8; Date: Mon, 7 Nov 2022 03:47:27 -0500 Subject: [PATCH 04/48] GUI: update credits --- src/gui/about.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/about.cpp b/src/gui/about.cpp index d5bac49e6..2ce39aa0c 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -91,6 +91,7 @@ const char* aboutLine[]={ "Raijin", "SnugglyBun", "SuperJet Spade", + "TakuikaNinja", "TheDuccinator", "theloredev", "TheRealHedgehogSonic", From c08c66b88ed2ed70e253fe3b3bc78c3c23994feb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 16:32:54 -0500 Subject: [PATCH 05/48] GUI: go back to built-in file picker on Android for now --- src/gui/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 6cf332fc1..7d90c428b 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -40,7 +40,7 @@ #define POWER_SAVE_DEFAULT 0 #endif -#if defined(__HAIKU__) +#if defined(__HAIKU__) || defined(IS_MOBILE) // NFD doesn't support Haiku #define SYS_FILE_DIALOG_DEFAULT 0 #else From 2e0710cacadafd27dc44444ac1e156822491c1f6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 16:46:01 -0500 Subject: [PATCH 06/48] GUI: Android system fonts --- src/gui/settings.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 7d90c428b..f2fe42d7f 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -3082,6 +3082,14 @@ void FurnaceGUI::popAccentColors() { #define SYSTEM_PAT_FONT_PATH_1 "/System/Library/Fonts/SFNSMono.ttf" #define SYSTEM_PAT_FONT_PATH_2 "/System/Library/Fonts/Courier New.ttf" #define SYSTEM_PAT_FONT_PATH_3 "/System/Library/Fonts/Courier New.ttf" +#elif defined(ANDROID) +#define SYSTEM_FONT_PATH_1 "/system/fonts/Roboto-Regular.ttf" +#define SYSTEM_FONT_PATH_2 "/system/fonts/DroidSans.ttf" +#define SYSTEM_FONT_PATH_3 "/system/fonts/DroidSans.ttf" +// ??? +#define SYSTEM_PAT_FONT_PATH_1 "/system/fonts/RobotoMono-Regular.ttf" +#define SYSTEM_PAT_FONT_PATH_2 "/system/fonts/DroidSansMono.ttf" +#define SYSTEM_PAT_FONT_PATH_3 "/system/fonts/CutiveMono.ttf" #else #define SYSTEM_FONT_PATH_1 "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf" #define SYSTEM_FONT_PATH_2 "/usr/share/fonts/TTF/DejaVuSans.ttf" From 15df2ed6bf8a80a7fec3c4b616d703408a93d902 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 17:05:16 -0500 Subject: [PATCH 07/48] GUI: enable settings panel in mobile view --- src/gui/editControls.cpp | 1 + src/gui/gui.cpp | 1 + src/gui/settings.cpp | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 86a7325ec..fe72351a6 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -242,6 +242,7 @@ void FurnaceGUI::drawMobileControls() { ImGui::SameLine(); if (ImGui::Button("Settings")) { mobileMenuOpen=false; + settingsOpen=true; } ImGui::SameLine(); if (ImGui::Button("Log")) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 30cb0850b..43a141892 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3747,6 +3747,7 @@ bool FurnaceGUI::loop() { } globalWinFlags=0; + drawSettings(); drawDebug(); drawLog(); } else { diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index f2fe42d7f..7b3701960 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -239,6 +239,12 @@ void FurnaceGUI::drawSettings() { nextWindow=GUI_WINDOW_NOTHING; } if (!settingsOpen) return; + if (mobileUI) { + ImVec2 setWindowPos=ImVec2(0,0); + ImVec2 setWindowSize=ImVec2(canvasW,canvasH); + ImGui::SetNextWindowPos(setWindowPos); + ImGui::SetNextWindowSize(setWindowSize); + } if (ImGui::Begin("Settings",&settingsOpen,ImGuiWindowFlags_NoDocking|globalWinFlags)) { if (!settingsOpen) { settingsOpen=true; From 184a6bd6b25ade7e57b015f8f34a70fcda30ac21 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 17:22:13 -0500 Subject: [PATCH 08/48] dev123 - store sample loop mode --- papers/format.md | 8 +++++++- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 8 ++++++-- src/engine/sample.h | 7 +++---- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/papers/format.md b/papers/format.md index 8a1f8c7a7..25990f1b4 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: +- 123: Furnace dev123 +- 122: Furnace dev122 - 121: Furnace dev121 - 120: Furnace dev120 - 119: Furnace dev119 @@ -1096,7 +1098,11 @@ size | description | - 9: BRR (SNES) | - 10: VOX | - 16: 16-bit PCM - 3 | reserved + 1 | loop direction (>=123) or reserved + | - 0: forward + | - 0: backward + | - 0: ping-pong + 2 | reserved 4 | loop start | - -1 means no loop 4 | loop end diff --git a/src/engine/engine.h b/src/engine/engine.h index 510ef23a1..5c3aa12e8 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -47,8 +47,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev122" -#define DIV_ENGINE_VERSION 122 +#define DIV_VERSION "dev123" +#define DIV_ENGINE_VERSION 123 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index fdc216ac1..19508f4ca 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2383,11 +2383,15 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (isNewSample) { sample->centerRate=reader.readI(); sample->depth=(DivSampleDepth)reader.readC(); + if (ds.version>=123) { + sample->loopMode=(DivSampleLoopMode)reader.readC(); + } else { + sample->loopMode=DIV_SAMPLE_LOOP_FORWARD; + } // reserved reader.readC(); reader.readC(); - reader.readC(); sample->loopStart=reader.readI(); sample->loopEnd=reader.readI(); @@ -4624,9 +4628,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeI(sample->rate); w->writeI(sample->centerRate); w->writeC(sample->depth); + w->writeC(sample->loopMode); w->writeC(0); // reserved w->writeC(0); - w->writeC(0); w->writeI(sample->loop?sample->loopStart:-1); w->writeI(sample->loop?sample->loopEnd:-1); diff --git a/src/engine/sample.h b/src/engine/sample.h index b0a9e8ac8..9fa11abf3 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -106,10 +106,9 @@ struct DivSample { DivSampleDepth depth; bool loop; // valid values are: - // - 0: No loop - // - 1: Forward loop - // - 2: Backward loop - // - 3: Pingpong loop + // - 0: Forward loop + // - 1: Backward loop + // - 2: Pingpong loop DivSampleLoopMode loopMode; // these are the new data structures. From 133627b325d402ac2006d3576f3ed1ff50ed2805 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 17:35:00 -0500 Subject: [PATCH 09/48] SMS: alleviate Nuked-PSG clicking, part 1 --- src/engine/platform/sms.cpp | 18 ++++++++++++++---- src/engine/platform/sms.h | 3 ++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 14427072d..60cb13c58 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -129,7 +129,7 @@ void DivPlatformSMS::tick(bool sysTick) { if (chan[i].outVol<0) chan[i].outVol=0; // old formula // ((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4; - rWrite(0,0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15)))); + chan[i].writeVol=true; } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { @@ -235,6 +235,12 @@ void DivPlatformSMS::tick(bool sysTick) { chan[3].freqChanged=false; updateSNMode=false; } + for (int i=0; i<4; i++) { + if (chan[i].writeVol) { + rWrite(0,0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15)))); + chan[i].writeVol=false; + } + } } int DivPlatformSMS::dispatch(DivCommand c) { @@ -250,7 +256,9 @@ int DivPlatformSMS::dispatch(DivCommand c) { } chan[c.chan].active=true; //if (!parent->song.brokenOutVol2) { - rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); + chan[c.chan].writeVol=true; + chan[c.chan].outVol=chan[c.chan].vol; + //rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); //} chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) { @@ -276,7 +284,9 @@ int DivPlatformSMS::dispatch(DivCommand c) { if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } - if (chan[c.chan].active) rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); + if (chan[c.chan].active) { + chan[c.chan].writeVol=true; + } } break; case DIV_CMD_GET_VOLUME: @@ -356,7 +366,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { void DivPlatformSMS::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - if (chan[ch].active) rWrite(0,0x90|ch<<5|(isMuted[ch]?15:(15-(chan[ch].outVol&15)))); + if (chan[ch].active) chan[ch].writeVol=true; } void DivPlatformSMS::forceIns() { diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index 0a4b121f1..e636b9d88 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -31,7 +31,7 @@ extern "C" { class DivPlatformSMS: public DivDispatch { struct Channel { int freq, baseFreq, pitch, pitch2, note, actualNote, ins; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, writeVol; signed char vol, outVol; DivMacroInt std; void macroInit(DivInstrument* which) { @@ -52,6 +52,7 @@ class DivPlatformSMS: public DivDispatch { keyOn(false), keyOff(false), inPorta(false), + writeVol(false), vol(15), outVol(15) {} }; From 1d262a97ee7034ac604032d040261f5e824f6330 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 17:45:36 -0500 Subject: [PATCH 10/48] dev124 - critical fix for a sample loading bug --- src/engine/fileOps.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 19508f4ca..0ff766535 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2387,6 +2387,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { sample->loopMode=(DivSampleLoopMode)reader.readC(); } else { sample->loopMode=DIV_SAMPLE_LOOP_FORWARD; + reader.readC(); } // reserved From 06ddf07d48f7c10e5c4119bf31ef6a2a943ae9f5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 17:45:43 -0500 Subject: [PATCH 11/48] dev124 --- src/engine/engine.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 5c3aa12e8..3dd058cf3 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -47,8 +47,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev123" -#define DIV_ENGINE_VERSION 123 +#define DIV_VERSION "dev124" +#define DIV_ENGINE_VERSION 124 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 From 8d8bdfd1f71dcb60b8949be16b3096c9d4126c59 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 18:39:04 -0500 Subject: [PATCH 12/48] dev125 - prepare for ExtCh FM macros --- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 15 +++++++++++++++ src/engine/platform/genesis.cpp | 1 + src/engine/platform/genesis.h | 2 +- src/engine/platform/ym2203.cpp | 1 + src/engine/platform/ym2203.h | 2 +- src/engine/platform/ym2608.cpp | 1 + src/engine/platform/ym2608.h | 2 +- src/engine/platform/ym2610shared.h | 3 ++- src/gui/sysConf.cpp | 31 ++++++++++++++++++++++++++++++ 10 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 3dd058cf3..8f57c5794 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -47,8 +47,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev124" -#define DIV_ENGINE_VERSION 124 +#define DIV_VERSION "dev125" +#define DIV_ENGINE_VERSION 125 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 0ff766535..bc80da32d 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2616,6 +2616,21 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } } + // ExtCh compat flag + if (ds.version<125) { + for (int i=0; isample_rate(chipClock); for (int i=0; i<6; i++) { oscBuf[i]->rate=rate; diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index b51a42343..b93e45ddb 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -91,7 +91,7 @@ class DivPlatformYM2203: public DivPlatformOPN { DivPlatformAY8910* ay; unsigned char sampleBank; - bool extMode; + bool extMode, noExtMacros; unsigned char prescale; friend void putDispatchChip(void*,int); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 79ae95111..a58bad8d6 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1394,6 +1394,7 @@ void DivPlatformYM2608::setFlags(const DivConfig& flags) { ayDiv=32; break; } + noExtMacros=flags.getBool("noExtMacros",false); rate=fm->sample_rate(chipClock); for (int i=0; i<16; i++) { oscBuf[i]->rate=rate; diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 7a9eefa97..f4c101c20 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -106,7 +106,7 @@ class DivPlatformYM2608: public DivPlatformOPN { unsigned char writeRSSOff, writeRSSOn; int globalRSSVolume; - bool extMode; + bool extMode, noExtMacros; unsigned char prescale; double NOTE_OPNB(int ch, int note); diff --git a/src/engine/platform/ym2610shared.h b/src/engine/platform/ym2610shared.h index 3641306ce..4b69920c9 100644 --- a/src/engine/platform/ym2610shared.h +++ b/src/engine/platform/ym2610shared.h @@ -141,7 +141,7 @@ template class DivPlatformYM2610Base: public DivPlatformOPN { unsigned char sampleBank; - bool extMode; + bool extMode, noExtMacros; unsigned char writeADPCMAOff, writeADPCMAOn; int globalADPCMAVolume; @@ -269,6 +269,7 @@ template class DivPlatformYM2610Base: public DivPlatformOPN { chipClock=8000000.0; break; } + noExtMacros=flags.getBool("noExtMacros",false); rate=chipClock/16; for (int i=0; irate=rate; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 967624a5d..79d7344c7 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -32,6 +32,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo case DIV_SYSTEM_YM2612_FRAC_EXT: { int clockSel=flags.getInt("clockSel",0); bool ladder=flags.getBool("ladderEffect",0); + bool noExtMacros=flags.getBool("noExtMacros",false); if (ImGui::RadioButton("NTSC (7.67MHz)",clockSel==0)) { clockSel=0; @@ -56,11 +57,17 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo if (ImGui::Checkbox("Enable DAC distortion",&ladder)) { altered=true; } + if (type==DIV_SYSTEM_YM2612_EXT || type==DIV_SYSTEM_YM2612_FRAC_EXT) { + if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) { + altered=true; + } + } if (altered) { e->lockSave([&]() { flags.set("clockSel",clockSel); flags.set("ladderEffect",ladder); + flags.set("noExtMacros",noExtMacros); }); } break; @@ -439,6 +446,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo case DIV_SYSTEM_YM2610B: case DIV_SYSTEM_YM2610B_EXT: { int clockSel=flags.getInt("clockSel",0); + bool noExtMacros=flags.getBool("noExtMacros",false); if (ImGui::RadioButton("8MHz (Neo Geo MVS)",clockSel==0)) { clockSel=0; @@ -449,9 +457,16 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo altered=true; } + if (type==DIV_SYSTEM_YM2610_EXT || type==DIV_SYSTEM_YM2610_FULL_EXT || type==DIV_SYSTEM_YM2610B_EXT) { + if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) { + altered=true; + } + } + if (altered) { e->lockSave([&]() { flags.set("clockSel",clockSel); + flags.set("noExtMacros",noExtMacros); }); } break; @@ -789,6 +804,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo case DIV_SYSTEM_OPN_EXT: { int clockSel=flags.getInt("clockSel",0); int prescale=flags.getInt("prescale",0); + bool noExtMacros=flags.getBool("noExtMacros",false); ImGui::Text("Clock rate:"); if (ImGui::RadioButton("3.58MHz (NTSC)",clockSel==0)) { @@ -829,10 +845,17 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo altered=true; } + if (type==DIV_SYSTEM_OPN_EXT) { + if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) { + altered=true; + } + } + if (altered) { e->lockSave([&]() { flags.set("clockSel",clockSel); flags.set("prescale",prescale); + flags.set("noExtMacros",noExtMacros); }); } break; @@ -841,6 +864,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo case DIV_SYSTEM_PC98_EXT: { int clockSel=flags.getInt("clockSel",0); int prescale=flags.getInt("prescale",0); + bool noExtMacros=flags.getBool("noExtMacros",false); ImGui::Text("Clock rate:"); if (ImGui::RadioButton("8MHz (Arcade)",clockSel==0)) { @@ -865,10 +889,17 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo altered=true; } + if (type==DIV_SYSTEM_PC98_EXT) { + if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) { + altered=true; + } + } + if (altered) { e->lockSave([&]() { flags.set("clockSel",clockSel); flags.set("prescale",prescale); + flags.set("noExtMacros",noExtMacros); }); } break; From bb6bcab2e363f60c8e26315e4adfe00b2e473464 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 7 Nov 2022 19:09:01 -0500 Subject: [PATCH 13/48] preparing stuff --- src/engine/platform/genesisext.cpp | 1 + src/engine/platform/genesisext.h | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 3e2714101..a1108e419 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -602,6 +602,7 @@ void DivPlatformGenesisExt::reset() { for (int i=0; i<4; i++) { opChan[i]=DivPlatformGenesisExt::OpChannel(); opChan[i].vol=127; + opChan[i].outVol=127; } // channel 3 mode diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index 6f46402f8..c1550f5be 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -28,8 +28,12 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask; - int vol; + int vol, outVol; unsigned char pan; + void macroInit(DivInstrument* which) { + std.init(which); + pitch2=0; + } OpChannel(): freqH(0), freqL(0), @@ -48,6 +52,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { inPorta(false), mask(true), vol(0), + outVol(0), pan(3) {} }; OpChannel opChan[4]; From 3745e0935dbe1cff7a4d9327f49a4a3d1eb22bb9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 8 Nov 2022 18:33:01 -0500 Subject: [PATCH 14/48] YM2612: prototype of ExtCh macros --- src/engine/platform/genesis.cpp | 2 +- src/engine/platform/genesisext.cpp | 62 +++++++++++++++++++++++++++--- src/engine/platform/genesisext.h | 3 +- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 7abfb41a9..85074228e 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -285,7 +285,7 @@ void DivPlatformGenesis::tick(bool sysTick) { chan[i].freqChanged=true; } } else { - if (chan[i].std.arp.had) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11); } diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index a1108e419..6e7897a08 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -52,6 +52,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { chan[2].state.ams=ins->fm.ams; chan[2].state.op[ordch]=ins->fm.op[ordch]; } + + if (noExtMacros) { + opChan[ch].macroInit(NULL); + } else { + opChan[ch].macroInit(ins); + } + if (!opChan[ch].std.vol.will) { + opChan[ch].outVol=opChan[ch].vol; + } unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; @@ -60,7 +69,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { rWrite(baseAddr+0x40,127); } else { if (opChan[ch].insChanged) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); } } if (opChan[ch].insChanged) { @@ -81,6 +90,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { if (c.value!=DIV_NOTE_NULL) { opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].portaPause=false; + opChan[ch].note=c.value; opChan[ch].freqChanged=true; } opChan[ch].keyOn=true; @@ -94,12 +104,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { opChan[ch].vol=c.value; + if (!opChan[ch].std.vol.has) { + opChan[ch].outVol=c.value; + } unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); } break; } @@ -210,7 +223,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); } else if (KVS(2,c.value)) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -393,8 +406,8 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) { rWrite(baseAddr+0x40,127); immWrite(baseAddr+0x40,127); } else if (KVS(2,ordch)) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].vol&0x7f,127)); - immWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127)); + immWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); immWrite(baseAddr+0x40,op.tl); @@ -440,6 +453,42 @@ void DivPlatformGenesisExt::tick(bool sysTick) { DivPlatformGenesis::tick(sysTick); + if (extMode && !noExtMacros) for (int i=0; i<4; i++) { + opChan[i].std.next(); + + if (opChan[i].std.vol.had) { + opChan[i].outVol=VOL_SCALE_LOG_BROKEN(opChan[i].vol,MIN(127,opChan[i].std.vol.val),127); + unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]]; + DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]]; + if (isOpMuted[i]) { + rWrite(baseAddr+ADDR_TL,127); + } else { + if (KVS(2,i)) { + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); + } else { + rWrite(baseAddr+ADDR_TL,op.tl); + } + } + } + + if (opChan[i].std.arp.had) { + if (!opChan[i].inPorta) { + opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11); + } + opChan[i].freqChanged=true; + } + + if (opChan[i].std.pitch.had) { + if (opChan[i].std.pitch.mode) { + opChan[i].pitch2+=opChan[i].std.pitch.val; + CLAMP_VAR(opChan[i].pitch2,-32768,32767); + } else { + opChan[i].pitch2=opChan[i].std.pitch.val; + } + opChan[i].freqChanged=true; + } + } + bool writeNoteOn=false; unsigned char writeMask=2; if (extMode) for (int i=0; i<4; i++) { @@ -527,7 +576,7 @@ void DivPlatformGenesisExt::forceIns() { if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); } else if (KVS(i,j)) { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].vol&0x7f,127)); + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].outVol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); } @@ -601,6 +650,7 @@ void DivPlatformGenesisExt::reset() { for (int i=0; i<4; i++) { opChan[i]=DivPlatformGenesisExt::OpChannel(); + opChan[i].std.setEngine(parent); opChan[i].vol=127; opChan[i].outVol=127; } diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index c1550f5be..fb68ecfff 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -25,7 +25,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { struct OpChannel { DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins; + int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins, note; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask; int vol, outVol; @@ -43,6 +43,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { pitch2(0), portaPauseFreq(0), ins(-1), + note(0), active(false), insChanged(true), freqChanged(false), From d917113ae1085e5f66b9fdbfaf619aaca168be86 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 9 Nov 2022 03:51:34 -0500 Subject: [PATCH 15/48] YM2612: implement op param macros in ExtCh --- src/engine/platform/genesisext.cpp | 59 +++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 6e7897a08..414098765 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -463,11 +463,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) { if (isOpMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (KVS(2,i)) { - rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); - } else { - rWrite(baseAddr+ADDR_TL,op.tl); - } + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); } } @@ -487,6 +483,59 @@ void DivPlatformGenesisExt::tick(bool sysTick) { } opChan[i].freqChanged=true; } + + // param macros + unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]]; + DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]]; + DivMacroInt::IntOp& m=opChan[i].std.op[orderedOps[i]]; + if (m.am.had) { + op.am=m.am.val; + rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); + } + if (m.ar.had) { + op.ar=m.ar.val; + rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); + } + if (m.dr.had) { + op.dr=m.dr.val; + rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); + } + if (m.mult.had) { + op.mult=m.mult.val; + rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); + } + if (m.rr.had) { + op.rr=m.rr.val; + rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); + } + if (m.sl.had) { + op.sl=m.sl.val; + rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); + } + if (m.tl.had) { + op.tl=127-m.tl.val; + if (isOpMuted[i]) { + rWrite(baseAddr+ADDR_TL,127); + } else { + rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); + } + } + if (m.rs.had) { + op.rs=m.rs.val; + rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); + } + if (m.dt.had) { + op.dt=m.dt.val; + rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); + } + if (m.d2r.had) { + op.d2r=m.d2r.val; + rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); + } + if (m.ssg.had) { + op.ssgEnv=m.ssg.val; + rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); + } } bool writeNoteOn=false; From 09574edc9649ca1db689ab8f23117b1ea8926370 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 9 Nov 2022 03:51:40 -0500 Subject: [PATCH 16/48] update bruno_time.fur --- demos/bruno_time.fur | Bin 10806 -> 12286 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/bruno_time.fur b/demos/bruno_time.fur index 0ad2d841eae8b1a9efa9c8e1a7cd6cf684da8e8d..4c8822e796c9d2efcb94cff2692bf13612872111 100644 GIT binary patch literal 12286 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 DG{wGD literal 10806 zcmV-6D#_J&ob7!HbX?V$=Brhu(o&La%bRSMWy`w>1egRm35JBlge^D(NWvo9a;#u1 z+Ll8zS^CbL)8|Z|>F(*7PG=_cbP@st2ur}w#;j&>3>e$s9q*eg%aUcSCCOUn`@ehN zt5=d9xTebkoIx*=N>%T>|Nh_q|L?<@d)2BH%gYy4#P6+IylPp++(njU#jWJm{2Q*i zkuSnwpJiQh#XKuwMGE|Q!)F!X=YO(3{wqH3*x1b)<3MYtl$2`vYvgwvflieWo`Rw%R2U-Evx-+EGzW4mR0T)nty;dgdPVu7dn#7MS5__mQM7bv`LbnIrSXLi z#4o??+jHVeD$1)@tpK&kv1rty;D?zOW)be^JG~ z zB_bdcA?)99<&Br${N4CBt5#N*$8QD$bK+P26|}bK@_0FJy1r`hGWor5RW%lfmoHpd zwQN;&1r~vyEUsL6&&s$~>(X*rapoLBk)sDh#bl>EzPRGvDr)k)XmnXs)jjd@>iB|+ z>gvknKUyjFoJTLv|MOYFRBQhVm;Rc6!-DV1??vKwiJ#ljy`lH-+BtaX~BYl_CG%3po7O#|CUHroX+ulABA=T3J2!{0lB!f$fPk zgyj#|drhuC7Mtb0$fVprEH)YCqvz+qmwgOA8=r?Vve)>B!Mm3|8&h0l>AhLLd>(5K z#(lB>e12)Ai~YQRWm=c%uKxv{Ponex&;GOE`kStk--Gv_$ER7=lW~1d0bU84O0NH+ z{;T>&^{?u2^^p3l`n`Gtul}f>QLiY!TA+Tae&M<X2=qk0!>Jg-*c``^@yc>O9co7GnJ9zNNq zHmNP@L$yt{scQ$Jf1$pFRX@bNudA1My#ku+)SGI9+KFp3E{)xx_9&maeGs}@m8yN9 zvkCZ@fwj?ZgX%6|lIUIPpc_DXj26_!7Uuz_IL%k2~Kfq@~eIq_!hgHU^yVQS7!QZJOssYy_+`S#wHr&6R z)N1hVQC>U2&06Snrz(N`_o<(|@LyLQ>WDgwwKsv{`_%U)@_ZO8?8CJe)L({WR^!!d zb*s9^#lcV140S^7hi2c0eb?i93)cp$vKja$by~IJ=OO&{4n9AkCP3aLYL!9%TwMX= zFV)}T`WyTfKl=mx=s9TOU10lEuj(g%JE;Y~x=H<&i}wfMJ6qL1ssE<_Ui}@s^)dAX z(Q9GL?W!C1`&CeNs$<}MmpY(Es~@K5ZiOlXU%$i(|ET^4s6PR}eG+o6h4%L%3IZym z!YTntK7xLZo1Klfe2xzaL(+3$kxj&FW&cIK}$cK{ro9?%#m=BY5=` z(JzDhZR(7QsXTo9L3b}bqZisLcj-^Gw->kv!NG&j`_n)_t)7LSyaIf$imGf?qzb`7 z3%F^5?S24zC#nBbT?o5849*|ID$hdhCmH+CK!4kS$_D+BDj#-egznlA`3qBG|3`?X zb@oM_+pBTHFps!r;p9R`Y z@Ps4yIa+-SnQNI#d!>k~HMsvJ`1=~fjO<{NyWeEw=R!M@IZgt70NyhZ_yw@v&mHaM zB11g~?5kKo_Nv!`m7VTA#A_6un*-T<>G?JIJxATZ%$w9+5Lt3HC=30y+&f<6?~SSs z$ZS~5LfqA0&p8ZReo1{B{M+_hrTzjut%JO>SNZ`EOTE>f17Y~Dn z7l2;Nyww7~o{aAi#&;9Y^o7X#3lM$F;Q_0#P8p~?4PTe6`)l~klcfF%xZelcO~&UF z5IZ^0TQ_`Q9DMCNz?Xw^6~3>-+M7XDB42X%!$yy(g4S{01uvYcu7t+E1O5eHjvcobd*P#?{5$S< z&vMUy3DR$YwsR0GW1+nW^wtadh1fN2P&Y&SmC*k^>JI$fjC&sg<;S^Syu=#oRaj&f zBE1m!G58q;eaQjiVEY@f!mZdlmg4(H$aeyFKMu;zaKCtsmCwt_dONXl0jXzGcU_=g z4DDZuOZ2}4-`7FDI^6pLbSB94u=$@^FKtFX>;-xpcAYSg?O3fBo^-LAr@jgATZoLm z2%az&^f%CF*8#r)__ra?2JDbEpgJ198-nJVLFELjKT=%)Z@&W3QvrNAR?0_2yv3N6 zy7E0-Z-c&6TPJ}mhQCP0Z$uo{!y6_NeI2OZgX=D2{T%rCdT33exaW z)f`5)+su{rLf(Gny)IC%Mc$|fexkY*_-o;Hi$Hw=d?_1Nma2XOINk&NZqVNh&p8a4 zEl?jo1fM|7c?9?XeE%Epo$G+T3)JVMe(VMT+Ph65FC6DYfXSw z-eZNm5lE@(q~84ioYVsuVa_`Z4b|el9%%0`7<+fq^KL~2F%r_R<1VuSD5?9!e|JDy z;a+wf!PnDwBB+h8f#&ao-z|gwZv#FD7JD7};&te32k38wEkyTq;5Gn!01;e|EOH#H zX#4_1eg(AuLqzWRu+SD{s^{VNV!b`|-tEw09c@be^ecNFx`AacJ7nzx|pyBj>*3_l)&_ur)So5Aw| z_?&b{+rh^X=qrJ!X`t0o_Alsq421wGt&S4z1{e5IS$+=6h z&W%{F8*)pv@CN&vEr`1}f!~Cc4#Dd>4E_}BrBc>=_n_vKoPQ_$D2{dC0Qb)U_aQsR z^`QR_*7^u~Y2j|wgsT;F3P9~9c+E24mqLc`!}p3I+bi5_B-csDxZY4d0&Dd^`?6nj z0Udy*FM;NNjH?1%`~YiR0PB7L^y8ra7QAL7R*}516}l5&_rv!rM4yE#2RZ(7@VpEh zEQI!Ng)C*z&!17NJ&xS7fgR^N`29ZgZ~)d4d;poPmmOCWcV7vei`U-)-WMQ>$K$TG ztkhlvQhG(ndRq{`hoG}ga6bT_>EezX!;U{6I$r|Xcfj^HA`9ig-&SMS`y=x9yTrc> z4QyfN5WEH48K7my9fhp-9ay~retSEpUxmCe07;(${wc)%M)s*2$cOg+1kk-eOQju# z?Y{!N=KLmPudgBNwm@r7;Cdcf+X|^apzmtWlYL4$H6L^k2KUpUy<3@au7?~~Anpp` zm20`*t^ws8pt_YE>27e}0Pe%^ZK+uck^f7;{dGX!iI}+-ynh{W?1zs$i{1VSXixTx zt)Tw_WB4e%ss~v$ALs()m(i#U~V%TX0xc?sTw}Xo-5rba_Pp6Qz9%FCv8l~P!57hWJ;`6{kA?S~V?Jh^$-VP03 zg;$p%2WLb2m)P5_Mg)9F>f0EDB7GM#SB%^jL;CZ9`yQ?SE#k}Infrl%l9kRz&L;NY zdpF*#1^2!9T+l_Z`)F9|LTK$4aBwX&e;N9g68OayU>`@#_agUsjsJ+2ZzDdBz3vEV z?<{6ZrUiOW>pe)}<5qBN%Jkh?Eehj$11XjNpyT&}cx(GW? z5b?Q|9o8Qq#U{|-1MEJ;O)a9mo6;B1@}m7|*fYM36|M&Di$Q%nxZerx9|HZSp?%pk z4@*pZaJ1ls;OtbPq7|1!{Jkg5gV{tRsYM?~(s;QI)&O)b7pQg>l+ zUJSm+f>H@QWiF6cL33Y4_MeV-g1Gl>=uW7wWsN3#V=XR`-3QATAzn(@t4>7LJ0DuR z95S2_NhX7*9&q{^@J}%BZU^;RP_6^-lJSK1F$OyUS1EYD6!CU3wn$gr{M2g#O8;{m@-#c!|p`tnp600g5SxGI}-Rw zkb4q;&V<~Tf%}W_Y6@12fX-$hr9Y9#k)5fY{5O(*l>C>F_wnFj2K?=7SmOfdZZbXz z;$G?Vo`LkQ!V8Z;ccQ%$#&aUDk62w_aY+9)_|2un$H7}4wD%UMKLgvn!5Pv?qrGNi z4c#RRUNkrfn2VtME3n1|(EcRw)(t;<4ftmv!+O>UqPsfkuLHSGdi+t2?PtLE=aK$- z?16F+9ou2`Ke5k!kD0#S&_B(b8wS3Z_Ai0Fvmp6A*#9fYw^OlZ6k6VfeEk9}xDIwW z2F;%$z5)E7VZ9cE*N!vN&obH*-;o~3k9#*m?`uqVQ44fE^(XTrp|AaCyhHzDpf3dV zIMytL_KqW8yvnZpeQ4qoP>qJZ#J$XjMpAnkKO6d!n45-o#&Ys>4D@9pxe>aTOxFg! zMTTa2k8nSR*s=7Y8Q}a&;6nP(k&r$C>%9l`dQjgDy6wOV2Thzw1Yo^F+-c**`@V#z zn~J|jvHv@bT(KUSll^)xcy8x3v=Q&OA$I(nuZ^SUN&JfaXB*8)2i6CUw*mVG_U#W@ zUw46{7W{63?!@-Fpi@FwB?C+Zb|#{399GR`_kEPozsU-<23VOSi4GE=9)x^_r8(27<1jOR>3lug0UiCCo!+|R)4Vs;UIu=I9h zp4Zr;?SjoZfNuluf*$~d0#Ka_#B@-e%vZB%xe@GLyFhUZu&;2YBKTHF-bf#iteFk& zOF(l5^VDRlF`YSQ9D8RU?m3EhUkCgfu)fURPs0KdeWxIW&@Tcl!Iu#~1-hG!pQ61e zwO4~3@-0?~A0qEa#%W;mH8FB?A!jKtvp`>TFb(M0q+bZHl-bJ>X#Z`jAibf~m)dhr zGIIr?z0ssO13!iPGORR%y?YGw{m|5Y@ckyPcd*kQB(?^ZD&F`e}g2zr$0T&CJ@T4EJ{497%tj z!C8squBps;GPlX&)bAv0_AaY)snA4glC>M@`BGyE^;x)V{1nE`XlPHms2*^-1Ne7H z{V-#$5mz&_u27#qZ=VkASZG4_kP^r)x{p9RV*Rb04QxZ+sHN9Q+_WPGg3P&-fEUjj z1CEREJ%+RD9Pk!`^v&Q|I`hq@!bs>FYPKJ{5dByQ6kyja*Kar+|7X^c7>} zCKBX>egynW?9{>IH?dOGc*#4>px;aBM?+gvX?d}BF7cvw;a}#C3D|oF`|_Re!W#B8 z&G_zQtyBoEOToSDP$O7*<#XPsxer2nt;oCEd3q-`+6ii|h15g1Zwz&(ZC7OI%e*v; zGuI$8M>G6Y`ZK|c=eBT#P7}4`>8lcV;~{-6@mlv{JHa<$r<3}42dkxeTD}ch5$;E@ z%9x33DmW2~=dk({&4tNqKtu>ZYzCK(QWsvVIYC&e^hk)Kk z?(3lWc3hq0J{KAvPwFzG^m9I{@gbg<V*tJavx<6l4GXsN0@1)&XA}}K&Jz)T5k-v&tkVOXB(nJ>Hi8jbsYeGnV{Hsv3xsy zFT(Sz@zA{FXdm9|00;V%F~ZXp!HfJd137N8bu;yMhQ3q8T4^k7kcaiUIG+uGlL)9w z?>B<@Q`{%yl4|obIq2bzGlF%>7~a>0oSxUa+1K+-)GQ?5d++wS0x(*CDd zE%mbAkTbQBtd06> zZDR!*A@#AWK*r*eUNgOv6Zykfr=B}zAAMI#FSS`OGh!!wDvued6!eQBOBW~}2jxSY z0cw0Z`};z6m?C|U=Q_=-B63)NPewK?1wMi`8+c-Nh&^hp>9YdlQtLiS?oYG((>57z z_I^35YzIZ*{vadp1pU98(#sAfdu0}+X>myuoXmW#O4OJ&v0oHSs# zkAwG__*q2Xt%dA+L0z)_`-f8&Vep27Xolo|T zK6W`p#OHH&Y2}16M8BOt>8D{GIX9>W&wH@*?7+9ix0%S%(&vK5F7Bm$>|MlfrDrKa z{6$!G9N6qt$g9&`fpaGbj zoNVpjM7!S9nla*I^qnq7Ubm@3N{JWkN#xaX*Ol4WPRLPXxX(4*$GA5ps6CmmjxxHR zL+wewAWy02XLxp#dztP;Ol>F9XW?({JAP9|Y3Zk6Ejc$h;@EBvXR0>$MW(t7Q2J*2 zPJyxA9QN9U>=$I$75dut+IC6l3buwb~7a2P226D_D-4X7^COpvmfrH^rAhHehTrk zIHi$pX}|HEovgT<&5l(--RH3`X*YQ%Y^0yTet9Bf)D_zf){MJ(mXS!YT^=;v%h^K< zXT_sHwT%7hbVw3`U24Gf4obg={mL2Rc_VNYn5wYV7lh*%##UIg$?UIl@=IvHdLi-WZqmw(&$ydR3VXWfPyrioTbg-$dUj zg2lD%Byvac`LIJK>+PiWnpx{c*;(asmeI`}Q+y{2((CR?rVW!JpUhbfI9XFB>aySK zs!lq(F#hUb_bon|ZKejZnD-`vf@JM|PUP5UIl7w8VTYl0-^jf{q%ULK&IP^%cZu)q zb>*E#)~bS!nx|Mq_op~F@bT${X{3H0xEM?A>8JB{((~=J7>$pxo9yJwPU?^_^rd&4 zxwy*Uoj!1On0afb={1GR5PK2bjrY;>PSJO4>1R`V(Vpyi2SItK*)ba^eVCn?bR&MA zrZ-aherRhPY^Jq0gVIaZ-*33z2T9!0M~w8XocKxP6fozD@5rQUv?Kja>Rvp*3G@Q& zgmgDOz#XU2WZe;r`x%^@=soW=eQyUnPoIYLv7?I;9{|stoSI4Ah#=POxR=O_anCzQ z{4VDV*8-iS^u5&HX-c01dzG5Vk$Nl2ytSVvvBLc^W=&grBE65=YvR;Kq%U!}m&nP& zXSLk%we3WDt-Yl5XH3@XrtNLdpT&y7&rWj>ZNG=MZ)Qgzov3uAeo8Mnznweo7$@h8 z?ImwDLgtTXd-2>lR_Yob=6PT*pI~a{IY~aa*Pc5UJWQnaPC44sa{@h+4s#9>0QWuI z?{&2$aj!jZ4)a#Fsh4*1JnI0fr4IIUA)H0z9X&6#YxRSi zQ|x1>iQQQ4Inz0B9S>iUKJTbGg*C>b zy1aut&8#;k8h%4vxbNiLM>_9(lXs?b(m#fMUK6MuWRI%5Y|(x{Pw*{132=t^gqd`Y zr}kuC8wW4h<{6_yq+Y|bz&1{JEIvWeNA6`}+rc_!gwftKGcgU}(+2j~hd3iRN$uHq z{TzbEckzUCl$nlCqx7P^c0N~n*qKo^aV|YzsP|I(gqfM;vC=Oi_oeh5A7>m#`J7FS z>9G^U4}iLG-_4Vv4)%^Q`d%5IYK&v8T&&-0p3oBR>!`gBJ~=T!?tAzgM+awaS*Fq# z{1n(;W{zhd?{VUfaYEHd>j_>{@1gcPXpw9)osensWKO%~WJS*?j*|O&?k-)RtGVxW z@ZIdZM}exG4NT#gpiFoYoKYMz6Sh;#aA$z*C-*kKi#usPYu%~DPr~b5PN(ZR;W`fL zCmnpRp)K0e_&%dOjW6ZdN|dvglSA-bhH^JA(Vw0e+S1DzPYI`n-DW~m!&BswtZdpi zi_=IO-_7nzPx@`?3t7jXcFuB6@M$H%cM^HV!Jpwyl*c}4Ds4B3^C_9`Hu41acnbYa zV$Sdh8qG;RBS-trRN8(tp9XIq7T-aMHC|tqBYhdQH<8-w$GxY>f33kcIQT9HFLPPH zIpvu`yl8I(J79T6tInX^_)ZtThx=$Ar!!MXJ(}yJSb;f@+|MKjW&Ott&(2b_{g!)8E zFSDaISij!zU+eh4)?bgwfEK5+1w7H7Lfw^cV(mAzaJ@mN;?FPx_=pdfr&8iP8J@_= zvYy;En{!C*f3;5hbut53+yUgNXZ>72oR*(po+ckK+CORhSI2K7Po_G_y^s5k-<%YP z_B4JBq_MSUbDzYw@_eC}atHVw;Z$`Z@soH~665@$joR1T>$6;q?;!WG`vzFQ<#4t( z39^gs$3Yf7y-CF%XZ-8v?QtrcjXyJGV^x2~m=^4sSVI(zzw&Eh;i#wVf1 znBc%DBn1h1{vVoouFrf!dNW+TtB>9dAW#AmUK?V$bYjP_~`zLUBO@dPTHeQyD0 z<)d*Gb7mannd}+%5?cNmgKy-?RG+EZZTc}ztBcKPLmp3r`&dn%=JO{>?VUC|f54o+ zCGjITuh#R2EYl0L8ocJe&g{HB^tf#Hd{I8Z9W#@cLNk8|@xP+!U?(?Nd!6PCC(6@1 zp`J&)p8VvS^Xvgr&Dzh;=-hADE&2>E*IfCWn-r0HuIc0Ya9_eikB;0rX3lnI>JU#+ z@`%neGqVDNmOjjK;p?e?JM$)(sl$fvJTr5NnaPWN9&NEAORy8IH@QbgZigd%9;Yq& z1}l@39HK+S>v~r7uj9Xt((6;npqbUg9KK^jXR`|oy6`Oy{W_QSLOcUXqBZTPgVq)4 z8R|cYZ(!Be&0Lw|=uG2tjpRY6p4RoSt-m@)`d((6RD7N}4-PUL_+0h0*564-`YuQM z*bwR=()K&}PWF--f70doK~Abt@%D2Fx}F|zx``$SZ~Kn+d^g^v0?3KgbYCAjMdgGg1wNl81&*Q8)+eA)a5Z>0F8}D;$pO?aY$mCpiAK%6q z-f5%z4yW45=AM~nsJrp@6rp<%_gZ?bz3?D>w)6Z^GG}Y<+jw%)#7Ukleb8t>*G1jN z+y2wz*xtss({_E7K4NMOjZRWe?pR6bo6HkT30CR-#&q&nkrCR7Ue(&bK-Nk*Di+a@14-dk34AOnV z%t-tx-0SDhhLhgyx6LMJ^|7}~;-e1rEK_N@rPtIozRmc(&qyD2&~AKk_Ne!pW>?(U z+=qDy7;#Hh79B+EQ2l|2ZZsy(;gyScaVHvJ@eu=Y9~>D{{TH~)Q*-6;%@ z?;9p=Y};w=MI3y@g-^A;Exq4+W9HsN zbC#cR8yTd#p^=m7xou9)a@)@4J8MYX50>8EZ&Gy^8H5j{cz!ES>TT}N818M|*%6a9 z1V7YvZ7H5-<0C2f)Gi_E`OOaZ{pMUGD}`^j^!`E84~_bu>CV0J{XBE9rEeZ2y~bx5 zbodjbZ+2zueq%eEe%2uR!9n;IgSIpFKnitxr%A=TrEfL(WX4YAK5Q;;?dj)*+fzI* zRbqPuxAu}*)5dqY;>L{*IV&XVjecfLz2meP?vpt$JP4g!VX*dE4fRydv!%87cpLAI zoaByYb8qjqp%iT;@gWcCTMhR;DcpyL!Mmlm|Lc$>_q`7Hwzk~(P)g+3d83u+_LPhr zc4^y?@fJZ zwWcpO_rW352Xk+!z7%{Sh5KL%+Ry21Qh#pkbx{8aPQuSPyM1sF+Q!@Gyvg&vgt_cF z{(yb&O_zW7X3O=JWBDzgmHa2+-2Xh>aIbT$z_9mcY8{`)`(Cg8Y2P0l_Wn$*ldc}J z)4qRrJ~OpWy88dD`A@ofu#y3x|4qZsnnMNCTqm5i0f)ao-F3nl(!=N7p|aAxe|Wl? zTIb&p5c=Oh_EMzx`{@}ZQ|ovM>ZM5U_tP^-rq=Pwyj}t1{eF6Zn5lKV5|vjX@qT}J zy6LXt#g7;No;zPMAoRb=>*Z+P?`LYu&dmDf+L668RA$yc*N*J<`rHTH=YxMIAl&~5 z^za0SUpU>@nOY~9<~m-PDBahYS|?pS_%cK{Q|qLwe=m8x^qJ%7$my+}PB#O3Z*A$l@70TVz4q>1 z&h0wh&HQJ}!P9*|nkHSZ`_uJ9uls#gD6RKh0ik;cudU?s@_wcq^V51i{igJb_cQsv z6AM%=|9PU(0hd6tG4oF z@UvCJe%2f$eM4nt=R4Qycu#NA^B=GK)Ad8I`-5q|?+OUrLwIdHpO^PD<(Qw=`|0kW zU%a2$_nm+k?*HreTtsrF*71t)aE3CA*K6-%D?qqU&8TWUBJWjD0<) zSjm9+_#VRRb-E0m&HbL+*;xphu3^(1@10F4ayDzG%V(wn`fTq1EbISl*8g|Om<)*I z|DXGC3w&Dh@pNn9OgZ?uUMJm}H(leO>vg;mTc#4^xn9R}{bWESi>BcSW@?K+*QLUz zRl=paj+djQOE=v|7S8o+_cKE7S%3CfyzlO-yxw=q>-B#2S-kJobBeD159GV_|3oa2 AApigX From 3275d92f999abb61cd16af12d89e532fad8dda27 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 9 Nov 2022 03:52:49 -0500 Subject: [PATCH 17/48] MOD import: handle Cxx with vol higher than 64 --- src/engine/fileOps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index bc80da32d..a5502040b 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2966,7 +2966,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { writeFxCol(fxTyp,fxVal); break; case 12: // set vol - data[row][3]=fxVal; + data[row][3]=MIN(0x40,fxVal); break; case 13: // break to row (BCD) writeFxCol(fxTyp,((fxVal>>4)*10)+(fxVal&15)); From a90cb2e0116376b228ada9ee40deaea0ea66ec25 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 9 Nov 2022 13:42:28 -0500 Subject: [PATCH 18/48] YM2612: macro release --- src/engine/platform/genesisext.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 414098765..42dba6f4b 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -102,6 +102,17 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { opChan[ch].keyOn=false; opChan[ch].active=false; break; + case DIV_CMD_NOTE_OFF_ENV: + if (noExtMacros) break; + opChan[ch].keyOff=true; + opChan[ch].keyOn=false; + opChan[ch].active=false; + opChan[ch].std.release(); + break; + case DIV_CMD_ENV_RELEASE: + if (noExtMacros) break; + opChan[ch].std.release(); + break; case DIV_CMD_VOLUME: { opChan[ch].vol=c.value; if (!opChan[ch].std.vol.has) { From 1ebc6aaab4ae7a8d4d61b8b2bee5a020f05084b5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 9 Nov 2022 14:45:58 -0500 Subject: [PATCH 19/48] enough furnace tracker the name is Furnace --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 000c66100..e5573b4ba 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Furnace Tracker +# Furnace (chiptune tracker) ![screenshot](papers/screenshot2.png) From 2c1a1b20de17c888d6ee0e6510ae2364bf8a4f12 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 9 Nov 2022 23:24:03 -0500 Subject: [PATCH 20/48] YM2612: fix ExtCh macro one-tick delay --- src/engine/platform/genesisext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 42dba6f4b..45a8898db 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -462,8 +462,6 @@ void DivPlatformGenesisExt::tick(bool sysTick) { } } - DivPlatformGenesis::tick(sysTick); - if (extMode && !noExtMacros) for (int i=0; i<4; i++) { opChan[i].std.next(); @@ -549,6 +547,8 @@ void DivPlatformGenesisExt::tick(bool sysTick) { } } + DivPlatformGenesis::tick(sysTick); + bool writeNoteOn=false; unsigned char writeMask=2; if (extMode) for (int i=0; i<4; i++) { From d944b979133bc06496cc2795413a4cdb193586f5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 9 Nov 2022 23:32:56 -0500 Subject: [PATCH 21/48] Watching Paint Dry by Burnt Fishy --- demos/watching_paint_dry.fur | Bin 0 -> 11324 bytes src/gui/about.cpp | 1 + 2 files changed, 1 insertion(+) create mode 100644 demos/watching_paint_dry.fur diff --git a/demos/watching_paint_dry.fur b/demos/watching_paint_dry.fur new file mode 100644 index 0000000000000000000000000000000000000000..6023ce4d9f48a442b51f35791b58b95c3f58e0d3 GIT binary patch literal 11324 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 Date: Wed, 9 Nov 2022 23:52:10 -0500 Subject: [PATCH 22/48] fix metronome in virtual tempo --- src/engine/engine.cpp | 1 + src/engine/engine.h | 3 ++- src/engine/playback.cpp | 23 +++++++++++++---------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index aab6b1188..55d3ad1a4 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2358,6 +2358,7 @@ void DivEngine::reset() { firstTick=false; shallStop=false; shallStopSched=false; + pendingMetroTick=0; nextSpeed=speed1; divider=60; if (curSubSong->customTempo) { diff --git a/src/engine/engine.h b/src/engine/engine.h index 8f57c5794..7bd0ae2e1 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -358,7 +358,7 @@ class DivEngine { double clockDrift; int stepPlay; int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch; - unsigned char extValue; + unsigned char extValue, pendingMetroTick; unsigned char speed1, speed2; short tempoAccum; DivStatusView view; @@ -1073,6 +1073,7 @@ class DivEngine { cmdsPerSecond(0), globalPitch(0), extValue(0), + pendingMetroTick(0), speed1(3), speed2(3), tempoAccum(0), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 24fc92389..708c55105 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -963,6 +963,13 @@ void DivEngine::nextRow() { printf("| %.2x:%s | \x1b[1;33m%3d%s\x1b[m\n",curOrder,pb1,curRow,pb3); } + if (curSubSong->hilightA>0) { + if ((curRow%curSubSong->hilightA)==0) pendingMetroTick=1; + } + if (curSubSong->hilightB>0) { + if ((curRow%curSubSong->hilightB)==0) pendingMetroTick=2; + } + prevOrder=curOrder; prevRow=curRow; @@ -1597,16 +1604,6 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi // 2. check whether we gonna tick if (cycles<=0) { // we have to tick - if (!freelance && stepPlay!=-1 && subticks==1) { - unsigned int realPos=size-(runLeftG>>MASTER_CLOCK_PREC); - if (realPos>=size) realPos=size-1; - if (curSubSong->hilightA>0) { - if ((curRow%curSubSong->hilightA)==0 && ticks==1) metroTick[realPos]=1; - } - if (curSubSong->hilightB>0) { - if ((curRow%curSubSong->hilightB)==0 && ticks==1) metroTick[realPos]=2; - } - } if (nextTick()) { lastLoopPos=size-(runLeftG>>MASTER_CLOCK_PREC); logD("last loop pos: %d for a size of %d and runLeftG of %d",lastLoopPos,size,runLeftG); @@ -1623,6 +1620,12 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } } + if (pendingMetroTick) { + unsigned int realPos=size-(runLeftG>>MASTER_CLOCK_PREC); + if (realPos>=size) realPos=size-1; + metroTick[realPos]=pendingMetroTick; + pendingMetroTick=0; + } } else { // 3. tick the clock and fill buffers as needed if (cycles Date: Thu, 10 Nov 2022 01:26:59 -0500 Subject: [PATCH 23/48] GUI: add a clock --- CMakeLists.txt | 1 + src/engine/engine.cpp | 10 ++++ src/engine/engine.h | 8 ++- src/engine/playback.cpp | 11 +++- src/gui/clock.cpp | 116 ++++++++++++++++++++++++++++++++++++++++ src/gui/gui.cpp | 12 +++++ src/gui/gui.h | 14 ++++- src/gui/guiConst.cpp | 5 ++ 8 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 src/gui/clock.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7869c57b7..10294d3e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -571,6 +571,7 @@ src/gui/guiConst.cpp src/gui/about.cpp src/gui/channels.cpp src/gui/chanOsc.cpp +src/gui/clock.cpp src/gui/compatFlags.cpp src/gui/cursor.cpp src/gui/dataList.cpp diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 55d3ad1a4..630fba01f 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2359,6 +2359,8 @@ void DivEngine::reset() { shallStop=false; shallStopSched=false; pendingMetroTick=0; + elapsedBars=0; + elapsedBeats=0; nextSpeed=speed1; divider=60; if (curSubSong->customTempo) { @@ -2547,6 +2549,14 @@ int DivEngine::getRow() { return prevRow; } +int DivEngine::getElapsedBars() { + return elapsedBars; +} + +int DivEngine::getElapsedBeats() { + return elapsedBeats; +} + size_t DivEngine::getCurrentSubSong() { return curSubSongIndex; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 7bd0ae2e1..fc3e43998 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -351,7 +351,7 @@ class DivEngine { bool midiOutClock; int midiOutMode; int softLockCount; - int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed; + int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats; size_t curSubSongIndex; double divider; int cycles; @@ -709,6 +709,10 @@ class DivEngine { // get current row int getRow(); + // get beat/bar + int getElapsedBars(); + int getElapsedBeats(); + // get current subsong size_t getCurrentSubSong(); @@ -1058,6 +1062,8 @@ class DivEngine { lastLoopPos(0), exportLoopCount(0), nextSpeed(3), + elapsedBars(0), + elapsedBeats(0), curSubSongIndex(0), divider(60), cycles(0), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 708c55105..442cd7bfb 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -964,10 +964,17 @@ void DivEngine::nextRow() { } if (curSubSong->hilightA>0) { - if ((curRow%curSubSong->hilightA)==0) pendingMetroTick=1; + if ((curRow%curSubSong->hilightA)==0) { + pendingMetroTick=1; + elapsedBeats++; + } } if (curSubSong->hilightB>0) { - if ((curRow%curSubSong->hilightB)==0) pendingMetroTick=2; + if ((curRow%curSubSong->hilightB)==0) { + pendingMetroTick=2; + elapsedBars++; + elapsedBeats=0; + } } prevOrder=curOrder; diff --git a/src/gui/clock.cpp b/src/gui/clock.cpp new file mode 100644 index 000000000..e8450d10a --- /dev/null +++ b/src/gui/clock.cpp @@ -0,0 +1,116 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "gui.h" +#include "imgui_internal.h" +#include "imgui.h" + +void FurnaceGUI::drawClock() { + if (nextWindow==GUI_WINDOW_CLOCK) { + clockOpen=true; + ImGui::SetNextWindowFocus(); + nextWindow=GUI_WINDOW_NOTHING; + } + if (!clockOpen) return; + if (ImGui::Begin("Clock",&clockOpen,globalWinFlags)) { + int row=e->getRow(); + int elapsedBars=e->getElapsedBars(); + int elapsedBeats=e->getElapsedBeats(); + bool playing=e->isPlaying(); + if (clockShowRow) { + ImGui::PushFont(bigFont); + ImGui::Text("%.3d:%.3d",e->getOrder(),row); + ImGui::PopFont(); + } + if (clockShowBeat) { + ImGui::PushFont(bigFont); + ImGui::Text("%.3d:%.1d",elapsedBars,elapsedBeats+1); + ImGui::PopFont(); + } + if (clockShowMetro) { + ImDrawList* dl=ImGui::GetWindowDrawList(); + ImGuiWindow* window=ImGui::GetCurrentWindow(); + ImVec2 size=ImGui::GetContentRegionAvail(); + size.y=12.0f*dpiScale; + + ImVec2 minArea=window->DC.CursorPos; + ImVec2 maxArea=ImVec2( + minArea.x+size.x, + minArea.y+size.y + ); + ImRect rect=ImRect(minArea,maxArea); + /*ImRect inRect=rect; + inRect.Min.x+=dpiScale; + inRect.Min.y+=dpiScale; + inRect.Max.x-=dpiScale; + inRect.Max.y-=dpiScale;*/ + ImGuiStyle& style=ImGui::GetStyle(); + ImGui::ItemSize(size,style.FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID("metroQ"))) { + int h1=e->curSubSong->hilightA; + int h2=e->curSubSong->hilightB; + if (h1>0 && h2>0) { + int beats=(h2+(h1-1))/h1; + if (beats<0) beats=1; + if (beats>16) beats=16; + if (playing) { + if (elapsedBeats!=oldBeat || elapsedBars!=oldBar) { + if (elapsedBeats>15) elapsedBeats=15; + clockMetroTick[elapsedBeats]=1.0f; + oldBeat=elapsedBeats; + oldBar=elapsedBars; + } + } else { + oldBeat=-1; + oldBar=-1; + } + for (int i=0; iAddQuadFilled( + ImLerp(minB,maxB,ImVec2(0.35f,0.0f)), + ImLerp(minB,maxB,ImVec2(0.9f,0.0f)), + ImLerp(minB,maxB,ImVec2(0.65f,1.0f)), + ImLerp(minB,maxB,ImVec2(0.1f,1.0f)), + ImGui::GetColorU32(col) + ); + + if (elapsedBeats==i && playing) { + clockMetroTick[i]-=0.1f*ImGui::GetIO().DeltaTime*60.0f; + if (clockMetroTick[i]<0.3f) clockMetroTick[i]=0.3f; + } else { + clockMetroTick[i]-=0.1f*ImGui::GetIO().DeltaTime*60.0f; + if (clockMetroTick[i]<0.0f) clockMetroTick[i]=0.0f; + } + } + } + } + } + if (clockShowTime) { + int totalTicks=e->getTotalTicks(); + int totalSeconds=e->getTotalSeconds(); + ImGui::PushFont(bigFont); + ImGui::Text("%.2d:%.2d.%.2d",(totalSeconds/60),totalSeconds%60,totalTicks/10000); + ImGui::PopFont(); + } + } + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SPOILER; + ImGui::End(); +} diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 43a141892..1ae6e1730 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3620,6 +3620,7 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("oscilloscope (master)",BIND_FOR(GUI_ACTION_WINDOW_OSCILLOSCOPE),oscOpen)) oscOpen=!oscOpen; if (ImGui::MenuItem("oscilloscope (per-channel)",BIND_FOR(GUI_ACTION_WINDOW_CHAN_OSC),chanOscOpen)) chanOscOpen=!chanOscOpen; if (ImGui::MenuItem("volume meter",BIND_FOR(GUI_ACTION_WINDOW_VOL_METER),volMeterOpen)) volMeterOpen=!volMeterOpen; + if (ImGui::MenuItem("clock",BIND_FOR(GUI_ACTION_WINDOW_CLOCK),clockOpen)) clockOpen=!clockOpen; if (ImGui::MenuItem("register view",BIND_FOR(GUI_ACTION_WINDOW_REGISTER_VIEW),regViewOpen)) regViewOpen=!regViewOpen; if (ImGui::MenuItem("log viewer",BIND_FOR(GUI_ACTION_WINDOW_LOG),logOpen)) logOpen=!logOpen; if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen; @@ -3783,6 +3784,7 @@ bool FurnaceGUI::loop() { drawChannels(); drawPatManager(); drawSysManager(); + drawClock(); drawRegView(); drawLog(); drawEffectList(); @@ -5021,6 +5023,7 @@ bool FurnaceGUI::init() { channelsOpen=e->getConfBool("channelsOpen",false); patManagerOpen=e->getConfBool("patManagerOpen",false); sysManagerOpen=e->getConfBool("sysManagerOpen",false); + clockOpen=e->getConfBool("clockOpen",false); regViewOpen=e->getConfBool("regViewOpen",false); logOpen=e->getConfBool("logOpen",false); effectListOpen=e->getConfBool("effectListOpen",false); @@ -5384,6 +5387,7 @@ bool FurnaceGUI::finish() { e->setConf("channelsOpen",channelsOpen); e->setConf("patManagerOpen",patManagerOpen); e->setConf("sysManagerOpen",sysManagerOpen); + e->setConf("clockOpen",clockOpen); e->setConf("regViewOpen",regViewOpen); e->setConf("logOpen",logOpen); e->setConf("effectListOpen",effectListOpen); @@ -5572,6 +5576,8 @@ FurnaceGUI::FurnaceGUI(): dragSourceY(0), dragDestinationX(0), dragDestinationY(0), + oldBeat(-1), + oldBar(-1), exportFadeOut(5.0), editControlsOpen(true), ordersOpen(true), @@ -5604,6 +5610,12 @@ FurnaceGUI::FurnaceGUI(): spoilerOpen(false), patManagerOpen(false), sysManagerOpen(false), + clockOpen(false), + clockShowReal(true), + clockShowRow(true), + clockShowBeat(true), + clockShowMetro(true), + clockShowTime(true), selecting(false), selectingFull(false), dragging(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index e1672a8e8..c65931265 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -243,6 +243,10 @@ enum FurnaceGUIColors { GUI_COLOR_PIANO_KEY_BOTTOM_ACTIVE, GUI_COLOR_PIANO_KEY_TOP_ACTIVE, + GUI_COLOR_CLOCK_TEXT, + GUI_COLOR_CLOCK_BEAT_LOW, + GUI_COLOR_CLOCK_BEAT_HIGH, + GUI_COLOR_LOGLEVEL_ERROR, GUI_COLOR_LOGLEVEL_WARNING, GUI_COLOR_LOGLEVEL_INFO, @@ -285,6 +289,7 @@ enum FurnaceGUIWindows { GUI_WINDOW_CHAN_OSC, GUI_WINDOW_SUBSONGS, GUI_WINDOW_FIND, + GUI_WINDOW_CLOCK, GUI_WINDOW_SPOILER }; @@ -425,6 +430,7 @@ enum FurnaceGUIActions { GUI_ACTION_WINDOW_CHAN_OSC, GUI_ACTION_WINDOW_SUBSONGS, GUI_ACTION_WINDOW_FIND, + GUI_ACTION_WINDOW_CLOCK, GUI_ACTION_COLLAPSE_WINDOW, GUI_ACTION_CLOSE_WINDOW, @@ -1367,7 +1373,7 @@ class FurnaceGUI { int curIns, curWave, curSample, curOctave, curOrder, prevIns, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan, soloTimeout, orderEditMode, orderCursor; int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget, newSongCategory, latchTarget; - int wheelX, wheelY, dragSourceX, dragSourceY, dragDestinationX, dragDestinationY; + int wheelX, wheelY, dragSourceX, dragSourceY, dragDestinationX, dragDestinationY, oldBeat, oldBar; double exportFadeOut; @@ -1375,7 +1381,10 @@ class FurnaceGUI { bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen; - bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen; + bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen, clockOpen; + + bool clockShowReal, clockShowRow, clockShowBeat, clockShowMetro, clockShowTime; + float clockMetroTick[16]; SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd; bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI; @@ -1717,6 +1726,7 @@ class FurnaceGUI { void drawSubSongs(); void drawFindReplace(); void drawSpoiler(); + void drawClock(); void parseKeybinds(); void promptKey(int which); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 4aa83fce3..5b8c5dc7d 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -513,6 +513,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WINDOW_CHAN_OSC", "Oscilloscope (per-channel)", 0), D("WINDOW_SUBSONGS", "Subsongs", 0), D("WINDOW_FIND", "Find/Replace", FURKMOD_CMD|SDLK_f), + D("WINDOW_CLOCK", "Clock", 0), D("COLLAPSE_WINDOW", "Collapse/expand current window", 0), D("CLOSE_WINDOW", "Close current window", FURKMOD_SHIFT|SDLK_ESCAPE), @@ -874,6 +875,10 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_PIANO_KEY_BOTTOM_ACTIVE,"",ImVec4(0.5f,0.5f,0.5f,1.0f)), D(GUI_COLOR_PIANO_KEY_TOP_ACTIVE,"",ImVec4(0.4f,0.4f,0.4f,1.0f)), + D(GUI_COLOR_CLOCK_TEXT,"",ImVec4(1.0f,1.0f,1.0f,1.0f)), + D(GUI_COLOR_CLOCK_BEAT_LOW,"",ImVec4(0.1f,0.13f,0.25f,1.0f)), + D(GUI_COLOR_CLOCK_BEAT_HIGH,"",ImVec4(0.5f,0.8f,1.0f,1.0f)), + D(GUI_COLOR_LOGLEVEL_ERROR,"",ImVec4(1.0f,0.2f,0.2f,1.0f)), D(GUI_COLOR_LOGLEVEL_WARNING,"",ImVec4(1.0f,1.0f,0.2f,1.0f)), D(GUI_COLOR_LOGLEVEL_INFO,"",ImVec4(0.4f,1.0f,0.4f,1.0f)), From 69bb628a8b9dad0ee48a44fdd7dffc9f59118f94 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 10 Nov 2022 04:48:15 -0500 Subject: [PATCH 24/48] PC speaker: add PC-98 clock rate options --- src/engine/platform/pcspkr.cpp | 12 +++++++++++- src/gui/sysConf.cpp | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 42a9ac5cb..226ee98ca 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -587,7 +587,17 @@ bool DivPlatformPCSpeaker::keyOffAffectsArp(int ch) { } void DivPlatformPCSpeaker::setFlags(const DivConfig& flags) { - chipClock=COLOR_NTSC/3.0; + switch (flags.getInt("clockSel",0)) { + case 1: // PC-98 + chipClock=38400*52; + break; + case 2: // PC-98 + chipClock=38400*64; + break; + default: // IBM PC + chipClock=COLOR_NTSC/3.0; + break; + } rate=chipClock/PCSPKR_DIVIDER; speakerType=flags.getInt("speakerType",0)&3; oscBuf->rate=rate; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 79d7344c7..f1b6822f0 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -683,8 +683,23 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo break; } case DIV_SYSTEM_PCSPKR: { + int clockSel=flags.getInt("clockSel",0); int speakerType=flags.getInt("speakerType",0); + ImGui::Text("Clock rate:"); + if (ImGui::RadioButton("1.19MHz (PC)",clockSel==0)) { + clockSel=0; + altered=true; + } + if (ImGui::RadioButton("1.99MHz (PC-98)",clockSel==1)) { + clockSel=1; + altered=true; + } + if (ImGui::RadioButton("2.46MHz (PC-98)",clockSel==2)) { + clockSel=2; + altered=true; + } + ImGui::Text("Speaker type:"); if (ImGui::RadioButton("Unfiltered",speakerType==0)) { speakerType=0; @@ -705,6 +720,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo if (altered) { e->lockSave([&]() { + flags.set("clockSel",clockSel); flags.set("speakerType",speakerType); }); } From e4054348f4e793ef47e7ff48a0dbadf6db717669 Mon Sep 17 00:00:00 2001 From: ZeroByteOrg Date: Thu, 10 Nov 2022 12:40:17 -0600 Subject: [PATCH 25/48] Fix ZSM export to emit LFO AMD/PMD initialization on YM2151 --- src/engine/zsmOps.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/engine/zsmOps.cpp b/src/engine/zsmOps.cpp index 21ffd5ecb..f5fa83090 100644 --- a/src/engine/zsmOps.cpp +++ b/src/engine/zsmOps.cpp @@ -94,10 +94,12 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) { if (VERA >= 0) disCont[VERA].dispatch->toggleRegisterDump(true); if (YM >= 0) { disCont[YM].dispatch->toggleRegisterDump(true); - zsm.writeYM(0x18,0); // initialize the LFO freq to 0 - // note - I think there's a bug where Furnace writes AMD/PMD=max - // that shouldn't be there, requiring this initialization that shouldn't - // be there for ZSM. + // emit LFO initialization commands + zsm.writeYM(0x18,0); // freq = 0 + zsm.writeYM(0x19,0x7F); // AMD = 7F + zsm.writeYM(0x19,0xFF); // PMD = 7F + // TODO: incorporate the Furnace meta-command for init data and filter + // out writes to otherwise-unused channels. } while (!done) { From 4a0b7e941f3a66e9307cd522b5a95041c2f639ae Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 10 Nov 2022 15:11:17 -0500 Subject: [PATCH 26/48] GUI: Android scaling weirdness --- src/gui/scaling.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/scaling.cpp b/src/gui/scaling.cpp index aee55c8c0..713aab7cf 100644 --- a/src/gui/scaling.cpp +++ b/src/gui/scaling.cpp @@ -201,6 +201,8 @@ double getScaleFactor(const char* driverHint) { if (SDL_GetDisplayDPI(0,&dpiScaleF,NULL,NULL)==0) { ret=round(dpiScaleF/192.0f); if (ret<1) ret=1; + logI("dpiScaleF: %f",dpiScaleF); + logI("ret: %f",ret); } #else From be781ef8d457521d40032d079187a69cc6256a53 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 10 Nov 2022 15:16:56 -0500 Subject: [PATCH 27/48] GUI: fix --- src/gui/scaling.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/scaling.cpp b/src/gui/scaling.cpp index 713aab7cf..7c42a1e33 100644 --- a/src/gui/scaling.cpp +++ b/src/gui/scaling.cpp @@ -197,9 +197,9 @@ double getScaleFactor(const char* driverHint) { // SDL fallback #ifdef ANDROID - float dpiScaleF=192.0f; + float dpiScaleF=160.0f; if (SDL_GetDisplayDPI(0,&dpiScaleF,NULL,NULL)==0) { - ret=round(dpiScaleF/192.0f); + ret=dpiScaleF/160.0f; if (ret<1) ret=1; logI("dpiScaleF: %f",dpiScaleF); logI("ret: %f",ret); From 700b32c3ab8eedefb41bc4d69841b813d183d3a7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 10 Nov 2022 16:47:53 -0500 Subject: [PATCH 28/48] GUI: commit state on Android when entering bg --- src/gui/gui.cpp | 19 ++++++++++++------- src/gui/gui.h | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 1ae6e1730..13b4a2d41 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2652,7 +2652,8 @@ int _processEvent(void* instance, SDL_Event* event) { int FurnaceGUI::processEvent(SDL_Event* ev) { #ifdef IS_MOBILE if (ev->type==SDL_APP_WILLENTERBACKGROUND) { - // TODO: save "last state" and potentially suspend engine + commitState(); + e->saveConf(); } #endif if (ev->type==SDL_KEYDOWN) { @@ -5337,15 +5338,10 @@ bool FurnaceGUI::init() { return true; } -bool FurnaceGUI::finish() { +void FurnaceGUI::commitState() { if (!mobileUI) { ImGui::SaveIniSettingsToDisk(finalLayoutPath); } - ImGui_ImplSDLRenderer_Shutdown(); - ImGui_ImplSDL2_Shutdown(); - ImGui::DestroyContext(); - SDL_DestroyRenderer(sdlRend); - SDL_DestroyWindow(sdlWin); e->setConf("configVersion",(int)DIV_ENGINE_VERSION); @@ -5459,6 +5455,15 @@ bool FurnaceGUI::finish() { e->setConf(key,recentFile[i]); } } +} + +bool FurnaceGUI::finish() { + commitState(); + ImGui_ImplSDLRenderer_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + SDL_DestroyRenderer(sdlRend); + SDL_DestroyWindow(sdlWin); for (int i=0; i Date: Thu, 10 Nov 2022 16:53:18 -0500 Subject: [PATCH 29/48] GUI: more mobile tweaks --- src/gui/gui.cpp | 8 +++++++- src/gui/settings.cpp | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 13b4a2d41..a11b13525 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2651,7 +2651,9 @@ int _processEvent(void* instance, SDL_Event* event) { int FurnaceGUI::processEvent(SDL_Event* ev) { #ifdef IS_MOBILE - if (ev->type==SDL_APP_WILLENTERBACKGROUND) { + if (ev->type==SDL_APP_TERMINATING) { + // TODO: save last song state here + } else if (ev->type==SDL_APP_WILLENTERBACKGROUND) { commitState(); e->saveConf(); } @@ -2959,7 +2961,11 @@ bool FurnaceGUI::detectOutOfBoundsWindow() { } bool FurnaceGUI::loop() { +#ifdef IS_MOBILE + bool doThreadedInput=true; +#else bool doThreadedInput=!settings.noThreadedInput; +#endif if (doThreadedInput) { logD("key input: event filter"); SDL_SetEventFilter(_processEvent,this); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 7b3701960..58e66eb28 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -528,6 +528,7 @@ void FurnaceGUI::drawSettings() { ImGui::SetTooltip("saves power by lowering the frame rate to 2fps when idle.\nmay cause issues under Mesa drivers!"); } +#ifndef IS_MOBILE bool noThreadedInputB=settings.noThreadedInput; if (ImGui::Checkbox("Disable threaded input (restart after changing!)",&noThreadedInputB)) { settings.noThreadedInput=noThreadedInputB; @@ -543,6 +544,7 @@ void FurnaceGUI::drawSettings() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("remembers the window's last position on startup."); } +#endif bool blankInsB=settings.blankIns; if (ImGui::Checkbox("New instruments are blank",&blankInsB)) { From 692d95664a845e0667cb117a6e847a61ced91a94 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 10 Nov 2022 16:56:28 -0500 Subject: [PATCH 30/48] GUI: enable power save on mobile --- src/gui/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 58e66eb28..02cd387cf 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -33,7 +33,7 @@ #define DEFAULT_NOTE_KEYS "5:7;6:4;7:3;8:16;10:6;11:8;12:24;13:10;16:11;17:9;18:26;19:28;20:12;21:17;22:1;23:19;24:23;25:5;26:14;27:2;28:21;29:0;30:100;31:13;32:15;34:18;35:20;36:22;38:25;39:27;43:100;46:101;47:29;48:31;53:102;" -#if defined(_WIN32) || defined(__APPLE__) +#if defined(_WIN32) || defined(__APPLE__) || defined(IS_MOBILE) #define POWER_SAVE_DEFAULT 1 #else // currently off on Linux/other due to Mesa catch-up behavior. From bf5b088a540b1da29f4194bf5ed021358decfe97 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 10 Nov 2022 17:27:50 -0500 Subject: [PATCH 31/48] GUI: "fix" piano being clickable under windows --- src/gui/piano.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gui/piano.cpp b/src/gui/piano.cpp index 1e606d774..a100e3ba1 100644 --- a/src/gui/piano.cpp +++ b/src/gui/piano.cpp @@ -219,11 +219,14 @@ void FurnaceGUI::drawPiano() { // render piano //ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); if (ImGui::ItemAdd(rect,ImGui::GetID("pianoDisplay"))) { - ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay")); + bool canInput=false; + if (ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay"))) { + canInput=true; + } if (view) { int notes=oct*12; // evaluate input - for (TouchPoint& i: activePoints) { + if (canInput) for (TouchPoint& i: activePoints) { if (rect.Contains(ImVec2(i.x,i.y))) { int note=(((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*notes)+12*off; if (note<0) continue; From c7b2227ee0173476a4228c38d57fa7e1858795c0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 10 Nov 2022 19:21:01 -0500 Subject: [PATCH 32/48] GUI: prepare to add more macro editor layouts --- src/gui/gui.h | 3 + src/gui/insEdit.cpp | 1040 +++++++++++++++++++++++------------------- src/gui/settings.cpp | 20 + 3 files changed, 582 insertions(+), 481 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 996fe1482..422bf856d 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1222,6 +1222,7 @@ class FurnaceGUI { int persistFadeOut; int exportLoops; double exportFadeOut; + int macroLayout; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -1352,6 +1353,7 @@ class FurnaceGUI { persistFadeOut(1), exportLoops(0), exportFadeOut(0.0), + macroLayout(0), maxUndoSteps(100), mainFontPath(""), patFontPath(""), @@ -1684,6 +1686,7 @@ class FurnaceGUI { void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel); + void drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float availableWidth, int index); void drawMacros(std::vector& macros); void actualWaveList(); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 609c4c0e6..3321bfeb2 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1294,518 +1294,596 @@ void FurnaceGUI::kvsConfig(DivInstrument* ins) { } } -void FurnaceGUI::drawMacros(std::vector& macros) { - float asFloat[256]; - int asInt[256]; - float loopIndicator[256]; - float bit30Indicator[256]; - bool doHighlight[256]; - int index=0; +void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float availableWidth, int index) { + static float asFloat[256]; + static int asInt[256]; + static float loopIndicator[256]; + static float bit30Indicator[256]; + static bool doHighlight[256]; - float reservedSpace=(settings.oldMacroVSlider)?(20.0f*dpiScale+ImGui::GetStyle().ItemSpacing.x):ImGui::GetStyle().ScrollbarSize; - - if (ImGui::BeginTable("MacroSpace",2)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - float lenAvail=ImGui::GetContentRegionAvail().x; - //ImGui::Dummy(ImVec2(120.0f*dpiScale,dpiScale)); - ImGui::SetNextItemWidth(120.0f*dpiScale); - if (ImGui::InputInt("##MacroPointSize",¯oPointSize,1,16)) { - if (macroPointSize<1) macroPointSize=1; - if (macroPointSize>256) macroPointSize=256; - } - ImGui::TableNextColumn(); - float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; - int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale)); - if (macroDragScroll>255-totalFit) { - macroDragScroll=255-totalFit; - } - ImGui::SetNextItemWidth(availableWidth); - if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { - if (macroDragScroll<0) macroDragScroll=0; - if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; - } - - // draw macros - for (FurnaceGUIMacroDesc& i: macros) { - ImGui::PushID(index); - ImGui::TableNextRow(); - - // description - ImGui::TableNextColumn(); - ImGui::Text("%s",i.displayName); - ImGui::SameLine(); - if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) { - i.macro->open^=1; + if ((i.macro->open&6)==0) { + for (int j=0; j<256; j++) { + bit30Indicator[j]=0; + if (j+macroDragScroll>=i.macro->len) { + asFloat[j]=0; + asInt[j]=0; + } else { + asFloat[j]=deBit30(i.macro->val[j+macroDragScroll]); + asInt[j]=deBit30(i.macro->val[j+macroDragScroll])+i.bitOffset; + if (i.bit30) bit30Indicator[j]=enBit30(i.macro->val[j+macroDragScroll]); } - if (i.macro->open&1) { - if ((i.macro->open&6)==0) { - ImGui::SetNextItemWidth(lenAvail); - int macroLen=i.macro->len; - if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED - if (macroLen<0) macroLen=0; - if (macroLen>255) macroLen=255; - i.macro->len=macroLen; - } - } - if (ImGui::Button(macroTypeLabels[(i.macro->open>>1)&3])) { - unsigned char prevOpen=i.macro->open; - i.macro->open+=2; - if (i.macro->open>=6) { - i.macro->open-=6; - } + if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->looprel)) { + loopIndicator[j]=0; + } else { + loopIndicator[j]=((i.macro->loop!=255 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=255 && (j+macroDragScroll)==i.macro->rel)<<1); + } + } + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); - // check whether macro type is now ADSR/LFO or sequence - if (((prevOpen&6)?1:0)!=((i.macro->open&6)?1:0)) { - // swap memory - // this way the macro isn't corrupted if the user decides to go - // back to sequence mode - i.macro->len^=i.macro->lenMemory; - i.macro->lenMemory^=i.macro->len; - i.macro->len^=i.macro->lenMemory; + if (i.macro->vZoom<1) { + if (i.macro->name=="arp") { + i.macro->vZoom=24; + i.macro->vScroll=120-12; + } else if (i.macro->name=="pitch") { + i.macro->vZoom=128; + i.macro->vScroll=2048-64; + } else { + i.macro->vZoom=i.max-i.min; + i.macro->vScroll=0; + } + } + if (i.macro->vZoom>(i.max-i.min)) { + i.macro->vZoom=i.max-i.min; + } - for (int j=0; j<16; j++) { - i.macro->val[j]^=i.macro->typeMemory[j]; - i.macro->typeMemory[j]^=i.macro->val[j]; - i.macro->val[j]^=i.macro->typeMemory[j]; - } - - // if ADSR/LFO, populate min/max - if (i.macro->open&6) { - i.macro->val[0]=i.min; - i.macro->val[1]=i.max; + memset(doHighlight,0,256*sizeof(bool)); + if (e->isRunning()) for (int j=0; jgetTotalChannelCount(); j++) { + DivChannelState* chanState=e->getChanState(j); + if (chanState==NULL) continue; + + if (chanState->keyOff) continue; + if (chanState->lastIns!=curIns) continue; + + DivMacroInt* macroInt=e->getMacroInt(j); + if (macroInt==NULL) continue; + + DivMacroStruct* macroStruct=macroInt->structByName(i.macro->name); + if (macroStruct==NULL) continue; + + if (macroStruct->lastPos>i.macro->len) continue; + if (macroStruct->lastPoslastPos>255) continue; + if (!macroStruct->actualHad) continue; + + doHighlight[macroStruct->lastPos-macroDragScroll]=true; + } + + if (i.isBitfield) { + PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),doHighlight); + } else { + PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.hoverFuncUser,i.blockMode,(i.macro->open&1)?genericGuide:NULL,doHighlight); + } + if ((i.macro->open&1) && (ImGui::IsItemClicked(ImGuiMouseButton_Left) || ImGui::IsItemClicked(ImGuiMouseButton_Right))) { + macroDragStart=ImGui::GetItemRectMin(); + macroDragAreaSize=ImVec2(availableWidth,i.height*dpiScale); + if (i.isBitfield) { + macroDragMin=i.min; + macroDragMax=i.max; + } else { + macroDragMin=i.min+i.macro->vScroll; + macroDragMax=i.min+i.macro->vScroll+i.macro->vZoom; + } + macroDragBitOff=i.bitOffset; + macroDragBitMode=i.isBitfield; + macroDragInitialValueSet=false; + macroDragInitialValue=false; + macroDragLen=totalFit; + macroDragActive=true; + macroDragBit30=i.bit30; + macroDragSettingBit30=false; + macroDragTarget=i.macro->val; + macroDragChar=false; + macroDragLineMode=(i.isBitfield)?false:ImGui::IsItemClicked(ImGuiMouseButton_Right); + macroDragLineInitial=ImVec2(0,0); + lastMacroDesc=i; + processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); + } + if ((i.macro->open&1)) { + if (ImGui::IsItemHovered()) { + if (ctrlWheeling) { + if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { + i.macro->vZoom+=wheelY*(1+(i.macro->vZoom>>4)); + if (i.macro->vZoom<1) i.macro->vZoom=1; + if (i.macro->vZoom>(i.max-i.min)) i.macro->vZoom=i.max-i.min; + if ((i.macro->vScroll+i.macro->vZoom)>(i.max-i.min)) { + i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } + } else { + macroPointSize+=wheelY; + if (macroPointSize<1) macroPointSize=1; + if (macroPointSize>256) macroPointSize=256; } - PARAMETER; - } - if (ImGui::IsItemHovered()) { - switch (i.macro->open&6) { - case 0: - ImGui::SetTooltip("Macro type: Sequence"); - break; - case 2: - ImGui::SetTooltip("Macro type: ADSR"); - break; - case 4: - ImGui::SetTooltip("Macro type: LFO"); - break; - default: - ImGui::SetTooltip("Macro type: What's going on here?"); - break; - } - } - if (i.macro->open&6) { - i.macro->len=16; - } - ImGui::SameLine(); - ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet"); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Delay/Step Length"); - } - if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) { - if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&i.macro->speed,&_ONE,&_THREE)) { - if (i.macro->speed<1) i.macro->speed=1; - MARK_MODIFIED; - } - if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&i.macro->delay,&_ONE,&_THREE)) { - MARK_MODIFIED; - } - ImGui::EndPopup(); - } - // do not change this! - // anything other than a checkbox will look ugly! - // if you really need more than two macro modes please tell me. - if (i.modeName!=NULL) { - bool modeVal=i.macro->mode; - String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); - if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { - i.macro->mode=modeVal; - } + } else if ((ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) && wheelY!=0) { + i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); + if (i.macro->vScroll<0) i.macro->vScroll=0; + if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } } - // macro area - ImGui::TableNextColumn(); - if ((i.macro->open&6)==0) { - for (int j=0; j<256; j++) { - bit30Indicator[j]=0; - if (j+macroDragScroll>=i.macro->len) { - asFloat[j]=0; - asInt[j]=0; - } else { - asFloat[j]=deBit30(i.macro->val[j+macroDragScroll]); - asInt[j]=deBit30(i.macro->val[j+macroDragScroll])+i.bitOffset; - if (i.bit30) bit30Indicator[j]=enBit30(i.macro->val[j+macroDragScroll]); + // slider + if (!i.isBitfield) { + if (settings.oldMacroVSlider) { + ImGui::SameLine(0.0f); + if (ImGui::VSliderInt("IMacroVScroll",ImVec2(20.0f*dpiScale,i.height*dpiScale),&i.macro->vScroll,0,(i.max-i.min)-i.macro->vZoom,"")) { + if (i.macro->vScroll<0) i.macro->vScroll=0; + if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } - if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->looprel)) { - loopIndicator[j]=0; - } else { - loopIndicator[j]=((i.macro->loop!=255 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=255 && (j+macroDragScroll)==i.macro->rel)<<1); + if (ImGui::IsItemHovered() && ctrlWheeling) { + i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); + if (i.macro->vScroll<0) i.macro->vScroll=0; + if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } - } - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); - - if (i.macro->vZoom<1) { - if (i.macro->name=="arp") { - i.macro->vZoom=24; - i.macro->vScroll=120-12; - } else if (i.macro->name=="pitch") { - i.macro->vZoom=128; - i.macro->vScroll=2048-64; - } else { - i.macro->vZoom=i.max-i.min; - i.macro->vScroll=0; - } - } - if (i.macro->vZoom>(i.max-i.min)) { - i.macro->vZoom=i.max-i.min; - } - - memset(doHighlight,0,256*sizeof(bool)); - if (e->isRunning()) for (int j=0; jgetTotalChannelCount(); j++) { - DivChannelState* chanState=e->getChanState(j); - if (chanState==NULL) continue; - - if (chanState->keyOff) continue; - if (chanState->lastIns!=curIns) continue; - - DivMacroInt* macroInt=e->getMacroInt(j); - if (macroInt==NULL) continue; - - DivMacroStruct* macroStruct=macroInt->structByName(i.macro->name); - if (macroStruct==NULL) continue; - - if (macroStruct->lastPos>i.macro->len) continue; - if (macroStruct->lastPoslastPos>255) continue; - if (!macroStruct->actualHad) continue; - - doHighlight[macroStruct->lastPos-macroDragScroll]=true; - } - - if (i.isBitfield) { - PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),doHighlight); } else { - PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open&1)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.hoverFuncUser,i.blockMode,(i.macro->open&1)?genericGuide:NULL,doHighlight); - } - if ((i.macro->open&1) && (ImGui::IsItemClicked(ImGuiMouseButton_Left) || ImGui::IsItemClicked(ImGuiMouseButton_Right))) { - macroDragStart=ImGui::GetItemRectMin(); - macroDragAreaSize=ImVec2(availableWidth,i.height*dpiScale); - if (i.isBitfield) { - macroDragMin=i.min; - macroDragMax=i.max; - } else { - macroDragMin=i.min+i.macro->vScroll; - macroDragMax=i.min+i.macro->vScroll+i.macro->vZoom; + ImS64 scrollV=(i.max-i.min-i.macro->vZoom)-i.macro->vScroll; + ImS64 availV=i.macro->vZoom; + ImS64 contentsV=(i.max-i.min); + + ImGui::SameLine(0.0f); + ImGui::SetCursorPosX(ImGui::GetCursorPosX()-ImGui::GetStyle().ItemSpacing.x); + ImRect scrollbarPos=ImRect(ImGui::GetCursorScreenPos(),ImGui::GetCursorScreenPos()); + scrollbarPos.Max.x+=ImGui::GetStyle().ScrollbarSize; + scrollbarPos.Max.y+=i.height*dpiScale; + ImGui::Dummy(ImVec2(ImGui::GetStyle().ScrollbarSize,i.height*dpiScale)); + if (ImGui::IsItemHovered() && ctrlWheeling) { + i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); + if (i.macro->vScroll<0) i.macro->vScroll=0; + if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; } - macroDragBitOff=i.bitOffset; - macroDragBitMode=i.isBitfield; + + ImGuiID scrollbarID=ImGui::GetID("IMacroVScroll"); + ImGui::KeepAliveID(scrollbarID); + if (ImGui::ScrollbarEx(scrollbarPos,scrollbarID,ImGuiAxis_Y,&scrollV,availV,contentsV,0)) { + i.macro->vScroll=(i.max-i.min-i.macro->vZoom)-scrollV; + } + } + } + + // bit 30 area + if (i.bit30) { + PlotCustom("##IMacroBit30",bit30Indicator,totalFit,macroDragScroll,NULL,0,1,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverBit30); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroDragStart=ImGui::GetItemRectMin(); + macroDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); macroDragInitialValueSet=false; macroDragInitialValue=false; macroDragLen=totalFit; macroDragActive=true; macroDragBit30=i.bit30; - macroDragSettingBit30=false; + macroDragSettingBit30=true; macroDragTarget=i.macro->val; macroDragChar=false; - macroDragLineMode=(i.isBitfield)?false:ImGui::IsItemClicked(ImGuiMouseButton_Right); + macroDragLineMode=false; macroDragLineInitial=ImVec2(0,0); lastMacroDesc=i; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } - if ((i.macro->open&1)) { - if (ImGui::IsItemHovered()) { - if (ctrlWheeling) { - if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { - i.macro->vZoom+=wheelY*(1+(i.macro->vZoom>>4)); - if (i.macro->vZoom<1) i.macro->vZoom=1; - if (i.macro->vZoom>(i.max-i.min)) i.macro->vZoom=i.max-i.min; - if ((i.macro->vScroll+i.macro->vZoom)>(i.max-i.min)) { - i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; - } - } else { - macroPointSize+=wheelY; - if (macroPointSize<1) macroPointSize=1; - if (macroPointSize>256) macroPointSize=256; - } - } else if ((ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) && wheelY!=0) { - i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); - if (i.macro->vScroll<0) i.macro->vScroll=0; - if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; - } - } + } - // slider - if (!i.isBitfield) { - if (settings.oldMacroVSlider) { - ImGui::SameLine(0.0f); - if (ImGui::VSliderInt("IMacroVScroll",ImVec2(20.0f*dpiScale,i.height*dpiScale),&i.macro->vScroll,0,(i.max-i.min)-i.macro->vZoom,"")) { - if (i.macro->vScroll<0) i.macro->vScroll=0; - if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; - } - if (ImGui::IsItemHovered() && ctrlWheeling) { - i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); - if (i.macro->vScroll<0) i.macro->vScroll=0; - if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; - } - } else { - ImS64 scrollV=(i.max-i.min-i.macro->vZoom)-i.macro->vScroll; - ImS64 availV=i.macro->vZoom; - ImS64 contentsV=(i.max-i.min); - - ImGui::SameLine(0.0f); - ImGui::SetCursorPosX(ImGui::GetCursorPosX()-ImGui::GetStyle().ItemSpacing.x); - ImRect scrollbarPos=ImRect(ImGui::GetCursorScreenPos(),ImGui::GetCursorScreenPos()); - scrollbarPos.Max.x+=ImGui::GetStyle().ScrollbarSize; - scrollbarPos.Max.y+=i.height*dpiScale; - ImGui::Dummy(ImVec2(ImGui::GetStyle().ScrollbarSize,i.height*dpiScale)); - if (ImGui::IsItemHovered() && ctrlWheeling) { - i.macro->vScroll+=wheelY*(1+(i.macro->vZoom>>4)); - if (i.macro->vScroll<0) i.macro->vScroll=0; - if (i.macro->vScroll>((i.max-i.min)-i.macro->vZoom)) i.macro->vScroll=(i.max-i.min)-i.macro->vZoom; - } - - ImGuiID scrollbarID=ImGui::GetID("IMacroVScroll"); - ImGui::KeepAliveID(scrollbarID); - if (ImGui::ScrollbarEx(scrollbarPos,scrollbarID,ImGuiAxis_Y,&scrollV,availV,contentsV,0)) { - i.macro->vScroll=(i.max-i.min-i.macro->vZoom)-scrollV; - } - } - } - - // bit 30 area - if (i.bit30) { - PlotCustom("##IMacroBit30",bit30Indicator,totalFit,macroDragScroll,NULL,0,1,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverBit30); - if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - macroDragStart=ImGui::GetItemRectMin(); - macroDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); - macroDragInitialValueSet=false; - macroDragInitialValue=false; - macroDragLen=totalFit; - macroDragActive=true; - macroDragBit30=i.bit30; - macroDragSettingBit30=true; - macroDragTarget=i.macro->val; - macroDragChar=false; - macroDragLineMode=false; - macroDragLineInitial=ImVec2(0,0); - lastMacroDesc=i; - processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); - } - } - - // loop area - PlotCustom("##IMacroLoop",loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverLoop); - if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - macroLoopDragStart=ImGui::GetItemRectMin(); - macroLoopDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); - macroLoopDragLen=totalFit; - if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { - macroLoopDragTarget=&i.macro->rel; - } else { - macroLoopDragTarget=&i.macro->loop; - } - macroLoopDragActive=true; - processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); - } - if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { - i.macro->rel=255; - } else { - i.macro->loop=255; - } - } - ImGui::SetNextItemWidth(availableWidth); - String& mmlStr=mmlString[index]; - if (ImGui::InputText("##IMacroMML",&mmlStr)) { - decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?i.max:0))-1):i.max,i.macro->rel,i.bit30); - } - if (!ImGui::IsItemActive()) { - encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel,false,i.bit30); - } + // loop area + PlotCustom("##IMacroLoop",loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverLoop); + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { + macroLoopDragStart=ImGui::GetItemRectMin(); + macroLoopDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); + macroLoopDragLen=totalFit; + if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { + macroLoopDragTarget=&i.macro->rel; + } else { + macroLoopDragTarget=&i.macro->loop; } - ImGui::PopStyleVar(); - } else { - if (i.macro->open&2) { - if (ImGui::BeginTable("MacroADSR",4)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3); - //ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.4); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Bottom"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER - if (i.macro->val[0]val[0]=i.min; - if (i.macro->val[0]>i.max) i.macro->val[0]=i.max; - } - - ImGui::TableNextColumn(); - ImGui::Text("Top"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER - if (i.macro->val[1]val[1]=i.min; - if (i.macro->val[1]>i.max) i.macro->val[1]=i.max; - } - - /*ImGui::TableNextColumn(); - ImGui::Text("the envelope goes here");*/ - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Attack"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MAAR",&i.macro->val[2],0,255)) { PARAMETER - if (i.macro->val[2]<0) i.macro->val[2]=0; - if (i.macro->val[2]>255) i.macro->val[2]=255; - } - - ImGui::TableNextColumn(); - ImGui::Text("Sustain"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MASL",&i.macro->val[5],0,255)) { PARAMETER - if (i.macro->val[5]<0) i.macro->val[5]=0; - if (i.macro->val[5]>255) i.macro->val[5]=255; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Hold"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MAHT",&i.macro->val[3],0,255)) { PARAMETER - if (i.macro->val[3]<0) i.macro->val[3]=0; - if (i.macro->val[3]>255) i.macro->val[3]=255; - } - - ImGui::TableNextColumn(); - ImGui::Text("SusTime"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MAST",&i.macro->val[6],0,255)) { PARAMETER - if (i.macro->val[6]<0) i.macro->val[6]=0; - if (i.macro->val[6]>255) i.macro->val[6]=255; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Decay"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MADR",&i.macro->val[4],0,255)) { PARAMETER - if (i.macro->val[4]<0) i.macro->val[4]=0; - if (i.macro->val[4]>255) i.macro->val[4]=255; - } - - ImGui::TableNextColumn(); - ImGui::Text("SusDecay"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MASR",&i.macro->val[7],0,255)) { PARAMETER - if (i.macro->val[7]<0) i.macro->val[7]=0; - if (i.macro->val[7]>255) i.macro->val[7]=255; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - - ImGui::TableNextColumn(); - ImGui::Text("Release"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MARR",&i.macro->val[8],0,255)) { PARAMETER - if (i.macro->val[8]<0) i.macro->val[8]=0; - if (i.macro->val[8]>255) i.macro->val[8]=255; - } - - ImGui::EndTable(); - } - } - if (i.macro->open&4) { - if (ImGui::BeginTable("MacroLFO",4)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3); - //ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.4); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Bottom"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER - if (i.macro->val[0]val[0]=i.min; - if (i.macro->val[0]>i.max) i.macro->val[0]=i.max; - } - - ImGui::TableNextColumn(); - ImGui::Text("Top"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER - if (i.macro->val[1]val[1]=i.min; - if (i.macro->val[1]>i.max) i.macro->val[1]=i.max; - } - - /*ImGui::TableNextColumn(); - ImGui::Text("the envelope goes here");*/ - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("Speed"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MLSpeed",&i.macro->val[11],0,255)) { PARAMETER - if (i.macro->val[11]<0) i.macro->val[11]=0; - if (i.macro->val[11]>255) i.macro->val[11]=255; - } - - ImGui::TableNextColumn(); - ImGui::Text("Phase"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MLPhase",&i.macro->val[13],0,1023)) { PARAMETER - if (i.macro->val[13]<0) i.macro->val[13]=0; - if (i.macro->val[13]>1023) i.macro->val[13]=1023; - } - - ImGui::TableNextColumn(); - ImGui::Text("Shape"); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##MLShape",&i.macro->val[12],0,2,macroLFOShapes[i.macro->val[12]&3])) { PARAMETER - if (i.macro->val[12]<0) i.macro->val[12]=0; - if (i.macro->val[12]>2) i.macro->val[12]=2; - } - - ImGui::EndTable(); - } + macroLoopDragActive=true; + processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { + i.macro->rel=255; + } else { + i.macro->loop=255; } } - ImGui::PopID(); - index++; + ImGui::SetNextItemWidth(availableWidth); + String& mmlStr=mmlString[index]; + if (ImGui::InputText("##IMacroMML",&mmlStr)) { + decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?i.max:0))-1):i.max,i.macro->rel,i.bit30); + } + if (!ImGui::IsItemActive()) { + encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel,false,i.bit30); + } } + ImGui::PopStyleVar(); + } else { + if (i.macro->open&2) { + if (ImGui::BeginTable("MacroADSR",4)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3); + //ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.4); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(availableWidth); - if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { - if (macroDragScroll<0) macroDragScroll=0; - if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Bottom"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER + if (i.macro->val[0]val[0]=i.min; + if (i.macro->val[0]>i.max) i.macro->val[0]=i.max; + } + + ImGui::TableNextColumn(); + ImGui::Text("Top"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER + if (i.macro->val[1]val[1]=i.min; + if (i.macro->val[1]>i.max) i.macro->val[1]=i.max; + } + + /*ImGui::TableNextColumn(); + ImGui::Text("the envelope goes here");*/ + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Attack"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MAAR",&i.macro->val[2],0,255)) { PARAMETER + if (i.macro->val[2]<0) i.macro->val[2]=0; + if (i.macro->val[2]>255) i.macro->val[2]=255; + } + + ImGui::TableNextColumn(); + ImGui::Text("Sustain"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MASL",&i.macro->val[5],0,255)) { PARAMETER + if (i.macro->val[5]<0) i.macro->val[5]=0; + if (i.macro->val[5]>255) i.macro->val[5]=255; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Hold"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MAHT",&i.macro->val[3],0,255)) { PARAMETER + if (i.macro->val[3]<0) i.macro->val[3]=0; + if (i.macro->val[3]>255) i.macro->val[3]=255; + } + + ImGui::TableNextColumn(); + ImGui::Text("SusTime"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MAST",&i.macro->val[6],0,255)) { PARAMETER + if (i.macro->val[6]<0) i.macro->val[6]=0; + if (i.macro->val[6]>255) i.macro->val[6]=255; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Decay"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MADR",&i.macro->val[4],0,255)) { PARAMETER + if (i.macro->val[4]<0) i.macro->val[4]=0; + if (i.macro->val[4]>255) i.macro->val[4]=255; + } + + ImGui::TableNextColumn(); + ImGui::Text("SusDecay"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MASR",&i.macro->val[7],0,255)) { PARAMETER + if (i.macro->val[7]<0) i.macro->val[7]=0; + if (i.macro->val[7]>255) i.macro->val[7]=255; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + + ImGui::TableNextColumn(); + ImGui::Text("Release"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MARR",&i.macro->val[8],0,255)) { PARAMETER + if (i.macro->val[8]<0) i.macro->val[8]=0; + if (i.macro->val[8]>255) i.macro->val[8]=255; + } + + ImGui::EndTable(); + } + } + if (i.macro->open&4) { + if (ImGui::BeginTable("MacroLFO",4)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.3); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.3); + //ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.4); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Bottom"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##MABottom",&i.macro->val[0],1,16)) { PARAMETER + if (i.macro->val[0]val[0]=i.min; + if (i.macro->val[0]>i.max) i.macro->val[0]=i.max; + } + + ImGui::TableNextColumn(); + ImGui::Text("Top"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##MATop",&i.macro->val[1],1,16)) { PARAMETER + if (i.macro->val[1]val[1]=i.min; + if (i.macro->val[1]>i.max) i.macro->val[1]=i.max; + } + + /*ImGui::TableNextColumn(); + ImGui::Text("the envelope goes here");*/ + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Speed"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MLSpeed",&i.macro->val[11],0,255)) { PARAMETER + if (i.macro->val[11]<0) i.macro->val[11]=0; + if (i.macro->val[11]>255) i.macro->val[11]=255; + } + + ImGui::TableNextColumn(); + ImGui::Text("Phase"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MLPhase",&i.macro->val[13],0,1023)) { PARAMETER + if (i.macro->val[13]<0) i.macro->val[13]=0; + if (i.macro->val[13]>1023) i.macro->val[13]=1023; + } + + ImGui::TableNextColumn(); + ImGui::Text("Shape"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##MLShape",&i.macro->val[12],0,2,macroLFOShapes[i.macro->val[12]&3])) { PARAMETER + if (i.macro->val[12]<0) i.macro->val[12]=0; + if (i.macro->val[12]>2) i.macro->val[12]=2; + } + + ImGui::EndTable(); + } + } + } +} + +#define BUTTON_TO_SET_MODE(buttonType) \ + if (buttonType(macroTypeLabels[(i.macro->open>>1)&3])) { \ + unsigned char prevOpen=i.macro->open; \ + i.macro->open+=2; \ + if (i.macro->open>=6) { \ + i.macro->open-=6; \ + } \ +\ + /* check whether macro type is now ADSR/LFO or sequence */ \ + if (((prevOpen&6)?1:0)!=((i.macro->open&6)?1:0)) { \ + /* swap memory */ \ + /* this way the macro isn't corrupted if the user decides to go */ \ + /* back to sequence mode */ \ + i.macro->len^=i.macro->lenMemory; \ + i.macro->lenMemory^=i.macro->len; \ + i.macro->len^=i.macro->lenMemory; \ +\ + for (int j=0; j<16; j++) { \ + i.macro->val[j]^=i.macro->typeMemory[j]; \ + i.macro->typeMemory[j]^=i.macro->val[j]; \ + i.macro->val[j]^=i.macro->typeMemory[j]; \ + } \ +\ + /* if ADSR/LFO, populate min/max */ \ + if (i.macro->open&6) { \ + i.macro->val[0]=i.min; \ + i.macro->val[1]=i.max; \ + } \ + } \ + PARAMETER; \ + } \ + if (ImGui::IsItemHovered()) { \ + switch (i.macro->open&6) { \ + case 0: \ + ImGui::SetTooltip("Macro type: Sequence"); \ + break; \ + case 2: \ + ImGui::SetTooltip("Macro type: ADSR"); \ + break; \ + case 4: \ + ImGui::SetTooltip("Macro type: LFO"); \ + break; \ + default: \ + ImGui::SetTooltip("Macro type: What's going on here?"); \ + break; \ + } \ + } \ + if (i.macro->open&6) { \ + i.macro->len=16; \ + } + +#define BUTTON_TO_SET_PROPS \ + ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet"); \ + if (ImGui::IsItemHovered()) { \ + ImGui::SetTooltip("Delay/Step Length"); \ + } \ + if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) { \ + if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&i.macro->speed,&_ONE,&_THREE)) { \ + if (i.macro->speed<1) i.macro->speed=1; \ + MARK_MODIFIED; \ + } \ + if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&i.macro->delay,&_ONE,&_THREE)) { \ + MARK_MODIFIED; \ + } \ + ImGui::EndPopup(); \ + } + +void FurnaceGUI::drawMacros(std::vector& macros) { + int index=0; + float reservedSpace=(settings.oldMacroVSlider)?(20.0f*dpiScale+ImGui::GetStyle().ItemSpacing.x):ImGui::GetStyle().ScrollbarSize; + switch (settings.macroLayout) { + case 0: { + if (ImGui::BeginTable("MacroSpace",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + float lenAvail=ImGui::GetContentRegionAvail().x; + //ImGui::Dummy(ImVec2(120.0f*dpiScale,dpiScale)); + ImGui::SetNextItemWidth(120.0f*dpiScale); + if (ImGui::InputInt("##MacroPointSize",¯oPointSize,1,16)) { + if (macroPointSize<1) macroPointSize=1; + if (macroPointSize>256) macroPointSize=256; + } + ImGui::TableNextColumn(); + float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; + int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale)); + if (macroDragScroll>255-totalFit) { + macroDragScroll=255-totalFit; + } + ImGui::SetNextItemWidth(availableWidth); + if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { + if (macroDragScroll<0) macroDragScroll=0; + if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; + } + + // draw macros + for (FurnaceGUIMacroDesc& i: macros) { + ImGui::PushID(index); + ImGui::TableNextRow(); + + // description + ImGui::TableNextColumn(); + ImGui::Text("%s",i.displayName); + ImGui::SameLine(); + if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) { + i.macro->open^=1; + } + if (i.macro->open&1) { + if ((i.macro->open&6)==0) { + ImGui::SetNextItemWidth(lenAvail); + int macroLen=i.macro->len; + if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED + if (macroLen<0) macroLen=0; + if (macroLen>255) macroLen=255; + i.macro->len=macroLen; + } + } + BUTTON_TO_SET_MODE(ImGui::Button); + ImGui::SameLine(); + BUTTON_TO_SET_PROPS; + // do not change this! + // anything other than a checkbox will look ugly! + // if you really need more than two macro modes please tell me. + if (i.modeName!=NULL) { + bool modeVal=i.macro->mode; + String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); + if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { + i.macro->mode=modeVal; + } + } + } + + // macro area + ImGui::TableNextColumn(); + drawMacroEdit(i,totalFit,availableWidth,index); + ImGui::PopID(); + index++; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(availableWidth); + if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { + if (macroDragScroll<0) macroDragScroll=0; + if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; + } + ImGui::EndTable(); + } + break; + } + case 1: { + ImGui::Text("Mobile"); + break; + } + case 2: { + for (FurnaceGUIMacroDesc& i: macros) { + if (index>0) ImGui::Separator(); + + float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; + int totalFit=i.macro->len; + if (totalFit<1) totalFit=1; + + ImGui::PushID(index); + + ImGui::TextUnformatted(i.displayName); + ImGui::SameLine(); + if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) { + i.macro->open^=1; + } + + if (i.macro->open&1) { + ImGui::SameLine(); + BUTTON_TO_SET_MODE(ImGui::Button); + } + + drawMacroEdit(i,totalFit,availableWidth,index); + + if (i.macro->open&1) { + if ((i.macro->open&6)==0) { + ImGui::Text("Length"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(120.0f*dpiScale); + int macroLen=i.macro->len; + if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED + if (macroLen<0) macroLen=0; + if (macroLen>255) macroLen=255; + i.macro->len=macroLen; + } + ImGui::SameLine(); + } + BUTTON_TO_SET_PROPS; + if (i.modeName!=NULL) { + bool modeVal=i.macro->mode; + String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); + ImGui::SameLine(); + if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { + i.macro->mode=modeVal; + } + } + } + + ImGui::PopID(); + index++; + } + break; + } + case 3: { + ImGui::Text("Single (with list)"); + break; + } + case 4: { + ImGui::Text("Single (combo box)"); + break; } - ImGui::EndTable(); } } diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 02cd387cf..74bd1cb8e 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1326,6 +1326,23 @@ void FurnaceGUI::drawSettings() { settings.susPosition=1; } + ImGui::Text("Macro editor layout:"); + if (ImGui::RadioButton("Unified##mel0",settings.macroLayout==0)) { + settings.macroLayout=0; + } + if (ImGui::RadioButton("Mobile##mel1",settings.macroLayout==1)) { + settings.macroLayout=1; + } + if (ImGui::RadioButton("Grid##mel2",settings.macroLayout==2)) { + settings.macroLayout=2; + } + if (ImGui::RadioButton("Single (with list)##mel3",settings.macroLayout==3)) { + settings.macroLayout=3; + } + if (ImGui::RadioButton("Single (combo box)##mel4",settings.macroLayout==4)) { + settings.macroLayout=4; + } + ImGui::Separator(); ImGui::Text("Namco 163 chip name"); @@ -2405,6 +2422,7 @@ void FurnaceGUI::syncSettings() { settings.persistFadeOut=e->getConfInt("persistFadeOut",1); settings.exportLoops=e->getConfInt("exportLoops",0); settings.exportFadeOut=e->getConfDouble("exportFadeOut",0.0); + settings.macroLayout=e->getConfInt("macroLayout",0); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2511,6 +2529,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.centerPattern,0,1); clampSetting(settings.ordersCursor,0,1); clampSetting(settings.persistFadeOut,0,1); + clampSetting(settings.macroLayout,0,4); if (settings.exportLoops<0.0) settings.exportLoops=0.0; if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0; @@ -2683,6 +2702,7 @@ void FurnaceGUI::commitSettings() { e->setConf("persistFadeOut",settings.persistFadeOut); e->setConf("exportLoops",settings.exportLoops); e->setConf("exportFadeOut",settings.exportFadeOut); + e->setConf("macroLayout",settings.macroLayout); // colors for (int i=0; i Date: Fri, 11 Nov 2022 00:46:39 -0500 Subject: [PATCH 33/48] GUI: more macro editor layouts, part 1 --- src/gui/gui.h | 10 ++- src/gui/insEdit.cpp | 170 +++++++++++++++++++++++++++++++------------- 2 files changed, 130 insertions(+), 50 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 422bf856d..94d54823b 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -951,6 +951,12 @@ struct FurnaceGUIMacroDesc { } }; +struct FurnaceGUIMacroEditState { + int selectedMacro; + FurnaceGUIMacroEditState(): + selectedMacro(0) {} +}; + enum FurnaceGUIFindQueryModes { GUI_QUERY_IGNORE=0, GUI_QUERY_MATCH, @@ -1522,6 +1528,8 @@ class FurnaceGUI { int macroLoopDragLen; bool macroLoopDragActive; + FurnaceGUIMacroEditState macroEditStateFM, macroEditStateOP[4], macroEditStateMacros; + ImVec2 waveDragStart; ImVec2 waveDragAreaSize; int* waveDragTarget; @@ -1687,7 +1695,7 @@ class FurnaceGUI { void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel); void drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float availableWidth, int index); - void drawMacros(std::vector& macros); + void drawMacros(std::vector& macros, FurnaceGUIMacroEditState& state); void actualWaveList(); void actualSampleList(); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 3321bfeb2..8ee173d52 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1719,23 +1719,23 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail i.macro->len=16; \ } -#define BUTTON_TO_SET_PROPS \ +#define BUTTON_TO_SET_PROPS(_x) \ ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet"); \ if (ImGui::IsItemHovered()) { \ ImGui::SetTooltip("Delay/Step Length"); \ } \ if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) { \ - if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&i.macro->speed,&_ONE,&_THREE)) { \ - if (i.macro->speed<1) i.macro->speed=1; \ + if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&_x.macro->speed,&_ONE,&_THREE)) { \ + if (_x.macro->speed<1) _x.macro->speed=1; \ MARK_MODIFIED; \ } \ - if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&i.macro->delay,&_ONE,&_THREE)) { \ + if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&_x.macro->delay,&_ONE,&_THREE)) { \ MARK_MODIFIED; \ } \ ImGui::EndPopup(); \ } -void FurnaceGUI::drawMacros(std::vector& macros) { +void FurnaceGUI::drawMacros(std::vector& macros, FurnaceGUIMacroEditState& state) { int index=0; float reservedSpace=(settings.oldMacroVSlider)?(20.0f*dpiScale+ImGui::GetStyle().ItemSpacing.x):ImGui::GetStyle().ScrollbarSize; switch (settings.macroLayout) { @@ -1788,7 +1788,7 @@ void FurnaceGUI::drawMacros(std::vector& macros) { } BUTTON_TO_SET_MODE(ImGui::Button); ImGui::SameLine(); - BUTTON_TO_SET_PROPS; + BUTTON_TO_SET_PROPS(i); // do not change this! // anything other than a checkbox will look ugly! // if you really need more than two macro modes please tell me. @@ -1825,59 +1825,131 @@ void FurnaceGUI::drawMacros(std::vector& macros) { break; } case 2: { - for (FurnaceGUIMacroDesc& i: macros) { - if (index>0) ImGui::Separator(); - - float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; - int totalFit=i.macro->len; - if (totalFit<1) totalFit=1; + int columns=round(ImGui::GetContentRegionAvail().x/(400.0*dpiScale)); + int curColumn=0; + if (ImGui::BeginTable("MacroGrid",columns,ImGuiTableFlags_BordersInner)) { + for (FurnaceGUIMacroDesc& i: macros) { + if (curColumn==0) ImGui::TableNextRow(); + ImGui::TableNextColumn(); - ImGui::PushID(index); + if (++curColumn>=columns) curColumn=0; + + float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; + int totalFit=i.macro->len; + if (totalFit<1) totalFit=1; - ImGui::TextUnformatted(i.displayName); - ImGui::SameLine(); - if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) { - i.macro->open^=1; - } + ImGui::PushID(index); - if (i.macro->open&1) { + ImGui::TextUnformatted(i.displayName); ImGui::SameLine(); - BUTTON_TO_SET_MODE(ImGui::Button); - } - - drawMacroEdit(i,totalFit,availableWidth,index); - - if (i.macro->open&1) { - if ((i.macro->open&6)==0) { - ImGui::Text("Length"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(120.0f*dpiScale); - int macroLen=i.macro->len; - if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED - if (macroLen<0) macroLen=0; - if (macroLen>255) macroLen=255; - i.macro->len=macroLen; - } - ImGui::SameLine(); + if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) { + i.macro->open^=1; } - BUTTON_TO_SET_PROPS; - if (i.modeName!=NULL) { - bool modeVal=i.macro->mode; - String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); + + if (i.macro->open&1) { ImGui::SameLine(); - if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { - i.macro->mode=modeVal; + BUTTON_TO_SET_MODE(ImGui::SmallButton); + } + + drawMacroEdit(i,totalFit,availableWidth,index); + + if (i.macro->open&1) { + if ((i.macro->open&6)==0) { + ImGui::Text("Length"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(120.0f*dpiScale); + int macroLen=i.macro->len; + if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED + if (macroLen<0) macroLen=0; + if (macroLen>255) macroLen=255; + i.macro->len=macroLen; + } + ImGui::SameLine(); + } + BUTTON_TO_SET_PROPS(i); + if (i.modeName!=NULL) { + bool modeVal=i.macro->mode; + String modeName=fmt::sprintf("%s##IMacroMode",i.modeName); + ImGui::SameLine(); + if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { + i.macro->mode=modeVal; + } } } - } - ImGui::PopID(); - index++; + ImGui::PopID(); + index++; + } + ImGui::EndTable(); } break; } case 3: { - ImGui::Text("Single (with list)"); + if (ImGui::BeginTable("MacroList",2,ImGuiTableFlags_Borders)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + for (size_t i=0; i255-totalFit) { + macroDragScroll=255-totalFit; + } + + if (state.selectedMacro<0 || state.selectedMacro>=(int)macros.size()) { + state.selectedMacro=0; + } + + if (state.selectedMacro>=0 && state.selectedMacro<(int)macros.size()) { + FurnaceGUIMacroDesc& m=macros[state.selectedMacro]; + m.macro->open|=1; + + m.height=ImGui::GetContentRegionAvail().y-ImGui::GetFontSize()-ImGui::GetFrameHeightWithSpacing()-12.0f*dpiScale-ImGui::GetStyle().ItemSpacing.y*3.0f; + if (m.macro->name=="arp") m.height-=12.0f*dpiScale; + if (m.height<10.0f*dpiScale) m.height=10.0f*dpiScale; + m.height/=dpiScale; + drawMacroEdit(m,totalFit,availableWidth,index); + + if (m.macro->open&1) { + if ((m.macro->open&6)==0) { + ImGui::Text("Length"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(120.0f*dpiScale); + int macroLen=m.macro->len; + if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED + if (macroLen<0) macroLen=0; + if (macroLen>255) macroLen=255; + m.macro->len=macroLen; + } + ImGui::SameLine(); + } + BUTTON_TO_SET_PROPS(m); + if (m.modeName!=NULL) { + bool modeVal=m.macro->mode; + String modeName=fmt::sprintf("%s##IMacroMode",m.modeName); + ImGui::SameLine(); + if (ImGui::Checkbox(modeName.c_str(),&modeVal)) { + m.macro->mode=modeVal; + } + } + } else { + ImGui::Text("The heck? No, this isn't even working correctly..."); + } + } else { + ImGui::Text("The only problem with that selectedMacro is that it's a bug..."); + } + + // goes here + ImGui::EndTable(); + } break; } case 4: { @@ -3648,7 +3720,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("LFO2 Speed",&ins->std.ex7Macro,0,255,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc("LFO2 Shape",&ins->std.ex8Macro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroLFOWaves)); } - drawMacros(macroList); + drawMacros(macroList,macroEditStateFM); ImGui::EndTabItem(); } for (int i=0; istd.opMacros[ordi].ssgMacro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,ssgEnvBits)); } } - drawMacros(macroList); + drawMacros(macroList,macroEditStateOP[ordi]); ImGui::PopID(); ImGui::EndTabItem(); } @@ -5223,7 +5295,7 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc("Noise",&ins->std.ex3Macro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } - drawMacros(macroList); + drawMacros(macroList,macroEditStateMacros); ImGui::EndTabItem(); } ImGui::EndTabBar(); From 373004f6ebcd23fe0b3e65b20461e9ff8ee73935 Mon Sep 17 00:00:00 2001 From: brickblock369 <59150779+brickblock369@users.noreply.github.com> Date: Fri, 11 Nov 2022 12:37:57 -0800 Subject: [PATCH 34/48] Add TIA drums to the instrument repo --- instruments/other/TIA Bass Drum.fui | Bin 0 -> 1983 bytes instruments/other/TIA Clap.fui | Bin 0 -> 1934 bytes instruments/other/TIA Hi-Hat Long.fui | Bin 0 -> 1969 bytes instruments/other/TIA Hi-Hat.fui | Bin 0 -> 1936 bytes instruments/other/TIA Snare Drum.fui | Bin 0 -> 2000 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/other/TIA Bass Drum.fui create mode 100644 instruments/other/TIA Clap.fui create mode 100644 instruments/other/TIA Hi-Hat Long.fui create mode 100644 instruments/other/TIA Hi-Hat.fui create mode 100644 instruments/other/TIA Snare Drum.fui diff --git a/instruments/other/TIA Bass Drum.fui b/instruments/other/TIA Bass Drum.fui new file mode 100644 index 0000000000000000000000000000000000000000..a65fa2ea8892d682f485c994e60df74e89a84f6c GIT binary patch literal 1983 zcmeHH&1%9x5dOv_O`?>gzCiX|u=EkqQVL!~&=-)>Ll58`mfl z6l@2+%*^gL-^?yyN6)Klxp;ZiZ_E56yBn3OscS1XT?{#YUMYKGER5W4}+n8aBlo+4V8S$`rKs6?!R%i=qj{eNKcX z=53wz-Eh_gAu9(&_lhB!GKv^aoW=}ZFZ_W0HG}KZ8-~om7hBW`-?a7&M769*J1TB# z9m=<&)hUi@QIig7xA*@-ulAWQJ+FU;J;86!zejdw`M;0-mNgfogK6+h*swvnp23DH m(Wx%d?pkG?50T=>RM2T&anO=N_*7vCa+piRL30jtF5V9cY2$(b literal 0 HcmV?d00001 diff --git a/instruments/other/TIA Clap.fui b/instruments/other/TIA Clap.fui new file mode 100644 index 0000000000000000000000000000000000000000..b90cf269186fdfc6002181b87d621354b797c0d8 GIT binary patch literal 1934 zcmeHHQHsJq41KY!t@<(G1v=jgE*_yG2>!^zdI1pyVJV{Pr+77QrkUEYZLC!gc0qj* znoM3^CPPVQuvx{E=}a%;_3!Glvjw2pEQX`+@!SWt2rwS@bpL0v1YDqI7-8T!>I3jB z9iSwU#-U5p>Q>~Nl5aDVManVySg2K8f0!-qqqvx}`1iuh2`*{Os}hXSm`# zI{y{fi{p2n;(p2=NPA!2o^W75+ZC6krT144Df^z{%0;Aj!5XWClMI?t2s`Ebpc0gc Ll+a2q^k2LqYT@6i literal 0 HcmV?d00001 diff --git a/instruments/other/TIA Hi-Hat Long.fui b/instruments/other/TIA Hi-Hat Long.fui new file mode 100644 index 0000000000000000000000000000000000000000..0edd37f1142dd4718ec9d22c34347b20fff853d7 GIT binary patch literal 1969 zcmeHH+iJo<5Itj(CSJ-ye<1r@Na-i&OHn9As6Qa36kk%X_EGxWzv`dqOw8aeE{R2` zP#id!+05n4PQnxqpUZOo@@g05$7*?3tN~bt%H-*J_MHN2WSC7xcDyLY^Ob#kFW-O| z=ty9mC6T!W63qgra@6NMChFfe_x#G6qDB!IC literal 0 HcmV?d00001 diff --git a/instruments/other/TIA Hi-Hat.fui b/instruments/other/TIA Hi-Hat.fui new file mode 100644 index 0000000000000000000000000000000000000000..0f5f3a59529287e9b83a42bcc7732c60b905d6b9 GIT binary patch literal 1936 zcmeHH%c{aK5ItjCT6Gcd2b%STil3kx(TxcD10uq8(Px2r+XMI?B^Dvw%HKU7l)7m??nfQ3W?wBSIm G;@trji{K^z literal 0 HcmV?d00001 diff --git a/instruments/other/TIA Snare Drum.fui b/instruments/other/TIA Snare Drum.fui new file mode 100644 index 0000000000000000000000000000000000000000..22cb3667c06127d66c7bf8b37b1c671695e82953 GIT binary patch literal 2000 zcmeHH%}T>S5dNk~OwuX~zCiXYRD6UKiqK0D+7~F&g9men_E>x!AHz3mXSTaBiAz!_ zRH%ONk(r&J{bmU>e%zGB>UphSinsUje!K;snGUo0V)+>ZTO?S{CVEk<%C(-Bn^zzN z29lR0QK0UC$Q1!(0@lw$qR~S~d`O|X{Vry!S)Wp>>J6K5g+UJDqQsIvHDom#H|$87 zfaU+d&YsKHM=4M>UbCGt`Gw5*(lcO+T9G6a@L4Y8C(7A1Hs|CVH@;}PvUK{`thjy2l7`usy*H_5TL9P;{lx8r}|uJ+8A?)UvMr_SHk-^Ks$Y3?-lE`W}nqA$XZ p0WIsR8|QjRzlzR9q-X5 literal 0 HcmV?d00001 From 4c90adda2b99f02478a5065ee0bcd6692aa566ae Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 12 Nov 2022 02:27:05 -0500 Subject: [PATCH 35/48] GUI: fix add/remove buttons for initial system --- src/gui/settings.cpp | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 74bd1cb8e..753ef6019 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -349,11 +349,15 @@ void FurnaceGUI::drawSettings() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::InputText("##InitSysName",&settings.initialSysName); + int sysCount=0; + int doRemove=-1; for (size_t i=0; settings.initialSys.getInt(fmt::sprintf("id%d",i),0); i++) { DivSystem sysID=e->systemFromFileFur(settings.initialSys.getInt(fmt::sprintf("id%d",i),0)); signed char sysVol=settings.initialSys.getInt(fmt::sprintf("vol%d",i),0); signed char sysPan=settings.initialSys.getInt(fmt::sprintf("pan%d",i),0); + sysCount=i+1; + //bool doRemove=false; bool doInvert=sysVol&128; signed char vol=sysVol&127; @@ -379,7 +383,7 @@ void FurnaceGUI::drawSettings() { ImGui::SameLine(); //ImGui::BeginDisabled(settings.initialSys.size()<=4); if (ImGui::Button(ICON_FA_MINUS "##InitSysRemove")) { - //doRemove=true; + doRemove=i; } //ImGui::EndDisabled(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-(50.0f*dpiScale)); @@ -404,17 +408,31 @@ void FurnaceGUI::drawSettings() { } ImGui::PopID(); - /*if (doRemove && settings.initialSys.size()>=8) { - settings.initialSys.erase(settings.initialSys.begin()+i,settings.initialSys.begin()+i+4); - i-=4; - }*/ } - if (ImGui::Button(ICON_FA_PLUS "##InitSysAdd")) { - /*settings.initialSys.push_back(DIV_SYSTEM_YM2612); - settings.initialSys.push_back(64); - settings.initialSys.push_back(0); - settings.initialSys.push_back(0);*/ + if (doRemove>=0 && sysCount>1) { + for (int i=doRemove; isystemToFileFur(DIV_SYSTEM_YM2612)); + settings.initialSys.set(fmt::sprintf("vol%d",sysCount),64); + settings.initialSys.set(fmt::sprintf("pan%d",sysCount),0); + settings.initialSys.set(fmt::sprintf("flags%d",sysCount),""); } ImGui::Separator(); From 6f1d916ac33ca7476342d439a294eccc16da32d3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 12 Nov 2022 02:59:42 -0500 Subject: [PATCH 36/48] temporarily enable debug artifacts --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e2d5aef2d..5a8674843 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ defaults: shell: bash env: - BUILD_TYPE: Release + BUILD_TYPE: Debug jobs: build: From e232d3f1685dd05c8687c123f3885783508b706f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 12 Nov 2022 03:14:28 -0500 Subject: [PATCH 37/48] let's try to narrow it down --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5a8674843..f78c06713 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ defaults: shell: bash env: - BUILD_TYPE: Debug + BUILD_TYPE: Release jobs: build: @@ -240,6 +240,7 @@ jobs: -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ -DWARNINGS_ARE_ERRORS=${USE_WAE} \ + -DUSE_RTMIDI=OFF \ "${CMAKE_EXTRA_ARGS[@]}" - name: Build From 4e9f9a05d6a4340b239457ef2f24ddab30275c03 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 12 Nov 2022 14:16:07 -0500 Subject: [PATCH 38/48] GUI: initial system reset to defaults oversight --- src/gui/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 753ef6019..7f95ffa04 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -338,7 +338,7 @@ void FurnaceGUI::drawSettings() { settings.initialSys.set("pan0",0); settings.initialSys.set("flags0",""); settings.initialSys.set("id1",e->systemToFileFur(DIV_SYSTEM_SMS)); - settings.initialSys.set("vol1",64); + settings.initialSys.set("vol1",32); settings.initialSys.set("pan1",0); settings.initialSys.set("flags1",""); settings.initialSysName="Sega Genesis/Mega Drive"; From 8ea5c7acc26ac3961af8f51f3ab0a34af3cb6183 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 12 Nov 2022 14:17:39 -0500 Subject: [PATCH 39/48] now let's see what happens --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f78c06713..e2d5aef2d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -240,7 +240,6 @@ jobs: -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ -DWARNINGS_ARE_ERRORS=${USE_WAE} \ - -DUSE_RTMIDI=OFF \ "${CMAKE_EXTRA_ARGS[@]}" - name: Build From fbacfd421cbcbed394c8aa11b5dc6f85df3170aa Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 13 Nov 2022 15:41:40 -0500 Subject: [PATCH 40/48] prepare for new preset format --- src/engine/engine.h | 14 +++++++------- src/engine/sysDef.cpp | 4 ++++ src/gui/gui.cpp | 1 - src/gui/gui.h | 19 ++++++++++++++++--- src/gui/newSong.cpp | 15 +++------------ src/gui/presets.cpp | 22 ++++++++++++++++++++++ 6 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index fc3e43998..bea954fa4 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -382,9 +382,9 @@ class DivEngine { std::vector midiOuts; std::vector cmdStream; std::vector possibleInsTypes; - DivSysDef* sysDefs[256]; - DivSystem sysFileMapFur[256]; - DivSystem sysFileMapDMF[256]; + static DivSysDef* sysDefs[256]; + static DivSystem sysFileMapFur[256]; + static DivSystem sysFileMapDMF[256]; struct SamplePreview { double rate; @@ -532,10 +532,10 @@ class DivEngine { void notifyWaveChange(int wave); // get system IDs - DivSystem systemFromFileFur(unsigned char val); - unsigned char systemToFileFur(DivSystem val); - DivSystem systemFromFileDMF(unsigned char val); - unsigned char systemToFileDMF(DivSystem val); + static DivSystem systemFromFileFur(unsigned char val); + static unsigned char systemToFileFur(DivSystem val); + static DivSystem systemFromFileDMF(unsigned char val); + static unsigned char systemToFileDMF(DivSystem val); // benchmark (returns time in seconds) double benchmarkPlayback(); diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 44b312463..b23ed7130 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -23,6 +23,10 @@ #include "song.h" #include "../ta-log.h" +DivSysDef* DivEngine::sysDefs[256]; +DivSystem DivEngine::sysFileMapFur[256]; +DivSystem DivEngine::sysFileMapDMF[256]; + DivSystem DivEngine::systemFromFileFur(unsigned char val) { return sysFileMapFur[val]; } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index a11b13525..845af6384 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -5655,7 +5655,6 @@ FurnaceGUI::FurnaceGUI(): curWindowLast(GUI_WINDOW_NOTHING), curWindowThreadSafe(GUI_WINDOW_NOTHING), lastPatternWidth(0.0f), - nextDesc(NULL), latchNote(-1), latchIns(-2), latchVol(-1), diff --git a/src/gui/gui.h b/src/gui/gui.h index 94d54823b..b467daac6 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -899,12 +899,25 @@ struct Gradient2D { } }; +struct FurnaceGUISysDefChip { + DivSystem sys; + int vol, pan; + const char* flags; + FurnaceGUISysDefChip(DivSystem s, int v, int p, const char* f): + sys(s), + vol(v), + pan(p), + flags(f) {} +}; + struct FurnaceGUISysDef { const char* name; - std::vector definition; + String definition; FurnaceGUISysDef(const char* n, std::initializer_list def): - name(n), definition(def) { + name(n) { + // fuck it } + FurnaceGUISysDef(const char* n, std::initializer_list def); }; struct FurnaceGUISysCategory { @@ -1404,7 +1417,7 @@ class FurnaceGUI { float patChanX[DIV_MAX_CHANS+1]; float patChanSlideY[DIV_MAX_CHANS+1]; float lastPatternWidth; - const int* nextDesc; + String nextDesc; String nextDescName; OperationMask opMaskDelete, opMaskPullDelete, opMaskInsert, opMaskPaste, opMaskTransposeNote, opMaskTransposeValue; diff --git a/src/gui/newSong.cpp b/src/gui/newSong.cpp index 7959149b8..596ef22a3 100644 --- a/src/gui/newSong.cpp +++ b/src/gui/newSong.cpp @@ -107,7 +107,7 @@ void FurnaceGUI::drawNewSong() { ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::Selectable(i.name,false,ImGuiSelectableFlags_DontClosePopups)) { - nextDesc=i.definition.data(); + nextDesc=i.definition; nextDescName=i.name; accepted=true; } @@ -129,7 +129,7 @@ void FurnaceGUI::drawNewSong() { ImGui::CloseCurrentPopup(); } else { unsigned int selection=rand()%newSystemCat->systems.size(); - nextDesc=newSystemCat->systems[selection].definition.data(); + nextDesc=newSystemCat->systems[selection].definition; nextDescName=newSystemCat->systems[selection].name; accepted=true; } @@ -143,16 +143,7 @@ void FurnaceGUI::drawNewSong() { } if (accepted) { - // TODO: remove after porting all presets to new format - String oldDescFormat; - for (const int* i=nextDesc; *i; i+=4) { - oldDescFormat+=fmt::sprintf("%d ",e->systemToFileFur((DivSystem)i[0])); - oldDescFormat+=fmt::sprintf("%d ",i[1]); - oldDescFormat+=fmt::sprintf("%d ",i[2]); - oldDescFormat+=fmt::sprintf("%d ",i[3]); - } - String oldDesc=e->decodeSysDesc(oldDescFormat.c_str()); - e->createNew(oldDesc.c_str(),nextDescName); + e->createNew(nextDesc.c_str(),nextDescName); undoHist.clear(); redoHist.clear(); curFileName=""; diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index db9197d88..5d009414a 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -18,6 +18,7 @@ */ #include "gui.h" +#include // add system configurations here. // every entry is written in the following format: @@ -2323,3 +2324,24 @@ void FurnaceGUI::initSystemPresets() { )); sysCategories.push_back(cat); } + +FurnaceGUISysDef::FurnaceGUISysDef(const char* n, std::initializer_list def): + name(n) { + std::vector uncompiled=def; + int index=0; + for (FurnaceGUISysDefChip& i: uncompiled) { + definition+=fmt::sprintf( + "id%d=%d\nvol%d=%d\npan%d=%d\nflags%d=%s\n", + index, + DivEngine::systemToFileFur(i.sys), + index, + i.vol, + index, + i.pan, + index, + i.flags + ); + index++; + } +} + From d422372b7f27c67dc7900a797c1d674c7f42b45c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 13 Nov 2022 16:25:50 -0500 Subject: [PATCH 41/48] convert presets to new format, part 1 --- CMakeLists.txt | 1 + src/baseutils.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++ src/baseutils.h | 28 ++++++++++++++ src/engine/config.cpp | 68 ++------------------------------- src/engine/engine.h | 6 ++- src/gui/gui.h | 5 +-- src/gui/presets.cpp | 30 ++++++++++++++- 7 files changed, 154 insertions(+), 73 deletions(-) create mode 100644 src/baseutils.cpp create mode 100644 src/baseutils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 10294d3e4..d79cfffbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,6 +308,7 @@ endif() set(ENGINE_SOURCES src/log.cpp +src/baseutils.cpp src/fileutils.cpp src/utfutils.cpp diff --git a/src/baseutils.cpp b/src/baseutils.cpp new file mode 100644 index 000000000..aad61eb48 --- /dev/null +++ b/src/baseutils.cpp @@ -0,0 +1,89 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "baseutils.h" +#include + +const char* base64Table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +std::string taEncodeBase64(const std::string& data) { + std::string ret; + + ret.reserve((2+data.size()*4)/3); + + unsigned int groupOfThree=0; + unsigned char pos=0; + for (const char& i: data) { + groupOfThree|=((unsigned char)i)<<((2-pos)<<3); + if (++pos>=3) { + pos=0; + ret+=base64Table[(groupOfThree>>18)&63]; + ret+=base64Table[(groupOfThree>>12)&63]; + ret+=base64Table[(groupOfThree>>6)&63]; + ret+=base64Table[groupOfThree&63]; + groupOfThree=0; + } + } + if (pos==2) { + ret+=base64Table[(groupOfThree>>18)&63]; + ret+=base64Table[(groupOfThree>>12)&63]; + ret+=base64Table[(groupOfThree>>6)&63]; + ret+='='; + } else if (pos==1) { + ret+=base64Table[(groupOfThree>>18)&63]; + ret+=base64Table[(groupOfThree>>12)&63]; + ret+="=="; + } + + return ret; +} + +std::string taDecodeBase64(const char* buf) { + std::string data; + + unsigned int groupOfThree=0; + signed char pos=18; + for (const char* i=buf; *i; i++) { + unsigned char nextVal=0; + if ((*i)=='/') { + nextVal=63; + } else if ((*i)=='+') { + nextVal=62; + } else if ((*i)>='0' && (*i)<='9') { + nextVal=52+((*i)-'0'); + } else if ((*i)>='a' && (*i)<='z') { + nextVal=26+((*i)-'a'); + } else if ((*i)>='A' && (*i)<='Z') { + nextVal=((*i)-'A'); + } else { + nextVal=0; + } + groupOfThree|=nextVal<>16)&0xff) data+=(groupOfThree>>16)&0xff; + if ((groupOfThree>>8)&0xff) data+=(groupOfThree>>8)&0xff; + if (groupOfThree&0xff) data+=groupOfThree&0xff; + groupOfThree=0; + } + } + + return data; +} diff --git a/src/baseutils.h b/src/baseutils.h new file mode 100644 index 000000000..438696aaa --- /dev/null +++ b/src/baseutils.h @@ -0,0 +1,28 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _BASEUTILS_H +#define _BASEUTILS_H + +#include + +std::string taEncodeBase64(const std::string& data); +std::string taDecodeBase64(const char* str); + +#endif diff --git a/src/engine/config.cpp b/src/engine/config.cpp index 47ff3997d..ce7b1b4ad 100644 --- a/src/engine/config.cpp +++ b/src/engine/config.cpp @@ -19,6 +19,7 @@ #include "config.h" #include "../ta-log.h" +#include "../baseutils.h" #include "../fileutils.h" #include @@ -48,41 +49,9 @@ String DivConfig::toString() { return ret; } -const char* base64Table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - String DivConfig::toBase64() { String data=toString(); - String ret; - - ret.reserve((2+data.size()*4)/3); - - unsigned int groupOfThree=0; - unsigned char pos=0; - for (char& i: data) { - groupOfThree|=((unsigned char)i)<<((2-pos)<<3); - if (++pos>=3) { - pos=0; - ret+=base64Table[(groupOfThree>>18)&63]; - ret+=base64Table[(groupOfThree>>12)&63]; - ret+=base64Table[(groupOfThree>>6)&63]; - ret+=base64Table[groupOfThree&63]; - groupOfThree=0; - } - } - if (pos==2) { - ret+=base64Table[(groupOfThree>>18)&63]; - ret+=base64Table[(groupOfThree>>12)&63]; - ret+=base64Table[(groupOfThree>>6)&63]; - ret+='='; - } else if (pos==1) { - ret+=base64Table[(groupOfThree>>18)&63]; - ret+=base64Table[(groupOfThree>>12)&63]; - ret+="=="; - } - - logV("toBase64: %s",ret); - - return ret; + return taEncodeBase64(data); } void DivConfig::parseLine(const char* line) { @@ -143,38 +112,7 @@ bool DivConfig::loadFromMemory(const char* buf) { } bool DivConfig::loadFromBase64(const char* buf) { - String data; - - unsigned int groupOfThree=0; - signed char pos=18; - for (const char* i=buf; *i; i++) { - unsigned char nextVal=0; - if ((*i)=='/') { - nextVal=63; - } else if ((*i)=='+') { - nextVal=62; - } else if ((*i)>='0' && (*i)<='9') { - nextVal=52+((*i)-'0'); - } else if ((*i)>='a' && (*i)<='z') { - nextVal=26+((*i)-'a'); - } else if ((*i)>='A' && (*i)<='Z') { - nextVal=((*i)-'A'); - } else { - nextVal=0; - } - groupOfThree|=nextVal<>16)&0xff) data+=(groupOfThree>>16)&0xff; - if ((groupOfThree>>8)&0xff) data+=(groupOfThree>>8)&0xff; - if (groupOfThree&0xff) data+=groupOfThree&0xff; - groupOfThree=0; - } - } - - logV("fromBase64: %s",data); - + String data=taDecodeBase64(buf); return loadFromMemory(data.c_str()); } diff --git a/src/engine/engine.h b/src/engine/engine.h index bea954fa4..50cabead1 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -440,8 +440,6 @@ class DivEngine { void reset(); void playSub(bool preserveDrift, int goalRow=0); - void convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivSystem sys); - bool loadDMF(unsigned char* file, size_t len); bool loadFur(unsigned char* file, size_t len); bool loadMod(unsigned char* file, size_t len); @@ -537,6 +535,10 @@ class DivEngine { static DivSystem systemFromFileDMF(unsigned char val); static unsigned char systemToFileDMF(DivSystem val); + // convert old flags + static void convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivSystem sys); + + // benchmark (returns time in seconds) double benchmarkPlayback(); double benchmarkSeek(); diff --git a/src/gui/gui.h b/src/gui/gui.h index b467daac6..36de61c54 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -913,10 +913,7 @@ struct FurnaceGUISysDefChip { struct FurnaceGUISysDef { const char* name; String definition; - FurnaceGUISysDef(const char* n, std::initializer_list def): - name(n) { - // fuck it - } + FurnaceGUISysDef(const char* n, std::initializer_list def); FurnaceGUISysDef(const char* n, std::initializer_list def); }; diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 5d009414a..d3080e3c1 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -18,6 +18,7 @@ */ #include "gui.h" +#include "../baseutils.h" #include // add system configurations here. @@ -2325,6 +2326,32 @@ void FurnaceGUI::initSystemPresets() { sysCategories.push_back(cat); } +FurnaceGUISysDef::FurnaceGUISysDef(const char* n, std::initializer_list def): + name(n) { + std::vector uncompiled=def; + int index=0; + + for (size_t i=0; i def): name(n) { std::vector uncompiled=def; @@ -2339,9 +2366,8 @@ FurnaceGUISysDef::FurnaceGUISysDef(const char* n, std::initializer_list Date: Sun, 13 Nov 2022 16:57:47 -0500 Subject: [PATCH 42/48] convert presets to new format, part 2 --- src/engine/engine.cpp | 12 ++++++++---- src/engine/engine.h | 4 ++-- src/gui/gui.cpp | 7 ++++++- src/gui/newSong.cpp | 2 +- src/gui/presets.cpp | 8 ++++---- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 630fba01f..32caa97ba 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1390,10 +1390,14 @@ String DivEngine::decodeSysDesc(String desc) { return newDesc.toBase64(); } -void DivEngine::initSongWithDesc(const char* description) { +void DivEngine::initSongWithDesc(const char* description, bool inBase64) { int chanCount=0; DivConfig c; - c.loadFromBase64(description); + if (inBase64) { + c.loadFromBase64(description); + } else { + c.loadFromMemory(description); + } int index=0; for (; index<32; index++) { song.system[index]=systemFromFileFur(c.getInt(fmt::sprintf("id%d",index),0)); @@ -1414,7 +1418,7 @@ void DivEngine::initSongWithDesc(const char* description) { song.systemLen=index; } -void DivEngine::createNew(const char* description, String sysName) { +void DivEngine::createNew(const char* description, String sysName, bool inBase64) { quitDispatch(); BUSY_BEGIN; saveLock.lock(); @@ -1422,7 +1426,7 @@ void DivEngine::createNew(const char* description, String sysName) { song=DivSong(); changeSong(0); if (description!=NULL) { - initSongWithDesc(description); + initSongWithDesc(description,inBase64); } if (sysName=="") { song.systemName=getSongSystemLegacyName(song,!getConfInt("noMultiSystem",0)); diff --git a/src/engine/engine.h b/src/engine/engine.h index 50cabead1..c47911cb2 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -467,7 +467,7 @@ class DivEngine { bool deinitAudioBackend(bool dueToSwitchMaster=false); void registerSystems(); - void initSongWithDesc(const char* description); + void initSongWithDesc(const char* description, bool inBase64=true); void exchangeIns(int one, int two); void swapChannels(int src, int dest); @@ -501,7 +501,7 @@ class DivEngine { // parse old system setup description String decodeSysDesc(String desc); // start fresh - void createNew(const char* description, String sysName); + void createNew(const char* description, String sysName, bool inBase64=true); // load a file. bool load(unsigned char* f, size_t length); // save as .dmf. diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 845af6384..dc5e6d6cf 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4438,9 +4438,14 @@ bool FurnaceGUI::loop() { ImGui::EndPopup(); } - ImGui::SetNextWindowSizeConstraints(ImVec2(400.0f*dpiScale,200.0f*dpiScale),ImVec2(canvasW,canvasH)); + ImVec2 newSongMinSize=mobileUI?ImVec2(canvasW-(portrait?0:(60.0*dpiScale)),canvasH-60.0*dpiScale):ImVec2(400.0f*dpiScale,200.0f*dpiScale); + ImVec2 newSongMaxSize=ImVec2(canvasW-((mobileUI && !portrait)?(60.0*dpiScale):0),canvasH-(mobileUI?(60.0*dpiScale):0)); + ImGui::SetNextWindowSizeConstraints(newSongMinSize,newSongMaxSize); if (ImGui::BeginPopupModal("New Song",NULL,ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoScrollbar)) { ImGui::SetWindowPos(ImVec2(((canvasW)-ImGui::GetWindowSize().x)*0.5,((canvasH)-ImGui::GetWindowSize().y)*0.5)); + if (ImGui::GetWindowSize().xcreateNew(nextDesc.c_str(),nextDescName); + e->createNew(nextDesc.c_str(),nextDescName,false); undoHist.clear(); redoHist.clear(); curFileName=""; diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index d3080e3c1..74255c550 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -2335,16 +2335,16 @@ FurnaceGUISysDef::FurnaceGUISysDef(const char* n, std::initializer_list def if (uncompiled[i]==0) break; DivConfig oldFlags; - DivEngine::convertOldFlags(uncompiled[3],oldFlags,(DivSystem)uncompiled[0]); + DivEngine::convertOldFlags(uncompiled[i+3],oldFlags,(DivSystem)uncompiled[i]); definition+=fmt::sprintf( "id%d=%d\nvol%d=%d\npan%d=%d\nflags%d=%s\n", index, - DivEngine::systemToFileFur((DivSystem)uncompiled[0]), + DivEngine::systemToFileFur((DivSystem)uncompiled[i]), index, - uncompiled[1], + uncompiled[i+1], index, - uncompiled[2], + uncompiled[i+2], index, oldFlags.toBase64() ); From 9ef3ec19bcc15ce236bf6e67fb98fb8b4b89041c Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Sun, 13 Nov 2022 22:59:28 +0100 Subject: [PATCH 43/48] fix YM2151 LFO shapes, correct some presets (#741) * fix YM2151 LFO shapes, correct some presets * pc-98 beeper clocks 1 for less advanced, earlier sound sources, 2 for more advanced, later era * revert the last commit * Revert "revert the last commit" This reverts commit 0746f37052a46e5c0cf503590d3062da7d82dd20. zmieniono: src/gui/presets.cpp * Revert "pc-98 beeper clocks" This reverts commit ba78cd44d88181d79733f6f30196bc588c762a33. zmieniono: src/gui/presets.cpp * remove beeper from zx128 finally caring about hw playback ey --- src/gui/insEdit.cpp | 2 +- src/gui/presets.cpp | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 8ee173d52..b762e0924 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -411,7 +411,7 @@ String macroLFOWaves(int id, float val, void* u) { case 1: return "Square"; case 2: - return "Sine"; + return "Triangle"; case 3: return "Random"; default: diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 74255c550..4566c568a 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -442,12 +442,14 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with PC-9801-26/K)", { DIV_SYSTEM_OPN, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with PC-9801-26/K; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -455,6 +457,7 @@ void FurnaceGUI::initSystemPresets() { "NEC PC-98 (with Sound Orchestra)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_OPL2, 64, 0, 4, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -462,6 +465,7 @@ void FurnaceGUI::initSystemPresets() { "NEC PC-98 (with Sound Orchestra; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_OPL2, 64, 0, 4, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -469,6 +473,7 @@ void FurnaceGUI::initSystemPresets() { "NEC PC-98 (with Sound Orchestra in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 4, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -476,6 +481,7 @@ void FurnaceGUI::initSystemPresets() { "NEC PC-98 (with Sound Orchestra in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 4, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -483,6 +489,7 @@ void FurnaceGUI::initSystemPresets() { "NEC PC-98 (with Sound Orchestra V)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_Y8950, 64, 0, 4, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -490,6 +497,7 @@ void FurnaceGUI::initSystemPresets() { "NEC PC-98 (with Sound Orchestra V; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_Y8950, 64, 0, 4, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -497,6 +505,7 @@ void FurnaceGUI::initSystemPresets() { "NEC PC-98 (with Sound Orchestra V in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 4, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -504,6 +513,7 @@ void FurnaceGUI::initSystemPresets() { "NEC PC-98 (with Sound Orchestra V in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 4, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -512,6 +522,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PC98, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), // 2x 16-bit Burr Brown DAC DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -520,18 +531,21 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PC98_EXT, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with PC-9801-73)", { DIV_SYSTEM_PC98, 64, 0, 1, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with PC-9801-73; extended channel 3)", { DIV_SYSTEM_PC98_EXT, 64, 0, 1, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -540,6 +554,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3, 64, 0, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -548,6 +563,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3, 64, 0, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -556,6 +572,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); @@ -564,19 +581,19 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, + DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "ZX Spectrum (48K)", { - DIV_SYSTEM_AY8910, 64, 0, 2, DIV_SYSTEM_SFX_BEEPER, 64, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "ZX Spectrum (128K)", { - DIV_SYSTEM_AY8910, 64, 0, 1, + DIV_SYSTEM_AY8910, 64, 0, 1, //beeper was also included 0 } )); From c5df68f8af6085597f1a0b2d5e9cb5d7845b569c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 13 Nov 2022 18:29:37 -0500 Subject: [PATCH 44/48] GUI: improve create ins from sample functionality pull request #740 --- src/engine/engine.cpp | 15 +++++++++++---- src/engine/engine.h | 2 +- src/gui/dataList.cpp | 5 +++++ src/gui/doAction.cpp | 42 +++++++++++++++++++++++++++++++++++++++++- src/gui/gui.cpp | 32 ++++++++++++++++++++++++++++++++ src/gui/gui.h | 5 ++++- 6 files changed, 94 insertions(+), 7 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 32caa97ba..d9e236016 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2686,12 +2686,17 @@ void DivEngine::unmuteAll() { BUSY_END; } -int DivEngine::addInstrument(int refChan) { +int DivEngine::addInstrument(int refChan, DivInstrumentType fallbackType) { if (song.ins.size()>=256) return -1; BUSY_BEGIN; DivInstrument* ins=new DivInstrument; int insCount=(int)song.ins.size(); - DivInstrumentType prefType=getPreferInsType(refChan); + DivInstrumentType prefType; + if (refChan<0) { + prefType=fallbackType; + } else { + prefType=getPreferInsType(refChan); + } switch (prefType) { case DIV_INS_OPLL: *ins=song.nullInsOPLL; @@ -2705,8 +2710,10 @@ int DivEngine::addInstrument(int refChan) { default: break; } - if (sysOfChan[refChan]==DIV_SYSTEM_QSOUND) { - *ins=song.nullInsQSound; + if (refChan>=0) { + if (sysOfChan[refChan]==DIV_SYSTEM_QSOUND) { + *ins=song.nullInsQSound; + } } ins->name=fmt::sprintf("Instrument %d",insCount); if (prefType!=DIV_INS_NULL) { diff --git a/src/engine/engine.h b/src/engine/engine.h index c47911cb2..4a36b27d7 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -759,7 +759,7 @@ class DivEngine { bool isExporting(); // add instrument - int addInstrument(int refChan=0); + int addInstrument(int refChan=0, DivInstrumentType fallbackType=DIV_INS_STD); // add instrument from pointer int addInstrumentPtr(DivInstrument* which); diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 8a62c822f..20f66dd59 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -60,6 +60,11 @@ void FurnaceGUI::drawInsList(bool asChild) { } ImGui::EndPopup(); } + } else { + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + displayInsTypeList=true; + displayInsTypeListMakeInsSample=-1; + } } ImGui::SameLine(); if (ImGui::Button(ICON_FA_FILES_O "##InsClone")) { diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index d4145276b..941d037c5 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -1291,14 +1291,54 @@ void FurnaceGUI::doAction(int what) { break; case GUI_ACTION_SAMPLE_MAKE_INS: { if (curSample<0 || curSample>=(int)e->song.sample.size()) break; + // determine instrument type + std::vector tempTypeList=e->getPossibleInsTypes(); + makeInsTypeList.clear(); + + for (DivInstrumentType& i: tempTypeList) { + if (i==DIV_INS_PCE || + i==DIV_INS_MSM6258 || + i==DIV_INS_MSM6295 || + i==DIV_INS_ADPCMA || + i==DIV_INS_ADPCMB || + i==DIV_INS_SEGAPCM || + i==DIV_INS_QSOUND || + i==DIV_INS_YMZ280B || + i==DIV_INS_RF5C68 || + i==DIV_INS_MULTIPCM || + i==DIV_INS_MIKEY || + i==DIV_INS_X1_010 || + i==DIV_INS_SWAN || + i==DIV_INS_AY || + i==DIV_INS_AY8930 || + i==DIV_INS_VRC6 || + i==DIV_INS_SU || + i==DIV_INS_SNES || + i==DIV_INS_ES5506) { + makeInsTypeList.push_back(i); + } + } + + if (makeInsTypeList.size()>1) { + displayInsTypeList=true; + displayInsTypeListMakeInsSample=curSample; + break; + } + + DivInstrumentType insType=DIV_INS_AMIGA; + if (!makeInsTypeList.empty()) { + insType=makeInsTypeList[0]; + } + DivSample* sample=e->song.sample[curSample]; curIns=e->addInstrument(cursor.xCoarse); if (curIns==-1) { showError("too many instruments!"); } else { - e->song.ins[curIns]->type=DIV_INS_AMIGA; + e->song.ins[curIns]->type=insType; e->song.ins[curIns]->name=sample->name; e->song.ins[curIns]->amiga.initSample=curSample; + if (insType!=DIV_INS_AMIGA) e->song.ins[curIns]->amiga.useSample=true; nextWindow=GUI_WINDOW_INS_EDIT; MARK_MODIFIED; wavePreviewInit=true; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index dc5e6d6cf..93c333689 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4409,6 +4409,11 @@ bool FurnaceGUI::loop() { ImGui::OpenPopup("Import Raw Sample"); } + if (displayInsTypeList) { + displayInsTypeList=false; + ImGui::OpenPopup("InsTypeList"); + } + if (displayExporting) { displayExporting=false; ImGui::OpenPopup("Rendering..."); @@ -4789,6 +4794,31 @@ bool FurnaceGUI::loop() { ImGui::EndPopup(); } + if (ImGui::BeginPopup("InsTypeList",ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings)) { + char temp[1024]; + for (DivInstrumentType& i: makeInsTypeList) { + strncpy(temp,insTypes[i],1023); + if (ImGui::MenuItem(temp)) { + // create ins + curIns=e->addInstrument(-1,i); + if (curIns==-1) { + showError("too many instruments!"); + } else { + if (displayInsTypeListMakeInsSample>=0 && displayInsTypeListMakeInsSample<(int)e->song.sample.size()) { + e->song.ins[curIns]->type=i; + e->song.ins[curIns]->name=e->song.sample[displayInsTypeListMakeInsSample]->name; + e->song.ins[curIns]->amiga.initSample=displayInsTypeListMakeInsSample; + if (i!=DIV_INS_AMIGA) e->song.ins[curIns]->amiga.useSample=true; + nextWindow=GUI_WINDOW_INS_EDIT; + wavePreviewInit=true; + } + MARK_MODIFIED; + } + } + } + ImGui::EndPopup(); + } + // TODO: // - multiple selection // - replace instrument @@ -5506,6 +5536,7 @@ FurnaceGUI::FurnaceGUI(): zsmExportLoop(true), vgmExportPatternHints(false), vgmExportDirectStream(false), + displayInsTypeList(false), portrait(false), injectBackUp(false), mobileMenuOpen(false), @@ -5526,6 +5557,7 @@ FurnaceGUI::FurnaceGUI(): zsmExportTickRate(60), macroPointSize(16), waveEditStyle(0), + displayInsTypeListMakeInsSample(-1), mobileMenuPos(0.0f), autoButtonSize(0.0f), curSysSection(NULL), diff --git a/src/gui/gui.h b/src/gui/gui.h index 36de61c54..29ece540b 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1055,9 +1055,11 @@ class FurnaceGUI { std::vector sysSearchResults; std::vector newSongSearchResults; std::deque recentFile; + std::vector makeInsTypeList; + bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, zsmExportLoop, vgmExportPatternHints; - bool vgmExportDirectStream; + bool vgmExportDirectStream, displayInsTypeList; bool portrait, injectBackUp, mobileMenuOpen; bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly; @@ -1068,6 +1070,7 @@ class FurnaceGUI { int zsmExportTickRate; int macroPointSize; int waveEditStyle; + int displayInsTypeListMakeInsSample; float mobileMenuPos, autoButtonSize; const int* curSysSection; From 23d3081fa7f8453a338be127b82f12f0046dc569 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Mon, 14 Nov 2022 15:50:13 +0100 Subject: [PATCH 45/48] Add X1-010 + MSM6258 demo track --- demos/splashingwater.fur | Bin 0 -> 46239 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/splashingwater.fur diff --git a/demos/splashingwater.fur b/demos/splashingwater.fur new file mode 100644 index 0000000000000000000000000000000000000000..e983d7c14c475220a3a099d0931abafc566c8804 GIT binary patch literal 46239 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≧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 literal 0 HcmV?d00001 From 3377ade9e6ae78ecc680dd9d0c9641a98bd3db96 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 14 Nov 2022 13:35:11 -0500 Subject: [PATCH 46/48] convert presets to new format, part 3 --- papers/doc/7-systems/ym2612.md | 2 -- src/gui/about.cpp | 1 - src/gui/presets.cpp | 22 +++++++++++----------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/papers/doc/7-systems/ym2612.md b/papers/doc/7-systems/ym2612.md index 56b1a3b18..ac17cedc3 100644 --- a/papers/doc/7-systems/ym2612.md +++ b/papers/doc/7-systems/ym2612.md @@ -2,8 +2,6 @@ one of two chips that powered the Sega Genesis. It is a six-channel, four-operator FM synthesizer. Channel #6 can be turned into 8-bit PCM player. -For 0.6pre1, Furnace can now support advanced YM2612 features that [Fractal](https://gitlab.com/Natsumi/Fractal-Sound) sound driver adds: two software-mixed PCM channels (variable pitch, sample offsets, max 13.7 khz rate) and CSM - ch3 special mode feature that can be abused to produce rudimentary speech synthesis. - # effects - `10xy`: set LFO parameters. diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 6d8aeaee1..924f2c0cc 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -155,7 +155,6 @@ const char* aboutLine[]={ "MSM6295 emulator by cam900", "", "greetings to:", - "Fractal Sound team", "NEOART Costa Rica", "all members of Deflers of Noice!", "", diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 4566c568a..7a11ceef3 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -25,12 +25,14 @@ // every entry is written in the following format: // cat.systems.push_back(FurnaceGUISysDef( // "System Name", { -// DIV_SYSTEM_???, Volume, Panning, Flags, -// DIV_SYSTEM_???, Volume, Panning, Flags, +// CH(DIV_SYSTEM_???, Volume, Panning, Flags), +// CH(DIV_SYSTEM_???, Volume, Panning, Flags), // ... -// 0 // } // )); +// flags are a string of new line-separated values. + +#define CH FurnaceGUISysDefChip void FurnaceGUI::initSystemPresets() { sysCategories.clear(); @@ -40,27 +42,25 @@ void FurnaceGUI::initSystemPresets() { cat=FurnaceGUISysCategory("Game consoles","let's play some chiptune making games!"); cat.systems.push_back(FurnaceGUISysDef( "Sega Genesis", { - DIV_SYSTEM_YM2612, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, "") } )); cat.systems.push_back(FurnaceGUISysDef( "Sega Genesis (extended channel 3)", { - DIV_SYSTEM_YM2612_EXT, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_EXT, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, "") } )); cat.systems.push_back(FurnaceGUISysDef( - "Sega Genesis (Fractal Sound template)", { + "Sega Genesis (DualPCM)", { DIV_SYSTEM_YM2612_FRAC, 64, 0, 0, DIV_SYSTEM_SMS, 32, 0, 0, 0 } )); cat.systems.push_back(FurnaceGUISysDef( - "Sega Genesis (Fractal Sound template, extended channel 3)", { + "Sega Genesis (DualPCM, extended channel 3)", { DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, 0, DIV_SYSTEM_SMS, 32, 0, 0, 0 From 27323e9f7b3f3d20bfea2784eeb46a2a78a39032 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 14 Nov 2022 14:14:33 -0500 Subject: [PATCH 47/48] convert presets to new format, part 4 --- src/gui/presets.cpp | 1361 ++++++++++++++++++++++--------------------- 1 file changed, 682 insertions(+), 679 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 7a11ceef3..a596ceebc 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -23,356 +23,359 @@ // add system configurations here. // every entry is written in the following format: -// cat.systems.push_back(FurnaceGUISysDef( +// ENTRY( // "System Name", { // CH(DIV_SYSTEM_???, Volume, Panning, Flags), // CH(DIV_SYSTEM_???, Volume, Panning, Flags), // ... -// } -// )); +// } +// ); // flags are a string of new line-separated values. #define CH FurnaceGUISysDefChip +#define CATEGORY_BEGIN(x,y) cat=FurnaceGUISysCategory(x,y); +#define CATEGORY_END sysCategories.push_back(cat); +#define ENTRY(...) cat.systems.push_back(FurnaceGUISysDef(__VA_ARGS__)); void FurnaceGUI::initSystemPresets() { sysCategories.clear(); FurnaceGUISysCategory cat; - cat=FurnaceGUISysCategory("Game consoles","let's play some chiptune making games!"); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Game consoles","let's play some chiptune making games!"); + ENTRY( "Sega Genesis", { CH(DIV_SYSTEM_YM2612, 64, 0, ""), CH(DIV_SYSTEM_SMS, 32, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Genesis (extended channel 3)", { CH(DIV_SYSTEM_YM2612_EXT, 64, 0, ""), CH(DIV_SYSTEM_SMS, 32, 0, "") } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Genesis (DualPCM)", { DIV_SYSTEM_YM2612_FRAC, 64, 0, 0, DIV_SYSTEM_SMS, 32, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Genesis (DualPCM, extended channel 3)", { DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, 0, DIV_SYSTEM_SMS, 32, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Genesis (with Sega CD)", { DIV_SYSTEM_YM2612, 64, 0, 0, DIV_SYSTEM_SMS, 32, 0, 0, DIV_SYSTEM_RF5C68, 64, 0, 18, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Genesis (extended channel 3 with Sega CD)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 0, DIV_SYSTEM_SMS, 32, 0, 0, DIV_SYSTEM_RF5C68, 64, 0, 18, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Master System", { DIV_SYSTEM_SMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Master System (with FM expansion)", { DIV_SYSTEM_SMS, 64, 0, 0, DIV_SYSTEM_OPLL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Master System (with FM expansion in drums mode)", { DIV_SYSTEM_SMS, 64, 0, 0, DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Game Gear", { DIV_SYSTEM_SMS, 64, 0, 0xc, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Game Boy", { DIV_SYSTEM_GB, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC Engine/TurboGrafx-16", { DIV_SYSTEM_PCE, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NES", { DIV_SYSTEM_NES, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with Konami VRC6", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_VRC6, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with Konami VRC7", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_VRC7, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with MMC5", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_MMC5, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with Sunsoft 5B", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 32, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with Namco 163", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_N163, 64, 0, 112, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Comboy with Family Noraebang", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_OPLL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Comboy with Family Noraebang (drums mode)", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom Disk System", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_FDS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNES", { DIV_SYSTEM_SNES, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Mattel Intellivision", { DIV_SYSTEM_AY8910, 64, 0, 48, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Vectrex", { DIV_SYSTEM_AY8910, 64, 0, 4, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo AES", { DIV_SYSTEM_YM2610_FULL, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo AES (extended channel 2)", { DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari 2600/7800", { DIV_SYSTEM_TIA, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari Lynx", { DIV_SYSTEM_LYNX, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "WonderSwan", { DIV_SYSTEM_SWAN, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Virtual Boy", { DIV_SYSTEM_VBOY, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Gamate", { DIV_SYSTEM_AY8910, 64, 0, 73, 0 } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("Computers","let's get to work on chiptune today."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Computers","let's get to work on chiptune today."); + ENTRY( "Commodore PET", { DIV_SYSTEM_PET, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore VIC-20", { DIV_SYSTEM_VIC20, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID)", { DIV_SYSTEM_C64_6581, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID)", { DIV_SYSTEM_C64_8580, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID + Sound Expander)", { DIV_SYSTEM_C64_6581, 64, 0, 1, DIV_SYSTEM_OPL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID + Sound Expander in drums mode)", { DIV_SYSTEM_C64_6581, 64, 0, 1, DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID + Sound Expander)", { DIV_SYSTEM_C64_8580, 64, 0, 1, DIV_SYSTEM_OPL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID + Sound Expander in drums mode)", { DIV_SYSTEM_C64_8580, 64, 0, 1, DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID + FM-YAM)", { DIV_SYSTEM_C64_6581, 64, 0, 1, DIV_SYSTEM_OPL2, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID + FM-YAM in drums mode)", { DIV_SYSTEM_C64_6581, 64, 0, 1, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID + FM-YAM)", { DIV_SYSTEM_C64_8580, 64, 0, 1, DIV_SYSTEM_OPL2, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID + FM-YAM in drums mode)", { DIV_SYSTEM_C64_8580, 64, 0, 1, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Amiga", { DIV_SYSTEM_AMIGA, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX", { DIV_SYSTEM_AY8910, 64, 0, 16, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + SFG-01", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_YM2151, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + MSX-AUDIO", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_Y8950, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + MSX-AUDIO (drums mode)", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + MSX-MUSIC", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_OPLL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + MSX-MUSIC (drums mode)", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Darky", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_AY8930, 64, 0, 139, // 3.58MHz @@ -380,8 +383,8 @@ void FurnaceGUI::initSystemPresets() { // per-channel mixer (soft panning, post processing) isn't emulated at all 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Playsoniq", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_SMS, 64, 0, 0, // Sega VDP @@ -389,135 +392,135 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_SCC_PLUS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + SCC", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_SCC, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + SCC+", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_SCC_PLUS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Neotron", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_YM2610_FULL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Neotron (extended channel 2)", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Neotron (with YM2610B)", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_YM2610B, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + Neotron (with YM2610B; extended channel 3)", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_YM2610B_EXT, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MSX + SIMPL", { DIV_SYSTEM_AY8910, 64, 0, 16, DIV_SYSTEM_PCM_DAC, 64, 0, 55929|(7<<16), // variable rate, Mono DAC 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-26/K)", { DIV_SYSTEM_OPN, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-26/K; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_OPL2, 64, 0, 4, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_OPL2, 64, 0, 4, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 4, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 4, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra V)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_Y8950, 64, 0, 4, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra V; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_Y8950, 64, 0, 4, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra V in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 4, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Orchestra V in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 4, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-86)", { // -73 also has OPNA DIV_SYSTEM_PC98, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), // 2x 16-bit Burr Brown DAC @@ -525,8 +528,8 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-86; extended channel 3)", { // -73 also has OPNA DIV_SYSTEM_PC98_EXT, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), @@ -534,22 +537,22 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-73)", { DIV_SYSTEM_PC98, 64, 0, 1, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with PC-9801-73; extended channel 3)", { DIV_SYSTEM_PC98_EXT, 64, 0, 1, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible)", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), @@ -557,8 +560,8 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), @@ -566,8 +569,8 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), @@ -575,8 +578,8 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), @@ -584,164 +587,164 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (48K)", { DIV_SYSTEM_SFX_BEEPER, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K)", { DIV_SYSTEM_AY8910, 64, 0, 1, //beeper was also included 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K) with TurboSound FM", { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K) with TurboSound FM (extended channel 3 on first OPN)", { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K) with TurboSound FM (extended channel 3 on second OPN)", { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K) with TurboSound FM (extended channel 3 on both OPNs)", { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (128K) with TurboSound", { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_AY8910, 64, 0, 1, // or YM2149 DIV_SYSTEM_AY8910, 64, 0, 1, // or YM2149 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Amstrad CPC", { DIV_SYSTEM_AY8910, 64, 0, 5, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari ST", { DIV_SYSTEM_AY8910, 64, 0, 19, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari STE", { DIV_SYSTEM_AY8910, 64, 0, 19, DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SAM CoupĂ©", { DIV_SYSTEM_SAA1099, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "BBC Micro", { DIV_SYSTEM_SMS, 64, 0, 0x42, // SN76489A 4MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC (barebones)", { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "IBM PCjr", { // it can be enable sound output at once DIV_SYSTEM_SMS, 64, 0, 0x44, // SN76496 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tandy 1000", { DIV_SYSTEM_SMS, 64, 0, 0x44, // NCR 8496 or SN76496 or Tandy PSSJ(with 8 bit DAC) DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Covox Sound Master", { DIV_SYSTEM_AY8930, 64, 0, 3, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + SSI 2001", { DIV_SYSTEM_C64_6581, 64, 0, 2, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Game Blaster", { DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + AdLib", { DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + AdLib (drums mode)", { DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster", { DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + AdLib/Sound Blaster (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster w/Game Blaster Compatible", { DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_SAA1099, 64, 0, 1, @@ -750,8 +753,8 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster w/Game Blaster Compatible (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, DIV_SYSTEM_SAA1099, 64, 0, 1, @@ -760,8 +763,8 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster Pro", { DIV_SYSTEM_OPL2, 64, -127, 0, DIV_SYSTEM_OPL2, 64, 127, 0, @@ -769,8 +772,8 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster Pro (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, -127, 0, DIV_SYSTEM_OPL2_DRUMS, 64, 127, 0, @@ -778,31 +781,31 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster Pro 2", { DIV_SYSTEM_OPL3, 64, 0, 0, DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + Sound Blaster Pro 2 (drums mode)", { DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + PC-FXGA", { DIV_SYSTEM_PCE, 64, 0, 0, // HuC6230 (WSG from HuC6280 but with built in 2 OKI ADPCM playback engines) DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC + SAAYM", { DIV_SYSTEM_YM2151, 64, 0, 0, // 3.58MHz or 4MHz selectable via jumper DIV_SYSTEM_SAA1099, 64, 0, 1, // 7.16MHz or 8MHz selectable via jumper @@ -810,563 +813,563 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sharp X1", { DIV_SYSTEM_AY8910, 64, 0, 3, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sharp X1 + FM Addon", { DIV_SYSTEM_AY8910, 64, 0, 3, DIV_SYSTEM_YM2151, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sharp X68000", { DIV_SYSTEM_YM2151, 64, 0, 2, DIV_SYSTEM_MSM6258, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "FM Towns", { DIV_SYSTEM_YM2612, 64, 0, 2, // YM3438 DIV_SYSTEM_RF5C68, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commander X16", { DIV_SYSTEM_VERA, 64, 0, 0, DIV_SYSTEM_YM2151, 32, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "TI-99/4A", { DIV_SYSTEM_SMS, 64, 0, 0x182, // SN94624 447KHz 0 } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("FM","chips which use frequency modulation (FM) to generate sound.\nsome of these also pack more (like square and sample channels)."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("FM","chips which use frequency modulation (FM) to generate sound.\nsome of these also pack more (like square and sample channels)."); + ENTRY( "Yamaha YM2151 (OPM)", { DIV_SYSTEM_YM2151, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2203 (OPN)", { DIV_SYSTEM_OPN, 64, 0, 3, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2203 (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2608 (OPNA)", { DIV_SYSTEM_PC98, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2608 (extended channel 3)", { DIV_SYSTEM_PC98_EXT, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2610 (OPNB)", { DIV_SYSTEM_YM2610_FULL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2610 (extended channel 2)", { DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2610B (OPNB2)", { DIV_SYSTEM_YM2610B, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2610B (extended channel 3)", { DIV_SYSTEM_YM2610B_EXT, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2612 (OPN2)", { DIV_SYSTEM_YM2612, 64, 0, (int)0x80000000, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2612 (extended channel 3)", { DIV_SYSTEM_YM2612_EXT, 64, 0, (int)0x80000000, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2612 (OPN2) with DualPCM", { DIV_SYSTEM_YM2612_FRAC, 64, 0, (int)0x80000000, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2612 (extended channel 3) with DualPCM", { DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, (int)0x80000000, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2413 (OPLL)", { DIV_SYSTEM_OPLL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2413 (drums mode)", { DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2414 (OPZ)", { DIV_SYSTEM_OPZ, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3438 (OPN2C)", { DIV_SYSTEM_YM2612, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3438 (extended channel 3)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3438 (OPN2C) with DualPCM", { DIV_SYSTEM_YM2612_FRAC, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3438 (extended channel 3) with DualPCM", { DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3526 (OPL)", { DIV_SYSTEM_OPL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3526 (drums mode)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha Y8950", { DIV_SYSTEM_Y8950, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha Y8950 (drums mode)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3812 (OPL2)", { DIV_SYSTEM_OPL2, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM3812 (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YMF262 (OPL3)", { DIV_SYSTEM_OPL3, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YMF262 (drums mode)", { DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, 0 } - )); + ); if (settings.hiddenSystems) { - cat.systems.push_back(FurnaceGUISysDef( + ENTRY( "Yamaha YMU759 (MA-2)", { DIV_SYSTEM_YMU759, 64, 0, 0, 0 } - )); + ); } - sysCategories.push_back(cat); + CATEGORY_END; - cat=FurnaceGUISysCategory("Square","these chips generate square/pulse tones only (but may include noise)."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Square","these chips generate square/pulse tones only (but may include noise)."); + ENTRY( "TI SN76489", { DIV_SYSTEM_SMS, 64, 0, 4, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "TI SN76489A", { DIV_SYSTEM_SMS, 64, 0, 0x40, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "TI SN76496", { DIV_SYSTEM_SMS, 64, 0, 0x44, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NCR 8496", { DIV_SYSTEM_SMS, 64, 0, 0x48, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tandy PSSJ 3-voice sound", { DIV_SYSTEM_SMS, 64, 0, 0x4c, // 8 bit DAC 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega PSG (SN76489-like)", { DIV_SYSTEM_SMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega PSG (SN76489-like, Stereo)", { DIV_SYSTEM_SMS, 64, 0, 0xc, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "TI SN94624", { DIV_SYSTEM_SMS, 64, 0, 0x182, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "TI SN76494", { DIV_SYSTEM_SMS, 64, 0, 0x186, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Toshiba T6W28", { DIV_SYSTEM_T6W28, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "AY-3-8910", { DIV_SYSTEM_AY8910, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "AY-3-8914", { DIV_SYSTEM_AY8910, 64, 0, 48, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YM2149(F)", { DIV_SYSTEM_AY8910, 64, 0, 16, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Philips SAA1099", { DIV_SYSTEM_SAA1099, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "PC Speaker", { DIV_SYSTEM_PCSPKR, 32, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore VIC", { DIV_SYSTEM_VIC20, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "OKI MSM5232", { DIV_SYSTEM_MSM5232, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Pong", { DIV_SYSTEM_PONG, 64, 0, 0, 0 } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("Sample","chips/systems which use PCM or ADPCM samples for sound synthesis."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Sample","chips/systems which use PCM or ADPCM samples for sound synthesis."); + ENTRY( "Amiga", { DIV_SYSTEM_AMIGA, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SegaPCM", { DIV_SYSTEM_SEGAPCM, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom QSound", { DIV_SYSTEM_QSOUND, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta/Allumer X1-010", { DIV_SYSTEM_X1_010, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Yamaha YMZ280B (PCMD8)", { DIV_SYSTEM_YMZ280B, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Ricoh RF5C68", { DIV_SYSTEM_RF5C68, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "OKI MSM6258", { DIV_SYSTEM_MSM6258, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "OKI MSM6295", { DIV_SYSTEM_MSM6295, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNES", { DIV_SYSTEM_SNES, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Generic PCM DAC", { DIV_SYSTEM_PCM_DAC, 64, 0, 0, 0 } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("Wavetable","chips which use user-specified waveforms to generate sound."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Wavetable","chips which use user-specified waveforms to generate sound."); + ENTRY( "PC Engine", { DIV_SYSTEM_PCE, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore PET (pseudo-wavetable)", { DIV_SYSTEM_PET, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Bubble System WSG", { DIV_SYSTEM_BUBSYS_WSG, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami SCC", { DIV_SYSTEM_SCC, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami SCC+", { DIV_SYSTEM_SCC_PLUS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco WSG", { DIV_SYSTEM_NAMCO, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco C15 (8-channel mono)", { DIV_SYSTEM_NAMCO_15XX, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco C30 (8-channel stereo)", { DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco 163", { DIV_SYSTEM_N163, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom Disk System (chip)", { DIV_SYSTEM_FDS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "WonderSwan", { DIV_SYSTEM_SWAN, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Virtual Boy", { DIV_SYSTEM_VBOY, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta/Allumer X1-010", { DIV_SYSTEM_X1_010, 64, 0, 0, 0 } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("Specialized","chips/systems with unique sound synthesis methods."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Specialized","chips/systems with unique sound synthesis methods."); + ENTRY( "MOS Technology SID (6581)", { DIV_SYSTEM_C64_6581, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "MOS Technology SID (8580)", { DIV_SYSTEM_C64_8580, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Microchip AY8930", { DIV_SYSTEM_AY8930, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Game Boy", { DIV_SYSTEM_GB, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari Lynx", { DIV_SYSTEM_LYNX, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari TIA", { DIV_SYSTEM_TIA, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NES (Ricoh 2A03)", { DIV_SYSTEM_NES, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commander X16 (VERA only)", { DIV_SYSTEM_VERA, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ZX Spectrum (beeper only)", { DIV_SYSTEM_SFX_BEEPER, 64, 0, 0, 0 } - )); + ); if (settings.hiddenSystems) { - cat.systems.push_back(FurnaceGUISysDef( + ENTRY( "Dummy System", { DIV_SYSTEM_DUMMY, 64, 0, 0, 0 } - )); + ); } - cat.systems.push_back(FurnaceGUISysDef( + ENTRY( "tildearrow Sound Unit", { DIV_SYSTEM_SOUND_UNIT, 64, 0, 0, 0 } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("Arcade systems","INSERT COIN"); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("Arcade systems","INSERT COIN"); + ENTRY( "Pong", { DIV_SYSTEM_PONG, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Bally Midway MCR", { // SSIO sound board DIV_SYSTEM_AY8910, 64, 0, 3, // 2MHz @@ -1374,8 +1377,8 @@ void FurnaceGUI::initSystemPresets() { // additional sound boards, mostly software controlled DAC 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Williams/Midway Y/T unit w/ADPCM sound board", { // ADPCM sound board DIV_SYSTEM_YM2151, 64, 0, 0, @@ -1383,8 +1386,8 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_MSM6295, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Gyruss", { DIV_SYSTEM_AY8910, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 0, @@ -1394,8 +1397,8 @@ void FurnaceGUI::initSystemPresets() { // additional discrete sound logics 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Bubble System", { DIV_SYSTEM_AY8910, 64, 0, 0, DIV_SYSTEM_AY8910, 64, 0, 0, @@ -1403,496 +1406,496 @@ void FurnaceGUI::initSystemPresets() { // VLM5030 exists but not used for music at all 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Battlantis", { DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2, 64, 0, 3, // "" 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Battlantis (drums mode on first OPL2)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2, 64, 0, 3, // "" 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Battlantis (drums mode on second OPL2)", { DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // "" 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Battlantis (drums mode on both OPL2s)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // "" 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Konami Hexion", { DIV_SYSTEM_SCC, 64, 0, 2, // 1.5MHz (3MHz input) DIV_SYSTEM_MSM6295, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Kyugo", { DIV_SYSTEM_AY8910, 64, 0, 14, DIV_SYSTEM_AY8910, 64, 0, 14, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 1", { DIV_SYSTEM_SMS, 64, 0, 0x42, // SN76489A 4MHz DIV_SYSTEM_SMS, 64, 0, 0x0141, // SN76489A 2MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System E", { DIV_SYSTEM_SMS, 64, 0, 0, DIV_SYSTEM_SMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System E (with FM expansion)", { DIV_SYSTEM_SMS, 64, 0, 0, DIV_SYSTEM_SMS, 64, 0, 0, DIV_SYSTEM_OPLL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System E (with FM expansion in drums mode)", { DIV_SYSTEM_SMS, 64, 0, 0, DIV_SYSTEM_SMS, 64, 0, 0, DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Hang-On", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_SEGAPCM, 64, 0, 0, // discrete logics, 62.5KHz output rate 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Hang-On (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_SEGAPCM, 64, 0, 0, // discrete logics, 62.5KHz output rate 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega OutRun/X Board", { DIV_SYSTEM_YM2151, 64, 0, 2, // 4MHz DIV_SYSTEM_SEGAPCM, 64, 0, 0, // ASIC, 31.25KHz output rate 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 24", { DIV_SYSTEM_YM2151, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 61499|(7<<16), // software controlled, variable rate via configurable timers 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 18", { DIV_SYSTEM_YM2612, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 18 (extended channel 3 on first OPN2C)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 18 (extended channel 3 on second OPN2C)", { DIV_SYSTEM_YM2612, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 18 (extended channel 3 on both OPN2Cs)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 32", { DIV_SYSTEM_YM2612, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 32 (extended channel 3 on first OPN2C)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 32 (extended channel 3 on second OPN2C)", { DIV_SYSTEM_YM2612, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega System 32 (extended channel 3 on both OPN2Cs)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom Exed Eyes", { DIV_SYSTEM_AY8910, 64, 0, 4, // 1.5MHz DIV_SYSTEM_SMS, 64, 0, 0x0104, // SN76489 3MHz DIV_SYSTEM_SMS, 64, 0, 0x0104, // SN76489 3MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom Arcade", { // 1943, Side arms, etc DIV_SYSTEM_OPN, 64, 0, 5, // 4 or 1.5MHz; various per games DIV_SYSTEM_OPN, 64, 0, 5, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom Arcade (extended channel 3 on first OPN)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, DIV_SYSTEM_OPN, 64, 0, 5, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom Arcade (extended channel 3 on second OPN)", { DIV_SYSTEM_OPN, 64, 0, 5, DIV_SYSTEM_OPN_EXT, 64, 0, 5, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom Arcade (extended channel 3 on both OPNs)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, DIV_SYSTEM_OPN_EXT, 64, 0, 5, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom CPS-1", { DIV_SYSTEM_YM2151, 64, 0, 0, // 3.58MHz DIV_SYSTEM_MSM6295, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Capcom CPS-2 (QSound)", { DIV_SYSTEM_QSOUND, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Jaleco Ginga NinkyouDen", { DIV_SYSTEM_AY8910, 64, 0, 16, // 1.79MHz DIV_SYSTEM_Y8950, 64, 0, 0, // 3.58MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Jaleco Ginga NinkyouDen (drums mode)", { DIV_SYSTEM_AY8910, 64, 0, 16, // 1.79MHz DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0, // 3.58MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Jaleco Mega System 1", { DIV_SYSTEM_YM2151, 64, 0, 1, // 3.5MHz (7MHz / 2) DIV_SYSTEM_MSM6295, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 2, // 4MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NMK 16-bit Arcade", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz; optional DIV_SYSTEM_MSM6295, 64, 0, 130, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 130, // ^^ 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NMK 16-bit Arcade (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz; optional DIV_SYSTEM_MSM6295, 64, 0, 130, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 130, // ^^ 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko DJ Boy", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, -127, 12, // 1.5MHz, Left output DIV_SYSTEM_MSM6295, 64, 127, 12, // 1.5MHz, Right output 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko DJ Boy (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, -127, 12, // 1.5MHz, Left output DIV_SYSTEM_MSM6295, 64, 127, 12, // 1.5MHz, Right output 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko Air Buster", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 141, // 3MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko Air Buster (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 141, // 3MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko Toybox System", { DIV_SYSTEM_AY8910, 64, 0, 19, // YM2149 2MHz DIV_SYSTEM_AY8910, 64, 0, 19, // ^^ DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Kaneko Jackie Chan", { DIV_SYSTEM_YMZ280B, 64, 0, 3, // 16MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Super Kaneko Nova System", { DIV_SYSTEM_YMZ280B, 64, 0, 4, // 16.67MHz (33.33MHz / 2) 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo Ninja Gaiden", { // Ninja Gaiden, Raiga, etc DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo Ninja Gaiden (extended channel 3 on first OPN)", { // Ninja Gaiden, Raiga, etc DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo Ninja Gaiden (extended channel 3 on second OPN)", { // Ninja Gaiden, Raiga, etc DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo Ninja Gaiden (extended channel 3 on both OPNs)", { // Ninja Gaiden, Raiga, etc DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo System", { DIV_SYSTEM_OPL3, 64, 0, 0, DIV_SYSTEM_YMZ280B, 64, 0, 0, DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Tecmo System (drums mode)", { DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, DIV_SYSTEM_YMZ280B, 64, 0, 0, DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seibu Kaihatsu Raiden", { // Raiden, Seibu cup soccer, Zero team, etc DIV_SYSTEM_OPL2, 64, 0, 0, // YM3812 3.58MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.023MHz (28.636363MHz / 28); various per games 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seibu Kaihatsu Raiden (drums mode)", { // Raiden, Seibu cup soccer, Zero team, etc DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, // YM3812 3.58MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.023MHz (28.636363MHz / 28); various per games 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sunsoft Shanghai 3", { DIV_SYSTEM_AY8910, 64, 0, 20, // YM2149 1.5MHz DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sunsoft Arcade", { DIV_SYSTEM_YM2612, 64, 0, 2, // discrete YM3438 8MHz DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sunsoft Arcade (extended channel 3)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete YM3438 8MHz DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari Klax", { DIV_SYSTEM_MSM6295, 64, 0, 7, // 0.895MHz (3.579545MHz / 4) 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari Rampart", { DIV_SYSTEM_OPLL, 64, 0, 0, // 3.579545MHz DIV_SYSTEM_MSM6295, 64, 0, 14, // 1.193MHz (3.579545MHz / 3) 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari Rampart (drums mode)", { DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.579545MHz DIV_SYSTEM_MSM6295, 64, 0, 14, // 1.193MHz (3.579545MHz / 3) 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Atari JSA IIIs", { DIV_SYSTEM_YM2151, 64, 0, 0, // 3.579545MHz DIV_SYSTEM_MSM6295, 64, -127, 14, // 1.193MHz (3.579545MHz / 3), Left output DIV_SYSTEM_MSM6295, 64, 127, 14, // 1.193MHz (3.579545MHz / 3), Right output 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Karnov", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL, 64, 0, 3, // 3MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Karnov (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL, 64, 0, 3, // 3MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Karnov (drums mode)", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL_DRUMS, 64, 0, 3, // 3MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Karnov (extended channel 3; drums mode)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL_DRUMS, 64, 0, 3, // 3MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Arcade", { // Bad dudes, Robocop, etc DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Arcade (extended channel 3)", { // Bad dudes, Robocop, etc DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Arcade (drums mode)", { // Bad dudes, Robocop, etc DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Arcade (extended channel 3; drums mode)", { // Bad dudes, Robocop, etc DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East PCX", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_PCE, 64, 0, 0, // software controlled MSM5205 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East PCX (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_PCE, 64, 0, 0, // software controlled MSM5205 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Dark Seal", { // Dark Seal, Crude Buster, Vapor Trail, etc DIV_SYSTEM_YM2151, 64, 0, 0, // 3.580MHz (32.22MHz / 9) DIV_SYSTEM_OPN, 64, 0, 2, // 4.0275MHz (32.22MHz / 8); optional @@ -1901,8 +1904,8 @@ void FurnaceGUI::initSystemPresets() { // HuC6280 is for control them, internal sound isn't used 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Dark Seal (extended channel 3)", { // Dark Seal, Crude Buster, Vapor Trail, etc DIV_SYSTEM_YM2151, 64, 0, 0, // 3.580MHz (32.22MHz / 9) DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4.0275MHz (32.22MHz / 8); optional @@ -1911,218 +1914,218 @@ void FurnaceGUI::initSystemPresets() { // HuC6280 is for control them, internal sound isn't used 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East Deco 156", { DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.007MHz (32.22MHz / 32); various per games DIV_SYSTEM_MSM6295, 64, 0, 8, // 1 or 2 or 2.014MHz (32.22MHz / 16); various per games 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Data East MLC", { DIV_SYSTEM_YMZ280B, 64, 0, 5, // 14MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Ikari Warriors", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Ikari Warriors (drums mode on first OPL)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Ikari Warriors (drums mode on second OPL)", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Ikari Warriors (drums mode on both OPLs)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Triple Z80", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Triple Z80 (drums mode on Y8950)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Triple Z80 (drums mode on OPL)", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Triple Z80 (drums mode on Y8950 and OPL)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Chopper I", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL2, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Chopper I (drums mode on Y8950)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL2, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Chopper I (drums mode on OPL2)", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Chopper I (drums mode on Y8950 and OPL2)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Touchdown Fever", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_Y8950, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Touchdown Fever (drums mode on OPL)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_Y8950, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Touchdown Fever (drums mode on Y8950)", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "SNK Touchdown Fever (drums mode on OPL and Y8950)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Alpha denshi Alpha-68K", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Alpha denshi Alpha-68K (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Alpha denshi Alpha-68K (drums mode)", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Alpha denshi Alpha-68K (extended channel 3; drums mode)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo MVS", { DIV_SYSTEM_YM2610_FULL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo MVS (extended channel 2)", { DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Nichibutsu Mag Max", { DIV_SYSTEM_AY8910, 64, 0, 13, DIV_SYSTEM_AY8910, 64, 0, 13, DIV_SYSTEM_AY8910, 64, 0, 13, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco (3-channel WSG)", { // Pac-Man, Galaga, Xevious, etc DIV_SYSTEM_NAMCO, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco Mappy", { // Mappy, Super Pac-Man, Libble Rabble, etc DIV_SYSTEM_NAMCO_15XX, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco Pac-Land", { // Pac-Land, Baraduke, Sky kid, etc DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco System 86", { // without expansion board case; Hopping Mappy, etc DIV_SYSTEM_YM2151, 64, 0, 0, DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco Thunder Ceptor", { DIV_SYSTEM_YM2151, 64, 0, 0, DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, DIV_SYSTEM_PCM_DAC, 64, 0, 7999|(7<<16), // M65C02 software driven, correct sample rate? 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Namco System 1", { DIV_SYSTEM_YM2151, 64, 0, 0, DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, @@ -2130,66 +2133,66 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PCM_DAC, 64, 0, 5999|(7<<16), // "" 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Taito Arcade", { DIV_SYSTEM_YM2610B, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Taito Arcade (extended channel 3)", { DIV_SYSTEM_YM2610B_EXT, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta 1", { DIV_SYSTEM_X1_010, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta 1 + FM addon", { DIV_SYSTEM_X1_010, 64, 0, 0, DIV_SYSTEM_YM2612, 64, 0, 2, // Discrete YM3438 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta 1 + FM addon (extended channel 3)", { DIV_SYSTEM_X1_010, 64, 0, 0, DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // Discrete YM3438 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Seta 2", { DIV_SYSTEM_X1_010, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Cave 68000", { DIV_SYSTEM_YMZ280B, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Coreland Cyber Tank", { DIV_SYSTEM_Y8950, 64, -127, 0, // 3.58MHz, Left output DIV_SYSTEM_Y8950, 64, 127, 0, // 3.58MHz, Right output 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Coreland Cyber Tank (drums mode)", { DIV_SYSTEM_Y8950, 64, -127, 0, // 3.58MHz, Left output DIV_SYSTEM_Y8950, 64, 127, 0, // 3.58MHz, Right output 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "ICE Skimaxx", { DIV_SYSTEM_MSM6295, 64, -127, 130, // 4MHz, Left output DIV_SYSTEM_MSM6295, 64, 127, 130, // 4MHz, Right output @@ -2197,150 +2200,150 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_MSM6295, 64, 127, 8, // 2MHz, Right output 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Toaplan 1", { DIV_SYSTEM_OPL2, 64, 0, 5, // 3.5MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Toaplan 1 (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 5, // 3.5MHz 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Dynax/Nakanihon 3rd generation hardware", { DIV_SYSTEM_AY8910, 64, 0, 0, // AY or YM, optional - 1.79MHz or 3.58MHz; various per game DIV_SYSTEM_OPLL, 64, 0, 0, DIV_SYSTEM_MSM6295, 64, 0, 6, // 1.023MHz mostly 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Dynax/Nakanihon 3rd generation hardware (drums mode)", { DIV_SYSTEM_AY8910, 64, 0, 0, // AY or YM, optional - 1.79MHz or 3.58MHz; various per game DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, DIV_SYSTEM_MSM6295, 64, 0, 6, // 1.023MHz mostly 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Dynax/Nakanihon Real Break", { DIV_SYSTEM_OPLL, 64, 0, 0, DIV_SYSTEM_YMZ280B, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Dynax/Nakanihon Real Break (drums mode)", { DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, DIV_SYSTEM_YMZ280B, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Irem M72", { DIV_SYSTEM_YM2151, 64, 0, 0, DIV_SYSTEM_PCM_DAC, 64, 0, 7811|(7<<16), 0 } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; - cat=FurnaceGUISysCategory("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."); - cat.systems.push_back(FurnaceGUISysDef( + CATEGORY_BEGIN("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."); + ENTRY( "Sega Genesis", { DIV_SYSTEM_YM2612, 64, 0, 0, DIV_SYSTEM_SMS, 32, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Genesis (extended channel 3)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 0, DIV_SYSTEM_SMS, 32, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Master System", { DIV_SYSTEM_SMS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Sega Master System (with FM expansion)", { DIV_SYSTEM_SMS, 64, 0, 0, DIV_SYSTEM_OPLL, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Game Boy", { DIV_SYSTEM_GB, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NEC PC Engine/TurboGrafx-16", { DIV_SYSTEM_PCE, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "NES", { DIV_SYSTEM_NES, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom with Konami VRC7", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_VRC7, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Famicom Disk System", { DIV_SYSTEM_NES, 64, 0, 0, DIV_SYSTEM_FDS, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (6581 SID)", { DIV_SYSTEM_C64_6581, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Commodore 64 (8580 SID)", { DIV_SYSTEM_C64_8580, 64, 0, 1, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Arcade (YM2151 and SegaPCM)", { DIV_SYSTEM_YM2151, 64, 0, 0, DIV_SYSTEM_SEGAPCM_COMPAT, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo CD", { DIV_SYSTEM_YM2610, 64, 0, 0, 0 } - )); - cat.systems.push_back(FurnaceGUISysDef( + ); + ENTRY( "Neo Geo CD (extended channel 2)", { DIV_SYSTEM_YM2610_EXT, 64, 0, 0, 0 } - )); - sysCategories.push_back(cat); + ); + CATEGORY_END; } FurnaceGUISysDef::FurnaceGUISysDef(const char* n, std::initializer_list def): From bda0ca5d95d7795abee196535beffbabde301299 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 14 Nov 2022 19:07:17 -0500 Subject: [PATCH 48/48] convert presets to new format, part 5 --- src/gui/presets.cpp | 924 +++++++++++++++----------------------------- 1 file changed, 305 insertions(+), 619 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index a596ceebc..8b0e5fcc2 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -57,192 +57,161 @@ void FurnaceGUI::initSystemPresets() { ); ENTRY( "Sega Genesis (DualPCM)", { - DIV_SYSTEM_YM2612_FRAC, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_FRAC, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, "") } ); ENTRY( "Sega Genesis (DualPCM, extended channel 3)", { - DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, "") } ); ENTRY( "Sega Genesis (with Sega CD)", { - DIV_SYSTEM_YM2612, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - DIV_SYSTEM_RF5C68, 64, 0, 18, - 0 + CH(DIV_SYSTEM_YM2612, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, ""), + CH(DIV_SYSTEM_RF5C68, 64, 0, + "clockSel=2\n" + "chipType=1\n" + ) } ); ENTRY( "Sega Genesis (extended channel 3 with Sega CD)", { - DIV_SYSTEM_YM2612_EXT, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - DIV_SYSTEM_RF5C68, 64, 0, 18, - 0 + CH(DIV_SYSTEM_YM2612_EXT, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, ""), + CH(DIV_SYSTEM_RF5C68, 64, 0, + "clockSel=2\n" + "chipType=1\n" + ) } ); ENTRY( "Sega Master System", { - DIV_SYSTEM_SMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, "") } ); ENTRY( "Sega Master System (with FM expansion)", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_OPLL, 64, 0, "") } ); ENTRY( "Sega Master System (with FM expansion in drums mode)", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, "") } ); ENTRY( "Sega Game Gear", { - DIV_SYSTEM_SMS, 64, 0, 0xc, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, "chipType=3") } ); ENTRY( "Game Boy", { - DIV_SYSTEM_GB, 64, 0, 0, - 0 + CH(DIV_SYSTEM_GB, 64, 0, "") } ); ENTRY( "NEC PC Engine/TurboGrafx-16", { - DIV_SYSTEM_PCE, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCE, 64, 0, "") } ); ENTRY( "NES", { - DIV_SYSTEM_NES, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, "") } ); ENTRY( "Famicom with Konami VRC6", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_VRC6, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_VRC6, 64, 0, "") } ); ENTRY( "Famicom with Konami VRC7", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_VRC7, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_VRC7, 64, 0, "") } ); ENTRY( "Famicom with MMC5", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_MMC5, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_MMC5, 64, 0, "") } ); ENTRY( "Famicom with Sunsoft 5B", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 32, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=2") } ); ENTRY( "Famicom with Namco 163", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_N163, 64, 0, 112, - 0 - } - ); - ENTRY( - "Comboy with Family Noraebang", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 - } - ); - ENTRY( - "Comboy with Family Noraebang (drums mode)", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_N163, 64, 0, "channels=7") } ); ENTRY( "Famicom Disk System", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_FDS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_FDS, 64, 0, "") } ); ENTRY( "SNES", { - DIV_SYSTEM_SNES, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SNES, 64, 0, "") } ); ENTRY( "Mattel Intellivision", { - DIV_SYSTEM_AY8910, 64, 0, 48, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=3") } ); ENTRY( "Vectrex", { - DIV_SYSTEM_AY8910, 64, 0, 4, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "clockSel=4") } ); ENTRY( "Neo Geo AES", { - DIV_SYSTEM_YM2610_FULL, 64, 0, 1, - 0 + CH(DIV_SYSTEM_YM2610_FULL, 64, 0, "clockSel=1") } ); ENTRY( "Neo Geo AES (extended channel 2)", { - DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 1, - 0 + CH(DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, "clockSel=1") } ); ENTRY( "Atari 2600/7800", { - DIV_SYSTEM_TIA, 64, 0, 0, - 0 + CH(DIV_SYSTEM_TIA, 64, 0, "") } ); ENTRY( "Atari Lynx", { - DIV_SYSTEM_LYNX, 64, 0, 0, - 0 + CH(DIV_SYSTEM_LYNX, 64, 0, "") } ); ENTRY( "WonderSwan", { - DIV_SYSTEM_SWAN, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SWAN, 64, 0, "") } ); ENTRY( "Virtual Boy", { - DIV_SYSTEM_VBOY, 64, 0, 0, - 0 + CH(DIV_SYSTEM_VBOY, 64, 0, "") } ); ENTRY( "Gamate", { - DIV_SYSTEM_AY8910, 64, 0, 73, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, + "clockSel=9\n" + "chipType=0\n" + "stereo=true\n" + ) } ); CATEGORY_END; @@ -250,274 +219,246 @@ void FurnaceGUI::initSystemPresets() { CATEGORY_BEGIN("Computers","let's get to work on chiptune today."); ENTRY( "Commodore PET", { - DIV_SYSTEM_PET, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PET, 64, 0, "") } ); ENTRY( "Commodore VIC-20", { - DIV_SYSTEM_VIC20, 64, 0, 1, - 0 + CH(DIV_SYSTEM_VIC20, 64, 0, "clockSel=1") } ); ENTRY( "Commodore 64 (6581 SID)", { - DIV_SYSTEM_C64_6581, 64, 0, 1, - 0 + CH(DIV_SYSTEM_C64_6581, 64, 0, "clockSel=1") } ); ENTRY( "Commodore 64 (8580 SID)", { - DIV_SYSTEM_C64_8580, 64, 0, 1, - 0 + CH(DIV_SYSTEM_C64_8580, 64, 0, "clockSel=1") } ); ENTRY( "Commodore 64 (6581 SID + Sound Expander)", { - DIV_SYSTEM_C64_6581, 64, 0, 1, - DIV_SYSTEM_OPL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_6581, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL, 64, 0, "") } ); ENTRY( "Commodore 64 (6581 SID + Sound Expander in drums mode)", { - DIV_SYSTEM_C64_6581, 64, 0, 1, - DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_6581, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL_DRUMS, 64, 0, "") } ); ENTRY( "Commodore 64 (8580 SID + Sound Expander)", { - DIV_SYSTEM_C64_8580, 64, 0, 1, - DIV_SYSTEM_OPL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_8580, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL, 64, 0, "") } ); ENTRY( "Commodore 64 (8580 SID + Sound Expander in drums mode)", { - DIV_SYSTEM_C64_8580, 64, 0, 1, - DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_8580, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL_DRUMS, 64, 0, "") } ); - ENTRY( + ENTRY( "Commodore 64 (6581 SID + FM-YAM)", { - DIV_SYSTEM_C64_6581, 64, 0, 1, - DIV_SYSTEM_OPL2, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_6581, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL2, 64, 0, "") } ); - ENTRY( + ENTRY( "Commodore 64 (6581 SID + FM-YAM in drums mode)", { - DIV_SYSTEM_C64_6581, 64, 0, 1, - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_6581, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, "") } ); - ENTRY( + ENTRY( "Commodore 64 (8580 SID + FM-YAM)", { - DIV_SYSTEM_C64_8580, 64, 0, 1, - DIV_SYSTEM_OPL2, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_8580, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL2, 64, 0, "") } ); - ENTRY( + ENTRY( "Commodore 64 (8580 SID + FM-YAM in drums mode)", { - DIV_SYSTEM_C64_8580, 64, 0, 1, - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_C64_8580, 64, 0, "clockSel=1"), + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, "") } ); ENTRY( "Amiga", { - DIV_SYSTEM_AMIGA, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AMIGA, 64, 0, "") } ); ENTRY( "MSX", { - DIV_SYSTEM_AY8910, 64, 0, 16, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1") } ); ENTRY( "MSX + SFG-01", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_YM2151, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_YM2151, 64, 0, "") } ); ENTRY( "MSX + MSX-AUDIO", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_Y8950, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_Y8950, 64, 0, "") } ); ENTRY( "MSX + MSX-AUDIO (drums mode)", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_Y8950_DRUMS, 64, 0, "") } ); ENTRY( "MSX + MSX-MUSIC", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_OPLL, 64, 0, "") } ); ENTRY( "MSX + MSX-MUSIC (drums mode)", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, "") } ); ENTRY( "MSX + Darky", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_AY8930, 64, 0, 139, // 3.58MHz - DIV_SYSTEM_AY8930, 64, 0, 139, // 3.58MHz or 3.6MHz selectable via register + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_AY8930, 64, 0, + "clockSel=11\n" + "halfClock=true\n" + ), // 3.58MHz + CH(DIV_SYSTEM_AY8930, 64, 0, + "clockSel=11\n" + "halfClock=true\n" + ) // 3.58MHz or 3.6MHz selectable via register // per-channel mixer (soft panning, post processing) isn't emulated at all - 0 } ); ENTRY( "MSX + Playsoniq", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_SMS, 64, 0, 0, // Sega VDP - DIV_SYSTEM_C64_8580, 64, 0, 0, - DIV_SYSTEM_SCC_PLUS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_SMS, 64, 0, ""), // Sega VDP + CH(DIV_SYSTEM_C64_8580, 64, 0, ""), + CH(DIV_SYSTEM_SCC_PLUS, 64, 0, "") } ); ENTRY( "MSX + SCC", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_SCC, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_SCC, 64, 0, "") } ); ENTRY( "MSX + SCC+", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_SCC_PLUS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_SCC_PLUS, 64, 0, "") } ); ENTRY( "MSX + Neotron", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_YM2610_FULL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_YM2610_FULL, 64, 0, "") } ); ENTRY( "MSX + Neotron (extended channel 2)", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, "") } ); ENTRY( "MSX + Neotron (with YM2610B)", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_YM2610B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_YM2610B, 64, 0, "") } ); ENTRY( "MSX + Neotron (with YM2610B; extended channel 3)", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_YM2610B_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_YM2610B_EXT, 64, 0, "") } ); ENTRY( "MSX + SIMPL", { - DIV_SYSTEM_AY8910, 64, 0, 16, - DIV_SYSTEM_PCM_DAC, 64, 0, 55929|(7<<16), // variable rate, Mono DAC - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, "chipType=1"), + CH(DIV_SYSTEM_PCM_DAC, 64, 0, + "rate=55930\n" + "outDepth=8\n" + ) // variable rate, Mono DAC } ); ENTRY( "NEC PC-98 (with PC-9801-26/K)", { - DIV_SYSTEM_OPN, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPN, 64, 0, "clockSel=4"), // 3.9936MHz but some compatible card has 4MHz + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1") } ); ENTRY( "NEC PC-98 (with PC-9801-26/K; extended channel 3)", { - DIV_SYSTEM_OPN_EXT, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPN_EXT, 64, 0, "clockSel=4"), // 3.9936MHz but some compatible card has 4MHz + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1") } ); + /* TODO: everything here ENTRY( "NEC PC-98 (with Sound Orchestra)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_OPL2, 64, 0, 4, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with Sound Orchestra; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_OPL2, 64, 0, 4, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with Sound Orchestra in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 4, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with Sound Orchestra in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 4, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with Sound Orchestra V)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_Y8950, 64, 0, 4, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with Sound Orchestra V; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_Y8950, 64, 0, 4, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with Sound Orchestra V in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 4, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 4, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with Sound Orchestra V in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 4, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 4, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( @@ -525,8 +466,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PC98, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), // 2x 16-bit Burr Brown DAC DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( @@ -534,40 +474,35 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_PC98_EXT, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with PC-9801-73)", { DIV_SYSTEM_PC98, 64, 0, 1, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with PC-9801-73; extended channel 3)", { DIV_SYSTEM_PC98_EXT, 64, 0, 1, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible)", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), - DIV_SYSTEM_OPL3, 64, 0, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL3, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), - DIV_SYSTEM_OPL3, 64, 0, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL3, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( @@ -575,8 +510,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( @@ -584,20 +518,17 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, "clockSel=1"), } ); ENTRY( "ZX Spectrum (48K)", { - DIV_SYSTEM_SFX_BEEPER, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SFX_BEEPER, 64, 0, ""), } ); ENTRY( "ZX Spectrum (128K)", { DIV_SYSTEM_AY8910, 64, 0, 1, //beeper was also included - 0 } ); ENTRY( @@ -605,7 +536,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, - 0 } ); ENTRY( @@ -613,7 +543,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, - 0 } ); ENTRY( @@ -621,7 +550,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, - 0 } ); ENTRY( @@ -629,7 +557,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, DIV_SYSTEM_OPN_EXT, 64, 0, 1, - 0 } ); ENTRY( @@ -637,19 +564,16 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 1, DIV_SYSTEM_AY8910, 64, 0, 1, // or YM2149 DIV_SYSTEM_AY8910, 64, 0, 1, // or YM2149 - 0 } ); ENTRY( "Amstrad CPC", { DIV_SYSTEM_AY8910, 64, 0, 5, - 0 } ); ENTRY( "Atari ST", { DIV_SYSTEM_AY8910, 64, 0, 19, - 0 } ); ENTRY( @@ -657,111 +581,96 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 19, DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), - 0 } ); ENTRY( "SAM CoupĂ©", { - DIV_SYSTEM_SAA1099, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SAA1099, 64, 0, ""), } ); ENTRY( "BBC Micro", { DIV_SYSTEM_SMS, 64, 0, 0x42, // SN76489A 4MHz - 0 } ); ENTRY( "PC (barebones)", { - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "IBM PCjr", { // it can be enable sound output at once DIV_SYSTEM_SMS, 64, 0, 0x44, // SN76496 - 0 } ); ENTRY( "Tandy 1000", { DIV_SYSTEM_SMS, 64, 0, 0x44, // NCR 8496 or SN76496 or Tandy PSSJ(with 8 bit DAC) - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "PC + Covox Sound Master", { DIV_SYSTEM_AY8930, 64, 0, 3, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "PC + SSI 2001", { DIV_SYSTEM_C64_6581, 64, 0, 2, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "PC + Game Blaster", { DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "PC + AdLib", { - DIV_SYSTEM_OPL2, 64, 0, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL2, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "PC + AdLib (drums mode)", { - DIV_SYSTEM_OPL2, 64, 0, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL2, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "PC + Sound Blaster", { - DIV_SYSTEM_OPL2, 64, 0, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, + CH(DIV_SYSTEM_OPL2, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), - 0 } ); ENTRY( "PC + AdLib/Sound Blaster (drums mode)", { - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, - DIV_SYSTEM_PCSPKR, 64, 0, 0, + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), - 0 } ); ENTRY( "PC + Sound Blaster w/Game Blaster Compatible", { - DIV_SYSTEM_OPL2, 64, 0, 0, + CH(DIV_SYSTEM_OPL2, 64, 0, ""), DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "PC + Sound Blaster w/Game Blaster Compatible (drums mode)", { - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, ""), DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( @@ -769,8 +678,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPL2, 64, -127, 0, DIV_SYSTEM_OPL2, 64, 127, 0, DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16)|(1<<20), //alternatively 44.1 khz mono - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( @@ -778,31 +686,27 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPL2_DRUMS, 64, -127, 0, DIV_SYSTEM_OPL2_DRUMS, 64, 127, 0, DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16)|(1<<20), //alternatively 44.1 khz mono - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "PC + Sound Blaster Pro 2", { - DIV_SYSTEM_OPL3, 64, 0, 0, + CH(DIV_SYSTEM_OPL3, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "PC + Sound Blaster Pro 2 (drums mode)", { - DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, + CH(DIV_SYSTEM_OPL3_DRUMS, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "PC + PC-FXGA", { DIV_SYSTEM_PCE, 64, 0, 0, // HuC6230 (WSG from HuC6280 but with built in 2 OKI ADPCM playback engines) - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( @@ -810,225 +714,192 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2151, 64, 0, 0, // 3.58MHz or 4MHz selectable via jumper DIV_SYSTEM_SAA1099, 64, 0, 1, // 7.16MHz or 8MHz selectable via jumper DIV_SYSTEM_SAA1099, 64, 0, 1, // "" - DIV_SYSTEM_PCSPKR, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 64, 0, ""), } ); ENTRY( "Sharp X1", { DIV_SYSTEM_AY8910, 64, 0, 3, - 0 } ); ENTRY( "Sharp X1 + FM Addon", { DIV_SYSTEM_AY8910, 64, 0, 3, DIV_SYSTEM_YM2151, 64, 0, 2, - 0 } ); ENTRY( "Sharp X68000", { DIV_SYSTEM_YM2151, 64, 0, 2, - DIV_SYSTEM_MSM6258, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM6258, 64, 0, ""), } ); ENTRY( "FM Towns", { DIV_SYSTEM_YM2612, 64, 0, 2, // YM3438 - DIV_SYSTEM_RF5C68, 64, 0, 0, - 0 + CH(DIV_SYSTEM_RF5C68, 64, 0, ""), } ); ENTRY( "Commander X16", { - DIV_SYSTEM_VERA, 64, 0, 0, - DIV_SYSTEM_YM2151, 32, 0, 0, - 0 + CH(DIV_SYSTEM_VERA, 64, 0, ""), + CH(DIV_SYSTEM_YM2151, 32, 0, ""), } ); ENTRY( "TI-99/4A", { DIV_SYSTEM_SMS, 64, 0, 0x182, // SN94624 447KHz - 0 } ); + */ CATEGORY_END; + /* TODO: everything here CATEGORY_BEGIN("FM","chips which use frequency modulation (FM) to generate sound.\nsome of these also pack more (like square and sample channels)."); ENTRY( "Yamaha YM2151 (OPM)", { - DIV_SYSTEM_YM2151, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2151, 64, 0, ""), } ); ENTRY( "Yamaha YM2203 (OPN)", { DIV_SYSTEM_OPN, 64, 0, 3, - 0 } ); ENTRY( "Yamaha YM2203 (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, - 0 } ); ENTRY( "Yamaha YM2608 (OPNA)", { - DIV_SYSTEM_PC98, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PC98, 64, 0, ""), } ); ENTRY( "Yamaha YM2608 (extended channel 3)", { - DIV_SYSTEM_PC98_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PC98_EXT, 64, 0, ""), } ); ENTRY( "Yamaha YM2610 (OPNB)", { - DIV_SYSTEM_YM2610_FULL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610_FULL, 64, 0, ""), } ); ENTRY( "Yamaha YM2610 (extended channel 2)", { - DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, ""), } ); ENTRY( "Yamaha YM2610B (OPNB2)", { - DIV_SYSTEM_YM2610B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610B, 64, 0, ""), } ); ENTRY( "Yamaha YM2610B (extended channel 3)", { - DIV_SYSTEM_YM2610B_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610B_EXT, 64, 0, ""), } ); ENTRY( "Yamaha YM2612 (OPN2)", { DIV_SYSTEM_YM2612, 64, 0, (int)0x80000000, - 0 } ); ENTRY( "Yamaha YM2612 (extended channel 3)", { DIV_SYSTEM_YM2612_EXT, 64, 0, (int)0x80000000, - 0 } ); ENTRY( "Yamaha YM2612 (OPN2) with DualPCM", { DIV_SYSTEM_YM2612_FRAC, 64, 0, (int)0x80000000, - 0 } ); ENTRY( "Yamaha YM2612 (extended channel 3) with DualPCM", { DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, (int)0x80000000, - 0 } ); ENTRY( "Yamaha YM2413 (OPLL)", { - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPLL, 64, 0, ""), } ); ENTRY( "Yamaha YM2413 (drums mode)", { - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, ""), } ); ENTRY( "Yamaha YM2414 (OPZ)", { - DIV_SYSTEM_OPZ, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPZ, 64, 0, ""), } ); ENTRY( "Yamaha YM3438 (OPN2C)", { - DIV_SYSTEM_YM2612, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612, 64, 0, ""), } ); ENTRY( "Yamaha YM3438 (extended channel 3)", { - DIV_SYSTEM_YM2612_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_EXT, 64, 0, ""), } ); ENTRY( "Yamaha YM3438 (OPN2C) with DualPCM", { - DIV_SYSTEM_YM2612_FRAC, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_FRAC, 64, 0, ""), } ); ENTRY( "Yamaha YM3438 (extended channel 3) with DualPCM", { - DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, ""), } ); ENTRY( "Yamaha YM3526 (OPL)", { - DIV_SYSTEM_OPL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL, 64, 0, ""), } ); ENTRY( "Yamaha YM3526 (drums mode)", { - DIV_SYSTEM_OPL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL_DRUMS, 64, 0, ""), } ); ENTRY( "Yamaha Y8950", { - DIV_SYSTEM_Y8950, 64, 0, 0, - 0 + CH(DIV_SYSTEM_Y8950, 64, 0, ""), } ); ENTRY( "Yamaha Y8950 (drums mode)", { - DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_Y8950_DRUMS, 64, 0, ""), } ); ENTRY( "Yamaha YM3812 (OPL2)", { - DIV_SYSTEM_OPL2, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL2, 64, 0, ""), } ); ENTRY( "Yamaha YM3812 (drums mode)", { - DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL2_DRUMS, 64, 0, ""), } ); ENTRY( "Yamaha YMF262 (OPL3)", { - DIV_SYSTEM_OPL3, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL3, 64, 0, ""), } ); ENTRY( "Yamaha YMF262 (drums mode)", { - DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPL3_DRUMS, 64, 0, ""), } ); if (settings.hiddenSystems) { ENTRY( "Yamaha YMU759 (MA-2)", { - DIV_SYSTEM_YMU759, 64, 0, 0, + CH(DIV_SYSTEM_YMU759, 64, 0, ""), 0 } ); @@ -1039,110 +910,92 @@ void FurnaceGUI::initSystemPresets() { ENTRY( "TI SN76489", { DIV_SYSTEM_SMS, 64, 0, 4, - 0 } ); ENTRY( "TI SN76489A", { DIV_SYSTEM_SMS, 64, 0, 0x40, - 0 } ); ENTRY( "TI SN76496", { DIV_SYSTEM_SMS, 64, 0, 0x44, - 0 } ); ENTRY( "NCR 8496", { DIV_SYSTEM_SMS, 64, 0, 0x48, - 0 } ); ENTRY( "Tandy PSSJ 3-voice sound", { DIV_SYSTEM_SMS, 64, 0, 0x4c, // 8 bit DAC - 0 } ); ENTRY( "Sega PSG (SN76489-like)", { - DIV_SYSTEM_SMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), } ); ENTRY( "Sega PSG (SN76489-like, Stereo)", { DIV_SYSTEM_SMS, 64, 0, 0xc, - 0 } ); ENTRY( "TI SN94624", { DIV_SYSTEM_SMS, 64, 0, 0x182, - 0 } ); ENTRY( "TI SN76494", { DIV_SYSTEM_SMS, 64, 0, 0x186, - 0 } ); ENTRY( "Toshiba T6W28", { - DIV_SYSTEM_T6W28, 64, 0, 0, - 0 + CH(DIV_SYSTEM_T6W28, 64, 0, ""), } ); ENTRY( "AY-3-8910", { - DIV_SYSTEM_AY8910, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8910, 64, 0, ""), } ); ENTRY( "AY-3-8914", { DIV_SYSTEM_AY8910, 64, 0, 48, - 0 } ); ENTRY( "Yamaha YM2149(F)", { DIV_SYSTEM_AY8910, 64, 0, 16, - 0 } ); ENTRY( "Philips SAA1099", { - DIV_SYSTEM_SAA1099, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SAA1099, 64, 0, ""), } ); ENTRY( "PC Speaker", { - DIV_SYSTEM_PCSPKR, 32, 0, 0, - 0 + CH(DIV_SYSTEM_PCSPKR, 32, 0, ""), } ); ENTRY( "Commodore VIC", { DIV_SYSTEM_VIC20, 64, 0, 1, - 0 } ); ENTRY( "OKI MSM5232", { - DIV_SYSTEM_MSM5232, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM5232, 64, 0, ""), } ); ENTRY( "Pong", { - DIV_SYSTEM_PONG, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PONG, 64, 0, ""), } ); CATEGORY_END; @@ -1150,62 +1003,52 @@ void FurnaceGUI::initSystemPresets() { CATEGORY_BEGIN("Sample","chips/systems which use PCM or ADPCM samples for sound synthesis."); ENTRY( "Amiga", { - DIV_SYSTEM_AMIGA, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AMIGA, 64, 0, ""), } ); ENTRY( "SegaPCM", { - DIV_SYSTEM_SEGAPCM, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SEGAPCM, 64, 0, ""), } ); ENTRY( "Capcom QSound", { - DIV_SYSTEM_QSOUND, 64, 0, 0, - 0 + CH(DIV_SYSTEM_QSOUND, 64, 0, ""), } ); ENTRY( "Seta/Allumer X1-010", { - DIV_SYSTEM_X1_010, 64, 0, 0, - 0 + CH(DIV_SYSTEM_X1_010, 64, 0, ""), } ); ENTRY( "Yamaha YMZ280B (PCMD8)", { - DIV_SYSTEM_YMZ280B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), } ); ENTRY( "Ricoh RF5C68", { - DIV_SYSTEM_RF5C68, 64, 0, 0, - 0 + CH(DIV_SYSTEM_RF5C68, 64, 0, ""), } ); ENTRY( "OKI MSM6258", { - DIV_SYSTEM_MSM6258, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM6258, 64, 0, ""), } ); ENTRY( "OKI MSM6295", { - DIV_SYSTEM_MSM6295, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM6295, 64, 0, ""), } ); ENTRY( "SNES", { - DIV_SYSTEM_SNES, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SNES, 64, 0, ""), } ); ENTRY( "Generic PCM DAC", { - DIV_SYSTEM_PCM_DAC, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCM_DAC, 64, 0, ""), } ); CATEGORY_END; @@ -1213,80 +1056,67 @@ void FurnaceGUI::initSystemPresets() { CATEGORY_BEGIN("Wavetable","chips which use user-specified waveforms to generate sound."); ENTRY( "PC Engine", { - DIV_SYSTEM_PCE, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCE, 64, 0, ""), } ); ENTRY( "Commodore PET (pseudo-wavetable)", { - DIV_SYSTEM_PET, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PET, 64, 0, ""), } ); ENTRY( "Konami Bubble System WSG", { - DIV_SYSTEM_BUBSYS_WSG, 64, 0, 0, - 0 + CH(DIV_SYSTEM_BUBSYS_WSG, 64, 0, ""), } ); ENTRY( "Konami SCC", { - DIV_SYSTEM_SCC, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SCC, 64, 0, ""), } ); ENTRY( "Konami SCC+", { - DIV_SYSTEM_SCC_PLUS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SCC_PLUS, 64, 0, ""), } ); ENTRY( "Namco WSG", { - DIV_SYSTEM_NAMCO, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO, 64, 0, ""), } ); ENTRY( "Namco C15 (8-channel mono)", { - DIV_SYSTEM_NAMCO_15XX, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO_15XX, 64, 0, ""), } ); ENTRY( "Namco C30 (8-channel stereo)", { - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO_CUS30, 64, 0, ""), } ); ENTRY( "Namco 163", { - DIV_SYSTEM_N163, 64, 0, 0, - 0 + CH(DIV_SYSTEM_N163, 64, 0, ""), } ); ENTRY( "Famicom Disk System (chip)", { - DIV_SYSTEM_FDS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_FDS, 64, 0, ""), } ); ENTRY( "WonderSwan", { - DIV_SYSTEM_SWAN, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SWAN, 64, 0, ""), } ); ENTRY( "Virtual Boy", { - DIV_SYSTEM_VBOY, 64, 0, 0, - 0 + CH(DIV_SYSTEM_VBOY, 64, 0, ""), } ); ENTRY( "Seta/Allumer X1-010", { - DIV_SYSTEM_X1_010, 64, 0, 0, - 0 + CH(DIV_SYSTEM_X1_010, 64, 0, ""), } ); CATEGORY_END; @@ -1295,69 +1125,59 @@ void FurnaceGUI::initSystemPresets() { ENTRY( "MOS Technology SID (6581)", { DIV_SYSTEM_C64_6581, 64, 0, 1, - 0 } ); ENTRY( "MOS Technology SID (8580)", { DIV_SYSTEM_C64_8580, 64, 0, 1, - 0 } ); ENTRY( "Microchip AY8930", { - DIV_SYSTEM_AY8930, 64, 0, 0, - 0 + CH(DIV_SYSTEM_AY8930, 64, 0, ""), } ); ENTRY( "Game Boy", { - DIV_SYSTEM_GB, 64, 0, 0, - 0 + CH(DIV_SYSTEM_GB, 64, 0, ""), } ); ENTRY( "Atari Lynx", { - DIV_SYSTEM_LYNX, 64, 0, 0, - 0 + CH(DIV_SYSTEM_LYNX, 64, 0, ""), } ); ENTRY( "Atari TIA", { - DIV_SYSTEM_TIA, 64, 0, 0, - 0 + CH(DIV_SYSTEM_TIA, 64, 0, ""), } ); ENTRY( "NES (Ricoh 2A03)", { - DIV_SYSTEM_NES, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), } ); ENTRY( "Commander X16 (VERA only)", { - DIV_SYSTEM_VERA, 64, 0, 0, - 0 + CH(DIV_SYSTEM_VERA, 64, 0, ""), } ); ENTRY( "ZX Spectrum (beeper only)", { - DIV_SYSTEM_SFX_BEEPER, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SFX_BEEPER, 64, 0, ""), } ); if (settings.hiddenSystems) { ENTRY( "Dummy System", { - DIV_SYSTEM_DUMMY, 64, 0, 0, + CH(DIV_SYSTEM_DUMMY, 64, 0, ""), 0 } ); } ENTRY( "tildearrow Sound Unit", { - DIV_SYSTEM_SOUND_UNIT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SOUND_UNIT, 64, 0, ""), } ); CATEGORY_END; @@ -1365,8 +1185,7 @@ void FurnaceGUI::initSystemPresets() { CATEGORY_BEGIN("Arcade systems","INSERT COIN"); ENTRY( "Pong", { - DIV_SYSTEM_PONG, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PONG, 64, 0, ""), } ); ENTRY( @@ -1375,136 +1194,118 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 3, // 2MHz DIV_SYSTEM_AY8910, 64, 0, 3, // 2MHz // additional sound boards, mostly software controlled DAC - 0 } ); ENTRY( "Williams/Midway Y/T unit w/ADPCM sound board", { // ADPCM sound board - DIV_SYSTEM_YM2151, 64, 0, 0, + CH(DIV_SYSTEM_YM2151, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 15624|(7<<16), // variable via OPM timer? - DIV_SYSTEM_MSM6295, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM6295, 64, 0, ""), } ); ENTRY( "Konami Gyruss", { - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, ""), // additional discrete sound logics - 0 } ); ENTRY( "Konami Bubble System", { - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_AY8910, 64, 0, 0, - DIV_SYSTEM_BUBSYS_WSG, 64, 0, 0, + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_AY8910, 64, 0, ""), + CH(DIV_SYSTEM_BUBSYS_WSG, 64, 0, ""), // VLM5030 exists but not used for music at all - 0 } ); ENTRY( "Konami Battlantis", { DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2, 64, 0, 3, // "" - 0 } ); ENTRY( "Konami Battlantis (drums mode on first OPL2)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2, 64, 0, 3, // "" - 0 } ); ENTRY( "Konami Battlantis (drums mode on second OPL2)", { DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // "" - 0 } ); ENTRY( "Konami Battlantis (drums mode on both OPL2s)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // "" - 0 } ); ENTRY( "Konami Hexion", { DIV_SYSTEM_SCC, 64, 0, 2, // 1.5MHz (3MHz input) DIV_SYSTEM_MSM6295, 64, 0, 1, - 0 } ); ENTRY( "Sega Kyugo", { DIV_SYSTEM_AY8910, 64, 0, 14, DIV_SYSTEM_AY8910, 64, 0, 14, - 0 } ); ENTRY( "Sega System 1", { DIV_SYSTEM_SMS, 64, 0, 0x42, // SN76489A 4MHz DIV_SYSTEM_SMS, 64, 0, 0x0141, // SN76489A 2MHz - 0 } ); ENTRY( "Sega System E", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_SMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 64, 0, ""), } ); ENTRY( "Sega System E (with FM expansion)", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_OPLL, 64, 0, ""), } ); ENTRY( "Sega System E (with FM expansion in drums mode)", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, ""), } ); ENTRY( "Sega Hang-On", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_SEGAPCM, 64, 0, 0, // discrete logics, 62.5KHz output rate - 0 } ); ENTRY( "Sega Hang-On (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_SEGAPCM, 64, 0, 0, // discrete logics, 62.5KHz output rate - 0 } ); ENTRY( "Sega OutRun/X Board", { DIV_SYSTEM_YM2151, 64, 0, 2, // 4MHz DIV_SYSTEM_SEGAPCM, 64, 0, 0, // ASIC, 31.25KHz output rate - 0 } ); ENTRY( "Sega System 24", { DIV_SYSTEM_YM2151, 64, 0, 2, // 4MHz DIV_SYSTEM_PCM_DAC, 64, 0, 61499|(7<<16), // software controlled, variable rate via configurable timers - 0 } ); ENTRY( @@ -1512,7 +1313,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2612, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz - 0 } ); ENTRY( @@ -1520,7 +1320,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz - 0 } ); ENTRY( @@ -1528,7 +1327,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2612, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz - 0 } ); ENTRY( @@ -1536,7 +1334,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete 8MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 1, // 10MHz - 0 } ); ENTRY( @@ -1544,7 +1341,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2612, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz - 0 } ); ENTRY( @@ -1552,7 +1348,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz - 0 } ); ENTRY( @@ -1560,7 +1355,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2612, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz - 0 } ); ENTRY( @@ -1568,7 +1362,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // discrete 8.05MHz YM3438 DIV_SYSTEM_YM2612_EXT, 64, 0, 4, // ^^ DIV_SYSTEM_RF5C68, 64, 0, 2, // 12.5MHz - 0 } ); ENTRY( @@ -1576,62 +1369,53 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 4, // 1.5MHz DIV_SYSTEM_SMS, 64, 0, 0x0104, // SN76489 3MHz DIV_SYSTEM_SMS, 64, 0, 0x0104, // SN76489 3MHz - 0 } ); ENTRY( "Capcom Arcade", { // 1943, Side arms, etc DIV_SYSTEM_OPN, 64, 0, 5, // 4 or 1.5MHz; various per games DIV_SYSTEM_OPN, 64, 0, 5, - 0 } ); ENTRY( "Capcom Arcade (extended channel 3 on first OPN)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, DIV_SYSTEM_OPN, 64, 0, 5, - 0 } ); ENTRY( "Capcom Arcade (extended channel 3 on second OPN)", { DIV_SYSTEM_OPN, 64, 0, 5, DIV_SYSTEM_OPN_EXT, 64, 0, 5, - 0 } ); ENTRY( "Capcom Arcade (extended channel 3 on both OPNs)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, DIV_SYSTEM_OPN_EXT, 64, 0, 5, - 0 } ); ENTRY( "Capcom CPS-1", { DIV_SYSTEM_YM2151, 64, 0, 0, // 3.58MHz - DIV_SYSTEM_MSM6295, 64, 0, 0, - 0 + CH(DIV_SYSTEM_MSM6295, 64, 0, ""), } ); ENTRY( "Capcom CPS-2 (QSound)", { - DIV_SYSTEM_QSOUND, 64, 0, 0, - 0 + CH(DIV_SYSTEM_QSOUND, 64, 0, ""), } ); ENTRY( "Jaleco Ginga NinkyouDen", { DIV_SYSTEM_AY8910, 64, 0, 16, // 1.79MHz DIV_SYSTEM_Y8950, 64, 0, 0, // 3.58MHz - 0 } ); ENTRY( "Jaleco Ginga NinkyouDen (drums mode)", { DIV_SYSTEM_AY8910, 64, 0, 16, // 1.79MHz DIV_SYSTEM_Y8950_DRUMS, 64, 0, 0, // 3.58MHz - 0 } ); ENTRY( @@ -1639,7 +1423,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2151, 64, 0, 1, // 3.5MHz (7MHz / 2) DIV_SYSTEM_MSM6295, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 2, // 4MHz - 0 } ); ENTRY( @@ -1647,7 +1430,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz; optional DIV_SYSTEM_MSM6295, 64, 0, 130, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 130, // ^^ - 0 } ); ENTRY( @@ -1655,7 +1437,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz; optional DIV_SYSTEM_MSM6295, 64, 0, 130, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 130, // ^^ - 0 } ); ENTRY( @@ -1663,7 +1444,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, -127, 12, // 1.5MHz, Left output DIV_SYSTEM_MSM6295, 64, 127, 12, // 1.5MHz, Right output - 0 } ); ENTRY( @@ -1671,21 +1451,18 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, -127, 12, // 1.5MHz, Left output DIV_SYSTEM_MSM6295, 64, 127, 12, // 1.5MHz, Right output - 0 } ); ENTRY( "Kaneko Air Buster", { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 141, // 3MHz - 0 } ); ENTRY( "Kaneko Air Buster (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 141, // 3MHz - 0 } ); ENTRY( @@ -1693,19 +1470,16 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 19, // YM2149 2MHz DIV_SYSTEM_AY8910, 64, 0, 19, // ^^ DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz - 0 } ); ENTRY( "Kaneko Jackie Chan", { DIV_SYSTEM_YMZ280B, 64, 0, 3, // 16MHz - 0 } ); ENTRY( "Super Kaneko Nova System", { DIV_SYSTEM_YMZ280B, 64, 0, 4, // 16.67MHz (33.33MHz / 2) - 0 } ); ENTRY( @@ -1713,7 +1487,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz - 0 } ); ENTRY( @@ -1721,7 +1494,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz - 0 } ); ENTRY( @@ -1729,7 +1501,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz - 0 } ); ENTRY( @@ -1737,78 +1508,67 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1MHz - 0 } ); ENTRY( "Tecmo System", { - DIV_SYSTEM_OPL3, 64, 0, 0, - DIV_SYSTEM_YMZ280B, 64, 0, 0, + CH(DIV_SYSTEM_OPL3, 64, 0, ""), + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz - 0 } ); ENTRY( "Tecmo System (drums mode)", { - DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, - DIV_SYSTEM_YMZ280B, 64, 0, 0, + CH(DIV_SYSTEM_OPL3_DRUMS, 64, 0, ""), + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), DIV_SYSTEM_MSM6295, 64, 0, 8, // 2MHz - 0 } ); ENTRY( "Seibu Kaihatsu Raiden", { // Raiden, Seibu cup soccer, Zero team, etc DIV_SYSTEM_OPL2, 64, 0, 0, // YM3812 3.58MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.023MHz (28.636363MHz / 28); various per games - 0 } ); ENTRY( "Seibu Kaihatsu Raiden (drums mode)", { // Raiden, Seibu cup soccer, Zero team, etc DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, // YM3812 3.58MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.023MHz (28.636363MHz / 28); various per games - 0 } ); ENTRY( "Sunsoft Shanghai 3", { DIV_SYSTEM_AY8910, 64, 0, 20, // YM2149 1.5MHz DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz - 0 } ); ENTRY( "Sunsoft Arcade", { DIV_SYSTEM_YM2612, 64, 0, 2, // discrete YM3438 8MHz DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz - 0 } ); ENTRY( "Sunsoft Arcade (extended channel 3)", { DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // discrete YM3438 8MHz DIV_SYSTEM_MSM6295, 64, 0, 1, // 1.056MHz - 0 } ); ENTRY( "Atari Klax", { DIV_SYSTEM_MSM6295, 64, 0, 7, // 0.895MHz (3.579545MHz / 4) - 0 } ); ENTRY( "Atari Rampart", { DIV_SYSTEM_OPLL, 64, 0, 0, // 3.579545MHz DIV_SYSTEM_MSM6295, 64, 0, 14, // 1.193MHz (3.579545MHz / 3) - 0 } ); ENTRY( "Atari Rampart (drums mode)", { DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.579545MHz DIV_SYSTEM_MSM6295, 64, 0, 14, // 1.193MHz (3.579545MHz / 3) - 0 } ); ENTRY( @@ -1816,35 +1576,30 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_YM2151, 64, 0, 0, // 3.579545MHz DIV_SYSTEM_MSM6295, 64, -127, 14, // 1.193MHz (3.579545MHz / 3), Left output DIV_SYSTEM_MSM6295, 64, 127, 14, // 1.193MHz (3.579545MHz / 3), Right output - 0 } ); ENTRY( "Data East Karnov", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL, 64, 0, 3, // 3MHz - 0 } ); ENTRY( "Data East Karnov (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL, 64, 0, 3, // 3MHz - 0 } ); ENTRY( "Data East Karnov (drums mode)", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL_DRUMS, 64, 0, 3, // 3MHz - 0 } ); ENTRY( "Data East Karnov (extended channel 3; drums mode)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL_DRUMS, 64, 0, 3, // 3MHz - 0 } ); ENTRY( @@ -1852,7 +1607,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional - 0 } ); ENTRY( @@ -1860,7 +1614,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional - 0 } ); ENTRY( @@ -1868,7 +1621,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional - 0 } ); ENTRY( @@ -1876,23 +1628,20 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz DIV_SYSTEM_OPL2_DRUMS, 64, 0, 3, // 3MHz DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 to 1.056MHz; various per games or optional - 0 } ); ENTRY( "Data East PCX", { DIV_SYSTEM_OPN, 64, 0, 5, // 1.5MHz - DIV_SYSTEM_PCE, 64, 0, 0, + CH(DIV_SYSTEM_PCE, 64, 0, ""), // software controlled MSM5205 - 0 } ); ENTRY( "Data East PCX (extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 5, // 1.5MHz - DIV_SYSTEM_PCE, 64, 0, 0, + CH(DIV_SYSTEM_PCE, 64, 0, ""), // software controlled MSM5205 - 0 } ); ENTRY( @@ -1902,7 +1651,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_MSM6295, 64, 0, 0, // 1.007MHz (32.22MHz / 32) DIV_SYSTEM_MSM6295, 64, 0, 8, // 2.014MHz (32.22MHz / 16); optional // HuC6280 is for control them, internal sound isn't used - 0 } ); ENTRY( @@ -1912,132 +1660,113 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_MSM6295, 64, 0, 0, // 1.007MHz (32.22MHz / 32) DIV_SYSTEM_MSM6295, 64, 0, 8, // 2.014MHz (32.22MHz / 16); optional // HuC6280 is for control them, internal sound isn't used - 0 } ); ENTRY( "Data East Deco 156", { DIV_SYSTEM_MSM6295, 64, 0, 0, // 1 or 1.007MHz (32.22MHz / 32); various per games DIV_SYSTEM_MSM6295, 64, 0, 8, // 1 or 2 or 2.014MHz (32.22MHz / 16); various per games - 0 } ); ENTRY( "Data East MLC", { DIV_SYSTEM_YMZ280B, 64, 0, 5, // 14MHz - 0 } ); ENTRY( "SNK Ikari Warriors", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, - 0 } ); ENTRY( "SNK Ikari Warriors (drums mode on first OPL)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, - 0 } ); ENTRY( "SNK Ikari Warriors (drums mode on second OPL)", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, - 0 } ); ENTRY( "SNK Ikari Warriors (drums mode on both OPLs)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, - 0 } ); ENTRY( "SNK Triple Z80", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, - 0 } ); ENTRY( "SNK Triple Z80 (drums mode on Y8950)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL, 64, 0, 2, - 0 } ); ENTRY( "SNK Triple Z80 (drums mode on OPL)", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, - 0 } ); ENTRY( "SNK Triple Z80 (drums mode on Y8950 and OPL)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, - 0 } ); ENTRY( "SNK Chopper I", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL2, 64, 0, 2, - 0 } ); ENTRY( "SNK Chopper I (drums mode on Y8950)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL2, 64, 0, 2, - 0 } ); ENTRY( "SNK Chopper I (drums mode on OPL2)", { DIV_SYSTEM_Y8950, 64, 0, 2, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 2, - 0 } ); ENTRY( "SNK Chopper I (drums mode on Y8950 and OPL2)", { DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, DIV_SYSTEM_OPL2_DRUMS, 64, 0, 2, - 0 } ); ENTRY( "SNK Touchdown Fever", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_Y8950, 64, 0, 2, - 0 } ); ENTRY( "SNK Touchdown Fever (drums mode on OPL)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_Y8950, 64, 0, 2, - 0 } ); ENTRY( "SNK Touchdown Fever (drums mode on Y8950)", { DIV_SYSTEM_OPL, 64, 0, 2, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, - 0 } ); ENTRY( "SNK Touchdown Fever (drums mode on OPL and Y8950)", { DIV_SYSTEM_OPL_DRUMS, 64, 0, 2, DIV_SYSTEM_Y8950_DRUMS, 64, 0, 2, - 0 } ); ENTRY( @@ -2045,7 +1774,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC - 0 } ); ENTRY( @@ -2053,7 +1781,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC - 0 } ); ENTRY( @@ -2061,7 +1788,6 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC - 0 } ); ENTRY( @@ -2069,19 +1795,16 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPN_EXT, 64, 0, 3, // 3MHz DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, // 3.58MHz DIV_SYSTEM_PCM_DAC, 64, 0, 7613|(7<<16), // software controlled 8 bit DAC - 0 } ); ENTRY( "Neo Geo MVS", { - DIV_SYSTEM_YM2610_FULL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610_FULL, 64, 0, ""), } ); ENTRY( "Neo Geo MVS (extended channel 2)", { - DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, ""), } ); ENTRY( @@ -2089,107 +1812,91 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_AY8910, 64, 0, 13, DIV_SYSTEM_AY8910, 64, 0, 13, DIV_SYSTEM_AY8910, 64, 0, 13, - 0 } ); ENTRY( "Namco (3-channel WSG)", { // Pac-Man, Galaga, Xevious, etc - DIV_SYSTEM_NAMCO, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO, 64, 0, ""), } ); ENTRY( "Namco Mappy", { // Mappy, Super Pac-Man, Libble Rabble, etc - DIV_SYSTEM_NAMCO_15XX, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO_15XX, 64, 0, ""), } ); ENTRY( "Namco Pac-Land", { // Pac-Land, Baraduke, Sky kid, etc - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NAMCO_CUS30, 64, 0, ""), } ); ENTRY( "Namco System 86", { // without expansion board case; Hopping Mappy, etc - DIV_SYSTEM_YM2151, 64, 0, 0, - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2151, 64, 0, ""), + CH(DIV_SYSTEM_NAMCO_CUS30, 64, 0, ""), } ); ENTRY( "Namco Thunder Ceptor", { - DIV_SYSTEM_YM2151, 64, 0, 0, - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, + CH(DIV_SYSTEM_YM2151, 64, 0, ""), + CH(DIV_SYSTEM_NAMCO_CUS30, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 7999|(7<<16), // M65C02 software driven, correct sample rate? - 0 } ); ENTRY( "Namco System 1", { - DIV_SYSTEM_YM2151, 64, 0, 0, - DIV_SYSTEM_NAMCO_CUS30, 64, 0, 0, + CH(DIV_SYSTEM_YM2151, 64, 0, ""), + CH(DIV_SYSTEM_NAMCO_CUS30, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 5999|(7<<16), // sample rate verified from https://github.com/mamedev/mame/blob/master/src/devices/sound/n63701x.cpp DIV_SYSTEM_PCM_DAC, 64, 0, 5999|(7<<16), // "" - 0 } ); ENTRY( "Taito Arcade", { - DIV_SYSTEM_YM2610B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610B, 64, 0, ""), } ); ENTRY( "Taito Arcade (extended channel 3)", { - DIV_SYSTEM_YM2610B_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610B_EXT, 64, 0, ""), } ); ENTRY( "Seta 1", { - DIV_SYSTEM_X1_010, 64, 0, 0, - 0 + CH(DIV_SYSTEM_X1_010, 64, 0, ""), } ); ENTRY( "Seta 1 + FM addon", { - DIV_SYSTEM_X1_010, 64, 0, 0, + CH(DIV_SYSTEM_X1_010, 64, 0, ""), DIV_SYSTEM_YM2612, 64, 0, 2, // Discrete YM3438 - 0 } ); ENTRY( "Seta 1 + FM addon (extended channel 3)", { - DIV_SYSTEM_X1_010, 64, 0, 0, + CH(DIV_SYSTEM_X1_010, 64, 0, ""), DIV_SYSTEM_YM2612_EXT, 64, 0, 2, // Discrete YM3438 - 0 } ); ENTRY( "Seta 2", { DIV_SYSTEM_X1_010, 64, 0, 1, - 0 } ); ENTRY( "Cave 68000", { - DIV_SYSTEM_YMZ280B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), } ); ENTRY( "Coreland Cyber Tank", { DIV_SYSTEM_Y8950, 64, -127, 0, // 3.58MHz, Left output DIV_SYSTEM_Y8950, 64, 127, 0, // 3.58MHz, Right output - 0 } ); ENTRY( "Coreland Cyber Tank (drums mode)", { DIV_SYSTEM_Y8950, 64, -127, 0, // 3.58MHz, Left output DIV_SYSTEM_Y8950, 64, 127, 0, // 3.58MHz, Right output - 0 } ); ENTRY( @@ -2198,56 +1905,48 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_MSM6295, 64, 127, 130, // 4MHz, Right output DIV_SYSTEM_MSM6295, 64, -127, 8, // 2MHz, Left output DIV_SYSTEM_MSM6295, 64, 127, 8, // 2MHz, Right output - 0 } ); ENTRY( "Toaplan 1", { DIV_SYSTEM_OPL2, 64, 0, 5, // 3.5MHz - 0 } ); ENTRY( "Toaplan 1 (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 5, // 3.5MHz - 0 } ); ENTRY( "Dynax/Nakanihon 3rd generation hardware", { DIV_SYSTEM_AY8910, 64, 0, 0, // AY or YM, optional - 1.79MHz or 3.58MHz; various per game - DIV_SYSTEM_OPLL, 64, 0, 0, + CH(DIV_SYSTEM_OPLL, 64, 0, ""), DIV_SYSTEM_MSM6295, 64, 0, 6, // 1.023MHz mostly - 0 } ); ENTRY( "Dynax/Nakanihon 3rd generation hardware (drums mode)", { DIV_SYSTEM_AY8910, 64, 0, 0, // AY or YM, optional - 1.79MHz or 3.58MHz; various per game - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, ""), DIV_SYSTEM_MSM6295, 64, 0, 6, // 1.023MHz mostly - 0 } ); ENTRY( "Dynax/Nakanihon Real Break", { - DIV_SYSTEM_OPLL, 64, 0, 0, - DIV_SYSTEM_YMZ280B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPLL, 64, 0, ""), + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), } ); ENTRY( "Dynax/Nakanihon Real Break (drums mode)", { - DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0, - DIV_SYSTEM_YMZ280B, 64, 0, 0, - 0 + CH(DIV_SYSTEM_OPLL_DRUMS, 64, 0, ""), + CH(DIV_SYSTEM_YMZ280B, 64, 0, ""), } ); ENTRY( "Irem M72", { - DIV_SYSTEM_YM2151, 64, 0, 0, + CH(DIV_SYSTEM_YM2151, 64, 0, ""), DIV_SYSTEM_PCM_DAC, 64, 0, 7811|(7<<16), - 0 } ); CATEGORY_END; @@ -2255,95 +1954,82 @@ void FurnaceGUI::initSystemPresets() { CATEGORY_BEGIN("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."); ENTRY( "Sega Genesis", { - DIV_SYSTEM_YM2612, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, ""), } ); ENTRY( "Sega Genesis (extended channel 3)", { - DIV_SYSTEM_YM2612_EXT, 64, 0, 0, - DIV_SYSTEM_SMS, 32, 0, 0, - 0 + CH(DIV_SYSTEM_YM2612_EXT, 64, 0, ""), + CH(DIV_SYSTEM_SMS, 32, 0, ""), } ); ENTRY( "Sega Master System", { - DIV_SYSTEM_SMS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), } ); ENTRY( "Sega Master System (with FM expansion)", { - DIV_SYSTEM_SMS, 64, 0, 0, - DIV_SYSTEM_OPLL, 64, 0, 0, - 0 + CH(DIV_SYSTEM_SMS, 64, 0, ""), + CH(DIV_SYSTEM_OPLL, 64, 0, ""), } ); ENTRY( "Game Boy", { - DIV_SYSTEM_GB, 64, 0, 0, - 0 + CH(DIV_SYSTEM_GB, 64, 0, ""), } ); ENTRY( "NEC PC Engine/TurboGrafx-16", { - DIV_SYSTEM_PCE, 64, 0, 0, - 0 + CH(DIV_SYSTEM_PCE, 64, 0, ""), } ); ENTRY( "NES", { - DIV_SYSTEM_NES, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), } ); ENTRY( "Famicom with Konami VRC7", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_VRC7, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_VRC7, 64, 0, ""), } ); ENTRY( "Famicom Disk System", { - DIV_SYSTEM_NES, 64, 0, 0, - DIV_SYSTEM_FDS, 64, 0, 0, - 0 + CH(DIV_SYSTEM_NES, 64, 0, ""), + CH(DIV_SYSTEM_FDS, 64, 0, ""), } ); ENTRY( "Commodore 64 (6581 SID)", { DIV_SYSTEM_C64_6581, 64, 0, 1, - 0 } ); ENTRY( "Commodore 64 (8580 SID)", { DIV_SYSTEM_C64_8580, 64, 0, 1, - 0 } ); ENTRY( "Arcade (YM2151 and SegaPCM)", { - DIV_SYSTEM_YM2151, 64, 0, 0, - DIV_SYSTEM_SEGAPCM_COMPAT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2151, 64, 0, ""), + CH(DIV_SYSTEM_SEGAPCM_COMPAT, 64, 0, ""), } ); ENTRY( "Neo Geo CD", { - DIV_SYSTEM_YM2610, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610, 64, 0, ""), } ); ENTRY( "Neo Geo CD (extended channel 2)", { - DIV_SYSTEM_YM2610_EXT, 64, 0, 0, - 0 + CH(DIV_SYSTEM_YM2610_EXT, 64, 0, ""), } ); CATEGORY_END; + */ } FurnaceGUISysDef::FurnaceGUISysDef(const char* n, std::initializer_list def):