Skip to content

Commit

Permalink
surge-fx: replace AccSlider with sst/jucegui/Knob.h (#7928)
Browse files Browse the repository at this point in the history
replace the juce knob we wrote years ago with the one from sst-jucegui as step one of an fx panel rebuild. Test build automation invalidation and accessibility
  • Loading branch information
shih1 authored Jan 1, 2025
1 parent f7c627f commit cf87ac7
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 43 deletions.
51 changes: 51 additions & 0 deletions src/surge-fx/KnobSource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef SURGE_SRC_SURGE_FX_KNOBSOURCE_H
#define SURGE_SRC_SURGE_FX_KNOBSOURCE_H

#include <juce_gui_basics/juce_gui_basics.h>
#include <sst/jucegui/data/Continuous.h>
#include <sst/jucegui/util/DebugHelpers.h>

struct KnobSource : sst::jucegui::data::Continuous
{
KnobSource(SurgefxAudioProcessor &p, SurgeFXParamDisplay &d, int i)
: processor(p), display(d), id(i)
{
}

std::string label{"KnobSource"};
std::string getLabel() const override { return label; }
void setLabel(std::string input) { label = input; }
float value{0};
float getValue() const override { return value; }
float getDefaultValue() const override { return processor.getFXStorageDefaultValue01(id); }

void setValueFromGUI(const float &f) override
{
value = f;
for (auto *l : guilisteners)
l->dataChanged();
for (auto *l : modellisteners)
l->dataChanged();

this->processor.setFXParamValue01(id, value);
display.setDisplay(getValueAsStringFor(value));
}

std::string getValueAsStringFor(float f) const override
{
return processor.getParamValue(id).c_str();
}

void setValueFromModel(const float &f) override
{
value = f;
for (auto *l : guilisteners)
l->dataChanged();
display.setDisplay(getValueAsStringFor(value));
}

SurgefxAudioProcessor &processor;
SurgeFXParamDisplay &display;
int id;
};
#endif // SURGE_SRC_SURGE_FX_KNOBSOURCE_H
108 changes: 68 additions & 40 deletions src/surge-fx/SurgeFXEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,14 @@ struct Picker : public juce::Component

//==============================================================================
SurgefxAudioProcessorEditor::SurgefxAudioProcessorEditor(SurgefxAudioProcessor &p)
: AudioProcessorEditor(&p), processor(p)
: AudioProcessorEditor(&p),
sst::jucegui::style::StyleConsumer(sst::jucegui::components::Knob::Styles::styleClass),
styleSheet(sst::jucegui::style::StyleSheet::getBuiltInStyleSheet(
sst::jucegui::style::StyleSheet::DARK)),
processor(p)
{
sst::jucegui::style::StyleSheet::initializeStyleSheets([]() {});

processor.storage->addErrorListener(this);
setAccessible(true);
setFocusContainerType(juce::Component::FocusContainerType::keyboardFocusContainer);
Expand All @@ -132,31 +138,32 @@ SurgefxAudioProcessorEditor::SurgefxAudioProcessorEditor(SurgefxAudioProcessor &
picker = std::make_unique<Picker>(this);
addAndMakeVisibleRecordOrder(picker.get());

auto backgroundColour = findColour(SurgeLookAndFeel::SurgeColourIds::componentBgStart);
auto surgeOrange = findColour(SurgeLookAndFeel::SurgeColourIds::orange);

using knobStyle = sst::jucegui::components::Knob::Styles;
styleSheet->setColour(knobStyle::styleClass, knobStyle::handle, backgroundColour);
styleSheet->setColour(knobStyle::styleClass, knobStyle::knobbase, backgroundColour);
styleSheet->setColour(knobStyle::styleClass, knobStyle::value, surgeOrange);
styleSheet->setColour(knobStyle::styleClass, knobStyle::value_hover, surgeOrange);

for (int i = 0; i < n_fx_params; ++i)
{
fxParamSliders[i].setRange(0.0, 1.0, 0.0001);
fxParamSliders[i].setValue(processor.getFXStorageValue01(i),
juce::NotificationType::dontSendNotification);
fxParamSliders[i].setSliderStyle(juce::Slider::SliderStyle::RotaryHorizontalVerticalDrag);
fxParamSliders[i].setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, true, 0,
0);
fxParamSliders[i].setChangeNotificationOnlyOnRelease(false);
fxParamSliders[i].setEnabled(processor.getParamEnabled(i));
fxParamSliders[i].onValueChange = [i, this]() {
this->processor.prepareParametersAbsentAudio();
this->processor.setFXParamValue01(i, this->fxParamSliders[i].getValue());
fxParamDisplay[i].setDisplay(
processor.getParamValueFromFloat(i, this->fxParamSliders[i].getValue()));
fxParamSliders[i].setTextValue(processor.getParamValue(i).c_str());
};
fxParamSliders[i].onDragStart = [i, this]() {
this->processor.setUserEditingFXParam(i, true);
};
fxParamSliders[i].onDragEnd = [i, this]() {
this->processor.setUserEditingFXParam(i, false);
};
fxParamSliders[i].setTitle("Parameter " + std::to_string(i) + " Knob");
addAndMakeVisibleRecordOrder(&(fxParamSliders[i]));
auto knob = std::make_unique<sst::jucegui::components::Knob>();
auto knobSource = std::make_unique<KnobSource>(processor, fxParamDisplay[i], i);

knob->setStyle(styleSheet);
knob->setModulationDisplay(sst::jucegui::components::Knob::Modulatable::NONE);

auto paramName = processor.getParamName(i) + " " + processor.getParamGroup(i);
knobSource->setValueFromGUI(processor.getFXStorageValue01(i));
knobSource->setLabel(paramName + " Knob");

knob->setSource(knobSource.get());

addAndMakeVisible(knob.get());
knobs.push_back(std::move(knob));
sources.push_back(std::move(knobSource));

fxTempoSync[i].setOnOffImage(BinaryData::TS_Act_svg, BinaryData::TS_Act_svgSize,
BinaryData::TS_Deact_svg, BinaryData::TS_Deact_svgSize);
Expand All @@ -168,7 +175,7 @@ SurgefxAudioProcessorEditor::SurgefxAudioProcessorEditor(SurgefxAudioProcessor &
this->processor.setFXParamTempoSync(i, this->fxTempoSync[i].getToggleState());
this->processor.setFXStorageTempoSync(i, this->fxTempoSync[i].getToggleState());
fxParamDisplay[i].setDisplay(
processor.getParamValueFromFloat(i, this->fxParamSliders[i].getValue()));
processor.getParamValueFromFloat(i, processor.getFXStorageValue01(i)));
this->processor.setUserEditingParamFeature(i, false);
};

Expand Down Expand Up @@ -201,7 +208,7 @@ SurgefxAudioProcessorEditor::SurgefxAudioProcessorEditor(SurgefxAudioProcessor &
this->processor.setFXParamExtended(i, this->fxExtended[i].getToggleState());
this->processor.setFXStorageExtended(i, this->fxExtended[i].getToggleState());
fxParamDisplay[i].setDisplay(
processor.getParamValueFromFloat(i, this->fxParamSliders[i].getValue()));
processor.getParamValueFromFloat(i, processor.getFXStorageValue01(i)));
this->processor.setUserEditingParamFeature(i, false);
};
fxExtended[i].setTitle("Parameter " + std::to_string(i) + " Extended");
Expand All @@ -216,8 +223,9 @@ SurgefxAudioProcessorEditor::SurgefxAudioProcessorEditor(SurgefxAudioProcessor &
this->processor.setUserEditingParamFeature(i, true);
this->processor.setFXParamAbsolute(i, this->fxAbsoluted[i].getToggleState());
this->processor.setFXStorageAbsolute(i, this->fxAbsoluted[i].getToggleState());

fxParamDisplay[i].setDisplay(
processor.getParamValueFromFloat(i, this->fxParamSliders[i].getValue()));
processor.getParamValueFromFloat(i, processor.getFXStorageValue01(i)));
this->processor.setUserEditingParamFeature(i, false);
};

