diff --git a/CMakeLists.txt b/CMakeLists.txt index cb10356..f7365d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,14 +36,16 @@ if(NOT GIT_HASH) endif() execute_process( - COMMAND git rev-list --count HEAD + COMMAND git status --porcelain WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_LOCAL_COMMITS + OUTPUT_VARIABLE GIT_STATUS OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) -if(NOT GIT_LOCAL_COMMITS) - set(GIT_LOCAL_COMMITS "0") +if(GIT_STATUS STREQUAL "") + set(GIT_DIRTY "clean") +else() + set(GIT_DIRTY "dirty") endif() string(TIMESTAMP BUILD_TIME "%Y-%m-%d %H:%M:%S") diff --git a/README.md b/README.md index f5a17f0..98f722c 100644 --- a/README.md +++ b/README.md @@ -60,10 +60,10 @@ make install # build, codesign, un-quarantine, install to ~/Library/Audio/Plu | Parameter | Range | Description | |---|---|---| | Fade | 0.1 – 10 s | Trail persistence time | -| Sensitivity | -12 – +24 dB | Input gain for M/S decode | -| Dot size | 0.5 – 8.0 px | Size of each plotted point | -| Smoothing | 0 – 0.99 | One-pole smoothing on M/S signals | -| Afterglow | 0 – 5 s | Extra lingers of the trail after the fade time | +| Response | -12 – +24 dB | Input gain for M/S decode | +| Size | 0.5 – 8.0 px | Size of each plotted point | +| Smooth | 0 – 0.99 | One-pole smoothing on M/S signals | +| Glow | 0 – 5 s | Extra lingers of the trail after the fade time | | Freeze | on/off | Stop capturing new points | ## Project structure diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 3958a9c..b0a205a 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -47,7 +47,7 @@ TerionProcessorEditor::TerionProcessorEditor(TerionProcessor& p) // Freeze button addAndMakeVisible(freezeButton); - freezeButton.setButtonText("FRZ"); + freezeButton.setButtonText("Freeze"); freezeButton.setColour(juce::ToggleButton::textColourId, juce::Colour(0xff888899)); freezeButton.setColour(juce::ToggleButton::tickColourId, juce::Colour(0xff7ecfcf)); freezeAttachment = std::make_unique( @@ -55,7 +55,7 @@ TerionProcessorEditor::TerionProcessorEditor(TerionProcessor& p) // Mono button addAndMakeVisible(monoButton); - monoButton.setButtonText("MONO"); + monoButton.setButtonText("Mono"); monoButton.setColour(juce::ToggleButton::textColourId, juce::Colour(0xff888899)); monoButton.setColour(juce::ToggleButton::tickColourId, juce::Colour(0xff7ecfcf)); monoAttachment = std::make_unique( @@ -133,10 +133,10 @@ void TerionProcessorEditor::paint(juce::Graphics& g) g.setColour(juce::Colour(0xff555566)); g.setFont(juce::Font(juce::FontOptions(9.0f * s))); - juce::String footerText = "Terion " + juce::String footerText = "Terion (Git: " + juce::String(TERION_GIT_HASH) - + " | " + juce::String(TERION_BUILD_TIME) - + " | " + juce::String(TERION_GIT_LOCAL_COMMITS) + " local"; + + ", " + juce::String(TERION_GIT_DIRTY) + + ") | built: " + juce::String(TERION_BUILD_TIME); g.drawFittedText(footerText, footer.reduced(static_cast(10.0f * s), 0), juce::Justification::centredLeft, 1); @@ -149,20 +149,18 @@ void TerionProcessorEditor::resized() const int knobs = static_cast(kKnobSize * s); const int margin = static_cast(kKnobMargin * s); const int scaleW = static_cast(76.0f * s); - const int monoW = static_cast(72.0f * s); + const int gap = static_cast(8.0f * s); auto bounds = getLocalBounds(); auto footer = bounds.removeFromBottom(footerH); - // Footer: scale dropdown + mono toggle on the right - scaleBox.setBounds(footer.getWidth() - scaleW, 1, scaleW, footerH - 2); - monoButton.setBounds(footer.getWidth() - scaleW - monoW, 1, monoW, footerH - 2); + // Footer: scale dropdown with an 8px gap on the top and right + scaleBox.setBounds(footer.getWidth() - scaleW - gap, gap, scaleW, footerH - 2 - gap); // Scope fills the remaining area scope.setBounds(bounds); - // Controls layout: knob row sits 8px above the footer, FRZ stays top-right - const int gap = static_cast(8.0f * s); + // Controls layout: knob row sits 8px above the footer, Freeze/Mono stay top-right const int numKnobs = 5; const int rowH = knobs + static_cast(12.0f * s) - static_cast(6.0f * s); const int startX = bounds.getWidth() - (numKnobs * (knobs + margin) + knobs + margin); @@ -173,8 +171,11 @@ void TerionProcessorEditor::resized() dotSizeKnob.setBounds(startX + 2 * (knobs + margin), startY, knobs, knobs); smoothingKnob.setBounds(startX + 3 * (knobs + margin), startY, knobs, knobs); afterglowKnob.setBounds(startX + 4 * (knobs + margin), startY, knobs, knobs); - freezeButton.setBounds(bounds.getWidth() - knobs - margin, static_cast(20.0f * s), - knobs, knobs - static_cast(20.0f * s)); + const int freezeY = static_cast(20.0f * s); + const int freezeH = knobs - static_cast(20.0f * s); + freezeButton.setBounds(bounds.getWidth() - knobs - margin, freezeY, knobs, freezeH); + monoButton.setBounds(bounds.getWidth() - knobs - margin, freezeY + freezeH + gap, + knobs, freezeH); const int labelY = startY + knobs - static_cast(6.0f * s); const int labelH = static_cast(12.0f * s); diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 2e852b2..921785d 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -8,22 +8,22 @@ TerionProcessor::TerionProcessor() apvts(*this, nullptr, "Parameters", { std::make_unique( juce::ParameterID{"fadeTime", 1}, - "Fade Time", + "Fade", juce::NormalisableRange(0.1f, 10.0f, 0.01f, 0.4f), 2.0f), std::make_unique( juce::ParameterID{"sensitivity", 2}, - "Sensitivity", + "Response", juce::NormalisableRange(-12.0f, 24.0f, 0.1f, 0.5f), 0.0f), std::make_unique( juce::ParameterID{"dotSize", 3}, - "Dot Size", + "Size", juce::NormalisableRange(0.5f, 8.0f, 0.1f, 0.5f), 1.0f), std::make_unique( juce::ParameterID{"smoothing", 4}, - "Smoothing", + "Smooth", juce::NormalisableRange(0.0f, 0.99f, 0.01f, 0.5f), 0.0f), std::make_unique( @@ -36,7 +36,7 @@ TerionProcessor::TerionProcessor() false), std::make_unique( juce::ParameterID{"afterglow", 7}, - "Afterglow", + "Glow", juce::NormalisableRange(0.0f, 5.0f, 0.01f, 0.5f), 0.5f) }) diff --git a/Source/VectorScope.cpp b/Source/VectorScope.cpp index f86eb3a..cc20c1e 100644 --- a/Source/VectorScope.cpp +++ b/Source/VectorScope.cpp @@ -13,6 +13,14 @@ VectorScope::~VectorScope() void VectorScope::timerCallback() { + // Refresh the numeric readouts at kMetricsRateHz while keeping the trail + // animation running at the full 30 Hz. + const float frozen = processor.apvts.getRawParameterValue("freeze")->load(); + if (frozen < 0.5f && ++metricFrame >= 30 / kMetricsRateHz) + { + metricFrame = 0; + cachedMetrics = processor.getMetrics(); + } repaint(); } @@ -183,7 +191,7 @@ void VectorScope::drawLegends(juce::Graphics& g, float cx, float cy, float radiu void VectorScope::drawMetricsOverlay(juce::Graphics& g, const juce::Rectangle& bounds) { - const auto& metrics = processor.getMetrics(); + const auto& metrics = cachedMetrics; const float s = currentScale; const int margin = static_cast(10.0f * s); const int lineHeight = static_cast(14.0f * s); @@ -217,6 +225,6 @@ void VectorScope::drawMetricsOverlay(juce::Graphics& g, const juce::Rectangle