over3tap

A three tap 32bit delay line with internal oversampling to limit unwanted interpolation filtering. Useful for choruses
Author: SmashedTransistors
License: LGPL
Github: tiar/delay/over3tap.axo

Inlets

frac32buffer wave input

frac32 d1

frac32 d2

frac32 d3

Outlets

frac32buffer out1

frac32buffer out2

frac32buffer out3

Attributes

combo size

combo Over

combo Ctrl

Declaration
static const uint32_t LENGTHPOW = (attr_size);
static const uint32_t LENGTH = (1 << attr_size);
static const uint32_t LENGTHMASK = ((1 << attr_size) - 1);
static const uint32_t MINDD = (32 << (27 - LENGTHPOW));
static const uint32_t MAXDD = (1 << 27) - (32 << (27 - LENGTHPOW));
int32_t *d;

int32_t interp(uint32_t ind, int32_t p) {
  // int32_t a = p&((1<<(27-LOG2))-1); //q27-LOG2
  // a <<= 31-(27-LOG2); //q31
  int32_t a = (p << (31 - (27 - LENGTHPOW))) & 0x7FFFFFFF; // q31
  int32_t i = p >> (27 - LENGTHPOW);                       // int
  i = (ind + i) & LENGTHMASK;
  int32_t d0 = d[i];
  return ___SMMLA(a, (d[(i + 1) & LENGTHMASK] - d0) << 1, d0);
}

uint32_t ind;
int32_t x, y;
int32_t d1, fd1, d2, fd2, d3, fd3;

float x0, x1, x2, x3, x4, x5, y0, y1;
float df1, df2, df3;
Init
static int32_t _d[attr_poly][1 << attr_size] __attribute__((section(".sdram")));
d = &_d[parent->polyIndex][0];

for (int i = 0; i < LENGTH; i++)
  d[i] = 0;
ind = 0;
d1 = fd1 = d2 = fd2 = d3 = fd3 = x = y = 0;
x0 = x1 = x2 = x3 = x4 = x5 = y0 = y1 = 0;

df1 = df2 = df3 = 0;
Control Rate
// writer
if (attr_Over == 1) {
  for (int smp = 0; smp < BUFSIZE; smp++) {
    // interp -> LP1
    ind--;
    ind &= LENGTHMASK;
    d[ind] = y = (((inlet_in[smp] + x) >> 1) + y) >> 1;
    // nointerp ->LP1
    x = inlet_in[smp];
    ind--;
    ind &= LENGTHMASK;
    d[ind] = y =
        ___SMMLA(1004378102, x - y,
                 y); // 0.4677q31 same gain as one zero one pole 0.5 at Sr/8
  }
}
if (attr_Over == 2) {
  for (int smp = 0; smp < BUFSIZE; smp++) {
    ind--;
    ind &= LENGTHMASK;
    d[ind] = inlet_in[smp];
    ind--;
    ind &= LENGTHMASK;
    d[ind] = inlet_in[smp];
  }
}
// use interpolator
if (attr_Over == 3) {
  for (int smp = 0; smp < BUFSIZE; smp++) {
    x0 = x1;
    x1 = x2;
    x2 = x3;
    x3 = x4;
    x4 = x5;
    x5 = (float)inlet_in[smp];
    /*outlet_y1 = (int32_t)x2;
    outlet_y0 = (int32_t)(
             (x5 + x0) * 0.025665914601895386f
         + (x4 + x1) * -0.04277652433649233f
         + (x3 + x2) * 0.517110609734597f
         );
            */
    ind--;
    ind &= LENGTHMASK;
    d[ind] = (int32_t)x2;
    ind--;
    ind &= LENGTHMASK;
    d[ind] = (int32_t)((x5 + x0) * 0.025665914601895386f +
                       (x4 + x1) * -0.04277652433649233f +
                       (x3 + x2) * 0.517110609734597f);
  }
}

// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
// readers
int i = ind;
#if attr_Ctrl == 0
int32_t dd1 = inlet_d1;
if (dd1 < MINDD)
  dd1 = MINDD;
else if (dd1 > MAXDD)
  dd1 = MAXDD;
#elif attr_Ctrl == 1
int32_t dd1 = (int32_t)df1;
df1 = (MAXDD / (1.0f + 3.0f * arm::q_to_float(inlet_d1, 27)));
#elif attr_Ctrl == 2
int32_t dd1 = (int32_t)df1;
df1 = (MAXDD / (1.0f + 7.0f * arm::q_to_float(inlet_d1, 27)));
if (dd1 < MINDD)
  dd1 = MINDD;
#else
int32_t dd1 = (int32_t)df1;
df1 = (MAXDD / (1.0f + 15.0f * arm::q_to_float(inlet_d1, 27)));
if (dd1 < MINDD)
  dd1 = MINDD;
#endif
dd1 = (dd1 - d1) >> 4;
for (int smp = 0; smp < BUFSIZE; smp++) {
  d1 += dd1;                                 // interpolation
  fd1 = ___SMMLA(0x10000000, d1 - fd1, fd1); // smooth
  outlet_out1[smp] = interp(i, fd1);
  i -= 2;
  i &= LENGTHMASK;
}
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
i = ind;
#if attr_Ctrl == 0
int32_t dd2 = inlet_d2;
if (dd2 < MINDD)
  dd2 = MINDD;
else if (dd2 > MAXDD)
  dd2 = MAXDD;
#elif attr_Ctrl == 1
int32_t dd2 = (int32_t)df2;
df2 = (MAXDD / (1.0f + 3.0f * arm::q_to_float(inlet_d2, 27)));
#elif attr_Ctrl == 2
int32_t dd2 = (int32_t)df2;
df2 = (MAXDD / (1.0f + 7.0f * arm::q_to_float(inlet_d2, 27)));
if (dd2 < MINDD)
  dd2 = MINDD;
#else
int32_t dd2 = (int32_t)df2;
df2 = (MAXDD / (1.0f + 15.0f * arm::q_to_float(inlet_d2, 27)));
if (dd2 < MINDD)
  dd2 = MINDD;
#endif
dd2 = (dd2 - d2) >> 4;
for (int smp = 0; smp < BUFSIZE; smp++) {
  d2 += dd2;                                 // interpolation
  fd2 = ___SMMLA(0x10000000, d2 - fd2, fd2); // smooth
  outlet_out2[smp] = interp(i, fd2);
  i -= 2;
  i &= LENGTHMASK;
}
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
i = ind;
#if attr_Ctrl == 0
int32_t dd3 = inlet_d3;
if (dd3 < MINDD)
  dd3 = MINDD;
else if (dd3 > MAXDD)
  dd3 = MAXDD;
#elif attr_Ctrl == 1
int32_t dd3 = (int32_t)df3;
df3 = (MAXDD / (1.0f + 3.0f * arm::q_to_float(inlet_d3, 27)));
if (dd3 < MINDD)
  dd3 = MINDD;
#elif attr_Ctrl == 2
int32_t dd3 = (int32_t)df3;
df3 = (MAXDD / (1.0f + 7.0f * arm::q_to_float(inlet_d3, 27)));
#else
int32_t dd3 = (int32_t)df3;
df3 = (MAXDD / (1.0f + 15.0f * arm::q_to_float(inlet_d3, 27)));
if (dd3 < MINDD)
  dd3 = MINDD;
#endif
dd3 = (dd3 - d3) >> 4;
for (int smp = 0; smp < BUFSIZE; smp++) {
  d3 += dd3;                                 // interpolation
  fd3 = ___SMMLA(0x10000000, d3 - fd3, fd3); // smooth
  outlet_out3[smp] = interp(i, fd3);
  i -= 2;
  i &= LENGTHMASK;
}

Privacy

© 2024 Zrna Research