/*
filter plugins by bhob rainey.  http://www.bhobrainey.net
MoogLadder is based on work by Victor Lazzarini and Antti Huovilainen.
RLPFD is based on a csound macro by Josep M Comajuncos
Streson is a near copy of code by Victor Lazzarini
NLFilt is an implementation of a formula by Dobson and Fitch

SuperCollider real time aud synthesis system
    Copyright (c) 2002 James McCartney. All rights reserved.
    http://www.audsynth.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

#include "SC_PlugIn.h"

static InterfaceTable* ft;

struct MoogLadder : public Unit {
    float m_fco, m_k2v;
    float m_res;
    float m_xnm1, m_y1nm1, m_y2nm1, m_y3nm1, m_y4nm1;
    float m_y1n, m_y2n, m_y3n, m_y4n, m_y1n1;
};

struct RLPFD : public Unit {
    float m_fco, m_res, m_ap, m_scl;
    float m_x1, m_y1, m_y2, m_y3;
    float m_x1nm1, m_y1nm1, m_y2nm1;
};

struct MultiFilt : public Unit {
    float m_hp, m_lp, m_bp, m_halfsamp;
    float m_cf, m_f, m_rq;
};

struct FilterDelayUnit : public Unit {
    float* m_dlybuf;

    float m_dsamp, m_fdelaylen;
    float m_delaytime, m_maxdelaytime;
    long m_iwrphase, m_idelaylen, m_mask;
    long m_numoutput;
};

struct Streson : public FilterDelayUnit {
    float m_lp, m_ap, m_a;
};

struct NLFiltN : public FilterDelayUnit {
    float m_a, m_b, m_d, m_c, m_l;
};

struct NLFiltL : public FilterDelayUnit {
    float m_a, m_b, m_d, m_c, m_l;
};

struct NLFiltC : public FilterDelayUnit {
    float m_a, m_b, m_d, m_c, m_l;
};

struct NestedAllpassN : public Unit {
    float m_dt1, m_dt2;
    float *m_buf1, *m_buf2;
    long m_phase, m_maxdel1, m_maxdel2, m_maxdel, m_numoutput, m_dsamp1, m_dsamp2;
};

struct NestedAllpassL : public Unit {
    float m_dt1, m_dt2, m_dsamp1, m_dsamp2;
    float *m_buf1, *m_buf2;
    long m_phase, m_maxdel1, m_maxdel2, m_maxdel, m_numoutput;
};

struct NestedAllpassC : public Unit {
    float m_dt1, m_dt2, m_dsamp1, m_dsamp2;
    float *m_buf1, *m_buf2;
    long m_phase, m_maxdel1, m_maxdel2, m_maxdel, m_numoutput;
};

struct DoubleNestedAllpassN : public Unit {
    float m_dt1, m_dt2, m_dt3;
    float *m_buf1, *m_buf2, *m_buf3;
    long m_phase, m_maxdel1, m_maxdel2, m_maxdel3, m_dsamp1, m_dsamp2, m_dsamp3, m_maxdel, m_numoutput;
};

struct DoubleNestedAllpassL : public Unit {
    float m_dt1, m_dt2, m_dt3, m_dsamp1, m_dsamp2, m_dsamp3;
    float *m_buf1, *m_buf2, *m_buf3;
    long m_phase, m_maxdel1, m_maxdel2, m_maxdel3, m_maxdel, m_numoutput;
};

struct DoubleNestedAllpassC : public Unit {
    float m_dt1, m_dt2, m_dt3, m_dsamp1, m_dsamp2, m_dsamp3;
    float *m_buf1, *m_buf2, *m_buf3;
    long m_phase, m_maxdel1, m_maxdel2, m_maxdel3, m_maxdel, m_numoutput;
};

// declare unit generator functions
extern "C" {
void MoogLadder_Ctor(MoogLadder* unit);
void MoogLadder_next_kk(MoogLadder* unit, int inNumSamples);
void MoogLadder_next_ka(MoogLadder* unit, int inNumSamples);
void MoogLadder_next_ak(MoogLadder* unit, int inNumSamples);
void MoogLadder_next_aa(MoogLadder* unit, int inNumSamples);

void RLPFD_Ctor(RLPFD* unit);
void RLPFD_next_kk(RLPFD* unit, int inNumSamples);
void RLPFD_next_ka(RLPFD* unit, int inNumSamples);
void RLPFD_next_ak(RLPFD* unit, int inNumSamples);
void RLPFD_next_aa(RLPFD* unit, int inNumSamples);

void MultiFilt_Ctor(MultiFilt* unit);
void MultiFilt_next_kk(MultiFilt* unit, int inNumSamples);
void MultiFilt_next_ak(MultiFilt* unit, int inNumSamples);
void MultiFilt_next_ka(MultiFilt* unit, int inNumSamples);
void MultiFilt_next_aa(MultiFilt* unit, int inNumSamples);

void FiltDelay_Reset(FilterDelayUnit* unit);
void FilterDelay_Dtor(FilterDelayUnit* unit);
void FilterDelay_AllocDelayLine(FilterDelayUnit* unit);

void Streson_Ctor(Streson* unit);
void Streson_next_a(Streson* unit, int inNumSamples);
void Streson_next_k(Streson* unit, int inNumSamples);
void Streson_next_a_z(Streson* unit, int inNumSamples);
void Streson_next_k_z(Streson* unit, int inNumSamples);

void NLFiltN_Ctor(NLFiltN* unit);
void NLFiltN_next(NLFiltN* unit, int inNumSamples);
void NLFiltN_next_z(NLFiltN* unit, int inNumSamples);

void NLFiltL_Ctor(NLFiltL* unit);
void NLFiltL_next(NLFiltL* unit, int inNumSamples);
void NLFiltL_next_z(NLFiltL* unit, int inNumSamples);

void NLFiltC_Ctor(NLFiltC* unit);
void NLFiltC_next(NLFiltC* unit, int inNumSamples);
void NLFiltC_next_z(NLFiltC* unit, int inNumSamples);

void NestedAllpassN_Ctor(NestedAllpassN* unit);
void NestedAllpassN_Dtor(NestedAllpassN* unit);
void NestedAllpassN_next(NestedAllpassN* unit, int inNumSamples);
void NestedAllpassN_next_z(NestedAllpassN* unit, int inNumSamples);

void NestedAllpassL_Ctor(NestedAllpassL* unit);
void NestedAllpassL_Dtor(NestedAllpassL* unit);
void NestedAllpassL_next(NestedAllpassL* unit, int inNumSamples);
void NestedAllpassL_next_z(NestedAllpassL* unit, int inNumSamples);

void NestedAllpassC_Ctor(NestedAllpassC* unit);
void NestedAllpassC_Dtor(NestedAllpassC* unit);
void NestedAllpassC_next(NestedAllpassC* unit, int inNumSamples);
void NestedAllpassC_next_z(NestedAllpassC* unit, int inNumSamples);

void DoubleNestedAllpassN_Ctor(DoubleNestedAllpassN* unit);
void DoubleNestedAllpassN_Dtor(DoubleNestedAllpassN* unit);
void DoubleNestedAllpassN_next(DoubleNestedAllpassN* unit, int inNumSamples);
void DoubleNestedAllpassN_next_z(DoubleNestedAllpassN* unit, int inNumSamples);

void DoubleNestedAllpassL_Ctor(DoubleNestedAllpassL* unit);
void DoubleNestedAllpassL_Dtor(DoubleNestedAllpassL* unit);
void DoubleNestedAllpassL_next(DoubleNestedAllpassL* unit, int inNumSamples);
void DoubleNestedAllpassL_next_z(DoubleNestedAllpassL* unit, int inNumSamples);

void DoubleNestedAllpassC_Ctor(DoubleNestedAllpassC* unit);
void DoubleNestedAllpassC_Dtor(DoubleNestedAllpassC* unit);
void DoubleNestedAllpassC_next(DoubleNestedAllpassC* unit, int inNumSamples);
void DoubleNestedAllpassC_next_z(DoubleNestedAllpassC* unit, int inNumSamples);
};

#define SET2BUF                                                                                                        \
    long bufsize1 = (long)ceil(ZIN0(1) * unit->mRate->mSampleRate + 1.f);                                              \
    long bufsize2 = (long)ceil(ZIN0(4) * unit->mRate->mSampleRate + 1.f);                                              \
    long maxdelay1 = bufsize1 + BUFLENGTH;                                                                             \
    maxdelay1 = NEXTPOWEROFTWO(maxdelay1);                                                                             \
    long maxdelay2 = bufsize2 + BUFLENGTH;                                                                             \
    maxdelay2 = NEXTPOWEROFTWO(maxdelay2);                                                                             \
    unit->m_buf1 = 0;                                                                                                  \
    unit->m_buf2 = 0;                                                                                                  \
    RTFree(unit->mWorld, unit->m_buf1);                                                                                \
    unit->m_buf1 = (float*)RTAlloc(unit->mWorld, maxdelay1 * sizeof(float));                                           \
    RTFree(unit->mWorld, unit->m_buf2);                                                                                \
    unit->m_buf2 = (float*)RTAlloc(unit->mWorld, maxdelay2 * sizeof(float));                                           \
    unit->m_maxdel1 = maxdelay1 - 1;                                                                                   \
    unit->m_maxdel2 = maxdelay2 - 1;                                                                                   \
    unit->m_maxdel = sc_max(unit->m_maxdel1, unit->m_maxdel2);                                                         \
    unit->m_numoutput = 0;                                                                                             \
    unit->m_dt1 = ZIN0(2);                                                                                             \
    unit->m_dt2 = ZIN0(5);

#define SET3BUF                                                                                                        \
    long bufsize1 = (long)ceil(ZIN0(1) * unit->mRate->mSampleRate + 1.f);                                              \
    long bufsize2 = (long)ceil(ZIN0(4) * unit->mRate->mSampleRate + 1.f);                                              \
    long bufsize3 = (long)ceil(ZIN0(7) * unit->mRate->mSampleRate + 1.f);                                              \
    long maxdelay1 = bufsize1 + BUFLENGTH;                                                                             \
    maxdelay1 = NEXTPOWEROFTWO(maxdelay1);                                                                             \
    long maxdelay2 = bufsize2 + BUFLENGTH;                                                                             \
    maxdelay2 = NEXTPOWEROFTWO(maxdelay2);                                                                             \
    long maxdelay3 = bufsize3 + BUFLENGTH;                                                                             \
    maxdelay3 = NEXTPOWEROFTWO(maxdelay3);                                                                             \
    unit->m_buf1 = 0;                                                                                                  \
    unit->m_buf2 = 0;                                                                                                  \
    unit->m_buf3 = 0;                                                                                                  \
    RTFree(unit->mWorld, unit->m_buf1);                                                                                \
    unit->m_buf1 = (float*)RTAlloc(unit->mWorld, maxdelay1 * sizeof(float));                                           \
    RTFree(unit->mWorld, unit->m_buf2);                                                                                \
    unit->m_buf2 = (float*)RTAlloc(unit->mWorld, maxdelay2 * sizeof(float));                                           \
    RTFree(unit->mWorld, unit->m_buf3);                                                                                \
    unit->m_buf3 = (float*)RTAlloc(unit->mWorld, maxdelay3 * sizeof(float));                                           \
    unit->m_maxdel1 = maxdelay1 - 1;                                                                                   \
    unit->m_maxdel2 = maxdelay2 - 1;                                                                                   \
    unit->m_maxdel3 = maxdelay3 - 1;                                                                                   \
    unit->m_maxdel = sc_max(unit->m_maxdel1, unit->m_maxdel2);                                                         \
    unit->m_maxdel = sc_max(unit->m_maxdel, unit->m_maxdel3);                                                          \
    unit->m_numoutput = 0;                                                                                             \
    unit->m_dt1 = ZIN0(2);                                                                                             \
    unit->m_dt2 = ZIN0(5);                                                                                             \
    unit->m_dt3 = ZIN0(8);                                                                                             \
/*                                                                                                                     \
static float cubicinterp(float x, float y0, float y1, float y2, float y3)                                              \
{                                                                                                                      \
    float c0 = y1;                                                                                                     \
    float c1 = 0.5f * (y2 - y0);                                                                                       \
    float c2 = y0 - 2.5f * y1 + 2.f * y2 - 0.5f * y3;                                                                  \
    float c3 = 0.5f * (y3 - y0) + 1.5f * (y1 - y2);                                                                    \
                                                                                                                       \
    return ((c3 * x + c2) * x + c1) * x + c0;                                                                          \
}                                                                                                                      \
*/
float CalcDelay(FilterDelayUnit* unit, float delaytime);
float CalcDelay(FilterDelayUnit* unit, float delaytime) {
    float next_dsamp = delaytime * SAMPLERATE;
    return sc_clip(next_dsamp, 1.f, unit->m_fdelaylen);
}

void FilterDelay_AllocDelayLine(FilterDelayUnit* unit) {
    long delaybufsize = (long)ceil(unit->m_maxdelaytime * SAMPLERATE + 1.f);
    delaybufsize = delaybufsize + BUFLENGTH;
    delaybufsize = NEXTPOWEROFTWO(delaybufsize);
    unit->m_fdelaylen = unit->m_idelaylen = delaybufsize;

    RTFree(unit->mWorld, unit->m_dlybuf);
    int size = delaybufsize * sizeof(float);
    unit->m_dlybuf = (float*)RTAlloc(unit->mWorld, size);
    unit->m_mask = delaybufsize - 1;
}

void FilterDelay_Reset(FilterDelayUnit* unit) {
    unit->m_dlybuf = 0;

    FilterDelay_AllocDelayLine(unit);

    unit->m_dsamp = CalcDelay(unit, unit->m_delaytime);

    unit->m_numoutput = 0;
    unit->m_iwrphase = 0;
}


void FilterDelay_Dtor(FilterDelayUnit* unit) { RTFree(unit->mWorld, unit->m_dlybuf); }

float Mirroring(float lower, float upper, float in);
float Mirroring(float lower, float upper, float in) {
    if (in > upper || in < lower) {
        float infrac = fabs(in - (long)in);
        if (in < lower)
            in = lower + infrac;
        else
            in = upper - infrac;
    }
    return in;
}

void NLFiltN_Ctor(NLFiltN* unit) {
    unit->m_maxdelaytime = 0.05;
    FilterDelay_Reset(unit);
    SETCALC(NLFiltN_next_z);
    unit->m_a = ZIN0(1);
    unit->m_b = ZIN0(2);
    unit->m_d = ZIN0(3);
    unit->m_c = ZIN0(4);
    unit->m_l = ZIN0(5);
    ZOUT0(0) = 0.f;
}

