over1tap

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

Inlets

frac32buffer wave input

frac32 d1

Outlets

frac32buffer out1

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;
float x0, x1, x2, x3, x4, x5, y0, y1;
float df1;
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 = x = y = 0;
x0 = x1 = x2 = x3 = x4 = x5 = y0 = y1 = 0;

df1 = 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(0x20000000, d1 - fd1, fd1); // smooth
  outlet_out1[smp] = interp(i, fd1);
  i -= 2;
  i &= LENGTHMASK;
}

Privacy

© 2024 Zrna Research