From ac68419b785dc2e3a8d6ffe6c7b0b01c6ef5105e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 01:18:41 -0500 Subject: [PATCH] implement KVS on YM2612 --- TODO.md | 4 --- src/engine/fileOps.cpp | 12 ++++++++ src/engine/platform/fmsharedbase.h | 2 ++ src/engine/platform/genesis.cpp | 16 +++++------ src/gui/gui.h | 1 + src/gui/insEdit.cpp | 46 ++++++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 12 deletions(-) diff --git a/TODO.md b/TODO.md index 84bc08a73..8b1378917 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1 @@ -# to-do for 0.6pre1.5 -- stereo separation control for AY -- KVS -- bug fixes diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 4c213744b..7da21f4fa 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -196,6 +196,15 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } */ + // Genesis detuned on Defle v10 and earlier + /*if (ds.version<19 && ds.system[0]==DIV_SYSTEM_GENESIS) { + ds.tuning=443.23; + }*/ + // C64 detuned on Defle v11 and earlier + /*if (ds.version<21 && (ds.system[0]==DIV_SYSTEM_C64_6581 || ds.system[0]==DIV_SYSTEM_C64_8580)) { + ds.tuning=433.2; + }*/ + logI("reading module data..."); if (ds.version>0x0c) { ds.subsong[0]->hilightA=reader.readC(); @@ -449,6 +458,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->fm.op[j].ssgEnv=reader.readC(); } } + if (ds.version<0x12) { // before version 10 all ops were responsive to volume + ins->fm.op[j].kvs=1; + } logD("OP%d: AM %d AR %d DAM %d DR %d DVB %d EGT %d KSL %d MULT %d RR %d SL %d SUS %d TL %d VIB %d WS %d RS %d DT %d D2R %d SSG-EG %d",j, ins->fm.op[j].am, diff --git a/src/engine/platform/fmsharedbase.h b/src/engine/platform/fmsharedbase.h index 640997392..15baacefa 100644 --- a/src/engine/platform/fmsharedbase.h +++ b/src/engine/platform/fmsharedbase.h @@ -23,6 +23,8 @@ #include "../dispatch.h" #include +#define KVS(x,y) ((chan[x].state.op[y].kvs==2 && isOutput[chan[x].state.alg][y]) || chan[x].state.op[y].kvs==1) + class DivPlatformFMBase: public DivDispatch { protected: const bool isOutput[8][4]={ diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 515f0c0ae..d289a3515 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -254,7 +254,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -327,7 +327,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -384,7 +384,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -501,7 +501,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[ch].state.alg][j]) { + if (KVS(ch,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -614,7 +614,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -687,7 +687,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -860,7 +860,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -1051,7 +1051,7 @@ void DivPlatformGenesis::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/gui/gui.h b/src/gui/gui.h index 77a127595..80b550401 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1603,6 +1603,7 @@ class FurnaceGUI { void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, const ImVec2& size, unsigned short instType); void drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size); void drawSysConf(int chan, DivSystem type, unsigned int& flags, bool modifyOnChange); + void kvsConfig(DivInstrument* ins); // these ones offer ctrl-wheel fine value changes. bool CWSliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format=NULL, ImGuiSliderFlags flags=0); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 31dfdb357..d08e276a7 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1211,6 +1211,46 @@ inline bool enBit30(const int val) { return false; } + +void FurnaceGUI::kvsConfig(DivInstrument* ins) { + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("(click to configure KVS)"); + } + int opCount=4; + if (ins->type==DIV_INS_OPLL) opCount=2; + if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; + if (ImGui::BeginPopupContextItem("IKVSOpt",ImGuiPopupFlags_MouseButtonLeft)) { + ImGui::Text("operator level changes with volume?"); + if (ImGui::BeginTable("KVSTable",4,ImGuiTableFlags_BordersInner)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); + for (int i=0; i<4; i++) { + int o=(opCount==4)?orderedOps[i]:i; + if (!(i&1)) ImGui::TableNextRow(); + const char* label="AUTO##OPKVS"; + if (ins->fm.op[o].kvs==0) { + label="NO##OPKVS"; + } else if (ins->fm.op[o].kvs==1) { + label="YES##OPKVS"; + } + ImGui::TableNextColumn(); + ImGui::Text("%d",i+1); + ImGui::TableNextColumn(); + ImGui::PushID(o); + if (ImGui::Button(label,ImVec2(ImGui::GetContentRegionAvail().x,0.0f))) { + if (++ins->fm.op[o].kvs>2) ins->fm.op[o].kvs=0; + PARAMETER; + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::EndPopup(); + } +} + void FurnaceGUI::drawMacros(std::vector& macros) { float asFloat[256]; int asInt[256]; @@ -1769,6 +1809,7 @@ void FurnaceGUI::drawInsEdit() { P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + kvsConfig(ins); break; case DIV_INS_OPZ: ImGui::TableNextColumn(); @@ -1781,6 +1822,8 @@ void FurnaceGUI::drawInsEdit() { P(CWSliderScalar(FM_NAME(FM_AMS2),ImGuiDataType_U8,&ins->fm.ams2,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + kvsConfig(ins); + if (ImGui::Button("Request from TX81Z")) { doAction(GUI_ACTION_TX81Z_REQUEST); } @@ -1813,6 +1856,7 @@ void FurnaceGUI::drawInsEdit() { } ImGui::TableNextColumn(); drawAlgorithm(ins->fm.alg&algMax,fourOp?FM_ALGS_4OP_OPL:FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + kvsConfig(ins); break; } case DIV_INS_OPLL: { @@ -1837,6 +1881,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndDisabled(); ImGui::TableNextColumn(); drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); + kvsConfig(ins); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); bool isPresent[4];