void NLFiltN_next(NLFiltN* unit, int inNumSamples) {
    float* out = ZOUT(0);
    float* in = ZIN(0);
    float next_a = ZIN0(1);
    float next_b = ZIN0(2);
    float next_d = ZIN0(3);
    float next_c = ZIN0(4);
    float next_l = ZIN0(5);
    float a = unit->m_a;
    float b = unit->m_b;
    float d = unit->m_d;
    float c = unit->m_c;
    float l = unit->m_l;
    float* dlybuf = unit->m_dlybuf;
    long iwrphase = unit->m_iwrphase;
    long mask = unit->m_mask;

    if (next_a != a || next_b != b || next_d != d || next_c != c || next_l != l) {
        float lslope = CALCSLOPE(next_l, l);
        float aslope = CALCSLOPE(next_a, a);
        float bslope = CALCSLOPE(next_b, b);
        float dslope = CALCSLOPE(next_d, d);
        float cslope = CALCSLOPE(next_c, c);
        LOOP(inNumSamples, a += aslope; b += bslope; d += dslope; c += cslope; l += lslope;
             float delay1 = dlybuf[(iwrphase - 1) & mask]; float delay2 = dlybuf[(iwrphase - 2) & mask];
             float delayL = dlybuf[(iwrphase - (long)l) & mask];

             float output = ZXP(in) + a * delay1 + b * delay2 + d * delayL * delayL - c;
             output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
             ZXP(out) = dlybuf[iwrphase & mask] = output; iwrphase++;);
    } else {
        LOOP(inNumSamples, float delay1 = dlybuf[(iwrphase - 1) & mask]; float delay2 = dlybuf[(iwrphase - 2) & mask];
             float delayL = dlybuf[(iwrphase - (long)l) & mask];

             float output = ZXP(in) + a * delay1 + b * delay2 + d * delayL * delayL - c;
             output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
             ZXP(out) = dlybuf[iwrphase & mask] = output; iwrphase++;);
    }

    unit->m_iwrphase = iwrphase;
    unit->m_a = a;
    unit->m_b = b;
    unit->m_d = d;
    unit->m_c = c;
    unit->m_l = l;
}

void NLFiltN_next_z(NLFiltN* unit, int inNumSamples) {
    float* out = ZOUT(0);
    float* in = ZIN(0);
    float next_a = ZIN0(1);
    float next_b = ZIN0(2);
    float next_d = ZIN0(3);
    float next_c = ZIN0(4);
    float next_l = ZIN0(5);
    float a = unit->m_a;
    float b = unit->m_b;
    float d = unit->m_d;
    float c = unit->m_c;
    float l = unit->m_l;
    float* dlybuf = unit->m_dlybuf;
    long iwrphase = unit->m_iwrphase;
    long mask = unit->m_mask;

    if (next_a != a || next_b != b || next_d != d || next_c != c || next_l != l) {
        float lslope = CALCSLOPE(next_l, l);
        float aslope = CALCSLOPE(next_a, a);
        float bslope = CALCSLOPE(next_b, b);
        float dslope = CALCSLOPE(next_d, d);
        float cslope = CALCSLOPE(next_c, c);
        LOOP(
            inNumSamples, a += aslope; b += bslope; d += dslope; c += cslope; l += lslope;
            long irphase = iwrphase - (long)l; float delay1 = dlybuf[(iwrphase - 1) & mask];
            float delay2 = dlybuf[(iwrphase - 2) & mask]; float delayL = dlybuf[irphase & mask];

            float input = ZXP(in); float output = input + a * delay1 + b * delay2 + d * delayL * delayL - c;
            output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
            if (irphase < 0) {
                dlybuf[iwrphase & mask] = input;
                ZXP(out) = 0.f;
            } else { ZXP(out) = dlybuf[iwrphase & mask] = output; } iwrphase++;);
    } else {
        LOOP(
            inNumSamples, long irphase = iwrphase - (long)l; float delay1 = dlybuf[(iwrphase - 1) & mask];
            float delay2 = dlybuf[(iwrphase - 2) & mask]; float delayL = dlybuf[irphase & mask];

            float input = ZXP(in); float output = input + a * delay1 + b * delay2 + d * delayL * delayL - c;
            output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
            if (irphase < 0) {
                dlybuf[iwrphase & mask] = input;
                ZXP(out) = 0.f;
            } else { ZXP(out) = dlybuf[iwrphase & mask] = output; } iwrphase++;);
    }

    unit->m_iwrphase = iwrphase;
    unit->m_a = a;
    unit->m_b = b;
    unit->m_d = d;
    unit->m_c = c;
    unit->m_l = l;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput >= unit->m_idelaylen) {
        SETCALC(NLFiltN_next);
    }
}


void NLFiltL_Ctor(NLFiltL* unit) {
    unit->m_maxdelaytime = 0.05;
    FilterDelay_Reset(unit);
    SETCALC(NLFiltL_next_z);
    unit->m_a = ZIN0(1);
    unit->m_b = ZIN0(2);
    unit->m_d = ZIN0(3);
    unit->m_c = ZIN0(4);
    unit->m_l = ZIN0(5);
    ZOUT0(0) = 0.f;
}

void NLFiltL_next(NLFiltL* unit, int inNumSamples) {
    float* out = ZOUT(0);
    float* in = ZIN(0);
    float next_a = ZIN0(1);
    float next_b = ZIN0(2);
    float next_d = ZIN0(3);
    float next_c = ZIN0(4);
    float next_l = ZIN0(5);
    float a = unit->m_a;
    float b = unit->m_b;
    float d = unit->m_d;
    float c = unit->m_c;
    float l = unit->m_l;
    float* dlybuf = unit->m_dlybuf;
    long iwrphase = unit->m_iwrphase;
    long mask = unit->m_mask;

    if (next_a != a || next_b != b || next_d != d || next_c != c || next_l != l) {
        float lslope = CALCSLOPE(next_l, l);
        float aslope = CALCSLOPE(next_a, a);
        float bslope = CALCSLOPE(next_b, b);
        float dslope = CALCSLOPE(next_d, d);
        float cslope = CALCSLOPE(next_c, c);
        LOOP(inNumSamples, l += lslope; a += aslope; b += bslope; d += dslope; c += cslope;
             float delay1 = dlybuf[(iwrphase - 1) & mask]; float delay2 = dlybuf[(iwrphase - 2) & mask];
             long l1 = (long)l; float frac = l - l1; float delayL1 = dlybuf[(iwrphase - l1) & mask];
             float delayL2 = dlybuf[(iwrphase - l1 - 1) & mask]; float delayL = lininterp(frac, delayL1, delayL2);

             float output = ZXP(in) + a * delay1 + b * delay2 + d * delayL * delayL - c;
             output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
             ZXP(out) = dlybuf[iwrphase & mask] = output; iwrphase++;)
    } else {
        LOOP(inNumSamples, float delay1 = dlybuf[(iwrphase - 1) & mask]; float delay2 = dlybuf[(iwrphase - 2) & mask];
             float delayL = dlybuf[(iwrphase - (long)l) & mask];

             float output = ZXP(in) + a * delay1 + b * delay2 + d * delayL * delayL - c;
             output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
             ZXP(out) = dlybuf[iwrphase & mask] = output; iwrphase++;)
    }

    unit->m_iwrphase = iwrphase;
    unit->m_a = a;
    unit->m_b = b;
    unit->m_d = d;
    unit->m_c = c;
    unit->m_l = l;
}

void NLFiltL_next_z(NLFiltL* unit, int inNumSamples) {
    float* out = ZOUT(0);
    float* in = ZIN(0);
    float next_a = ZIN0(1);
    float next_b = ZIN0(2);
    float next_d = ZIN0(3);
    float next_c = ZIN0(4);
    float next_l = ZIN0(5);
    float a = unit->m_a;
    float b = unit->m_b;
    float d = unit->m_d;
    float c = unit->m_c;
    float l = unit->m_l;
    float* dlybuf = unit->m_dlybuf;
    long iwrphase = unit->m_iwrphase;
    long mask = unit->m_mask;

    if (next_a != a || next_b != b || next_d != d || next_c != c || next_l != l) {
        float lslope = CALCSLOPE(next_l, l);
        float aslope = CALCSLOPE(next_a, a);
        float bslope = CALCSLOPE(next_b, b);
        float dslope = CALCSLOPE(next_d, d);
        float cslope = CALCSLOPE(next_c, c);
        LOOP(
            inNumSamples, l += lslope; a += aslope; b += bslope; d += dslope; c += cslope;
            float delay1 = dlybuf[(iwrphase - 1) & mask]; float delay2 = dlybuf[(iwrphase - 2) & mask];
            long l1 = (long)l; float frac = l - l1; long irphase = iwrphase - l1;
            float delayL1 = dlybuf[irphase & mask]; float delayL2 = dlybuf[(irphase - 1) & mask];
            float delayL = lininterp(frac, delayL1, delayL2); float input = ZXP(in);
            float output = input + a * delay1 + b * delay2 + d * delayL * delayL - c;
            output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
            if ((irphase - 1) < 0) {
                dlybuf[iwrphase & mask] = input;
                ZXP(out) = 0.f;
            } else { ZXP(out) = dlybuf[iwrphase & mask] = output; } iwrphase++;)
    } else {
        LOOP(
            inNumSamples, float delay1 = dlybuf[(iwrphase - 1) & mask]; float delay2 = dlybuf[(iwrphase - 2) & mask];
            long l1 = (long)l; float frac = l - l1; long irphase = iwrphase - l1;
            float delayL1 = dlybuf[irphase & mask]; float delayL2 = dlybuf[(irphase - 1) & mask];
            float delayL = lininterp(frac, delayL1, delayL2); float input = ZXP(in);
            float output = input + a * delay1 + b * delay2 + d * delayL * delayL - c;
            output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
            if ((irphase - 1) < 0) {
                dlybuf[iwrphase & mask] = input;
                ZXP(out) = 0.f;
            } else { ZXP(out) = dlybuf[iwrphase & mask] = output; } iwrphase++;)
    }

    unit->m_iwrphase = iwrphase;
    unit->m_a = a;
    unit->m_b = b;
    unit->m_d = d;
    unit->m_c = c;
    unit->m_l = l;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput >= unit->m_idelaylen) {
        SETCALC(NLFiltL_next);
    }
}

void NLFiltC_Ctor(NLFiltC* unit) {
    unit->m_maxdelaytime = 0.05;
    FilterDelay_Reset(unit);
    SETCALC(NLFiltC_next_z);
    unit->m_a = ZIN0(1);
    unit->m_b = ZIN0(2);
    unit->m_d = ZIN0(3);
    unit->m_c = ZIN0(4);
    unit->m_l = ZIN0(5);
    ZOUT0(0) = 0.f;
}

void NLFiltC_next(NLFiltC* unit, int inNumSamples) {
    float* out = ZOUT(0);
    float* in = ZIN(0);
    float next_a = ZIN0(1);
    float next_b = ZIN0(2);
    float next_d = ZIN0(3);
    float next_c = ZIN0(4);
    float next_l = ZIN0(5);
    float a = unit->m_a;
    float b = unit->m_b;
    float d = unit->m_d;
    float c = unit->m_c;
    float l = unit->m_l;
    float* dlybuf = unit->m_dlybuf;
    long iwrphase = unit->m_iwrphase;
    long mask = unit->m_mask;

    if (next_a != a || next_b != b || next_d != d || next_c != c || next_l != l) {
        float lslope = CALCSLOPE(next_l, l);
        float aslope = CALCSLOPE(next_a, a);
        float bslope = CALCSLOPE(next_b, b);
        float dslope = CALCSLOPE(next_d, d);
        float cslope = CALCSLOPE(next_c, c);
        LOOP(inNumSamples, l += lslope; a += aslope; b += bslope; d += dslope; c += cslope;
             float delay1 = dlybuf[(iwrphase - 1) & mask]; float delay2 = dlybuf[(iwrphase - 2) & mask];
             long l1 = (long)l; float frac = l - l1; long irdphase1 = iwrphase - l1; long irdphase2 = irdphase1 - 1;
             long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; float d0 = dlybuf[irdphase0 & mask];
             float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask];
             float d3 = dlybuf[irdphase3 & mask]; float delayL = cubicinterp(frac, d0, d1, d2, d3);

             float output = ZXP(in) + a * delay1 + b * delay2 + d * delayL * delayL - c;
             output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
             ZXP(out) = dlybuf[iwrphase & mask] = output; iwrphase++;)
    } else {
        LOOP(inNumSamples, float delay1 = dlybuf[(iwrphase - 1) & mask]; float delay2 = dlybuf[(iwrphase - 2) & mask];
             long l1 = (long)l; float frac = l - l1; long irdphase1 = iwrphase - l1; long irdphase2 = irdphase1 - 1;
             long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; float d0 = dlybuf[irdphase0 & mask];
             float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask];
             float d3 = dlybuf[irdphase3 & mask]; float delayL = cubicinterp(frac, d0, d1, d2, d3);

             float output = ZXP(in) + a * delay1 + b * delay2 + d * delayL * delayL - c;
             output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
             ZXP(out) = dlybuf[iwrphase & mask] = output; iwrphase++;)
    }

    unit->m_iwrphase = iwrphase;
    unit->m_a = a;
    unit->m_b = b;
    unit->m_d = d;
    unit->m_c = c;
    unit->m_l = l;
}