Expand Down Expand Up @@ -261,6 +269,7 @@ SurgefxAudioProcessorEditor::SurgefxAudioProcessorEditor(SurgefxAudioProcessor &

idleTimer = std::make_unique<IdleTimer>(this);
idleTimer->startTimer(1000 / 5);
resized();
}

SurgefxAudioProcessorEditor::~SurgefxAudioProcessorEditor()
Expand All @@ -282,45 +291,60 @@ void SurgefxAudioProcessorEditor::resetLabels()
handler->notifyAccessibilityEvent(juce::AccessibilityEvent::valueChanged);
}
};

knobs.clear();
sources.clear();

for (int i = 0; i < n_fx_params; ++i)
{
auto nm = processor.getParamName(i) + " " + processor.getParamGroup(i);
fxParamSliders[i].setValue(processor.getFXStorageValue01(i),
juce::NotificationType::dontSendNotification);
auto knob = std::make_unique<sst::jucegui::components::Knob>();
auto knobSource = std::make_unique<KnobSource>(processor, fxParamDisplay[i], i);

knob->setStyle(styleSheet);
knob->setModulationDisplay(sst::jucegui::components::Knob::Modulatable::NONE);

auto paramName = processor.getParamName(i) + " " + processor.getParamGroup(i);
knobSource->setValueFromGUI(processor.getFXStorageValue01(i));
auto name = paramName + " Knob";
knobSource->setLabel(name);

knob->setSource(knobSource.get());
knob->setEnabled(processor.getParamEnabled(i));

addAndMakeVisible(*knob);
knobs.push_back(std::move(knob));
sources.push_back(std::move(knobSource));

fxParamDisplay[i].setDisplay(processor.getParamValue(i).c_str());
fxParamDisplay[i].setGroup(processor.getParamGroup(i).c_str());
fxParamDisplay[i].setName(processor.getParamName(i).c_str());
fxParamDisplay[i].allowsTypein = processor.canSetParameterByString(i);

fxParamDisplay[i].setEnabled(processor.getParamEnabled(i));
fxParamDisplay[i].setAppearsDeactivated(processor.getFXStorageAppearsDeactivated(i));
fxParamSliders[i].setEnabled(processor.getParamEnabled(i) &&
!processor.getFXStorageAppearsDeactivated(i));
st(fxParamSliders[i], nm + " Knob");
fxParamSliders[i].setTextValue(processor.getParamValue(i).c_str());

fxTempoSync[i].setEnabled(processor.canTempoSync(i));
fxTempoSync[i].setAccessible(processor.canTempoSync(i));
fxTempoSync[i].setToggleState(processor.getFXStorageTempoSync(i),
juce::NotificationType::dontSendNotification);
st(fxTempoSync[i], nm + " Tempo Synced");
st(fxTempoSync[i], name + " Tempo Synced");
fxDeactivated[i].setEnabled(false);

fxExtended[i].setEnabled(processor.canExtend(i));
fxExtended[i].setToggleState(processor.getFXStorageExtended(i),
juce::NotificationType::dontSendNotification);
fxExtended[i].setAccessible(processor.canExtend(i));
st(fxExtended[i], nm + " Extended");
st(fxExtended[i], name + " Extended");
fxAbsoluted[i].setEnabled(processor.canAbsolute(i));
fxAbsoluted[i].setToggleState(processor.getFXStorageAbsolute(i),
juce::NotificationType::dontSendNotification);
fxAbsoluted[i].setAccessible(processor.canAbsolute(i));
st(fxAbsoluted[i], nm + " Absolute");
st(fxAbsoluted[i], name + " Absolute");
fxDeactivated[i].setEnabled(processor.canDeactitvate(i));
fxDeactivated[i].setToggleState(processor.getFXStorageDeactivated(i),
juce::NotificationType::dontSendNotification);
fxDeactivated[i].setAccessible(processor.canDeactitvate(i));
st(fxDeactivated[i], nm + " Deactivated");
st(fxDeactivated[i], name + " Deactivated");
}

