#include "PluginProcessor.h" #include "PluginEditor.h" #include "ScopeComponent.h" //============================================================================== NeuralSynthAudioProcessorEditor::NeuralSynthAudioProcessorEditor (NeuralSynthAudioProcessor& p) : AudioProcessorEditor (&p), audioProcessor (p), mainScopeComponent(audioProcessor.getAudioBufferQueue()) { auto& tree = audioProcessor.parameters; addAndMakeVisible(mainScopeComponent); waveformSelector.setModel(&waveformContents); waveformContents.onSelect = [this](int row) { // write to the parameter so voices update safely audioProcessor.parameters.getParameterAsValue("waveform") = (float)juce::jlimit(0, 3, row); }; addAndMakeVisible(waveformSelector); // --- Panels --- adsrComponent.emplace(tree, "adsr", "Amp Env"); adsrComponent->enableGraphScope([this](float x) { auto& tree = this->audioProcessor.parameters; float A = tree.getParameter("adsr_attack")->getValue(); float D = tree.getParameter("adsr_decay")->getValue(); float S = tree.getParameter("adsr_sustain")->getValue(); float R = tree.getParameter("adsr_release")->getValue(); const float sustainLen = 1.0f; const float total = A + D + sustainLen + R; A /= total; D /= total; R /= total; float m = 0.0f, c = 0.0f; if (x < A) { m = 1.0f / A; c = 0.0f; } else if (x < A + D) { m = (S - 1.0f) / D; c = 1.0f - m * A; } else if (x < A + D + (sustainLen / total)) { m = 0.0f; c = S; } else { m = (S / -R); c = -m; } return m * x + c; }); addAndMakeVisible(*adsrComponent); chorusComponent.emplace(tree, "chorus", "Chorus"); chorusComponent->enableSampleScope(audioProcessor.getChorusAudioBufferQueue()); addAndMakeVisible(*chorusComponent); delayComponent.emplace(tree, "delay", "Delay"); delayComponent->enableSampleScope(audioProcessor.getDelayAudioBufferQueue()); addAndMakeVisible(*delayComponent); reverbComponent.emplace(tree, "reverb", "Reverb"); reverbComponent->enableSampleScope(audioProcessor.getReverbAudioBufferQueue()); addAndMakeVisible(*reverbComponent); eqComponent.emplace(tree, "EQ"); addAndMakeVisible(*eqComponent); flangerComponent.emplace(tree, "flanger", "Flanger"); flangerComponent->enableSampleScope(audioProcessor.getFlangerAudioBufferQueue()); addAndMakeVisible(*flangerComponent); distortionComponent.emplace(tree, "distortion", "Distortion"); distortionComponent->enableSampleScope(audioProcessor.getDistortionAudioBufferQueue()); addAndMakeVisible(*distortionComponent); filterComponent.emplace(tree, "filter", "Filter"); filterComponent->enableSampleScope(audioProcessor.getFilterAudioBufferQueue()); addAndMakeVisible(*filterComponent); filterEnvComponent.emplace(tree, "fenv", "Filter Env"); filterEnvComponent->enableGraphScope([this](float x) { auto& tree = this->audioProcessor.parameters; float A = tree.getParameter("fenv_attack")->getValue(); float D = tree.getParameter("fenv_decay")->getValue(); float S = tree.getParameter("fenv_sustain")->getValue(); float R = tree.getParameter("fenv_release")->getValue(); const float sustainLen = 1.0f; const float total = A + D + sustainLen + R; A /= total; D /= total; R /= total; float m = 0.0f, c = 0.0f; if (x < A) { m = 1.0f / A; c = 0.0f; } else if (x < A + D) { m = (S - 1.0f) / D; c = 1.0f - m * A; } else if (x < A + D + (sustainLen / total)) { m = 0.0f; c = S; } else { m = (S / -R); c = -m; } return m * x + c; }); addAndMakeVisible(*filterEnvComponent); // Master fader + label addAndMakeVisible(masterLevelSlider); masterLevelLabel.setText("Master", juce::dontSendNotification); { juce::Font f; f.setHeight(12.0f); f.setBold(true); masterLevelLabel.setFont(f); } masterLevelLabel.setJustificationType(juce::Justification::centred); addAndMakeVisible(masterLevelLabel); // Blank placeholder addAndMakeVisible(blankPanel); // Attach master parameter gainAttachment = std::make_unique( audioProcessor.parameters, "master", masterLevelSlider.slider); setSize(1400, 720); } //============================================================================== NeuralSynthAudioProcessorEditor::~NeuralSynthAudioProcessorEditor() = default; //============================================================================== void NeuralSynthAudioProcessorEditor::paint (juce::Graphics& g) { g.fillAll(getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId)); } //============================================================================== void NeuralSynthAudioProcessorEditor::resized() { auto bounds = getLocalBounds().reduced(16); juce::Grid grid; grid.templateRows = { juce::Grid::TrackInfo(juce::Grid::Fr(20)), // scope row juce::Grid::TrackInfo(juce::Grid::Fr(40)), // row 1 juce::Grid::TrackInfo(juce::Grid::Fr(40)) // row 2 }; // 6 columns: 5 content + 1 sidebar (waveform+master) grid.templateColumns = { juce::Grid::TrackInfo(juce::Grid::Fr(18)), juce::Grid::TrackInfo(juce::Grid::Fr(18)), juce::Grid::TrackInfo(juce::Grid::Fr(18)), juce::Grid::TrackInfo(juce::Grid::Fr(18)), juce::Grid::TrackInfo(juce::Grid::Fr(18)), juce::Grid::TrackInfo(juce::Grid::Fr(10)) }; // Row 0 grid.items.add(juce::GridItem(mainScopeComponent) .withArea(juce::GridItem::Span(1), juce::GridItem::Span(5))); grid.items.add(juce::GridItem(waveformSelector) .withArea(juce::GridItem::Span(1), juce::GridItem::Span(1))); // Row 1 grid.items.add(juce::GridItem(*adsrComponent)); grid.items.add(juce::GridItem(*chorusComponent)); grid.items.add(juce::GridItem(*delayComponent)); grid.items.add(juce::GridItem(*reverbComponent)); grid.items.add(juce::GridItem(*eqComponent)); grid.items.add(juce::GridItem(masterLevelLabel)); // Row 2 grid.items.add(juce::GridItem(*flangerComponent)); grid.items.add(juce::GridItem(*distortionComponent)); grid.items.add(juce::GridItem(*filterComponent)); grid.items.add(juce::GridItem(*filterEnvComponent)); grid.items.add(juce::GridItem(blankPanel)); grid.items.add(juce::GridItem(masterLevelSlider)); grid.performLayout(bounds); }