From 1bdcbf95d3204671b88277e9b36d560b2b05e9e6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 12 Aug 2024 23:20:08 -0500 Subject: [PATCH 01/37] prepare a ROM export dialog --- src/gui/exportOptions.cpp | 11 +++++++++++ src/gui/gui.cpp | 8 ++++++++ src/gui/gui.h | 2 ++ 3 files changed, 21 insertions(+) diff --git a/src/gui/exportOptions.cpp b/src/gui/exportOptions.cpp index 4b4360839..904c88891 100644 --- a/src/gui/exportOptions.cpp +++ b/src/gui/exportOptions.cpp @@ -239,6 +239,10 @@ void FurnaceGUI::drawExportVGM(bool onWindow) { } } +void FurnaceGUI::drawExportROM(bool onWindow) { + +} + void FurnaceGUI::drawExportZSM(bool onWindow) { exitDisabledTimer=1; @@ -434,6 +438,10 @@ void FurnaceGUI::drawExport() { drawExportVGM(true); ImGui::EndTabItem(); } + if (ImGui::BeginTabItem(_("ROM"))) { + drawExportROM(true); + ImGui::EndTabItem(); + } int numZSMCompat=0; for (int i=0; isong.systemLen; i++) { if ((e->song.system[i]==DIV_SYSTEM_VERA) || (e->song.system[i]==DIV_SYSTEM_YM2151)) numZSMCompat++; @@ -488,6 +496,9 @@ void FurnaceGUI::drawExport() { case GUI_EXPORT_VGM: drawExportVGM(true); break; + case GUI_EXPORT_ROM: + drawExportROM(true); + break; case GUI_EXPORT_ZSM: drawExportZSM(true); break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 3ba5e2705..1d262ce16 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4295,6 +4295,10 @@ bool FurnaceGUI::loop() { drawExportVGM(); ImGui::EndMenu(); } + if (ImGui::BeginMenu(_("export ROM..."))) { + drawExportROM(); + ImGui::EndMenu(); + } int numZSMCompat=0; for (int i=0; isong.systemLen; i++) { if ((e->song.system[i]==DIV_SYSTEM_VERA) || (e->song.system[i]==DIV_SYSTEM_YM2151)) numZSMCompat++; @@ -4349,6 +4353,10 @@ bool FurnaceGUI::loop() { curExportType=GUI_EXPORT_VGM; displayExport=true; } + if (ImGui::MenuItem(_("export ROM..."))) { + curExportType=GUI_EXPORT_ROM; + displayExport=true; + } int numZSMCompat=0; for (int i=0; isong.systemLen; i++) { if ((e->song.system[i]==DIV_SYSTEM_VERA) || (e->song.system[i]==DIV_SYSTEM_YM2151)) numZSMCompat++; diff --git a/src/gui/gui.h b/src/gui/gui.h index 515d77fc8..50020e0db 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -651,6 +651,7 @@ enum FurnaceGUIExportTypes { GUI_EXPORT_AUDIO=0, GUI_EXPORT_VGM, + GUI_EXPORT_ROM, GUI_EXPORT_ZSM, GUI_EXPORT_TIUNA, GUI_EXPORT_CMD_STREAM, @@ -2686,6 +2687,7 @@ class FurnaceGUI { void drawExportAudio(bool onWindow=false); void drawExportVGM(bool onWindow=false); + void drawExportROM(bool onWindow=false); void drawExportZSM(bool onWindow=false); void drawExportTiuna(bool onWindow=false); void drawExportAmigaVal(bool onWindow=false); From 45eab67fd46d7f5b197d3429deefd31164b767e9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 13 Aug 2024 04:10:03 -0500 Subject: [PATCH 02/37] prepare more stuff --- CMakeLists.txt | 1 + src/engine/engine.h | 6 ++++ src/engine/export.h | 26 +++++++++++------ src/engine/exportDef.cpp | 60 +++++++++++++++++++++++++++++++++++++++ src/gui/exportOptions.cpp | 11 +++++++ 5 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 src/engine/exportDef.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b7bc35433..464283d9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -693,6 +693,7 @@ src/engine/configEngine.cpp src/engine/dispatchContainer.cpp src/engine/engine.cpp src/engine/export.cpp +src/engine/exportDef.cpp src/engine/fileOpsIns.cpp src/engine/fileOpsSample.cpp src/engine/filter.cpp diff --git a/src/engine/engine.h b/src/engine/engine.h index a2e900c81..7f19e946b 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -518,6 +518,7 @@ class DivEngine { static DivSysDef* sysDefs[DIV_MAX_CHIP_DEFS]; static DivSystem sysFileMapFur[DIV_MAX_CHIP_DEFS]; static DivSystem sysFileMapDMF[DIV_MAX_CHIP_DEFS]; + static DivROMExportDef* romExportDefs[DIV_ROM_MAX]; DivCSPlayer* cmdStreamInt; @@ -624,6 +625,7 @@ class DivEngine { bool deinitAudioBackend(bool dueToSwitchMaster=false); void registerSystems(); + void registerROMExports(); void initSongWithDesc(const char* description, bool inBase64=true, bool oldVol=false); void exchangeIns(int one, int two); @@ -884,6 +886,9 @@ class DivEngine { // get sys definition const DivSysDef* getSystemDef(DivSystem sys); + // get ROM export definition + const DivROMExportDef* getROMExportDef(DivROMExportOptions opt); + // convert sample rate format int fileToDivRate(int frate); int divToFileRate(int drate); @@ -1466,6 +1471,7 @@ class DivEngine { memset(pitchTable,0,4096*sizeof(int)); memset(effectSlotMap,-1,4096*sizeof(short)); memset(sysDefs,0,DIV_MAX_CHIP_DEFS*sizeof(void*)); + memset(romExportDefs,0,DIV_ROM_MAX*sizeof(void*)); memset(walked,0,8192); memset(oscBuf,0,DIV_MAX_OUTPUTS*(sizeof(float*))); memset(exportChannelMask,1,DIV_MAX_CHANS*sizeof(bool)); diff --git a/src/engine/export.h b/src/engine/export.h index 9445ecfe9..4911217c8 100644 --- a/src/engine/export.h +++ b/src/engine/export.h @@ -29,6 +29,8 @@ class DivEngine; enum DivROMExportOptions { DIV_ROM_ABSTRACT=0, DIV_ROM_AMIGA_VALIDATION, + DIV_ROM_ZSM, + DIV_ROM_TIUNA, DIV_ROM_MAX }; @@ -67,24 +69,30 @@ class DivROMExport { virtual ~DivROMExport() {} }; +enum DivROMExportReqPolicy { + // exactly these chips. + DIV_REQPOL_EXACT=0, + // specified chips must be present but any amount of them is acceptable. + DIV_REQPOL_ANY, + // at least one of the specified chips. + DIV_REQPOL_LAX +}; + struct DivROMExportDef { const char* name; const char* author; const char* description; - DivSystem requisites[32]; - int requisitesLen; + std::vector requisites; bool multiOutput; + DivROMExportReqPolicy requisitePolicy; - DivROMExportDef(const char* n, const char* a, const char* d, std::initializer_list req, bool multiOut): + DivROMExportDef(const char* n, const char* a, const char* d, std::initializer_list req, bool multiOut, DivROMExportReqPolicy reqPolicy): name(n), author(a), description(d), - multiOutput(multiOut) { - requisitesLen=0; - memset(requisites,0,32*sizeof(DivSystem)); - for (DivSystem i: req) { - requisites[requisitesLen++]=i; - } + multiOutput(multiOut), + requisitePolicy(reqPolicy) { + requisites=req; } }; diff --git a/src/engine/exportDef.cpp b/src/engine/exportDef.cpp new file mode 100644 index 000000000..bdf881e65 --- /dev/null +++ b/src/engine/exportDef.cpp @@ -0,0 +1,60 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2024 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 "engine.h" + +DivROMExportDef* DivEngine::romExportDefs[DIV_ROM_MAX]; + +const DivROMExportDef* DivEngine::getROMExportDef(DivROMExportOptions opt) { + return romExportDefs[opt]; +} + +void DivEngine::registerROMExports() { + logD("registering ROM exports..."); + + romExportDefs[DIV_ROM_AMIGA_VALIDATION]=new DivROMExportDef( + "Amiga Validation", "tildearrow", + "a test export for ensuring Amiga emulation is accurate. do not use!", + {DIV_SYSTEM_AMIGA}, + true, DIV_REQPOL_EXACT + ); + + romExportDefs[DIV_ROM_ZSM]=new DivROMExportDef( + "Commander X16 ZSM", "ZeroByteOrg and MooingLemur", + "Commander X16 Zsound Music File.\n" + "for use with Melodius, Calliope and/or ZSMKit:\n" + "- https://github.com/mooinglemur/zsmkit (development)\n" + "- https://github.com/mooinglemur/melodius (player)\n" + "- https://github.com/ZeroByteOrg/calliope (player)\n", + { + DIV_SYSTEM_YM2151, DIV_SYSTEM_VERA + }, + true, DIV_REQPOL_LAX + ); + + romExportDefs[DIV_ROM_TIUNA]=new DivROMExportDef( + "Atari 2600 (TIunA)", "Natt Akuma", + "advanced driver with software tuning support.\n" + "see https://github.com/AYCEdemo/twin-tiuna for code.", + { + DIV_SYSTEM_TIA + }, + true, DIV_REQPOL_ANY + ); +} \ No newline at end of file diff --git a/src/gui/exportOptions.cpp b/src/gui/exportOptions.cpp index 904c88891..582ba3055 100644 --- a/src/gui/exportOptions.cpp +++ b/src/gui/exportOptions.cpp @@ -240,7 +240,18 @@ void FurnaceGUI::drawExportVGM(bool onWindow) { } void FurnaceGUI::drawExportROM(bool onWindow) { + exitDisabledTimer=1; + + if (onWindow) { + ImGui::Separator(); + if (ImGui::Button(_("Cancel"),ImVec2(200.0f*dpiScale,0))) ImGui::CloseCurrentPopup(); + ImGui::SameLine(); + } + if (ImGui::Button(_("Export"),ImVec2(200.0f*dpiScale,0))) { + openFileDialog(GUI_FILE_EXPORT_ROM); + ImGui::CloseCurrentPopup(); + } } void FurnaceGUI::drawExportZSM(bool onWindow) { From a8122d3efdb638be39238902a8534209ec79411f Mon Sep 17 00:00:00 2001 From: MooingLemur Date: Sun, 11 Aug 2024 20:24:48 -0700 Subject: [PATCH 03/37] Add VERA 47.0.3 chip type --- src/engine/platform/sound/vera_psg.c | 5 +++-- src/engine/zsm.cpp | 8 -------- src/gui/sysConf.cpp | 6 +++++- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/engine/platform/sound/vera_psg.c b/src/engine/platform/sound/vera_psg.c index be080ace9..7ed3d48e5 100644 --- a/src/engine/platform/sound/vera_psg.c +++ b/src/engine/platform/sound/vera_psg.c @@ -5,6 +5,7 @@ // Chip revisions // 0: V 0.3.0 // 1: V 47.0.0 (9-bit volume, phase reset on mute) +// 2: V 47.0.3 (Pulse Width XOR on Saw and Triangle) #include "vera_psg.h" @@ -88,8 +89,8 @@ render(struct VERA_PSG* psg, int16_t *left, int16_t *right) uint8_t v = 0; switch (ch->waveform) { case WF_PULSE: v = (ch->phase >> 10) > ch->pw ? 0 : 63; break; - case WF_SAWTOOTH: v = ch->phase >> 11; break; - case WF_TRIANGLE: v = (ch->phase & 0x10000) ? (~(ch->phase >> 10) & 0x3F) : ((ch->phase >> 10) & 0x3F); break; + case WF_SAWTOOTH: v = (ch->phase >> 11) ^ (psg->chipType < 2 ? 0 : (ch->pw ^ 0x3f) & 0x3f); break; + case WF_TRIANGLE: v = ((ch->phase & 0x10000) ? (~(ch->phase >> 10) & 0x3F) : ((ch->phase >> 10) & 0x3F)) ^ (psg->chipType < 2 ? 0 : (ch->pw ^ 0x3f) & 0x3f); break; case WF_NOISE: v = ch->noiseval; break; } int8_t sv = (v ^ 0x20); diff --git a/src/engine/zsm.cpp b/src/engine/zsm.cpp index 87dbde8d2..75cc3d9da 100644 --- a/src/engine/zsm.cpp +++ b/src/engine/zsm.cpp @@ -133,14 +133,6 @@ void DivZSM::writePSG(unsigned char a, unsigned char v) { } else if (a>=64) { return writePCM(a-64,v); } - if (optimize) { - if ((a&3)==3 && v>64) { - // Pulse width on non-pulse waves is nonsense and wasteful - // No need to preserve state here because the next write that - // selects pulse will also set the pulse width in this register - v&=0xc0; - } - } if (psgState[psg_PREV][a]==v) { if (psgState[psg_NEW][a]!=v) { // NEW value is being reset to the same as PREV value diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 0875f25c1..6ce257357 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -2482,7 +2482,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl break; } case DIV_SYSTEM_VERA: { - int chipType=flags.getInt("chipType",1); + int chipType=flags.getInt("chipType",2); ImGui::Text(_("Chip revision:")); ImGui::Indent(); @@ -2494,6 +2494,10 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl chipType=1; altered=true; } + if (ImGui::RadioButton(_("V 47.0.3 (Tri/Saw PW XOR)"),chipType==2)) { + chipType=2; + altered=true; + } ImGui::Unindent(); if (altered) { From 3b9cf70ff56737b09981525aee8c2d7caa92c652 Mon Sep 17 00:00:00 2001 From: MooingLemur Date: Sun, 11 Aug 2024 20:47:40 -0700 Subject: [PATCH 04/37] VERA: bump default chip type --- src/engine/platform/vera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index e4e78933e..b6b7cf831 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -532,7 +532,7 @@ void DivPlatformVERA::poke(std::vector& wlist) { } void DivPlatformVERA::setFlags(const DivConfig& flags) { - psg->chipType=flags.getInt("chipType",1); + psg->chipType=flags.getInt("chipType",2); chipClock=25000000; CHECK_CUSTOM_CLOCK; rate=chipClock/512; From 0224882a429e37da05b26a8b3398bc02194ea12f Mon Sep 17 00:00:00 2001 From: MooingLemur Date: Sun, 11 Aug 2024 21:03:21 -0700 Subject: [PATCH 05/37] oops, should have been 47.0.2 --- src/engine/platform/sound/vera_psg.c | 2 +- src/gui/sysConf.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/sound/vera_psg.c b/src/engine/platform/sound/vera_psg.c index 7ed3d48e5..597aa5974 100644 --- a/src/engine/platform/sound/vera_psg.c +++ b/src/engine/platform/sound/vera_psg.c @@ -5,7 +5,7 @@ // Chip revisions // 0: V 0.3.0 // 1: V 47.0.0 (9-bit volume, phase reset on mute) -// 2: V 47.0.3 (Pulse Width XOR on Saw and Triangle) +// 2: V 47.0.2 (Pulse Width XOR on Saw and Triangle) #include "vera_psg.h" diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 6ce257357..f460a5434 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -2494,7 +2494,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl chipType=1; altered=true; } - if (ImGui::RadioButton(_("V 47.0.3 (Tri/Saw PW XOR)"),chipType==2)) { + if (ImGui::RadioButton(_("V 47.0.2 (Tri/Saw PW XOR)"),chipType==2)) { chipType=2; altered=true; } From b5e500d85d90fb7576394b8b77c9d4ae5c9e488b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 13 Aug 2024 04:14:46 -0500 Subject: [PATCH 06/37] dev217 --- src/engine/engine.h | 4 ++-- src/engine/fileOps/fur.cpp | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 7f19e946b..9ecf819ee 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -54,8 +54,8 @@ class DivWorkPool; #define DIV_UNSTABLE -#define DIV_VERSION "Import Test" -#define DIV_ENGINE_VERSION 216 +#define DIV_VERSION "dev217" +#define DIV_ENGINE_VERSION 217 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOps/fur.cpp b/src/engine/fileOps/fur.cpp index 0251c410e..5483d8fb9 100644 --- a/src/engine/fileOps/fur.cpp +++ b/src/engine/fileOps/fur.cpp @@ -2094,6 +2094,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { ds.systemFlags[i].set("oldPitch",true); } } + } else if (ds.version<217) { + for (int i=0; i Date: Tue, 13 Aug 2024 04:40:26 -0500 Subject: [PATCH 07/37] a menu --- src/engine/engine.cpp | 3 +++ src/engine/engine.h | 2 ++ src/gui/exportOptions.cpp | 22 +++++++++++++++++++++- src/gui/gui.cpp | 3 ++- src/gui/gui.h | 3 +++ 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 1a382b85e..bfde6906b 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3916,6 +3916,9 @@ bool DivEngine::preInit(bool noSafeMode) { // register systems if (!systemsRegistered) registerSystems(); + // register ROM exports + if (!romExportsRegistered) registerROMExports(); + // TODO: re-enable with a better approach // see issue #1581 /* diff --git a/src/engine/engine.h b/src/engine/engine.h index 9ecf819ee..e30334fd4 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -465,6 +465,7 @@ class DivEngine { bool midiIsDirectProgram; bool lowLatency; bool systemsRegistered; + bool romExportsRegistered; bool hasLoadedSomething; bool midiOutClock; bool midiOutTime; @@ -1365,6 +1366,7 @@ class DivEngine { midiIsDirectProgram(false), lowLatency(false), systemsRegistered(false), + romExportsRegistered(false), hasLoadedSomething(false), midiOutClock(false), midiOutTime(false), diff --git a/src/gui/exportOptions.cpp b/src/gui/exportOptions.cpp index 582ba3055..c943779eb 100644 --- a/src/gui/exportOptions.cpp +++ b/src/gui/exportOptions.cpp @@ -241,7 +241,27 @@ void FurnaceGUI::drawExportVGM(bool onWindow) { void FurnaceGUI::drawExportROM(bool onWindow) { exitDisabledTimer=1; - + + const DivROMExportDef* def=e->getROMExportDef(romTarget); + + ImGui::Text("select target:"); + if (ImGui::BeginCombo("##ROMTarget",def==NULL?"":def->name)) { for (int i=0; igetROMExportDef((DivROMExportOptions)i); @@ -252,6 +252,7 @@ void FurnaceGUI::drawExportROM(bool onWindow) { if (ImGui::Selectable(newDef->name)) { romTarget=(DivROMExportOptions)i; romMultiFile=newDef->multiOutput; + romConfig=DivConfig(); if (newDef->fileExt==NULL) { romFilterName=""; romFilterExt=""; @@ -271,34 +272,66 @@ void FurnaceGUI::drawExportROM(bool onWindow) { ImGui::TextWrapped("%s",def->description); } - /* - ImGui::InputText(_("base song label name"),&asmBaseLabel); // TODO: validate label - if (ImGui::InputInt(_("max size in first bank"),&tiunaFirstBankSize,1,100)) { - if (tiunaFirstBankSize<0) tiunaFirstBankSize=0; - if (tiunaFirstBankSize>4096) tiunaFirstBankSize=4096; - } - if (ImGui::InputInt(_("max size in other banks"),&tiunaOtherBankSize,1,100)) { - if (tiunaOtherBankSize<16) tiunaOtherBankSize=16; - if (tiunaOtherBankSize>4096) tiunaOtherBankSize=4096; - } - - ImGui::Text(_("chips to export:")); - int selected=0; - for (int i=0; isong.systemLen; i++) { - DivSystem sys=e->song.system[i]; - bool isTIA=sys==DIV_SYSTEM_TIA; - ImGui::BeginDisabled((!isTIA) || (selected>=1)); - ImGui::Checkbox(fmt::sprintf("%d. %s##_SYSV%d",i+1,getSystemName(e->song.system[i]),i).c_str(),&willExport[i]); - ImGui::EndDisabled(); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { - if (!isTIA) { - ImGui::SetTooltip(_("this chip is not supported by the file format!")); - } else if (selected>=1) { - ImGui::SetTooltip(_("only one Atari TIA is supported!")); + ImGui::Separator(); + + bool altered=false; + + switch (romTarget) { + case DIV_ROM_TIUNA: { + String asmBaseLabel=romConfig.getString("baseLabel","song"); + int firstBankSize=romConfig.getInt("firstBankSize",3072); + int otherBankSize=romConfig.getInt("otherBankSize",4096-48); + + // TODO; validate label + if (ImGui::InputText(_("base song label name"),&asmBaseLabel)) { + altered=true; } + if (ImGui::InputInt(_("max size in first bank"),&firstBankSize,1,100)) { + if (firstBankSize<0) firstBankSize=0; + if (firstBankSize>4096) firstBankSize=4096; + altered=true; + } + if (ImGui::InputInt(_("max size in other banks"),&otherBankSize,1,100)) { + if (otherBankSize<16) otherBankSize=16; + if (otherBankSize>4096) otherBankSize=4096; + altered=true; + } + + ImGui::Text(_("chips to export:")); + int selected=0; + for (int i=0; isong.systemLen; i++) { + DivSystem sys=e->song.system[i]; + bool isTIA=sys==DIV_SYSTEM_TIA; + ImGui::BeginDisabled((!isTIA) || (selected>=1)); + if (ImGui::Checkbox(fmt::sprintf("%d. %s##_SYSV%d",i+1,getSystemName(e->song.system[i]),i).c_str(),&willExport[i])) { + altered=true; + } + ImGui::EndDisabled(); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { + if (!isTIA) { + ImGui::SetTooltip(_("this chip is not supported by the file format!")); + } else if (selected>=1) { + ImGui::SetTooltip(_("only one Atari TIA is supported!")); + } + } + if (isTIA && willExport[i]) selected++; + + if (altered) { + romConfig.set("baseLabel",asmBaseLabel); + romConfig.set("firstBankSize",firstBankSize); + romConfig.set("otherBankSize",otherBankSize); + } + } + break; } - if (isTIA && willExport[i]) selected++; + case DIV_ROM_ABSTRACT: + ImGui::TextWrapped("%s",_("select a target from the menu at the top of this dialog.")); + break; + default: + ImGui::TextWrapped("%s",_("this export method doesn't offer any options.")); + break; } + /* */ if (onWindow) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index d01589503..45d71e95f 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -7933,9 +7933,6 @@ FurnaceGUI::FurnaceGUI(): vgmExportTrailingTicks(-1), drawHalt(10), zsmExportTickRate(60), - asmBaseLabel(""), - tiunaFirstBankSize(3072), - tiunaOtherBankSize(4096-48), macroPointSize(16), waveEditStyle(0), displayInsTypeListMakeInsSample(-1), diff --git a/src/gui/gui.h b/src/gui/gui.h index 7a7b8ed0f..7f0fd18ff 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1632,9 +1632,6 @@ class FurnaceGUI { int cvHiScore; int drawHalt; int zsmExportTickRate; - String asmBaseLabel; - int tiunaFirstBankSize; - int tiunaOtherBankSize; int macroPointSize; int waveEditStyle; int displayInsTypeListMakeInsSample; From 34517754ad017bc73564af6b3e3e7bd3a37ed4a7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 13 Aug 2024 18:42:11 -0500 Subject: [PATCH 13/37] port TIunA to export framework, part 4 index option --- src/engine/export/tiuna.cpp | 31 ++++++++++++++++++------------- src/gui/exportOptions.cpp | 31 ++++++++++++------------------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/engine/export/tiuna.cpp b/src/engine/export/tiuna.cpp index 985eba49f..397cee34f 100644 --- a/src/engine/export/tiuna.cpp +++ b/src/engine/export/tiuna.cpp @@ -183,16 +183,15 @@ static void writeCmd(std::vector& cmds, TiunaCmd& cmd, unsigned char void DivExportTiuna::run() { int loopOrder, loopOrderRow, loopEnd; - int tiaIdx; int tick=0; SafeWriter* w; std::map allCmds[2]; // config - int* sysToExport=NULL; String baseLabel=conf.getString("baseLabel","song"); int firstBankSize=conf.getInt("firstBankSize",3072); int otherBankSize=conf.getInt("otherBankSize",4096-48); + int tiaIdx=conf.getInt("sysToExport",-1); e->stop(); e->repeatPattern=false; @@ -210,23 +209,29 @@ void DivExportTiuna::run() { w=new SafeWriter; w->init(); - tiaIdx=-1; - - for (int i=0; isong.systemLen; i++) { - if (sysToExport!=NULL && !sysToExport[i]) continue; - if (e->song.system[i]==DIV_SYSTEM_TIA) { - tiaIdx=i; - e->disCont[i].dispatch->toggleRegisterDump(true); - break; + if (tiaIdx<0 || tiaIdx>=e->song.systemLen) { + tiaIdx=-1; + for (int i=0; isong.systemLen; i++) { + if (e->song.system[i]==DIV_SYSTEM_TIA) { + tiaIdx=i; + break; + } } - } - if (tiaIdx<0) { - logAppend("ERROR: selected TIA system not found"); + if (tiaIdx<0) { + logAppend("ERROR: selected TIA system not found"); + failed=true; + running=false; + return; + } + } else if (e->song.system[tiaIdx]!=DIV_SYSTEM_TIA) { + logAppend("ERROR: selected chip is not a TIA!"); failed=true; running=false; return; } + e->disCont[tiaIdx].dispatch->toggleRegisterDump(true); + // write patterns // bool writeLoop=false; logAppend("recording sequence..."); diff --git a/src/gui/exportOptions.cpp b/src/gui/exportOptions.cpp index 2ca8fa7e0..aca5523f0 100644 --- a/src/gui/exportOptions.cpp +++ b/src/gui/exportOptions.cpp @@ -281,6 +281,7 @@ void FurnaceGUI::drawExportROM(bool onWindow) { String asmBaseLabel=romConfig.getString("baseLabel","song"); int firstBankSize=romConfig.getInt("firstBankSize",3072); int otherBankSize=romConfig.getInt("otherBankSize",4096-48); + int sysToExport=romConfig.getInt("sysToExport",-1); // TODO; validate label if (ImGui::InputText(_("base song label name"),&asmBaseLabel)) { @@ -297,30 +298,22 @@ void FurnaceGUI::drawExportROM(bool onWindow) { altered=true; } - ImGui::Text(_("chips to export:")); - int selected=0; + ImGui::Text(_("chip to export:")); for (int i=0; isong.systemLen; i++) { DivSystem sys=e->song.system[i]; - bool isTIA=sys==DIV_SYSTEM_TIA; - ImGui::BeginDisabled((!isTIA) || (selected>=1)); - if (ImGui::Checkbox(fmt::sprintf("%d. %s##_SYSV%d",i+1,getSystemName(e->song.system[i]),i).c_str(),&willExport[i])) { + bool isTIA=(sys==DIV_SYSTEM_TIA); + ImGui::BeginDisabled(!isTIA); + if (ImGui::RadioButton(fmt::sprintf("%d. %s##_SYSV%d",i+1,getSystemName(e->song.system[i]),i).c_str(),sysToExport==i)) { + sysToExport=i; altered=true; } ImGui::EndDisabled(); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { - if (!isTIA) { - ImGui::SetTooltip(_("this chip is not supported by the file format!")); - } else if (selected>=1) { - ImGui::SetTooltip(_("only one Atari TIA is supported!")); - } - } - if (isTIA && willExport[i]) selected++; - - if (altered) { - romConfig.set("baseLabel",asmBaseLabel); - romConfig.set("firstBankSize",firstBankSize); - romConfig.set("otherBankSize",otherBankSize); - } + } + if (altered) { + romConfig.set("baseLabel",asmBaseLabel); + romConfig.set("firstBankSize",firstBankSize); + romConfig.set("otherBankSize",otherBankSize); + romConfig.set("sysToExport",sysToExport); } break; } From f906b4ebe4bcc50468fe0de20c0985ff05e8df13 Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 14 Aug 2024 17:54:20 +0900 Subject: [PATCH 14/37] Safety check for MSM6295 bankswitched address --- src/engine/platform/msm6295.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 916234f0e..6b40575b9 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -39,14 +39,25 @@ const char** DivPlatformMSM6295::getRegisterSheet() { } u8 DivPlatformMSM6295::read_byte(u32 address) { - if (adpcmMem==NULL || address>=getSampleMemCapacity(0)) { + if (adpcmMem==NULL) { return 0; } if (isBanked) { if (address<0x400) { - return adpcmMem[(bank[(address>>8)&0x3]<<16)|(address&0x3ff)]; + unsigned int bankedAddress=(bank[(address>>8)&0x3]<<16)|(address&0x3ff); + if (bankedAddress>=getSampleMemCapacity(0)) { + return 0; + } + return adpcmMem[bankedAddress&0xffffff]; } - return adpcmMem[(bank[(address>>16)&0x3]<<16)|(address&0xffff)]; + unsigned int bankedAddress=(bank[(address>>16)&0x3]<<16)|(address&0xffff); + if (bankedAddress>=getSampleMemCapacity(0)) { + return 0; + } + return adpcmMem[bankedAddress&0xffffff]; + } + if (address>=getSampleMemCapacity(0)) { + return 0; } return adpcmMem[address&0x3ffff]; } From eaa943e7240f48177e9284d13cd85ac11b55e6b0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 15 Aug 2024 11:27:30 -0500 Subject: [PATCH 15/37] GUI: parse ROM export requisites --- src/engine/song.h | 2 + src/gui/exportOptions.cpp | 30 ++++++----- src/gui/gui.cpp | 110 +++++++++++++++++++++++++++++++++++--- src/gui/gui.h | 3 ++ src/gui/newSong.cpp | 1 + src/gui/sysManager.cpp | 7 +++ 6 files changed, 133 insertions(+), 20 deletions(-) diff --git a/src/engine/song.h b/src/engine/song.h index 8912ec4a1..5976b904f 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -141,6 +141,8 @@ enum DivSystem { DIV_SYSTEM_5E01, DIV_SYSTEM_BIFURCATOR, DIV_SYSTEM_SID2, + + DIV_SYSTEM_MAX }; enum DivEffectType: unsigned short { diff --git a/src/gui/exportOptions.cpp b/src/gui/exportOptions.cpp index aca5523f0..bb223aac4 100644 --- a/src/gui/exportOptions.cpp +++ b/src/gui/exportOptions.cpp @@ -249,16 +249,18 @@ void FurnaceGUI::drawExportROM(bool onWindow) { for (int i=0; igetROMExportDef((DivROMExportOptions)i); if (newDef!=NULL) { - if (ImGui::Selectable(newDef->name)) { - romTarget=(DivROMExportOptions)i; - romMultiFile=newDef->multiOutput; - romConfig=DivConfig(); - if (newDef->fileExt==NULL) { - romFilterName=""; - romFilterExt=""; - } else { - romFilterName=newDef->fileType; - romFilterExt=newDef->fileExt; + if (romExportAvail[i]) { + if (ImGui::Selectable(newDef->name)) { + romTarget=(DivROMExportOptions)i; + romMultiFile=newDef->multiOutput; + romConfig=DivConfig(); + if (newDef->fileExt==NULL) { + romFilterName=""; + romFilterExt=""; + } else { + romFilterName=newDef->fileType; + romFilterExt=newDef->fileExt; + } } } } @@ -436,9 +438,11 @@ void FurnaceGUI::drawExport() { drawExportVGM(true); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem(_("ROM"))) { - drawExportROM(true); - ImGui::EndTabItem(); + if (romExportExists) { + if (ImGui::BeginTabItem(_("ROM"))) { + drawExportROM(true); + ImGui::EndTabItem(); + } } int numZSMCompat=0; for (int i=0; isong.systemLen; i++) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 45d71e95f..37443c46e 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -752,6 +752,88 @@ void FurnaceGUI::autoDetectSystem() { } } +void FurnaceGUI::updateROMExportAvail() { + unsigned char sysReqCount[DIV_SYSTEM_MAX]; + unsigned char defReqCount[DIV_SYSTEM_MAX]; + + memset(sysReqCount,0,DIV_SYSTEM_MAX); + for (int i=0; isong.systemLen; i++) { + sysReqCount[e->song.system[i]]++; + } + + memset(romExportAvail,0,sizeof(bool)*DIV_ROM_MAX); + romExportExists=false; + + for (int i=0; igetROMExportDef((DivROMExportOptions)i); + if (newDef!=NULL) { + // check for viability + bool viable=true; + + memset(defReqCount,0,DIV_SYSTEM_MAX); + for (DivSystem j: newDef->requisites) { + defReqCount[j]++; + } + + switch (newDef->requisitePolicy) { + case DIV_REQPOL_EXACT: + for (int j=0; jsysReqCount[j]) { + viable=false; + break; + } + } + break; + case DIV_REQPOL_LAX: + viable=false; + for (DivSystem j: newDef->requisites) { + if (defReqCount[j]<=sysReqCount[j]) { + viable=true; + break; + } + } + break; + } + + if (viable) { + romExportAvail[i]=true; + romExportExists=true; + } + } + } + + if (!romExportAvail[romTarget]) { + // find a new one + romTarget=DIV_ROM_ABSTRACT; + for (int i=0; igetROMExportDef((DivROMExportOptions)i); + if (newDef!=NULL) { + if (romExportAvail[i]) { + romTarget=(DivROMExportOptions)i; + romMultiFile=newDef->multiOutput; + romConfig=DivConfig(); + if (newDef->fileExt==NULL) { + romFilterName=""; + romFilterExt=""; + } else { + romFilterName=newDef->fileType; + romFilterExt=newDef->fileExt; + } + break; + } + } + } + } +} + ImVec4 FurnaceGUI::channelColor(int ch) { switch (settings.channelColors) { case 0: @@ -2359,6 +2441,7 @@ int FurnaceGUI::load(String path) { undoHist.clear(); redoHist.clear(); updateWindowTitle(); + updateROMExportAvail(); updateScroll(0); if (!e->getWarnings().empty()) { showWarning(e->getWarnings(),GUI_WARN_GENERIC); @@ -4301,9 +4384,11 @@ bool FurnaceGUI::loop() { drawExportVGM(); ImGui::EndMenu(); } - if (ImGui::BeginMenu(_("export ROM..."))) { - drawExportROM(); - ImGui::EndMenu(); + if (romExportExists) { + if (ImGui::BeginMenu(_("export ROM..."))) { + drawExportROM(); + ImGui::EndMenu(); + } } int numZSMCompat=0; for (int i=0; isong.systemLen; i++) { @@ -4336,9 +4421,11 @@ bool FurnaceGUI::loop() { curExportType=GUI_EXPORT_VGM; displayExport=true; } - if (ImGui::MenuItem(_("export ROM..."))) { - curExportType=GUI_EXPORT_ROM; - displayExport=true; + if (romExportExists) { + if (ImGui::MenuItem(_("export ROM..."))) { + curExportType=GUI_EXPORT_ROM; + displayExport=true; + } } int numZSMCompat=0; for (int i=0; isong.systemLen; i++) { @@ -4387,6 +4474,7 @@ bool FurnaceGUI::loop() { autoDetectSystem(); } updateWindowTitle(); + updateROMExportAvail(); } ImGui::EndMenu(); } @@ -4413,6 +4501,7 @@ bool FurnaceGUI::loop() { autoDetectSystem(); } updateWindowTitle(); + updateROMExportAvail(); } else { showError(fmt::sprintf(_("cannot change chip! (%s)"),e->getLastError())); } @@ -4437,6 +4526,7 @@ bool FurnaceGUI::loop() { autoDetectSystem(); updateWindowTitle(); } + updateROMExportAvail(); } } ImGui::EndMenu(); @@ -5695,6 +5785,7 @@ bool FurnaceGUI::loop() { selEnd=SelectionPoint(); cursor=SelectionPoint(); updateWindowTitle(); + updateROMExportAvail(); } else { ImGui::OpenPopup(_("New Song")); } @@ -6245,6 +6336,7 @@ bool FurnaceGUI::loop() { updateWindowTitle(); MARK_MODIFIED; } + updateROMExportAvail(); ImGui::CloseCurrentPopup(); } ImGui::SameLine(); @@ -7263,6 +7355,7 @@ bool FurnaceGUI::init() { } updateWindowTitle(); + updateROMExportAvail(); logV("max texture size: %dx%d",rend->getMaxTextureWidth(),rend->getMaxTextureHeight()); @@ -8397,7 +8490,8 @@ FurnaceGUI::FurnaceGUI(): romTarget(DIV_ROM_ABSTRACT), romMultiFile(false), romExportSave(false), - pendingExport(NULL) { + pendingExport(NULL), + romExportExists(false) { // value keys valueKeys[SDLK_0]=0; valueKeys[SDLK_1]=1; @@ -8516,6 +8610,8 @@ FurnaceGUI::FurnaceGUI(): // effect sorting memset(effectsShow,1,sizeof(bool)*10); + memset(romExportAvail,0,sizeof(bool)*DIV_ROM_MAX); + strncpy(noteOffLabel,"OFF",32); strncpy(noteRelLabel,"===",32); strncpy(macroRelLabel,"REL",32); diff --git a/src/gui/gui.h b/src/gui/gui.h index 7f0fd18ff..0a4f434f5 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -2683,6 +2683,8 @@ class FurnaceGUI { String romFilterName, romFilterExt; String romExportPath; DivROMExport* pendingExport; + bool romExportAvail[DIV_ROM_MAX]; + bool romExportExists; // user presets window std::vector selectedUserPreset; @@ -2732,6 +2734,7 @@ class FurnaceGUI { bool portSet(String label, unsigned int portSetID, int ins, int outs, int activeIns, int activeOuts, int& clickedPort, std::map& portPos); void updateWindowTitle(); + void updateROMExportAvail(); void autoDetectSystem(); void autoDetectSystemIter(std::vector& category, bool& isMatch, std::map& defCountMap, std::map& defConfMap, std::map& sysCountMap, std::map& sysConfMap); void prepareLayout(); diff --git a/src/gui/newSong.cpp b/src/gui/newSong.cpp index d542188a4..f03715be5 100644 --- a/src/gui/newSong.cpp +++ b/src/gui/newSong.cpp @@ -289,6 +289,7 @@ void FurnaceGUI::drawNewSong() { selEnd=SelectionPoint(); cursor=SelectionPoint(); updateWindowTitle(); + updateROMExportAvail(); ImGui::CloseCurrentPopup(); } diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp index e7a25d67c..b4e08fc36 100644 --- a/src/gui/sysManager.cpp +++ b/src/gui/sysManager.cpp @@ -91,6 +91,11 @@ void FurnaceGUI::drawSysManager() { if (!e->duplicateSystem(i,sysDupCloneChannels,sysDupEnd)) { showError(fmt::sprintf(_("cannot clone chip! (%s)"),e->getLastError())); } else { + if (e->song.autoSystem) { + autoDetectSystem(); + updateWindowTitle(); + } + updateROMExportAvail(); MARK_MODIFIED; } } @@ -105,6 +110,7 @@ void FurnaceGUI::drawSysManager() { autoDetectSystem(); } updateWindowTitle(); + updateROMExportAvail(); } else { showError(fmt::sprintf(_("cannot change chip! (%s)"),e->getLastError())); } @@ -143,6 +149,7 @@ void FurnaceGUI::drawSysManager() { autoDetectSystem(); } updateWindowTitle(); + updateROMExportAvail(); ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); From a9591fae71987fced38681d7a5139298ec48cef8 Mon Sep 17 00:00:00 2001 From: Aleksi Knutsi <53163105+host12prog@users.noreply.github.com> Date: Fri, 16 Aug 2024 03:55:29 +0700 Subject: [PATCH 16/37] AY Timer bug fixes and some QOL improvements (#2073) * Create android.yml * bug fixes part 1 * bollocks number 1 * Update android.yml * why are you crackling you arent supposed to do that * stop crackling please * what a load of * what a load of part 2 * what a load of part 3 * what a load of part 4 * final commit... i hope! * final commit my rear bottom * final commit for real this time * Delete .github/workflows/android.yml * Update sysDef.cpp --- src/engine/platform/ay.cpp | 85 +++++++++++++++++++++++++++----------- src/engine/sysDef.cpp | 1 + src/gui/editControls.cpp | 2 +- src/gui/insEdit.cpp | 4 ++ 4 files changed, 68 insertions(+), 24 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index b073e423e..4e5357722 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -155,43 +155,76 @@ void DivPlatformAY8910::runDAC() { } void DivPlatformAY8910::runTFX() { - if (selCore) return; + /* + developer's note: if you are checking for intellivision + make sure to add "&& selCore" + because for some reason, the register remap doesn't work + when the user uses AtomicSSG core + */ int timerPeriod, output; for (int i=0; i<3; i++) { if (chan[i].active && (chan[i].curPSGMode.val&16) && !(chan[i].curPSGMode.val&8) && chan[i].tfx.mode!=-1) { + if (chan[i].tfx.mode == -1 && !isMuted[i]) { + /* + bug: if in the timer FX macro the user enables + and then disables PWM while there is no volume macro + there is now a random chance that the resulting output + is silent or has volume set incorrectly + i've tried to implement a fix, but it seems to be + ineffective, so... + TODO: actually implement a proper fix + */ + if (intellivision && chan[i].curPSGMode.getEnvelope()) { + immWrite(0x08+i,(chan[i].outVol&0xc)<<2); + continue; + } else { + immWrite(0x08+i,(chan[i].outVol&15)|((chan[i].curPSGMode.getEnvelope())<<2)); + continue; + } + } chan[i].tfx.counter += 1; if (chan[i].tfx.counter >= chan[i].tfx.period && chan[i].tfx.mode == 0) { chan[i].tfx.counter = 0; chan[i].tfx.out ^= 1; - output = MAX(0, ((chan[i].tfx.out) ? (chan[i].outVol&15) : (chan[i].tfx.lowBound-(15-chan[i].outVol)))); - output &= 15; + output = ((chan[i].tfx.out) ? chan[i].outVol : (chan[i].tfx.lowBound-(15-chan[i].outVol))); + // TODO: fix this stupid crackling noise that happens + // everytime the volume changes + output = (output <= 0) ? 0 : output; // underflow + output = (output >= 15) ? 15 : output; // overflow + output &= 15; // i don't know if i need this but i'm too scared to remove it if (!isMuted[i]) { - immWrite(0x08+i,output|(chan[i].curPSGMode.getEnvelope()<<2)); + if (intellivision && selCore) { + immWrite(0x0b+i,(output&0xc)<<2); + } else { + immWrite(0x08+i,output|(chan[i].curPSGMode.getEnvelope()<<2)); + } } } if (chan[i].tfx.counter >= chan[i].tfx.period && chan[i].tfx.mode == 1) { chan[i].tfx.counter = 0; if (!isMuted[i]) { - immWrite(0xd, ayEnvMode); + if (intellivision && selCore) { + immWrite(0xa, ayEnvMode); + } else { + immWrite(0xd, ayEnvMode); + } } } if (chan[i].tfx.counter >= chan[i].tfx.period && chan[i].tfx.mode == 2) { chan[i].tfx.counter = 0; } - if (chan[i].tfx.mode == -1 && !isMuted[i]) { - if (intellivision && chan[i].curPSGMode.getEnvelope()) { - immWrite(0x08+i,(chan[i].outVol&0xc)<<2); - } else { - immWrite(0x08+i,(chan[i].outVol&15)|((chan[i].curPSGMode.getEnvelope())<<2)); - } - } } if (chan[i].tfx.num > 0) { - timerPeriod = chan[i].freq*chan[i].tfx.den/chan[i].tfx.num; - } else { - timerPeriod = chan[i].freq*chan[i].tfx.den; - } + timerPeriod = chan[i].freq*chan[i].tfx.den/chan[i].tfx.num; + } else { + timerPeriod = chan[i].freq*chan[i].tfx.den; + } if (chan[i].tfx.num > 0 && chan[i].tfx.den > 0) chan[i].tfx.period=timerPeriod+chan[i].tfx.offset; + // stupid pitch correction because: + // YM2149 half-clock and Sunsoft 5B: timers run an octave too high + // on AtomicSSG core timers run 2 octaves too high + if (clockSel || sunsoft) chan[i].tfx.period = chan[i].tfx.period * 2; + if (selCore) chan[i].tfx.period = chan[i].tfx.period * 4; } } @@ -388,6 +421,7 @@ void DivPlatformAY8910::tick(bool sysTick) { if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { chan[i].tfx.counter = 0; + chan[i].tfx.out = 0; if (chan[i].nextPSGMode.val&8) { if (dumpWrites) addWrite(0xffff0002+(i<<8),0); if (chan[i].dac.sample<0 || chan[i].dac.sample>=parent->song.sampleLen) { @@ -726,12 +760,10 @@ int DivPlatformAY8910::dispatch(DivCommand c) { break; } case DIV_CMD_STD_NOISE_MODE: - if (c.value&0xf0 && !(chan[c.chan].nextPSGMode.val&8)) { - chan[c.chan].nextPSGMode.val|=16; - chan[c.chan].tfx.mode = (c.value&3); - } if (!(chan[c.chan].nextPSGMode.val&8)) { - if (c.value<16) { + chan[c.chan].nextPSGMode.val|=16; + chan[c.chan].tfx.mode=(((c.value&0xf0)>>4)&3)-1; + if ((c.value&15)<16) { chan[c.chan].nextPSGMode.val=(c.value+1)&7; chan[c.chan].nextPSGMode.val|=chan[c.chan].curPSGMode.val&16; if (chan[c.chan].active) { @@ -805,9 +837,16 @@ int DivPlatformAY8910::dispatch(DivCommand c) { updateOutSel(true); immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); break; - case DIV_CMD_AY_AUTO_PWM: - chan[c.chan].tfx.offset=c.value; + case DIV_CMD_AY_NOISE_MASK_AND: + chan[c.chan].tfx.num=c.value>>4; + chan[c.chan].tfx.den=c.value&15; break; + case DIV_CMD_AY_AUTO_PWM: { + // best way i could find to do signed :/ + signed char signVal=c.value; + chan[c.chan].tfx.offset=signVal; + break; + } case DIV_CMD_SAMPLE_MODE: if (c.value>0) { chan[c.chan].nextPSGMode.val|=8; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 093369fc2..a8e50461e 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -433,6 +433,7 @@ void DivEngine::registerSystems() { {0x25, {DIV_CMD_AY_ENVELOPE_SLIDE, _("25xx: Envelope slide up"), negEffectVal}}, {0x26, {DIV_CMD_AY_ENVELOPE_SLIDE, _("26xx: Envelope slide down")}}, {0x29, {DIV_CMD_AY_AUTO_ENVELOPE, _("29xy: Set auto-envelope (x: numerator; y: denominator)")}}, + {0x2c, {DIV_CMD_AY_AUTO_PWM, _("2Cxx: Set timer period offset (bit 7: sign)")}}, {0x2e, {DIV_CMD_AY_IO_WRITE, _("2Exx: Write to I/O port A"), constVal<0>, effectVal}}, {0x2f, {DIV_CMD_AY_IO_WRITE, _("2Fxx: Write to I/O port B"), constVal<1>, effectVal}}, }; diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 3eba0298c..c492a8e17 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -130,7 +130,7 @@ const bool mobileButtonPersist[32]={ // page 1 false, false, - false, + true, false, true, true, diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index ebef2402d..99dbf26dc 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -7569,6 +7569,10 @@ void FurnaceGUI::drawInsEdit() { macroList.push_back(FurnaceGUIMacroDesc(_("Timer Num"),&ins->std.ex8Macro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("Timer Den"),&ins->std.fmsMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(_("PWM Boundary"),&ins->std.amsMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER])); + // workaround, because the gui will not set + // zoom or scroll if we're not in macros tab + ins->std.ex7Macro.vZoom=128; + ins->std.ex7Macro.vScroll=2048-64; drawMacros(macroList,macroEditStateMacros); ImGui::EndTabItem(); } From faed541abf22a3a68b61f5ac2cb106f148225118 Mon Sep 17 00:00:00 2001 From: MrHassium <165818730+MrHassium@users.noreply.github.com> Date: Thu, 15 Aug 2024 22:56:17 +0200 Subject: [PATCH 17/37] 2 new demo song and a name change (#2058) * Famitune 1 * Ay Mate! * Name Change momento!!!! * I dont know how to replace files so we deleting and putting new versions * Updating a song * die * Updating a song again * comma --- demos/ay8910/AyMate!.fur | Bin 0 -> 877 bytes demos/gameboy/GB_WaitForMe.fur | Bin 1701 -> 1624 bytes demos/msx/OPLL_OperationPleaseLeaveLeave.fur | Bin 1254 -> 1260 bytes demos/nes/Famitune1.fur | Bin 0 -> 16419 bytes src/gui/about.cpp | 3 ++- 5 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 demos/ay8910/AyMate!.fur create mode 100644 demos/nes/Famitune1.fur diff --git a/demos/ay8910/AyMate!.fur b/demos/ay8910/AyMate!.fur new file mode 100644 index 0000000000000000000000000000000000000000..c42647b78e700f1a392ce6256bef4400865515ef GIT binary patch literal 877 zcmV-z1CsoBoV}IHZ&ODU#=n^}zJA*vgk&j;*sNfIO41ETybK{#3b++%Mcs%9lo|wt zke8!iLE{T;CDgKI(^W+!{s5{jx?{<%3zn^P7wsR=Wf9foo4IqzLkW>8h4KAq#%IoV z&Y5$suMduP=Vz`=b?Ucnf7PAt9DE6&j@2>N8vW!a%|#F>VD{8Wlwo#d++LaV@$PYQ zo3V`?FZ6aEJ3E?p>gTU4b{e?YxpsBFbDgF?PD5*DHMV1zs&&vHJP8-P8#(!z^@GO3+Av?(PbYb))aKw6W%Oj@3{ zU-6iqWPJHWeSEevwK(6sRo_1}eE95v4G}o@rN?sG-(y8I5n@P&1SCsxBu@&YNJ^wk zDx^w)i28{7i28{7i28{7i28{7i28{7i28{7i28{7hIi?Jx>|FN zdl_%f?rOQ1&t^nHOzaaYZ4_b^LjCyK=RUf5?hl!}VRM&xm($#pis1k@_F{_|hte1t zzS&#!^V8;Mt*hy?k?o?|mo6;ubF!Y}oUneqz&T<4dWmzw>UtURYBuGvm3KVb10=s* z(9rj+TMsUq>c0xLoud}Vu9U!^J1Oi!`kIkY!kYOx9O&`=)R()`mwSSNP-M{Aiz{NR z$!eS3C(R$M(`7?1~tV=EJ)`M$Hn`FRQ)KlJ?^3_tT3votn!J D=`hH} literal 0 HcmV?d00001 diff --git a/demos/gameboy/GB_WaitForMe.fur b/demos/gameboy/GB_WaitForMe.fur index 5e3c821418d634fa2552367468e33a6ca96c250f..499c627a22710de29bda8675c26c6e3c357e5b05 100644 GIT binary patch literal 1624 zcmV-e2B-OWoW)m7Y*bYgKKH#hKb@J*6c8BGXs3WFq&EI6#Fb8qZK*&(st_WgQ|7g{ zlU7kG`SGLaA`k&0U@?R%YD3yF`?u<`@|rI(f>*!g0jJ#Lz&VI>_m0BPr^U zV*2}$f53Qv`u{%87N!<+6SE7s%Wik>;7IObq13aOyX3laxyoGkAv)_$PAs@nMAv>j zLY5_@ju3&i5MLlsKLb5T)J@s>NXLji1)h%+4FT)G&NiZVfZu_! z1kqQ(V@aZ3;1=))@N$aiGvH6)LOan1z&fx$O|%012As5ZwT717Zi!H1I9( z=uV;q;3uFCjP4@(8aVg}(I9XKNbZ(rEi5|{jm6s%$y9qf6MnZ;=mBieno3Jx*chP{ zUwe^)tjWJlkU&em(kJ+%#&F@Xn;V$D64Jxi7o?jteyj_?0&KtmB0v;~0db%WNB~J7 z1+)WcAOjHj(D$M5L*IwK4}Bl{KJC#F81TthMfe+H3??`l`2kZs*0H~onYAJ8oG1kDokd5Pp$H%5F zUV@2dq=~pP5tnYFu7s_~4}dHSq$H{KTZB1}HaHWUuwG64G>8K)4}+i==+Yi?_SiivH! z*|0I#u(5+n3Qmt1PCqVaYK32(2rlO>3@ygS6H?)&J^flo`QRmv0k|*h<2)=TSsupaLub%aE;L zeiyi^-p&*w zRW|5Bhdo%wqso?~m6BqAgV}NG+59wqm;xrTE&?vErObl@Y4F$5>D%6jRRASvLvbU4G*so(HJxjnjYw3H$90jP<2U?!&B+N4b`|C~mYMvm%7?z9-#uN9*MS?* zxrzBhUP~DpD6j$aD%5Y7%+t5VYbls!=Dn617tCci5hPOG6E<{$4JA2}nh}Zey7j0P zLGzL+*(ygCTqY(x&7|lLuvRm!t@Ngl>PeW`2d4@nH*dHN(|b zH?Ou7j9C+&am9mMZJa3D8dvC~zTQP(90Wn721QYBxo_ca)ocZ79~M{ z=(e@o=E3qu{SrsEB`vpE@ItoQ*2CG#mdl1Nu_0TBu-z@!h%G{9dbhgeHanq+>VJE; zzU4M=iiis#4!*+4rRh;tO*WaFyP&$AF6x9h5i-&@|krYjy+(-qs%bj7wcU9nwF zS8QX`J-`M+O}DEQ&)l2d(07OVTTgbNx5#V3g%Dm3;Y<^q<76LTI#+)>A{P8q;+dMW zgIFP-$J&+OV8IM|5%M{#i}H#EGvt$ym$9Cd;RLf|7!ypgIqChJknzoM%+#D673Vb8 z7l6jBjO}J)wqb0YJ`b|^8h^}6PiA6Zj**6E;J?V47gYYA$zHa+*s_%%Jd*N}!5-V& W3Nahn%Z4n|(7Ki6ApZgi=S{jLlqjYE literal 1701 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 W+N@;DO0tEYsUP~g>ELg1k(l;-X>X+f delta 1247 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 literal 0 HcmV?d00001 diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 13c877186..e3093cde3 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -75,7 +75,7 @@ const char* aboutLine[]={ "Polski: freq-mod, PoznańskiSzybkowiec", "Português (Brasil): Kagamiin~", "Русский: Background2982, LTVA", - "Slovenčina: Mr. Hassium", + "Slovenčina: Wegfrei", "Svenska: RevvoBolt", "ไทย: akumanatt", "", @@ -206,6 +206,7 @@ const char* aboutLine[]={ "Ultraprogramer", "UserSniper", "Weeppiko", + "Wegfrei", "Xan", "Yuzu4K", "Zabir", From c8797927c0bdafd62dfb460488ea4283c403d0c7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 15 Aug 2024 15:56:44 -0500 Subject: [PATCH 18/37] character --- demos/ay8910/{AyMate!.fur => AyMate.fur} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename demos/ay8910/{AyMate!.fur => AyMate.fur} (100%) diff --git a/demos/ay8910/AyMate!.fur b/demos/ay8910/AyMate.fur similarity index 100% rename from demos/ay8910/AyMate!.fur rename to demos/ay8910/AyMate.fur From a701954a6324c35225cf50a5ac88efba5e10ba17 Mon Sep 17 00:00:00 2001 From: asikwus <67226624+asikwus@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:31:18 +0200 Subject: [PATCH 19/37] Added OPM instrument patches --- instruments/OPM/Bowed Lead 1.dmp | Bin 0 -> 51 bytes instruments/OPM/Brass 4.dmp | Bin 0 -> 51 bytes instruments/OPM/Brass 5.dmp | Bin 0 -> 51 bytes instruments/OPM/Brass 6.dmp | Bin 0 -> 51 bytes instruments/OPM/Brass 7.dmp | Bin 0 -> 51 bytes instruments/OPM/Brass 8.dmp | Bin 0 -> 51 bytes instruments/OPM/Dist 2.dmp | Bin 0 -> 51 bytes instruments/OPM/Dist Bass 2.dmp | Bin 0 -> 51 bytes instruments/OPM/Elec Bass 1.dmp | Bin 0 -> 51 bytes instruments/OPM/Electric Piano 2.dmp | Bin 0 -> 51 bytes instruments/OPM/FlangerStrings 1.dmp | Bin 0 -> 51 bytes instruments/OPM/FlangerStrings 2.dmp | Bin 0 -> 51 bytes instruments/OPM/FlangerStrings 3.dmp | Bin 0 -> 51 bytes instruments/OPM/Flute 2.dmp | Bin 0 -> 51 bytes instruments/OPM/Flute.dmp | Bin 0 -> 51 bytes instruments/OPM/HammeredMetalLd1.dmp | Bin 0 -> 51 bytes instruments/OPM/Impact Synth 4.dmp | Bin 0 -> 51 bytes instruments/OPM/Liquid Lead 3.dmp | Bin 0 -> 51 bytes instruments/OPM/Mallet 2.dmp | Bin 0 -> 51 bytes instruments/OPM/Mallet 3.dmp | Bin 0 -> 51 bytes instruments/OPM/Mallet 4.dmp | Bin 0 -> 51 bytes instruments/OPM/Mellow Lead 1.dmp | Bin 0 -> 51 bytes instruments/OPM/Metal Bass 2.dmp | Bin 0 -> 51 bytes instruments/OPM/Metal Bass 4.dmp | Bin 0 -> 51 bytes instruments/OPM/Metal Bass 5.dmp | Bin 0 -> 51 bytes instruments/OPM/Metal Bass 6.dmp | Bin 0 -> 51 bytes instruments/OPM/Mini Acid 1.dmp | Bin 0 -> 51 bytes instruments/OPM/Octave Synth 1.dmp | Bin 0 -> 51 bytes instruments/OPM/Piano Low.dmp | Bin 0 -> 51 bytes instruments/OPM/Plucked 1.dmp | Bin 0 -> 51 bytes instruments/OPM/Plucked 2.dmp | Bin 0 -> 51 bytes instruments/OPM/Plucked 3.dmp | Bin 0 -> 51 bytes instruments/OPM/Slap Bass 1.dmp | Bin 0 -> 51 bytes instruments/OPM/StringEns 3.dmp | Bin 0 -> 51 bytes instruments/OPM/Synth Brass 3.dmp | Bin 0 -> 51 bytes instruments/OPM/Synth Brass 4.dmp | Bin 0 -> 51 bytes instruments/OPM/Synth Brass 5.dmp | Bin 0 -> 51 bytes instruments/OPM/Synth Brass 6.dmp | Bin 0 -> 51 bytes instruments/OPM/Synth Flute.dmp | Bin 0 -> 51 bytes instruments/OPM/Synth Lead 2.dmp | Bin 0 -> 51 bytes instruments/OPM/Synth Lead 3.dmp | Bin 0 -> 51 bytes instruments/OPM/Synth Reed 2.dmp | Bin 0 -> 51 bytes instruments/OPM/Synth Reed 3.dmp | Bin 0 -> 51 bytes instruments/OPM/Synth Reed 4.dmp | Bin 0 -> 51 bytes instruments/OPM/VariBrass 2.dmp | Bin 0 -> 51 bytes 45 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/OPM/Bowed Lead 1.dmp create mode 100644 instruments/OPM/Brass 4.dmp create mode 100644 instruments/OPM/Brass 5.dmp create mode 100644 instruments/OPM/Brass 6.dmp create mode 100644 instruments/OPM/Brass 7.dmp create mode 100644 instruments/OPM/Brass 8.dmp create mode 100644 instruments/OPM/Dist 2.dmp create mode 100644 instruments/OPM/Dist Bass 2.dmp create mode 100644 instruments/OPM/Elec Bass 1.dmp create mode 100644 instruments/OPM/Electric Piano 2.dmp create mode 100644 instruments/OPM/FlangerStrings 1.dmp create mode 100644 instruments/OPM/FlangerStrings 2.dmp create mode 100644 instruments/OPM/FlangerStrings 3.dmp create mode 100644 instruments/OPM/Flute 2.dmp create mode 100644 instruments/OPM/Flute.dmp create mode 100644 instruments/OPM/HammeredMetalLd1.dmp create mode 100644 instruments/OPM/Impact Synth 4.dmp create mode 100644 instruments/OPM/Liquid Lead 3.dmp create mode 100644 instruments/OPM/Mallet 2.dmp create mode 100644 instruments/OPM/Mallet 3.dmp create mode 100644 instruments/OPM/Mallet 4.dmp create mode 100644 instruments/OPM/Mellow Lead 1.dmp create mode 100644 instruments/OPM/Metal Bass 2.dmp create mode 100644 instruments/OPM/Metal Bass 4.dmp create mode 100644 instruments/OPM/Metal Bass 5.dmp create mode 100644 instruments/OPM/Metal Bass 6.dmp create mode 100644 instruments/OPM/Mini Acid 1.dmp create mode 100644 instruments/OPM/Octave Synth 1.dmp create mode 100644 instruments/OPM/Piano Low.dmp create mode 100644 instruments/OPM/Plucked 1.dmp create mode 100644 instruments/OPM/Plucked 2.dmp create mode 100644 instruments/OPM/Plucked 3.dmp create mode 100644 instruments/OPM/Slap Bass 1.dmp create mode 100644 instruments/OPM/StringEns 3.dmp create mode 100644 instruments/OPM/Synth Brass 3.dmp create mode 100644 instruments/OPM/Synth Brass 4.dmp create mode 100644 instruments/OPM/Synth Brass 5.dmp create mode 100644 instruments/OPM/Synth Brass 6.dmp create mode 100644 instruments/OPM/Synth Flute.dmp create mode 100644 instruments/OPM/Synth Lead 2.dmp create mode 100644 instruments/OPM/Synth Lead 3.dmp create mode 100644 instruments/OPM/Synth Reed 2.dmp create mode 100644 instruments/OPM/Synth Reed 3.dmp create mode 100644 instruments/OPM/Synth Reed 4.dmp create mode 100644 instruments/OPM/VariBrass 2.dmp diff --git a/instruments/OPM/Bowed Lead 1.dmp b/instruments/OPM/Bowed Lead 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..5e485475aae0850ac993009a312ef447ae899385 GIT binary patch literal 51 ycmWm2F$w@75Cp;ASrx%RoXFrJ|NqEiv!d1vniyXa8#2jfQxyH$wG!b&t%4sR?g2gk literal 0 HcmV?d00001 diff --git a/instruments/OPM/Brass 4.dmp b/instruments/OPM/Brass 4.dmp new file mode 100644 index 0000000000000000000000000000000000000000..3509dba50c3d5a13258d4390f95fdc206a4d55f7 GIT binary patch literal 51 ycmd<)U}RutVqg;I046m7R{#J2 literal 0 HcmV?d00001 diff --git a/instruments/OPM/Dist Bass 2.dmp b/instruments/OPM/Dist Bass 2.dmp new file mode 100644 index 0000000000000000000000000000000000000000..93a97392c011d2209f1ff6b970f7e202b4ba8deb GIT binary patch literal 51 zcmWm2u?+wq2n4`?6fhbZJ1bUj|LMf;a%&Jq=*bX8GY57C6;kBQUi{0M4zC?}D60X2 literal 0 HcmV?d00001 diff --git a/instruments/OPM/Elec Bass 1.dmp b/instruments/OPM/Elec Bass 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..74357feb702da476de2128843bbe06a93f983f09 GIT binary patch literal 51 ycmXBIF$w@63i+|ImQlFf)v9_{r6T55Z2EXd|$jQS>4+#oq@hHvxtK literal 0 HcmV?d00001 diff --git a/instruments/OPM/Electric Piano 2.dmp b/instruments/OPM/Electric Piano 2.dmp new file mode 100644 index 0000000000000000000000000000000000000000..169689818c5318140456ec16aac7492955de57e5 GIT binary patch literal 51 scmd<)U}RupVPKS%XJchzU|<9yd3jb4lMToek!NNF(oC#yCJQ?Q03+T3Q2+n{ literal 0 HcmV?d00001 diff --git a/instruments/OPM/FlangerStrings 1.dmp b/instruments/OPM/FlangerStrings 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..334caeff2b57052b10bf6f28a1ebaf26046b14ff GIT binary patch literal 51 ycmW;Aw+#Rw3;@BmO_B(%8Gw@g*CTv&`dWk>kvWPu2-xmX9W@B6J(58EUv38@Jpn%e literal 0 HcmV?d00001 diff --git a/instruments/OPM/FlangerStrings 2.dmp b/instruments/OPM/FlangerStrings 2.dmp new file mode 100644 index 0000000000000000000000000000000000000000..7425f9ee688d97b7928546e252c990d81dc583a4 GIT binary patch literal 51 zcmd<)U}RutWnh%x=VRn&U|?imU{>d2W#(sKVrF1qkP!ee8Q6dl!eCJbCI$uoBQ60z literal 0 HcmV?d00001 diff --git a/instruments/OPM/FlangerStrings 3.dmp b/instruments/OPM/FlangerStrings 3.dmp new file mode 100644 index 0000000000000000000000000000000000000000..9becf2f8dc4c5f5220c891c80500b58c397ecd8d GIT binary patch literal 51 tcmd<)U}RutVPF&!Wnf?hBNiP9lYxPOS&pBHiJgIwnSp^(1I%OqG65f10VMzc literal 0 HcmV?d00001 diff --git a/instruments/OPM/Flute 2.dmp b/instruments/OPM/Flute 2.dmp new file mode 100644 index 0000000000000000000000000000000000000000..97a711fd4e2f0f9f16483636ddcca26260c36957 GIT binary patch literal 51 zcmd<)U}RutVBiy!WMTx;j0_A+>Y_~iKqfOQ1EZz{KOY+d6B7{g3p4R?07W?%0450m Aa{vGU literal 0 HcmV?d00001 diff --git a/instruments/OPM/Flute.dmp b/instruments/OPM/Flute.dmp new file mode 100644 index 0000000000000000000000000000000000000000..ade7fa7e5105778da44e49adfad18972d13d38c3 GIT binary patch literal 51 zcmd<)U}RutX5bT)WMX7zU|?imU{V)l;s-LBSs55LCHVO`8JL*Z7?}8lnfO4W91H*^ CzyWvw literal 0 HcmV?d00001 diff --git a/instruments/OPM/HammeredMetalLd1.dmp b/instruments/OPM/HammeredMetalLd1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..172a27fd0262bcb12a342ba833d646c593347859 GIT binary patch literal 51 zcmd<)U}RutU|^OLI|HLIoCyFh2m!SK literal 0 HcmV?d00001 diff --git a/instruments/OPM/Mallet 3.dmp b/instruments/OPM/Mallet 3.dmp new file mode 100644 index 0000000000000000000000000000000000000000..9e55d50bd9f3b7a709726302b6d6d6a6ae15ad12 GIT binary patch literal 51 tcmd<)U}RutXJAy3=V4%BU}E8CVB(kO;pJdpU|?ln1u{XR3`n9(3;-%w0f_(r literal 0 HcmV?d00001 diff --git a/instruments/OPM/Mallet 4.dmp b/instruments/OPM/Mallet 4.dmp new file mode 100644 index 0000000000000000000000000000000000000000..a9576c4ce1248e15d690ab1f39a913c319a1c4b2 GIT binary patch literal 51 ucmd<)U}RupXJ8kV=i_5zU|{BAV3CvO1~Qo#*cljrOh%9>I|HLIoCyFe2LYV` literal 0 HcmV?d00001 diff --git a/instruments/OPM/Mellow Lead 1.dmp b/instruments/OPM/Mellow Lead 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..9adb3ced090251ab1d0720d44fe2537bd16f985a GIT binary patch literal 51 xcmd<)U}RutW?+;NXPU|?ooVBnMI0x}udSQr=#S3;-uz B0dD{R literal 0 HcmV?d00001 diff --git a/instruments/OPM/Plucked 1.dmp b/instruments/OPM/Plucked 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..adbaf68db5c15af62902998e42e0a562db3e90ca GIT binary patch literal 51 vcmd<)U}RutVBl1h=i=vJU}R)qU{sQ4gEE;FA);(RQ9*fmMlJ?MHg*O8E}H?t literal 0 HcmV?d00001 diff --git a/instruments/OPM/Plucked 2.dmp b/instruments/OPM/Plucked 2.dmp new file mode 100644 index 0000000000000000000000000000000000000000..42df0e2fc07bf503bc459c3a3af599bb55daf79f GIT binary patch literal 51 zcmWN{F%AGA2n507PK3n5#vTj*|3=AnlU->DBC326>g<+W;1Kp}Z4<#$83Fe60VwnV AhX4Qo literal 0 HcmV?d00001 diff --git a/instruments/OPM/Plucked 3.dmp b/instruments/OPM/Plucked 3.dmp new file mode 100644 index 0000000000000000000000000000000000000000..368e9b717099ecf7e0568367bef036b79cd34467 GIT binary patch literal 51 zcmW;8(FuSs5JbVZ3YUvQjx^vR_TOWI^EG#h2IFzBKnI+kqw;UO&gv*Y)7G`yST3Id A!vFvP literal 0 HcmV?d00001 diff --git a/instruments/OPM/Slap Bass 1.dmp b/instruments/OPM/Slap Bass 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..95dd31c43e146fa0afc95873a91c2030502ec9bc GIT binary patch literal 51 ucmd<)U}RumW?&VU=jCH%U}9!qV33yQ05XAs3=GQhJTNAYJR2VeSQG##z5#v! literal 0 HcmV?d00001 diff --git a/instruments/OPM/StringEns 3.dmp b/instruments/OPM/StringEns 3.dmp new file mode 100644 index 0000000000000000000000000000000000000000..db134804eecdc205ea8c237b0534e1bbc61a0b1a GIT binary patch literal 51 zcmd<)U}RutVqlb)0{|um0doKV literal 0 HcmV?d00001 diff --git a/instruments/OPM/Synth Brass 6.dmp b/instruments/OPM/Synth Brass 6.dmp new file mode 100644 index 0000000000000000000000000000000000000000..a8baa14736d4698fab95c7288219c707e163e20f GIT binary patch literal 51 tcmd<)U}RutVqlWyXJFxHU}R=xU{;f2;D<7m1;I=fMg}H6uqXqN2>>Sg0eAoa literal 0 HcmV?d00001 diff --git a/instruments/OPM/Synth Flute.dmp b/instruments/OPM/Synth Flute.dmp new file mode 100644 index 0000000000000000000000000000000000000000..a2ee316483e0ef34fd1c6a4053f20f6d86fc0164 GIT binary patch literal 51 xcmd<)U}RurVPNE!E5gXn3lwEx001k60iFN= literal 0 HcmV?d00001 diff --git a/instruments/OPM/Synth Lead 2.dmp b/instruments/OPM/Synth Lead 2.dmp new file mode 100644 index 0000000000000000000000000000000000000000..0248a94e3f2728e620181231fd8c22616a6b1e19 GIT binary patch literal 51 xcmd<)U}RupWZ+bmXJ_YUU}j-tV3L(*VdQ6EU|?lnmV_`_co-P@AWUXf1^_D*0gM0u literal 0 HcmV?d00001 diff --git a/instruments/OPM/Synth Lead 3.dmp b/instruments/OPM/Synth Lead 3.dmp new file mode 100644 index 0000000000000000000000000000000000000000..4a6eacfab775e8ca487f20cec849866e80cad8fd GIT binary patch literal 51 scmd<)U}RupVPN2w7hvXRU|?ZnU{sc8VFWT6SQwauAWRknlbMA904BcyYybcN literal 0 HcmV?d00001 diff --git a/instruments/OPM/Synth Reed 2.dmp b/instruments/OPM/Synth Reed 2.dmp new file mode 100644 index 0000000000000000000000000000000000000000..e2cafd0a29cbdb05bff15ff4b8e5520750301d87 GIT binary patch literal 51 zcmd<)U}RumWMEenW#Z>xU}9!wV3ikOW#V7}vKW}e1y~t57(i?$F)?m_9w3v80RSXs B0bc+B literal 0 HcmV?d00001 diff --git a/instruments/OPM/Synth Reed 3.dmp b/instruments/OPM/Synth Reed 3.dmp new file mode 100644 index 0000000000000000000000000000000000000000..a508ee5d06147d54e097febae5fdb01f67eb04e9 GIT binary patch literal 51 wcmXBGu@L|u2n4}{7l+Zn4x|VBFV29CcBe5#+_IG@0 Date: Tue, 23 Jul 2024 12:48:47 +0200 Subject: [PATCH 20/37] Added OPN instrument patches --- instruments/OPN/bass/A.Bass1.fui | Bin 0 -> 1670 bytes instruments/OPN/bass/A.Bass2a.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/A.Bass2b.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/A.Bass2c.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/Digi.Bass1.fui | Bin 0 -> 1672 bytes instruments/OPN/bass/Digi.Bass2.fui | Bin 0 -> 1672 bytes instruments/OPN/bass/Digi.Bass3.fui | Bin 0 -> 1672 bytes instruments/OPN/bass/E.Bass1a.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass1b.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass1c.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass1d.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass1e.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass2a.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass2b.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass2c.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass3a.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass3b.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass3c.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass3d.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass3e.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass3f.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass3g.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass4a.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass4b.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass4c.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/E.Bass5.fui | Bin 0 -> 1670 bytes instruments/OPN/bass/E.Bass6.fui | Bin 0 -> 1670 bytes instruments/OPN/bass/E.Bass7.fui | Bin 0 -> 1670 bytes instruments/OPN/bass/House Bass 2.fui | Bin 0 -> 1673 bytes instruments/OPN/bass/House Bass.fui | Bin 0 -> 1671 bytes instruments/OPN/bass/Metal Bass 1.dmp | Bin 0 -> 51 bytes instruments/OPN/bass/Metal Bass 3.dmp | Bin 0 -> 51 bytes instruments/OPN/bass/Percussion Bass 2.dmp | Bin 0 -> 51 bytes instruments/OPN/bass/Percussion Bass.dmp | Bin 0 -> 51 bytes instruments/OPN/bass/Slap Bass 2.fui | Bin 0 -> 1672 bytes instruments/OPN/bass/Slap Bass 3.fui | Bin 0 -> 1672 bytes instruments/OPN/bass/Slap Bass 4.fui | Bin 0 -> 1672 bytes 37 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/OPN/bass/A.Bass1.fui create mode 100644 instruments/OPN/bass/A.Bass2a.fui create mode 100644 instruments/OPN/bass/A.Bass2b.fui create mode 100644 instruments/OPN/bass/A.Bass2c.fui create mode 100644 instruments/OPN/bass/Digi.Bass1.fui create mode 100644 instruments/OPN/bass/Digi.Bass2.fui create mode 100644 instruments/OPN/bass/Digi.Bass3.fui create mode 100644 instruments/OPN/bass/E.Bass1a.fui create mode 100644 instruments/OPN/bass/E.Bass1b.fui create mode 100644 instruments/OPN/bass/E.Bass1c.fui create mode 100644 instruments/OPN/bass/E.Bass1d.fui create mode 100644 instruments/OPN/bass/E.Bass1e.fui create mode 100644 instruments/OPN/bass/E.Bass2a.fui create mode 100644 instruments/OPN/bass/E.Bass2b.fui create mode 100644 instruments/OPN/bass/E.Bass2c.fui create mode 100644 instruments/OPN/bass/E.Bass3a.fui create mode 100644 instruments/OPN/bass/E.Bass3b.fui create mode 100644 instruments/OPN/bass/E.Bass3c.fui create mode 100644 instruments/OPN/bass/E.Bass3d.fui create mode 100644 instruments/OPN/bass/E.Bass3e.fui create mode 100644 instruments/OPN/bass/E.Bass3f.fui create mode 100644 instruments/OPN/bass/E.Bass3g.fui create mode 100644 instruments/OPN/bass/E.Bass4a.fui create mode 100644 instruments/OPN/bass/E.Bass4b.fui create mode 100644 instruments/OPN/bass/E.Bass4c.fui create mode 100644 instruments/OPN/bass/E.Bass5.fui create mode 100644 instruments/OPN/bass/E.Bass6.fui create mode 100644 instruments/OPN/bass/E.Bass7.fui create mode 100644 instruments/OPN/bass/House Bass 2.fui create mode 100644 instruments/OPN/bass/House Bass.fui create mode 100644 instruments/OPN/bass/Metal Bass 1.dmp create mode 100644 instruments/OPN/bass/Metal Bass 3.dmp create mode 100644 instruments/OPN/bass/Percussion Bass 2.dmp create mode 100644 instruments/OPN/bass/Percussion Bass.dmp create mode 100644 instruments/OPN/bass/Slap Bass 2.fui create mode 100644 instruments/OPN/bass/Slap Bass 3.fui create mode 100644 instruments/OPN/bass/Slap Bass 4.fui diff --git a/instruments/OPN/bass/A.Bass1.fui b/instruments/OPN/bass/A.Bass1.fui new file mode 100644 index 0000000000000000000000000000000000000000..46604da86cdbaa61f4878e18ce45a738fec3df55 GIT binary patch literal 1670 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l526V_-;OU}SLAQ*cTwE>CZdhdZB8I;GVA zgv^J@kJ^J80)HVi@rB3l52AV_-;OU}SLAQ*cTwE>g@u;ZkH^U}c5rK&9om8Q3^A7#JA2P{m<9c`jyF4ppFjpn=$cJQpJeNQ#*Q zn=AuA1Cs;LWef};X-p;ZKvAN>e*yrTLFigQP9Ybdn?;BZv4=bx37L&9KN9Rh_w#V) z6H2F)`k#>bF!@n?P(uI~F2I7AHGuU1BLhg9L4g?|j)R424Cy=^#u6!vw; literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/A.Bass2b.fui b/instruments/OPN/bass/A.Bass2b.fui new file mode 100644 index 0000000000000000000000000000000000000000..d643c4f0b321c2036475e604f2ec48f51e5b5a2a GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLAQ*cTwE>g@u;ZkH^U}c5rK&9omm{~bgf$~5N*nm7Y0~@CX0|O%$HdzJ+c`il{kXB|6 ztn&N}Ob$SoF))CnF_p*zMTrLg2>@&cp=$v-gw9`bA?WH!3|NU#gt&%>Qh zD4kO3e?sQN60r1NkXOQbN~f{34=fdPbZ F0RTnbFQotg literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/A.Bass2c.fui b/instruments/OPN/bass/A.Bass2c.fui new file mode 100644 index 0000000000000000000000000000000000000000..d2d24b1a98252fce0c13422fe9e0b73b9cb781f5 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLAQ*cTwE>g@u;ZkH^U}c5rK&9om8Q3^A7#JA2P{m<9c`jyF4ppFjpn=$cJQo88NQ#*Q zn=AuA1Cs;LWef};X-p;ZKvAN>e*yrTLFigQP9Ybdn?;BZv4=bx37L&9KN9Rh_w#V) z6H2F)`k#>bF!@n?P(uI~F2I7AHGuU1BLhg9L4g?|j)R424Cy=^#u6!vw;)HVi@rB3l2$OV_-;OU}SK~OwZJFN-Qo`Fl1n6 zXJB9gDU#=BVC9u&U|@#nK%?b3f$|b~K0gDK1JG#<3>;7l zq>z9-5}P3NKLLQv0CX)Nr;rQK%_78y*h8L;gv>^l9|?A$`+2zY38hm?{ZGhznEa?c ws38Cg7hp-u8o+vhkpU#lpn#(UM5qR8EJ^%m! literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/Digi.Bass2.fui b/instruments/OPN/bass/Digi.Bass2.fui new file mode 100644 index 0000000000000000000000000000000000000000..3239f31dd18a918efb3d402a7886c60ad2bee804 GIT binary patch literal 1672 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l2$OV_-;OU}SK~OwZJFN-Qo`Fk)a~ zXJB9gDUxSlWaX7+U}A>pK%?b38CZEG7#Q%#bMdm^lV{}O1)7ONKR*ML1JG#<3>;7l zq>z9-5}P3NKLLQv0CX)Nr;rQK%_78y*h8L;gv>^l9|?A$`+2zY38hm?{ZGhznEa?c ws38Cg7hp-u8o+vhkpU#lpn#(UM5qR)HVi@rB3l2$OV_-;OU}SK~OwZJFN-Qo`FlJz8 zXJB9gDU#>oW#ctwU}A>pK%?b38Q6Hm85nTN^D?sWisF&yWMJn7nu$X{KLe8k&}j?| z98e6TkbpcAn;`Q)0f5Z_bS)sKkPFbwBE*N-L!OO<%tn_V33j3TdARclrBh1%Psn_j z{HQ&sApi>(U`fmxz)HVi@rB3l52AV_-;OU}SLBQ*cTwE>fWE zVc>vbAcX|vk=O*8{|NwW2B2#JIfYz+ZWbXv#2)f&BxE+a{7A41-Ot0FPbi&I>VHD! z!{kTpK@9;|xBv@c)&SN6j0_-Y1_kT|AVM(%SRJZSr16l=BAt!5AmZm|U;trU001x~ BFQEVc literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass1b.fui b/instruments/OPN/bass/E.Bass1b.fui new file mode 100644 index 0000000000000000000000000000000000000000..b008696ae145c11fdb9e440c6295ff15c6564a7c GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>=O)$ZT}^kzg0PpNBi2P&%d5 z|Afqk$&cED8UnCz0T#rp0jviY89>qu3fK!kgklD;I#i=b;~|?xIva06#Lo{btAQ97 F006_IFOL8K literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass1c.fui b/instruments/OPN/bass/E.Bass1c.fui new file mode 100644 index 0000000000000000000000000000000000000000..1a1fa99335bec40f9ad1800901780b6158e677e1 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>fWE zVc>vbAcX|vk=O*8{|NwW2B2#JIfYz+ZWbXv#2)f&BxE+a{7A41-Ot0FPbi&I>VHD! z!{kTpK@9;|xBv@c)&SN6j0_-Y1_kT|AVM(%SRJZSr16l=BAt!5AmZm|U;trU002(Q BFQxzh literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass1d.fui b/instruments/OPN/bass/E.Bass1d.fui new file mode 100644 index 0000000000000000000000000000000000000000..13db5e3af184de28cb9b34076ea1e7c7c601035e GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>_{ zU;(L-7vkh+Qe|LZhG{^f<+&L6nfMqO*}$sNBtiQ5fbs@F1}=G!exP;C*e&2^U~&Mt zg@FT#ffN#uM`9CX{wDyi8Gx<@

rNx>s>;Q}m(Sp!%PFfxFo85FP=fC$A5V0EZQk;X$di*z>Lf{34=fdPbZ0RT30 BFQNbd literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass1e.fui b/instruments/OPN/bass/E.Bass1e.fui new file mode 100644 index 0000000000000000000000000000000000000000..bdfdecbc6e2b944e8addb33926aba7f5ab3ed967 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>TK=ZL%z|X+s z0CEch2NVM-Bp{E(Cdm9x0AMo!T?@!58f?eo-9`1ZX>6B9c z6EYtrKWYzZ2*APxSP-)YupVG!07)|_U@rg>iW$J_P>mvuhin$)HVi@rB3l52AV_-;OU}SLBQ*cTwE>}&&XOd%JVi17oK&54v8Th#+8JL+lP{m<92|h-CCIbd$HXQQuApHzD_46|@ zIRIV8zyQ*YX@opblxXmu0KjGtx)zXA$OY(T5#mGaA zCuBZMe$*b+5P*dXupnj)U_HRd0Fq`)HVi@rB3l52AV_-;OU}SLBQ*cTwE>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>%fm@t`nHgvXHXy;lz`&}&z|4k2UY?18jhg|detrff z2cXLs7=XrrF_1z6@M)cHUrSLfSf`uKsSpJA7T%AHWD%$U4A6kh3@C!&L@;k zDfK@g^I`I%_MnCUEL?yEF>3(p0Y(OpG=l;&LL3JR)fm!wIE*Dy7;izu&(FXB!ngnc DE0iyG literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass3a.fui b/instruments/OPN/bass/E.Bass3a.fui new file mode 100644 index 0000000000000000000000000000000000000000..96f236ccbd249f8a30b9f7f78dcdcab7bbe678f6 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>88>8h~r?P8bdk{hp|Ko<1L8zfn_)d;{pJc Ck1vS; literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass3b.fui b/instruments/OPN/bass/E.Bass3b.fui new file mode 100644 index 0000000000000000000000000000000000000000..fe7e9922f62963158761268481f1b5ed998eb423 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>D=W?%#IY^8>8h~r?P8bdk{hp|Ko<1L8zfn_)d;{pKx CbuXF# literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass3c.fui b/instruments/OPN/bass/E.Bass3c.fui new file mode 100644 index 0000000000000000000000000000000000000000..e1b3feb47c955f630675251151b5c34e420a4036 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>8^l9|?A$`+2zY38hm? z{ZGhznEa?cs38Cg7hplm8o+vhkpU#lpumg}$H781hIAedV~G^TTM&WDa1h1?0HNM5 AwEzGB literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass3d.fui b/instruments/OPN/bass/E.Bass3d.fui new file mode 100644 index 0000000000000000000000000000000000000000..fedfb8431188fe37b83349f5060e13d4107252c5 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>~r3jKV;9payI}o{N>A(HxIFJ0m|o15h4p8-@w|3``C{ zmoYGKKrxU)0`f>~g3SK}05${AwSb&LEc{UO<8(n@R*oE%r;m#+NPAT<2 zA@gDKqxPVN04!X91u<&?>j6dvkTin=GeR5(3)L9Xc{q$EQW$SR1S-Qp7#9Elw5~6> literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass3e.fui b/instruments/OPN/bass/E.Bass3e.fui new file mode 100644 index 0000000000000000000000000000000000000000..64a3c187e6dbb4ac86ffab978c98d2b2145d81c4 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>D=W?%#IY^?l@RzUr@?$gH26;dU^56^3&<(t0(7$o@geq*XCooA(d9>iUFd!u?tDV& zlv4i_G9M;CY7c4%z`_Ms5VHob9$;huNi!%gBgApAP>ms-hr?JRh4B_dpfVg>j^i*4 E0E#a!u>b%7 literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass3f.fui b/instruments/OPN/bass/E.Bass3f.fui new file mode 100644 index 0000000000000000000000000000000000000000..ae876d3a78adaa4d9f92f6fcfa5354a94a50fdd4 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>$8X4pds6lYxOzfPsk(Xa+VQ&&JHaXwJZlTb_|0sE>)21DkFJeg-B7 zpvxE-K+>2>3(p0Y(OpG=l;&LL3JR)fm!wIE*Dy7;izu4=lt%7#9ElLUAv9 literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass3g.fui b/instruments/OPN/bass/E.Bass3g.fui new file mode 100644 index 0000000000000000000000000000000000000000..0bf4008beb723c92b96a415014eaddcf1f5a4c09 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>n zNO^X41|~@c23B^M4pds6lYxOzf`NezXa+VQ&&JNcXpT>wfghxgl>?h@pd6C}&}9q^ zAZbh`@<36d!G8h(n?dMWKu#eSpqoXA53z?l8wr_>E)HVi@rB3l52AV_-;OU}SLBQ*cTwE>h3O=hk6hV&j16K&53^82Fh*7#P@q8n6KwHU@rfB?e|TE^M+43^I(2{7g(h z^I5UV^D{6x0A0qw0J0v_3GzTuqQQRx0GmPRT0l-A7oeL(h!3%cJR1p_jV?bD>_YeR zaOV?Br)HVi@rB3l52AV_-;OU}SLBQ*cTwE>h3O=Qd(sV&j16K&53^82Fh*7#P@q8n6KwHU@rfB?e|TE^M+43^I(2{7g(h z^I5UV^D{6x0A0qw0J0v_3GzTuqQQRx0GmPRT0l-A7oeL(h!3%cJR1p_jV?bD>_YeR zaOV?Brf literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass4c.fui b/instruments/OPN/bass/E.Bass4c.fui new file mode 100644 index 0000000000000000000000000000000000000000..5d093ef605a7047f8adc50dd630b5e9b1603eda8 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}SLBQ*cTwE>h1&_YeR zaOV?Br)HVi@rB3l526V_-;OU}SLBQ*cTwE>CuBZM xe$*b+5P*dXupDL$U_HRd0Fq`)HVi@rB3l526V_-;OU}SLBQ*cTwE>oexSS#0|O&2c}_-tphb+#%rG4& zG(Q8A1JGd%3>;7lq>z9-5}P3NKLLQv0CX)Nr;rQK%_78y*h8L;gv>^l9|?A$`+2zY z38hm?{ZGhznEa?cs38Cg7hpNe8o+vhkpU#lpn$yqL?~tet3x%4G#;{9q_goBMEv{= J3?PgP002m$FIE5m literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/E.Bass7.fui b/instruments/OPN/bass/E.Bass7.fui new file mode 100644 index 0000000000000000000000000000000000000000..a199aa5bd069695ebef6332169c263f5a7842c77 GIT binary patch literal 1670 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l526V_-;OU}SLBQ*cTwE>)HVi@rB3l2$SV_-;OU}W&fFD*`0a7rvLRxn~< zU}s=p0jUz>Vd7^}VPFI*!V2Ws82GuR8JL(kuu3yX2{7`ri38>NvCD(?GvL(E&%opW zbQ=Q$$aqXE3(p0Y(OpG=l;&LL3JR)fm!wIE*Dy7;izu4=mn67#9El6hScE literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/House Bass.fui b/instruments/OPN/bass/House Bass.fui new file mode 100644 index 0000000000000000000000000000000000000000..c9f50c207597507d265ef482bd999d3ddc1e9851 GIT binary patch literal 1671 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l52AV_-;OU}W&fFD*`0a7rvLW?*1v zU|<2M5#wXzXHsBb1S-J_TU}j)oV3e0<1u{W^MOvO4$Yf*zigH6lflL4_z5%8H literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/Metal Bass 3.dmp b/instruments/OPN/bass/Metal Bass 3.dmp new file mode 100644 index 0000000000000000000000000000000000000000..afb3374f6a023814a42b3dbecd08f4ca5a8d5ec7 GIT binary patch literal 51 ocmd;PVq{=vVBnCK7vSe-00RkmPAHQ}MxGnQWC4ov$g@G204&S_r2qf` literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/Percussion Bass 2.dmp b/instruments/OPN/bass/Percussion Bass 2.dmp new file mode 100644 index 0000000000000000000000000000000000000000..1e751ebccc4df320ba021a7e7088d6ba130e3580 GIT binary patch literal 51 rcmd;PVq{=vVBnON=i}#RU}j)oV3d?+1TsN@NlBgq$YcbG^1wv_E3E;Q literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/Percussion Bass.dmp b/instruments/OPN/bass/Percussion Bass.dmp new file mode 100644 index 0000000000000000000000000000000000000000..ff580b77a912212ead7db80983af637c5dc30727 GIT binary patch literal 51 ucmd;PVq{=vW?+$$=jP{UU}j)oV3d$&1TsN@QAl10$Yf*zGI=4QKqdexI{}aY literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/Slap Bass 2.fui b/instruments/OPN/bass/Slap Bass 2.fui new file mode 100644 index 0000000000000000000000000000000000000000..7898c13c15852f5f6978f86d25feada50127e522 GIT binary patch literal 1672 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l2$OV_-;OU}Ol+Ni0xsN-Qo`Fk)b0 zXJB9gDU#=7;ABz+GJpcufIKS$7o!GH251O2Aj;3i#UjMO#D+s&o`;c(6{Hcn`TPt_ z4nU_dFmOOIkU|3TNNj@4{{#Rw1JJdAoI)-@H;WJ-Vh?#X5;7ZIek9n1?&smoCzMVp z^*47}9w-j3rVSZ$ZS*&%gk}xBvh- Cc`!i$ literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/Slap Bass 3.fui b/instruments/OPN/bass/Slap Bass 3.fui new file mode 100644 index 0000000000000000000000000000000000000000..b61505ed7a2e259752c41bf08f4e1e0e8be614c4 GIT binary patch literal 1672 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l2$OV_-;OU}Ol+Ni0xsN-Qo`FlJz4 zXJB9gDU#=7;ABz+GJpcufIKS$7o##z251O2ASS@h#UjSQ#D+s&o|ln}6{Hcn`TPt_ z4nU_dFmOOIkU|3TNNj@4{{#Rw1JJdAoI)-@H;WJ-Vh?#X5;7ZIek9n1?&smoCzMVp z^*47}9w-j3rVSZ$ZS*&%gk}xBviA CAuvS% literal 0 HcmV?d00001 diff --git a/instruments/OPN/bass/Slap Bass 4.fui b/instruments/OPN/bass/Slap Bass 4.fui new file mode 100644 index 0000000000000000000000000000000000000000..937c1e89daac6550f414a6f492efc16ff7185108 GIT binary patch literal 1672 zcmdOOD=o@POioqE%quP_($h_0U|>)HVi@rB3l2$OV_-;OU}Ol+Ni0xsN-Qo`FkxU~ zXJB9gDU#=7=44V}U|<9aU<2~3j9iTBKzX1c*np@2I~R)p0~0QJd0r+iR-i^4=JPW! zIRKr;z`y~;Kne-SBe4lG{}TY%3_#ZcatgTs-7G?Uh&|-lNXTq-`H^53x}S$TpHMob z)c=IchslrHgBk*`Z~>OYtO2YC7#Tp)3<}H$aU3jEV@T)WFqTMRyaf?IKLY~@;{pIu C!7xPt literal 0 HcmV?d00001 From 12a2a881a11af163836b8403a02ddf9d219b949c Mon Sep 17 00:00:00 2001 From: asikwus_henke Date: Tue, 23 Jul 2024 13:41:03 +0200 Subject: [PATCH 21/37] Added more OPN instrument patches --- instruments/OPN/drums/BassD 1.dmp | Bin 0 -> 51 bytes instruments/OPN/drums/Cymbal.fui | Bin 0 -> 1023 bytes instruments/OPN/drums/Kick Drum.fui | Bin 0 -> 1706 bytes instruments/OPN/drums/Snare 4.dmp | Bin 0 -> 51 bytes instruments/OPN/drums/Snare Drum.fui | Bin 0 -> 1683 bytes instruments/OPN/guitar/Synth Guitar.dmp | Bin 0 -> 51 bytes instruments/OPN/horn/Brass Lead 1.fui | Bin 0 -> 48 bytes instruments/OPN/horn/Brass Lead 2.fui | Bin 0 -> 48 bytes instruments/OPN/horn/Brass Synth 1.dmp | Bin 0 -> 51 bytes instruments/OPN/horn/ModBrass 1.dmp | Bin 0 -> 51 bytes instruments/OPN/horn/Sharp Hepta-Brass.dmp | Bin 0 -> 51 bytes instruments/OPN/horn/Sharp Horn.dmp | Bin 0 -> 51 bytes instruments/OPN/horn/Synth Brass 1.dmp | Bin 0 -> 51 bytes instruments/OPN/horn/Synth Brass 2.dmp | Bin 0 -> 51 bytes instruments/OPN/horn/Trumpet 1.fui | Bin 0 -> 1670 bytes instruments/OPN/horn/Trumpet 2.fui | Bin 0 -> 48 bytes instruments/OPN/horn/VariBrass 1.dmp | Bin 0 -> 51 bytes instruments/OPN/keys/Digital Clav 1.fui | Bin 0 -> 48 bytes instruments/OPN/keys/Digital Piano 1.fui | Bin 0 -> 48 bytes instruments/OPN/keys/Digital Piano 2.fui | Bin 0 -> 48 bytes instruments/OPN/keys/Digital Piano 3.fui | Bin 0 -> 48 bytes instruments/OPN/keys/E. Piano 3 (Glassy).dmp | Bin 0 -> 51 bytes instruments/OPN/keys/Organ 2 (Digital).dmp | Bin 0 -> 51 bytes instruments/OPN/keys/Organ 3.fui | Bin 0 -> 48 bytes instruments/OPN/keys/Organ 4.fui | Bin 0 -> 48 bytes instruments/OPN/keys/Soft Organ Lead.dmp | Bin 0 -> 51 bytes instruments/OPN/percussion/Mallet 1.dmp | Bin 0 -> 51 bytes instruments/OPN/synth/Liquid Lead.dmp | Bin 0 -> 51 bytes instruments/OPN/synth/Metal Lead 2.dmp | Bin 0 -> 51 bytes instruments/OPN/synth/Metal Lead 3.dmp | Bin 0 -> 51 bytes instruments/OPN/synth/Metal Lead.dmp | Bin 0 -> 51 bytes instruments/OPN/synth/ResoUnison-Synth 1.dmp | Bin 0 -> 51 bytes instruments/OPN/synth/Saw Lead.fui | Bin 0 -> 48 bytes instruments/OPN/synth/SeqSynth 1.dmp | Bin 0 -> 51 bytes instruments/OPN/synth/Synth Reed 1.dmp | Bin 0 -> 51 bytes instruments/OPN/wind/Clarinet.fui | Bin 0 -> 48 bytes instruments/OPN/wind/Even-Calliope.dmp | Bin 0 -> 51 bytes instruments/OPN/wind/Harmonica 2.fui | Bin 0 -> 48 bytes instruments/OPN/wind/Sax 1.fui | Bin 0 -> 1666 bytes instruments/OPN/wind/Sax 2 (Bari).fui | Bin 0 -> 1673 bytes 40 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 instruments/OPN/drums/BassD 1.dmp create mode 100644 instruments/OPN/drums/Cymbal.fui create mode 100644 instruments/OPN/drums/Kick Drum.fui create mode 100644 instruments/OPN/drums/Snare 4.dmp create mode 100644 instruments/OPN/drums/Snare Drum.fui create mode 100644 instruments/OPN/guitar/Synth Guitar.dmp create mode 100644 instruments/OPN/horn/Brass Lead 1.fui create mode 100644 instruments/OPN/horn/Brass Lead 2.fui create mode 100644 instruments/OPN/horn/Brass Synth 1.dmp create mode 100644 instruments/OPN/horn/ModBrass 1.dmp create mode 100644 instruments/OPN/horn/Sharp Hepta-Brass.dmp create mode 100644 instruments/OPN/horn/Sharp Horn.dmp create mode 100644 instruments/OPN/horn/Synth Brass 1.dmp create mode 100644 instruments/OPN/horn/Synth Brass 2.dmp create mode 100644 instruments/OPN/horn/Trumpet 1.fui create mode 100644 instruments/OPN/horn/Trumpet 2.fui create mode 100644 instruments/OPN/horn/VariBrass 1.dmp create mode 100644 instruments/OPN/keys/Digital Clav 1.fui create mode 100644 instruments/OPN/keys/Digital Piano 1.fui create mode 100644 instruments/OPN/keys/Digital Piano 2.fui create mode 100644 instruments/OPN/keys/Digital Piano 3.fui create mode 100644 instruments/OPN/keys/E. Piano 3 (Glassy).dmp create mode 100644 instruments/OPN/keys/Organ 2 (Digital).dmp create mode 100644 instruments/OPN/keys/Organ 3.fui create mode 100644 instruments/OPN/keys/Organ 4.fui create mode 100644 instruments/OPN/keys/Soft Organ Lead.dmp create mode 100644 instruments/OPN/percussion/Mallet 1.dmp create mode 100644 instruments/OPN/synth/Liquid Lead.dmp create mode 100644 instruments/OPN/synth/Metal Lead 2.dmp create mode 100644 instruments/OPN/synth/Metal Lead 3.dmp create mode 100644 instruments/OPN/synth/Metal Lead.dmp create mode 100644 instruments/OPN/synth/ResoUnison-Synth 1.dmp create mode 100644 instruments/OPN/synth/Saw Lead.fui create mode 100644 instruments/OPN/synth/SeqSynth 1.dmp create mode 100644 instruments/OPN/synth/Synth Reed 1.dmp create mode 100644 instruments/OPN/wind/Clarinet.fui create mode 100644 instruments/OPN/wind/Even-Calliope.dmp create mode 100644 instruments/OPN/wind/Harmonica 2.fui create mode 100644 instruments/OPN/wind/Sax 1.fui create mode 100644 instruments/OPN/wind/Sax 2 (Bari).fui diff --git a/instruments/OPN/drums/BassD 1.dmp b/instruments/OPN/drums/BassD 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..f3e7ea19054ec33cb7713c8ff11ac33afc312881 GIT binary patch literal 51 ycmWm0K@I>A3;@9`r9y&89Gv?9UrOgRBMDUz^Q{YVNAYLTLtcJLbR+m}(a8rWEdibY literal 0 HcmV?d00001 diff --git a/instruments/OPN/drums/Cymbal.fui b/instruments/OPN/drums/Cymbal.fui new file mode 100644 index 0000000000000000000000000000000000000000..475b4f726f2abd8185fa60c291de796ef0e54f58 GIT binary patch literal 1023 zcmdOOD=o@POioqE%quP_($h6%U|>)HVi@rB3l0IXO&J&&oGWva5_1?>*cljDKw|PN zTnvnYAQpBY&%n*VAi}`FhFzLLUVxR8Sqv!2g;7lr0@YI tJd*!`03;8hu>m|)HVi@rB3l3>wV_-;OU}W&lOwLwtDJsonU}0xq zU;!zS7iHw<2XdHU>d|O)HVi@rB3l7OA_)|d7i8dPW(CR%K literal 0 HcmV?d00001 diff --git a/instruments/OPN/guitar/Synth Guitar.dmp b/instruments/OPN/guitar/Synth Guitar.dmp new file mode 100644 index 0000000000000000000000000000000000000000..6f7efa205650d9806aa2433143a2dcb8cb05eb82 GIT binary patch literal 51 wcmd;PVq{=oVqoMIXXoc<009P literal 0 HcmV?d00001 diff --git a/instruments/OPN/horn/Brass Lead 2.fui b/instruments/OPN/horn/Brass Lead 2.fui new file mode 100644 index 0000000000000000000000000000000000000000..817a98893d2beb351c1d65d967d27bdcbf737636 GIT binary patch literal 48 vcmZ?s^b0=8z{ud{tHSWbje&tdKwiMnlz|~pLY~b{l!1YX14v5&`A`}F*X;)v literal 0 HcmV?d00001 diff --git a/instruments/OPN/horn/Brass Synth 1.dmp b/instruments/OPN/horn/Brass Synth 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..3b440a8871bab30a92498fe86c6cca299bb3a2e3 GIT binary patch literal 51 xcmd;PVq{=vVqlcu<74D!U}9!qV3gzqGuapzIIZ~j_@Sag!psc(42%q13;-p00dxQW literal 0 HcmV?d00001 diff --git a/instruments/OPN/horn/ModBrass 1.dmp b/instruments/OPN/horn/ModBrass 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..97f8a0aac6552c564b55922eaa1b6f513b2c4b4c GIT binary patch literal 51 wcmd;PVq{=rWnhsIVC3LrU|{9|Gx<3g7+HZ>MvRf411QSCz$735VggwV03s~`LI3~& literal 0 HcmV?d00001 diff --git a/instruments/OPN/horn/Sharp Hepta-Brass.dmp b/instruments/OPN/horn/Sharp Hepta-Brass.dmp new file mode 100644 index 0000000000000000000000000000000000000000..2599a07dd264fa146923d9c255e74d2ed989d8bf GIT binary patch literal 51 zcmd;PVq{=oW?&Q&km2EAU|?WnV3*}*<^?iYSs56`1sEB)85md?85jjc*+B}J85sZ~ C9RWT7 literal 0 HcmV?d00001 diff --git a/instruments/OPN/horn/Sharp Horn.dmp b/instruments/OPN/horn/Sharp Horn.dmp new file mode 100644 index 0000000000000000000000000000000000000000..ed1d71fb9814ec71ceeacdcd90a9413a2d63a490 GIT binary patch literal 51 zcmd;PVq{=vW?+&OC%WBXa>o literal 0 HcmV?d00001 diff --git a/instruments/OPN/horn/Synth Brass 1.dmp b/instruments/OPN/horn/Synth Brass 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..ceb765fe747b972a2c31b15e4968275acf1856f8 GIT binary patch literal 51 zcmd;PVq{=tVPF&%VdG$9U|{B8V3d+&)HVi@rB3l526V_-;OU}Oj>D$OlOEm1IJU}9%r zU;!!N<74D!6lY*!hN(xRd080wxs7nkgY@%j;FcF=X5_WR0lHa)_z-)@vyqV5=<*}ME_6Q+cRrzXN~!+|nGcg6 vwFfl>VBrERhgkzy4=^%-q!|=&m9PlqsK$`aLzqMk3vWTh4=lt%7#9El=MgXF literal 0 HcmV?d00001 diff --git a/instruments/OPN/horn/Trumpet 2.fui b/instruments/OPN/horn/Trumpet 2.fui new file mode 100644 index 0000000000000000000000000000000000000000..111665d2179608ec5aaf2128b4944fe1604a2d86 GIT binary patch literal 48 xcmZ?s^b0=8z{ud{tHSU_oq@qnqL0r(o`E4zy%$WIYXJHG8GtH+ncevr7ytwL33>nk literal 0 HcmV?d00001 diff --git a/instruments/OPN/horn/VariBrass 1.dmp b/instruments/OPN/horn/VariBrass 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..ef970e6d3fb2fbda9a8e6aae8a1ee22c0251bb4d GIT binary patch literal 51 tcmd;PVq{=vVqlcy)*w0O|k$ literal 0 HcmV?d00001 diff --git a/instruments/OPN/keys/Digital Clav 1.fui b/instruments/OPN/keys/Digital Clav 1.fui new file mode 100644 index 0000000000000000000000000000000000000000..3867cfd1d5d7a2a12dc211d0f73fc87efe0d4a5e GIT binary patch literal 48 zcmZ?s^b0=8z{ud{tHSU_oq-`qBc8)qpMil-Qgz#11q~c2Z#m$D7Xt% literal 0 HcmV?d00001 diff --git a/instruments/OPN/keys/Digital Piano 3.fui b/instruments/OPN/keys/Digital Piano 3.fui new file mode 100644 index 0000000000000000000000000000000000000000..3636a6202ba8e8d46431564f8ca3ea0001e78027 GIT binary patch literal 48 scmZ?s^b0=8z{ud{tHSWbfq{WhS)Kt%F(m0gXhRNpE_V(FhD0b00MoDr=l}o! literal 0 HcmV?d00001 diff --git a/instruments/OPN/keys/E. Piano 3 (Glassy).dmp b/instruments/OPN/keys/E. Piano 3 (Glassy).dmp new file mode 100644 index 0000000000000000000000000000000000000000..a519345adbea5465c296b7f713ddff7b8e77d057 GIT binary patch literal 51 tcmd;PVq{=vVc?UL7hvaLU|?ovV3d$&=La%bc^MdmAxvflIFpru0RSuh0h<5- literal 0 HcmV?d00001 diff --git a/instruments/OPN/keys/Organ 2 (Digital).dmp b/instruments/OPN/keys/Organ 2 (Digital).dmp new file mode 100644 index 0000000000000000000000000000000000000000..47ea44ccae2c2613fe85007d243a1a07f6e97091 GIT binary patch literal 51 xcmXBIyAA*l5Jkar*P~IasD(u7|347XO{SQzh}Hmy1bKJ)Wd`}DAk^931~@1(0gM0u literal 0 HcmV?d00001 diff --git a/instruments/OPN/keys/Organ 3.fui b/instruments/OPN/keys/Organ 3.fui new file mode 100644 index 0000000000000000000000000000000000000000..b952efa902a6e5f62feef148d271110fc13eb942 GIT binary patch literal 48 scmZ?s^b0=8z{ud{tHSWbm4Sg#PM*Pmfq@}e8A3C$18FWGpA$j@0M8u;l>h($ literal 0 HcmV?d00001 diff --git a/instruments/OPN/keys/Organ 4.fui b/instruments/OPN/keys/Organ 4.fui new file mode 100644 index 0000000000000000000000000000000000000000..cdb3c8fa61890ab5bbc1e896d1bd04d4e6a0b4bb GIT binary patch literal 48 ycmZ?s^b0=8z{ud{tHSUloq>T}UY_5>lz}0cONzmPi-CceONz|}NGEd1gZTj4Ne2D^ literal 0 HcmV?d00001 diff --git a/instruments/OPN/keys/Soft Organ Lead.dmp b/instruments/OPN/keys/Soft Organ Lead.dmp new file mode 100644 index 0000000000000000000000000000000000000000..1582e5d7ba2fc3c23f6b741730689a6b0de2b3c1 GIT binary patch literal 51 xcmWm2u@L|u2*ALAqIed17B0a4JBr;WQ-yBS*y00<)9#Tq5X+3D=LP-Ozj!3@0a^e6 literal 0 HcmV?d00001 diff --git a/instruments/OPN/percussion/Mallet 1.dmp b/instruments/OPN/percussion/Mallet 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..c54a1c6baf122b1cb74fc4dae20bc22003b7ebe7 GIT binary patch literal 51 tcmd;PVq{=oW8hblX8-|K1_o{sc^-Z?1_ow!1{Ps?L1riuD$2sn001cX0h9m$ literal 0 HcmV?d00001 diff --git a/instruments/OPN/synth/Liquid Lead.dmp b/instruments/OPN/synth/Liquid Lead.dmp new file mode 100644 index 0000000000000000000000000000000000000000..92b2f1fbdaeea461da7ac5d66d21d8a924ba86e8 GIT binary patch literal 51 vcmd;PVq{=rU|^ILXJX`FU|}eBLQ^) literal 0 HcmV?d00001 diff --git a/instruments/OPN/synth/Metal Lead.dmp b/instruments/OPN/synth/Metal Lead.dmp new file mode 100644 index 0000000000000000000000000000000000000000..716bff888d5e7ab5f809eb9d370d8a5ef3401d8a GIT binary patch literal 51 ycmd;PVq{=vVBk=fXJO)JU|?ooU{sLj;NWLqWCZerFxM6DZ2YzyxIiMFAkA0ZIS> literal 0 HcmV?d00001 diff --git a/instruments/OPN/synth/Saw Lead.fui b/instruments/OPN/synth/Saw Lead.fui new file mode 100644 index 0000000000000000000000000000000000000000..5b2352051eb62312385c53c45679002ba3f32e5b GIT binary patch literal 48 pcmZ?s^b0=8z{ud{tHSUloPohmTAtlepMk-MU7o{L9*O3L@B!T02QL5s literal 0 HcmV?d00001 diff --git a/instruments/OPN/synth/SeqSynth 1.dmp b/instruments/OPN/synth/SeqSynth 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..036bf0ab6b6779b05d0207949b8ce1b8155b79db GIT binary patch literal 51 wcmd;PVq{=pVqoMH=jLZ)00CwdQ67Fy1_nkT5*1?wi83)Tu!@L-MOhda03vt+R{#J2 literal 0 HcmV?d00001 diff --git a/instruments/OPN/synth/Synth Reed 1.dmp b/instruments/OPN/synth/Synth Reed 1.dmp new file mode 100644 index 0000000000000000000000000000000000000000..bdbacbb43b92a48c61bf90e93a691186806d43d5 GIT binary patch literal 51 zcmd;PVq{=oVqjO2W8>!pGI$tR6vY^MSs55uco-P@)HVi@rB3l525V_-;OU}OkRtWYpyU|?rpU;;^t zaBy=n$ulrB!_=bDLM+UjOp*)?ENJ2|t_TAYCxbd}d43K?ZbqPD9Om;gFgXAn#lXM; z#Xt%P$Rn`{GXE0**bG3|0&)tu0NpG?e26{d*+|H2bor5B7rLK^JD*TGrPTj~%!kR3 x+JhPbuy6sE!K?wS2N)SZ(hLeXN)HVi@rB3l2$SV_-;OU}OkRtWYpg&~QpD%G6|F zVPRlk0;v+>Wng1uXJ7(zVA_yq5qSnS25trhRwOZGrjR@fHv Date: Thu, 15 Aug 2024 20:28:40 -0700 Subject: [PATCH 22/37] Satellite Interconnects Demo song - Multi chip (#2065) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * demo pack within packs where packs became packs so packs just * cease esfm demos and replace remaining 'slots' * rrahh * fix loop points + optimize '🌌' * W H A T * Satellite Interconnects - Multi chip * demos/multichip movement verification --- demos/multichip/satellite_interconnects.fur | Bin 0 -> 51305 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/multichip/satellite_interconnects.fur diff --git a/demos/multichip/satellite_interconnects.fur b/demos/multichip/satellite_interconnects.fur new file mode 100644 index 0000000000000000000000000000000000000000..b8516e4a4bb85c0439385aa29c31e45fbfcc6868 GIT binary patch literal 51305 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 G#8A%11t3oV literal 0 HcmV?d00001 From 3b04df7a13c33f12c0212ecb58afca246a600a05 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 16 Aug 2024 04:06:33 -0500 Subject: [PATCH 23/37] update format.md --- papers/format.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/papers/format.md b/papers/format.md index 92f8b0edf..d8e12b7bd 100644 --- a/papers/format.md +++ b/papers/format.md @@ -256,6 +256,8 @@ size | description | - 0xe0: QSound - 19 channels | - 0xe1: PS1 - 24 channels (UNAVAILABLE) | - 0xe2: C64 (6581) with PCM - 4 channels (UNAVAILABLE) + | - 0xe3: Watara Supervision - 4 channels (UNAVAILABLE) + | - 0xe4: µPD1771C - 1 channel (UNAVAILABLE) | - 0xf0: SID2 - 3 channels | - 0xf1: 5E01 - 5 channels | - 0xfc: Pong - 1 channel From 8ad9bfa2456089549724aed31b121f05a36464b5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 16 Aug 2024 23:59:20 -0500 Subject: [PATCH 24/37] fix panbrello depth --- src/engine/playback.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index c61415abd..3b3234934 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1647,26 +1647,34 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { chan[i].panPos+=chan[i].panRate; chan[i].panPos&=255; - // calculate... + // calculate inverted... switch (chan[i].panPos&0xc0) { case 0: // center -> right - chan[i].panL=0xff-((chan[i].panPos&0x3f)<<2); - chan[i].panR=0xff; + chan[i].panL=((chan[i].panPos&0x3f)<<2); + chan[i].panR=0; break; case 0x40: // right -> center - chan[i].panL=(chan[i].panPos&0x3f)<<2; - chan[i].panR=0xff; + chan[i].panL=0xff-((chan[i].panPos&0x3f)<<2); + chan[i].panR=0; break; case 0x80: // center -> left - chan[i].panL=0xff; - chan[i].panR=0xff-((chan[i].panPos&0x3f)<<2); + chan[i].panL=0; + chan[i].panR=((chan[i].panPos&0x3f)<<2); break; case 0xc0: // left -> center - chan[i].panL=0xff; - chan[i].panR=(chan[i].panPos&0x3f)<<2; + chan[i].panL=0; + chan[i].panR=0xff-((chan[i].panPos&0x3f)<<2); break; } + // multiply by depth + chan[i].panL=(chan[i].panL*chan[i].panDepth)/15; + chan[i].panR=(chan[i].panR*chan[i].panDepth)/15; + + // then invert it to get final panning + chan[i].panL^=0xff; + chan[i].panR^=0xff; + dispatchCmd(DivCommand(DIV_CMD_PANNING,i,chan[i].panL,chan[i].panR)); } From 3cde827c17fcb7efa5bef8f93c7745622494f909 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 17 Aug 2024 00:12:02 -0500 Subject: [PATCH 25/37] GUI: localize bitfield labels --- src/gui/plot_nolerp.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/gui/plot_nolerp.cpp b/src/gui/plot_nolerp.cpp index 170fc20d9..aa57f0da7 100644 --- a/src/gui/plot_nolerp.cpp +++ b/src/gui/plot_nolerp.cpp @@ -26,6 +26,8 @@ #include "imgui.h" #include "imgui_internal.h" +#include "../ta-utils.h" + struct FurnacePlotArrayGetterData { const float* Values; @@ -270,12 +272,13 @@ int PlotBitfieldEx(const char* label, int (*values_getter)(void* data, int idx), float lineHeight=ImGui::GetTextLineHeight()/2.0; for (int i=0; i Date: Sat, 17 Aug 2024 13:50:52 -0700 Subject: [PATCH 26/37] Add action to set curIns based on current channel instrument at cursor (#2090) * push test * remove test file * add GUI_ACTION_PAT_ABSORB_INSTRUMENT action (set current instrument to channel's current instrument column) --------- Co-authored-by: Adam Lederer --- src/gui/doAction.cpp | 11 +++++++++++ src/gui/gui.h | 1 + src/gui/guiConst.cpp | 1 + src/gui/settings.cpp | 1 + 4 files changed, 14 insertions(+) diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index fff5a85d9..bf5b89519 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -676,6 +676,17 @@ void FurnaceGUI::doAction(int what) { latchTarget=0; latchNibble=false; break; + case GUI_ACTION_PAT_ABSORB_INSTRUMENT: { + DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],false); + if (!pat) break; + for (int i=cursor.y; i>=0; i--) { + if (pat->data[i][2] >= 0) { + curIns=pat->data[i][2]; + break; + } + } + break; + } case GUI_ACTION_INS_LIST_ADD: if (settings.insTypeMenu) { diff --git a/src/gui/gui.h b/src/gui/gui.h index 0a4f434f5..ae6dde1ef 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -816,6 +816,7 @@ enum FurnaceGUIActions { GUI_ACTION_PAT_LATCH, GUI_ACTION_PAT_SCROLL_MODE, GUI_ACTION_PAT_CLEAR_LATCH, + GUI_ACTION_PAT_ABSORB_INSTRUMENT, GUI_ACTION_PAT_MAX, GUI_ACTION_INS_LIST_MIN, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 09d0fefbb..13e8a9478 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -687,6 +687,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("PAT_LATCH", _N("Set note input latch"), 0), D("PAT_SCROLL_MODE", _N("Change mobile scroll mode"), 0), D("PAT_CLEAR_LATCH", _N("Clear note input latch"), 0), + D("PAT_ABSORB_INSTRUMENT", _N("Set current instrument to channel's current instrument column"), 0), D("PAT_MAX", "", NOT_AN_ACTION), D("INS_LIST_MIN", _N("---Instrument list"), NOT_AN_ACTION), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index b6c244430..8241e9ab1 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2415,6 +2415,7 @@ void FurnaceGUI::drawSettings() { UI_KEYBIND_CONFIG(GUI_ACTION_PAT_EXPAND_SONG); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_LATCH); UI_KEYBIND_CONFIG(GUI_ACTION_PAT_CLEAR_LATCH); + UI_KEYBIND_CONFIG(GUI_ACTION_PAT_ABSORB_INSTRUMENT); KEYBIND_CONFIG_END; ImGui::TreePop(); From 6037adab514ccc2a4f01c64b046caf0b73485956 Mon Sep 17 00:00:00 2001 From: Electric Keet Date: Thu, 25 Jul 2024 20:48:58 -0700 Subject: [PATCH 27/37] General docs updates. New menu items, new options, a whole new user systems feature... --- doc/2-interface/README.md | 21 +-- doc/2-interface/export.md | 51 +++---- doc/2-interface/keyboard.md | 194 ++++++++++++++------------ doc/2-interface/menu-bar.md | 106 +++++++------- doc/2-interface/play-edit-controls.md | 1 + doc/2-interface/settings.md | 74 +++++++--- doc/2-interface/song-info.md | 16 ++- doc/3-pattern/README.md | 4 + doc/6-sample/README.md | 1 + doc/7-systems/gba.md | 10 +- doc/8-advanced/README.md | 37 ++--- doc/8-advanced/channels.md | 5 +- doc/8-advanced/chanosc.md | 1 + doc/8-advanced/chip-manager.md | 2 + doc/8-advanced/user-systems.md | 22 +++ doc/8-advanced/user-systems.png | Bin 0 -> 35024 bytes 16 files changed, 311 insertions(+), 234 deletions(-) create mode 100644 doc/8-advanced/user-systems.md create mode 100644 doc/8-advanced/user-systems.png diff --git a/doc/2-interface/README.md b/doc/2-interface/README.md index aa16af8d4..7d4300adf 100644 --- a/doc/2-interface/README.md +++ b/doc/2-interface/README.md @@ -18,30 +18,31 @@ the default layout of Furnace is depicted below. - [play/edit controls](play-edit-controls.md) - [instrument/wavetable/sample list](asset-list.md) - [song information](song-info.md) -- [effect list window](effect-list-window.md) - [pattern view](../3-pattern/README.md) +- [effect list window](effect-list-window.md) - [instrument editor](../4-instrument/README.md) - [wavetable editor](../5-wave/README.md) - [sample editor](../6-sample/README.md) ## advanced topics -- [mixer](../8-advanced/mixer.md) -- [grooves](../8-advanced/grooves.md) -- [channels](../8-advanced/channels.md) -- [pattern manager](../8-advanced/pat-manager.md) -- [chip manager](../8-advanced/chip-manager.md) -- [compatibility flags](../8-advanced/compat-flags.md) - [song comments](../8-advanced/comments.md) -- [piano/input pad](../8-advanced/piano.md) +- [channels](../8-advanced/channels.md) +- [chip manager](../8-advanced/chip-manager.md) +- [pattern manager](../8-advanced/pat-manager.md) +- [mixer](../8-advanced/mixer.md) +- [compatibility flags](../8-advanced/compat-flags.md) - [oscilloscope](../8-advanced/osc.md) - [oscilloscope (per channel)](../8-advanced/chanosc.md) +- [oscilloscope (X-Y)](../8-advanced/xyosc.md) - [clock](../8-advanced/clock.md) -- [register view](../8-advanced/regview.md) +- [grooves](../8-advanced/grooves.md) - [log viewer](../8-advanced/log-viewer.md) +- [register view](../8-advanced/regview.md) - [statistics](../8-advanced/stats.md) +- [memory composition](../8-advanced/memory-composition.md) ## other topics -- [basic mode](basic-mode.md) +- [piano/input pad](../8-advanced/piano.md) - [settings](settings.md) diff --git a/doc/2-interface/export.md b/doc/2-interface/export.md index 8d6f32074..e924a1717 100644 --- a/doc/2-interface/export.md +++ b/doc/2-interface/export.md @@ -1,26 +1,27 @@ # export -Furnace allows you to export your song in several formats. this section deals with describing the available export options. +Furnace allows you to export your song in several formats. this section deals with describing the available export options within each tab of the export window. -## export audio +## Audio this option allows you to export your song in .wav format. I know I know, no .mp3 or .ogg export yet, but you can use a converter. -there are two parameters: - +- **Export type**: + - **one file**: exports your song to one .wav file. + - **multiple files (one per chip)**: exports the output of each chip to .wav files. + - **multiple files (one per channel)**: exports the output of each channel to .wav files. + - useful for usage with a channel visualizer such as corrscope. +- **Bit depth**: + - **16-bit integer**: the most common type of .wav file, perfect for music playback. + - **32-bit float**: used for advanced audio manipulation. don't select this unless you know what you need it for. +- **Sample rate**: the default is 44100, the most common .wav sample rate. +- **Channels in file**: default is 2 (stereo). Set to 1 for mono. - **Loops**: sets the number of times the song will loop. - does not have effect if the song ends with `FFxx` effect. - **Fade out (seconds)**: sets the fade out time when the song is over. - does not have effect if the song ends with `FFxx` effect. -and three export choices: - -- **one file**: exports your song to one .wav file. -- **multiple files (one per chip)**: exports the output of each chip to .wav files. -- **multiple files (one per channel)**: exports the output of each channel to .wav files. - - useful for usage with a channel visualizer such as corrscope. - -## export VGM +## VGM this option allows exporting to a VGM (Video Game Music) file. these can be played back with VGMPlay (for example). @@ -40,9 +41,6 @@ the following settings exist: - **custom**: allows you to specify how many ticks to add. - `0` is effectively none, disabling loop trail completely. - this option will not appear if the loop modality isn't set to None as there wouldn't be a need to. -- **chips to export**: select which chips are going to be exported. - - due to VGM format limitations, you can only select up to two of each chip type. - - some chips will not be available, either because VGM doesn't support these yet, or because you selected an old format version. - **add pattern change hints**: this option adds a "hint" when a pattern change occurs. only useful if you're a developer. - the format of the "hint" data block that gets written is: `67 66 FE ll ll ll ll 01 oo rr pp pp pp ...` - `ll`: length, a 32-bit little-endian number @@ -51,12 +49,9 @@ the following settings exist: - `pp`: pattern index (one per channel) - **direct stream mode**: this option allows DualPCM to work. don't use this for other chips. - may or may not play well with hardware VGM players. - -click on **click to export** to begin exporting. - -## export text - -this option allows you to export your song as a text file. +- **chips to export**: select which chips are going to be exported. + - due to VGM format limitations, you can only select up to two of each chip type. + - some chips will not be available, either because VGM doesn't support these yet, or because you selected an old format version. ## export ZSM @@ -72,21 +67,21 @@ the following settings are available: - **loop**: enables loop. if disabled, the song won't loop. - **optimize size**: removes unnecessary commands to reduce size. -click on **Begin Export** to... you know. +## export text + +this option allows you to export your song as a text file. ## export command stream -this option exports a binary file which contains a dump of the internal command stream produced when playing the song. +this option exports a binary file in Furnace's own command stream format (FCS) which contains a dump of the internal command stream produced when playing the song. -it's not really useful, unless you're a developer and want to use a command stream dump for some reason (e.g. writing a hardware sound driver). - -- **export**: exports in Furnace's own command stream format (FCS). see `export-tech.md` in `papers/` for details. +it's not really useful, unless you're a developer and want to use a command stream dump for some reason (e.g. writing a hardware sound driver). see `export-tech.md` in `papers/` for details. ## export DMF this option allows you to save your song as a .dmf which can be opened in DefleMask. -the following systems are supported when saving as 1.0/legacy: +the following systems are supported when saving as 1.0/legacy (0.12): - Sega Genesis/Mega Drive (YM2612 + SN76489) - Sega Genesis/Mega Drive (YM2612 + SN76489, extended channel 3) - Sega Master System @@ -97,7 +92,7 @@ the following systems are supported when saving as 1.0/legacy: - Arcade (YM2151 + SegaPCM 5-channel compatibility) - Neo Geo CD (DefleMask 1.0+) -the following systems are supported when saving as 1.1.3+: +the following systems are also supported when saving as 1.1.3+: - Sega Master System (with FM expansion) - NES + Konami VRC7 - Famicom Disk System diff --git a/doc/2-interface/keyboard.md b/doc/2-interface/keyboard.md index 317538567..675ba0b55 100644 --- a/doc/2-interface/keyboard.md +++ b/doc/2-interface/keyboard.md @@ -39,7 +39,7 @@ the keys in the "Global hotkeys" section can be used in any window, although not | Panic | `F12` | | | | | **Window activation** | | -| Find/Replace | Ctrl-F | +| Find/Replace | `Ctrl-F` | | Settings | — | | Song Information | — | | Subsongs | — | @@ -63,16 +63,23 @@ the keys in the "Global hotkeys" section can be used in any window, although not | Piano | — | | Oscilloscope (master) | — | | Oscilloscope (per-channel) | — | +| Oscilloscope (X-Y) | — | | Volume Meter | — | | Clock | — | | Register View | — | | Log Viewer | — | | Statistics | — | +| Memory Composition | — | | Effect List | — | | Debug Menu | `Ctrl-Shift-D` | +| Command Stream Player | — | | About | — | | Collapse/expand current window | — | | Close current window | `Shift-Escape` | +| Command Palette | `Ctrl-P` | +| Recent files (Palette) | — | +| Insstruments (Palette) | — | +| Samples (Palette) | — | | | | | **Note input** | | | _see "note input" section after table_ | | @@ -102,8 +109,8 @@ the keys in the "Global hotkeys" section can be used in any window, although not | Move cursor down by one (override Edit Step) | `Shift-End` | | Move cursor to previous channel | — | | Move cursor to next channel | — | -| Move cursor to next channel (overflow) | — | | Move cursor to previous channel (overflow) | — | +| Move cursor to next channel (overflow) | — | | Move cursor to beginning of pattern | `Home` | | Move cursor to end of pattern | `End` | | Move cursor up (coarse) | `PageUp` | @@ -118,6 +125,10 @@ the keys in the "Global hotkeys" section can be used in any window, although not | Expand selection to end of pattern | — | | Expand selection upwards (coarse) | `Shift-PageUp` | | Expand selection downwards (coarse) | `Shift-PageDown` | +| Move selection up by one | `Alt-Up` | +| Move selection down by one | `Alt-Down` | +| Move selection to previous channel | `Alt-Left` | +| Move selection to next channel | `Alt-Right` | | Delete | `Delete` | | Pull delete | `Backspace` | | Insert | `Insert` | @@ -143,102 +154,103 @@ the keys in the "Global hotkeys" section can be used in any window, although not | Clear note input latch | — | | | | | **Instrument list** | | -| Add | `Insert` | -| Duplicate | `Ctrl-D` | -| Open | — | -| Open (replace current) | — | -| Save | — | -| Save (.dmp) | — | -| Move up | `Shift-Up` | -| Move down | `Shift-Down` | -| Delete | — | -| Edit | `Shift-Return` | -| Cursor up | `Up` | -| Cursor down | `Down` | -| Toggle folders/standard view | `Ctrl-V` | +| Add instrument | `Insert` | +| Duplicate instrument | `Ctrl-D` | +| Open instrument | — | +| Open instrument (replace current) | — | +| Save instrument | — | +| Save instrument (.dmp) | — | +| Move instrument up in list | `Shift-Up` | +| Move instrument down in list | `Shift-Down` | +| Delete instrument | — | +| Edit instrument | `Shift-Return` | +| Instrument cursor up | `Up` | +| Instrument cursor down | `Down` | +| Instruments: toggle folders/standard view | `Ctrl-V` | | | | | **Wavetable list** | | -| Add | `Insert` | -| Duplicate | `Ctrl-D` | -| Open | — | -| Open (replace current) | — | -| Save | — | -| Save (.dmw) | — | -| Save (raw) | — | -| Move up | `Shift-Up` | -| Move down | `Shift-Down` | -| Delete | — | -| Edit | `Shift-Return` | -| Cursor up | `Up` | -| Cursor down | `Down` | -| Toggle folders/standard view | `Ctrl-V` | +| Add wavetable | `Insert` | +| Duplicate wavetable | `Ctrl-D` | +| Open wavetable | — | +| Open wavetable (replace current) | — | +| Save wavetable | — | +| Save wavetable (.dmw) | — | +| Save wavetable (raw) | — | +| Move wavetable up in list | `Shift-Up` | +| Move wavetable down in list | `Shift-Down` | +| Delete wavetable | — | +| Edit wavetable | `Shift-Return` | +| Wavetable cursor up | `Up` | +| Wavetable cursor down | `Down` | +| Wavetables: toggle folders/standard view | `Ctrl-V` | | | | | **Sample list** | | -| Add | `Insert` | -| Duplicate | `Ctrl-D` | -| Create wavetable from selection | `Ctrl-W` | -| Open | — | -| Open (replace current) | — | -| Import raw data | — | -| Import raw data (replace current) | — | -| Save | — | -| Save (raw) | — | -| Move up | `Shift-Up` | -| Move down | `Shift-Down` | -| Delete | — | -| Edit | `Shift-Return` | -| Cursor up | `Up` | -| Cursor down | `Down` | -| Preview | — | -| Stop preview | — | -| Toggle folders/standard view | `Ctrl-V` | +| Add sample | `Insert` | +| Duplicate sample | `Ctrl-D` | +| Sample Editor: Create wavetable from selection | `Ctrl-W` | +| Open sample | — | +| Open sample (replace current) | — | +| Import raw sample data | — | +| Import raw sample data (replace current) | — | +| Save sample | — | +| Save sample (raw) | — | +| Move sample up in list | `Shift-Up` | +| Move sample down in list | `Shift-Down` | +| Delete sample | — | +| Edit sample | `Shift-Return` | +| Sample cursor up | `Up` | +| Sample cursor down | `Down` | +| Sample Preview | — | +| Stop sample preview | — | +| Samples: Toggle folders/standard view | `Ctrl-V` | +| Samples: Make me a drum kit | — | | | | | **Orders** | | | Previous order | `Up` | | Next order | `Down` | -| Cursor left | `Left` | -| Cursor right | `Right` | -| Increase value | — | -| Decrease value | — | -| Switch edit mode | — | -| Toggle alter entire row | `Ctrl-L` | -| Add | `Insert` | -| Duplicate | `Ctrl-D` | -| Deep clone | `Ctrl-Shift-D` | -| Duplicate to end of song | `Ctrl-E` | -| Deep clone to end of song | `Ctrl-Shift-E` | -| Remove | `Delete` | -| Move up | `Shift-Up` | -| Move down | `Shift-Down` | -| Replay | — | +| Order cursor left | `Left` | +| Order cursor right | `Right` | +| Increase order value | — | +| Decrease order value | — | +| Switch order edit mode | — | +| Order: Toggle alter entire row | `Ctrl-L` | +| Add order | `Insert` | +| Duplicate order | `Ctrl-D` | +| Deep clone order | `Ctrl-Shift-D` | +| Copy current order to end of song | `Ctrl-E` | +| Deep clone current order to end of song | `Ctrl-Shift-E` | +| Remove order | `Delete` | +| Move order up | `Shift-Up` | +| Move order down | `Shift-Down` | +| Replay order | — | | | | | **Sample editor** | | -| Edit mode: Select | `Shift-I` | -| Edit mode: Draw | `Shift-D` | -| Cut | `Ctrl-X` | -| Copy | `Ctrl-C` | -| Paste | `Ctrl-V` | -| Paste replace | `Ctrl-Shift-V` | -| Paste mix | `Ctrl-Alt-V` | -| Select all | `Ctrl-A` | -| Resize | `Ctrl-R` | -| Resample | `Ctrl-E` | -| Amplify | `Ctrl-B` | -| Normalize | `Ctrl-N` | -| Fade in | `Ctrl-I` | -| Fade out | `Ctrl-O` | -| Insert silence | `Insert` | -| Apply silence | `Shift-Delete` | -| Delete | `Delete` | -| Trim | `Ctrl-Delete` | -| Reverse | `Ctrl-T` | -| Invert | `Ctrl-Shift-T` | -| Signed/unsigned exchange | `Ctrl-U` | -| Apply filter | `Ctrl-F` | -| Preview sample | — | -| Stop sample preview | — | -| Zoom in | `Ctrl-=` | -| Zoom out | `Ctrl--` | -| Toggle auto-zoom | `Ctrl-0` | -| Create instrument from sample | — | -| Set loop to selection | `Ctrl-L` | +| Sample editor mode: Select | `Shift-I` | +| Sample editor mode: Draw | `Shift-D` | +| Sample editor: Cut | `Ctrl-X` | +| Sample editor: Copy | `Ctrl-C` | +| Sample editor: Paste | `Ctrl-V` | +| Sample editor: Paste replace | `Ctrl-Shift-V` | +| Sample editor: Paste mix | `Ctrl-Alt-V` | +| Sample editor: Select all | `Ctrl-A` | +| Sample editor: Resize | `Ctrl-R` | +| Sample editor: Resample | `Ctrl-E` | +| Sample editor: Amplify | `Ctrl-B` | +| Sample editor: Normalize | `Ctrl-N` | +| Sample editor: Fade in | `Ctrl-I` | +| Sample editor: Fade out | `Ctrl-O` | +| Sample editor: Insert silence | `Insert` | +| Sample editor: Apply silence | `Shift-Delete` | +| Sample editor: Delete | `Delete` | +| Sample editor: Trim | `Ctrl-Delete` | +| Sample editor: Reverse | `Ctrl-T` | +| Sample editor: Invert | `Ctrl-Shift-T` | +| Sample editor: Signed/unsigned exchange | `Ctrl-U` | +| Sample editor: Apply filter | `Ctrl-F` | +| Sample editor: Preview sample | — | +| Sample editor: Stop sample preview | — | +| Sample editor: Zoom in | `Ctrl-=` | +| Sample editor: Zoom out | `Ctrl--` | +| Sample editor: Toggle auto-zoom | `Ctrl-0` | +| Sample editor: Create instrument from sample | — | +| Sample editor: Set loop to selection | `Ctrl-L` | diff --git a/doc/2-interface/menu-bar.md b/doc/2-interface/menu-bar.md index ec3c6b1bf..58d0b4729 100644 --- a/doc/2-interface/menu-bar.md +++ b/doc/2-interface/menu-bar.md @@ -2,24 +2,20 @@ the menu bar allows you to select from five menus: file, edit, settings, window and help. -items in _italic_ don't appear in basic mode and are only available in advanced mode. - ## file -- **new...**: creates a new song. +- **new...**: opens the new song dialog to choose a system. + - click a system name to create a new song with it. + - some systems have several variants and are grouped, indicated by with a triangle to the left of the name. the first click on a group opens it. clicking again on the group name will create a new song with it. - **open...**: opens the file picker, allowing you to select a song to open. - see [file formats](formats.md) for a list of formats Furnace is able to open. - **open recent**: contains a list of the songs you've opened before. - **clear history**: erases the file history. - - **save**: saves the current song. - opens the file picker if this is a new song, or a backup. - **save as...**: opens the file picker, allowing you to save the song under a different name. - -- **export**: allows you to export your song into other formats, such as audio files, VGM and more. see the [export](export.md) page for more information. - +- **export...**: allows you to export your song into other formats, such as audio files, VGM and more. see the [export](export.md) page for more information. - **manage chips**: opens the [Chip Manager](../8-advanced/chip-manager.md) dialog. - - **restore backup**: restores a previously saved backup. - Furnace keeps up to 5 backups of a song. - the backup directory is located in: @@ -28,21 +24,18 @@ items in _italic_ don't appear in basic mode and are only available in advanced - Linux/other: `~/.config/furnace/backups` - this directory grows in size as you use Furnace. remember to delete old backups periodically to save space. - **do NOT rely on the backup system as auto-save!** you should save a restored backup because Furnace will not save backups of backups. - - **exit**: closes Furnace. ## edit - **...**: does nothing except prevent accidental clicks on later menu items if the menu is too tall to fit on the program window. - - **undo**: reverts the last action. - **redo**: repeats what you undid previously. - - **cut**: moves the current selection in the pattern view to clipboard. - **copy**: copies the current selection in the pattern view to clipboard. - **paste**: inserts the clipboard's contents in the cursor position. - you may be able to paste from OpenMPT as well. -- _**paste special...**:_ variants of the paste feature. +- **paste special...**: variants of the paste feature. - **paste mix**: inserts the clipboard's contents in the cursor position, but does not erase the occupied region. - **paste mix (background)**: does the same thing as paste mix, but doesn't alter content which is already there. - **paste with ins (foreground)**: same thing as paste mix, but changes the instrument. @@ -55,81 +48,84 @@ items in _italic_ don't appear in basic mode and are only available in advanced - if the selection is tall, it will select the entire column. - if a column is already selected, it will select the entire channel. - if a channel is already selected, it will select the entire pattern. - -- _**operation mask**:_ toggles which columns will be affected by the listed operations. [more information here.](../8-advanced/opmask.md) -- _**input latch**:_ determines which data are placed along with a note. [more information here.](../8-advanced/inputlatch.md) - +- **operation mask**: toggles which columns will be affected by the listed operations. [more information here.](../8-advanced/opmask.md) +- **input latch**: determines which data are placed along with a note. [more information here.](../8-advanced/inputlatch.md) - **note/octave up/down**: transposes notes in the current selection. - - **values up/down**: changes values in the current selection by ±1 or ±16. - - **transpose**: transpose notes or change values by a specific amount. - - **interpolate**: fills in gaps in the selection by interpolation between values. -- **change instrument**: changes the instrument number in a selection. -- **gradient/fade**: replace the selection with a "gradient" that goes from the beginning of the selection to the end. +- **change instrument...**: changes the instrument number in a selection. +- **gradient/fade...**: replace the selection with a "gradient" that goes from the beginning of the selection to the end. - does not affect the note column. - **Nibble mode**: when enabled, the fade will be per-nibble (0 to F) rather than per-value (00 to FF). - use for effects like `04xy` (vibrato). -- **scale**: scales values in the selection by a specific amount. +- **scale...**: scales values in the selection by a specific amount. - use to change volume in a selection for example. - **randomize**: replaces the selection with random values. - does not affect the note column. + - **Nibble mode**: when enabled, the randomization will be per-nibble (0 to F) rather than per-value (00 to FF). - **invert values**: `00` becomes `FF`, `01` becomes `FE`, `02` becomes `FD` and so on. - - **flip selection**: flips the selection so it is backwards. - **collapse/expand amount**: allows you to specify how much to collapse/expand in the next two menu items. - **collapse**: shrinks the selected contents. - **expand**: expands the selected contents. - - **collapse pattern**: same as collapse, but affects the entire pattern. - **expand pattern**: same as expand, but affects the entire pattern. - - **collapse song**: same as collapse, but affects the entire song. - it also changes speeds and pattern length to compensate. - **expand song**: same as expand, but affects the entire song. - it also changes speeds and pattern length to compensate. - -- _**find/replace**:_ shows [the Find/Replace window](../8-advanced/find-replace.md). - -- **clear**: opens a window that allows you to mass-delete things like songs, unused instruments, and the like. +- **find/replace**: shows [the Find/Replace window](../8-advanced/find-replace.md). +- **clear...**: opens a window that allows you to mass-delete things like songs, unused instruments, and the like. ## settings - **full screen**: expands the Furnace window so it covers your screen. - **lock layout**: prevents you from dragging/resizing docked windows, or docking more. -- **basic mode**: toggles [Basic Mode](basic-mode.md). -- **visualizer**: toggles pattern view particle effects when the song plays. +- **pattern visualizer**: toggles pattern view particle effects when the song plays. - **reset layout**: resets the workspace to its defaults. -- **settings...**: shows the Settings window. these are detailed in [settings.md]. +- **user systems...**: shows the User Systems window. this is detailed in [the User Systems documentation](../8-advanced/user-systems.md). +- **settings...**: shows the Settings window. these are detailed in [the Settings documentation](settings.md). ## window all these menu items show or hide their associated windows. -- [song information](song-info.md) -- [subsongs](song-info.md) -- [speed](song-info.md) -- [instruments](../4-instrument/README.md) -- [wavetables](../5-wave/README.md) -- [samples](../6-sample/README.md) -- [orders](order-list.md) -- [pattern](../3-pattern/README.md) -- _[mixer](../8-advanced/mixer.md)_ -- _[grooves](../8-advanced/grooves.md)_ -- _[channels](../8-advanced/channels.md)_ -- _[pattern manager](../8-advanced/pat-manager.md)_ -- _[chip manager](../8-advanced/chip-manager.md)_ -- _[compatibility flags](../8-advanced/compat-flags.md)_ -- [song comments](../8-advanced/comments.md) - -- [piano](../8-advanced/piano.md) -- [oscilloscope](../8-advanced/osc.md) -- [oscilloscopes (per-channel)](../8-advanced/chanosc.md) -- [clock](../8-advanced/clock.md) -- [register view](../8-advanced/regview.md) -- [log viewer](../8-advanced/log-viewer.md) -- [stats](../8-advanced/stats.md) +- song + - **[song comments](../8-advanced/comments.md)** + - **[song information](song-info.md)** + - **[subsongs](song-info.md)** + - **[channels](../8-advanced/channels.md)** + - **[chip manager](../8-advanced/chip-manager.md)** + - **[orders](order-list.md)** + - **[pattern](../3-pattern/README.md)** + - **[pattern manager](../8-advanced/pat-manager.md)** + - **[mixer](../8-advanced/mixer.md)** + - **[compatibility flags](../8-advanced/compat-flags.md)** +- assets + - **[instruments](../4-instrument/README.md)** + - **[samples](../6-sample/README.md)** + - **[wavetables](../5-wave/README.md)** + - **[instrument editor](../4-instrument/README.md)** + - **[sample editor](../6-sample/README.md)** + - **[wavetable editor](../5-wave/README.md)** +- visualizers + - **[oscilloscope](../8-advanced/osc.md)** + - **[oscilloscope (per-channel)](../8-advanced/chanosc.md)** + - **[oscilloscope (X-Y)](../8-advanced/xyosc.md)** + - volume meter +- tempo + - **[clock](../8-advanced/clock.md)** + - **[grooves](../8-advanced/grooves.md)** + - **[speed](song-info.md)** +- debug + - **[log viewer](../8-advanced/log-viewer.md)** + - **[register view](../8-advanced/regview.md)** + - **[statistics](../8-advanced/stats.md)** + - **[memory composition](../8-advanced/memory-composition.md)** +- **[effect list](../3-pattern/effects.md)** +- **[play/edit controls](play-edit-controls.md)** +- **[piano/input pad](../8-advanced/piano.md)** ## help diff --git a/doc/2-interface/play-edit-controls.md b/doc/2-interface/play-edit-controls.md index d7814ac25..47e4f103b 100644 --- a/doc/2-interface/play-edit-controls.md +++ b/doc/2-interface/play-edit-controls.md @@ -13,6 +13,7 @@ the "Play/Edit Controls" are used to control playback and change parameters of t - **Poly**: turns on polyphony for previewing notes. toggles to **Mono** for monophony (one note at a time only). - **Octave**: sets current input octave. - **Step**: sets edit step. if this is 1, entering a note or effect will move to the next row. if this is a larger number, rows will be skipped. if this is 0, the cursor will stay in place. + - if clicked, Step becomes **Coarse**, which sets the number of rows moved with `PgUp`, `PgDn`, and related movement shortcuts. clicking again will revert it to Step. - **Follow orders**: if on, the selected order in the orders window will follow the song during playback. - **Follow pattern**: if on, the cursor will follow playback and the song will scroll by as it plays. diff --git a/doc/2-interface/settings.md b/doc/2-interface/settings.md index ec61e9371..eadbf55a9 100644 --- a/doc/2-interface/settings.md +++ b/doc/2-interface/settings.md @@ -1,6 +1,6 @@ # settings -the Settings window allows you to change Furnace setting. +the Settings window allows you to change Furnace settings. settings are saved when clicking the **OK** or **Apply** buttons at the bottom of the window. @@ -8,18 +8,23 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o ### Program +- **Language**: select the language used for the interface. some languages are incomplete, and are listed with their approximate completion percentage. - **Render backend**: changing this may help with performace or compatibility issues. the available render backends are: + - SDL Renderer: this was the only available render backend prior to the addition of dedicated OpenGL/DirectX backends in 0.6. default on macOS. + - DirectX 11: works with the majority of graphics chips/cards and is optimized specifically for Windows. + - it is slower than the other backends. + - DirectX 9: use if your hardware is incompatible with DirectX 11. - OpenGL 3.0: works with the majority of graphics chips/cards (from 2010 onwards). default on Linux. - OpenGL 2.0: use if you have a card without OpenGL 3.0 support. - OpenGL 1.1: use if your card doesn't even support OpenGL 2.0. - - DirectX 11: works with the majority of graphics chips/cards and is optimized specifically for Windows. - - SDL Renderer: this was the only available render backend prior to the addition of dedicated OpenGL/DirectX backends in 0.6. default on macOS. - - it is slower than the other backends. - Software: this is a last resort backend which renders the interface in software. very slow! -- **Render driver**: this setting appears when using the SDL Renderer backend. it allows you to select an SDL render driver. +- **Advanced render backend settings**: only applicable with some render backends. + - **Render driver**: this setting only appears when using the SDL Renderer backend. it allows you to select an SDL render driver. + - OpenGL settings: these only appear when using an OpenGL backend, and should only be adjusted if the display is incorrect. - **VSync**: synchronizes rendering to VBlank and eliminates tearing. - **Frame rate limit**: allows you to set a frame rate limit (in frames per second). - only has effect when VSync is off or not available (e.g. software rendering or force-disabled on driver settings). +- **Display render time**: displays frame rate and frame render time at the right side of the menu bar. - **Late render clear**: this option is only useful when using old versions of Mesa drivers. it force-waits for VBlank by clearing after present, reducing latency. - **Power-saving mode**: saves power by lowering the frame rate to 2fps when idle. - may cause issues under Mesa drivers! @@ -49,6 +54,7 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Remember last values** - **Store instrument name in .fui**: when enabled, saving an instrument will store its name. this may increase file size. - **Load instrument name from .fui**: when enabled, loading an instrument will use the stored name (if present). otherwise, it will use the file name. +- **Auto-fill file name when saving**: pre-fill the file name field with an appropriate name when saving or exporting. ### New Song @@ -79,6 +85,11 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **New instruments are blank**: when enabled, adding FM instruments will make them blank (rather than loading the default one). +### Configuration +- **Import**: select an exported `.ini` config file to overwrite current settings. +- **Export**: select an `.ini` file to save current settings. +- **Factory Reset**: resets all settings to default. + ## Audio ### Output @@ -100,9 +111,7 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Sample rate**: audio output rate. - a lower rate decreases quality and isn't really beneficial. - if using PortAudio backend, be careful about this value. -- **Outputs**: number of audio outputs created, up to 16. - - only appears when Backend is JACK. -- **Channels**: mono, stereo or something. +- **Outputs**: number of audio outputs created, up to 16. default is 2 (stereo). - **Buffer size**: size of buffer in both samples and milliseconds. - setting this to a low value may cause stuttering/glitches in playback (known as "underruns" or "xruns"). - setting this to a high value increases latency. @@ -135,6 +144,7 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o ### MIDI input - **MIDI input**: input device. + - **Rescan MIDI devices**: repopulates list with all currently connected MIDI devices. useful if a device is connected while Furnace is running. - **Note input**: enables note input. disable if you intend to use this device only for binding actions. - **Velocity input**: enables velocity input when entering notes in the pattern. - **Map MIDI channels to direct channels**: when enabled, notes from MIDI channels will be mapped to channels rather than the cursor position. @@ -291,6 +301,7 @@ below all the binds, select a key from the dropdown list to add it. it will appe - **Push value when overwriting instead of clearing it**: in the order list and pattern editors, typing into an already-filled value will shift digits instead of starting fresh. for example: - if off: moving the cursor onto the value `A5` and typing a "B" results in `0B`. - if on: moving the cursor onto the value `A5` and typing a "B" results in `5B`. +- **Keyboard note/value input repeat (hold key to input continuously)** - **Effect input behavior:** - **Move down**: after entering an effect (or effect value), the cursor moves down. - **Move to effect value (otherwise move down)**: after entering an effect, the cursor moves to its value. if entering a value, the cursor moves down. @@ -359,11 +370,7 @@ below all the binds, select a key from the dropdown list to add it. it will appe - **Pattern font** font for the pattern view, the order list, and related. - if "Custom...", a file path selector will appear. - **Size**: font size. -- **Display Japanese characters**, **Display Chinese (Simplified) characters**, **Display Chinese (Traditional) characters** and **Display Korean characters**: only toggle these options if you have enough graphics memory. - - these are a temporary solution until dynamic font atlas is implemented in Dear ImGui. - #### FreeType-specific settings - - **Anti-aliased fonts**: when enabled, fonts will be rendered smooth. - **Support bitmap fonts**: this option allows you to enable the loading of bitmap fonts. - be noted that this may force non-bitmap fonts to undesired sizes! @@ -376,6 +383,13 @@ below all the binds, select a key from the dropdown list to add it. it will appe - **Disable**: only rely upon font hinting data. - **Enable**: prefer font hinting data if present. - **Force**: ignore font hinting data. +#### non-specific settings +- **Oversample**: renders the font internally at higher resolution for visual quality. + - higher settings use more video memory. + - for pixel or bitmap fonts, set this to **1x**. +- **Load fallback font**: load an extra font that contains nearly all characters that can be used, in case the selected fonts lack them. uses much video memory +- **Display Japanese characters**, **Display Chinese (Simplified) characters**, **Display Chinese (Traditional) characters** and **Display Korean characters**: only toggle these options if you have enough graphics memory. + - these are a temporary solution until dynamic font atlas is implemented in Dear ImGui. ### Program @@ -386,15 +400,16 @@ below all the binds, select a key from the dropdown list to add it. it will appe - **/path/to/file.fur - Furnace** - **Display system name on title bar** - **Display chip names instead of "multi-system" in title bar** -- **Export options layout:** - - **Sub-menus in File menu**: export options appear in the File menu as sub-menus. - - **Modal window with tabs**: a single "export..." option that opens a dialog with export options. this is the default. - - **Modal windows with options in File menu**: like Sub-menus in File menu, but instead of being sub-menus, selecting one opens a dialog with export settings. - **Status bar:** - **Cursor details** - **File path** - **Cursor details or file path** - **Nothing** +- **Display playback status when playing**: display playback time and current location in the menu bar. +- **Export options layout:** + - **Sub-menus in File menu**: export options appear in the File menu as sub-menus. + - **Modal window with tabs**: a single "export..." option that opens a dialog with export options. this is the default. + - **Modal windows with options in File menu**: like Sub-menus in File menu, but instead of being sub-menus, selecting one opens a dialog with export settings. - **Capitalize menu bar** - **Display add/configure/change/remove chip menus in File menu**: if enabled, the "manage chips" item in the file menu is split into the four listed items for quick access. @@ -532,10 +547,10 @@ below all the binds, select a key from the dropdown list to add it. it will appe - **Rounded window corners** - **Rounded buttons** - **Rounded menu corners** +- **Rounded tabs** +- **Rounded scrollbars** - **Borders around widgets**: draws borders on buttons, checkboxes, text widgets, and the like. - - ## Color ### Color scheme @@ -544,9 +559,28 @@ below all the binds, select a key from the dropdown list to add it. it will appe - **Export** - **Reset defaults** - **Guru mode**: exposes all color options (instead of accent colors). -- **General** +- **Interface** + - **Frame shading**: applies a gradient effect to buttons and input boxes. - **Color scheme type:** - **Dark** - **Light** - - **Frame shading**: applies a gradient effect to buttons and input boxes. + - **Accent colors**: select main interface colors. + - **Primary** + - **Secondary** - several more categories... + +## Backup + +### Configuration + +- **Enable backup system**: turn on automatic backups of the current open file. +- **Interval (in seconds)**: time between automatic backups. +- **Backups per file**: maximum number of backups to store for each file. + +### Backup Management + +- **Purge before**: + - **Go**: purge backups whose filenames precede the selected date. +- total space used by all backups: + - **Refresh**: recalculate space. + - **Delete All**: purge all backups. diff --git a/doc/2-interface/song-info.md b/doc/2-interface/song-info.md index 24a42f95e..1e10663a3 100644 --- a/doc/2-interface/song-info.md +++ b/doc/2-interface/song-info.md @@ -3,11 +3,11 @@ - **Name**: the track's title. - **Author**: the author(s) of this track. - **Album**: the associated album name (or the name of the game the song is from). -- **System**: the game console or computer the track is designed for. this is automatically set when creating a new tune, but in advanced mode, it can be changed to anything one wants. the **Auto** button will provide a guess based on the chips in use. +- **System**: the game console or computer the track is designed for. this is automatically set when creating a new tune, but can be changed to anything. the **Auto** button will provide a guess based on the chips in use. all of this metadata will be included in a VGM export. this isn't the case for an audio export, however. -- _**Tuning (A-4)**_: set tuning based on the note A-4, which should be 440 in most cases. opening an Amiga MOD will set it to 436 for hardware compatibility. available only in advanced mode. +- **Tuning (A-4)**: set tuning based on the note A-4, which should be 440 in most cases. opening an Amiga MOD will set it to 436 for hardware compatibility. ## subsongs @@ -23,16 +23,17 @@ this window allows one to create **subsongs** - multiple individual songs within there are multiple ways to set the tempo of a song. -items in _italic_ don't appear in basic mode and are only available in advanced mode. +**Base Tempo**: tempo in beats per minute (BPM). this is affected by the Highlight settings below. +- clicking the Base Tempo button switches to the more technical Tick Rate. **Tick Rate**: the frequency of ticks per second, thus the rate at which notes and effects are processed. - all values are allowed for all chips, though most chips have hardware limitations that mean they should stay at either 60 (approximately NTSC) or 50 (exactly PAL). -- clicking the Tick Rate button switches to a more traditional **Base Tempo** BPM setting. +- clicking the Tick Rate button switches to the more traditional Base Tempo BPM setting. **Speed**: the number of ticks per row. - clicking the "Speed" button changes to more complex modes covered in the [grooves](../8-advanced/grooves.md) page. -_**Virtual Tempo**:_ Simulates any arbitrary tempo without altering the tick rate. it does this by adding or skipping ticks to approximate the tempo. the two numbers represent a ratio applied to the actual tick rate. example: +**Virtual Tempo**: simulates any arbitrary tempo without altering the tick rate. it does this by adding or skipping ticks to approximate the tempo. the two numbers represent a ratio applied to the actual tick rate. example: - set tick rate to 150 BPM (60 Hz) and speed to 6. - set the first virtual tempo number (numerator) to 200. - set the second virtual tempo number (denominator) to 150. @@ -40,7 +41,8 @@ _**Virtual Tempo**:_ Simulates any arbitrary tempo without altering the tick rat - the ratio doesn't have to match BPM numbers. set the numerator to 4 and the denominator to 5, and the virtual BPM becomes 150 × 4/5 = 120. - another way to accomplish this with more control over the results is to use grooves. see the page on [grooves](../8-advanced/grooves.md) for details. -_**Divider**:_ Changes the effective tick rate. a tick rate of 60Hz and a divisor of 6 will result in ticks lasting a tenth of a second each! +**Divider**: changes the effective tick rate. a tick rate of 60Hz and a divisor of 6 will result in ticks lasting a tenth of a second each! +- to the right, the effective BPM is listed, taking all settings into account. **Highlight**: sets the pattern row highlights: - the first value represents the number of rows per beat. @@ -50,4 +52,4 @@ _**Divider**:_ Changes the effective tick rate. a tick rate of 60Hz and a diviso **Pattern Length**: the length of each pattern in rows. this affects all patterns in the song, and every pattern must be the same length. (Individual patterns can be cut short by `0Bxx`, `0Dxx`, and `FFxx` commands.) -_**Song Length**:_ how many orders are in the order list. decreasing it will hide the orders at the bottom. increasing it will restore those orders; increasing it further will add new orders of all `00` patterns. +**Song Length**: how many orders are in the order list. decreasing it will hide the orders at the bottom. increasing it will restore those orders; increasing it further will add new orders of all `00` patterns. diff --git a/doc/3-pattern/README.md b/doc/3-pattern/README.md index 31713ea64..77060b5f2 100644 --- a/doc/3-pattern/README.md +++ b/doc/3-pattern/README.md @@ -119,6 +119,10 @@ Shift-Up | expand selection upwards Shift-Down | expand selection downwards Shift-Left | expand selection to the left Shift-Right | expand selection to the right +Alt-Up | move selection up by one +Alt-Down | move selection down by one +Alt-Left | move selection to previous channel +Alt-Right | move selection to next channel Backspace | delete note at cursor and/or pull pattern upwards (configurable) Delete | delete selection Insert | create blank row at cursor position and push pattern diff --git a/doc/6-sample/README.md b/doc/6-sample/README.md index 2e870c95d..5ebe571c1 100644 --- a/doc/6-sample/README.md +++ b/doc/6-sample/README.md @@ -89,6 +89,7 @@ in there, you can modify certain data pertaining to your sample, such as the: - **Open**: replaces current sample. - right-clicking brings up a menu: - **import raw...**: brings up a file selector, then presents a dialog to choose the format of the selected file. + - **import raw (replace)...**: same as above, but instead of adding it to the sample list, it replaces the currently selected sample. - **Save**: saves current sample to disk. - right-clicking brings up a menu: - **save raw...**: brings up a file selector, then saves the sample as raw data. diff --git a/doc/7-systems/gba.md b/doc/7-systems/gba.md index 692d8db0d..a0653a5fe 100644 --- a/doc/7-systems/gba.md +++ b/doc/7-systems/gba.md @@ -15,11 +15,11 @@ it features echo and up to 16 voices. - `10xx`: **change wave.** - `11xy`: **configure echo.** - - this effect is kinda odd. this is how it works: - -> How do you echo on GBA -> -> Create an empty instrment and put a very high note of it in channel 1 then do 110x in effect column and set volume column to set feedback and do nothing else on it + - this effect is kinda odd. here's how to use it: + - create an empty instrument and put a very high note of it in channel 1. + - put `110x` in the effect column. + - set volume column to set feedback. + - don't use the channel for anything else. - `12xy`: **toggle invert.** - `x` left channel. diff --git a/doc/8-advanced/README.md b/doc/8-advanced/README.md index 4a9512823..759737e0e 100644 --- a/doc/8-advanced/README.md +++ b/doc/8-advanced/README.md @@ -8,22 +8,27 @@ as listed in the "Edit" menu: as listed in the "Window" menu: -- [mixer](mixer.md) -- [grooves](grooves.md) -- [channel manager](channels.md) -- [pattern manager](pat-manager.md) -- [chip manager](chip-manager.md) -- [compatibility flags](compat-flags.md) -- [song comments](comments.md) - -- [piano](piano.md) -- [oscilloscope](osc.md) -- [oscilloscope (X-Y)](xyosc.md) -- [oscilloscopes (per-channel)](chanosc.md) -- [clock](clock.md) -- [register view](regview.md) -- [log viewer](log-viewer.md) -- [stats](stats.md) +- song + - [song comments](../8-advanced/comments.md) + - [channels](../8-advanced/channels.md) + - [chip manager](../8-advanced/chip-manager.md) + - [pattern manager](../8-advanced/pat-manager.md) + - [mixer](../8-advanced/mixer.md) + - [compatibility flags](../8-advanced/compat-flags.md) +- visualizers + - [oscilloscope](../8-advanced/osc.md) + - [oscilloscope (per-channel)](../8-advanced/chanosc.md) + - [oscilloscope (X-Y)](../8-advanced/xyosc.md) + - volume meter +- tempo + - [clock](../8-advanced/clock.md) + - [grooves](../8-advanced/grooves.md) +- debug + - [log viewer](../8-advanced/log-viewer.md) + - [register view](../8-advanced/regview.md) + - [statistics](../8-advanced/stats.md) + - [memory composition](../8-advanced/memory-composition.md) +- [piano/input pad](../8-advanced/piano.md) other: diff --git a/doc/8-advanced/channels.md b/doc/8-advanced/channels.md index 5b70f00dd..53bc00065 100644 --- a/doc/8-advanced/channels.md +++ b/doc/8-advanced/channels.md @@ -5,8 +5,9 @@ the "Channels" dialog allows manipulation of the song's channels. ![channels dialog](channels.png) each channel has the following options: -- **Visible**: uncheck the box to hide the channel from the pattern view. pattern data will be kept. -- crossed-arrows button: click and drag to rearrange pattern data throughout the song. +- **Pat**: uncheck the box to hide the channel from the pattern view. pattern data will be kept. +- **Osc**: uncheck the box to hide the channel from the per-channel oscilloscope view. +- **Swap**: click and drag to rearrange pattern data throughout the song. - note: this does **not** move channels around! it only moves the channel's pattern data. - **Name**: the name displayed at the top of each channel in the pattern view. - the next setting is "short name", which is displayed in the orders view and/or when a channel is collapsed. diff --git a/doc/8-advanced/chanosc.md b/doc/8-advanced/chanosc.md index 6a2cd27ed..54163dfb3 100644 --- a/doc/8-advanced/chanosc.md +++ b/doc/8-advanced/chanosc.md @@ -14,6 +14,7 @@ right-clicking the view will display the configuration view shown above: - **Mode 2**: bias slightly toward more columns. - **Mode 3**: always more columns than rows. - **Amplitude**: scales amplitude for all oscilloscope views. +- **Line size**: controls line thickness. - **Gradient**: this allows you to use a gradient for determining the waveforms' colors instead of a single color. see the gradient section for more information. - if this option is off, a color selector will be displayed. right-click on it for some options: - select between the square selector and the color wheel selector. diff --git a/doc/8-advanced/chip-manager.md b/doc/8-advanced/chip-manager.md index 41a187fd9..09388e802 100644 --- a/doc/8-advanced/chip-manager.md +++ b/doc/8-advanced/chip-manager.md @@ -8,6 +8,8 @@ the **chip manager** window allows you to manage chips, including adding, changi **Clone channel data**: when cloning chips, also copy patterns, pattern names, channel names and other parameters to the clone. +**Clone at end**: instead of inserting the clone directly after the cloned chip, add it to the end. + to move a chip around, click and drag the ![crossed-arrows](chip-manager-move.png) button to the left. to duplicate a chip, click the **Clone** button. diff --git a/doc/8-advanced/user-systems.md b/doc/8-advanced/user-systems.md new file mode 100644 index 000000000..d60772654 --- /dev/null +++ b/doc/8-advanced/user-systems.md @@ -0,0 +1,22 @@ +# user systems + +combinations of chips and chip configurations can be stored as **user systems** – presets that are easily accessed when starting a new song. + +![user systems window](user-systems.png) + +the `+` button at the top of the **Systems** list will add a new system. + +next to the **Name** field, the **Remove** button removes the current system from the list. + +chip configuration is exactly as in the [chip manager](chip-manager.md) window. + +the **Advanced** field stores additional settings that are set when a new song is started. these are listed in "option=value" format, one per line. +- `tickRate`: sets tick rate. + +**Save and Close**: as it says. + +**Import**: opens a dialog to select a `.cfgu` file, then adds its systems to the list. + +**Import (replace)**: opens a similar dialog, then clears the existing systems list and replaces it with the imported one. + +**Export**: stores the current list of systems in a selected `.cfgu` file. \ No newline at end of file diff --git a/doc/8-advanced/user-systems.png b/doc/8-advanced/user-systems.png new file mode 100644 index 0000000000000000000000000000000000000000..c300530a3178e4d451ba5ad1b614103f3bb5e5dd GIT binary patch literal 35024 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⁢3y(mHZo$4Y@dIx6aVcNiXlh#z0s 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 Date: Fri, 26 Jul 2024 11:12:30 -0700 Subject: [PATCH 28/37] Minor docs tweaks and fixes. --- doc/2-interface/export.md | 8 ++++---- doc/2-interface/settings.md | 15 +++++++++------ doc/2-interface/song-info.md | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/doc/2-interface/export.md b/doc/2-interface/export.md index e924a1717..4009df9d8 100644 --- a/doc/2-interface/export.md +++ b/doc/2-interface/export.md @@ -53,7 +53,7 @@ the following settings exist: - due to VGM format limitations, you can only select up to two of each chip type. - some chips will not be available, either because VGM doesn't support these yet, or because you selected an old format version. -## export ZSM +## ZSM ZSM (ZSound Music) is a format designed for the Commander X16 to allow hardware playback. it may contain data for either YM2151 or VERA chips. @@ -67,17 +67,17 @@ the following settings are available: - **loop**: enables loop. if disabled, the song won't loop. - **optimize size**: removes unnecessary commands to reduce size. -## export text +## Text this option allows you to export your song as a text file. -## export command stream +## Command Stream this option exports a binary file in Furnace's own command stream format (FCS) which contains a dump of the internal command stream produced when playing the song. it's not really useful, unless you're a developer and want to use a command stream dump for some reason (e.g. writing a hardware sound driver). see `export-tech.md` in `papers/` for details. -## export DMF +## DMF this option allows you to save your song as a .dmf which can be opened in DefleMask. diff --git a/doc/2-interface/settings.md b/doc/2-interface/settings.md index eadbf55a9..cfe12c949 100644 --- a/doc/2-interface/settings.md +++ b/doc/2-interface/settings.md @@ -2,7 +2,8 @@ the Settings window allows you to change Furnace settings. -settings are saved when clicking the **OK** or **Apply** buttons at the bottom of the window. +settings are saved when clicking the **OK** or **Apply** buttons at the bottom of the window, and when closing the program. several backups are kept in the Furnace settings directory. + ## General @@ -11,8 +12,8 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Language**: select the language used for the interface. some languages are incomplete, and are listed with their approximate completion percentage. - **Render backend**: changing this may help with performace or compatibility issues. the available render backends are: - SDL Renderer: this was the only available render backend prior to the addition of dedicated OpenGL/DirectX backends in 0.6. default on macOS. - - DirectX 11: works with the majority of graphics chips/cards and is optimized specifically for Windows. - it is slower than the other backends. + - DirectX 11: works with the majority of graphics chips/cards and is optimized specifically for Windows. - DirectX 9: use if your hardware is incompatible with DirectX 11. - OpenGL 3.0: works with the majority of graphics chips/cards (from 2010 onwards). default on Linux. - OpenGL 2.0: use if you have a card without OpenGL 3.0 support. @@ -54,7 +55,9 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Remember last values** - **Store instrument name in .fui**: when enabled, saving an instrument will store its name. this may increase file size. - **Load instrument name from .fui**: when enabled, loading an instrument will use the stored name (if present). otherwise, it will use the file name. -- **Auto-fill file name when saving**: pre-fill the file name field with an appropriate name when saving or exporting. +- **Auto-fill file name when saving**: pre-fill the file name field when saving or exporting. + - when saving a module, the existing file name will be auto-filled. + - when saving an instrument or sample, its name will be auto-filled. ### New Song @@ -88,7 +91,7 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o ### Configuration - **Import**: select an exported `.ini` config file to overwrite current settings. - **Export**: select an `.ini` file to save current settings. -- **Factory Reset**: resets all settings to default. +- **Factory Reset**: resets all settings to default and purges settings backups. ## Audio @@ -575,12 +578,12 @@ below all the binds, select a key from the dropdown list to add it. it will appe - **Enable backup system**: turn on automatic backups of the current open file. - **Interval (in seconds)**: time between automatic backups. -- **Backups per file**: maximum number of backups to store for each file. +- **Backups per file**: maximum number of backups to store for each file. oldest backups are deleted first. ### Backup Management - **Purge before**: - - **Go**: purge backups whose filenames precede the selected date. + - **Go**: purge all backups from before the selected date. - total space used by all backups: - **Refresh**: recalculate space. - **Delete All**: purge all backups. diff --git a/doc/2-interface/song-info.md b/doc/2-interface/song-info.md index 1e10663a3..f9773807c 100644 --- a/doc/2-interface/song-info.md +++ b/doc/2-interface/song-info.md @@ -3,7 +3,7 @@ - **Name**: the track's title. - **Author**: the author(s) of this track. - **Album**: the associated album name (or the name of the game the song is from). -- **System**: the game console or computer the track is designed for. this is automatically set when creating a new tune, but can be changed to anything. the **Auto** button will provide a guess based on the chips in use. +- **System**: the name of the game console or computer the track is designed for. this is automatically set when creating a new tune, but can be changed to anything. the **Auto** button will provide a guess based on the chips in use. all of this metadata will be included in a VGM export. this isn't the case for an audio export, however. From 0d5ff1d30ef4d13fc62a1dd00a5b9f7e26a082ee Mon Sep 17 00:00:00 2001 From: Electric Keet Date: Fri, 26 Jul 2024 18:39:14 -0700 Subject: [PATCH 29/37] More tweaks to export.md. --- doc/2-interface/export.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/2-interface/export.md b/doc/2-interface/export.md index 4009df9d8..2b68a0a9a 100644 --- a/doc/2-interface/export.md +++ b/doc/2-interface/export.md @@ -1,8 +1,8 @@ # export -Furnace allows you to export your song in several formats. this section deals with describing the available export options within each tab of the export window. +Furnace allows you to export your song in several formats. this section deals with describing the available export options. -## Audio +## audio this option allows you to export your song in .wav format. I know I know, no .mp3 or .ogg export yet, but you can use a converter. @@ -11,10 +11,11 @@ this option allows you to export your song in .wav format. I know I know, no .mp - **multiple files (one per chip)**: exports the output of each chip to .wav files. - **multiple files (one per channel)**: exports the output of each channel to .wav files. - useful for usage with a channel visualizer such as corrscope. -- **Bit depth**: - - **16-bit integer**: the most common type of .wav file, perfect for music playback. - - **32-bit float**: used for advanced audio manipulation. don't select this unless you know what you need it for. -- **Sample rate**: the default is 44100, the most common .wav sample rate. +- **Bit depth**: default is 16-bit integer. +- **Sample rate**: affects the quality of the output file. + - default is 44100, "CD quality". + - lower sample rates lose fidelity as upper frequencies disappear. + - higher sample rates gain frequencies that can't be heard at the cost of file size and rendering time. - **Channels in file**: default is 2 (stereo). Set to 1 for mono. - **Loops**: sets the number of times the song will loop. - does not have effect if the song ends with `FFxx` effect. @@ -67,11 +68,11 @@ the following settings are available: - **loop**: enables loop. if disabled, the song won't loop. - **optimize size**: removes unnecessary commands to reduce size. -## Text +## text this option allows you to export your song as a text file. -## Command Stream +## command stream this option exports a binary file in Furnace's own command stream format (FCS) which contains a dump of the internal command stream produced when playing the song. From db058444b9ff0f1a7a78901f6aab3d0b34ef16ab Mon Sep 17 00:00:00 2001 From: Electric Keet Date: Sat, 3 Aug 2024 12:27:09 -0700 Subject: [PATCH 30/37] Tightening up some text. --- doc/2-interface/menu-bar.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/2-interface/menu-bar.md b/doc/2-interface/menu-bar.md index 58d0b4729..fff10825b 100644 --- a/doc/2-interface/menu-bar.md +++ b/doc/2-interface/menu-bar.md @@ -6,7 +6,7 @@ the menu bar allows you to select from five menus: file, edit, settings, window - **new...**: opens the new song dialog to choose a system. - click a system name to create a new song with it. - - some systems have several variants and are grouped, indicated by with a triangle to the left of the name. the first click on a group opens it. clicking again on the group name will create a new song with it. + - some systems have several variants, which are inside a group. - **open...**: opens the file picker, allowing you to select a song to open. - see [file formats](formats.md) for a list of formats Furnace is able to open. - **open recent**: contains a list of the songs you've opened before. From ee1cfd9e837eeabf8880916907671f93219aa623 Mon Sep 17 00:00:00 2001 From: Electric Keet Date: Wed, 7 Aug 2024 21:47:37 -0700 Subject: [PATCH 31/37] SNES docs update. --- doc/7-systems/snes.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/7-systems/snes.md b/doc/7-systems/snes.md index 7b39ed87f..978af2106 100644 --- a/doc/7-systems/snes.md +++ b/doc/7-systems/snes.md @@ -59,7 +59,7 @@ Furnace also allows the SNES to use wavetables (and the wavetable synthesizer) i - `00` to `7F` for 0 to 127. - `80` to `FF` for -128 to -1. - note: be sure the sum of all coefficients is between -128 and 127. sums outside that may result in overflow and therefore clicking. - - see [SnesLab](https://sneslab.net/wiki/FIR_Filter) for a full explanation and examples. + - see SnesLab for [echo filter explanations and examples](https://sneslab.net/wiki/FIR_Filter#Uses). ## info @@ -67,6 +67,8 @@ this chip uses the [SNES](../4-instrument/snes.md) instrument editor. when two channels are joined for pitch modulation, the channel bar will show `mod` on a bracket tying them together. +when using sample offset commands, be sure to open each involved sample in the sample editor, look to the "Info" section at the top-left, and check the "no BRR filters" box. this prevents sound glitches, at the cost of lowering the sample quality to 4-bit. + ## channel status the following icons are displayed when channel status is enabled in the pattern view: @@ -93,6 +95,8 @@ the following options are available in the Chip Manager window: - **Feedback**: sets how much of the echo output will be fed back into the buffer. - **Echo volume**: sets echo volume. - **Echo filter**: adjusts echo filter. +- **Dec/Hex**: toggles decimal or hexadecimal mode for the filter settings text entry box to the right. + - SnesLab provides [echo filter explanations and examples](https://sneslab.net/wiki/FIR_Filter#Uses). their example filter strings can be pasted directly into the filter settings text entry box if set to Hex mode. ## ADSR From 41e094d79d12b30e2bb50bbe1c2789e4b93c7b23 Mon Sep 17 00:00:00 2001 From: LTVA1 <87536432+LTVA1@users.noreply.github.com> Date: Tue, 13 Aug 2024 20:50:29 +0300 Subject: [PATCH 32/37] OPL3, hide unused channels --- src/engine/fileOps/s3m.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/engine/fileOps/s3m.cpp b/src/engine/fileOps/s3m.cpp index d13c1c7c2..ea8d2d58e 100644 --- a/src/engine/fileOps/s3m.cpp +++ b/src/engine/fileOps/s3m.cpp @@ -287,7 +287,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { if (hasFM && hasPCM) break; } - int pcmChan=hasFM?9:0; + int pcmChan=hasFM?18:0; int fmChan=hasPCM?32:0; int invalidChan=40; @@ -312,6 +312,20 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { ds.subsong[0]->chanShow[i]=false; ds.subsong[0]->chanShowChanOsc[i]=false; } + + if (hasFM) { + for (int i=0; i<18; i++) { + ds.subsong[0]->chanShow[i]=false; + ds.subsong[0]->chanShowChanOsc[i]=false; + } + } + } + + if (hasFM) { + for (int i=(hasPCM?32:0) + 9; i<(hasPCM?32:0) + 18; i++) { + ds.subsong[0]->chanShow[i]=false; + ds.subsong[0]->chanShowChanOsc[i]=false; + } } logV("numChans: %d",numChans); @@ -327,7 +341,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { ds.systemLen++; } if (hasFM) { - ds.system[ds.systemLen]=DIV_SYSTEM_OPL2; + ds.system[ds.systemLen]=DIV_SYSTEM_OPL3; ds.systemVol[ds.systemLen]=1.0f; ds.systemPan[ds.systemLen]=0; ds.systemLen++; From 5770f381ba3f0a1b79e8580235048597dd3ca14a Mon Sep 17 00:00:00 2001 From: LTVA1 <87536432+LTVA1@users.noreply.github.com> Date: Wed, 14 Aug 2024 18:40:17 +0300 Subject: [PATCH 33/37] setting to choose between OPL2 and OPL3, channel naming --- src/engine/engine.h | 4 +- src/engine/fileOps/fileOpsCommon.cpp | 4 +- src/engine/fileOps/s3m.cpp | 78 ++++++++++++++++++---------- src/gui/gui.cpp | 4 +- src/gui/gui.h | 2 + src/gui/settings.cpp | 12 +++++ 6 files changed, 72 insertions(+), 32 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index f010d7001..4364adf13 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -597,7 +597,7 @@ class DivEngine { bool loadDMF(unsigned char* file, size_t len); bool loadFur(unsigned char* file, size_t len, int variantID=0); bool loadMod(unsigned char* file, size_t len); - bool loadS3M(unsigned char* file, size_t len); + bool loadS3M(unsigned char* file, size_t len, bool opl2=false); bool loadXM(unsigned char* file, size_t len); bool loadIT(unsigned char* file, size_t len); bool loadFTM(unsigned char* file, size_t len, bool dnft, bool dnftSig, bool eft); @@ -689,7 +689,7 @@ class DivEngine { void createNew(const char* description, String sysName, bool inBase64=true); void createNewFromDefaults(); // load a file. - bool load(unsigned char* f, size_t length, const char* nameHint=NULL); + bool load(unsigned char* f, size_t length, const char* nameHint=NULL, bool s3mOPL2=false); // play a binary command stream. bool playStream(unsigned char* f, size_t length); // get the playing stream. diff --git a/src/engine/fileOps/fileOpsCommon.cpp b/src/engine/fileOps/fileOpsCommon.cpp index 1a2f36319..78bf00b41 100644 --- a/src/engine/fileOps/fileOpsCommon.cpp +++ b/src/engine/fileOps/fileOpsCommon.cpp @@ -19,7 +19,7 @@ #include "fileOpsCommon.h" -bool DivEngine::load(unsigned char* f, size_t slen, const char* nameHint) { +bool DivEngine::load(unsigned char* f, size_t slen, const char* nameHint, bool s3mOPL2) { unsigned char* file; size_t len; if (slen<21) { @@ -158,7 +158,7 @@ bool DivEngine::load(unsigned char* f, size_t slen, const char* nameHint) { return loadIT(file,len); } else if (len>=48) { if (memcmp(&file[0x2c],DIV_S3M_MAGIC,4)==0) { - return loadS3M(file,len); + return loadS3M(file,len,s3mOPL2); } else if (memcmp(file,DIV_XM_MAGIC,17)==0) { return loadXM(file,len); } diff --git a/src/engine/fileOps/s3m.cpp b/src/engine/fileOps/s3m.cpp index ea8d2d58e..5974f2f11 100644 --- a/src/engine/fileOps/s3m.cpp +++ b/src/engine/fileOps/s3m.cpp @@ -48,7 +48,7 @@ static void readSbiOpData(sbi_t& sbi, SafeReader& reader) { sbi.FeedConnect = reader.readC(); } -bool DivEngine::loadS3M(unsigned char* file, size_t len) { +bool DivEngine::loadS3M(unsigned char* file, size_t len, bool opl2) { struct InvalidHeaderException {}; bool success=false; char magic[4]={0,0,0,0}; @@ -273,11 +273,16 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { bool hasPCM=false; bool hasFM=false; int numChans=0; + int realNumChans=0; - for (int i=0; i<32; i++) { - if (chanSettings[i]==255) continue; - if ((chanSettings[i]&127)>=32) continue; - if ((chanSettings[i]&127)>=16) { + for (int ch=0; ch<32; ch++) { + if (chanSettings[ch]!=255) realNumChans++; + } + + for (int ch=0; ch<32; ch++) { + if (chanSettings[ch]==255) continue; + if ((chanSettings[ch]&127)>=32) continue; + if ((chanSettings[ch]&127)>=16) { hasFM=true; } else { hasPCM=true; @@ -287,48 +292,69 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { if (hasFM && hasPCM) break; } - int pcmChan=hasFM?18:0; + int pcmChan=hasFM?(opl2 ? 9 : 18):0; int fmChan=hasPCM?32:0; int invalidChan=40; - for (int i=0; i<32; i++) { - if (chanSettings[i]==255) { - chanMap[i]=invalidChan++; + for (int ch=0; ch<32; ch++) { + if (chanSettings[ch]==255) { + chanMap[ch]=invalidChan++; continue; } - if ((chanSettings[i]&127)>=32) { - chanMap[i]=invalidChan++; + if ((chanSettings[ch]&127)>=32) { + chanMap[ch]=invalidChan++; continue; } - if ((chanSettings[i]&127)>=16) { - chanMap[i]=fmChan++; + if ((chanSettings[ch]&127)>=16) { + chanMap[ch]=fmChan++; } else { - chanMap[i]=pcmChan++; + chanMap[ch]=pcmChan++; } } + char buffer[40]; + int chanIndex = 1; + if (hasPCM) { - for (int i=pcmChan; i<32; i++) { - ds.subsong[0]->chanShow[i]=false; - ds.subsong[0]->chanShowChanOsc[i]=false; + for(int ch = 0; ch < pcmChan - (realNumChans - (hasFM ? 9 : 0)); ch++) + { + ds.subsong[0]->chanShow[ch]=false; + ds.subsong[0]->chanShowChanOsc[ch]=false; } - if (hasFM) { - for (int i=0; i<18; i++) { - ds.subsong[0]->chanShow[i]=false; - ds.subsong[0]->chanShowChanOsc[i]=false; + for (int ch=pcmChan; ch<32; ch++) { + ds.subsong[0]->chanShow[ch]=false; + ds.subsong[0]->chanShowChanOsc[ch]=false; + } + + for(int ch = 0; ch < 32; ch++) + { + if(ds.subsong[0]->chanShow[ch]) + { + snprintf(buffer, 40, _("Channel %d"), chanIndex); + ds.subsong[0]->chanName[ch] = buffer; + chanIndex++; } } } - if (hasFM) { - for (int i=(hasPCM?32:0) + 9; i<(hasPCM?32:0) + 18; i++) { - ds.subsong[0]->chanShow[i]=false; - ds.subsong[0]->chanShowChanOsc[i]=false; + if (hasFM && !opl2) { + for (int ch=(hasPCM?32:0) + 9; ch<(hasPCM?32:0) + 18; ch++) { + ds.subsong[0]->chanShow[ch]=false; + ds.subsong[0]->chanShowChanOsc[ch]=false; + } + + chanIndex = 1; + + for (int ch=(hasPCM?32:0); ch<(hasPCM?32:0) + 9; ch++) { + snprintf(buffer, 40, _("FM %d"), chanIndex); + ds.subsong[0]->chanName[ch] = buffer; + chanIndex++; } } logV("numChans: %d",numChans); + logV("realNumChans: %d",realNumChans); ds.systemName="PC"; if (hasPCM) { @@ -341,7 +367,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { ds.systemLen++; } if (hasFM) { - ds.system[ds.systemLen]=DIV_SYSTEM_OPL3; + ds.system[ds.systemLen]=opl2 ? DIV_SYSTEM_OPL2 : DIV_SYSTEM_OPL3; ds.systemVol[ds.systemLen]=1.0f; ds.systemPan[ds.systemLen]=0; ds.systemLen++; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 37443c46e..0ce0a69fa 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2417,7 +2417,7 @@ int FurnaceGUI::load(String path) { return 1; } fclose(f); - if (!e->load(file,(size_t)len,path.c_str())) { + if (!e->load(file,(size_t)len,path.c_str(),settings.OPL2s3mImport)) { lastError=e->getLastError(); logE("could not open file!"); return 1; @@ -4110,7 +4110,7 @@ bool FurnaceGUI::loop() { if (!tutorial.introPlayed || settings.alwaysPlayIntro==3 || (settings.alwaysPlayIntro==2 && curFileName.empty())) { unsigned char* introTemp=new unsigned char[intro_fur_len]; memcpy(introTemp,intro_fur,intro_fur_len); - e->load(introTemp,intro_fur_len); + e->load(introTemp,intro_fur_len,NULL,settings.OPL2s3mImport); } } diff --git a/src/gui/gui.h b/src/gui/gui.h index ae6dde1ef..b4b134be9 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1958,6 +1958,7 @@ class FurnaceGUI { unsigned int maxUndoSteps; float vibrationStrength; int vibrationLength; + bool OPL2s3mImport; String mainFontPath; String headFontPath; String patFontPath; @@ -2214,6 +2215,7 @@ class FurnaceGUI { maxUndoSteps(100), vibrationStrength(0.5f), vibrationLength(20), + OPL2s3mImport(false), mainFontPath(""), headFontPath(""), patFontPath(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 8241e9ab1..5a125d0f8 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1254,6 +1254,14 @@ void FurnaceGUI::drawSettings() { } popDestColor(); + // SUBSECTION CONFIGURATION + CONFIG_SUBSECTION(_("Modules import")); + bool s3mOPL2B=settings.OPL2s3mImport; + if (ImGui::Checkbox(_("Use OPL2 instead of OPL3 for .s3m modules import"),&s3mOPL2B)) { + settings.OPL2s3mImport=s3mOPL2B; + settingsChanged=true; + } + END_SECTION; } CONFIG_SECTION(_("Audio")) { @@ -4746,6 +4754,8 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { settings.vibrationStrength=conf.getFloat("vibrationStrength",0.5f); settings.vibrationLength=conf.getInt("vibrationLength",20); + settings.OPL2s3mImport=conf.getInt("OPL2s3mImport",false); + settings.backupEnable=conf.getInt("backupEnable",1); settings.backupInterval=conf.getInt("backupInterval",30); settings.backupMaxCopies=conf.getInt("backupMaxCopies",5); @@ -5331,6 +5341,8 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { conf.set("vibrationStrength",settings.vibrationStrength); conf.set("vibrationLength",settings.vibrationLength); + conf.set("OPL2s3mImport",settings.OPL2s3mImport); + conf.set("backupEnable",settings.backupEnable); conf.set("backupInterval",settings.backupInterval); conf.set("backupMaxCopies",settings.backupMaxCopies); From f5743da6e8cd4f0594d8ce4d5f587225f069b2f5 Mon Sep 17 00:00:00 2001 From: LTVA1 <87536432+LTVA1@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:43:37 +0300 Subject: [PATCH 34/37] Update settings.cpp --- 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 5a125d0f8..1847a2a26 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -4754,7 +4754,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { settings.vibrationStrength=conf.getFloat("vibrationStrength",0.5f); settings.vibrationLength=conf.getInt("vibrationLength",20); - settings.OPL2s3mImport=conf.getInt("OPL2s3mImport",false); + settings.OPL2s3mImport=conf.getBool("OPL2s3mImport",false); settings.backupEnable=conf.getInt("backupEnable",1); settings.backupInterval=conf.getInt("backupInterval",30); From 636a9921a2415f89a8b198b79348084e3bfb5773 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 17 Aug 2024 16:29:13 -0500 Subject: [PATCH 35/37] changes --- src/engine/engine.h | 4 ++-- src/engine/fileOps/fileOpsCommon.cpp | 4 ++-- src/engine/fileOps/s3m.cpp | 3 ++- src/gui/gui.cpp | 4 ++-- src/gui/gui.h | 4 ++-- src/gui/settings.cpp | 15 ++++++++------- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 4364adf13..f010d7001 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -597,7 +597,7 @@ class DivEngine { bool loadDMF(unsigned char* file, size_t len); bool loadFur(unsigned char* file, size_t len, int variantID=0); bool loadMod(unsigned char* file, size_t len); - bool loadS3M(unsigned char* file, size_t len, bool opl2=false); + bool loadS3M(unsigned char* file, size_t len); bool loadXM(unsigned char* file, size_t len); bool loadIT(unsigned char* file, size_t len); bool loadFTM(unsigned char* file, size_t len, bool dnft, bool dnftSig, bool eft); @@ -689,7 +689,7 @@ class DivEngine { void createNew(const char* description, String sysName, bool inBase64=true); void createNewFromDefaults(); // load a file. - bool load(unsigned char* f, size_t length, const char* nameHint=NULL, bool s3mOPL2=false); + bool load(unsigned char* f, size_t length, const char* nameHint=NULL); // play a binary command stream. bool playStream(unsigned char* f, size_t length); // get the playing stream. diff --git a/src/engine/fileOps/fileOpsCommon.cpp b/src/engine/fileOps/fileOpsCommon.cpp index 78bf00b41..1a2f36319 100644 --- a/src/engine/fileOps/fileOpsCommon.cpp +++ b/src/engine/fileOps/fileOpsCommon.cpp @@ -19,7 +19,7 @@ #include "fileOpsCommon.h" -bool DivEngine::load(unsigned char* f, size_t slen, const char* nameHint, bool s3mOPL2) { +bool DivEngine::load(unsigned char* f, size_t slen, const char* nameHint) { unsigned char* file; size_t len; if (slen<21) { @@ -158,7 +158,7 @@ bool DivEngine::load(unsigned char* f, size_t slen, const char* nameHint, bool s return loadIT(file,len); } else if (len>=48) { if (memcmp(&file[0x2c],DIV_S3M_MAGIC,4)==0) { - return loadS3M(file,len,s3mOPL2); + return loadS3M(file,len); } else if (memcmp(file,DIV_XM_MAGIC,17)==0) { return loadXM(file,len); } diff --git a/src/engine/fileOps/s3m.cpp b/src/engine/fileOps/s3m.cpp index 5974f2f11..9e212d8d3 100644 --- a/src/engine/fileOps/s3m.cpp +++ b/src/engine/fileOps/s3m.cpp @@ -48,9 +48,10 @@ static void readSbiOpData(sbi_t& sbi, SafeReader& reader) { sbi.FeedConnect = reader.readC(); } -bool DivEngine::loadS3M(unsigned char* file, size_t len, bool opl2) { +bool DivEngine::loadS3M(unsigned char* file, size_t len) { struct InvalidHeaderException {}; bool success=false; + bool opl2=!getConfInt("s3mOPL3",0); char magic[4]={0,0,0,0}; SafeReader reader=SafeReader(file,len); warnings=""; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 0ce0a69fa..37443c46e 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2417,7 +2417,7 @@ int FurnaceGUI::load(String path) { return 1; } fclose(f); - if (!e->load(file,(size_t)len,path.c_str(),settings.OPL2s3mImport)) { + if (!e->load(file,(size_t)len,path.c_str())) { lastError=e->getLastError(); logE("could not open file!"); return 1; @@ -4110,7 +4110,7 @@ bool FurnaceGUI::loop() { if (!tutorial.introPlayed || settings.alwaysPlayIntro==3 || (settings.alwaysPlayIntro==2 && curFileName.empty())) { unsigned char* introTemp=new unsigned char[intro_fur_len]; memcpy(introTemp,intro_fur,intro_fur_len); - e->load(introTemp,intro_fur_len,NULL,settings.OPL2s3mImport); + e->load(introTemp,intro_fur_len); } } diff --git a/src/gui/gui.h b/src/gui/gui.h index b4b134be9..1619f831a 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1958,7 +1958,7 @@ class FurnaceGUI { unsigned int maxUndoSteps; float vibrationStrength; int vibrationLength; - bool OPL2s3mImport; + int s3mOPL3; String mainFontPath; String headFontPath; String patFontPath; @@ -2215,7 +2215,7 @@ class FurnaceGUI { maxUndoSteps(100), vibrationStrength(0.5f), vibrationLength(20), - OPL2s3mImport(false), + s3mOPL3(0), mainFontPath(""), headFontPath(""), patFontPath(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 1847a2a26..ae085f072 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1254,11 +1254,11 @@ void FurnaceGUI::drawSettings() { } popDestColor(); - // SUBSECTION CONFIGURATION - CONFIG_SUBSECTION(_("Modules import")); - bool s3mOPL2B=settings.OPL2s3mImport; - if (ImGui::Checkbox(_("Use OPL2 instead of OPL3 for .s3m modules import"),&s3mOPL2B)) { - settings.OPL2s3mImport=s3mOPL2B; + // SUBSECTION IMPORT + CONFIG_SUBSECTION(_("Import")); + bool s3mOPL3B=settings.s3mOPL3; + if (ImGui::Checkbox(_("Use OPL3 instead of OPL2 for S3M import"),&s3mOPL3B)) { + settings.s3mOPL3=s3mOPL3B; settingsChanged=true; } @@ -4754,7 +4754,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { settings.vibrationStrength=conf.getFloat("vibrationStrength",0.5f); settings.vibrationLength=conf.getInt("vibrationLength",20); - settings.OPL2s3mImport=conf.getBool("OPL2s3mImport",false); + settings.s3mOPL3=conf.getInt("s3mOPL3",0); settings.backupEnable=conf.getInt("backupEnable",1); settings.backupInterval=conf.getInt("backupInterval",30); @@ -5268,6 +5268,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { clampSetting(settings.backupMaxCopies,1,100); clampSetting(settings.autoFillSave,0,1); clampSetting(settings.autoMacroStepSize,0,1); + clampSetting(settings.s3mOPL3,0,1); if (settings.exportLoops<0.0) settings.exportLoops=0.0; if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0; @@ -5341,7 +5342,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { conf.set("vibrationStrength",settings.vibrationStrength); conf.set("vibrationLength",settings.vibrationLength); - conf.set("OPL2s3mImport",settings.OPL2s3mImport); + conf.set("s3mOPL3",settings.s3mOPL3); conf.set("backupEnable",settings.backupEnable); conf.set("backupInterval",settings.backupInterval); From 3fce04e77bcada61d7a9a74fac6a1f34d6f6fe56 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 17 Aug 2024 16:56:11 -0500 Subject: [PATCH 36/37] GUI: getGain debug --- src/gui/debugWindow.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 594554c57..b08c60532 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -36,6 +36,8 @@ static float oscDebugMax=1.0; static float oscDebugPower=1.0; static int oscDebugRepeat=1; static int numApples=1; +static int getGainChan=0; +static int getGainVol=0; static void _drawOsc(const ImDrawList* drawList, const ImDrawCmd* cmd) { if (cmd!=NULL) { @@ -721,6 +723,13 @@ void FurnaceGUI::drawDebug() { ImGui::TreePop(); } #endif + if (ImGui::TreeNode("Get Gain Test")) { + float realVol=e->getGain(getGainChan,getGainVol); + ImGui::InputInt("Chan",&getGainChan); + ImGui::InputInt("Vol",&getGainVol); + ImGui::Text("result: %.0f%%",realVol*100.0f); + ImGui::TreePop(); + } if (ImGui::TreeNode("User Interface")) { if (ImGui::Button("Inspect")) { inspectorOpen=!inspectorOpen; From 3f47979ea771107a6cb98cd1b3cd2b2e2010c192 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 17 Aug 2024 17:18:14 -0500 Subject: [PATCH 37/37] IT import: handle end of file when reading samples --- src/engine/fileOps/it.cpp | 102 ++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/src/engine/fileOps/it.cpp b/src/engine/fileOps/it.cpp index a3ed09c49..a729706d7 100644 --- a/src/engine/fileOps/it.cpp +++ b/src/engine/fileOps/it.cpp @@ -639,6 +639,8 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { logD("seek not needed..."); } + logV("reading sample data (%d)",s->samples); + if (flags&8) { // compressed sample unsigned int ret=0; logV("decompression begin... (%d)",s->samples); @@ -672,62 +674,66 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) { } logV("got: %d",ret); } else { - if (s->depth==DIV_SAMPLE_DEPTH_16BIT) { - if (flags&4) { // downmix stereo - for (unsigned int i=0; isamples; i++) { - short l; - if (convert&2) { - l=reader.readS_BE(); - } else { - l=reader.readS(); + try { + if (s->depth==DIV_SAMPLE_DEPTH_16BIT) { + if (flags&4) { // downmix stereo + for (unsigned int i=0; isamples; i++) { + short l; + if (convert&2) { + l=reader.readS_BE(); + } else { + l=reader.readS(); + } + if (!(convert&1)) { + l^=0x8000; + } + s->data16[i]=l; } - if (!(convert&1)) { - l^=0x8000; + for (unsigned int i=0; isamples; i++) { + short r; + if (convert&2) { + r=reader.readS_BE(); + } else { + r=reader.readS(); + } + if (!(convert&1)) { + r^=0x8000; + } + s->data16[i]=(s->data16[i]+r)>>1; } - s->data16[i]=l; - } - for (unsigned int i=0; isamples; i++) { - short r; - if (convert&2) { - r=reader.readS_BE(); - } else { - r=reader.readS(); + } else { + for (unsigned int i=0; isamples; i++) { + if (convert&2) { + s->data16[i]=reader.readS_BE()^((convert&1)?0:0x8000); + } else { + s->data16[i]=reader.readS()^((convert&1)?0:0x8000); + } } - if (!(convert&1)) { - r^=0x8000; - } - s->data16[i]=(s->data16[i]+r)>>1; } } else { - for (unsigned int i=0; isamples; i++) { - if (convert&2) { - s->data16[i]=reader.readS_BE()^((convert&1)?0:0x8000); - } else { - s->data16[i]=reader.readS()^((convert&1)?0:0x8000); + if (flags&4) { // downmix stereo + for (unsigned int i=0; isamples; i++) { + signed char l=reader.readC(); + if (!(convert&1)) { + l^=0x80; + } + s->data8[i]=l; + } + for (unsigned int i=0; isamples; i++) { + signed char r=reader.readC(); + if (!(convert&1)) { + r^=0x80; + } + s->data8[i]=(s->data8[i]+r)>>1; + } + } else { + for (unsigned int i=0; isamples; i++) { + s->data8[i]=reader.readC()^((convert&1)?0:0x80); } } } - } else { - if (flags&4) { // downmix stereo - for (unsigned int i=0; isamples; i++) { - signed char l=reader.readC(); - if (!(convert&1)) { - l^=0x80; - } - s->data8[i]=l; - } - for (unsigned int i=0; isamples; i++) { - signed char r=reader.readC(); - if (!(convert&1)) { - r^=0x80; - } - s->data8[i]=(s->data8[i]+r)>>1; - } - } else { - for (unsigned int i=0; isamples; i++) { - s->data8[i]=reader.readC()^((convert&1)?0:0x80); - } - } + } catch (EndOfFileException& e) { + logW("premature end of file..."); } }