From 2108cffec227c0432c62eeab43efc88b95c7d0c4 Mon Sep 17 00:00:00 2001 From: Eknous-P Date: Fri, 10 Oct 2025 19:36:02 +0400 Subject: [PATCH] mixer: per-chp peak meters, fix almost every ui issue: - fix wrong verticaltext clipping - fix verticaltext overflow centering - add hscroll to mixer --- src/engine/engine.h | 3 +++ src/engine/playback.cpp | 30 ++++++++++++++++++++++++++++++ src/gui/gui.cpp | 8 +++++--- src/gui/mixer.cpp | 32 ++++++++++++++++++++++++-------- 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index a0e181c5d..b4dc29a75 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -698,6 +698,8 @@ class DivEngine { int lastNBIns, lastNBOuts, lastNBSize; std::atomic processTime; + float chipPeak[DIV_MAX_CHIPS][DIV_MAX_OUTPUTS]; + void runExportThread(); void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size); DivInstrument* getIns(int index, DivInstrumentType fallbackType=DIV_INS_FM); @@ -1542,6 +1544,7 @@ class DivEngine { memset(walked,0,8192); memset(oscBuf,0,DIV_MAX_OUTPUTS*(sizeof(float*))); memset(exportChannelMask,1,DIV_MAX_CHANS*sizeof(bool)); + memset(chipPeak,0,DIV_MAX_CHIPS*DIV_MAX_OUTPUTS*sizeof(float)); for (int i=0; igetOutputCount(); j++) { + chipPeak[i][j]*=1.0-decay; + float peak=chipPeak[i][j]; + for (unsigned int k=0; kgetPostAmp()/32768.0f; // TODO: PARSE PANNING, FRONT/REAR AND PATCHBAY + // switch (j) { + // case 0: + // out*=MIN(1.0f,1.0f-song.systemPan[i])*MIN(1.0f,1.0f+song.systemPanFR[i]); + // break; + // case 1: + // out*=MIN(1.0f,1.0f+song.systemPan[i])*MIN(1.0f,1.0f+song.systemPanFR[i]); + // break; + // case 2: + // out*=MIN(1.0f,1.0f-song.systemPan[i])*MIN(1.0f,1.0f-song.systemPanFR[i]); + // break; + // case 3: + // out*=MIN(1.0f,1.0f+song.systemPan[i])*MIN(1.0f,1.0f-song.systemPanFR[i]); + // break; + // default: break; + // } + if (out>peak) peak=out; + } + chipPeak[i][j]+=(peak-chipPeak[i][j])*0.9; + } + } + // force mono audio (if enabled) if (forceMono && outChans>1) { for (size_t i=0; iAddText(pos, ImGui::GetColorU32(ImGuiCol_Text), text); vtxEnd=dl->_VtxCurrentIdx; - ImGui::ShadeVertsTransformPos(dl, vtxBegin, vtxEnd, pos+ImVec2(size.x,0), 0, -1, pos); + ImGui::ShadeVertsTransformPos(dl, vtxBegin, vtxEnd, pos+ImVec2(size.x,0), 0, -1, ImGui::GetCursorScreenPos()); ImGui::Dummy(ImVec2(size.y,size.x)); } void FurnaceGUI::VerticalText(float maxSize, bool centered, const char* fmt, ...) { va_list args; va_start(args, fmt); - ImVec2 pos=ImGui::GetCursorScreenPos(); + ImVec2 pos=ImGui::GetWindowPos(); ImDrawList* dl=ImGui::GetWindowDrawList(); int vtxBegin, vtxEnd; vtxBegin=dl->_VtxCurrentIdx; @@ -466,10 +466,12 @@ void FurnaceGUI::VerticalText(float maxSize, bool centered, const char* fmt, ... vsnprintf(text, 4096, fmt, args); const char* textEol=ImGui::FindRenderedTextEnd(text); ImVec2 size=ImGui::CalcTextSize(text); + dl->PushClipRect(pos,pos+ImGui::GetWindowSize()); ImGui::RenderTextEllipsis(dl,pos,pos+ImVec2(maxSize,ImGui::GetFontSize()),maxSize,text,textEol,&size); + dl->PopClipRect(); vtxEnd=dl->_VtxCurrentIdx; float ySize=(size.x>maxSize)?maxSize:size.x; - ImGui::ShadeVertsTransformPos(dl, vtxBegin, vtxEnd, pos, 0, -1, pos+ImVec2(0,ySize+(centered?(maxSize-size.x)/2.0f:0))); + ImGui::ShadeVertsTransformPos(dl, vtxBegin, vtxEnd, pos, 0, -1, ImGui::GetCursorScreenPos()+ImVec2(0,(size.x+ySize)/2+(centered?(maxSize-size.x)/2.0f:0))); ImGui::Dummy(ImVec2(size.y,centered?maxSize:ySize)); } diff --git a/src/gui/mixer.cpp b/src/gui/mixer.cpp index d39a4777f..d9cabc2b9 100644 --- a/src/gui/mixer.cpp +++ b/src/gui/mixer.cpp @@ -229,16 +229,34 @@ void FurnaceGUI::drawMixer() { float maxY=ImGui::GetContentRegionAvail().y; VerticalText(maxY, true,_("Master Volume")); ImGui::SameLine(); + ImVec2 pos=ImGui::GetCursorScreenPos(); + drawVolMeterInternal(ImGui::GetWindowDrawList(), ImRect(pos,pos+ImVec2(40*dpiScale,maxY)),peak,e->getAudioDescGot().outChans,false); + ImGui::PushStyleColor(ImGuiCol_FrameBg,0); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive,0); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,127<song.masterVol,0,3,"%.2fx")) { if (e->song.masterVol<0) e->song.masterVol=0; if (e->song.masterVol>3) e->song.masterVol=3; MARK_MODIFIED; } rightClickable + ImGui::PopStyleColor(3); ImGui::SameLine(); - if (ImGui::BeginChild("##mixerPerChipContainer")) { - const float childWidth=60*dpiScale; + + const float itemWidth=60*dpiScale; + // figure out if we need to cut the height for the scrollbar + float calcWidth=(itemWidth+1.5f*ImGui::GetStyle().FramePadding.x+4*ImGui::GetStyle().FramePadding.x+dpiScale)*e->song.systemLen; + float realwidth=ImGui::GetWindowWidth()-ImGui::GetCursorPosX(); + if (calcWidth>realwidth) maxY-=ImGui::GetStyle().ScrollbarSize; + if (ImGui::BeginChild("##mixerPerChipContainer", ImVec2(0,0),0,ImGuiWindowFlags_HorizontalScrollbar)) { for (int i=0; isong.systemLen; i++) { - if (chipMixer(i, ImVec2(childWidth,maxY))) MARK_MODIFIED; + ImGui::GetWindowDrawList()->AddRectFilled( + ImGui::GetCursorScreenPos(), + ImGui::GetCursorScreenPos()+ImVec2(dpiScale,maxY), + ImGui::GetColorU32(ImGuiCol_Separator) + ); + ImGui::Dummy(ImVec2(dpiScale,maxY)); + ImGui::SameLine(); + if (chipMixer(i, ImVec2(itemWidth,maxY))) MARK_MODIFIED; ImGui::SameLine(); } } @@ -436,17 +454,14 @@ bool FurnaceGUI::chipMixer(int which, ImVec2 size) { ImGui::SameLine(); float vTextWidth=textHeight+2*ImGui::GetStyle().FramePadding.x; - // TODO: per-chip per-out peak - float volMeter[2]; - volMeter[0]=0.5; - volMeter[1]=0.5; ImGui::SetCursorPos(curPos); ImVec2 pos=ImGui::GetCursorScreenPos(); - drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(size.x-vTextWidth,volSliderHeight)),volMeter,2,false); + drawVolMeterInternal(ImGui::GetWindowDrawList(),ImRect(pos,pos+ImVec2(size.x-vTextWidth,volSliderHeight)),e->chipPeak[which],e->getDispatch(which)->getOutputCount(),false); ImGui::PushStyleColor(ImGuiCol_FrameBg,0); ImGui::PushStyleColor(ImGuiCol_FrameBgActive,0); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered,127<