void NLFiltC_next_z(NLFiltC* unit, int inNumSamples) {
    float* out = ZOUT(0);
    float* in = ZIN(0);
    float next_a = ZIN0(1);
    float next_b = ZIN0(2);
    float next_d = ZIN0(3);
    float next_c = ZIN0(4);
    float next_l = ZIN0(5);
    float a = unit->m_a;
    float b = unit->m_b;
    float d = unit->m_d;
    float c = unit->m_c;
    float l = unit->m_l;
    float* dlybuf = unit->m_dlybuf;
    long iwrphase = unit->m_iwrphase;
    long mask = unit->m_mask;

    if (next_a != a || next_b != b || next_d != d || next_c != c || next_l != l) {
        float lslope = CALCSLOPE(next_l, l);
        float aslope = CALCSLOPE(next_a, a);
        float bslope = CALCSLOPE(next_b, b);
        float dslope = CALCSLOPE(next_d, d);
        float cslope = CALCSLOPE(next_c, c);
        LOOP(
            inNumSamples, l += lslope; a += aslope; b += bslope; d += dslope; c += cslope;
            float delay1 = dlybuf[(iwrphase - 1) & mask]; float delay2 = dlybuf[(iwrphase - 2) & mask];
            long l1 = (long)l; float frac = l - l1; long irdphase1 = iwrphase - l1; long irdphase2 = irdphase1 - 1;
            long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; float d0 = dlybuf[irdphase0 & mask];
            float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask];
            float d3 = dlybuf[irdphase3 & mask]; float delayL = cubicinterp(frac, d0, d1, d2, d3);
            float input = ZXP(in); float output = input + a * delay1 + b * delay2 + d * delayL * delayL - c;
            output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
            if (irdphase3 < 0) {
                dlybuf[iwrphase & mask] = input;
                ZXP(out) = 0.f;
            } else { ZXP(out) = dlybuf[iwrphase & mask] = output; } iwrphase++;)
    } else {
        LOOP(
            inNumSamples, float delay1 = dlybuf[(iwrphase - 1) & mask]; float delay2 = dlybuf[(iwrphase - 2) & mask];
            long l1 = (long)l; float frac = l - l1; long irdphase1 = iwrphase - l1; long irdphase2 = irdphase1 - 1;
            long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; float d0 = dlybuf[irdphase0 & mask];
            float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask];
            float d3 = dlybuf[irdphase3 & mask]; float delayL = cubicinterp(frac, d0, d1, d2, d3);
            float input = ZXP(in); float output = input + a * delay1 + b * delay2 + d * delayL * delayL - c;
            output = output - (output * output * output * 0.166666667); output = Mirroring(-1.0, 1.0, output);
            if (irdphase3 < 0) {
                dlybuf[iwrphase & mask] = input;
                ZXP(out) = 0.f;
            } else { ZXP(out) = dlybuf[iwrphase & mask] = output; } iwrphase++;)
    }

    unit->m_iwrphase = iwrphase;
    unit->m_a = a;
    unit->m_b = b;
    unit->m_d = d;
    unit->m_c = c;
    unit->m_l = l;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput > unit->m_idelaylen) {
        SETCALC(NLFiltC_next);
    }
}

void Streson_Ctor(Streson* unit) {
    unit->m_maxdelaytime = 0.05;
    FilterDelay_Reset(unit);
    float delaytime = ZIN0(1);
    float tdelay = delaytime * SAMPLERATE;
    unit->m_dsamp = (long)(tdelay - 0.5);
    float fracdelay = tdelay - (unit->m_dsamp + 0.5);
    unit->m_a = (1 - fracdelay) / (1 + fracdelay);
    unit->m_lp = unit->m_ap = 0.f;
    unit->m_delaytime = delaytime;
    if (INRATE(1) == calc_FullRate)
        SETCALC(Streson_next_a_z);
    else
        SETCALC(Streson_next_k_z);
    ZOUT0(0) = 0.f;
}

void Streson_next_k(Streson* unit, int inNumSamples) {
    float* out = ZOUT(0);
    float* in = ZIN(0);
    float delaytime = unit->m_delaytime;
    float next_delaytime = ZIN0(1);
    float dsamp = unit->m_dsamp;
    float a = unit->m_a;
    float* dlybuf = unit->m_dlybuf;
    long iwrphase = unit->m_iwrphase;
    long mask = unit->m_mask;
    float ap = unit->m_ap;
    float lp = unit->m_lp;

    if (next_delaytime != delaytime) {
        float tdelay = next_delaytime * SAMPLERATE;
        float dsamp = (long)(tdelay - 0.5);
        float fracdelay = tdelay - (dsamp + 0.5);
        float a = (1 - fracdelay) / (1 + fracdelay);
        LOOP(inNumSamples, long irdphase = iwrphase - (long)dsamp; float input = ZXP(in) + dlybuf[irdphase & mask];
             float s = lp * 0.5 + input * 0.5; lp = input; float sample = ap + s * a; ZXP(out) = sample;
             ap = s - (sample * a); dlybuf[iwrphase & mask] = sample * ZIN0(2); ++iwrphase;);
    } else {
        LOOP(inNumSamples, long irdphase = iwrphase - (long)dsamp; float input = ZXP(in) + dlybuf[irdphase & mask];
             float s = lp * 0.5 + input * 0.5; lp = input; float sample = ap + s * a; ZXP(out) = sample;
             ap = s - (sample * a); dlybuf[iwrphase & mask] = sample * ZIN0(2); ++iwrphase;);
    }

    unit->m_iwrphase = iwrphase;
    unit->m_ap = zapgremlins(ap);
    unit->m_lp = zapgremlins(lp);
    unit->m_dsamp = dsamp;
    unit->m_a = a;
}

void Streson_next_k_z(Streson* unit, int inNumSamples) {
    float* out = ZOUT(0);
    float* in = ZIN(0);
    float delaytime = unit->m_delaytime;
    float next_delaytime = ZIN0(1);
    float dsamp = unit->m_dsamp;
    float a = unit->m_a;
    float* dlybuf = unit->m_dlybuf;
    long iwrphase = unit->m_iwrphase;
    long mask = unit->m_mask;
    float ap = unit->m_ap;
    float lp = unit->m_lp;

    if (next_delaytime != delaytime) {
        float tdelay = next_delaytime * SAMPLERATE;
        float dsamp = (long)(tdelay - 0.5);
        float fracdelay = tdelay - (dsamp + 0.5);
        float a = (1 - fracdelay) / (1 + fracdelay);
        LOOP(
            inNumSamples, long irdphase = iwrphase - (long)dsamp; float aud = ZXP(in);
            float input = aud + dlybuf[irdphase & mask]; float s = lp * 0.5 + input * 0.5; lp = input;
            float sample = ap + s * a; ap = s - (sample * a); if (irdphase < 0) {
                dlybuf[iwrphase & mask] = aud;
                ZXP(out) = 0.f;
            } else {
                ZXP(out) = sample;
                dlybuf[iwrphase & mask] = sample * ZIN0(2);
            } ++iwrphase;);
    } else {
        LOOP(
            inNumSamples, long irdphase = iwrphase - (long)dsamp; float aud = ZXP(in);
            float input = aud + dlybuf[irdphase & mask]; float s = lp * 0.5 + input * 0.5; lp = input;
            float sample = ap + s * a; ap = s - (sample * a); if (irdphase < 0) {
                dlybuf[iwrphase & mask] = aud;
                ZXP(out) = 0.f;
            } else {
                ZXP(out) = sample;
                dlybuf[iwrphase & mask] = sample * ZIN0(2);
            } ++iwrphase;);
    }

    unit->m_iwrphase = iwrphase;
    unit->m_ap = zapgremlins(ap);
    unit->m_lp = zapgremlins(lp);
    unit->m_dsamp = dsamp;
    unit->m_a = a;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput >= unit->m_idelaylen) {
        SETCALC(Streson_next_k);
    }
}

void Streson_next_a(Streson* unit, int inNumSamples) {
    float* out = ZOUT(0);
    float* in = ZIN(0);
    float* delaytime = ZIN(1);
    float dsamp = unit->m_dsamp;
    float a = unit->m_a;
    float* dlybuf = unit->m_dlybuf;
    long iwrphase = unit->m_iwrphase;
    long mask = unit->m_mask;
    float ap = unit->m_ap;
    float lp = unit->m_lp;

    LOOP(inNumSamples, float tdelay = ZXP(delaytime) * SAMPLERATE; float dsamp = (long)(tdelay - 0.5);
         float fracdelay = tdelay - (dsamp + 0.5); float a = (1 - fracdelay) / (1 + fracdelay);
         long irdphase = iwrphase - (long)dsamp; float input = ZXP(in) + dlybuf[irdphase & mask];
         float s = lp * 0.5 + input * 0.5; lp = input; float sample = ap + s * a; ZXP(out) = sample;
         ap = s - (sample * a); dlybuf[iwrphase & mask] = sample * ZIN0(2); ++iwrphase;);

    unit->m_iwrphase = iwrphase;
    unit->m_ap = zapgremlins(ap);
    unit->m_lp = zapgremlins(lp);
    unit->m_dsamp = dsamp;
    unit->m_a = a;
}

void Streson_next_a_z(Streson* unit, int inNumSamples) {
    float* out = ZOUT(0);
    float* in = ZIN(0);
    float* delaytime = ZIN(1);
    float dsamp = unit->m_dsamp;
    float a = unit->m_a;
    float* dlybuf = unit->m_dlybuf;
    long iwrphase = unit->m_iwrphase;
    long mask = unit->m_mask;
    float ap = unit->m_ap;
    float lp = unit->m_lp;

    LOOP(
        inNumSamples, float tdelay = ZXP(delaytime) * SAMPLERATE; float dsamp = (long)(tdelay - 0.5);
        float fracdelay = tdelay - (dsamp + 0.5); float a = (1 - fracdelay) / (1 + fracdelay);
        long irdphase = iwrphase - (long)dsamp; float aud = ZXP(in); float input = aud + dlybuf[irdphase & mask];
        float s = lp * 0.5 + input * 0.5; lp = input; float sample = ap + s * a; ap = s - (sample * a);
        if (irdphase < 0) {
            dlybuf[iwrphase & mask] = aud;
            ZXP(out) = 0.f;
        } else {
            ZXP(out) = sample;
            dlybuf[iwrphase & mask] = sample * ZIN0(2);
        } ++iwrphase;);

    unit->m_iwrphase = iwrphase;
    unit->m_ap = zapgremlins(ap);
    unit->m_lp = zapgremlins(lp);
    unit->m_dsamp = dsamp;
    unit->m_a = a;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput >= unit->m_idelaylen) {
        SETCALC(Streson_next_a);
    }
}


void MoogLadder_Ctor(MoogLadder* unit) {
    if (INRATE(1) == calc_FullRate) {
        if (INRATE(2) == calc_FullRate) {
            SETCALC(MoogLadder_next_aa);
        } else {
            SETCALC(MoogLadder_next_ak);
        }
    } else {
        if (INRATE(2) == calc_FullRate) {
            SETCALC(MoogLadder_next_ka);
        } else {
            SETCALC(MoogLadder_next_kk);
        }
    }
    unit->m_fco = IN0(1);
    float fc = unit->m_fco * SAMPLEDUR;
    float f = unit->m_fco * SAMPLEDUR * 0.5;
    float fcr = 1.8730 * fc * fc * fc + 0.4955 * fc * fc - 0.6490 * fc + 0.9988;
    unit->m_k2v = 1.25 * (1 - exp(-twopi * fcr * f));
    unit->m_res = IN0(2);
    unit->m_xnm1 = unit->m_y1nm1 = unit->m_y2nm1 = unit->m_y3nm1 = unit->m_y4nm1 = 0.0f;
    unit->m_y1n = unit->m_y2n = unit->m_y3n = unit->m_y4n = unit->m_y1n1 = 0.0f;
    ClearUnitOutputs(unit, 1);
}

void MoogLadder_next_kk(MoogLadder* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float nextfco = IN0(1);
    float nextres = IN0(2);
    float fco = unit->m_fco;
    float res = unit->m_res;

    float xnm1 = unit->m_xnm1;
    float y1nm1 = unit->m_y1nm1;
    float y2nm1 = unit->m_y2nm1;
    float y3nm1 = unit->m_y3nm1;
    float y4nm1 = unit->m_y4nm1;
    float y1n1 = unit->m_y1n1;
    float y2n1, y3n1;
    float k2v = unit->m_k2v;
    float y1n = unit->m_y1n;
    float y2n = unit->m_y2n;
    float y3n = unit->m_y3n;
    float y4n = unit->m_y4n;
    // float i2v = 0.6103515625;
    float i2v = 0.70466;

    float fc, f, fcr, xn;
    float k2vslope = 0;
    float resslope = 0;

    if (nextfco != fco) {
        fc = nextfco * SAMPLEDUR;
        f = nextfco * SAMPLEDUR * 0.5;
        fcr = 1.8730 * ((fc * fc * fc) + 0.4955 * (fc * fc)) - 0.6490 * fc + 0.9988;
        float nextk2v = 1.25 * (1 - exp(-twopi * fcr * f));
        k2vslope = CALCSLOPE(nextk2v, k2v);
    }

    if (nextres != res) {
        resslope = CALCSLOPE(nextres, res);
    };

    for (int i = 0; i < inNumSamples; i++) {
        float input = ZXP(in);
        xn = input - 8 * res * y4n;
        float xn1 = xn * i2v;

        float y2nm11 = y2nm1 * i2v;
        float y3nm11 = y3nm1 * i2v;
        float y4nm11 = y4nm1 * i2v;

        y1n = xnm1 + k2v * (xn1 / (1 + fabs(xn1)) - y1n1 / (1 + fabs(y1n1)));
        y1n1 = y1n * i2v;
        y2n = y2nm1 + k2v * (y1n1 / (1 + fabs(y1n1)) - y2nm11 / (1 + fabs(y2nm11)));
        y2n1 = y2n * i2v;
        y3n = y3nm1 + k2v * (y2n1 / (1 + fabs(y2n1)) - y3nm11 / (1 + fabs(y3nm11)));
        y3n1 = y3n * i2v;
        y4n = y4nm1 + k2v * (y3n1 / (1 + fabs(y3n1)) - y4nm11 / (1 + fabs(y4nm11)));
        y4n = (y4n + y4nm1) * 0.5;

        xnm1 = xn;
        y1nm1 = y1n;
        y2nm1 = y2n;
        y3nm1 = y3n;
        y4nm1 = y4n;

        xn = input - 8 * res * y4n;

        xn1 = xn * i2v;
        y2nm11 = y2nm1 * i2v;
        y3nm11 = y3nm1 * i2v;
        y4nm11 = y4nm1 * i2v;

        y1n = xnm1 + k2v * (xn1 / (1 + fabs(xn1)) - y1n1 / (1 + fabs(y1n1)));
        y1n1 = y1n * i2v;
        y2n = y2nm1 + k2v * (y1n1 / (1 + fabs(y1n1)) - y2nm11 / (1 + fabs(y2nm11)));
        y2n1 = y2n * i2v;
        y3n = y3nm1 + k2v * (y2n1 / (1 + fabs(y2n1)) - y3nm11 / (1 + fabs(y3nm11)));
        y3n1 = y3n * i2v;
        y4n = y4nm1 + k2v * (y3n1 / (1 + fabs(y3n1)) - y4nm11 / (1 + fabs(y4nm11)));
        y4n = (y4n + y4nm1) * 0.5;

        xnm1 = xn;
        y1nm1 = y1n;
        y2nm1 = y2n;
        y3nm1 = y3n;
        y4nm1 = y4n;

        if (k2vslope != 0)
            k2v += k2vslope;
        if (resslope != 0)
            res += resslope;
        ZXP(out) = y4n;
    }

    unit->m_fco = nextfco;
    unit->m_res = res;
    unit->m_k2v = k2v;
    unit->m_xnm1 = zapgremlins(xnm1);
    unit->m_y1nm1 = zapgremlins(y1nm1);
    unit->m_y2nm1 = zapgremlins(y2nm1);
    unit->m_y3nm1 = zapgremlins(y3nm1);
    unit->m_y4nm1 = zapgremlins(y4nm1);
    unit->m_y1n1 = zapgremlins(y1n1);
    unit->m_y1n = zapgremlins(y1n);
    unit->m_y2n = zapgremlins(y2n);
    unit->m_y3n = zapgremlins(y3n);
    unit->m_y4n = zapgremlins(y4n);
}

