mirror of
https://codeberg.org/armin/beamgrid.git
synced 2026-09-01 04:10:47 +02:00
add LICENSE, update README, update source
This commit is contained in:
parent
6ab142e450
commit
e0177ed26f
9 changed files with 395 additions and 53 deletions
|
|
@ -7,7 +7,7 @@ BeamgridAudioProcessorEditor::BeamgridAudioProcessorEditor (BeamgridAudioProcess
|
|||
analyserComponent (p.getAnalyser(), p.getParametersState(), lookAndFeel)
|
||||
{
|
||||
setLookAndFeel (&lookAndFeel);
|
||||
setSize (820, 460);
|
||||
setSize (980, 480);
|
||||
|
||||
// Make the editor freely resizable (with a corner resizer). The plugin
|
||||
// reports IPlugView::canResize() == true to the host, which is what FL
|
||||
|
|
@ -33,7 +33,12 @@ BeamgridAudioProcessorEditor::BeamgridAudioProcessorEditor (BeamgridAudioProcess
|
|||
setupKnob (barfalloffSlider, "");
|
||||
setupKnob (barsSlider, "");
|
||||
setupKnob (hueSlider, "");
|
||||
setupKnob (modeSlider, "");
|
||||
setupKnob (ledsSlider, "");
|
||||
setupKnob (smoothSlider, "");
|
||||
barsSlider.setNumDecimalPlacesToDisplay (0);
|
||||
modeSlider.setNumDecimalPlacesToDisplay (0);
|
||||
ledsSlider.setNumDecimalPlacesToDisplay (0);
|
||||
|
||||
graceLabel.setText ("PEAK GRACE", juce::dontSendNotification);
|
||||
graceLabel.setJustificationType (juce::Justification::centred);
|
||||
|
|
@ -60,6 +65,35 @@ BeamgridAudioProcessorEditor::BeamgridAudioProcessorEditor (BeamgridAudioProcess
|
|||
hueLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
|
||||
addAndMakeVisible (hueLabel);
|
||||
|
||||
modeLabel.setText ("MODE", juce::dontSendNotification);
|
||||
modeLabel.setJustificationType (juce::Justification::centred);
|
||||
modeLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
|
||||
addAndMakeVisible (modeLabel);
|
||||
|
||||
ledsLabel.setText ("LEDS", juce::dontSendNotification);
|
||||
ledsLabel.setJustificationType (juce::Justification::centred);
|
||||
ledsLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
|
||||
addAndMakeVisible (ledsLabel);
|
||||
|
||||
smoothLabel.setText ("SMOOTH", juce::dontSendNotification);
|
||||
smoothLabel.setJustificationType (juce::Justification::centred);
|
||||
smoothLabel.setColour (juce::Label::textColourId, juce::Colours::lightgrey);
|
||||
addAndMakeVisible (smoothLabel);
|
||||
|
||||
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));
|
||||
scaleBox.setColour (juce::ComboBox::textColourId, juce::Colours::lightgrey);
|
||||
scaleBox.setColour (juce::ComboBox::arrowColourId, juce::Colours::lightgrey);
|
||||
scaleBox.onChange = [this]
|
||||
{
|
||||
const double pct = scaleBox.getText().retainCharacters ("0123456789.").getDoubleValue();
|
||||
const double scale = juce::jlimit (0.5, 3.0, pct / 100.0);
|
||||
setScaleFactor (scale);
|
||||
processorRef.getParametersState().state.setProperty ("uiScale", scale, nullptr);
|
||||
};
|
||||
addAndMakeVisible (scaleBox);
|
||||
|
||||
titleLabel.setText ("BEAMGRID", juce::dontSendNotification);
|
||||
titleLabel.setJustificationType (juce::Justification::centredRight);
|
||||
titleLabel.setFont (juce::FontOptions (20.0f, juce::Font::bold));
|
||||
|
|
@ -68,7 +102,7 @@ BeamgridAudioProcessorEditor::BeamgridAudioProcessorEditor (BeamgridAudioProcess
|
|||
|
||||
statusLabel.setFont (juce::FontOptions (11.0f));
|
||||
statusLabel.setColour (juce::Label::textColourId, juce::Colours::grey);
|
||||
statusLabel.setJustificationType (juce::Justification::centredLeft);
|
||||
statusLabel.setJustificationType (juce::Justification::centredRight);
|
||||
|
||||
juce::String status;
|
||||
status << "git " << juce::String (BEAMGRID_GIT_COMMIT).substring (0, 7);
|
||||
|
|
@ -87,13 +121,69 @@ BeamgridAudioProcessorEditor::BeamgridAudioProcessorEditor (BeamgridAudioProcess
|
|||
processorRef.getParametersState(), "bars", barsSlider);
|
||||
hueAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
|
||||
processorRef.getParametersState(), "hue", hueSlider);
|
||||
modeAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
|
||||
processorRef.getParametersState(), "mode", modeSlider);
|
||||
ledsAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
|
||||
processorRef.getParametersState(), "leds", ledsSlider);
|
||||
smoothAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
|
||||
processorRef.getParametersState(), "smooth", smoothSlider);
|
||||
|
||||
// Set these AFTER the attachments: SliderAttachment installs its own
|
||||
// textFromValueFunction, so assigning afterwards makes ours take effect.
|
||||
barsSlider.textFromValueFunction = [] (double v)
|
||||
{
|
||||
return juce::String (juce::roundToInt (v));
|
||||
};
|
||||
|
||||
modeSlider.textFromValueFunction = [] (double v)
|
||||
{
|
||||
const int m = juce::roundToInt (v);
|
||||
return m == 2 ? juce::String ("SPECTRUM")
|
||||
: m == 3 ? juce::String ("LED")
|
||||
: juce::String ("BARS");
|
||||
};
|
||||
|
||||
// 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();
|
||||
|
||||
processorRef.getParametersState().addParameterListener ("hue", this);
|
||||
|
||||
// Restore the saved UI size + scale from the plugin state (the host saves
|
||||
// this state with the project), so the window reopens the same way.
|
||||
auto& uiState = processorRef.getParametersState().state;
|
||||
const double storedScale = uiState.getProperty ("uiScale", 1.0);
|
||||
|
||||
const double scales[] = { 0.75, 1.0, 1.5, 2.0, 2.5, 3.0 };
|
||||
int scaleIdx = 1;
|
||||
for (int i = 0; i < 6; ++i)
|
||||
if (std::abs (scales[i] - storedScale) < 0.001)
|
||||
scaleIdx = i;
|
||||
scaleBox.setSelectedItemIndex (scaleIdx); // triggers onChange -> setScaleFactor
|
||||
|
||||
const int storedW = uiState.getProperty ("uiWidth", getWidth());
|
||||
const int storedH = uiState.getProperty ("uiHeight", getHeight());
|
||||
setSize (storedW, storedH);
|
||||
}
|
||||
|
||||
BeamgridAudioProcessorEditor::~BeamgridAudioProcessorEditor()
|
||||
{
|
||||
processorRef.getParametersState().removeParameterListener ("hue", this);
|
||||
setLookAndFeel (nullptr);
|
||||
}
|
||||
|
||||
void BeamgridAudioProcessorEditor::parameterChanged (const juce::String& parameterID, float newValue)
|
||||
{
|
||||
if (parameterID == "hue")
|
||||
{
|
||||
// Update the shared LookAndFeel immediately and repaint the whole
|
||||
// editor so every rotary knob's arc (and the title) recolours.
|
||||
lookAndFeel.setHueTurns (newValue - 0.5f);
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void BeamgridAudioProcessorEditor::paint (juce::Graphics& g)
|
||||
{
|
||||
g.fillAll (juce::Colours::black);
|
||||
|
|
@ -108,27 +198,63 @@ void BeamgridAudioProcessorEditor::resized()
|
|||
const int knob = 64;
|
||||
const int y = getHeight() - panelH + 14;
|
||||
|
||||
analyserComponent.setBounds (0, 0, getWidth(), getHeight() - panelH);
|
||||
// 32px blank bar across the very top of the plugin (the dropdown sits
|
||||
// 16px below the top edge so it isn't glued to it). 30px blank strip on
|
||||
// the right so the spectrum doesn't touch the right border.
|
||||
const int topBarH = 32;
|
||||
const int rightPad = 30;
|
||||
analyserComponent.setBounds (0, topBarH, getWidth() - rightPad, getHeight() - panelH - topBarH);
|
||||
|
||||
const int margin = 32;
|
||||
const int spacing = knob + 24;
|
||||
const int margin = 24;
|
||||
const int gap = 14;
|
||||
const int count = 8;
|
||||
const int titleW = 220;
|
||||
|
||||
barsSlider.setBounds (margin, y, knob, knob);
|
||||
barsLabel.setBounds (margin, y + knob + 2, knob, 18);
|
||||
// Available width for the knob row (leave room on the right for the title).
|
||||
const int avail = getWidth() - margin * 2 - titleW;
|
||||
int spacing = knob + gap;
|
||||
const int minSpacing = knob + 4;
|
||||
if ((count - 1) * spacing + knob > avail)
|
||||
spacing = juce::jmax (minSpacing, (avail - knob) / (count - 1));
|
||||
|
||||
graceSlider.setBounds (margin + spacing, y, knob, knob);
|
||||
graceLabel.setBounds (margin + spacing, y + knob + 2, knob, 18);
|
||||
struct KnobRow { juce::Slider& s; juce::Label& l; };
|
||||
const KnobRow knobs[] = {
|
||||
{ graceSlider, graceLabel },
|
||||
{ falloffSlider, falloffLabel },
|
||||
{ barfalloffSlider, barfalloffLabel },
|
||||
{ barsSlider, barsLabel },
|
||||
{ hueSlider, hueLabel },
|
||||
{ modeSlider, modeLabel },
|
||||
{ ledsSlider, ledsLabel },
|
||||
{ smoothSlider, smoothLabel },
|
||||
};
|
||||
|
||||
barfalloffSlider.setBounds (margin + spacing * 2, y, knob, knob);
|
||||
barfalloffLabel.setBounds (margin + spacing * 2, y + knob + 2, knob, 18);
|
||||
const juce::Font labelFont (juce::FontOptions (11.0f));
|
||||
|
||||
falloffSlider.setBounds (margin + spacing * 3, y, knob, knob);
|
||||
falloffLabel.setBounds (margin + spacing * 3, y + knob + 2, knob, 18);
|
||||
// Knobs are drawn 16px higher than the panel baseline; the title and
|
||||
// status bar below stay anchored to the original baseline.
|
||||
const int knobY = y - 16;
|
||||
|
||||
hueSlider.setBounds (margin + spacing * 4, y, knob, knob);
|
||||
hueLabel.setBounds (margin + spacing * 4, y + knob + 2, knob, 18);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
const int x = margin + i * spacing;
|
||||
knobs[i].s.setBounds (x, knobY, knob, knob);
|
||||
|
||||
titleLabel.setBounds (getWidth() - 262, y - 6, 210, knob + 24);
|
||||
// Let the label span the full spacing (wider than the knob) so longer
|
||||
// names like "BAR FALLOFF" aren't clipped, centred under the knob.
|
||||
const int labelW = spacing;
|
||||
const int labelX = x + (knob - labelW) / 2;
|
||||
knobs[i].l.setFont (labelFont);
|
||||
knobs[i].l.setBounds (labelX, knobY + knob + 2, labelW, 18);
|
||||
}
|
||||
|
||||
statusLabel.setBounds (8, getHeight() - 16, getWidth() - 16, 14);
|
||||
titleLabel.setBounds (getWidth() - titleW - margin, y - 6, titleW, knob + 24);
|
||||
statusLabel.setBounds (16, getHeight() - 16, getWidth() - 42, 14);
|
||||
|
||||
// UI scaling dropdown, top-right (16px below the top edge).
|
||||
scaleBox.setBounds (getWidth() - 96 - margin, 16, 96, 16);
|
||||
|
||||
// Remember the current window size so it can be restored with the project.
|
||||
processorRef.getParametersState().state.setProperty ("uiWidth", getWidth(), nullptr);
|
||||
processorRef.getParametersState().state.setProperty ("uiHeight", getHeight(), nullptr);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue