2023-07-18 16:25:09 +00:00
|
|
|
#pragma once
|
|
|
|
#include "../shape/Vector2.h"
|
|
|
|
#include <JuceHeader.h>
|
|
|
|
|
2023-07-21 10:08:55 +00:00
|
|
|
class FloatParameter : public juce::AudioProcessorParameterWithID {
|
2023-07-18 16:25:09 +00:00
|
|
|
public:
|
|
|
|
std::atomic<float> min = 0.0;
|
|
|
|
std::atomic<float> max = 1.0;
|
|
|
|
std::atomic<float> step = 0.001;
|
|
|
|
|
2023-07-21 10:08:55 +00:00
|
|
|
FloatParameter(juce::String name, juce::String id, float value, float min, float max, float step = 0.001, juce::String label = "") : juce::AudioProcessorParameterWithID(id, name), value(value), min(min), max(max), step(step), label(label) {}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
juce::String getName(int maximumStringLength) const override {
|
|
|
|
return name.substring(0, maximumStringLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
juce::String getLabel() const override {
|
2023-07-20 19:01:09 +00:00
|
|
|
return label;
|
|
|
|
}
|
|
|
|
|
2023-07-18 16:25:09 +00:00
|
|
|
// returns value in range [0, 1]
|
|
|
|
float getNormalisedValue(float value) const {
|
|
|
|
// clip value to valid range
|
2023-07-20 19:01:09 +00:00
|
|
|
auto min = this->min.load();
|
|
|
|
auto max = this->max.load();
|
2023-07-18 16:25:09 +00:00
|
|
|
value = juce::jlimit(min, max, value);
|
|
|
|
// normalize value to range [0, 1]
|
2023-07-20 19:01:09 +00:00
|
|
|
return (value - min) / (max - min);
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
float getUnnormalisedValue(float value) const {
|
2023-07-20 19:01:09 +00:00
|
|
|
value = juce::jlimit(0.0f, 1.0f, value);
|
2023-07-18 16:25:09 +00:00
|
|
|
auto min = this->min.load();
|
|
|
|
auto max = this->max.load();
|
|
|
|
return min + value * (max - min);
|
2023-07-20 19:01:09 +00:00
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
float getValue() const override {
|
|
|
|
return getNormalisedValue(value.load());
|
|
|
|
}
|
|
|
|
|
|
|
|
float getValueUnnormalised() const {
|
2023-07-20 19:01:09 +00:00
|
|
|
return value.load();
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
void setValue(float newValue) override {
|
|
|
|
value = getUnnormalisedValue(newValue);
|
2023-07-20 19:01:09 +00:00
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
void setValueUnnormalised(float newValue) {
|
2023-07-20 19:01:09 +00:00
|
|
|
value = newValue;
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
void setUnnormalisedValueNotifyingHost(float newValue) {
|
2023-07-20 19:01:09 +00:00
|
|
|
setValueNotifyingHost(getNormalisedValue(newValue));
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
float getDefaultValue() const override {
|
2023-07-20 19:01:09 +00:00
|
|
|
return 0.0f;
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
int getNumSteps() const override {
|
2023-07-20 19:01:09 +00:00
|
|
|
return (max.load() - min.load()) / step.load();
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
bool isDiscrete() const override {
|
2023-07-20 19:01:09 +00:00
|
|
|
return false;
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
bool isBoolean() const override {
|
2023-07-20 19:01:09 +00:00
|
|
|
return false;
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
bool isOrientationInverted() const override {
|
2023-07-20 19:01:09 +00:00
|
|
|
return false;
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
juce::String getText(float value, int maximumStringLength) const override {
|
|
|
|
auto string = juce::String(getUnnormalisedValue(value), 3);
|
|
|
|
return string.substring(0, maximumStringLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
float getValueForText(const juce::String& text) const override {
|
2023-07-20 19:01:09 +00:00
|
|
|
return getNormalisedValue(text.getFloatValue());
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
bool isAutomatable() const override {
|
2023-07-20 19:01:09 +00:00
|
|
|
return true;
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
bool isMetaParameter() const override {
|
2023-07-20 19:01:09 +00:00
|
|
|
return false;
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
juce::AudioProcessorParameter::Category getCategory() const override {
|
2023-07-20 19:01:09 +00:00
|
|
|
return juce::AudioProcessorParameter::genericParameter;
|
|
|
|
}
|
2023-07-18 16:25:09 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
// value is not necessarily in the range [min, max] so effect applications may need to clip to a valid range
|
|
|
|
std::atomic<float> value = 0.0;
|
2023-07-20 19:01:09 +00:00
|
|
|
juce::String label;
|
|
|
|
};
|
|
|
|
|
2023-07-21 10:08:55 +00:00
|
|
|
class IntParameter : public juce::AudioProcessorParameterWithID {
|
2023-07-20 19:01:09 +00:00
|
|
|
public:
|
|
|
|
std::atomic<int> min = 0;
|
|
|
|
std::atomic<int> max = 10;
|
|
|
|
|
2023-07-21 10:41:01 +00:00
|
|
|
IntParameter(juce::String name, juce::String id, int value, int min, int max) : AudioProcessorParameterWithID(id, name), value(value), min(min), max(max) {}
|
2023-07-20 19:01:09 +00:00
|
|
|
|
|
|
|
juce::String getName(int maximumStringLength) const override {
|
|
|
|
return name.substring(0, maximumStringLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
juce::String getLabel() const override {
|
|
|
|
return juce::String();
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns value in range [0, 1]
|
|
|
|
float getNormalisedValue(float value) const {
|
|
|
|
// clip value to valid range
|
|
|
|
auto min = this->min.load();
|
|
|
|
auto max = this->max.load();
|
|
|
|
value = juce::jlimit(min, max, (int) value);
|
|
|
|
// normalize value to range [0, 1]
|
|
|
|
return (value - min) / (max - min);
|
|
|
|
}
|
|
|
|
|
|
|
|
float getUnnormalisedValue(float value) const {
|
|
|
|
value = juce::jlimit(0.0f, 1.0f, value);
|
|
|
|
auto min = this->min.load();
|
|
|
|
auto max = this->max.load();
|
|
|
|
return min + value * (max - min);
|
|
|
|
}
|
|
|
|
|
|
|
|
float getValue() const override {
|
|
|
|
return getNormalisedValue(value.load());
|
|
|
|
}
|
|
|
|
|
|
|
|
float getValueUnnormalised() const {
|
|
|
|
return value.load();
|
|
|
|
}
|
|
|
|
|
|
|
|
void setValue(float newValue) override {
|
|
|
|
value = getUnnormalisedValue(newValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setValueUnnormalised(float newValue) {
|
|
|
|
value = newValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setUnnormalisedValueNotifyingHost(float newValue) {
|
|
|
|
setValueNotifyingHost(getNormalisedValue(newValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
float getDefaultValue() const override {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getNumSteps() const override {
|
|
|
|
return max.load() - min.load() + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDiscrete() const override {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isBoolean() const override {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isOrientationInverted() const override {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
juce::String getText(float value, int maximumStringLength) const override {
|
|
|
|
auto string = juce::String((int) getUnnormalisedValue(value));
|
|
|
|
return string.substring(0, maximumStringLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
float getValueForText(const juce::String& text) const override {
|
|
|
|
return getNormalisedValue(text.getIntValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isAutomatable() const override {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isMetaParameter() const override {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
juce::AudioProcessorParameter::Category getCategory() const override {
|
|
|
|
return juce::AudioProcessorParameter::genericParameter;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// value is not necessarily in the range [min, max] so effect applications may need to clip to a valid range
|
|
|
|
std::atomic<int> value = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class LfoType : int {
|
|
|
|
Static = 1,
|
|
|
|
Sine = 2,
|
|
|
|
Square = 3,
|
|
|
|
Seesaw = 4,
|
|
|
|
Triangle = 5,
|
|
|
|
Sawtooth = 6,
|
|
|
|
ReverseSawtooth = 7,
|
|
|
|
Noise = 8
|
|
|
|
};
|
|
|
|
|
2023-07-20 20:54:21 +00:00
|
|
|
class LfoTypeParameter : public IntParameter {
|
|
|
|
public:
|
|
|
|
LfoTypeParameter(juce::String name, juce::String id, int value) : IntParameter(name, id, value, 1, 8) {}
|
|
|
|
|
|
|
|
juce::String getText(float value, int maximumStringLength) const override {
|
|
|
|
switch ((LfoType)(int)getUnnormalisedValue(value)) {
|
|
|
|
case LfoType::Static:
|
|
|
|
return "Static";
|
|
|
|
case LfoType::Sine:
|
|
|
|
return "Sine";
|
|
|
|
case LfoType::Square:
|
|
|
|
return "Square";
|
|
|
|
case LfoType::Seesaw:
|
|
|
|
return "Seesaw";
|
|
|
|
case LfoType::Triangle:
|
|
|
|
return "Triangle";
|
|
|
|
case LfoType::Sawtooth:
|
|
|
|
return "Sawtooth";
|
|
|
|
case LfoType::ReverseSawtooth:
|
|
|
|
return "Reverse Sawtooth";
|
|
|
|
case LfoType::Noise:
|
|
|
|
return "Noise";
|
|
|
|
default:
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float getValueForText(const juce::String& text) const override {
|
|
|
|
if (text == "Static") {
|
|
|
|
return (int)LfoType::Static;
|
|
|
|
} else if (text == "Sine") {
|
|
|
|
return (int)LfoType::Sine;
|
|
|
|
} else if (text == "Square") {
|
|
|
|
return (int)LfoType::Square;
|
|
|
|
} else if (text == "Seesaw") {
|
|
|
|
return (int)LfoType::Seesaw;
|
|
|
|
} else if (text == "Triangle") {
|
|
|
|
return (int)LfoType::Triangle;
|
|
|
|
} else if (text == "Sawtooth") {
|
|
|
|
return (int)LfoType::Sawtooth;
|
|
|
|
} else if (text == "Reverse Sawtooth") {
|
|
|
|
return (int)LfoType::ReverseSawtooth;
|
|
|
|
} else if (text == "Noise") {
|
|
|
|
return (int)LfoType::Noise;
|
|
|
|
} else {
|
|
|
|
return (int)LfoType::Static;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-07-20 19:01:09 +00:00
|
|
|
class EffectParameter : public FloatParameter {
|
|
|
|
public:
|
|
|
|
std::atomic<bool> smoothValueChange = true;
|
2023-07-21 10:08:55 +00:00
|
|
|
LfoTypeParameter* lfo = new LfoTypeParameter(name + " LFO", paramID + "Lfo", 1);
|
|
|
|
FloatParameter* lfoRate = new FloatParameter(name + " LFO Rate", paramID + "LfoRate", 1.0f, 0.0f, 100.0f, 0.1f, "Hz");
|
2023-07-20 20:41:53 +00:00
|
|
|
std::atomic<float> phase = 0.0f;
|
2023-07-20 19:01:09 +00:00
|
|
|
|
|
|
|
std::vector<juce::AudioProcessorParameter*> getParameters() {
|
2023-07-21 10:08:55 +00:00
|
|
|
std::vector<juce::AudioProcessorParameter*> parameters;
|
|
|
|
parameters.push_back(this);
|
|
|
|
if (lfo != nullptr) {
|
|
|
|
parameters.push_back(lfo);
|
|
|
|
}
|
|
|
|
if (lfoRate != nullptr) {
|
|
|
|
parameters.push_back(lfoRate);
|
|
|
|
}
|
|
|
|
return parameters;
|
2023-07-20 19:01:09 +00:00
|
|
|
}
|
|
|
|
|
2023-07-21 10:08:55 +00:00
|
|
|
void disableLfo() {
|
|
|
|
delete lfo;
|
|
|
|
delete lfoRate;
|
|
|
|
lfo = nullptr;
|
|
|
|
lfoRate = nullptr;
|
|
|
|
}
|
|
|
|
|
2023-07-20 19:01:09 +00:00
|
|
|
EffectParameter(juce::String name, juce::String id, float value, float min, float max, float step = 0.001, bool smoothValueChange = true) : FloatParameter(name, id, value, min, max, step), smoothValueChange(smoothValueChange) {}
|
2023-07-18 16:25:09 +00:00
|
|
|
};
|