OPLL: implement fixed freq mode for drums

issue #249
This commit is contained in:
tildearrow 2022-03-04 01:18:16 -05:00
parent 8e5b3abab8
commit 8758277199
6 changed files with 123 additions and 6 deletions

View File

@ -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

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;