void MoogLadder_next_ka(MoogLadder* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float nextfco = IN0(1);
    float fco = unit->m_fco;
    float* res = IN(2);

    float xnm1 = unit->m_xnm1;
    float y1nm1 = unit->m_y1nm1;
    float y2nm1 = unit->m_y2nm1;
    float y3nm1 = unit->m_y3nm1;
    float y4nm1 = unit->m_y4nm1;
    float y1n1 = unit->m_y1n1;
    float y2n1, y3n1;
    float k2v = unit->m_k2v;
    float y1n = unit->m_y1n;
    float y2n = unit->m_y2n;
    float y3n = unit->m_y3n;
    float y4n = unit->m_y4n;
    float i2v = 0.70466;

    float fc, f, fcr, xn;
    float k2vslope = 0;

    if (nextfco != fco) {
        fc = nextfco * SAMPLEDUR;
        f = nextfco * SAMPLEDUR * 0.5;
        fcr = 1.8730 * ((fc * fc * fc) + 0.4955 * (fc * fc)) - 0.6490 * fc + 0.9988;
        float nextk2v = 1.25 * (1 - exp(-twopi * fcr * f));
        k2vslope = CALCSLOPE(nextk2v, k2v);
    }

    for (int i = 0; i < inNumSamples; i++) {
        float input = ZXP(in);
        xn = input - 8 * res[i] * y4n;
        float xn1 = xn * i2v;

        float y2nm11 = y2nm1 * i2v;
        float y3nm11 = y3nm1 * i2v;
        float y4nm11 = y4nm1 * i2v;

        y1n = xnm1 + k2v * (xn1 / (1 + fabs(xn1)) - y1n1 / (1 + fabs(y1n1)));
        y1n1 = y1n * i2v;
        y2n = y2nm1 + k2v * (y1n1 / (1 + fabs(y1n1)) - y2nm11 / (1 + fabs(y2nm11)));
        y2n1 = y2n * i2v;
        y3n = y3nm1 + k2v * (y2n1 / (1 + fabs(y2n1)) - y3nm11 / (1 + fabs(y3nm11)));
        y3n1 = y3n * i2v;
        y4n = y4nm1 + k2v * (y3n1 / (1 + fabs(y3n1)) - y4nm11 / (1 + fabs(y4nm11)));
        y4n = (y4n + y4nm1) * 0.5;

        xnm1 = xn;
        y1nm1 = y1n;
        y2nm1 = y2n;
        y3nm1 = y3n;
        y4nm1 = y4n;

        xn = input - 8 * res[i] * y4n;

        xn1 = xn * i2v;
        y2nm11 = y2nm1 * i2v;
        y3nm11 = y3nm1 * i2v;
        y4nm11 = y4nm1 * i2v;

        y1n = xnm1 + k2v * (xn1 / (1 + fabs(xn1)) - y1n1 / (1 + fabs(y1n1)));
        y1n1 = y1n * i2v;
        y2n = y2nm1 + k2v * (y1n1 / (1 + fabs(y1n1)) - y2nm11 / (1 + fabs(y2nm11)));
        y2n1 = y2n * i2v;
        y3n = y3nm1 + k2v * (y2n1 / (1 + fabs(y2n1)) - y3nm11 / (1 + fabs(y3nm11)));
        y3n1 = y3n * i2v;
        y4n = y4nm1 + k2v * (y3n1 / (1 + fabs(y3n1)) - y4nm11 / (1 + fabs(y4nm11)));
        y4n = (y4n + y4nm1) * 0.5;

        xnm1 = xn;
        y1nm1 = y1n;
        y2nm1 = y2n;
        y3nm1 = y3n;
        y4nm1 = y4n;

        if (k2vslope != 0)
            k2v += k2vslope;
        ZXP(out) = y4n;
    }

    unit->m_fco = nextfco;
    unit->m_k2v = k2v;
    unit->m_xnm1 = zapgremlins(xnm1);
    unit->m_y1nm1 = zapgremlins(y1nm1);
    unit->m_y2nm1 = zapgremlins(y2nm1);
    unit->m_y3nm1 = zapgremlins(y3nm1);
    unit->m_y4nm1 = zapgremlins(y4nm1);
    unit->m_y1n1 = zapgremlins(y1n1);
    unit->m_y1n = zapgremlins(y1n);
    unit->m_y2n = zapgremlins(y2n);
    unit->m_y3n = zapgremlins(y3n);
    unit->m_y4n = zapgremlins(y4n);
}

void MoogLadder_next_ak(MoogLadder* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* nextfco = IN(1);
    float nextres = IN0(2);
    float fco = unit->m_fco;
    float res = unit->m_res;

    float xnm1 = unit->m_xnm1;
    float y1nm1 = unit->m_y1nm1;
    float y2nm1 = unit->m_y2nm1;
    float y3nm1 = unit->m_y3nm1;
    float y4nm1 = unit->m_y4nm1;
    float y1n1 = unit->m_y1n1;
    float y2n1, y3n1;
    float k2v = unit->m_k2v;
    float y1n = unit->m_y1n;
    float y2n = unit->m_y2n;
    float y3n = unit->m_y3n;
    float y4n = unit->m_y4n;
    float i2v = 0.70466;

    float fc, f, fcr, xn;
    float resslope = 0;

    if (nextres != res) {
        resslope = CALCSLOPE(nextres, res);
    }

    for (int i = 0; i < inNumSamples; i++) {
        if (nextfco[i] != fco) {
            fc = nextfco[i] * SAMPLEDUR;
            f = nextfco[i] * SAMPLEDUR * 0.5;
            fcr = 1.8730 * ((fc * fc * fc) + 0.4955 * (fc * fc)) - 0.6490 * fc + 0.9988;
            k2v = 1.25 * (1 - exp(-twopi * fcr * f));
            fco = nextfco[i];
        }
        float input = ZXP(in);
        xn = input - 8 * res * y4n;
        float xn1 = xn * i2v;

        float y2nm11 = y2nm1 * i2v;
        float y3nm11 = y3nm1 * i2v;
        float y4nm11 = y4nm1 * i2v;

        y1n = xnm1 + k2v * (xn1 / (1 + fabs(xn1)) - y1n1 / (1 + fabs(y1n1)));
        y1n1 = y1n * i2v;
        y2n = y2nm1 + k2v * (y1n1 / (1 + fabs(y1n1)) - y2nm11 / (1 + fabs(y2nm11)));
        y2n1 = y2n * i2v;
        y3n = y3nm1 + k2v * (y2n1 / (1 + fabs(y2n1)) - y3nm11 / (1 + fabs(y3nm11)));
        y3n1 = y3n * i2v;
        y4n = y4nm1 + k2v * (y3n1 / (1 + fabs(y3n1)) - y4nm11 / (1 + fabs(y4nm11)));
        y4n = (y4n + y4nm1) * 0.5;

        xnm1 = xn;
        y1nm1 = y1n;
        y2nm1 = y2n;
        y3nm1 = y3n;
        y4nm1 = y4n;

        xn = input - 8 * res * y4n;

        xn1 = xn * i2v;
        y2nm11 = y2nm1 * i2v;
        y3nm11 = y3nm1 * i2v;
        y4nm11 = y4nm1 * i2v;

        y1n = xnm1 + k2v * (xn1 / (1 + fabs(xn1)) - y1n1 / (1 + fabs(y1n1)));
        y1n1 = y1n * i2v;
        y2n = y2nm1 + k2v * (y1n1 / (1 + fabs(y1n1)) - y2nm11 / (1 + fabs(y2nm11)));
        y2n1 = y2n * i2v;
        y3n = y3nm1 + k2v * (y2n1 / (1 + fabs(y2n1)) - y3nm11 / (1 + fabs(y3nm11)));
        y3n1 = y3n * i2v;
        y4n = y4nm1 + k2v * (y3n1 / (1 + fabs(y3n1)) - y4nm11 / (1 + fabs(y4nm11)));
        y4n = (y4n + y4nm1) * 0.5;

        xnm1 = xn;
        y1nm1 = y1n;
        y2nm1 = y2n;
        y3nm1 = y3n;
        y4nm1 = y4n;

        if (resslope != 0)
            res += resslope;
        ZXP(out) = y4n;
    }

    unit->m_fco = fco;
    unit->m_res = res;
    unit->m_k2v = k2v;
    unit->m_xnm1 = zapgremlins(xnm1);
    unit->m_y1nm1 = zapgremlins(y1nm1);
    unit->m_y2nm1 = zapgremlins(y2nm1);
    unit->m_y3nm1 = zapgremlins(y3nm1);
    unit->m_y4nm1 = zapgremlins(y4nm1);
    unit->m_y1n1 = zapgremlins(y1n1);
    unit->m_y1n = zapgremlins(y1n);
    unit->m_y2n = zapgremlins(y2n);
    unit->m_y3n = zapgremlins(y3n);
    unit->m_y4n = zapgremlins(y4n);
}

void MoogLadder_next_aa(MoogLadder* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* nextfco = IN(1);
    float fco = unit->m_fco;
    float* res = IN(2);

    float xnm1 = unit->m_xnm1;
    float y1nm1 = unit->m_y1nm1;
    float y2nm1 = unit->m_y2nm1;
    float y3nm1 = unit->m_y3nm1;
    float y4nm1 = unit->m_y4nm1;
    float y1n1 = unit->m_y1n1;
    float y2n1, y3n1;
    float k2v = unit->m_k2v;
    float y1n = unit->m_y1n;
    float y2n = unit->m_y2n;
    float y3n = unit->m_y3n;
    float y4n = unit->m_y4n;
    float i2v = 0.70466;

    float fc, f, fcr, xn;

    for (int i = 0; i < inNumSamples; i++) {
        if (nextfco[i] != fco) {
            fc = nextfco[i] * SAMPLEDUR;
            f = nextfco[i] * SAMPLEDUR * 0.5;
            fcr = 1.8730 * ((fc * fc * fc) + 0.4955 * (fc * fc)) - 0.6490 * fc + 0.9988;
            k2v = 1.220703125 * (1 - exp(-twopi * fcr * f));
            fco = nextfco[i];
        }

        float input = ZXP(in);
        xn = input - 8 * res[i] * y4n;
        float xn1 = xn * i2v;

        float y2nm11 = y2nm1 * i2v;
        float y3nm11 = y3nm1 * i2v;
        float y4nm11 = y4nm1 * i2v;

        y1n = xnm1 + k2v * (xn1 / (1 + fabs(xn1)) - y1n1 / (1 + fabs(y1n1)));
        y1n1 = y1n * i2v;
        y2n = y2nm1 + k2v * (y1n1 / (1 + fabs(y1n1)) - y2nm11 / (1 + fabs(y2nm11)));
        y2n1 = y2n * i2v;
        y3n = y3nm1 + k2v * (y2n1 / (1 + fabs(y2n1)) - y3nm11 / (1 + fabs(y3nm11)));
        y3n1 = y3n * i2v;
        y4n = y4nm1 + k2v * (y3n1 / (1 + fabs(y3n1)) - y4nm11 / (1 + fabs(y4nm11)));
        y4n = (y4n + y4nm1) * 0.5;

        xnm1 = xn;
        y1nm1 = y1n;
        y2nm1 = y2n;
        y3nm1 = y3n;
        y4nm1 = y4n;

        xn = input - 8 * res[i] * y4n;

        xn1 = xn * i2v;
        y2nm11 = y2nm1 * i2v;
        y3nm11 = y3nm1 * i2v;
        y4nm11 = y4nm1 * i2v;

        y1n = xnm1 + k2v * (xn1 / (1 + fabs(xn1)) - y1n1 / (1 + fabs(y1n1)));
        y1n1 = y1n * i2v;
        y2n = y2nm1 + k2v * (y1n1 / (1 + fabs(y1n1)) - y2nm11 / (1 + fabs(y2nm11)));
        y2n1 = y2n * i2v;
        y3n = y3nm1 + k2v * (y2n1 / (1 + fabs(y2n1)) - y3nm11 / (1 + fabs(y3nm11)));
        y3n1 = y3n * i2v;
        y4n = y4nm1 + k2v * (y3n1 / (1 + fabs(y3n1)) - y4nm11 / (1 + fabs(y4nm11)));
        y4n = (y4n + y4nm1) * 0.5;

        xnm1 = xn;
        y1nm1 = y1n;
        y2nm1 = y2n;
        y3nm1 = y3n;
        y4nm1 = y4n;

        ZXP(out) = y4n;
    }

    unit->m_k2v = k2v;
    unit->m_xnm1 = zapgremlins(xnm1);
    unit->m_y1nm1 = zapgremlins(y1nm1);
    unit->m_y2nm1 = zapgremlins(y2nm1);
    unit->m_y3nm1 = zapgremlins(y3nm1);
    unit->m_y4nm1 = zapgremlins(y4nm1);
    unit->m_y1n1 = zapgremlins(y1n1);
    unit->m_y1n = zapgremlins(y1n);
    unit->m_y2n = zapgremlins(y2n);
    unit->m_y3n = zapgremlins(y3n);
    unit->m_y4n = zapgremlins(y4n);
}

void MultiFilt_Ctor(MultiFilt* unit) {
    if (INRATE(1) == calc_FullRate) {
        if (INRATE(2) == calc_FullRate) {
            SETCALC(MultiFilt_next_aa);
        } else {
            SETCALC(MultiFilt_next_ak);
        }
    } else {
        if (INRATE(2) == calc_FullRate) {
            SETCALC(MultiFilt_next_ka);
        } else {
            SETCALC(MultiFilt_next_kk);
        }
    }
    float cf = ZIN0(1);
    unit->m_cf = cf;
    unit->m_rq = ZIN0(2);
    unit->m_f = 2.f * sin(pi * cf * SAMPLEDUR * 0.25);
    unit->m_hp = unit->m_lp = unit->m_bp = 0.0f;
    unit->m_halfsamp = 20000;
    ClearUnitOutputs(unit, 1);
}

