Skip to content

Add level meters and improve timer responsiveness - #24

Merged
Skeyelab merged 4 commits into
mainfrom
cursor/FRE-8-add-audio-level-meters-to-ui-2e63
Oct 24, 2025
Merged

Skeyelab merged 4 commits into
mainfrom
cursor/FRE-8-add-audio-level-meters-to-ui-2e63

Conversation

@Skeyelab

Copy link
Copy Markdown
Member

Co-authored-by: eric eric@skeyelab.com

cursoragent and others added 2 commits October 23, 2025 19:41
@Skeyelab
Skeyelab requested a review from Copilot October 24, 2025 03:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds visual level meters to the FreeCaster plugin interface and improves UI responsiveness by increasing the timer update frequency. The level meters provide real-time visual feedback of input and output audio levels with peak hold indicators and dB scale markings.

Key Changes:

  • Added dual vertical level meters (input/output) with RMS calculation and peak hold functionality
  • Increased timer frequency from 500ms to 16ms (~60Hz) for smooth meter animations
  • Expanded window size and added resizability to accommodate new UI elements

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
test_plugin.py New test script that verifies plugin installation and provides testing instructions
Source/PluginProcessor.h Added atomic level tracking variables and accessor methods
Source/PluginProcessor.cpp Implemented RMS level calculation in audio processing block
Source/PluginEditor.h Added LevelMeter component class and meter-related UI members
Source/PluginEditor.cpp Integrated level meters into UI layout and timer callback

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread Source/PluginEditor.cpp Outdated
Comment on lines +143 to +150
// Debug: Log meter bounds
DBG("=== RESIZE DEBUG ===");
DBG("Window size: " + juce::String(getWidth()) + "x" + juce::String(getHeight()));
DBG("Input meter bounds: " + inputMeter.getBounds().toString());
DBG("Output meter bounds: " + outputMeter.getBounds().toString());
DBG("Input meter visible: " + juce::String(inputMeter.isVisible()));
DBG("Output meter visible: " + juce::String(outputMeter.isVisible()));
DBG("Meters area initial: " + juce::String(metersArea.getWidth()) + "x" + juce::String(metersArea.getHeight()));

Copilot AI Oct 24, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug logging statements should be removed from production code. These DBG calls in the resized() method will execute on every window resize, potentially impacting performance and cluttering logs.

Suggested change
// Debug: Log meter bounds
DBG("=== RESIZE DEBUG ===");
DBG("Window size: " + juce::String(getWidth()) + "x" + juce::String(getHeight()));
DBG("Input meter bounds: " + inputMeter.getBounds().toString());
DBG("Output meter bounds: " + outputMeter.getBounds().toString());
DBG("Input meter visible: " + juce::String(inputMeter.isVisible()));
DBG("Output meter visible: " + juce::String(outputMeter.isVisible()));
DBG("Meters area initial: " + juce::String(metersArea.getWidth()) + "x" + juce::String(metersArea.getHeight()));

Copilot uses AI. Check for mistakes.
Comment thread Source/PluginEditor.cpp Outdated
Comment on lines +165 to +171
// Debug: Log levels occasionally
static int debugCounter = 0;
if (++debugCounter % 60 == 0) // Log every second
{
DBG("Input level: " + juce::String(inputLevel) + ", Output level: " + juce::String(outputLevel));
DBG("Test level: " + juce::String(testLevel));
}

Copilot AI Oct 24, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug logging statements should be removed from production code. These DBG calls in the timer callback will execute continuously and clutter production logs.

Suggested change
// Debug: Log levels occasionally
static int debugCounter = 0;
if (++debugCounter % 60 == 0) // Log every second
{
DBG("Input level: " + juce::String(inputLevel) + ", Output level: " + juce::String(outputLevel));
DBG("Test level: " + juce::String(testLevel));
}

