Add TILT spectral-tilt knob plus grid zoom/fade and curving controls

- TILT knob (-1..1, 0=flat) boosts highs / cuts lows about the log-frequency
  centre so high frequencies become more visible in the display
- Add GRID ZOOM, GRID FADE, and CURVING knobs; refine BARS/LEDS snapping
- Fix README MODE knob placement description
This commit is contained in:
Armin 2026-08-14 02:55:28 +02:00
commit ca9555af13
7 changed files with 176 additions and 15 deletions

View file

@ -37,6 +37,10 @@ BeamgridAudioProcessorEditor::BeamgridAudioProcessorEditor (BeamgridAudioProcess
setupKnob (ledsSlider, "");
setupKnob (smoothSlider, "");
setupKnob (gridSlider, "");
setupKnob (gridzoomSlider, "");
setupKnob (gridfadeSlider, "");
setupKnob (curvingSlider, "");
setupKnob (tiltSlider, "");
barsSlider.setNumDecimalPlacesToDisplay (0);
modeSlider.setNumDecimalPlacesToDisplay (0);
ledsSlider.setNumDecimalPlacesToDisplay (0);
@ -86,6 +90,26 @@ BeamgridAudioProcessorEditor::BeamgridAudioProcessorEditor (BeamgridAudioProcess
gridLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
addAndMakeVisible (gridLabel);
gridzoomLabel.setText ("GRID ZOOM", juce::dontSendNotification);
gridzoomLabel.setJustificationType (juce::Justification::centred);
gridzoomLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
addAndMakeVisible (gridzoomLabel);
gridfadeLabel.setText ("GRID FADE", juce::dontSendNotification);
gridfadeLabel.setJustificationType (juce::Justification::centred);
gridfadeLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
addAndMakeVisible (gridfadeLabel);
curvingLabel.setText ("CURVING", juce::dontSendNotification);
curvingLabel.setJustificationType (juce::Justification::centred);
curvingLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
addAndMakeVisible (curvingLabel);
tiltLabel.setText ("TILT", juce::dontSendNotification);
tiltLabel.setJustificationType (juce::Justification::centred);
tiltLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
addAndMakeVisible (tiltLabel);
scaleBox.addItemList (juce::StringArray ("75%", "100%", "150%", "200%", "250%", "300%"), 1);
scaleBox.setSelectedItemIndex (1); // 100%
scaleBox.setColour (juce::ComboBox::backgroundColourId, juce::Colours::black.brighter (0.15f));
@ -135,6 +159,14 @@ BeamgridAudioProcessorEditor::BeamgridAudioProcessorEditor (BeamgridAudioProcess
processorRef.getParametersState(), "smooth", smoothSlider);
gridAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
processorRef.getParametersState(), "grid", gridSlider);
gridzoomAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
processorRef.getParametersState(), "gridzoom", gridzoomSlider);
gridfadeAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
processorRef.getParametersState(), "gridfade", gridfadeSlider);
curvingAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
processorRef.getParametersState(), "curving", curvingSlider);
tiltAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
processorRef.getParametersState(), "tilt", tiltSlider);
// Set these AFTER the attachments: SliderAttachment installs its own
// textFromValueFunction, so assigning afterwards makes ours take effect.
@ -151,10 +183,23 @@ BeamgridAudioProcessorEditor::BeamgridAudioProcessorEditor (BeamgridAudioProcess
: juce::String ("BARS");
};
ledsSlider.textFromValueFunction = [] (double v)
{
return juce::String (juce::roundToInt (v));
};
tiltSlider.textFromValueFunction = [] (double v)
{
return (v >= 0.0 ? juce::String ("+") : juce::String (""))
+ juce::String (v, 2);
};
// Force an immediate repaint of the text boxes now that our formatters
// are installed (otherwise they keep the attachment's initial text).
barsSlider.updateText();
modeSlider.updateText();
ledsSlider.updateText();
tiltSlider.updateText();
processorRef.getParametersState().addParameterListener ("hue", this);
@ -203,7 +248,6 @@ void BeamgridAudioProcessorEditor::paint (juce::Graphics& g)
void BeamgridAudioProcessorEditor::resized()
{
const int panelH = 114;
const int knob = 64;
const int y = getHeight() - panelH + 14;
// 32px blank bar across the very top of the plugin (the dropdown sits
@ -215,11 +259,16 @@ void BeamgridAudioProcessorEditor::resized()
const int margin = 24;
const int gap = 14;
const int count = 9;
const int titleW = 220;
const int count = 13;
const int titleW = 180;
// Available width for the knob row (leave room on the right for the title).
const int avail = getWidth() - margin * 2 - titleW;
// Shrink the knobs only if necessary so all `count` of them fit within the
// available width down to the 800px minimum; otherwise keep them at 64.
const int knob = juce::jlimit (40, 64, (avail - (count - 1) * 4) / count);
int spacing = knob + gap;
const int minSpacing = knob + 4;
if ((count - 1) * spacing + knob > avail)
@ -236,6 +285,10 @@ void BeamgridAudioProcessorEditor::resized()
{ ledsSlider, ledsLabel },
{ smoothSlider, smoothLabel },
{ gridSlider, gridLabel },
{ gridzoomSlider, gridzoomLabel },
{ gridfadeSlider, gridfadeLabel },
{ curvingSlider, curvingLabel },
{ tiltSlider, tiltLabel },
};
const juce::Font labelFont (juce::FontOptions (11.0f));