void MultiFilt_next_kk(MultiFilt* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out[3];
    out[0] = ZOUT(0);
    out[1] = ZOUT(1);
    out[2] = ZOUT(2);
    float nextcf = ZIN0(1);
    float nextrq = ZIN0(2);
    float rq = unit->m_rq;
    float f = unit->m_f;
    float hp = unit->m_hp;
    float lp = unit->m_lp;
    float bp = unit->m_bp;

    if (nextcf != unit->m_cf) {
        float nextf = 2.f * sin(pi * nextcf * SAMPLEDUR * 0.25);
        float fslope = CALCSLOPE(nextf, f);

        if (nextrq != rq) {
            if (nextrq * unit->m_halfsamp < nextcf)
                nextrq = nextcf / unit->m_halfsamp;
            float rqslope = CALCSLOPE(nextrq, rq);
            LOOP(inNumSamples, float sig = ZXP(in); hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 f += fslope; rq += rqslope;

                 ZXP(out[0]) = lp; ZXP(out[1]) = hp; ZXP(out[2]) = bp;);
        } else {
            if (rq * unit->m_halfsamp < nextcf)
                rq = nextcf / unit->m_halfsamp;
            LOOP(inNumSamples, float sig = ZXP(in); hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 f += fslope;

                 ZXP(out[0]) = lp; ZXP(out[1]) = hp; ZXP(out[2]) = bp;);
        }
    } else {
        if (nextrq != rq) {
            if (nextrq * unit->m_halfsamp < nextcf)
                nextrq = nextcf / unit->m_halfsamp;
            float rqslope = CALCSLOPE(nextrq, rq);
            LOOP(inNumSamples, float sig = ZXP(in); hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 rq += rqslope;

                 ZXP(out[0]) = lp; ZXP(out[1]) = hp; ZXP(out[2]) = bp;);
        } else {
            if (rq * unit->m_halfsamp < nextcf)
                rq = nextcf / unit->m_halfsamp;
            LOOP(inNumSamples, float sig = ZXP(in); hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

                 ZXP(out[0]) = lp; ZXP(out[1]) = hp; ZXP(out[2]) = bp;);
        }
    }

    unit->m_hp = zapgremlins(hp);
    unit->m_lp = zapgremlins(lp);
    unit->m_bp = zapgremlins(bp);
    unit->m_f = f;
    unit->m_cf = nextcf;
    unit->m_rq = nextrq;
}

void MultiFilt_next_ak(MultiFilt* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out[3];
    out[0] = ZOUT(0);
    out[1] = ZOUT(1);
    out[2] = ZOUT(2);
    float* nextcf = ZIN(1);
    float nextrq = ZIN0(2);
    float rq = unit->m_rq;
    float f = unit->m_f;
    float hp = unit->m_hp;
    float lp = unit->m_lp;
    float bp = unit->m_bp;
    float lastcf = unit->m_cf;
    float cf;

    if (nextrq != rq) {
        float rqslope = CALCSLOPE(nextrq, rq);
        LOOP(
            inNumSamples, cf = ZXP(nextcf); if (cf != lastcf) {
                f = 2.f * sin(pi * cf * SAMPLEDUR * 0.25);
                lastcf = cf;
            }

            if (rq * unit->m_halfsamp < cf) rq = cf / unit->m_halfsamp;

            float sig = ZXP(in); hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

            hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

            hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

            hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

            rq += rqslope;

            ZXP(out[0]) = lp; ZXP(out[1]) = hp; ZXP(out[2]) = bp;);
    } else {
        LOOP(
            inNumSamples, cf = ZXP(nextcf); if (cf != lastcf) {
                f = 2.f * sin(pi * cf * SAMPLEDUR * 0.25);
                lastcf = cf;
            }

            if (rq * unit->m_halfsamp < cf) rq = cf / unit->m_halfsamp;
            float sig = ZXP(in); hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

            hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

            hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

            hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

            ZXP(out[0]) = lp; ZXP(out[1]) = hp; ZXP(out[2]) = bp;);
    }

    unit->m_hp = zapgremlins(hp);
    unit->m_lp = zapgremlins(lp);
    unit->m_bp = zapgremlins(bp);
    unit->m_f = f;
    unit->m_cf = cf;
    unit->m_rq = nextrq;
}

void MultiFilt_next_ka(MultiFilt* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out[3];
    out[0] = ZOUT(0);
    out[1] = ZOUT(1);
    out[2] = ZOUT(2);
    float nextcf = ZIN0(1);
    float* nextrq = ZIN(2);
    float rq;
    float f = unit->m_f;
    float hp = unit->m_hp;
    float lp = unit->m_lp;
    float bp = unit->m_bp;

    if (nextcf != unit->m_cf) {
        float nextf = 2.f * sin(pi * nextcf * SAMPLEDUR * 0.25);
        float fslope = CALCSLOPE(nextf, f);

        LOOP(inNumSamples, rq = ZXP(nextrq); if (rq * unit->m_halfsamp < nextcf) rq = nextcf / unit->m_halfsamp;
             float sig = ZXP(in); hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

             hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

             hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

             hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

             f += fslope;

             ZXP(out[0]) = lp; ZXP(out[1]) = hp; ZXP(out[2]) = bp;);
    } else {
        LOOP(inNumSamples, rq = ZXP(nextrq); if (rq * unit->m_halfsamp < nextcf) rq = nextcf / unit->m_halfsamp;
             float sig = ZXP(in); hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

             hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

             hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

             hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

             ZXP(out[0]) = lp; ZXP(out[1]) = hp; ZXP(out[2]) = bp;);
    }

    unit->m_hp = zapgremlins(hp);
    unit->m_lp = zapgremlins(lp);
    unit->m_bp = zapgremlins(bp);
    unit->m_f = f;
    unit->m_cf = nextcf;
    unit->m_rq = rq;
}

void MultiFilt_next_aa(MultiFilt* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out[3];
    out[0] = ZOUT(0);
    out[1] = ZOUT(1);
    out[2] = ZOUT(2);
    float* nextcf = ZIN(1);
    float* nextrq = ZIN(2);
    float f = unit->m_f;
    float hp = unit->m_hp;
    float lp = unit->m_lp;
    float bp = unit->m_bp;
    float lastcf = unit->m_cf;
    float cf, rq;

    LOOP(
        inNumSamples, cf = ZXP(nextcf); rq = ZXP(nextrq); if (cf != lastcf) {
            f = 2.f * sin(pi * cf * SAMPLEDUR * 0.25);
            lastcf = cf;
        }

        if (rq * unit->m_halfsamp < cf) rq = cf / unit->m_halfsamp;

        float sig = ZXP(in); hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

        hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

        hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

        hp = sig - rq * bp - lp; lp = bp * f + lp; bp = hp * f + bp;

        ZXP(out[0]) = lp; ZXP(out[1]) = hp; ZXP(out[2]) = bp;);

    unit->m_hp = zapgremlins(hp);
    unit->m_lp = zapgremlins(lp);
    unit->m_bp = zapgremlins(bp);
    unit->m_f = f;
    unit->m_cf = cf;
    unit->m_rq = rq;
}

void RLPFD_Ctor(RLPFD* unit) {
    if (INRATE(1) == calc_FullRate) {
        if (INRATE(2) == calc_FullRate) {
            SETCALC(RLPFD_next_aa); // a-rate fco and res
        } else {
            SETCALC(RLPFD_next_ak); // a-rate fco, k-rate res
        }
    } else {
        if (INRATE(2) == calc_FullRate) {
            SETCALC(RLPFD_next_ka); // k-rate fco, a-rate res
        } else {
            SETCALC(RLPFD_next_kk);
        } // k-rate fco and res
    }
    float fco = IN0(1);
    float fcn = 2.f * fco * SAMPLEDUR;
    unit->m_ap = ((-2.7441 * fcn + 3.1433) * fcn + 1.74) * fcn - 0.9984;
    float ap1 = unit->m_ap + 1;
    unit->m_scl = ((2.7079 * ap1 + 10.963) * ap1 - 14.934) * ap1 + 8.4974;
    unit->m_fco = fco;
    unit->m_res = IN0(2);
    unit->m_x1 = unit->m_y1 = unit->m_y2 = unit->m_y3 = 0.0f;
    unit->m_x1nm1 = unit->m_y1nm1 = unit->m_y2nm1 = 0.0f;
    ClearUnitOutputs(unit, 1);
}

void RLPFD_next_kk(RLPFD* unit, int inNumSamples) {
    float* in = IN(0);
    float* out = OUT(0);
    float nextfco = IN0(1);
    float nextres = IN0(2);
    float dist = IN0(3) * 0.001;
    float fco = unit->m_fco;
    float res = unit->m_res;
    float fcn = 2.f * nextfco * SAMPLEDUR;

    float x1nm1 = unit->m_x1nm1;
    float y1nm1 = unit->m_y1nm1;
    float y2nm1 = unit->m_y2nm1;
    float ap = unit->m_ap;
    float ap1 = ap + 1.f;
    float scl = unit->m_scl;
    float y1 = unit->m_y1;
    float y2 = unit->m_y2;
    float y3 = unit->m_y3;
    float x1 = unit->m_x1;

    float apslope = 0;
    float resslope = 0;
    float sclslope = 0;

    if (nextfco != fco) {
        float nextap = ((-2.7441 * fcn + 3.1433) * fcn + 1.74) * fcn - 0.9984;
        ap1 = nextap + 1;
        float nextscl = ((2.7079 * ap1 + 10.963) * ap1 - 14.934) * ap1 + 8.4974;
        apslope = CALCSLOPE(nextap, ap);
        sclslope = CALCSLOPE(nextscl, scl);
    }

    if (nextres != res) {
        resslope = CALCSLOPE(nextres, res);
    }

    for (int i = 0; i < inNumSamples; i++) {
        float kres = res * scl;
        ap1 = ap + 1.f;
        x1 = in[i] - kres * y3 / sqrt(1 + y3 * y3);
        y1 = ((x1 + x1nm1) * ap1) * 0.5 - ap * y1;
        y2 = ((y1 + y1nm1) * ap1) * 0.5 - ap * y2;
        y3 = ((y2 + y2nm1) * ap1) * 0.5 - ap * y3;
        if (dist > 0.f)
            y3 = y3 * (1.f + (dist * (1.5 + 2.f * kres * (1.f - fcn))));
        y3 = y3 / sqrt(1 + y3 * y3);

        x1nm1 = x1;
        y1nm1 = y1;
        y2nm1 = y2;

        out[i] = y3;

        if (apslope != 0.f) {
            ap += apslope;
            scl += sclslope;
        }
        if (resslope != 0.f)
            res += resslope;
    }

    unit->m_ap = ap;
    unit->m_scl = scl;
    unit->m_fco = nextfco;
    unit->m_res = res;
    unit->m_x1 = zapgremlins(x1);
    unit->m_y1 = zapgremlins(y1);
    unit->m_y2 = zapgremlins(y2);
    unit->m_y3 = zapgremlins(y3);
    unit->m_x1nm1 = zapgremlins(x1nm1);
    unit->m_y1nm1 = zapgremlins(y1nm1);
    unit->m_y2nm1 = zapgremlins(y2nm1);
}

void RLPFD_next_ka(RLPFD* unit, int inNumSamples) {
    float* in = IN(0);
    float* out = OUT(0);
    float nextfco = IN0(1);
    float dist = IN0(3) * 0.001;
    float fco = unit->m_fco;
    float* res = IN(2);
    float fcn = 2.f * nextfco * SAMPLEDUR;

    float x1nm1 = unit->m_x1nm1;
    float y1nm1 = unit->m_y1nm1;
    float y2nm1 = unit->m_y2nm1;
    float ap = unit->m_ap;
    float ap1 = ap + 1.f;
    float scl = unit->m_scl;
    float y1 = unit->m_y1;
    float y2 = unit->m_y2;
    float y3 = unit->m_y3;
    float x1 = unit->m_x1;

    float apslope = 0;
    float sclslope = 0;

    if (nextfco != fco) {
        float nextap = ((-2.7441 * fcn + 3.1433) * fcn + 1.74) * fcn - 0.9984;
        ap1 = nextap + 1;
        float nextscl = ((2.7079 * ap1 + 10.963) * ap1 - 14.934) * ap1 + 8.4974;
        apslope = CALCSLOPE(nextap, ap);
        sclslope = CALCSLOPE(nextscl, scl);
    }

    for (int i = 0; i < inNumSamples; i++) {
        float kres = res[i] * scl;
        ap1 = ap + 1.f;
        x1 = in[i] - kres * y3 / sqrt(1 + y3 * y3);
        y1 = ((x1 + x1nm1) * ap1) * 0.5 - ap * y1;
        y2 = ((y1 + y1nm1) * ap1) * 0.5 - ap * y2;
        y3 = ((y2 + y2nm1) * ap1) * 0.5 - ap * y3;
        if (dist > 0.f)
            y3 = y3 * (1.f + (dist * (1.5 + 2.f * kres * (1.f - fcn))));
        y3 = y3 / sqrt(1 + y3 * y3);

        x1nm1 = x1;
        y1nm1 = y1;
        y2nm1 = y2;

        out[i] = y3;

        if (apslope != 0.f) {
            ap += apslope;
            scl += sclslope;
        }
    }

    unit->m_ap = ap;
    unit->m_scl = scl;
    unit->m_fco = nextfco;
    unit->m_x1 = zapgremlins(x1);
    unit->m_y1 = zapgremlins(y1);
    unit->m_y2 = zapgremlins(y2);
    unit->m_y3 = zapgremlins(y3);
    unit->m_x1nm1 = zapgremlins(x1nm1);
    unit->m_y1nm1 = zapgremlins(y1nm1);
    unit->m_y2nm1 = zapgremlins(y2nm1);
}

