From 7b1713758bca595ddc86acda8b087bf844d1379a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 12 Sep 2022 00:37:25 -0500 Subject: [PATCH] dev114 - operator muting for OPN/OPM --- papers/format.md | 4 ++- src/engine/engine.h | 4 +-- src/engine/instrument.cpp | 12 ++++++-- src/engine/platform/arcade.cpp | 7 ++++- src/engine/platform/arcade.h | 5 ++-- src/engine/platform/genesis.cpp | 7 ++++- src/engine/platform/genesis.h | 3 +- src/engine/platform/ym2203.cpp | 7 ++++- src/engine/platform/ym2203.h | 3 +- src/engine/platform/ym2608.cpp | 7 ++++- src/engine/platform/ym2608.h | 3 +- src/engine/platform/ym2610.cpp | 7 ++++- src/engine/platform/ym2610.h | 5 ++-- src/engine/platform/ym2610b.cpp | 7 ++++- src/engine/platform/ym2610b.h | 5 ++-- src/gui/insEdit.cpp | 52 ++++++++++++++++++++++++++------- 16 files changed, 108 insertions(+), 30 deletions(-) diff --git a/papers/format.md b/papers/format.md index 14512fe12..da06488fa 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 114: Furnace dev114 - 113: Furnace dev113 - 112: Furnace dev112 - 111: Furnace dev111 @@ -497,7 +498,8 @@ size | description 1 | vib 1 | ws 1 | ksr - 12 | reserved + 1 | operator enabled (>=114) or reserved + 11 | reserved --- | **Game Boy instrument data** 1 | volume 1 | direction diff --git a/src/engine/engine.h b/src/engine/engine.h index 869587a24..3047a8af7 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev113" -#define DIV_ENGINE_VERSION 113 +#define DIV_VERSION "dev114" +#define DIV_ENGINE_VERSION 114 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 19cb1ba55..22cdddf4b 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -71,8 +71,10 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(op.ws); w->writeC(op.ksr); + w->writeC(op.enable); + // reserved - for (int k=0; k<12; k++) { + for (int k=0; k<11; k++) { w->writeC(0); } } @@ -716,8 +718,14 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { op.ws=reader.readC(); op.ksr=reader.readC(); + if (version>=114) { + op.enable=reader.readC(); + } else { + reader.readC(); + } + // reserved - for (int k=0; k<12; k++) reader.readC(); + for (int k=0; k<11; k++) reader.readC(); } // GB diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 90de2387a..7d44fe8a8 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -348,7 +348,7 @@ void DivPlatformArcade::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - immWrite(0x08,0x78|i); + immWrite(0x08,(chan[i].opMask<<3)|i); chan[i].keyOn=false; } } @@ -370,6 +370,11 @@ int DivPlatformArcade::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } chan[c.chan].macroInit(ins); diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index 93aa490d0..683394e3b 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -45,7 +45,7 @@ class DivPlatformArcade: public DivPlatformOPM { signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset; int vol, outVol; - unsigned char chVolL, chVolR; + unsigned char chVolL, chVolR, opMask; void macroInit(DivInstrument* which) { std.init(which); pitch2=0; @@ -71,7 +71,8 @@ class DivPlatformArcade: public DivPlatformOPM { vol(0), outVol(0), chVolL(127), - chVolR(127) {} + chVolR(127), + opMask(15) {} }; Channel chan[8]; DivDispatchOscBuffer* oscBuf[8]; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index f499865ef..5b4b535bf 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -480,7 +480,7 @@ void DivPlatformGenesis::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - if (i<6) immWrite(0x28,0xf0|konOffs[i]); + if (i<6) immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); chan[i].keyOn=false; } } @@ -591,6 +591,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } chan[c.chan].macroInit(ins); diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 5e61fe678..34a4d4f23 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -47,7 +47,7 @@ class DivPlatformGenesis: public DivPlatformOPN { int ins; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset; int vol, outVol; - unsigned char pan; + unsigned char pan, opMask; bool dacMode; int dacPeriod; @@ -85,6 +85,7 @@ class DivPlatformGenesis: public DivPlatformOPN { vol(0), outVol(0), pan(3), + opMask(15), dacMode(false), dacPeriod(0), dacRate(0), diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 178ef05b8..46696b8ac 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -386,7 +386,7 @@ void DivPlatformYM2203::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - immWrite(0x28,0xf0|konOffs[i]); + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); chan[i].keyOn=false; } } @@ -409,6 +409,11 @@ int DivPlatformYM2203::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/ym2203.h b/src/engine/platform/ym2203.h index 0395c9d0f..921c1d94b 100644 --- a/src/engine/platform/ym2203.h +++ b/src/engine/platform/ym2203.h @@ -43,7 +43,7 @@ class DivPlatformYM2203: public DivPlatformOPN { DivInstrumentFM state; unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; + unsigned char psgMode, autoEnvNum, autoEnvDen, opMask; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; int vol, outVol; @@ -66,6 +66,7 @@ class DivPlatformYM2203: public DivPlatformOPN { psgMode(1), autoEnvNum(0), autoEnvDen(0), + opMask(15), active(false), insChanged(true), freqChanged(false), diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 244e4a16e..801bab329 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -582,7 +582,7 @@ void DivPlatformYM2608::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - immWrite(0x28,0xf0|konOffs[i]); + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); chan[i].keyOn=false; } } @@ -683,6 +683,11 @@ int DivPlatformYM2608::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/ym2608.h b/src/engine/platform/ym2608.h index 7a471b8bf..1689436ee 100644 --- a/src/engine/platform/ym2608.h +++ b/src/engine/platform/ym2608.h @@ -48,7 +48,7 @@ class DivPlatformYM2608: public DivPlatformOPN { DivInstrumentFM state; unsigned char freqH, freqL; int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins; - unsigned char psgMode, autoEnvNum, autoEnvDen; + unsigned char psgMode, autoEnvNum, autoEnvDen, opMask; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; int vol, outVol; @@ -72,6 +72,7 @@ class DivPlatformYM2608: public DivPlatformOPN { psgMode(1), autoEnvNum(0), autoEnvDen(0), + opMask(15), active(false), insChanged(true), freqChanged(false), diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 064b49f2d..63a6d72e3 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -619,7 +619,7 @@ void DivPlatformYM2610::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - immWrite(0x28,0xf0|konOffs[i]); + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); chan[i].keyOn=false; } } @@ -727,6 +727,11 @@ int DivPlatformYM2610::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 5e22ed2a0..0e363329a 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -76,7 +76,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; int vol, outVol; int sample; - unsigned char pan; + unsigned char pan, opMask; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -107,7 +107,8 @@ class DivPlatformYM2610: public DivPlatformYM2610Base { vol(0), outVol(15), sample(-1), - pan(3) {} + pan(3), + opMask(15) {} }; Channel chan[14]; DivDispatchOscBuffer* oscBuf[14]; diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 8d283374d..f01f39b42 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -601,7 +601,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { chan[i].freqChanged=false; } if (chan[i].keyOn) { - immWrite(0x28,0xf0|konOffs[i]); + immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); chan[i].keyOn=false; } } @@ -709,6 +709,11 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; + chan[c.chan].opMask= + (chan[c.chan].state.op[0].enable?1:0)| + (chan[c.chan].state.op[2].enable?2:0)| + (chan[c.chan].state.op[1].enable?4:0)| + (chan[c.chan].state.op[3].enable?8:0); } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index 703f8dd4a..87500e9b0 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -43,7 +43,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; int vol, outVol; int sample; - unsigned char pan; + unsigned char pan, opMask; DivMacroInt std; void macroInit(DivInstrument* which) { std.init(which); @@ -74,7 +74,8 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base { vol(0), outVol(15), sample(-1), - pan(3) {} + pan(3), + opMask(15) {} }; Channel chan[16]; DivDispatchOscBuffer* oscBuf[16]; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 563e05794..3ffc86a8a 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1737,6 +1737,7 @@ void FurnaceGUI::drawInsEdit() { int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; + bool opsAreMutable=(ins->type==DIV_INS_FM); if (ImGui::BeginTabItem("FM")) { if (ImGui::BeginTable("fmDetails",3,ImGuiTableFlags_SizingStretchSame)) { @@ -2091,16 +2092,27 @@ void FurnaceGUI::drawInsEdit() { if (i==0) sliderHeight=(ImGui::GetContentRegionAvail().y/opCount)-ImGui::GetStyle().ItemSpacing.y; ImGui::PushID(fmt::sprintf("op%d",i).c_str()); + String opNameLabel; if (ins->type==DIV_INS_OPL_DRUMS) { - ImGui::Text("%s",oplDrumNames[i]); + opNameLabel=fmt::sprintf("%s",oplDrumNames[i]); } else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { if (i==1) { - ImGui::Text("Kick"); + opNameLabel="Kick"; } else { - ImGui::Text("Env"); + opNameLabel="Env"; } } else { - ImGui::Text("OP%d",i+1); + opNameLabel=fmt::sprintf("OP%d",i+1); + } + if (opsAreMutable) { + pushToggleColors(op.enable); + if (ImGui::Button(opNameLabel.c_str())) { + op.enable=!op.enable; + PARAMETER; + } + popToggleColors(); + } else { + ImGui::TextUnformatted(opNameLabel.c_str()); } // drag point @@ -2388,11 +2400,20 @@ void FurnaceGUI::drawInsEdit() { } else { snprintf(tempID,1024,"Operator %d",i+1); } - float nextCursorPosX=ImGui::GetCursorPosX()+0.5*(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(tempID).x); + float nextCursorPosX=ImGui::GetCursorPosX()+0.5*(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(tempID).x-(opsAreMutable?(ImGui::GetStyle().FramePadding.x*2.0f):0.0f)); OP_DRAG_POINT; ImGui::SameLine(); ImGui::SetCursorPosX(nextCursorPosX); - ImGui::TextUnformatted(tempID); + if (opsAreMutable) { + pushToggleColors(op.enable); + if (ImGui::Button(tempID)) { + op.enable=!op.enable; + PARAMETER; + } + popToggleColors(); + } else { + ImGui::TextUnformatted(tempID); + } float sliderHeight=200.0f*dpiScale; float waveWidth=140.0*dpiScale; @@ -2824,18 +2845,29 @@ void FurnaceGUI::drawInsEdit() { } ImGui::Dummy(ImVec2(dpiScale,dpiScale)); + String opNameLabel; OP_DRAG_POINT; ImGui::SameLine(); if (ins->type==DIV_INS_OPL_DRUMS) { - ImGui::Text("%s",oplDrumNames[i]); + opNameLabel=fmt::sprintf("%s",oplDrumNames[i]); } else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { if (i==1) { - ImGui::Text("Envelope 2 (kick only)"); + opNameLabel="Envelope 2 (kick only)"; } else { - ImGui::Text("Envelope"); + opNameLabel="Envelope"; } } else { - ImGui::Text("OP%d",i+1); + opNameLabel=fmt::sprintf("OP%d",i+1); + } + if (opsAreMutable) { + pushToggleColors(op.enable); + if (ImGui::Button(opNameLabel.c_str())) { + op.enable=!op.enable; + PARAMETER; + } + popToggleColors(); + } else { + ImGui::TextUnformatted(opNameLabel.c_str()); } ImGui::SameLine();