Initial BEAMGRID VST3/AU spectrum analyzer

This commit is contained in:
opencode 2026-08-13 23:15:38 +02:00
commit 0a3fe6d853
15 changed files with 908 additions and 0 deletions

134
Source/PluginEditor.cpp Normal file
View file

@ -0,0 +1,134 @@
#include "PluginEditor.h"
#include "GitVersion.h"
BeamgridAudioProcessorEditor::BeamgridAudioProcessorEditor (BeamgridAudioProcessor& p)
: AudioProcessorEditor (&p),
processorRef (p),
analyserComponent (p.getAnalyser(), p.getParametersState(), lookAndFeel)
{
setLookAndFeel (&lookAndFeel);
setSize (820, 460);
// Make the editor freely resizable (with a corner resizer). The plugin
// reports IPlugView::canResize() == true to the host, which is what FL
// Studio (and other hosts) use to enable their native maximize button.
setResizable (true, true);
setResizeLimits (420, 260, 4000, 4000);
analyserComponent.setLookAndFeel (&lookAndFeel);
addAndMakeVisible (analyserComponent);
auto setupKnob = [&] (juce::Slider& s, const juce::String& name)
{
s.setSliderStyle (juce::Slider::RotaryHorizontalVerticalDrag);
s.setTextBoxStyle (juce::Slider::TextBoxBelow, false, 80, 18);
s.setColour (juce::Slider::textBoxTextColourId, juce::Colours::lightgrey);
s.setTextValueSuffix (" " + name);
s.setLookAndFeel (&lookAndFeel);
addAndMakeVisible (s);
};
setupKnob (graceSlider, "ms");
setupKnob (falloffSlider, "");
setupKnob (barfalloffSlider, "");
setupKnob (barsSlider, "");
setupKnob (hueSlider, "");
barsSlider.setNumDecimalPlacesToDisplay (0);
graceLabel.setText ("PEAK GRACE", juce::dontSendNotification);
graceLabel.setJustificationType (juce::Justification::centred);
graceLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
addAndMakeVisible (graceLabel);
falloffLabel.setText ("PEAK FALLOFF", juce::dontSendNotification);
falloffLabel.setJustificationType (juce::Justification::centred);
falloffLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
addAndMakeVisible (falloffLabel);
barfalloffLabel.setText ("BAR FALLOFF", juce::dontSendNotification);
barfalloffLabel.setJustificationType (juce::Justification::centred);
barfalloffLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
addAndMakeVisible (barfalloffLabel);
barsLabel.setText ("BARS", juce::dontSendNotification);
barsLabel.setJustificationType (juce::Justification::centred);
barsLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
addAndMakeVisible (barsLabel);
hueLabel.setText ("HUE", juce::dontSendNotification);
hueLabel.setJustificationType (juce::Justification::centred);
hueLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
addAndMakeVisible (hueLabel);
titleLabel.setText ("BEAMGRID", juce::dontSendNotification);
titleLabel.setJustificationType (juce::Justification::centredRight);
titleLabel.setFont (juce::FontOptions (20.0f, juce::Font::bold));
titleLabel.setColour (juce::Label::textColourId, lookAndFeel.getTeal());
addAndMakeVisible (titleLabel);
statusLabel.setFont (juce::FontOptions (11.0f));
statusLabel.setColour (juce::Label::textColourId, juce::Colours::grey);
statusLabel.setJustificationType (juce::Justification::centredLeft);
juce::String status;
status << "git " << juce::String (BEAMGRID_GIT_COMMIT).substring (0, 7);
status << " [" << (BEAMGRID_GIT_DIRTY ? "dirty" : "clean") << "]";
status << " build " << BEAMGRID_BUILD_DATE;
statusLabel.setText (status, juce::dontSendNotification);
addAndMakeVisible (statusLabel);
graceAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
processorRef.getParametersState(), "grace", graceSlider);
falloffAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
processorRef.getParametersState(), "falloff", falloffSlider);
barfalloffAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
processorRef.getParametersState(), "barfalloff", barfalloffSlider);
barsAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
processorRef.getParametersState(), "bars", barsSlider);
hueAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
processorRef.getParametersState(), "hue", hueSlider);
}
BeamgridAudioProcessorEditor::~BeamgridAudioProcessorEditor()
{
setLookAndFeel (nullptr);
}
void BeamgridAudioProcessorEditor::paint (juce::Graphics& g)
{
g.fillAll (juce::Colours::black);
// Keep the title colour in sync with the HUE knob.
titleLabel.setColour (juce::Label::textColourId, lookAndFeel.getTeal());
}
void BeamgridAudioProcessorEditor::resized()
{
const int panelH = 114;
const int knob = 64;
const int y = getHeight() - panelH + 14;
analyserComponent.setBounds (0, 0, getWidth(), getHeight() - panelH);
const int margin = 32;
const int spacing = knob + 24;
barsSlider.setBounds (margin, y, knob, knob);
barsLabel.setBounds (margin, y + knob + 2, knob, 18);
graceSlider.setBounds (margin + spacing, y, knob, knob);
graceLabel.setBounds (margin + spacing, y + knob + 2, knob, 18);
barfalloffSlider.setBounds (margin + spacing * 2, y, knob, knob);
barfalloffLabel.setBounds (margin + spacing * 2, y + knob + 2, knob, 18);
falloffSlider.setBounds (margin + spacing * 3, y, knob, knob);
falloffLabel.setBounds (margin + spacing * 3, y + knob + 2, knob, 18);
hueSlider.setBounds (margin + spacing * 4, y, knob, knob);
hueLabel.setBounds (margin + spacing * 4, y + knob + 2, knob, 18);
titleLabel.setBounds (getWidth() - 262, y - 6, 210, knob + 24);
statusLabel.setBounds (8, getHeight() - 16, getWidth() - 16, 14);
}