void RLPFD_next_ak(RLPFD* unit, int inNumSamples) {
    float* in = IN(0);
    float* out = OUT(0);
    float nextres = IN0(2);
    float dist = IN0(3) * 0.001;
    float* nextfco = IN(1);
    float fco = unit->m_fco;
    float res = unit->m_res;

    float x1nm1 = unit->m_x1nm1;
    float y1nm1 = unit->m_y1nm1;
    float y2nm1 = unit->m_y2nm1;
    float ap = unit->m_ap;
    float ap1 = ap + 1.f;
    float scl = unit->m_scl;
    float y1 = unit->m_y1;
    float y2 = unit->m_y2;
    float y3 = unit->m_y3;
    float x1 = unit->m_x1;

    float resslope = 0;

    if (nextres != res) {
        resslope = CALCSLOPE(nextres, res);
    }

    for (int i = 0; i < inNumSamples; i++) {
        float fcn = 2.f * nextfco[i] * SAMPLEDUR;
        if (nextfco[i] != fco) {
            ap = ((-2.7441 * fcn + 3.1433) * fcn + 1.74) * fcn - 0.9984;
            ap1 = ap + 1;
            scl = ((2.7079 * ap1 + 10.963) * ap1 - 14.934) * ap1 + 8.4974;
            fco = nextfco[i];
        }
        float kres = res * scl;
        x1 = in[i] - kres * y3 / sqrt(1 + y3 * y3);
        y1 = ((x1 + x1nm1) * ap1) * 0.5 - ap * y1;
        y2 = ((y1 + y1nm1) * ap1) * 0.5 - ap * y2;
        y3 = ((y2 + y2nm1) * ap1) * 0.5 - ap * y3;
        if (dist > 0.f)
            y3 = y3 * (1.f + (dist * (1.5 + 2.f * kres * (1.f - fcn))));
        y3 = y3 / sqrt(1 + y3 * y3);

        x1nm1 = x1;
        y1nm1 = y1;
        y2nm1 = y2;

        out[i] = y3;
        if (resslope != 0.f)
            res += resslope;
    }

    unit->m_res = res;
    unit->m_fco = fco;
    unit->m_ap = ap;
    unit->m_scl = scl;
    unit->m_x1 = zapgremlins(x1);
    unit->m_y1 = zapgremlins(y1);
    unit->m_y2 = zapgremlins(y2);
    unit->m_y3 = zapgremlins(y3);
    unit->m_x1nm1 = zapgremlins(x1nm1);
    unit->m_y1nm1 = zapgremlins(y1nm1);
    unit->m_y2nm1 = zapgremlins(y2nm1);
}

void RLPFD_next_aa(RLPFD* unit, int inNumSamples) {
    float* in = IN(0);
    float* out = OUT(0);
    float dist = IN0(3) * 0.001;
    float* nextfco = IN(1);
    float fco = unit->m_fco;
    float* res = IN(2);

    float x1nm1 = unit->m_x1nm1;
    float y1nm1 = unit->m_y1nm1;
    float y2nm1 = unit->m_y2nm1;
    float ap = unit->m_ap;
    float ap1 = ap + 1.f;
    float scl = unit->m_scl;
    float y1 = unit->m_y1;
    float y2 = unit->m_y2;
    float y3 = unit->m_y3;
    float x1 = unit->m_x1;

    for (int i = 0; i < inNumSamples; i++) {
        float fcn = 2.f * nextfco[i] * SAMPLEDUR;
        if (nextfco[i] != fco) {
            ap = ((-2.7441 * fcn + 3.1433) * fcn + 1.74) * fcn - 0.9984;
            ap1 = ap + 1;
            scl = ((2.7079 * ap1 + 10.963) * ap1 - 14.934) * ap1 + 8.4974;
            fco = nextfco[i];
        }
        float kres = res[i] * scl;
        x1 = in[i] - kres * y3 / sqrt(1 + y3 * y3);
        y1 = ((x1 + x1nm1) * ap1) * 0.5 - ap * y1;
        y2 = ((y1 + y1nm1) * ap1) * 0.5 - ap * y2;
        y3 = ((y2 + y2nm1) * ap1) * 0.5 - ap * y3;
        if (dist > 0.f)
            y3 = y3 * (1.f + (dist * (1.5 + 2.f * kres * (1.f - fcn))));
        y3 = y3 / sqrt(1 + y3 * y3);

        x1nm1 = x1;
        y1nm1 = y1;
        y2nm1 = y2;

        out[i] = y3;
    }

    unit->m_fco = fco;
    unit->m_ap = ap;
    unit->m_scl = scl;
    unit->m_x1 = zapgremlins(x1);
    unit->m_y1 = zapgremlins(y1);
    unit->m_y2 = zapgremlins(y2);
    unit->m_y3 = zapgremlins(y3);
    unit->m_x1nm1 = zapgremlins(x1nm1);
    unit->m_y1nm1 = zapgremlins(y1nm1);
    unit->m_y2nm1 = zapgremlins(y2nm1);
}

void NestedAllpassN_Ctor(NestedAllpassN* unit) {
    SET2BUF
    unit->m_phase = 0;
    unit->m_dsamp1 = -(long)(unit->m_dt1 * unit->mRate->mSampleRate);
    unit->m_dsamp2 = -(long)(unit->m_dt2 * unit->mRate->mSampleRate);
    SETCALC(NestedAllpassN_next_z);
    ZOUT0(0) = 0.f;
}

void NestedAllpassN_Dtor(NestedAllpassN* unit) {
    RTFree(unit->mWorld, unit->m_buf1);
    RTFree(unit->mWorld, unit->m_buf2);
}

void NestedAllpassN_next_z(NestedAllpassN* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float del1;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    long dsamp1 = unit->m_dsamp1;
    long dsamp2 = unit->m_dsamp2;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    float samp, sum, output;

    if (next_dt1 == dt1 && next_dt2 == dt2) {
        LOOP(
            inNumSamples, phase++; dsamp1++; dsamp2++; samp = ZXP(in); if (dsamp1 < 0 || dsamp2 < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                ZXP(out) = 0.f;
            } else {
                del1 = buf1[dsamp1 & mask1];
                sum = buf2[dsamp2 & mask2] - gain2 * del1;
                output = sum - gain1 * samp;
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum;
                ZXP(out) = output;
            };);
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        LOOP(
            inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2;
            dsamp1 = phase - (long)(dt1 * unit->mRate->mSampleRate);
            dsamp2 = phase - (long)(dt2 * unit->mRate->mSampleRate); samp = ZXP(in);
            buf1[phase & mask1] = samp + gain1 * output; buf2[phase & mask2] = del1 + gain2 * sum;
            if (dsamp1 < 0 || dsamp2 < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                ZXP(out) = 0.f;
            } else {
                del1 = buf1[dsamp1 & mask1];
                sum = buf2[dsamp2 & mask2] - gain2 * del1;
                output = sum - gain1 * samp;
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum;
                ZXP(out) = output;
            };);
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput >= unit->m_maxdel) {
        SETCALC(NestedAllpassN_next);
    }
}

void NestedAllpassN_next(NestedAllpassN* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float del1;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    long dsamp1 = unit->m_dsamp1;
    long dsamp2 = unit->m_dsamp2;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    float samp, sum, output;

    if (next_dt1 == dt1 && next_dt2 == dt2) {
        LOOP(inNumSamples, phase++; dsamp1++; dsamp2++; samp = ZXP(in); del1 = buf1[dsamp1 & mask1];
             sum = buf2[dsamp2 & mask2] - gain2 * del1; output = sum - gain1 * samp;
             buf1[phase & mask1] = samp + gain1 * output; buf2[phase & mask2] = del1 + gain2 * sum; ZXP(out) = output;);
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        LOOP(inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2;
             dsamp1 = phase - (long)(dt1 * unit->mRate->mSampleRate);
             dsamp2 = phase - (long)(dt2 * unit->mRate->mSampleRate); samp = ZXP(in); del1 = buf1[dsamp1 & mask1];
             sum = buf2[dsamp2 & mask2] - gain2 * del1; output = sum - gain1 * samp;
             buf1[phase & mask1] = samp + gain1 * output; buf2[phase & mask2] = del1 + gain2 * sum; ZXP(out) = output;);
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;
}

void NestedAllpassL_Ctor(NestedAllpassL* unit) {
    SET2BUF
    unit->m_phase = 0;
    unit->m_dsamp1 = -(unit->m_dt1 * unit->mRate->mSampleRate);
    unit->m_dsamp2 = -(unit->m_dt2 * unit->mRate->mSampleRate);
    SETCALC(NestedAllpassL_next_z);
    ZOUT0(0) = 0.f;
}

void NestedAllpassL_Dtor(NestedAllpassL* unit) {
    RTFree(unit->mWorld, unit->m_buf1);
    RTFree(unit->mWorld, unit->m_buf2);
}

void NestedAllpassL_next(NestedAllpassL* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float del1;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    float dsamp1 = unit->m_dsamp1;
    float dsamp2 = unit->m_dsamp2;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    float samp, sum, output, frac1, frac2, del11, del21;

    if (next_dt1 == dt1 && next_dt2 == dt2) {
        int idsamp1;
        int idsamp2;
        LOOP(inNumSamples, phase++; dsamp1++; dsamp2++; idsamp1 = (int)dsamp1; idsamp2 = (int)dsamp2;
             frac1 = dsamp1 - idsamp1; frac2 = dsamp2 - idsamp2; samp = ZXP(in); del11 = buf1[idsamp1 & mask1];
             del21 = buf2[idsamp2 & mask2]; float del12 = buf1[(idsamp1 - 1) & mask1];
             float del22 = buf2[(idsamp2 - 1) & mask2]; del1 = lininterp(frac1, del11, del12);
             sum = lininterp(frac2, del21, del22) - gain2 * del1; output = sum - gain1 * samp;
             buf1[phase & mask1] = samp + gain1 * output; buf2[phase & mask2] = del1 + gain2 * sum; ZXP(out) = output;);
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        LOOP(inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2; dsamp1 = phase - dt1 * unit->mRate->mSampleRate;
             dsamp2 = phase - dt2 * unit->mRate->mSampleRate; int idsamp1 = (int)dsamp1; int idsamp2 = (int)dsamp2;
             frac1 = dsamp1 - idsamp1; frac2 = dsamp2 - idsamp2; samp = ZXP(in);
             del1 = lininterp(frac1, buf1[idsamp1 & mask1], buf1[(idsamp1 - 1) & mask1]);
             sum = lininterp(frac2, buf2[idsamp2 & mask2], buf2[(idsamp2 - 1) & mask2]) - gain2 * del1;
             output = sum - gain1 * samp; buf1[phase & mask1] = samp + gain1 * output;
             buf2[phase & mask2] = del1 + gain2 * sum; ZXP(out) = output;);
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;
}

void NestedAllpassL_next_z(NestedAllpassL* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float del1;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    float dsamp1 = unit->m_dsamp1;
    float dsamp2 = unit->m_dsamp2;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    float samp, sum, output, frac1, frac2, del11, del21;

    if (next_dt1 == dt1 && next_dt2 == dt2) {
        int idsamp1;
        int idsamp2;
        LOOP(
            inNumSamples, phase++; dsamp1++; dsamp2++; idsamp1 = (int)dsamp1; idsamp2 = (int)dsamp2;
            frac1 = dsamp1 - idsamp1; frac2 = dsamp2 - idsamp2; samp = ZXP(in); del11 = buf1[idsamp1 & mask1];
            del21 = buf2[idsamp2 & mask2]; float del12 = buf1[(idsamp1 - 1) & mask1];
            float del22 = buf2[(idsamp2 - 1) & mask2]; del1 = lininterp(frac1, del11, del12);
            sum = lininterp(frac2, del21, del22) - gain2 * del1; output = sum - gain1 * samp;
            if ((idsamp1 - 1) < 0 || (idsamp2 - 1) < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                ZXP(out) = 0.f;
            } else {
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum;
                ZXP(out) = output;
            });
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        LOOP(
            inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2; dsamp1 = phase - dt1 * unit->mRate->mSampleRate;
            dsamp2 = phase - dt2 * unit->mRate->mSampleRate; int idsamp1 = (int)dsamp1; int idsamp2 = (int)dsamp2;
            frac1 = dsamp1 - idsamp1; frac2 = dsamp2 - idsamp2; samp = ZXP(in); del11 = buf1[idsamp1 & mask1];
            del21 = buf2[idsamp2 & mask2]; del1 = lininterp(frac1, del11, buf1[(idsamp1 - 1) & mask1]);
            sum = lininterp(frac2, del21, buf2[(idsamp2 - 1) & mask2]) - gain2 * del1; output = sum - gain1 * samp;
            if ((idsamp1 - 1) < 0 || (idsamp2 - 1) < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                ZXP(out) = 0.f;
            } else {
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum;
                ZXP(out) = output;
            });
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput >= unit->m_maxdel) {
        SETCALC(NestedAllpassL_next);
    }
}


void NestedAllpassC_Ctor(NestedAllpassC* unit) {
    SET2BUF
    unit->m_phase = 0;
    unit->m_dsamp1 = -(unit->m_dt1 * unit->mRate->mSampleRate);
    unit->m_dsamp2 = -(unit->m_dt2 * unit->mRate->mSampleRate);
    SETCALC(NestedAllpassC_next_z);
    ZOUT0(0) = 0.f;
}

void NestedAllpassC_Dtor(NestedAllpassC* unit) {
    RTFree(unit->mWorld, unit->m_buf1);
    RTFree(unit->mWorld, unit->m_buf2);
}

void NestedAllpassC_next(NestedAllpassC* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float del1, del2;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    float dsamp1 = unit->m_dsamp1;
    float dsamp2 = unit->m_dsamp2;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    float samp, sum, output, frac1, frac2;

    if (next_dt1 == dt1 && next_dt2 == dt2) {
        int idsamp1;
        int idsamp2;
        LOOP(inNumSamples, phase++; dsamp1++; dsamp2++; idsamp1 = (int)dsamp1; idsamp2 = (int)dsamp2;
             frac1 = dsamp1 - idsamp1; frac2 = dsamp2 - idsamp2; samp = ZXP(in);
             float del10 = buf1[(idsamp1 + 1) & mask1]; float del11 = buf1[idsamp1 & mask1];
             float del12 = buf1[(idsamp1 - 1) & mask1]; float del13 = buf1[(idsamp1 - 2) & mask1];
             del1 = cubicinterp(frac1, del10, del11, del12, del13); float del20 = buf2[(idsamp2 + 1) & mask2];
             float del21 = buf2[idsamp2 & mask2]; float del22 = buf2[(idsamp2 - 1) & mask2];
             float del23 = buf2[(idsamp2 - 2) & mask2]; del2 = cubicinterp(frac1, del20, del21, del22, del23);
             sum = del2 - gain2 * del1; output = sum - gain1 * samp; buf1[phase & mask1] = samp + gain1 * output;
             buf2[phase & mask2] = del1 + gain2 * sum; ZXP(out) = output;);
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        LOOP(inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2; dsamp1 = phase - dt1 * unit->mRate->mSampleRate;
             dsamp2 = phase - dt2 * unit->mRate->mSampleRate; int idsamp1 = (int)dsamp1; int idsamp2 = (int)dsamp2;
             frac1 = dsamp1 - idsamp1; frac2 = dsamp2 - idsamp2; samp = ZXP(in); float del11 = buf1[idsamp1 & mask1];
             float del12 = buf1[(idsamp1 - 1) & mask1]; float del13 = buf1[(idsamp1 - 2) & mask1];
             float del10 = buf1[(idsamp1 + 1) & mask1]; del1 = cubicinterp(frac1, del10, del11, del12, del13);
             float del21 = buf2[idsamp2 & mask2]; float del22 = buf2[(idsamp2 - 1) & mask2];
             float del23 = buf2[(idsamp2 - 2) & mask2]; float del20 = buf2[(idsamp2 + 1) & mask2];
             del2 = cubicinterp(frac1, del20, del21, del22, del23); sum = del2 - gain2 * del1;
             output = sum - gain1 * samp; buf1[phase & mask1] = samp + gain1 * output;
             buf2[phase & mask2] = del1 + gain2 * sum; ZXP(out) = output;);
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;
}

void NestedAllpassC_next_z(NestedAllpassC* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float del1, del2;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    float dsamp1 = unit->m_dsamp1;
    float dsamp2 = unit->m_dsamp2;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    float samp, sum, output, frac1, frac2;

    if (next_dt1 == dt1 && next_dt2 == dt2) {
        int idsamp1;
        int idsamp2;
        LOOP(
            inNumSamples, phase++; dsamp1++; dsamp2++; idsamp1 = (int)dsamp1; idsamp2 = (int)dsamp2;
            frac1 = dsamp1 - idsamp1; frac2 = dsamp2 - idsamp2; samp = ZXP(in);
            float del10 = buf1[(idsamp1 + 1) & mask1]; float del11 = buf1[idsamp1 & mask1];
            float del12 = buf1[(idsamp1 - 1) & mask1]; float del13 = buf1[(idsamp1 - 2) & mask1];
            del1 = cubicinterp(frac1, del10, del11, del12, del13); float del20 = buf2[(idsamp2 + 1) & mask2];
            float del21 = buf2[idsamp2 & mask2]; float del22 = buf2[(idsamp2 - 1) & mask2];
            float del23 = buf2[(idsamp2 - 2) & mask2]; del2 = cubicinterp(frac1, del20, del21, del22, del23);
            sum = del2 - gain2 * del1; output = sum - gain1 * samp; if (idsamp1 < 0 || idsamp2 < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                ZXP(out) = 0.f;
            } else {
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum;
                ZXP(out) = output;
            });
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        LOOP(
            inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2; dsamp1 = phase - dt1 * unit->mRate->mSampleRate;
            dsamp2 = phase - dt2 * unit->mRate->mSampleRate; int idsamp1 = (int)dsamp1; int idsamp2 = (int)dsamp2;
            frac1 = dsamp1 - idsamp1; frac2 = dsamp2 - idsamp2; samp = ZXP(in); float del11 = buf1[idsamp1 & mask1];
            float del12 = buf1[(idsamp1 - 1) & mask1]; float del13 = buf1[(idsamp1 - 2) & mask1];
            float del10 = buf1[(idsamp1 + 1) & mask1]; del1 = cubicinterp(frac1, del10, del11, del12, del13);
            float del21 = buf2[idsamp2 & mask2]; float del22 = buf2[(idsamp2 - 1) & mask2];
            float del23 = buf2[(idsamp2 - 2) & mask2]; float del20 = buf2[(idsamp2 + 1) & mask2];
            del2 = cubicinterp(frac1, del20, del21, del22, del23); sum = del2 - gain2 * del1;
            output = sum - gain1 * samp; if (idsamp1 < 0 || idsamp2 < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                ZXP(out) = 0.f;
            } else {
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum;
                ZXP(out) = output;
            });
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput >= unit->m_maxdel) {
        SETCALC(NestedAllpassC_next);
    }
}

void DoubleNestedAllpassN_Ctor(DoubleNestedAllpassN* unit) {
    SET3BUF
    unit->m_phase = 0;
    unit->m_dsamp1 = -(long)(unit->m_dt1 * unit->mRate->mSampleRate);
    unit->m_dsamp2 = -(long)(unit->m_dt2 * unit->mRate->mSampleRate);
    unit->m_dsamp3 = -(long)(unit->m_dt3 * unit->mRate->mSampleRate);
    SETCALC(DoubleNestedAllpassN_next_z);
    ZOUT0(0) = 0.f;
}

void DoubleNestedAllpassN_Dtor(DoubleNestedAllpassN* unit) {
    RTFree(unit->mWorld, unit->m_buf1);
    RTFree(unit->mWorld, unit->m_buf2);
    RTFree(unit->mWorld, unit->m_buf3);
}

void DoubleNestedAllpassN_next(DoubleNestedAllpassN* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float* buf3 = unit->m_buf3;
    float del1;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float dt3 = unit->m_dt3;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    float next_dt3 = ZIN0(8);
    long dsamp1 = unit->m_dsamp1;
    long dsamp2 = unit->m_dsamp2;
    long dsamp3 = unit->m_dsamp3;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    float gain3 = ZIN0(9);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    long mask3 = unit->m_maxdel3;
    float samp, sum1, sum2, output;

    if (next_dt1 == dt1 && next_dt2 == dt2 && next_dt3 == dt3) {
        LOOP(inNumSamples, phase++; dsamp1++; dsamp2++; dsamp3++; samp = ZXP(in); del1 = buf1[dsamp1 & mask1];
             sum1 = buf2[dsamp2 & mask2] - gain2 * del1; sum2 = buf3[dsamp3 & mask3] - gain3 * sum1;
             output = sum2 - gain1 * samp; buf1[phase & mask1] = samp + gain1 * output;
             buf2[phase & mask2] = del1 + gain2 * sum1; buf3[phase & mask3] = sum1 + gain3 * sum2; ZXP(out) = output;);
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        float dslope3 = CALCSLOPE(next_dt3, dt3);
        LOOP(inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2; dt3 += dslope3;
             dsamp1 = phase - (long)(dt1 * unit->mRate->mSampleRate);
             dsamp2 = phase - (long)(dt2 * unit->mRate->mSampleRate);
             dsamp3 = phase - (long)(dt3 * unit->mRate->mSampleRate); samp = ZXP(in); del1 = buf1[dsamp1 & mask1];
             sum1 = buf2[dsamp2 & mask2] - gain2 * del1; sum2 = buf3[dsamp3 & mask3] - gain3 * sum1;
             output = sum2 - gain1 * samp; buf1[phase & mask1] = samp + gain1 * output;
             buf2[phase & mask2] = del1 + gain2 * sum1; buf3[phase & mask3] = sum1 + gain3 * sum2; ZXP(out) = output;);
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dsamp3 = dsamp3;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;
    unit->m_dt3 = dt3;
}

void DoubleNestedAllpassN_next_z(DoubleNestedAllpassN* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float* buf3 = unit->m_buf3;
    float del1;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float dt3 = unit->m_dt3;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    float next_dt3 = ZIN0(8);
    long dsamp1 = unit->m_dsamp1;
    long dsamp2 = unit->m_dsamp2;
    long dsamp3 = unit->m_dsamp3;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    float gain3 = ZIN0(9);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    long mask3 = unit->m_maxdel3;
    float samp, sum1, sum2, output;

    if (next_dt1 == dt1 && next_dt2 == dt2 && next_dt3 == dt3) {
        LOOP(
            inNumSamples, phase++; dsamp1++; dsamp2++; dsamp3++; samp = ZXP(in); del1 = buf1[dsamp1 & mask1];
            sum1 = buf2[dsamp2 & mask2] - gain2 * del1; sum2 = buf3[dsamp3 & mask3] - gain3 * sum1;
            output = sum2 - gain1 * samp; if (dsamp1 < 0 || dsamp2 < 0 || dsamp3 < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                buf3[phase & mask3] = samp;
                ZXP(out) = 0.f;
            } else {
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum1;
                buf3[phase & mask3] = sum1 + gain3 * sum2;
                ZXP(out) = output;
            });
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        float dslope3 = CALCSLOPE(next_dt3, dt3);
        LOOP(
            inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2; dt3 += dslope3;
            dsamp1 = phase - (long)(dt1 * unit->mRate->mSampleRate);
            dsamp2 = phase - (long)(dt2 * unit->mRate->mSampleRate);
            dsamp3 = phase - (long)(dt3 * unit->mRate->mSampleRate); samp = ZXP(in); del1 = buf1[dsamp1 & mask1];
            sum1 = buf2[dsamp2 & mask2] - gain2 * del1; sum2 = buf3[dsamp3 & mask3] - gain3 * sum1;
            output = sum2 - gain1 * samp; if (dsamp1 < 0 || dsamp2 < 0 || dsamp3 < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                buf3[phase & mask3] = samp;
                ZXP(out) = 0.f;
            } else {
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum1;
                buf3[phase & mask3] = sum1 + gain3 * sum2;
                ZXP(out) = output;
            });
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dsamp3 = dsamp3;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;
    unit->m_dt3 = dt3;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput >= unit->m_maxdel) {
        SETCALC(DoubleNestedAllpassN_next);
    }
}

void DoubleNestedAllpassL_Ctor(DoubleNestedAllpassL* unit) {
    SET3BUF
    unit->m_phase = 0;
    unit->m_dsamp1 = -unit->m_dt1 * unit->mRate->mSampleRate;
    unit->m_dsamp2 = -unit->m_dt2 * unit->mRate->mSampleRate;
    unit->m_dsamp3 = -unit->m_dt3 * unit->mRate->mSampleRate;
    SETCALC(DoubleNestedAllpassL_next_z);
    ZOUT0(0) = 0.f;
}

void DoubleNestedAllpassL_Dtor(DoubleNestedAllpassL* unit) {
    RTFree(unit->mWorld, unit->m_buf1);
    RTFree(unit->mWorld, unit->m_buf2);
    RTFree(unit->mWorld, unit->m_buf3);
}

void DoubleNestedAllpassL_next(DoubleNestedAllpassL* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float* buf3 = unit->m_buf3;
    float del1;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float dt3 = unit->m_dt3;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    float next_dt3 = ZIN0(8);
    float dsamp1 = unit->m_dsamp1;
    float dsamp2 = unit->m_dsamp2;
    float dsamp3 = unit->m_dsamp3;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    float gain3 = ZIN0(9);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    long mask3 = unit->m_maxdel3;
    float samp, sum1, sum2, output;

    if (next_dt1 == dt1 && next_dt2 == dt2 && next_dt3 == dt3) {
        int idsamp1;
        int idsamp2;
        int idsamp3;
        LOOP(inNumSamples, phase++; dsamp1++; dsamp2++; dsamp3++; idsamp1 = (int)dsamp1; float frac1 = dsamp1 - idsamp1;
             idsamp2 = (int)dsamp2; float frac2 = dsamp2 - idsamp2; idsamp3 = (int)dsamp3;
             float frac3 = dsamp3 - idsamp3; samp = ZXP(in); float del10 = buf1[idsamp1 & mask1];
             float del20 = buf2[idsamp2 & mask2]; float del30 = buf3[idsamp3 & mask3];
             float del11 = buf1[(idsamp1 - 1) & mask1]; float del21 = buf2[(idsamp2 - 1) & mask2];
             float del31 = buf3[(idsamp3 - 1) & mask3]; del1 = lininterp(frac1, del10, del11);
             sum1 = lininterp(frac2, del20, del21) - gain2 * del1; sum2 = lininterp(frac3, del30, del31) - gain3 * sum1;
             output = sum2 - gain1 * samp; buf1[phase & mask1] = samp + gain1 * output;
             buf2[phase & mask2] = del1 + gain2 * sum1; buf3[phase & mask3] = sum1 + gain3 * sum2; ZXP(out) = output;);
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        float dslope3 = CALCSLOPE(next_dt3, dt3);
        LOOP(inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2; dt3 += dslope3;
             dsamp1 = phase - (long)(dt1 * unit->mRate->mSampleRate);
             dsamp2 = phase - (long)(dt2 * unit->mRate->mSampleRate);
             dsamp3 = phase - (long)(dt3 * unit->mRate->mSampleRate); int idsamp1 = (int)dsamp1;
             float frac1 = dsamp1 - idsamp1; int idsamp2 = (int)dsamp2; float frac2 = dsamp2 - idsamp2;
             int idsamp3 = (int)dsamp3; float frac3 = dsamp3 - idsamp3; samp = ZXP(in);
             del1 = lininterp(frac1, buf1[idsamp1 & mask1], buf1[(idsamp1 - 1) & mask1]);
             sum1 = lininterp(frac2, buf2[idsamp2 & mask2], buf2[(idsamp2 - 1) & mask2]) - gain2 * del1;
             sum2 = lininterp(frac3, buf3[idsamp3 & mask3], buf3[(idsamp3 - 1) & mask3]) - gain3 * sum1;
             output = sum2 - gain1 * samp; buf1[phase & mask1] = samp + gain1 * output;
             buf2[phase & mask2] = del1 + gain2 * sum1; buf3[phase & mask3] = sum1 + gain3 * sum2; ZXP(out) = output;);
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dsamp3 = dsamp3;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;
    unit->m_dt3 = dt3;
}

void DoubleNestedAllpassL_next_z(DoubleNestedAllpassL* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float* buf3 = unit->m_buf3;
    float del1;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float dt3 = unit->m_dt3;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    float next_dt3 = ZIN0(8);
    float dsamp1 = unit->m_dsamp1;
    float dsamp2 = unit->m_dsamp2;
    float dsamp3 = unit->m_dsamp3;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    float gain3 = ZIN0(9);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    long mask3 = unit->m_maxdel3;
    float samp, sum1, sum2, output;

    if (next_dt1 == dt1 && next_dt2 == dt2 && next_dt3 == dt3) {
        int idsamp1;
        int idsamp2;
        int idsamp3;
        LOOP(
            inNumSamples, phase++; dsamp1++; dsamp2++; dsamp3++; idsamp1 = (int)dsamp1; float frac1 = dsamp1 - idsamp1;
            idsamp2 = (int)dsamp2; float frac2 = dsamp2 - idsamp2; idsamp3 = (int)dsamp3;
            float frac3 = dsamp3 - idsamp3; int idsamp11 = idsamp1 - 1; int idsamp21 = idsamp2 - 1;
            int idsamp31 = idsamp3 - 1; samp = ZXP(in); float del10 = buf1[idsamp1 & mask1];
            float del20 = buf2[idsamp2 & mask2]; float del30 = buf3[idsamp3 & mask3];
            float del11 = buf1[idsamp11 & mask1]; float del21 = buf2[idsamp21 & mask2];
            float del31 = buf3[idsamp31 & mask3]; del1 = lininterp(frac1, del10, del11);
            sum1 = lininterp(frac2, del20, del21) - gain2 * del1; sum2 = lininterp(frac3, del30, del31) - gain3 * sum1;
            output = sum2 - gain1 * samp; if (idsamp11 < 0 || idsamp21 < 0 || idsamp31 < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                buf3[phase & mask3] = samp;
                ZXP(out) = 0.f;
            } else {
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum1;
                buf3[phase & mask3] = sum1 + gain3 * sum2;
                ZXP(out) = output;
            });
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        float dslope3 = CALCSLOPE(next_dt3, dt3);
        LOOP(
            inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2; dt3 += dslope3;
            dsamp1 = phase - (long)(dt1 * unit->mRate->mSampleRate);
            dsamp2 = phase - (long)(dt2 * unit->mRate->mSampleRate);
            dsamp3 = phase - (long)(dt3 * unit->mRate->mSampleRate); int idsamp1 = (int)dsamp1;
            float frac1 = dsamp1 - idsamp1; int idsamp2 = (int)dsamp2; float frac2 = dsamp2 - idsamp2;
            int idsamp3 = (int)dsamp3; float frac3 = dsamp3 - idsamp3; int idsamp11 = idsamp1 - 1;
            int idsamp21 = idsamp2 - 1; int idsamp31 = idsamp3 - 1; samp = ZXP(in);
            del1 = lininterp(frac1, buf1[idsamp1 & mask1], buf1[idsamp11 & mask1]);
            sum1 = lininterp(frac2, buf2[idsamp2 & mask2], buf2[idsamp21 & mask2]) - gain2 * del1;
            sum2 = lininterp(frac3, buf3[idsamp3 & mask3], buf3[idsamp31 & mask3]) - gain3 * sum1;
            output = sum2 - gain1 * samp; if (idsamp11 < 0 || idsamp21 < 0 || idsamp31 < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                buf3[phase & mask3] = samp;
                ZXP(out) = 0.f;
            } else {
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum1;
                buf3[phase & mask3] = sum1 + gain3 * sum2;
                ZXP(out) = output;
            });
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dsamp3 = dsamp3;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;
    unit->m_dt3 = dt3;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput >= unit->m_maxdel) {
        SETCALC(DoubleNestedAllpassL_next);
    }
}

void DoubleNestedAllpassC_Ctor(DoubleNestedAllpassC* unit) {
    SET3BUF
    unit->m_phase = 0;
    unit->m_dsamp1 = -unit->m_dt1 * unit->mRate->mSampleRate;
    unit->m_dsamp2 = -unit->m_dt2 * unit->mRate->mSampleRate;
    unit->m_dsamp3 = -unit->m_dt3 * unit->mRate->mSampleRate;
    SETCALC(DoubleNestedAllpassC_next_z);
    ZOUT0(0) = 0.f;
}

void DoubleNestedAllpassC_Dtor(DoubleNestedAllpassC* unit) {
    RTFree(unit->mWorld, unit->m_buf1);
    RTFree(unit->mWorld, unit->m_buf2);
    RTFree(unit->mWorld, unit->m_buf3);
}

void DoubleNestedAllpassC_next(DoubleNestedAllpassC* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float* buf3 = unit->m_buf3;
    float del1;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float dt3 = unit->m_dt3;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    float next_dt3 = ZIN0(8);
    float dsamp1 = unit->m_dsamp1;
    float dsamp2 = unit->m_dsamp2;
    float dsamp3 = unit->m_dsamp3;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    float gain3 = ZIN0(9);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    long mask3 = unit->m_maxdel3;
    float samp, sum1, sum2, output;

    if (next_dt1 == dt1 && next_dt2 == dt2 && next_dt3 == dt3) {
        int idsamp1;
        int idsamp2;
        int idsamp3;
        LOOP(inNumSamples, phase++; dsamp1++; dsamp2++; dsamp3++; idsamp1 = (int)dsamp1; float frac1 = dsamp1 - idsamp1;
             idsamp2 = (int)dsamp2; float frac2 = dsamp2 - idsamp2; idsamp3 = (int)dsamp3;
             float frac3 = dsamp3 - idsamp3; samp = ZXP(in); float del10 = buf1[(idsamp1 + 1) & mask1];
             float del20 = buf2[(idsamp2 + 1) & mask2]; float del30 = buf3[(idsamp3 + 1) & mask3];
             float del11 = buf1[(idsamp1)&mask1]; float del21 = buf2[(idsamp2)&mask2];
             float del31 = buf3[(idsamp3)&mask3]; float del12 = buf1[(idsamp1 - 1) & mask1];
             float del22 = buf2[(idsamp2 - 1) & mask2]; float del32 = buf3[(idsamp3 - 1) & mask3];
             float del13 = buf1[(idsamp1 - 2) & mask1]; float del23 = buf2[(idsamp2 - 2) & mask2];
             float del33 = buf3[(idsamp3 - 2) & mask3]; del1 = cubicinterp(frac1, del10, del11, del12, del13);
             sum1 = cubicinterp(frac2, del20, del21, del22, del23) - gain2 * del1;
             sum2 = cubicinterp(frac3, del30, del31, del32, del33) - gain3 * sum1; output = sum2 - gain1 * samp;
             buf1[phase & mask1] = samp + gain1 * output; buf2[phase & mask2] = del1 + gain2 * sum1;
             buf3[phase & mask3] = sum1 + gain3 * sum2; ZXP(out) = output;);
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        float dslope3 = CALCSLOPE(next_dt3, dt3);
        LOOP(inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2; dt3 += dslope3;
             dsamp1 = phase - (long)(dt1 * unit->mRate->mSampleRate);
             dsamp2 = phase - (long)(dt2 * unit->mRate->mSampleRate);
             dsamp3 = phase - (long)(dt3 * unit->mRate->mSampleRate); int idsamp1 = (int)dsamp1;
             float frac1 = dsamp1 - idsamp1; int idsamp2 = (int)dsamp2; float frac2 = dsamp2 - idsamp2;
             int idsamp3 = (int)dsamp3; float frac3 = dsamp3 - idsamp3; samp = ZXP(in);
             del1 = cubicinterp(frac1, buf1[(idsamp1 + 1) & mask1], buf1[idsamp1 & mask1], buf1[(idsamp1 - 1) & mask1],
                                buf1[(idsamp1 - 2) & mask1]);
             sum1 = cubicinterp(frac2, buf2[(idsamp2 + 1) & mask2], buf2[idsamp2 & mask2], buf2[(idsamp2 - 1) & mask2],
                                buf2[(idsamp2 - 2) & mask2])
                 - gain2 * del1;
             sum2 = cubicinterp(frac3, buf3[(idsamp3 + 1) & mask3], buf3[idsamp3 & mask3], buf3[(idsamp3 - 1) & mask3],
                                buf3[(idsamp3 - 2) & mask3])
                 - gain3 * sum1;
             output = sum2 - gain1 * samp; buf1[phase & mask1] = samp + gain1 * output;
             buf2[phase & mask2] = del1 + gain2 * sum1; buf3[phase & mask3] = sum1 + gain3 * sum2; ZXP(out) = output;);
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dsamp3 = dsamp3;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;
    unit->m_dt3 = dt3;
}

void DoubleNestedAllpassC_next_z(DoubleNestedAllpassC* unit, int inNumSamples) {
    float* in = ZIN(0);
    float* out = ZOUT(0);
    float* buf1 = unit->m_buf1;
    float* buf2 = unit->m_buf2;
    float* buf3 = unit->m_buf3;
    float del1;
    float dt1 = unit->m_dt1;
    float dt2 = unit->m_dt2;
    float dt3 = unit->m_dt3;
    float next_dt1 = ZIN0(2);
    float next_dt2 = ZIN0(5);
    float next_dt3 = ZIN0(8);
    float dsamp1 = unit->m_dsamp1;
    float dsamp2 = unit->m_dsamp2;
    float dsamp3 = unit->m_dsamp3;
    float gain1 = ZIN0(3);
    float gain2 = ZIN0(6);
    float gain3 = ZIN0(9);
    long phase = unit->m_phase;
    long mask1 = unit->m_maxdel1;
    long mask2 = unit->m_maxdel2;
    long mask3 = unit->m_maxdel3;
    float samp, sum1, sum2, output;

    if (next_dt1 == dt1 && next_dt2 == dt2 && next_dt3 == dt3) {
        int idsamp1;
        int idsamp2;
        int idsamp3;
        LOOP(
            inNumSamples, phase++; dsamp1++; dsamp2++; dsamp3++; idsamp1 = (int)dsamp1; float frac1 = dsamp1 - idsamp1;
            idsamp2 = (int)dsamp2; float frac2 = dsamp2 - idsamp2; idsamp3 = (int)dsamp3;
            float frac3 = dsamp3 - idsamp3; int idsamp13 = idsamp1 - 2; int idsamp23 = idsamp2 - 2;
            int idsamp33 = idsamp3 - 2; samp = ZXP(in); float del10 = buf1[(idsamp1 + 1) & mask1];
            float del20 = buf2[(idsamp2 + 1) & mask2]; float del30 = buf3[(idsamp3 + 1) & mask3];
            float del11 = buf1[(idsamp1)&mask1]; float del21 = buf2[(idsamp2)&mask2];
            float del31 = buf3[(idsamp3)&mask3]; float del12 = buf1[(idsamp1 - 1) & mask1];
            float del22 = buf2[(idsamp2 - 1) & mask2]; float del32 = buf3[(idsamp3 - 1) & mask3];
            float del13 = buf1[idsamp13 & mask1]; float del23 = buf2[idsamp23 & mask2];
            float del33 = buf3[idsamp33 & mask3]; del1 = cubicinterp(frac1, del10, del11, del12, del13);
            sum1 = cubicinterp(frac2, del20, del21, del22, del23) - gain2 * del1;
            sum2 = cubicinterp(frac3, del30, del31, del32, del33) - gain3 * sum1; output = sum2 - gain1 * samp;
            if (idsamp13 < 0 || idsamp23 < 0 || idsamp33 < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                buf3[phase & mask3] = samp;
                ZXP(out) = 0.f;
            } else {
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum1;
                buf3[phase & mask3] = sum1 + gain3 * sum2;
                ZXP(out) = output;
            });
    } else {
        float dslope1 = CALCSLOPE(next_dt1, dt1);
        float dslope2 = CALCSLOPE(next_dt2, dt2);
        float dslope3 = CALCSLOPE(next_dt3, dt3);
        LOOP(
            inNumSamples, phase++; dt1 += dslope1; dt2 += dslope2; dt3 += dslope3;
            dsamp1 = phase - (long)(dt1 * unit->mRate->mSampleRate);
            dsamp2 = phase - (long)(dt2 * unit->mRate->mSampleRate);
            dsamp3 = phase - (long)(dt3 * unit->mRate->mSampleRate); int idsamp1 = (int)dsamp1;
            float frac1 = dsamp1 - idsamp1; int idsamp2 = (int)dsamp2; float frac2 = dsamp2 - idsamp2;
            int idsamp3 = (int)dsamp3; float frac3 = dsamp3 - idsamp3; int idsamp13 = idsamp1 - 2;
            int idsamp23 = idsamp2 - 2; int idsamp33 = idsamp3 - 2; samp = ZXP(in);
            del1 = cubicinterp(frac1, buf1[(idsamp1 + 1) & mask1], buf1[idsamp1 & mask1], buf1[(idsamp1 - 1) & mask1],
                               buf1[idsamp13 & mask1]);
            sum1 = cubicinterp(frac2, buf2[(idsamp2 + 1) & mask2], buf2[idsamp2 & mask2], buf2[(idsamp2 - 1) & mask2],
                               buf2[idsamp23 & mask2])
                - gain2 * del1;
            sum2 = cubicinterp(frac3, buf3[(idsamp3 + 1) & mask3], buf3[idsamp3 & mask3], buf3[(idsamp3 - 1) & mask3],
                               buf3[idsamp33 & mask3])
                - gain3 * sum1;
            output = sum2 - gain1 * samp; if (idsamp13 < 0 || idsamp23 < 0 || idsamp33 < 0) {
                buf1[phase & mask1] = samp;
                buf2[phase & mask2] = samp;
                buf3[phase & mask3] = samp;
                ZXP(out) = 0.f;
            } else {
                buf1[phase & mask1] = samp + gain1 * output;
                buf2[phase & mask2] = del1 + gain2 * sum1;
                buf3[phase & mask3] = sum1 + gain3 * sum2;
                ZXP(out) = output;
            });
    }

    unit->m_phase = phase;
    unit->m_dsamp1 = dsamp1;
    unit->m_dsamp2 = dsamp2;
    unit->m_dsamp3 = dsamp3;
    unit->m_dt1 = dt1;
    unit->m_dt2 = dt2;
    unit->m_dt3 = dt3;

    unit->m_numoutput += inNumSamples;
    if (unit->m_numoutput >= unit->m_maxdel) {
        SETCALC(DoubleNestedAllpassC_next);
    }
}

#define DefineFilterDelay(name)                                                                                        \
    (*ft->fDefineUnit)(#name, sizeof(name), (UnitCtorFunc)&name##_Ctor, (UnitDtorFunc)&FilterDelay_Dtor, 0);

PluginLoad(BhobFilt) {
    ft = inTable;

    DefineSimpleUnit(MoogLadder);
    DefineSimpleUnit(RLPFD);
    DefineSimpleUnit(MultiFilt);
    DefineDtorUnit(NestedAllpassN);
    DefineDtorUnit(NestedAllpassL);
    DefineDtorUnit(NestedAllpassC);
    DefineDtorUnit(DoubleNestedAllpassN);
    DefineDtorUnit(DoubleNestedAllpassL);
    DefineDtorUnit(DoubleNestedAllpassC);
    DefineFilterDelay(Streson);
    DefineFilterDelay(NLFiltN);
    DefineFilterDelay(NLFiltL);
    DefineFilterDelay(NLFiltC);
}

////////////////////////////////////////////////////////////////////
