From 495aec86bde00b3c03be0b3022f64f6aef10c263 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 30 May 2022 14:02:54 -0500 Subject: [PATCH 1/7] fix addOrder() undefined behavior --- src/engine/engine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 639712e54..bee45e4b3 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2146,6 +2146,7 @@ void DivEngine::delSample(int index) { void DivEngine::addOrder(bool duplicate, bool where) { unsigned char order[DIV_MAX_CHANS]; if (curSubSong->ordersLen>=0xff) return; + memset(order,0,DIV_MAX_CHANS); BUSY_BEGIN_SOFT; if (duplicate) { for (int i=0; i Date: Mon, 30 May 2022 18:37:07 -0500 Subject: [PATCH 2/7] prepare for OPL drums instrument type #310 --- src/engine/instrument.h | 1 + src/engine/song.h | 5 ++- src/engine/sysDef.cpp | 17 ++++---- src/gui/dataList.cpp | 4 ++ src/gui/gui.h | 1 + src/gui/guiConst.cpp | 2 + src/gui/insEdit.cpp | 91 +++++++++++++++++++++++++---------------- 7 files changed, 77 insertions(+), 44 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index f389233c3..c4af6f042 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -59,6 +59,7 @@ enum DivInstrumentType: unsigned short { DIV_INS_SNES=29, DIV_INS_SU=30, DIV_INS_NAMCO=31, + DIV_INS_OPL_DRUMS=32, DIV_INS_MAX, DIV_INS_NULL }; diff --git a/src/engine/song.h b/src/engine/song.h index c9d98275a..ee0d6ed1f 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -408,7 +408,7 @@ struct DivSong { std::vector subsong; - DivInstrument nullIns, nullInsOPLL, nullInsOPL, nullInsQSound; + DivInstrument nullIns, nullInsOPLL, nullInsOPL, nullInsOPLDrums, nullInsQSound; DivWavetable nullWave; DivSample nullSample; @@ -551,6 +551,9 @@ struct DivSong { nullInsOPL.fm.op[1].rr=12; nullInsOPL.fm.op[1].mult=1; nullInsOPL.name="This is a bug! Report!"; + nullInsOPL.fm.kickFreq=0x520; + nullInsOPL.fm.snareHatFreq=0x550; + nullInsOPL.fm.tomTopFreq=0x1c0; nullInsQSound.std.panLMacro.mode=true; } diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 45fde7187..96f47b456 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -19,6 +19,7 @@ #include "dispatch.h" #include "engine.h" +#include "instrument.h" #include "song.h" #include "../ta-log.h" @@ -1582,8 +1583,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, - {}, + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, oplDrumsEffectHandler, fmOPLPostEffectHandler ); @@ -1594,8 +1595,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, - {}, + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, oplDrumsEffectHandler, fmOPLPostEffectHandler ); @@ -1606,8 +1607,8 @@ void DivEngine::registerSystems() { {"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick", "Snare", "Tom", "Top", "HiHat"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "BD", "SD", "TM", "TP", "HH"}, {DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, - {}, + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, oplDrumsEffectHandler, fmOPLPostEffectHandler ); @@ -1853,8 +1854,8 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat", "PCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "PCM"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA}, - {}, + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_AMIGA}, + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_NULL}, oplEffectHandler, fmOPLPostEffectHandler ); diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 4e0979972..62b93479b 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -313,6 +313,10 @@ void FurnaceGUI::drawInsList() { ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_NAMCO]); name=fmt::sprintf(ICON_FA_PIE_CHART " %.2X: %s##_INS%d",i,ins->name,i); break; + case DIV_INS_OPL_DRUMS: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPL_DRUMS]); + name=fmt::sprintf(ICON_FA_COFFEE " %.2X: %s##_INS%d",i,ins->name,i); + break; default: ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]); name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i); diff --git a/src/gui/gui.h b/src/gui/gui.h index 8f1f9d1d5..898be919e 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -151,6 +151,7 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_SNES, GUI_COLOR_INSTR_SU, GUI_COLOR_INSTR_NAMCO, + GUI_COLOR_INSTR_OPL_DRUMS, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_FM, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 4172836d5..722c56520 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -112,6 +112,7 @@ const char* insTypes[DIV_INS_MAX+1]={ "SNES", "Sound Unit", "Namco WSG", + "OPL (drums)", NULL }; @@ -758,6 +759,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_SNES,"",ImVec4(0.8f,0.7f,1.0f,1.0f)), D(GUI_COLOR_INSTR_SU,"",ImVec4(0.95f,0.98f,1.0f,1.0f)), D(GUI_COLOR_INSTR_NAMCO,"",ImVec4(1.0f,1.0f,0.0f,1.0f)), + D(GUI_COLOR_INSTR_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_CHANNEL_FM,"",ImVec4(0.2f,0.8f,1.0f,1.0f)), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 30aac2378..6d6e424c8 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -75,6 +75,10 @@ const char* opzWaveforms[8]={ "Sine", "Triangle", "Cut Sine", "Cut Triangle", "Squished Sine", "Squished Triangle", "Squished AbsSine", "Squished AbsTriangle" }; +const char* oplDrumNames[4]={ + "Snare", "Tom", "Top", "HiHat" +}; + const bool opIsOutput[8][4]={ {false,false,false,true}, {false,false,false,true}, @@ -1474,7 +1478,7 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::BeginTabBar("insEditTab")) { std::vector macroList; - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL_DRUMS) { char label[32]; int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; @@ -1516,22 +1520,27 @@ void FurnaceGUI::drawInsEdit() { showError("Coming soon!"); } break; - case DIV_INS_OPL: { - bool fourOp=(ins->fm.ops==4); + case DIV_INS_OPL: + case DIV_INS_OPL_DRUMS: { + bool fourOp=(ins->fm.ops==4 || ins->type==DIV_INS_OPL_DRUMS); bool drums=ins->fm.opllPreset==16; int algMax=fourOp?3:1; ImGui::TableNextColumn(); ins->fm.alg&=algMax; P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable - ImGui::BeginDisabled(ins->fm.opllPreset==16); - if (ImGui::Checkbox("4-op",&fourOp)) { PARAMETER - ins->fm.ops=fourOp?4:2; + if (ins->type==DIV_INS_OPL) { + ImGui::BeginDisabled(ins->fm.opllPreset==16); + if (ImGui::Checkbox("4-op",&fourOp)) { PARAMETER + ins->fm.ops=fourOp?4:2; + } + ImGui::EndDisabled(); } - ImGui::EndDisabled(); ImGui::TableNextColumn(); P(CWSliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&algMax)); rightClickable - if (ImGui::Checkbox("Drums",&drums)) { PARAMETER - ins->fm.opllPreset=drums?16:0; + if (ins->type==DIV_INS_OPL) { + if (ImGui::Checkbox("Drums",&drums)) { PARAMETER + ins->fm.opllPreset=drums?16:0; + } } ImGui::TableNextColumn(); drawAlgorithm(ins->fm.alg&algMax,fourOp?FM_ALGS_4OP_OPL:FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); @@ -1576,7 +1585,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTable(); } - if ((ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL) && ins->fm.opllPreset==16) { + if (((ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL) && ins->fm.opllPreset==16) || ins->type==DIV_INS_OPL_DRUMS) { ins->fm.ops=2; P(ImGui::Checkbox("Fixed frequency mode",&ins->fm.fixedDrums)); if (ImGui::IsItemHovered()) { @@ -1611,7 +1620,7 @@ void FurnaceGUI::drawInsEdit() { if (willDisplayOps) { if (settings.fmLayout==0) { int numCols=16; - if (ins->type==DIV_INS_OPL) numCols=13; + if (ins->type==DIV_INS_OPL ||ins->type==DIV_INS_OPL_DRUMS) numCols=13; if (ins->type==DIV_INS_OPLL) numCols=12; if (ins->type==DIV_INS_OPZ) numCols=19; if (ImGui::BeginTable("FMOperators",numCols,ImGuiTableFlags_SizingStretchProp|ImGuiTableFlags_BordersH|ImGuiTableFlags_BordersOuterV)) { @@ -1722,7 +1731,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TextUnformatted("Other"); } ImGui::TableNextColumn(); - if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ) { ImGui::TableNextColumn(); CENTER_TEXT(FM_NAME(FM_WS)); ImGui::TextUnformatted(FM_NAME(FM_WS)); @@ -1738,14 +1747,16 @@ void FurnaceGUI::drawInsEdit() { float sliderHeight=32.0f*dpiScale; for (int i=0; ifm.op[(opCount==4)?opOrder[i]:i]; + DivInstrumentFM::Operator& op=ins->fm.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i]; ImGui::TableNextRow(); ImGui::TableNextColumn(); // push colors if (settings.separateFMColors) { bool mod=true; - if (opCount==4) { + if (ins->type==DIV_INS_OPL_DRUMS) { + mod=false; + } else if (opCount==4) { if (ins->type==DIV_INS_OPL) { if (opIsOutputOPL[ins->fm.alg&3][i]) mod=false; } else { @@ -1774,7 +1785,9 @@ void FurnaceGUI::drawInsEdit() { if (i==0) sliderHeight=(ImGui::GetContentRegionAvail().y/opCount)-ImGui::GetStyle().ItemSpacing.y; ImGui::PushID(fmt::sprintf("op%d",i).c_str()); - if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { + if (ins->type==DIV_INS_OPL_DRUMS) { + ImGui::Text("%s",oplDrumNames[i]); + } else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { if (i==1) { ImGui::Text("Kick"); } else { @@ -1792,7 +1805,7 @@ void FurnaceGUI::drawInsEdit() { maxTl=63; } } - if (ins->type==DIV_INS_OPL) { + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; @@ -1926,7 +1939,7 @@ void FurnaceGUI::drawInsEdit() { } } - if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPZ) { + if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ) { ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); ImGui::TableNextColumn(); @@ -1961,7 +1974,7 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER op.ksr=ksrOn; } - if (ins->type==DIV_INS_OPL) { + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER op.sus=susOn; } @@ -1972,7 +1985,7 @@ void FurnaceGUI::drawInsEdit() { } } - if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ) { ImGui::TableNextColumn(); ImGui::Dummy(ImVec2(4.0f*dpiScale,2.0f*dpiScale)); ImGui::TableNextColumn(); @@ -1980,7 +1993,7 @@ void FurnaceGUI::drawInsEdit() { drawWaveform(op.ws&7,ins->type==DIV_INS_OPZ,ImVec2(ImGui::GetContentRegionAvail().x,sliderHeight-ImGui::GetFrameHeightWithSpacing())); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable - if (ins->type==DIV_INS_OPL && ImGui::IsItemHovered()) { + if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); } } else if (ins->type==DIV_INS_OPLL) { @@ -1989,7 +2002,7 @@ void FurnaceGUI::drawInsEdit() { } ImGui::TableNextColumn(); - drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,sliderHeight),ins->type); + drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,sliderHeight),ins->type); if (settings.separateFMColors) { popAccentColors(); @@ -2015,7 +2028,7 @@ void FurnaceGUI::drawInsEdit() { } if (ImGui::BeginTable("FMOperators",columns,ImGuiTableFlags_SizingStretchSame)) { for (int i=0; ifm.op[(opCount==4)?opOrder[i]:i]; + DivInstrumentFM::Operator& op=ins->fm.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i]; if ((settings.fmLayout!=3 && ((i+1)&1)) || i==0 || settings.fmLayout==2) ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Separator(); @@ -2024,7 +2037,9 @@ void FurnaceGUI::drawInsEdit() { // push colors if (settings.separateFMColors) { bool mod=true; - if (opCount==4) { + if (ins->type==DIV_INS_OPL_DRUMS) { + mod=false; + } else if (opCount==4) { if (ins->type==DIV_INS_OPL) { if (opIsOutputOPL[ins->fm.alg&3][i]) mod=false; } else { @@ -2051,7 +2066,9 @@ void FurnaceGUI::drawInsEdit() { } ImGui::Dummy(ImVec2(dpiScale,dpiScale)); - if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { + if (ins->type==DIV_INS_OPL_DRUMS) { + ImGui::Text("%s",oplDrumNames[i]); + } else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) { if (i==1) { ImGui::Text("Envelope 2 (kick only)"); } else { @@ -2076,7 +2093,7 @@ void FurnaceGUI::drawInsEdit() { maxTl=63; } } - if (ins->type==DIV_INS_OPL) { + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; @@ -2086,7 +2103,7 @@ void FurnaceGUI::drawInsEdit() { bool vibOn=op.vib; bool susOn=op.sus; // don't you make fun of this one unsigned char ssgEnv=op.ssgEnv&7; - if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPZ) { + if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS && ins->type!=DIV_INS_OPZ) { ImGui::SameLine(); if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); @@ -2098,7 +2115,7 @@ void FurnaceGUI::drawInsEdit() { } } - if (ins->type==DIV_INS_OPL) { + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { ImGui::SameLine(); if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER op.sus=susOn; @@ -2106,7 +2123,7 @@ void FurnaceGUI::drawInsEdit() { } //52.0 controls vert scaling; default 96 - drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type); + drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type); //P(CWSliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); rightClickable if (ImGui::BeginTable("opParams",2,ImGuiTableFlags_SizingStretchProp)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); \ @@ -2229,12 +2246,12 @@ void FurnaceGUI::drawInsEdit() { } } - if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) { + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPZ) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); P(CWSliderScalar("##WS",ImGuiDataType_U8,&op.ws,&_ZERO,&_SEVEN,(ins->type==DIV_INS_OPZ)?opzWaveforms[op.ws&7]:(settings.oplStandardWaveNames?oplWaveformsStandard[op.ws&7]:oplWaveforms[op.ws&7]))); rightClickable - if (ins->type==DIV_INS_OPL && ImGui::IsItemHovered()) { + if ((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) && ImGui::IsItemHovered()) { ImGui::SetTooltip("OPL2/3 only (last 4 waveforms are OPL3 only)"); } ImGui::TableNextColumn(); @@ -2244,7 +2261,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTable(); } - if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL) { + if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER op.vib=vibOn; } @@ -2275,7 +2292,7 @@ void FurnaceGUI::drawInsEdit() { } else { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_ALG),&ins->std.algMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FB),&ins->std.fbMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); - if (ins->type!=DIV_INS_OPL) { + if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPL_DRUMS) { if (ins->type==DIV_INS_OPZ) { // TODO: FMS2/AMS2 macros macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_FMS),&ins->std.fmsMacro,0,7,96,uiColors[GUI_COLOR_MACRO_OTHER])); @@ -2298,7 +2315,11 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTabItem(); } for (int i=0; itype==DIV_INS_OPL_DRUMS) { + snprintf(label,31,"%s Macros",oplDrumNames[i]); + } else { + snprintf(label,31,"OP%d Macros",i+1); + } if (ImGui::BeginTabItem(label)) { ImGui::PushID(i); int ordi=(opCount==4)?orderedOps[i]:i; @@ -2310,12 +2331,12 @@ void FurnaceGUI::drawInsEdit() { maxTl=63; } } - if (ins->type==DIV_INS_OPL) { + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { maxTl=63; } int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; - if (ins->type==DIV_INS_OPL) { + if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS) { macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_TL),&ins->std.opMacros[ordi].tlMacro,0,maxTl,128,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_AR),&ins->std.opMacros[ordi].arMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_OTHER])); macroList.push_back(FurnaceGUIMacroDesc(FM_NAME(FM_DR),&ins->std.opMacros[ordi].drMacro,0,maxArDr,64,uiColors[GUI_COLOR_MACRO_OTHER])); From 4abfd4f097829d07be326f469ca1cc92486e05eb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 30 May 2022 18:40:26 -0500 Subject: [PATCH 3/7] FM: change the kick label issue #310 --- src/engine/sysDef.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 96f47b456..be2c72363 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1580,7 +1580,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_OPL_DRUMS]=new DivSysDef( "Yamaha YM3526 (OPL) with drums", NULL, 0xa2, 0, 11, true, false, 0x151, false, "the OPL chip but with drums mode enabled.", - {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, + {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick/FM 7", "Snare", "Tom", "Top", "HiHat"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, @@ -1592,7 +1592,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_OPL2_DRUMS]=new DivSysDef( "Yamaha YM3812 (OPL2) with drums", NULL, 0xa3, 0, 11, true, false, 0x151, false, "the OPL2 chip but with drums mode enabled.", - {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, + {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick/FM 7", "Snare", "Tom", "Top", "HiHat"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, @@ -1604,7 +1604,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_OPL3_DRUMS]=new DivSysDef( "Yamaha YMF262 (OPL3) with drums", NULL, 0xa4, 0, 20, true, false, 0x151, false, "the OPL3 chip but with drums mode enabled.", - {"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick", "Snare", "Tom", "Top", "HiHat"}, + {"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick/FM 16", "Snare", "Tom", "Top", "HiHat"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "BD", "SD", "TM", "TP", "HH"}, {DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS}, @@ -1821,7 +1821,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_OPL4_DRUMS]=new DivSysDef( "Yamaha OPL4 with drums", NULL, 0xaf, 0, 44, true, true, 0, false, "the OPL4 but with drums mode turned on.", - {"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick", "Snare", "Tom", "Top", "HiHat", "PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "PCM 17", "PCM 18", "PCM 19", "PCM 20", "PCM 21", "PCM 22", "PCM 23", "PCM 24"}, + {"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick/FM 16", "Snare", "Tom", "Top", "HiHat", "PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "PCM 17", "PCM 18", "PCM 19", "PCM 20", "PCM 21", "PCM 22", "PCM 23", "PCM 24"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "BD", "SD", "TM", "TP", "HH", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P8", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"}, {DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM} @@ -1851,7 +1851,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_Y8950_DRUMS]=new DivSysDef( "Yamaha Y8950 with drums", NULL, 0xb3, 0, 12, true, false, 0x151, false, "the Y8950 chip, in drums mode.", - {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat", "PCM"}, + {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick/FM 7", "Snare", "Tom", "Top", "HiHat", "PCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "PCM"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_OPL_DRUMS, DIV_INS_AMIGA}, From bc98673a2091c7fcdbe49c54a2c6f0845bb4dedb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 30 May 2022 19:02:24 -0500 Subject: [PATCH 4/7] GUI: double click selects column --- TODO.md | 1 - src/gui/cursor.cpp | 17 ++++++++++++++++- src/gui/gui.h | 2 ++ src/gui/settings.cpp | 9 ++++++++- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 0c5518f47..e2826a605 100644 --- a/TODO.md +++ b/TODO.md @@ -11,7 +11,6 @@ - volume commands should work on Game Boy - add another FM editor layout - if macros have release, note off should release them -- add ability to select a column by double clicking - add ability to move selection by dragging - Apply button in settings - find and replace diff --git a/src/gui/cursor.cpp b/src/gui/cursor.cpp index 244880735..e47dfd629 100644 --- a/src/gui/cursor.cpp +++ b/src/gui/cursor.cpp @@ -27,6 +27,21 @@ void FurnaceGUI::startSelection(int xCoarse, int xFine, int y, bool fullRow) { if (xCoarse!=selStart.xCoarse || xFine!=selStart.xFine || y!=selStart.y) { curNibble=false; } + + if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && !fullRow && settings.doubleClickColumn) { + if (cursor.xCoarse==xCoarse && cursor.xFine==xFine && cursor.y==y) { + // select entire channel + selStart.xCoarse=xCoarse; + selStart.xFine=0; + selStart.y=0; + selEnd.xCoarse=xCoarse; + selEnd.xFine=2+e->curPat[selEnd.xCoarse].effectCols*2; + selEnd.y=e->curSubSong->patLen-1; + + finishSelection(); + return; + } + } if (fullRow) { selStart.xCoarse=firstChannel; @@ -314,4 +329,4 @@ void FurnaceGUI::editAdvance() { selStart=cursor; selEnd=cursor; updateScroll(cursor.y); -} \ No newline at end of file +} diff --git a/src/gui/gui.h b/src/gui/gui.h index 898be919e..2c6d54b00 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -950,6 +950,7 @@ class FurnaceGUI { int volCellSpacing; int effectCellSpacing; int effectValCellSpacing; + int doubleClickColumn; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -1048,6 +1049,7 @@ class FurnaceGUI { volCellSpacing(0), effectCellSpacing(0), effectValCellSpacing(0), + doubleClickColumn(1), maxUndoSteps(100), mainFontPath(""), patFontPath(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 78c81e2cb..8176c6be6 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -404,6 +404,11 @@ void FurnaceGUI::drawSettings() { settings.cursorMoveNoScroll=cursorMoveNoScrollB; } + bool doubleClickColumnB=settings.doubleClickColumn; + if (ImGui::Checkbox("Double click selects entire column",&doubleClickColumnB)) { + settings.doubleClickColumn=doubleClickColumnB; + } + bool allowEditDockingB=settings.allowEditDocking; if (ImGui::Checkbox("Allow docking editors",&allowEditDockingB)) { settings.allowEditDocking=allowEditDockingB; @@ -2009,7 +2014,7 @@ void FurnaceGUI::syncSettings() { settings.insCellSpacing=e->getConfInt("insCellSpacing",0); settings.volCellSpacing=e->getConfInt("volCellSpacing",0); settings.effectCellSpacing=e->getConfInt("effectCellSpacing",0); - settings.effectValCellSpacing=e->getConfInt("effectValCellSpacing",0); + settings.doubleClickColumn=e->getConfInt("doubleClickColumn",0); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -2092,6 +2097,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.volCellSpacing,0,32); clampSetting(settings.effectCellSpacing,0,32); clampSetting(settings.effectValCellSpacing,0,32); + clampSetting(settings.doubleClickColumn,0,1); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); if (settings.initialSys.size()<4) { @@ -2223,6 +2229,7 @@ void FurnaceGUI::commitSettings() { e->setConf("volCellSpacing",settings.volCellSpacing); e->setConf("effectCellSpacing",settings.effectCellSpacing); e->setConf("effectValCellSpacing",settings.effectValCellSpacing); + e->setConf("doubleClickColumn",settings.doubleClickColumn); // colors for (int i=0; i Date: Tue, 31 May 2022 10:11:39 +0900 Subject: [PATCH 5/7] Fix possible issue in horizontal scroll --- extern/imgui_patched/imgui_internal.h | 27 ++++++++----------- extern/imgui_patched/imgui_tables.cpp | 37 ++++++++++++--------------- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/extern/imgui_patched/imgui_internal.h b/extern/imgui_patched/imgui_internal.h index 3d6a3a1d0..be3ab9222 100644 --- a/extern/imgui_patched/imgui_internal.h +++ b/extern/imgui_patched/imgui_internal.h @@ -566,9 +566,8 @@ struct ImBitArray void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); } void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); } void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2) - bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } - ImBitArray& operator|=(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); return *this; } - bool operator&(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } + bool operator[](int n) const { return TestBit(n); } + bool operator&(int n) const { return TestBit(n); } bool operator==(ImBitArray const &a) const { for (int i = 0; i < ((BITCOUNT + 31) >> 5); ++i) @@ -614,23 +613,17 @@ struct IMGUI_API ImBitVector void SetBit(int n) { IM_ASSERT(n >= 0 && n < BitCount); ImBitArraySetBit(Storage.Data, n); } void SetBitRange(int n, int n2) { IM_ASSERT(n >= 0 && n < BitCount && n2 > n && n2 <= BitCount); ImBitArraySetBitRange(Storage.Data, n, n2); } // Works on range [n..n2) void ClearBit(int n) { IM_ASSERT(n >= 0 && n < BitCount); ImBitArrayClearBit(Storage.Data, n); } - bool operator[](int n) const { IM_ASSERT(n >= 0 && n < BitCount); return ImBitArrayTestBit(Storage.Data, n); } - ImBitVector& operator|=(int n) { IM_ASSERT(n >= 0 && n < BitCount); ImBitArraySetBit(Storage.Data, n); return *this; } - bool operator&(int n) const { IM_ASSERT(n >= 0 && n < BitCount); return ImBitArrayTestBit(Storage.Data, n); } - bool operator==(ImBitVector const &a) const + bool CheckEqual(ImBitVector const &a) const { for (int i = 0; i < ImMin((a.BitCount + 31) >> 5, (BitCount + 31) >> 5); ++i) if (Storage[i] != a.Storage[i]) return false; return true; } - bool operator!=(ImBitVector const &a) const - { - for (int i = 0; i < ImMin((a.BitCount + 31) >> 5, (BitCount + 31) >> 5); ++i) - if (Storage[i] == a.Storage[i]) - return false; - return true; - } + bool operator[](int n) const { return TestBit(n); } + bool operator&(int n) const { return TestBit(n); } + bool operator==(ImBitVector const &a) const { return CheckEqual(a); } + bool operator!=(ImBitVector const &a) const { return !CheckEqual(a); } }; // Helper: ImSpan<> @@ -2503,8 +2496,8 @@ struct IMGUI_API ImGuiTabBar #define IMGUI_TABLE_DRAW_CHANNELS(c) (4 + (c) * 2) // See TableSetupDrawChannels() // Our current column maximum is IMGUI_TABLE_MAX_COLUMNS but we may raise that in the future. -typedef ImS32 ImGuiTableColumnIdx; -typedef ImU32 ImGuiTableDrawChannelIdx; +typedef ImS16 ImGuiTableColumnIdx; +typedef ImU16 ImGuiTableDrawChannelIdx; // [Internal] sizeof() ~ 104 // We use the terminology "Enabled" to refer to a column that is not Hidden by user/api. @@ -2563,7 +2556,7 @@ struct ImGuiTableColumn PrevEnabledColumn = NextEnabledColumn = -1; SortOrder = -1; SortDirection = ImGuiSortDirection_None; - DrawChannelCurrent = DrawChannelFrozen = DrawChannelUnfrozen = (ImU32)-1; + DrawChannelCurrent = DrawChannelFrozen = DrawChannelUnfrozen = (ImU16)-1; } }; diff --git a/extern/imgui_patched/imgui_tables.cpp b/extern/imgui_patched/imgui_tables.cpp index 6aea054eb..5a21a0b13 100644 --- a/extern/imgui_patched/imgui_tables.cpp +++ b/extern/imgui_patched/imgui_tables.cpp @@ -797,8 +797,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) else table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n; column->IndexWithinEnabledSet = table->ColumnsEnabledCount++; - table->EnabledMaskByIndex |= column_n; - table->EnabledMaskByDisplayOrder |= column->DisplayOrder; + table->EnabledMaskByIndex.SetBit(column_n); + table->EnabledMaskByDisplayOrder.SetBit(column->DisplayOrder); prev_visible_column_idx = column_n; IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); @@ -846,7 +846,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - if (!(table->EnabledMaskByIndex & column_n)) + if (!table->EnabledMaskByIndex.TestBit(column_n)) continue; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -862,7 +862,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) if (column->AutoFitQueue != 0x00) column->WidthRequest = width_auto; - else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex & column_n)) + else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex.TestBit(column_n))) column->WidthRequest = width_auto; // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets @@ -909,7 +909,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - if (!(table->EnabledMaskByIndex & column_n)) + if (!table->EnabledMaskByIndex.TestBit(column_n)) continue; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -936,7 +936,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths)) for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) { - if (!(table->EnabledMaskByDisplayOrder & order_n)) + if (!table->EnabledMaskByDisplayOrder.TestBit(order_n)) continue; ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]]; if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch)) @@ -977,7 +977,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Clear status flags column->Flags &= ~ImGuiTableColumnFlags_StatusMask_; - if ((table->EnabledMaskByDisplayOrder & order_n) == 0) + if (!table->EnabledMaskByDisplayOrder.TestBit(order_n)) { // Hidden column: clear a few fields and we are done with it for the remainder of the function. // We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper. @@ -1030,12 +1030,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y); const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY; if (is_visible) - table->VisibleMaskByIndex |= column_n; + table->VisibleMaskByIndex.SetBit(column_n); // Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output. column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0; if (column->IsRequestOutput) - table->RequestOutputMaskByIndex |= column_n; + table->RequestOutputMaskByIndex.SetBit(column_n); // Mark column as SkipItems (ignoring all items/layout) column->IsSkipItems = !column->IsEnabled || table->HostSkipItems; @@ -1163,7 +1163,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table) for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { - if (!(table->EnabledMaskByDisplayOrder & order_n)) + if (!table->EnabledMaskByDisplayOrder.TestBit(order_n)) continue; const int column_n = table->DisplayOrderToIndex[order_n]; @@ -1299,7 +1299,7 @@ void ImGui::EndTable() float auto_fit_width_for_stretched = 0.0f; float auto_fit_width_for_stretched_min = 0.0f; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - if (table->EnabledMaskByIndex & column_n) + if (table->EnabledMaskByIndex.TestBit(column_n)) { ImGuiTableColumn* column = &table->Columns[column_n]; float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column); @@ -1645,7 +1645,7 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n return; if (column_n == -1) column_n = table->CurrentColumn; - if ((table->VisibleMaskByIndex & column_n) == 0) + if (!table->VisibleMaskByIndex.TestBit(column_n)) return; if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n) table->RowCellDataCurrent++; @@ -1920,7 +1920,7 @@ bool ImGui::TableSetColumnIndex(int column_n) // Return whether the column is visible. User may choose to skip submitting items based on this return value, // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. - return (table->RequestOutputMaskByIndex & column_n) != 0; + return table->RequestOutputMaskByIndex.TestBit(column_n); } // [Public] Append into the next column, wrap and create a new row when already on last column @@ -1946,7 +1946,7 @@ bool ImGui::TableNextColumn() // Return whether the column is visible. User may choose to skip submitting items based on this return value, // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. int column_n = table->CurrentColumn; - return (table->RequestOutputMaskByIndex & column_n) != 0; + return table->RequestOutputMaskByIndex.TestBit(column_n); } @@ -1998,11 +1998,6 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n) { // FIXME-TABLE: Could avoid this if draw channel is dummy channel? SetWindowClipRectBeforeSetChannel(window, column->ClipRect); - if (column->DrawChannelCurrent==(ImGuiTableDrawChannelIdx)-1) { - // temporary workaround for #502 - //printf("sorry!\n"); - column->DrawChannelCurrent=column_n; - } table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); } @@ -2380,7 +2375,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) // 1. Scan channels and take note of those which can be merged for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - if ((table->VisibleMaskByIndex & column_n) == 0) + if (!table->VisibleMaskByIndex.TestBit(column_n)) continue; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -2544,7 +2539,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) { for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { - if (!(table->EnabledMaskByDisplayOrder & order_n)) + if (!table->EnabledMaskByDisplayOrder.TestBit(order_n)) continue; const int column_n = table->DisplayOrderToIndex[order_n]; From 2119675b100a63be7b942070f369120a1774402b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 30 May 2022 21:21:42 -0500 Subject: [PATCH 6/7] OPN: fix 11xx not working on ExtCh issue #503 --- src/engine/platform/genesisext.cpp | 5 +++++ src/engine/platform/ym2203ext.cpp | 5 +++++ src/engine/platform/ym2608ext.cpp | 5 +++++ src/engine/platform/ym2610bext.cpp | 5 +++++ src/engine/platform/ym2610ext.cpp | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 4d4935b5f..cc4abc88b 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -179,6 +179,11 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { rWrite(0x22,lfoValue); break; } + case DIV_CMD_FM_FB: { + chan[2].state.fb=c.value&7; + rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); + break; + } case DIV_CMD_FM_MULT: { // TODO unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index 929687fe4..95937207d 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -155,6 +155,11 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) { rWrite(0x22,(c.value&7)|((c.value>>4)<<3)); break; } + case DIV_CMD_FM_FB: { + chan[2].state.fb=c.value&7; + rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); + break; + } case DIV_CMD_FM_MULT: { // TODO unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index 285e350de..441640b45 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -155,6 +155,11 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) { rWrite(0x22,(c.value&7)|((c.value>>4)<<3)); break; } + case DIV_CMD_FM_FB: { + chan[2].state.fb=c.value&7; + rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); + break; + } case DIV_CMD_FM_MULT: { // TODO unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 20b56c018..cd7e494b9 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -155,6 +155,11 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { rWrite(0x22,(c.value&7)|((c.value>>4)<<3)); break; } + case DIV_CMD_FM_FB: { + chan[2].state.fb=c.value&7; + rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); + break; + } case DIV_CMD_FM_MULT: { // TODO unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index a3d5df21d..bf6df44e7 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -155,6 +155,11 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { rWrite(0x22,(c.value&7)|((c.value>>4)<<3)); break; } + case DIV_CMD_FM_FB: { + chan[1].state.fb=c.value&7; + rWrite(chanOffs[1]+ADDR_FB_ALG,(chan[1].state.alg&7)|(chan[1].state.fb<<3)); + break; + } case DIV_CMD_FM_MULT: { // TODO unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); From fc0a51ed5673ed8c50ac12e102ed55e3ba4bc69b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 30 May 2022 21:40:07 -0500 Subject: [PATCH 7/7] GUI: add oscilloscope window size setting and also remember last zoom/winSize value --- src/engine/engine.cpp | 3 +++ src/gui/gui.cpp | 8 ++++++++ src/gui/gui.h | 1 + src/gui/osc.cpp | 16 ++++++++++++---- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index bee45e4b3..6a23663ab 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2973,6 +2973,9 @@ bool DivEngine::init() { oscBuf[0]=new float[32768]; oscBuf[1]=new float[32768]; + memset(oscBuf[0],0,32768*sizeof(float)); + memset(oscBuf[1],0,32768*sizeof(float)); + initDispatch(); renderSamples(); reset(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 40f00e91e..50729a155 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3927,6 +3927,9 @@ bool FurnaceGUI::init() { if (orderEditMode<0) orderEditMode=0; if (orderEditMode>3) orderEditMode=3; + oscZoom=e->getConfFloat("oscZoom",0.5f); + oscWindowSize=e->getConfFloat("oscWindowSize",20.0f); + pianoOctaves=e->getConfInt("pianoOctaves",pianoOctaves); pianoOctavesEdit=e->getConfInt("pianoOctavesEdit",pianoOctavesEdit); pianoOptions=e->getConfBool("pianoOptions",pianoOptions); @@ -4137,6 +4140,10 @@ bool FurnaceGUI::finish() { e->setConf("followPattern",followPattern); e->setConf("orderEditMode",orderEditMode); + // commit oscilloscope state + e->setConf("oscZoom",oscZoom); + e->setConf("oscWindowSize",oscWindowSize); + // commit piano state e->setConf("pianoOctaves",pianoOctaves); e->setConf("pianoOctavesEdit",pianoOctavesEdit); @@ -4422,6 +4429,7 @@ FurnaceGUI::FurnaceGUI(): openSampleFilterOpt(false), oscTotal(0), oscZoom(0.5f), + oscWindowSize(20.0f), oscZoomSlider(false), chanOscCols(3), chanOscWindowSize(20.0f), diff --git a/src/gui/gui.h b/src/gui/gui.h index 2c6d54b00..e62311c12 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1240,6 +1240,7 @@ class FurnaceGUI { int oscTotal; float oscValues[512]; float oscZoom; + float oscWindowSize; bool oscZoomSlider; // per-channel oscilloscope diff --git a/src/gui/osc.cpp b/src/gui/osc.cpp index f85a323d6..406d3ccce 100644 --- a/src/gui/osc.cpp +++ b/src/gui/osc.cpp @@ -21,9 +21,6 @@ #include "imgui_internal.h" #include -// TODO: -// - potentially move oscilloscope seek position to the end, and read the last samples -// - this allows for setting up the window size void FurnaceGUI::readOsc() { int writePos=e->oscWritePos; int readPos=e->oscReadPos; @@ -47,8 +44,11 @@ void FurnaceGUI::readOsc() { total=oscTotal+(bias>>6); if (total>avail) total=avail; //printf("total: %d. avail: %d bias: %d\n",total,avail,bias); + + int winSize=e->getAudioDescGot().rate*(oscWindowSize/1000.0); + int oscReadPos=(writePos-winSize)&0x7fff; for (int i=0; i<512; i++) { - int pos=(readPos+(i*total/512))&0x7fff; + int pos=(oscReadPos+(i*winSize/512))&0x7fff; oscValues[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f; if (oscValues[i]>0.001f || oscValues[i]<-0.001f) { WAKE_UP; @@ -97,6 +97,14 @@ void FurnaceGUI::drawOsc() { if (oscZoom>2.0) oscZoom=2.0; } ImGui::SameLine(); + if (ImGui::VSliderFloat("##OscWinSize",ImVec2(20.0f*dpiScale,ImGui::GetContentRegionAvail().y),&oscWindowSize,5.0,100.0)) { + if (oscWindowSize<5.0) oscWindowSize=5.0; + if (oscWindowSize>100.0) oscWindowSize=100.0; + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { + oscWindowSize=20.0; + } + ImGui::SameLine(); } ImDrawList* dl=ImGui::GetWindowDrawList();