From 875827719927cd7789e2b89b4ccdc6c1c1798952 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 4 Mar 2022 01:18:16 -0500 Subject: [PATCH] OPLL: implement fixed freq mode for drums issue #249 --- papers/format.md | 7 ++++ src/engine/engine.h | 4 +- src/engine/instrument.cpp | 16 ++++++++ src/engine/instrument.h | 8 +++- src/engine/platform/opll.cpp | 19 ++++++++- src/gui/insEdit.cpp | 75 +++++++++++++++++++++++++++++++++++- 6 files changed, 123 insertions(+), 6 deletions(-) diff --git a/papers/format.md b/papers/format.md index 7c113b53..8e8c62e2 100644 --- a/papers/format.md +++ b/papers/format.md @@ -29,6 +29,7 @@ furthermore, an `or reserved` indicates this field is always present, but is res the format versions are: +- 63: Furnace dev63 - 62: Furnace dev62 - 61: Furnace dev61 - 60: Furnace dev60 @@ -476,6 +477,12 @@ size | description 1?? | VIB macro 1?? | WS macro 1?? | KSR macro + --- | **OPL drums mode data** (>=63) + 1 | fixed frequency mode + 1 | reserved + 2 | kick frequency + 2 | snare/hi-hat frequency + 2 | tom/top frequency ``` # wavetable diff --git a/src/engine/engine.h b/src/engine/engine.h index 921d4156..19d589db 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -37,8 +37,8 @@ warnings+=(String("\n")+x); \ } -#define DIV_VERSION "dev62" -#define DIV_ENGINE_VERSION 62 +#define DIV_VERSION "dev63" +#define DIV_ENGINE_VERSION 63 enum DivStatusView { DIV_STATUS_NOTHING=0, diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index d5933981..d65a27d0 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -371,6 +371,13 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(op.ksrMacro[j]); } } + + // OPL drum data + w->writeC(fm.fixedDrums); + w->writeC(0); // reserved + w->writeS(fm.kickFreq); + w->writeS(fm.snareHatFreq); + w->writeS(fm.tomTopFreq); } DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { @@ -694,6 +701,15 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { } } + // OPL drum data + if (version>=63) { + fm.fixedDrums=reader.readC(); + reader.readC(); // reserved + fm.kickFreq=reader.readS(); + fm.snareHatFreq=reader.readS(); + fm.tomTopFreq=reader.readS(); + } + return DIV_DATA_SUCCESS; } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index aef84f20..27ce2a4c 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -67,6 +67,8 @@ enum DivInstrumentType { struct DivInstrumentFM { unsigned char alg, fb, fms, ams, ops, opllPreset; + bool fixedDrums; + unsigned short kickFreq, snareHatFreq, tomTopFreq; struct Operator { unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ @@ -98,7 +100,11 @@ struct DivInstrumentFM { fms(0), ams(0), ops(4), - opllPreset(0) { + opllPreset(0), + fixedDrums(false), + kickFreq(0x520), + snareHatFreq(0x550), + tomTopFreq(0x1c0) { // default instrument fb=4; op[0].tl=42; diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index c6a8bf4d..2c2413c4 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -377,7 +377,24 @@ int DivPlatformOPLL::dispatch(DivCommand c) { if (c.chan>=6 && properDrums) { // drums mode chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); + if (chan[c.chan].state.opllPreset==16 && chan[c.chan].state.fixedDrums) { + switch (c.chan) { + case 6: + chan[c.chan].baseFreq=(chan[c.chan].state.kickFreq&511)<<(chan[c.chan].state.kickFreq>>9); + break; + case 7: case 10: + chan[c.chan].baseFreq=(chan[c.chan].state.snareHatFreq&511)<<(chan[c.chan].state.snareHatFreq>>9); + break; + case 8: case 9: + chan[c.chan].baseFreq=(chan[c.chan].state.tomTopFreq&511)<<(chan[c.chan].state.tomTopFreq>>9); + break; + default: + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); + break; + } + } else { + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); + } chan[c.chan].note=c.value; chan[c.chan].freqChanged=true; } diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 3f5ac067..de381e6b 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -81,7 +81,7 @@ const char* opllInsNames[17]={ "Synth Bass", "Acoustic Bass", "Electric Guitar", - "Drums (compatibility only!)" + "Drums" }; enum FMParams { @@ -857,7 +857,78 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_OPLL && ins->fm.opllPreset==16) { - ImGui::Text("the Drums patch is only there for compatibility.\nit is highly encouraged you use the OPLL (drums) system instead!"); + P(ImGui::Checkbox("Fixed frequency mode",&ins->fm.fixedDrums)); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("when enabled, drums will be set to the specified frequencies, ignoring the note."); + } + if (ins->fm.fixedDrums) { + int block=0; + int fNum=0; + if (ImGui::BeginTable("fixedDrumSettings",3)) { + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("Drum"); + ImGui::TableNextColumn(); + ImGui::Text("Block"); + ImGui::TableNextColumn(); + ImGui::Text("FreqNum"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + block=(ins->fm.kickFreq>>9)&7; + fNum=ins->fm.kickFreq&511; + ImGui::Text("Kick"); + ImGui::TableNextColumn(); + if (ImGui::InputInt("##DBlock0",&block,1,1)) { + if (block<0) block=0; + if (block>7) block=7; + ins->fm.kickFreq=(block<<9)|fNum; + } + ImGui::TableNextColumn(); + if (ImGui::InputInt("##DFreq0",&fNum,1,1)) { + if (fNum<0) fNum=0; + if (fNum>511) fNum=511; + ins->fm.kickFreq=(block<<9)|fNum; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + block=(ins->fm.snareHatFreq>>9)&7; + fNum=ins->fm.snareHatFreq&511; + ImGui::Text("Snare/Hi-hat"); + ImGui::TableNextColumn(); + if (ImGui::InputInt("##DBlock1",&block,1,1)) { + if (block<0) block=0; + if (block>7) block=7; + ins->fm.snareHatFreq=(block<<9)|fNum; + } + ImGui::TableNextColumn(); + if (ImGui::InputInt("##DFreq1",&fNum,1,1)) { + if (fNum<0) fNum=0; + if (fNum>511) fNum=511; + ins->fm.snareHatFreq=(block<<9)|fNum; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + block=(ins->fm.tomTopFreq>>9)&7; + fNum=ins->fm.tomTopFreq&511; + ImGui::Text("Tom/Top"); + ImGui::TableNextColumn(); + if (ImGui::InputInt("##DBlock2",&block,1,1)) { + if (block<0) block=0; + if (block>7) block=7; + ins->fm.tomTopFreq=(block<<9)|fNum; + } + ImGui::TableNextColumn(); + if (ImGui::InputInt("##DFreq2",&fNum,1,1)) { + if (fNum<0) fNum=0; + if (fNum>511) fNum=511; + ins->fm.tomTopFreq=(block<<9)|fNum; + } + ImGui::EndTable(); + } + } } bool willDisplayOps=true;