171 lines
6.6 KiB
C++
171 lines
6.6 KiB
C++
#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<juce::AudioProcessorValueTreeState::SliderAttachment>(
|
|
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);
|
|
}
|