waveshaper 16p

Wavetable type waveshaper distortion. Uses pre integration as an attempt to reduce antialiasing.
Author: Sputnki
License: BSD
Github: sptnk/effect/waveshaper 16p.axo

Inlets

frac32buffer input signal

frac32buffer 16 coefficient buffer, these represent the shape of a curve in several points

frac32 amount of feedback

Outlets

frac32buffer out

Parameters

frac32.s.map feedback

Attributes

spinner number of individual waveshaper units chained together

Declaration
typedef struct {
  int32_t q[17]; // actual coefficients
  int32_t Q[17]; // integral values
} waveshaper_coefs;
// the positive semiperiod of the wave is subdivided in 16 segments. I want to
// do pre integration, hoping to have a mild antialiasing

typedef struct {
  int32_t x_old; // old x value
  int32_t Y_old; // old integrated value
} waveshaper_state;

int32_t integrate_segment(int32_t dx, int32_t yi, int32_t yi_1) {
  int32_t dy = yi - yi_1;
  int32_t dx_sq = ___SMMUL(dx << 2, dx << 3);
  return ___SMMUL(yi_1 << 2, dx << 3) + (___SMMUL(dx_sq << 2, dy << 3) << 3);
}

int32_t integrate_fullseg(int32_t yi, int32_t yi_1) { return yi_1 + yi >> 5; }

void waveshaper_setcoefs(waveshaper_coefs *coefs, waveshaper_state *state,
                         int32_t *ybuf) {
  (coefs->Q[0]) = 0;
  (coefs->q[0]) = 0;
  for (int i = 1; i < 17; i++) {
    (coefs->q[i]) = ybuf[i - 1];
    (coefs->Q[i]) =
        (coefs->Q[i - 1]) + integrate_fullseg((coefs->q[i]), (coefs->q[i - 1]));
  }

  int32_t x = (state->x_old);
  int32_t x_abs = x > 0 ? x : -x;
  int32_t i = (x_abs >> 23);
  int32_t z = x_abs & 0x7FFFFF;

  int32_t q_i = coefs->q[i + 1];
  int32_t q_i_1 = coefs->q[i];
  int32_t Q_i_1 = coefs->Q[i];

  int32_t Y = Q_i_1 + integrate_segment(z, q_i, q_i_1);
  state->Y_old = Y;
}

int32_t waveshaper_process(waveshaper_coefs *coefs, waveshaper_state *state,
                           int32_t input) {
  int32_t x = __SSAT(input, 28);
  int32_t x_sign = x > 0 ? 1 : -1;
  int32_t x_abs = x * x_sign;
  int32_t i = (x_abs >> 23);
  int32_t z = x_abs & 0x7FFFFF;

  int32_t q_i = coefs->q[i + 1];
  int32_t q_i_1 = coefs->q[i];
  int32_t Q_i_1 = coefs->Q[i];

  int32_t y = ___SMMLA(q_i - q_i_1 << 2, z << 7, q_i_1) * x_sign;
  int32_t Y = Q_i_1 + integrate_segment(z, q_i, q_i_1);

  int32_t dx = x - (state->x_old);
  int32_t dx_abs = dx > 0 ? dx : -dx;

  int32_t dY = Y - (state->Y_old);

  int32_t dY_dx = 134217728.0f * ((float)dY) / ((float)dx);

  state->x_old = x;
  state->Y_old = Y;

  return (dx_abs > (1 << 10)) ? dY_dx : y;
}

int32_t out = 0;

int32_t buffer[attr_chain + 1];

waveshaper_coefs wsc[attr_chain];
waveshaper_state wss[attr_chain];
Control Rate
int i;

int32_t coefs[BUFSIZE];
for (i = 0; i < BUFSIZE; i++) {
  coefs[i] = inlet_coefs[i];
}

for (int i = 0; i < attr_chain; i++)
  waveshaper_setcoefs(&wsc[i], &wss[i], coefs);

int32_t feed = __SSAT(inlet_feed + param_feed, 28);
Audio Rate
buffer[0] = inlet_in + ___SMMUL(feed << 2, buffer[attr_chain] << 3);
for (int i = 0; i < attr_chain; i++)
  buffer[i + 1] = waveshaper_process(&wsc[i], &wss[i], buffer[i]);
outlet_out = buffer[attr_chain];

Privacy

© 2024 Zrna Research