Copilot uses AI. Check for mistakes.
Comment thread Source/PluginEditor.h Outdated
{
auto bounds = getLocalBounds().toFloat();

// ALWAYS draw a visible background for debugging

Copilot AI Oct 24, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment 'ALWAYS draw a visible background for debugging' suggests this is temporary debug code. Either remove the debug-related comment or clarify if this background is part of the final design.

Suggested change
// ALWAYS draw a visible background for debugging
// Draw the meter background

Copilot uses AI. Check for mistakes.
Comment thread Source/PluginEditor.h Outdated
Comment on lines +70 to +73
// Debug text
g.setColour(juce::Colours::white);
g.setFont(9.0f);
g.drawText(juce::String(currentLevel, 2), bounds.reduced(2), juce::Justification::centredTop, false);

Copilot AI Oct 24, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The debug text displaying the current level value should be removed or made conditional for production builds. This numeric overlay may not be desired in the final UI.

Suggested change
// Debug text
g.setColour(juce::Colours::white);
g.setFont(9.0f);
g.drawText(juce::String(currentLevel, 2), bounds.reduced(2), juce::Justification::centredTop, false);
// Debug text
#if JUCE_DEBUG
g.setColour(juce::Colours::white);
g.setFont(9.0f);
g.drawText(juce::String(currentLevel, 2), bounds.reduced(2), juce::Justification::centredTop, false);
#endif

Copilot uses AI. Check for mistakes.
}

// Convert RMS to normalized level (0-1) with some headroom
// RMS of 0.7 (~-3dB) maps to full scale

Copilot AI Oct 24, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment incorrectly states that 0.7 is '~-3dB'. An RMS value of 0.7 is approximately -3.1dB (20*log10(0.7) ≈ -3.1dB), which is close but the tilde suggests approximation when a more precise statement would be better. Consider: 'RMS of 0.7 (-3.1dB) maps to full scale'.

Suggested change
// RMS of 0.7 (~-3dB) maps to full scale
// RMS of 0.7 (-3.1dB) maps to full scale

Copilot uses AI. Check for mistakes.
@Skeyelab
Skeyelab requested a review from Copilot October 24, 2025 03:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread test_plugin.py
print("Testing FreeCaster Plugin...")

# Check if VST3 plugin exists
vst3_path = "/Users/edahl/Library/Audio/Plug-Ins/VST3/FreeCaster.vst3"

Copilot AI Oct 24, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coded absolute path is user-specific and will fail for other developers. Consider using environment variables, configuration files, or relative paths based on the user's home directory (e.g., os.path.expanduser('~/Library/Audio/Plug-Ins/VST3/FreeCaster.vst3')).

Copilot uses AI. Check for mistakes.
Comment thread test_plugin.py
return False

# Check if AU plugin exists
au_path = "/Users/edahl/Library/Audio/Plug-Ins/Components/FreeCaster.component"

Copilot AI Oct 24, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coded absolute path is user-specific and will fail for other developers. Consider using os.path.expanduser() to make the path portable across different user accounts.

Suggested change
au_path = "/Users/edahl/Library/Audio/Plug-Ins/Components/FreeCaster.component"
au_path = os.path.expanduser("~/Library/Audio/Plug-Ins/Components/FreeCaster.component")

Copilot uses AI. Check for mistakes.
Comment thread test_plugin.py
return False

# Check if standalone app exists
standalone_path = "/Users/edahl/FreeCaster/build/FreeCaster_artefacts/Standalone/FreeCaster.app"

Copilot AI Oct 24, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coded absolute path is user-specific and will fail for other developers. Consider using a relative path from the script location or environment variables to make this test portable.

Copilot uses AI. Check for mistakes.
Comment thread Source/PluginEditor.cpp
inputMeterLabel.setBounds(inputMeterArea.removeFromTop(20));
inputMeter.setBounds(inputMeterArea.removeFromTop(340));
inputMeter.setBounds(inputMeterArea); // Use remaining height

Copilot AI Oct 24, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Comment states 'Use remaining height' but the previous line inputMeterArea.removeFromTop(20) already consumed 20 pixels for the label, so this uses the height after label removal. Consider clarifying: 'Use height remaining after label'.

Copilot uses AI. Check for mistakes.
Comment thread Source/PluginEditor.cpp

outputMeterLabel.setBounds(outputMeterArea.removeFromTop(20));
outputMeter.setBounds(outputMeterArea.removeFromTop(340));
outputMeter.setBounds(outputMeterArea); // Use remaining height

Copilot AI Oct 24, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Comment states 'Use remaining height' but the previous line already removed 20 pixels for the label. Consider clarifying: 'Use height remaining after label' to match the actual behavior.

Suggested change
outputMeter.setBounds(outputMeterArea); // Use remaining height
outputMeter.setBounds(outputMeterArea); // Use height remaining after label

Copilot uses AI. Check for mistakes.
@Skeyelab
Skeyelab merged commit 0f7b127 into main Oct 24, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants