Fix line endings and some cleanup

This commit is contained in:
Roboboffin
2025-10-23 04:00:21 +01:00
parent 24eb354ace
commit 3ac2cc15b1
66 changed files with 3029 additions and 0 deletions

341
Source/PluginEditor.h Normal file
View File

@@ -0,0 +1,341 @@
#pragma once
#include <JuceHeader.h>
#include "PluginProcessor.h"
#include "GraphComponent.h"
#include "ScopeComponent.h"
//============================== ScopeSliderComponent ==========================
// A generic panel: optional scope/graph + rotary sliders + labels.
// Adds a per-panel "On" toggle (bound to "<group>_on").
class ScopeSliderComponent : public juce::Component {
static const int fontSize = 11;
public:
ScopeSliderComponent(juce::AudioProcessorValueTreeState& tree,
const std::string paramGroup,
const juce::String& titleText = {})
: paramGroupId(paramGroup), treeRef(tree)
{
const auto& sliderDetails = PARAM_SETTINGS.at(paramGroup);
for (const auto& [name, sliderDetail] : sliderDetails) {
sliders.push_back(std::make_unique<juce::Slider>());
labels.push_back(std::make_unique<juce::Label>());
attachments.push_back(std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(
tree, paramGroup + "_" + name, *sliders.back()));
labels.back()->setText(sliderDetail.label, juce::dontSendNotification);
sliders.back()->setRange(sliderDetail.min, sliderDetail.max);
}
for (auto& slider : sliders)
{
slider->setSliderStyle(juce::Slider::Rotary);
slider->setTextBoxStyle(juce::Slider::TextBoxBelow, false, 50, 20);
addAndMakeVisible(*slider);
}
for (auto& label : labels)
{
juce::Font f; f.setHeight((float)fontSize); f.setBold(true);
label->setFont(f);
label->setColour(juce::Label::textColourId, juce::Colours::lightgreen);
label->setJustificationType(juce::Justification::centred);
addAndMakeVisible(*label);
}
if (titleText.isNotEmpty())
{
titleLabel.setText(titleText, juce::dontSendNotification);
juce::Font tf; tf.setHeight(12.0f); tf.setBold(true);
titleLabel.setFont(tf);
titleLabel.setJustificationType(juce::Justification::centredLeft);
titleLabel.setColour(juce::Label::textColourId, juce::Colours::white);
addAndMakeVisible(titleLabel);
}
// Bypass toggle (per panel), id "<group>_on"
bypassButton.setButtonText("On");
bypassButton.setClickingTogglesState(true);
addAndMakeVisible(bypassButton);
bypassAttachment = std::make_unique<juce::AudioProcessorValueTreeState::ButtonAttachment>(
treeRef, paramGroupId + "_on", bypassButton);
}
void enableSampleScope(AudioBufferQueue<float>& audioBufferQueue) {
scope.emplace(audioBufferQueue);
useGraphScope = false;
addAndMakeVisible(*scope);
}
void enableGraphScope(const std::function<float(float)>& func) {
graphScope.emplace(0.0f, 1.0f, 100);
graphScope->setFunction(func);
useGraphScope = true;
addAndMakeVisible(*graphScope);
}
private:
void paint(juce::Graphics& g) override
{
g.fillAll(juce::Colours::darkgrey);
g.setColour(juce::Colours::white);
g.drawRect(getLocalBounds());
}
void resized() override
{
// --- Top bar (manual) ----------------------------------------------
auto area = getLocalBounds().reduced(10);
auto top = area.removeFromTop(22);
auto btnW = 46;
bypassButton.setBounds(top.removeFromRight(btnW).reduced(2, 1));
titleLabel.setBounds(top);
// --- Rest (grid) ----------------------------------------------------
juce::Grid grid;
grid.templateRows = {
juce::Grid::TrackInfo(juce::Grid::Fr(55)), // scope/graph
juce::Grid::TrackInfo(juce::Grid::Fr(30)), // sliders
juce::Grid::TrackInfo(juce::Grid::Fr(15)) // labels
};
const int n = (int)sliders.size();
grid.templateColumns.resize(n);
for (int i = 0; i < n; ++i)
grid.templateColumns.getReference(i) = juce::Grid::TrackInfo(juce::Grid::Fr(1));
grid.items.clear();
// Row 1: scope/graph only add if constructed
if (useGraphScope)
{
if (graphScope)
grid.items.add(juce::GridItem(*graphScope)
.withArea(juce::GridItem::Span(1), juce::GridItem::Span(n)));
else
grid.items.add(juce::GridItem()
.withArea(juce::GridItem::Span(1), juce::GridItem::Span(n)));
}
else
{
if (scope)
grid.items.add(juce::GridItem(*scope)
.withArea(juce::GridItem::Span(1), juce::GridItem::Span(n)));
else
grid.items.add(juce::GridItem()
.withArea(juce::GridItem::Span(1), juce::GridItem::Span(n)));
}
// Row 2: sliders
for (int i = 0; i < n; ++i)
grid.items.add(juce::GridItem(*sliders[(size_t)i]));
// Row 3: labels
for (int i = 0; i < n; ++i)
grid.items.add(juce::GridItem(*labels[(size_t)i]));
grid.performLayout(area);
}
bool useGraphScope{ false };
std::optional<ScopeComponent<float>> scope;
std::optional<GraphComponent<float>> graphScope;
std::vector<std::unique_ptr<juce::Slider>> sliders;
std::vector<std::unique_ptr<juce::Label>> labels;
std::vector<std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment>> attachments;
juce::ToggleButton bypassButton;
std::unique_ptr<juce::AudioProcessorValueTreeState::ButtonAttachment> bypassAttachment;
juce::Label titleLabel;
std::string paramGroupId;
juce::AudioProcessorValueTreeState& treeRef;
};
//============================== EqualizerComponent ============================
// Adds an On/Off toggle bound to "eq_on".
class EqualizerComponent : public juce::Component {
static const int fontSize = 11;
public:
explicit EqualizerComponent(juce::AudioProcessorValueTreeState& tree,
const juce::String& titleText = {})
{
setupSlider(lowGainSlider);
setupSlider(midGainSlider);
setupSlider(highGainSlider);
setupLabel(lowGainLabel, "L");
setupLabel(midGainLabel, "M");
setupLabel(highGainLabel, "H");
if (titleText.isNotEmpty())
{
titleLabel.setText(titleText, juce::dontSendNotification);
juce::Font tf; tf.setHeight(13.0f); tf.setBold(true);
titleLabel.setFont(tf);
titleLabel.setJustificationType(juce::Justification::centredLeft);
titleLabel.setColour(juce::Label::textColourId, juce::Colours::white);
addAndMakeVisible(titleLabel);
}
// Attachments
lowGainAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(tree, "lowEQ", lowGainSlider);
midGainAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(tree, "midEQ", midGainSlider);
highGainAttachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment>(tree, "highEQ", highGainSlider);
// EQ bypass toggle
bypassButton.setButtonText("On");
bypassButton.setClickingTogglesState(true);
addAndMakeVisible(bypassButton);
bypassAttachment = std::make_unique<juce::AudioProcessorValueTreeState::ButtonAttachment>(tree, "eq_on", bypassButton);
}
private:
void setupSlider(juce::Slider& slider) {
slider.setRange(-24.0f, 24.0f, 0.1f);
slider.setSliderStyle(juce::Slider::LinearBarVertical);
slider.setTextBoxStyle(juce::Slider::TextBoxBelow, false, 50, 20);
addAndMakeVisible(slider);
}
void setupLabel(juce::Label& lbl, juce::String txt) {
juce::Font f; f.setHeight((float)fontSize); f.setBold(true);
lbl.setFont(f);
lbl.setColour(juce::Label::textColourId, juce::Colours::lightgreen);
lbl.setJustificationType(juce::Justification::centred);
lbl.setText(txt, juce::dontSendNotification);
addAndMakeVisible(lbl);
}
void paint(juce::Graphics& g) override {
g.fillAll(juce::Colours::darkgrey);
g.setColour(juce::Colours::white);
g.drawRect(getLocalBounds());
}
void resized() override {
auto area = getLocalBounds().reduced(10);
auto top = area.removeFromTop(22);
auto btnW = 46;
bypassButton.setBounds(top.removeFromRight(btnW).reduced(2, 1));
titleLabel.setBounds(top);
juce::Grid grid;
grid.templateRows = {
juce::Grid::TrackInfo(juce::Grid::Fr(1)),
juce::Grid::TrackInfo(juce::Grid::Fr(1))
};
grid.templateColumns = {
juce::Grid::TrackInfo(juce::Grid::Fr(1)),
juce::Grid::TrackInfo(juce::Grid::Fr(1)),
juce::Grid::TrackInfo(juce::Grid::Fr(1))
};
grid.items = {
lowGainSlider, midGainSlider, highGainSlider,
lowGainLabel, midGainLabel, highGainLabel
};
grid.performLayout(area);
}
juce::Slider lowGainSlider, midGainSlider, highGainSlider;
juce::Label lowGainLabel, midGainLabel, highGainLabel;
std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment> lowGainAttachment, midGainAttachment, highGainAttachment;
juce::ToggleButton bypassButton;
std::unique_ptr<juce::AudioProcessorValueTreeState::ButtonAttachment> bypassAttachment;
juce::Label titleLabel;
};
//============================== Waveform List Model ===========================
struct WaveformSelectorContents final : public juce::ListBoxModel
{
int getNumRows() override { return 4; }
void paintListBoxItem(int rowNumber, juce::Graphics& g,
int width, int height, bool rowIsSelected) override
{
if (rowIsSelected) g.fillAll(juce::Colours::lightblue);
g.setColour(juce::LookAndFeel::getDefaultLookAndFeel()
.findColour(juce::Label::textColourId));
juce::Font f; f.setHeight((float)height * 0.7f);
g.setFont(f);
g.drawText(waves[(size_t)rowNumber], 5, 0, width, height,
juce::Justification::centredLeft, true);
}
void selectedRowsChanged (int lastRowSelected) override
{
if (onSelect) onSelect(lastRowSelected);
}
std::function<void (int)> onSelect;
std::vector<juce::String> waves { "Sine", "Saw", "Square", "Triangle" };
};
//============================== MasterVolumeComponent =========================
class MasterVolumeComponent : public juce::Component
{
public:
MasterVolumeComponent()
{
slider.setSliderStyle(juce::Slider::LinearBarVertical);
slider.setTextBoxStyle(juce::Slider::NoTextBox, false, 20, 20);
addAndMakeVisible(slider);
}
void resized() override
{
slider.setBounds(getLocalBounds().reduced(30));
}
juce::Slider slider;
};
//============================== Editor =======================================
class NeuralSynthAudioProcessorEditor : public juce::AudioProcessorEditor
{
public:
NeuralSynthAudioProcessorEditor (NeuralSynthAudioProcessor&);
~NeuralSynthAudioProcessorEditor() override;
void paint (juce::Graphics&) override;
void resized() override;
private:
NeuralSynthAudioProcessor& audioProcessor;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NeuralSynthAudioProcessorEditor)
juce::ListBox waveformSelector;
WaveformSelectorContents waveformContents;
std::optional<ScopeSliderComponent> adsrComponent; // Amp Env
std::optional<ScopeSliderComponent> chorusComponent;
std::optional<ScopeSliderComponent> delayComponent;
std::optional<ScopeSliderComponent> reverbComponent;
std::optional<ScopeSliderComponent> flangerComponent;
std::optional<ScopeSliderComponent> distortionComponent;
std::optional<ScopeSliderComponent> filterComponent;
std::optional<ScopeSliderComponent> filterEnvComponent; // Filter Env panel
MasterVolumeComponent masterLevelSlider;
juce::Label masterLevelLabel;
std::optional<EqualizerComponent> eqComponent;
std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment> gainAttachment;
ScopeComponent<float> mainScopeComponent;
juce::Component blankPanel;
};