Skip to content

Commit

Permalink
Add ADAA clipper
Browse files Browse the repository at this point in the history
  • Loading branch information
hemmer committed Mar 25, 2024
1 parent 700a5cc commit 9d3a09d
Showing 1 changed file with 56 additions and 13 deletions.
69 changes: 56 additions & 13 deletions src/Octaves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,42 @@ float aliasSuppressedOffsetSaw(const float* phases, float pw) {

for (int i = 0; i < 3; ++i) {
float pwp = 2 * phases[i] - 2 * pw; // range -1 to +1

pwp += simd::ifelse(pwp > 1, -2, 0); // modulo on [-1, +1]
sawOffsetBuff[i] = (pwp * pwp * pwp - pwp) / 6.0; // eq 11
}
return (sawOffsetBuff[0] - 2.0 * sawOffsetBuff[1] + sawOffsetBuff[2]);
}

template<typename T>
class HardClipperADAA {
public:

T process(T x) {
T y = simd::ifelse(simd::abs(x - xPrev) < 1e-5,
f(0.5 * (xPrev + x)),
(F(x) - F(xPrev)) / (x - xPrev));

xPrev = x;
return y;
}


static T f(T x) {
return simd::ifelse(simd::abs(x) < 1, x, simd::sgn(x));
}

static T F(T x) {
return simd::ifelse(simd::abs(x) < 1, 0.5 * x * x, x * simd::sgn(x) - 0.5);
}

void reset() {
xPrev = 0.f;
}

private:
T xPrev = 0.f;
};

struct Octaves : Module {
enum ParamId {
Expand Down Expand Up @@ -77,7 +106,9 @@ struct Octaves : Module {

bool limitPW = true;
bool removePulseDC = false;
bool adaa = false;
int oversamplingIndex = 0;
static const int NUM_OUTPUTS = 6;

Octaves() {
config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
Expand Down Expand Up @@ -122,6 +153,8 @@ struct Octaves : Module {
float phases[3];
bool forceNaive = false;

HardClipperADAA<float> hardClipper[NUM_OUTPUTS];

void process(const ProcessArgs& args) override {

float pitch = params[TUNE_PARAM].getValue() + inputs[VOCT1_INPUT].getVoltage() + inputs[VOCT2_INPUT].getVoltage();
Expand All @@ -130,7 +163,7 @@ struct Octaves : Module {
// -1 to +1
float pwmCV = params[PWM_CV_PARAM].getValue() * clamp(inputs[PWM_INPUT].getVoltage() / 10.f, -1.f, 1.f);
const float pulseWidthLimit = limitPW ? 0.05f : 0.0f;

// pwm in [-0.25 : +0.25]
float pwm = clamp(0.5 - params[PWM_PARAM].getValue() + 0.5 * pwmCV, -0.5f + pulseWidthLimit, 0.5f - pulseWidthLimit);
pwm /= 2.0;
Expand All @@ -142,11 +175,11 @@ struct Octaves : Module {

float sum = 0.f;
float sumNaive = 0.f;
for (int c = 0; c < 6; c++) {
for (int c = 0; c < NUM_OUTPUTS; c++) {
// derive phases for higher octaves from base phase (this keeps things in sync!)
const float n = (float)(1 << c);
// this is on [0, 1]
const float effectivePhaseRaw = n * std::fmod(phase, 1 / n);
const float effectivePhaseRaw = n * std::fmod(phase, 1 / n);
// this is on [0, 1], and offset in time by 0.25
const float effectivePhase = std::fmod(effectivePhaseRaw + 0.25, 1);

Expand Down Expand Up @@ -194,22 +227,24 @@ struct Octaves : Module {


sum += outForOctave;
sum = clamp(sum, -1.f, 1.f);
if (adaa) {
sum = hardClipper[c].process(sum);
}
else {
sum = clamp(sum, -1.f, 1.f);
}

if (outputs[OUT_01F_OUTPUT + c].isConnected()) {
outputs[OUT_01F_OUTPUT + c].setVoltage(5 * sum);
sum = 0.f;
}

if (c == 0) {
outputs[OUT_OUTPUT].setVoltage(effectivePhase);

float saw = aliasSuppressedSaw(phases, 2*pwm);
float sawOffset = aliasSuppressedOffsetSaw(phases, 2*pwm);
float denominatorInv = 0.25 / (effectiveDeltaPhase * effectiveDeltaPhase);
float dpwOrder3_ = gain * (-saw) * denominatorInv;
if (false) {
float x = 3 * std::sin(2 * M_PI * effectivePhase);
outputs[OUT_OUTPUT].setVoltage(clamp(x, -1.f, 1.f));

outputs[OUT2_OUTPUT].setVoltage(dpwOrder3_);
//float y = hardClipper.process(x);
//outputs[OUT2_OUTPUT].setVoltage(y);
}


Expand All @@ -226,6 +261,7 @@ struct Octaves : Module {
json_object_set_new(rootJ, "removePulseDC", json_boolean(removePulseDC));
json_object_set_new(rootJ, "limitPW", json_boolean(limitPW));
json_object_set_new(rootJ, "forceNaive", json_boolean(forceNaive));
json_object_set_new(rootJ, "adaa", json_boolean(adaa));
// TODO:
// json_object_set_new(rootJ, "oversamplingIndex", json_integer(oversampler[0].getOversamplingIndex()));
return rootJ;
Expand Down Expand Up @@ -253,6 +289,11 @@ struct Octaves : Module {
oversamplingIndex = json_integer_value(oversamplingIndexJ);
onSampleRateChange();
}

json_t* adaaJ = json_object_get(rootJ, "adaa");
if (adaaJ) {
adaa = json_boolean_value(adaaJ);
}
}
};

Expand Down Expand Up @@ -336,6 +377,8 @@ struct OctavesWidget : ModuleWidget {

menu->addChild(createBoolPtrMenuItem("Force naive waveforms", "", &module->forceNaive));

menu->addChild(createBoolPtrMenuItem("ADAADAA", "", &module->adaa));


}
};
Expand Down

0 comments on commit 9d3a09d

Please sign in to comment.