picker->repaint();
Expand All @@ -331,6 +355,7 @@ void SurgefxAudioProcessorEditor::resetLabels()
{
h->notifyAccessibilityEvent(juce::AccessibilityEvent::structureChanged);
}
resized();
}

void SurgefxAudioProcessorEditor::setEffectType(int i)
Expand All @@ -353,7 +378,7 @@ void SurgefxAudioProcessorEditor::paramsChangedCallback()
{
if (i < n_fx_params)
{
fxParamSliders[i].setValue(fv[i], juce::NotificationType::dontSendNotification);
sources.at(i)->setValueFromModel(fv[i]);
fxParamDisplay[i].setDisplay(processor.getParamValueFor(i, fv[i]));
}
else
Expand Down Expand Up @@ -389,7 +414,10 @@ void SurgefxAudioProcessorEditor::resized()
juce::Rectangle<int> position{(i / 6) * getWidth() / 2 + sliderOff,
(i % 6) * rowHeight + ypos0, rowHeight - sliderOff,
rowHeight - sliderOff};
fxParamSliders[i].setBounds(position);

position = position.reduced(position.getWidth() * 0.10, position.getHeight() * 0.10);

knobs.at(i).get()->setBounds(position);

int buttonSize = 19;
if (getWidth() < baseWidth)
Expand Down
13 changes: 11 additions & 2 deletions src/surge-fx/SurgeFXEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,20 @@

#include "SurgeFXProcessor.h"
#include "SurgeLookAndFeel.h"
#include "KnobSource.h"

#include "juce_gui_basics/juce_gui_basics.h"

#include <sst/jucegui/style/StyleSheet.h>
#include <sst/jucegui/components/Knob.h>

//==============================================================================
/**
*/
class SurgefxAudioProcessorEditor : public juce::AudioProcessorEditor,
juce::AsyncUpdater,
SurgeStorage::ErrorListener
SurgeStorage::ErrorListener,
sst::jucegui::style::StyleConsumer
{
public:
SurgefxAudioProcessorEditor(SurgefxAudioProcessor &);
Expand Down Expand Up @@ -105,6 +110,9 @@ class SurgefxAudioProcessorEditor : public juce::AudioProcessorEditor,

static constexpr int baseWidth = 600, baseHeight = 55 * 6 + 80 + topSection;

std::vector<std::unique_ptr<sst::jucegui::components::Knob>> knobs;
std::vector<std::unique_ptr<KnobSource>> sources;

private:
struct AccSlider : public juce::Slider
{
Expand Down Expand Up @@ -159,7 +167,7 @@ class SurgefxAudioProcessorEditor : public juce::AudioProcessorEditor,
return false;
}
};
AccSlider fxParamSliders[n_fx_params];

SurgeFXParamDisplay fxParamDisplay[n_fx_params];
SurgeTempoSyncSwitch fxTempoSync[n_fx_params];
SurgeTempoSyncSwitch fxDeactivated[n_fx_params];
Expand Down Expand Up @@ -196,6 +204,7 @@ class SurgefxAudioProcessorEditor : public juce::AudioProcessorEditor,

public:
std::vector<juce::Component *> accessibleOrderWeakRefs;
std::shared_ptr<sst::jucegui::style::StyleSheet> styleSheet;

public:
std::unique_ptr<juce::ComponentTraverser> createFocusTraverser() override;
Expand Down
4 changes: 4 additions & 0 deletions src/surge-fx/SurgeFXProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ class SurgefxAudioProcessor : public juce::AudioProcessor,

int getEffectType() { return effectNum; }
float getFXStorageValue01(int i) { return fxstorage->p[fx_param_remap[i]].get_value_f01(); }
float getFXStorageDefaultValue01(int i)
{
return fxstorage->p[fx_param_remap[i]].get_default_value_f01();
}
float getFXParamValue01(int i) { return *(fxParams[i]); }
void setFXParamValue01(int i, float f) { *(fxParams[i]) = f; }

Expand Down

0 comments on commit cf87ac7

Please sign in to comment.