waveshaper 16p f

Wavetable type waveshaper distortion. Uses pre integration as an attempt to reduce antialiasing. Every waveshaper input is lowpassed (6db)
Author: Sputnki
License: BSD
Github: sptnk/effect/waveshaper 16p f.axo

Inlets

frac32buffer input signal

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

frac32 amount of feedback

frac32 filter cutoff pitch

frac32 "rule" for cutoff pitch in chained units

Outlets

frac32buffer out

Parameters

frac32.s.map feedback

frac32.s.map "rule" for cutoff pitch in chained units

frac32.s.map.pitch filter cutoff pitch

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;
}

typedef struct {
  int32_t f = 0;
  int32_t val = 0;
} filter_state;

void filter_setpitch(filter_state *state, int32_t pitch) {
  MTOF(pitch, state->f);
}

int32_t lowpass_process(filter_state *state, int32_t input) {
  state->val = ___SMMLA((input - (state->val)) << 1, state->f, state->val);
  return (state->val);
}

filter_state lps[attr_chain - 1];

int32_t out = 0;

int32_t buffer[attr_chain + 1];

waveshaper_coefs wsc[attr_chain];
waveshaper_state wss[attr_chain];
Init
for (int i = 0; i < attr_chain; i++)
  filter_setpitch(&lps[i], 1 << 27);
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);
  filter_setpitch(&lps[i],
                  inlet_pitch + param_pitch + (i * (param_chain / attr_chain)));
}

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], lowpass_process(&lps[i], buffer[i]));
outlet_out = buffer[attr_chain];

Privacy

© 2024 Zrna Research