From 39001dcb6a53f7a9a299b84180729876f6b1d4e4 Mon Sep 17 00:00:00 2001 From: Kagamiin~ Date: Mon, 16 Oct 2023 16:57:04 -0300 Subject: [PATCH] Adding operator routing visualization --- src/engine/sysDef.cpp | 4 +- src/gui/gui.h | 1 + src/gui/insEdit.cpp | 111 +++++++++++++++++++++++++++++++++++--- src/gui/sysConf.cpp | 1 + src/gui/sysPartNumber.cpp | 2 + 5 files changed, 111 insertions(+), 8 deletions(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 769650723..1773ad4a6 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1920,8 +1920,8 @@ void DivEngine::registerSystems() { // TODO: ask Tilde to standardize! sysDefs[DIV_SYSTEM_ESFM]=new DivSysDef( - "ESFM (TODO: gimme a better name)", NULL, 0xd0, 0, 18, true, false, 0, false, 0, - "TODO: give ESFM the beautiful description it deserves", + "ESS ES1xxx-series (ESFM)", NULL, 0xd0, 0, 18, true, false, 0, false, 0, + "A unique FM synth featured in PC sound cards.\nBased on the OPL3 design, but with lots of its features extended.", {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "FM 10", "FM 11", "FM 12", "FM 13", "FM 14", "FM 15", "FM 16", "FM 17", "FM 18"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, diff --git a/src/gui/gui.h b/src/gui/gui.h index 0cff7b595..b450be196 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -2209,6 +2209,7 @@ class FurnaceGUI { void drawSSGEnv(unsigned char type, const ImVec2& size); void drawWaveform(unsigned char type, bool opz, const ImVec2& size); void drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, const ImVec2& size); + void drawESFMAlgorithm(DivInstrumentESFM& esfm, const ImVec2& size); 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, float maxRr, const ImVec2& size, unsigned short instType); void drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size); bool drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& flags, bool modifyOnChange, bool fromMenu=false); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 63600289e..f1b8ecabe 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1164,6 +1164,110 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons } } +void FurnaceGUI::drawESFMAlgorithm(DivInstrumentESFM& esfm, const ImVec2& size) { + ImDrawList* dl=ImGui::GetWindowDrawList(); + ImGuiWindow* window=ImGui::GetCurrentWindow(); + + ImVec2 minArea=window->DC.CursorPos; + ImVec2 maxArea=ImVec2( + minArea.x+size.x, + minArea.y+size.y + ); + ImRect rect=ImRect(minArea,maxArea); + ImGuiStyle& style=ImGui::GetStyle(); + ImU32 colorM=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_MOD]); + ImU32 colorC=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_CAR]); + ImU32 colorsL[8]; + for (int i=0; i<8; i++){ + float alpha=(float)i/7.0f; + ImVec4 color=uiColors[GUI_COLOR_FM_ALG_LINE]; + color.w *= alpha; + colorsL[i]=ImGui::GetColorU32(color); + } + ImGui::ItemSize(size,style.FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID("alg"))) { + ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ALG_BG]),true,style.FrameRounding); + const float circleRadius=6.0f*dpiScale+1.0f; + //int modFb = esfm.op[0].modIn&7; + int mod12 = esfm.op[1].modIn&7; + int mod23 = esfm.op[2].modIn&7; + int mod34 = esfm.op[3].modIn&7; + int out1 = esfm.op[0].outLvl&7; + int out2 = esfm.op[1].outLvl&7; + int out3 = esfm.op[2].outLvl&7; + int out4 = esfm.op[3].outLvl&7; + bool isMod[4]; + for (int i=0; i<4; i++) { + DivInstrumentESFM::Operator& opE = esfm.op[i]; + isMod[i]=true; + if (opE.outLvl==7) isMod[i]=false; + else if (opE.outLvl>0) { + if (i==3) isMod[i]=false; + else { + DivInstrumentESFM::Operator& opENext=esfm.op[i+1]; + if (opENext.modIn==0) isMod[i]=false; + else if ((opE.outLvl-opENext.modIn) >= 2) isMod[i]=false; + } + } + } + + ImVec2 posOp1=ImLerp(rect.Min,rect.Max,ImVec2(0.2f,0.25f)); + ImVec2 posOp2=ImLerp(rect.Min,rect.Max,ImVec2(0.4f,0.25f)); + ImVec2 posOp3=ImLerp(rect.Min,rect.Max,ImVec2(0.6f,0.25f)); + ImVec2 posOp4=ImLerp(rect.Min,rect.Max,ImVec2(0.8f,0.25f)); + ImVec2 posBusbarOp1=ImLerp(rect.Min,rect.Max,ImVec2(0.2f,0.75f)); + ImVec2 posBusbarOp2=ImLerp(rect.Min,rect.Max,ImVec2(0.4f,0.75f)); + ImVec2 posBusbarOp3=ImLerp(rect.Min,rect.Max,ImVec2(0.6f,0.75f)); + ImVec2 posBusbarOp4=ImLerp(rect.Min,rect.Max,ImVec2(0.8f,0.75f)); + + ImVec2 posBusbarStart=ImLerp(rect.Min,rect.Max,ImVec2(0.15f,0.75f)); + ImVec2 posBusbarEnd=ImLerp(rect.Min,rect.Max,ImVec2(0.85f,0.75f)); + bool busbarStartSeen=false; + for (int i=0; i<4; i++) { + DivInstrumentESFM::Operator& opE=esfm.op[i]; + if (opE.outLvl>0) { + if (!busbarStartSeen) { + busbarStartSeen=true; + posBusbarStart=ImLerp(rect.Min,rect.Max,ImVec2(0.15f+0.2f*i,0.75f)); + } + posBusbarEnd=ImLerp(rect.Min,rect.Max,ImVec2(0.25f+0.2f*i,0.75f)); + } + } + + if (mod12) addAALine(dl,posOp1,posOp2,colorsL[mod12]); + if (mod23) addAALine(dl,posOp2,posOp3,colorsL[mod23]); + if (mod34) addAALine(dl,posOp3,posOp4,colorsL[mod34]); + if (out1) addAALine(dl,posOp1,posBusbarOp1,colorsL[out1]); + if (out2) addAALine(dl,posOp2,posBusbarOp2,colorsL[out2]); + if (out3) addAALine(dl,posOp3,posBusbarOp3,colorsL[out3]); + if (out4) addAALine(dl,posOp4,posBusbarOp4,colorsL[out4]); + + addAALine(dl,posBusbarStart,posBusbarEnd,colorsL[2]); + // addAALine(dl,posBusbarEnd,posBusbarEnd+ImVec2(-8.0f*dpiScale,-4.0f*dpiScale),colorsL[2]); + // addAALine(dl,posBusbarEnd,posBusbarEnd+ImVec2(-8.0f*dpiScale,4.0f*dpiScale),colorsL[2]); + // addAALine(dl,posBusbarStart+ImVec2(4.0f*dpiScale,-4.0f*dpiScale),posBusbarStart+ImVec2(4.0f*dpiScale,4.0f*dpiScale),colorsL[2]); + + dl->AddCircle(posOp1,6.0f*dpiScale+1.0f,isMod[0]?colorM:colorC); + dl->AddCircleFilled(posOp1,4.0f*dpiScale+1.0f,isMod[0]?colorM:colorC); + dl->AddCircleFilled(posOp2,4.0f*dpiScale+1.0f,isMod[1]?colorM:colorC); + dl->AddCircleFilled(posOp3,4.0f*dpiScale+1.0f,isMod[2]?colorM:colorC); + dl->AddCircleFilled(posOp4,4.0f*dpiScale+1.0f,isMod[3]?colorM:colorC); + + posOp1.x-=ImGui::CalcTextSize("1").x+circleRadius+3.0f*dpiScale; + posOp2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0f*dpiScale; + posOp3.x-=ImGui::CalcTextSize("3").x+circleRadius+3.0f*dpiScale; + posOp4.x-=ImGui::CalcTextSize("4").x+circleRadius+3.0f*dpiScale; + posOp1.y-=ImGui::CalcTextSize("1").y*0.5f; + posOp2.y-=ImGui::CalcTextSize("2").y*0.5f; + posOp3.y-=ImGui::CalcTextSize("3").y*0.5f; + posOp4.y-=ImGui::CalcTextSize("4").y*0.5f; + dl->AddText(posOp1,isMod[0]?colorM:colorC,"1"); + dl->AddText(posOp2,isMod[1]?colorM:colorC,"2"); + dl->AddText(posOp3,isMod[2]?colorM:colorC,"3"); + dl->AddText(posOp4,isMod[3]?colorM:colorC,"4"); + } +} + void FurnaceGUI::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, float maxRr, const ImVec2& size, unsigned short instType) { ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); @@ -3182,10 +3286,6 @@ void FurnaceGUI::drawInsEdit() { } break; } - case DIV_INS_ESFM: { - // unreachable - break; - } default: break; } @@ -3212,8 +3312,7 @@ void FurnaceGUI::drawInsEdit() { WAKE_UP; } } else { - //drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); - ImGui::TextUnformatted("TODO: implement fancy ESFM\nauto algorithm drawing"); + drawESFMAlgorithm(ins->esfm, ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); } kvsConfig(ins); } diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index b8caa7390..813942d0c 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -2225,6 +2225,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl case DIV_SYSTEM_C219: break; case DIV_SYSTEM_YMU759: + case DIV_SYSTEM_ESFM: supportsCustomRate=false; ImGui::Text("nothing to configure"); break; diff --git a/src/gui/sysPartNumber.cpp b/src/gui/sysPartNumber.cpp index d71e65a98..3facab9cd 100644 --- a/src/gui/sysPartNumber.cpp +++ b/src/gui/sysPartNumber.cpp @@ -277,6 +277,8 @@ const char* FurnaceGUI::getSystemPartNumber(DivSystem sys, DivConfig& flags) { case DIV_SYSTEM_C219: return "C219"; break; + case DIV_SYSTEM_ESFM: + return "ES1xxx"; default: return FurnaceGUI::getSystemName(sys); break;