2026-08-15 15:36:28 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <JuceHeader.h>
|
|
|
|
|
#include "PluginProcessor.h"
|
|
|
|
|
#include "PresetManager.h"
|
|
|
|
|
#include "GUI/AmbivalenceUI.h"
|
|
|
|
|
#include "GUI/DecayCurveViz.h"
|
|
|
|
|
|
2026-08-15 18:31:51 +02:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// EditorContent
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// Holds every UI element of the editor and is the only component that gets a
|
|
|
|
|
// zoom transform applied. The top-level AudioProcessorEditor stays
|
|
|
|
|
// untransformed and is sized to exactly fit the transformed content, so the
|
|
|
|
|
// host always sees a window that matches what the plugin draws (no double
|
|
|
|
|
// scaling, no clipped / blank margins at any zoom level).
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
class EditorContent : public juce::Component
|
2026-08-15 15:36:28 +02:00
|
|
|
{
|
|
|
|
|
public:
|
2026-08-15 18:31:51 +02:00
|
|
|
explicit EditorContent(FDNReverbAudioProcessor& p, AmbivalenceLookAndFeel& laf);
|
2026-08-15 15:36:28 +02:00
|
|
|
|
|
|
|
|
void paint(juce::Graphics&) override;
|
|
|
|
|
void resized() override;
|
|
|
|
|
|
2026-08-15 18:31:51 +02:00
|
|
|
void setProMode(bool pro);
|
2026-08-15 15:36:28 +02:00
|
|
|
|
2026-08-15 18:31:51 +02:00
|
|
|
// --- zoom ---
|
|
|
|
|
static constexpr float kDefaultZoom = 1.5f;
|
|
|
|
|
float currentZoom{ kDefaultZoom };
|
|
|
|
|
float uiScale{ 1.0f }; // derived from getWidth()/W, applied to every child bounds
|
|
|
|
|
std::function<void(float)> onZoomChange;
|
|
|
|
|
AmbivalenceLookAndFeel* lookAndFeel{ nullptr };
|
2026-08-15 15:36:28 +02:00
|
|
|
|
|
|
|
|
// --- common ---
|
|
|
|
|
DecayCurveViz decayCurveViz;
|
|
|
|
|
VUMeter vuIn, vuOut;
|
|
|
|
|
juce::Label titleLabel;
|
|
|
|
|
|
|
|
|
|
juce::Label labelMetricsTitle;
|
|
|
|
|
juce::Label labelD50Caption, labelD50Value;
|
|
|
|
|
juce::Label labelC50Caption, labelC50Value;
|
|
|
|
|
juce::Label labelC80Caption, labelC80Value;
|
|
|
|
|
juce::Label labelEDTCaption, labelEDTValue;
|
|
|
|
|
|
|
|
|
|
juce::Label statusLabel;
|
|
|
|
|
|
2026-08-15 18:31:51 +02:00
|
|
|
juce::TextButton zoomButton;
|
2026-08-15 15:36:28 +02:00
|
|
|
juce::TextButton proModeButton;
|
|
|
|
|
juce::TextButton erSoloButton;
|
|
|
|
|
std::unique_ptr<juce::AudioProcessorValueTreeState::ButtonAttachment> proModeAttachment;
|
|
|
|
|
std::unique_ptr<juce::AudioProcessorValueTreeState::ButtonAttachment> erSoloAttachment;
|
|
|
|
|
|
2026-08-15 18:31:51 +02:00
|
|
|
bool proMode{ false };
|
2026-08-15 15:36:28 +02:00
|
|
|
|
|
|
|
|
// --- Normal Mode ---
|
|
|
|
|
ArcKnob kPreDelay, kRoomSize, kDecay;
|
|
|
|
|
ArcKnob kHFDamp, kLFAbsorb;
|
|
|
|
|
ArcKnob kDiffusion, kModAmt, kModRate;
|
|
|
|
|
ArcKnob kStereoW;
|
|
|
|
|
ArcKnob kERLevel, kSaturation;
|
|
|
|
|
ArcKnob kWet, kDry;
|
|
|
|
|
ArcKnob kDuckAmt, kDuckThr, kDuckAtt, kDuckRel;
|
|
|
|
|
ArcKnob kLoCutNorm, kHiCutNorm;
|
|
|
|
|
|
|
|
|
|
// --- ProMode panel ---
|
|
|
|
|
std::array<ArcKnob, 10> kRTBands;
|
|
|
|
|
juce::Label satTypeLabel;
|
|
|
|
|
juce::ComboBox satTypeCombo;
|
|
|
|
|
std::unique_ptr<juce::AudioProcessorValueTreeState::ComboBoxAttachment> satTypeAttachment;
|
|
|
|
|
ArcKnob kTiltLow, kTiltMid, kTiltHigh;
|
|
|
|
|
ArcKnob kLoCutPro, kHiCutPro;
|
|
|
|
|
|
|
|
|
|
// --- preset UI ---
|
|
|
|
|
juce::TextButton presetPrevButton;
|
|
|
|
|
juce::ComboBox presetCombo;
|
|
|
|
|
juce::TextButton presetNextButton;
|
|
|
|
|
juce::TextButton presetSaveButton;
|
2026-08-15 18:31:51 +02:00
|
|
|
juce::TextButton presetLoadButton;
|
2026-08-15 15:36:28 +02:00
|
|
|
juce::TextButton presetDeleteButton;
|
|
|
|
|
|
|
|
|
|
// --- layout constants ---
|
|
|
|
|
static constexpr int W = 900;
|
2026-08-15 18:31:51 +02:00
|
|
|
static constexpr int H = 450;
|
2026-08-15 15:36:28 +02:00
|
|
|
static constexpr int PAD = 8;
|
|
|
|
|
static constexpr int KNOB_W = 64;
|
|
|
|
|
static constexpr int KNOB_H = 72;
|
|
|
|
|
static constexpr int KNOB_LBL_H = 14;
|
|
|
|
|
static constexpr int UNIT_H = 88;
|
|
|
|
|
static constexpr int ROW1_GAP = 18;
|
|
|
|
|
static constexpr int STATUS_H = 16;
|
|
|
|
|
|
|
|
|
|
// Fixed X of the preset panel
|
|
|
|
|
// DUCKING end (616) + gap(16) = 632
|
|
|
|
|
static constexpr int PRESET_PANEL_X = 632;
|
|
|
|
|
|
2026-08-15 18:31:51 +02:00
|
|
|
void updatePanelVisibility();
|
|
|
|
|
void showZoomMenu();
|
|
|
|
|
void setZoomLevel(float scale);
|
|
|
|
|
|
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EditorContent)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
// Editor
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
class FDNReverbEditor : public juce::AudioProcessorEditor,
|
|
|
|
|
private juce::Timer
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit FDNReverbEditor(FDNReverbAudioProcessor&);
|
|
|
|
|
~FDNReverbEditor() override;
|
|
|
|
|
|
|
|
|
|
void paint(juce::Graphics&) override;
|
|
|
|
|
void resized() override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void timerCallback() override;
|
|
|
|
|
|
|
|
|
|
// --- Preset UI helpers ---
|
|
|
|
|
void refreshPresetCombo();
|
|
|
|
|
void savePresetWithDialog();
|
|
|
|
|
void deleteCurrentPreset();
|
|
|
|
|
|
|
|
|
|
FDNReverbAudioProcessor& audioProcessor;
|
|
|
|
|
AmbivalenceLookAndFeel laf;
|
|
|
|
|
std::unique_ptr<EditorContent> content;
|
|
|
|
|
std::unique_ptr<PresetManager> presetManager;
|
|
|
|
|
|
2026-08-15 15:36:28 +02:00
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FDNReverbEditor)
|
2026-08-15 18:31:51 +02:00
|
|
|
};
|