2026-08-05 19:55:57 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <JuceHeader.h>
|
|
|
|
|
#include "ui/SequencerMatrix.h"
|
|
|
|
|
|
2026-08-05 23:12:17 +02:00
|
|
|
class MonostepAudioProcessor;
|
2026-08-05 19:55:57 +02:00
|
|
|
|
|
|
|
|
class EditorLookAndFeel final : public juce::LookAndFeel_V4
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
EditorLookAndFeel();
|
|
|
|
|
|
|
|
|
|
void drawRotarySlider (juce::Graphics&, int x, int y, int w, int h,
|
|
|
|
|
float sliderPos, float rotaryStartAngle, float rotaryEndAngle,
|
|
|
|
|
juce::Slider&) override;
|
|
|
|
|
|
|
|
|
|
void drawToggleButton (juce::Graphics&, juce::ToggleButton&,
|
|
|
|
|
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override;
|
|
|
|
|
|
|
|
|
|
void drawButtonBackground (juce::Graphics&, juce::Button&,
|
|
|
|
|
const juce::Colour& backgroundColour, bool shouldDrawButtonAsHighlighted,
|
|
|
|
|
bool shouldDrawButtonAsDown) override;
|
|
|
|
|
|
|
|
|
|
void drawButtonText (juce::Graphics&, juce::TextButton&,
|
|
|
|
|
bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override;
|
2026-08-05 23:12:17 +02:00
|
|
|
|
|
|
|
|
void drawComboBox (juce::Graphics&, int width, int height, bool isMouseButtonDown,
|
|
|
|
|
int buttonX, int buttonY, int buttonW, int buttonH, juce::ComboBox&) override;
|
|
|
|
|
juce::Font getComboBoxFont (juce::ComboBox&) override;
|
|
|
|
|
|
|
|
|
|
void drawPopupMenuBackground (juce::Graphics&, int width, int height) override;
|
|
|
|
|
void drawPopupMenuItem (juce::Graphics&, const juce::Rectangle<int>& area,
|
|
|
|
|
bool isSeparator, bool isActive, bool isHighlighted, bool isTicked, bool hasSubMenu,
|
|
|
|
|
const juce::String& text, const juce::String& shortcutKeyText,
|
|
|
|
|
const juce::Drawable* icon, const juce::Colour* textColour) override;
|
|
|
|
|
juce::Font getPopupMenuFont() override;
|
2026-08-05 19:55:57 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Knob final : public juce::Component
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit Knob (const juce::String& title);
|
|
|
|
|
|
|
|
|
|
juce::Slider& getSlider() { return slider; }
|
|
|
|
|
|
|
|
|
|
void attach (juce::AudioProcessorValueTreeState& apvts, const juce::String& paramId)
|
|
|
|
|
{
|
|
|
|
|
attachment = std::make_unique<juce::AudioProcessorValueTreeState::SliderAttachment> (apvts, paramId, slider);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setFormat (std::function<juce::String (float)> formatFn)
|
|
|
|
|
{
|
|
|
|
|
format = std::move (formatFn);
|
|
|
|
|
updateValueLabel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setOnValueChanged (std::function<void (float)> valueChangedFn)
|
|
|
|
|
{
|
|
|
|
|
customOnValueChange = std::move (valueChangedFn);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-06 15:51:56 +02:00
|
|
|
void setDragSensitivity (int pixels) { slider.setMouseDragSensitivity (pixels); }
|
|
|
|
|
|
2026-08-05 19:55:57 +02:00
|
|
|
void resized() override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void updateValueLabel();
|
|
|
|
|
|
|
|
|
|
juce::Slider slider;
|
|
|
|
|
juce::Label titleLabel;
|
|
|
|
|
juce::Label valueLabel;
|
|
|
|
|
std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment> attachment;
|
|
|
|
|
std::function<juce::String (float)> format;
|
|
|
|
|
std::function<void (float)> customOnValueChange;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class ChoiceBar final : public juce::Component,
|
|
|
|
|
public juce::AudioProcessorValueTreeState::Listener
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ChoiceBar (juce::AudioProcessorValueTreeState& apvts,
|
|
|
|
|
const juce::String& paramId,
|
|
|
|
|
const juce::StringArray& choices);
|
|
|
|
|
|
|
|
|
|
ChoiceBar (const juce::StringArray& choices,
|
|
|
|
|
std::function<void (int)> onSelected);
|
|
|
|
|
|
|
|
|
|
~ChoiceBar() override;
|
|
|
|
|
|
|
|
|
|
void parameterChanged (const juce::String&, float) override;
|
|
|
|
|
|
|
|
|
|
void setManualHandler (std::function<void (int)> handler) { manualHandler = std::move (handler); }
|
|
|
|
|
|
2026-08-06 15:51:56 +02:00
|
|
|
void setSelectedIndex (int index)
|
|
|
|
|
{
|
|
|
|
|
index = juce::jlimit (0, juce::jmax (0, buttons.size() - 1), index);
|
|
|
|
|
for (int i = 0; i < buttons.size(); ++i)
|
|
|
|
|
buttons[i]->setToggleState (i == index, juce::dontSendNotification);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-05 19:55:57 +02:00
|
|
|
void resized() override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void refreshFromParam();
|
|
|
|
|
void setIndex (int index);
|
|
|
|
|
|
|
|
|
|
juce::AudioProcessorValueTreeState* apvts = nullptr;
|
|
|
|
|
juce::String paramId;
|
|
|
|
|
std::function<void (int)> manualHandler;
|
|
|
|
|
juce::OwnedArray<juce::TextButton> buttons;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class StepPanel final : public juce::Component
|
|
|
|
|
{
|
|
|
|
|
public:
|
2026-08-05 23:12:17 +02:00
|
|
|
explicit StepPanel (MonostepAudioProcessor& processor);
|
2026-08-05 19:55:57 +02:00
|
|
|
|
|
|
|
|
void setSelectedStep (int stepIdx);
|
|
|
|
|
void refresh();
|
|
|
|
|
|
|
|
|
|
std::function<void (int)> onStepSelected;
|
|
|
|
|
|
|
|
|
|
void resized() override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void clearPattern();
|
|
|
|
|
|
2026-08-05 23:12:17 +02:00
|
|
|
MonostepAudioProcessor& processor;
|
2026-08-05 19:55:57 +02:00
|
|
|
|
|
|
|
|
int selectedStep = 0;
|
|
|
|
|
bool updating = false;
|
|
|
|
|
|
|
|
|
|
juce::Label titleLabel;
|
|
|
|
|
juce::Label noteLabel;
|
|
|
|
|
juce::Label gateLabel;
|
|
|
|
|
Knob fineKnob;
|
|
|
|
|
juce::TextButton prevButton;
|
|
|
|
|
juce::TextButton nextButton;
|
|
|
|
|
juce::TextButton clearButton;
|
2026-08-05 23:12:17 +02:00
|
|
|
juce::TextButton shiftLeftButton;
|
|
|
|
|
juce::TextButton shiftRightButton;
|
|
|
|
|
|
|
|
|
|
juce::Label toolsCaption;
|
|
|
|
|
juce::ComboBox presetCombo;
|
|
|
|
|
juce::TextButton randomizeButton;
|
|
|
|
|
juce::Label randomizeCaption;
|
|
|
|
|
|
|
|
|
|
enum RandomGroup
|
|
|
|
|
{
|
|
|
|
|
RandomPattern,
|
|
|
|
|
RandomOsc,
|
|
|
|
|
RandomFilter,
|
|
|
|
|
RandomEnv,
|
|
|
|
|
RandomSeq,
|
|
|
|
|
RandomFx,
|
2026-08-06 18:38:32 +02:00
|
|
|
RandomAccent,
|
|
|
|
|
RandomSlide,
|
|
|
|
|
RandomFine,
|
|
|
|
|
RandomRate,
|
2026-08-05 23:12:17 +02:00
|
|
|
RandomGroupCount
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
juce::ToggleButton randomizeToggles[RandomGroupCount];
|
2026-08-06 15:51:56 +02:00
|
|
|
|
|
|
|
|
juce::ToggleButton retrigToggle;
|
|
|
|
|
std::unique_ptr<juce::AudioProcessorValueTreeState::ButtonAttachment> retrigAttachment;
|
|
|
|
|
|
|
|
|
|
juce::TextButton resetFineButton;
|
2026-08-05 19:55:57 +02:00
|
|
|
};
|
|
|
|
|
|
2026-08-05 23:12:17 +02:00
|
|
|
class MonostepAudioProcessorEditor final : public juce::AudioProcessorEditor,
|
2026-08-05 19:55:57 +02:00
|
|
|
public juce::Timer
|
|
|
|
|
{
|
|
|
|
|
public:
|
2026-08-05 23:12:17 +02:00
|
|
|
explicit MonostepAudioProcessorEditor (MonostepAudioProcessor& processor);
|
|
|
|
|
~MonostepAudioProcessorEditor() override;
|
2026-08-05 19:55:57 +02:00
|
|
|
|
|
|
|
|
void paint (juce::Graphics&) override;
|
|
|
|
|
void resized() override;
|
|
|
|
|
|
|
|
|
|
void timerCallback() override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void paintContent (juce::Graphics&);
|
|
|
|
|
|
|
|
|
|
class ContentComponent final : public juce::Component
|
|
|
|
|
{
|
|
|
|
|
public:
|
2026-08-05 23:12:17 +02:00
|
|
|
explicit ContentComponent (MonostepAudioProcessorEditor& owner) : ownerRef (owner) {}
|
2026-08-05 19:55:57 +02:00
|
|
|
|
|
|
|
|
void paint (juce::Graphics& g) override { ownerRef.paintContent (g); }
|
|
|
|
|
|
|
|
|
|
private:
|
2026-08-05 23:12:17 +02:00
|
|
|
MonostepAudioProcessorEditor& ownerRef;
|
2026-08-05 19:55:57 +02:00
|
|
|
};
|
|
|
|
|
|
2026-08-05 23:12:17 +02:00
|
|
|
MonostepAudioProcessor& processorRef;
|
2026-08-05 19:55:57 +02:00
|
|
|
|
|
|
|
|
ContentComponent content;
|
|
|
|
|
|
2026-08-06 18:38:32 +02:00
|
|
|
static constexpr int baseWidth = 1360;
|
2026-08-06 15:51:56 +02:00
|
|
|
static constexpr int baseHeight = 780;
|
2026-08-05 19:55:57 +02:00
|
|
|
|
|
|
|
|
float zoomFactor = 1.0f;
|
|
|
|
|
|
|
|
|
|
void setZoomFactor (float newZoom);
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<EditorLookAndFeel> lnf;
|
|
|
|
|
std::vector<std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment>> attachments;
|
|
|
|
|
|
|
|
|
|
Knob lengthKnob;
|
|
|
|
|
Knob swingKnob;
|
|
|
|
|
Knob rootKnob;
|
|
|
|
|
Knob gateKnob;
|
|
|
|
|
Knob masterKnob;
|
2026-08-05 23:12:17 +02:00
|
|
|
Knob coarseKnob;
|
|
|
|
|
Knob coarseKnob2;
|
2026-08-05 19:55:57 +02:00
|
|
|
Knob detuneKnob;
|
|
|
|
|
Knob mixKnob;
|
2026-08-05 23:12:17 +02:00
|
|
|
Knob fineKnob1;
|
|
|
|
|
Knob fineKnob2;
|
2026-08-05 19:55:57 +02:00
|
|
|
Knob cutoffKnob;
|
|
|
|
|
Knob resKnob;
|
|
|
|
|
Knob glideKnob;
|
|
|
|
|
Knob attackKnob;
|
|
|
|
|
Knob decayKnob;
|
|
|
|
|
Knob sustainKnob;
|
|
|
|
|
Knob releaseKnob;
|
2026-08-06 15:51:56 +02:00
|
|
|
Knob fAttackKnob;
|
|
|
|
|
Knob fDecayKnob;
|
|
|
|
|
Knob fSustainKnob;
|
|
|
|
|
Knob fReleaseKnob;
|
|
|
|
|
Knob fAmountKnob;
|
2026-08-05 23:12:17 +02:00
|
|
|
Knob driveKnob;
|
|
|
|
|
Knob ringKnob;
|
2026-08-06 16:35:34 +02:00
|
|
|
Knob delayTimeKnob;
|
2026-08-06 18:38:32 +02:00
|
|
|
Knob delayFeedbackKnob;
|
|
|
|
|
Knob delayDryWetKnob;
|
2026-08-06 16:35:34 +02:00
|
|
|
Knob reverbRoomKnob;
|
|
|
|
|
Knob reverbStrengthKnob;
|
|
|
|
|
Knob reverbDiffusionKnob;
|
2026-08-06 18:38:32 +02:00
|
|
|
Knob reverbDryWetKnob;
|
2026-08-06 16:35:34 +02:00
|
|
|
juce::ToggleButton delaySyncToggle;
|
|
|
|
|
std::unique_ptr<juce::AudioProcessorValueTreeState::ButtonAttachment> delaySyncAttachment;
|
2026-08-05 23:12:17 +02:00
|
|
|
Knob accentKnob;
|
2026-08-05 19:55:57 +02:00
|
|
|
|
|
|
|
|
ChoiceBar rateBar;
|
|
|
|
|
ChoiceBar octaveBar;
|
|
|
|
|
ChoiceBar zoomBar;
|
2026-08-05 23:45:59 +02:00
|
|
|
juce::ComboBox wave1Box;
|
|
|
|
|
juce::ComboBox wave2Box;
|
2026-08-06 15:51:56 +02:00
|
|
|
juce::ComboBox filterTypeBox;
|
2026-08-05 23:45:59 +02:00
|
|
|
std::unique_ptr<juce::AudioProcessorValueTreeState::ComboBoxAttachment> wave1Attachment;
|
|
|
|
|
std::unique_ptr<juce::AudioProcessorValueTreeState::ComboBoxAttachment> wave2Attachment;
|
2026-08-06 15:51:56 +02:00
|
|
|
std::unique_ptr<juce::AudioProcessorValueTreeState::ComboBoxAttachment> filterTypeAttachment;
|
2026-08-05 19:55:57 +02:00
|
|
|
|
|
|
|
|
SequencerMatrix matrix;
|
|
|
|
|
StepPanel stepPanel;
|
|
|
|
|
|
|
|
|
|
int lastPlayStep = -1;
|
|
|
|
|
|
|
|
|
|
void refreshEditor();
|
|
|
|
|
};
|