From d3bf0804e10058461811cb84702559019ff1b0bb Mon Sep 17 00:00:00 2001 From: Armin Date: Mon, 14 Sep 2026 02:42:22 +0200 Subject: [PATCH] fix chorus popSample read pointer drift; show welcome only on first open --- Source/LcdPanel.cpp | 28 +++++++++++++++++++++++++++- Source/LcdPanel.h | 2 ++ Source/PluginProcessor.cpp | 11 +++++++---- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Source/LcdPanel.cpp b/Source/LcdPanel.cpp index b6c5343..70dc3fb 100644 --- a/Source/LcdPanel.cpp +++ b/Source/LcdPanel.cpp @@ -185,7 +185,14 @@ LcdPanel::LcdPanel (RMX19AudioProcessor& p) presentImage = juce::Image (juce::Image::ARGB, gridW * presentScale, gridH * presentScale, false); backdrop = juce::Image (juce::Image::ARGB, gridW * subsample, gridH * subsample, false); buildBackdrop(); - splashUntil = juce::Time::getMillisecondCounter() + 1500; + if (firstRunEver()) + { + splashUntil = juce::Time::getMillisecondCounter() + 1500; + } + else + { + screen = Screen::Home; + } lastMidi = proc.getLastMidiTime(); startTimerHz (22); } @@ -195,6 +202,25 @@ LcdPanel::~LcdPanel() stopTimer(); } +// The welcome splash plays only on the very first plugin open ever. A small +// flag file under the user's Application Support dir records that it was shown, +// so later instances start directly on the Home screen. +static juce::File welcomeFlagFile() +{ + return juce::File::getSpecialLocation (juce::File::userApplicationDataDirectory) + .getChildFile ("RMX-19").getChildFile ("welcome.seen"); +} + +bool LcdPanel::firstRunEver() +{ + auto flag = welcomeFlagFile(); + if (flag.exists()) + return false; + flag.getParentDirectory().createDirectory(); + flag.replaceWithText ("seen"); + return true; +} + void LcdPanel::timerCallback() { bool needsRedraw = (screen == Screen::Splash); diff --git a/Source/LcdPanel.h b/Source/LcdPanel.h index c11a55c..541c541 100644 --- a/Source/LcdPanel.h +++ b/Source/LcdPanel.h @@ -18,6 +18,8 @@ public: void resetToHome(); + static bool firstRunEver(); + static constexpr int gridW = 160; // dot-matrix cell resolution static constexpr int gridH = 64; // internal supersampling: dots are rasterized as anti-aliased circles at 4x, diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 3eeb696..55a9b17 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -81,10 +81,13 @@ public: chorusL.pushSample (0, inL); chorusR.pushSample (0, inR); - const float mL = 0.5f * (chorusL.popSample (0, chBase + chDepth * t1) - + chorusL.popSample (0, chBase + chDepth * t2)); - const float mR = 0.5f * (chorusR.popSample (0, chBase + chDepth * t2) - + chorusR.popSample (0, chBase + chDepth * t3)); + // multi-tap: only the first popSample advances the read pointer, + // otherwise one push + two pops drifts the taps through the whole + // buffer and late-stale echoes of old notes come back (octave up). + const float mL = 0.5f * (chorusL.popSample (0, chBase + chDepth * t1, true) + + chorusL.popSample (0, chBase + chDepth * t2, false)); + const float mR = 0.5f * (chorusR.popSample (0, chBase + chDepth * t2, true) + + chorusR.popSample (0, chBase + chDepth * t3, false)); outL += mL * wet * 0.8f; outR += mR * wet * 0.8f; }