2026-08-04 03:33:53 +01:00
|
|
|
#include "DistrhoDetails.hpp"
|
2026-08-02 05:37:06 +01:00
|
|
|
#include "DistrhoPlugin.hpp"
|
|
|
|
|
#include "DistrhoPluginInfo.h"
|
|
|
|
|
|
2026-08-05 17:43:54 +01:00
|
|
|
#include <cmath>
|
|
|
|
|
|
2026-08-02 20:14:51 +01:00
|
|
|
#include "../../core/Clipper.hpp"
|
2026-08-05 13:46:12 +01:00
|
|
|
#include "../../core/Filter.hpp"
|
2026-08-02 20:14:51 +01:00
|
|
|
#include "../../core/Gain.hpp"
|
2026-08-04 03:33:53 +01:00
|
|
|
#include "../../core/Mixer.hpp"
|
2026-08-02 20:14:51 +01:00
|
|
|
|
2026-08-02 05:37:06 +01:00
|
|
|
START_NAMESPACE_DISTRHO
|
|
|
|
|
|
2026-08-04 05:25:40 +01:00
|
|
|
const int BUFFER_SIZE = 16384;
|
|
|
|
|
|
2026-08-05 13:46:12 +01:00
|
|
|
struct AudioBuffers {
|
|
|
|
|
float clippedL[BUFFER_SIZE];
|
|
|
|
|
float clippedR[BUFFER_SIZE];
|
|
|
|
|
float lpL[BUFFER_SIZE];
|
|
|
|
|
float lpR[BUFFER_SIZE];
|
|
|
|
|
};
|
|
|
|
|
|
2026-08-02 05:37:06 +01:00
|
|
|
class SquidgeDistortion : public Plugin {
|
2026-08-02 20:14:51 +01:00
|
|
|
|
2026-08-02 05:37:06 +01:00
|
|
|
public:
|
2026-08-04 05:15:46 +01:00
|
|
|
enum MixerChannels { kChannelDry, kChannelWet, kChannelCount };
|
2026-08-02 20:14:51 +01:00
|
|
|
enum Parameters {
|
|
|
|
|
kParamGain,
|
2026-08-02 22:58:56 +01:00
|
|
|
kParamClipMode,
|
2026-08-05 13:46:12 +01:00
|
|
|
kParamFilter,
|
|
|
|
|
kParamFilterFeedback,
|
2026-08-04 03:33:53 +01:00
|
|
|
kParamMixVolume,
|
2026-08-05 18:06:44 +01:00
|
|
|
kParamResonance,
|
2026-08-02 20:14:51 +01:00
|
|
|
kParameterCount // must be last
|
|
|
|
|
};
|
2026-08-04 03:33:53 +01:00
|
|
|
SquidgeDistortion()
|
2026-08-05 13:46:12 +01:00
|
|
|
: Plugin(kParameterCount, 0, 0), gain_(2.0f), mixer_(1.0f), filter_(440) {
|
2026-08-04 03:33:53 +01:00
|
|
|
mixer_.setInputGain(kChannelDry, 0.0f);
|
|
|
|
|
mixer_.setInputGain(kChannelWet, 1.0f);
|
|
|
|
|
}
|
2026-08-02 05:37:06 +01:00
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
const char *getLabel() const override { return "SquidgeDistortion"; }
|
|
|
|
|
const char *getDescription() const override {
|
|
|
|
|
return "Simple distortion plugin.";
|
|
|
|
|
}
|
|
|
|
|
const char *getMaker() const override { return "SquidgeSoft"; }
|
2026-08-02 17:17:23 +01:00
|
|
|
const char *getLicense() const override { return "GPL3"; }
|
|
|
|
|
uint32_t getVersion() const override { return d_version(0, 1, 0); }
|
|
|
|
|
int64_t getUniqueId() const override { return d_cconst('S', 'Q', 'D', 'T'); }
|
2026-08-02 05:37:06 +01:00
|
|
|
|
2026-08-02 20:14:51 +01:00
|
|
|
void initParameter(uint32_t index, Parameter ¶meter) override {
|
|
|
|
|
switch (index) {
|
|
|
|
|
case kParamGain:
|
|
|
|
|
parameter.name = "Gain";
|
|
|
|
|
parameter.symbol = "gain";
|
|
|
|
|
parameter.ranges.min = 1.0f;
|
|
|
|
|
parameter.ranges.def = 2.0f;
|
|
|
|
|
parameter.ranges.max = 10.0f;
|
|
|
|
|
parameter.hints = kParameterIsAutomatable;
|
2026-08-02 22:58:56 +01:00
|
|
|
break;
|
|
|
|
|
case kParamClipMode:
|
|
|
|
|
parameter.name = "Clip Mode";
|
|
|
|
|
parameter.symbol = "clipmode";
|
|
|
|
|
parameter.ranges.min = 0.0f;
|
|
|
|
|
parameter.ranges.def = 0.0f;
|
|
|
|
|
parameter.ranges.max = Clipper::kClipperModeCount - 1;
|
|
|
|
|
parameter.hints = kParameterIsAutomatable | kParameterIsInteger;
|
|
|
|
|
parameter.enumValues.count = Clipper::kClipperModeCount;
|
|
|
|
|
parameter.enumValues.restrictedMode = true;
|
2026-08-03 15:35:36 +01:00
|
|
|
|
|
|
|
|
static const ParameterEnumerationValue
|
|
|
|
|
sClipModes[Clipper::kClipperModeCount] = {
|
|
|
|
|
{0.0f, "Soft"}, {1.0f, "Hard"}, {2.0f, "Fold"}};
|
|
|
|
|
parameter.enumValues.values =
|
|
|
|
|
const_cast<ParameterEnumerationValue *>(sClipModes);
|
2026-08-02 20:14:51 +01:00
|
|
|
break;
|
2026-08-05 13:46:12 +01:00
|
|
|
case kParamFilter:
|
|
|
|
|
parameter.name = "Filter";
|
|
|
|
|
parameter.symbol = "filter";
|
|
|
|
|
parameter.ranges.min = 20.0f;
|
|
|
|
|
parameter.ranges.def = 1000.0f;
|
|
|
|
|
parameter.ranges.max = 10000.0f;
|
|
|
|
|
parameter.hints = kParameterIsAutomatable;
|
|
|
|
|
break;
|
|
|
|
|
case kParamFilterFeedback:
|
2026-08-05 18:06:44 +01:00
|
|
|
parameter.name = "Feedback";
|
2026-08-05 13:46:12 +01:00
|
|
|
parameter.symbol = "filterfeedback";
|
|
|
|
|
parameter.ranges.min = 0.0f;
|
2026-08-05 18:06:44 +01:00
|
|
|
parameter.ranges.def = 0.0f;
|
|
|
|
|
parameter.ranges.max = 0.95f;
|
2026-08-05 13:46:12 +01:00
|
|
|
parameter.hints = kParameterIsAutomatable;
|
|
|
|
|
break;
|
2026-08-04 03:33:53 +01:00
|
|
|
case kParamMixVolume:
|
|
|
|
|
parameter.name = "Dry/Wet";
|
|
|
|
|
parameter.symbol = "drywetvolume";
|
|
|
|
|
parameter.ranges.min = 0.0f;
|
|
|
|
|
parameter.ranges.def = 1.0f;
|
|
|
|
|
parameter.ranges.max = 1.0f;
|
|
|
|
|
parameter.hints = kParameterIsAutomatable;
|
|
|
|
|
break;
|
2026-08-05 18:06:44 +01:00
|
|
|
case kParamResonance:
|
|
|
|
|
parameter.name = "Resonance";
|
|
|
|
|
parameter.symbol = "resonance";
|
|
|
|
|
parameter.ranges.min = 0.0f;
|
|
|
|
|
parameter.ranges.def = 0.1f;
|
|
|
|
|
parameter.ranges.max = 1.0f;
|
|
|
|
|
parameter.hints = kParameterIsAutomatable;
|
|
|
|
|
break;
|
2026-08-02 20:14:51 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float getParameterValue(uint32_t index) const override {
|
|
|
|
|
switch (index) {
|
|
|
|
|
case kParamGain:
|
|
|
|
|
return gain_.getGain();
|
2026-08-02 22:58:56 +01:00
|
|
|
case kParamClipMode:
|
|
|
|
|
return (float)clipper_.getMode();
|
2026-08-05 13:46:12 +01:00
|
|
|
case kParamFilter:
|
|
|
|
|
return (float)filter_.getCutOff();
|
|
|
|
|
case kParamFilterFeedback:
|
|
|
|
|
return (float)filter_.getFeedback();
|
2026-08-04 03:33:53 +01:00
|
|
|
case kParamMixVolume:
|
|
|
|
|
return mixer_.getInputGain(kChannelWet);
|
2026-08-05 18:06:44 +01:00
|
|
|
case kParamResonance:
|
|
|
|
|
return (float)filter_.getResonance();
|
2026-08-02 20:14:51 +01:00
|
|
|
}
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setParameterValue(uint32_t index, float value) override {
|
|
|
|
|
switch (index) {
|
|
|
|
|
case kParamGain:
|
|
|
|
|
gain_.setGain(value);
|
|
|
|
|
break;
|
2026-08-02 22:58:56 +01:00
|
|
|
case kParamClipMode:
|
2026-08-05 17:43:54 +01:00
|
|
|
value = std::fmin(std::fmax(value, 0.0f),
|
|
|
|
|
static_cast<float>(Clipper::kClipperModeCount - 1));
|
|
|
|
|
clipper_.setMode(static_cast<Clipper::ClipperMode>(std::lround(value)));
|
2026-08-02 22:58:56 +01:00
|
|
|
break;
|
2026-08-05 13:46:12 +01:00
|
|
|
case kParamFilter:
|
|
|
|
|
filter_.setCutOff(value);
|
|
|
|
|
break;
|
|
|
|
|
case kParamFilterFeedback:
|
|
|
|
|
filter_.setFeedback(value);
|
|
|
|
|
break;
|
2026-08-04 03:33:53 +01:00
|
|
|
case kParamMixVolume:
|
|
|
|
|
mixer_.setInputGain(kChannelWet, value);
|
|
|
|
|
mixer_.setInputGain(kChannelDry, 1.0f - value);
|
|
|
|
|
break;
|
2026-08-05 18:06:44 +01:00
|
|
|
case kParamResonance:
|
|
|
|
|
filter_.setResonance(value);
|
|
|
|
|
break;
|
2026-08-02 20:14:51 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void run(const float **inputs, float **outputs, uint32_t frames) override {
|
2026-08-04 05:25:40 +01:00
|
|
|
if (frames > BUFFER_SIZE) {
|
|
|
|
|
for (uint32_t i = 0; i < frames; ++i) {
|
|
|
|
|
outputs[0][i] = inputs[0][i];
|
|
|
|
|
outputs[1][i] = inputs[1][i];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-08-05 13:46:12 +01:00
|
|
|
gain_.processStereo(inputs[0], inputs[1], buffers_.clippedL,
|
|
|
|
|
buffers_.clippedR, frames);
|
|
|
|
|
clipper_.processStereo(buffers_.clippedL, buffers_.clippedR,
|
|
|
|
|
buffers_.clippedL, buffers_.clippedR, frames);
|
|
|
|
|
filter_.processStereo(buffers_.clippedL, buffers_.clippedR, buffers_.lpL,
|
|
|
|
|
buffers_.lpR, frames);
|
2026-08-04 03:33:53 +01:00
|
|
|
|
2026-08-05 13:46:12 +01:00
|
|
|
const float *inputsL[2] = {inputs[0], buffers_.lpL};
|
|
|
|
|
const float *inputsR[2] = {inputs[1], buffers_.lpR};
|
2026-08-04 03:33:53 +01:00
|
|
|
|
|
|
|
|
mixer_.processStereo(inputsL, inputsR, outputs[0], outputs[1], frames);
|
2026-08-02 20:14:51 +01:00
|
|
|
}
|
2026-08-02 05:37:06 +01:00
|
|
|
|
2026-08-05 13:46:12 +01:00
|
|
|
void sampleRateChanged(double newSr) override {
|
|
|
|
|
filter_.setSampleRate(static_cast<float>(newSr));
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-02 05:37:06 +01:00
|
|
|
private:
|
2026-08-02 20:14:51 +01:00
|
|
|
Gain gain_;
|
|
|
|
|
Clipper clipper_;
|
2026-08-04 03:33:53 +01:00
|
|
|
Mixer<2> mixer_;
|
2026-08-05 13:46:12 +01:00
|
|
|
Filter filter_;
|
|
|
|
|
AudioBuffers buffers_;
|
2026-08-02 05:37:06 +01:00
|
|
|
|
|
|
|
|
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SquidgeDistortion);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Plugin *createPlugin() { return new SquidgeDistortion(); }
|
|
|
|
|
|
|
|
|
|
END_NAMESPACE_DISTRHO
|