phaser_32

Phaser, 0 to 32 stages, external control
Author: Are Leistad
License: BSD
Github: drj/fx/phaser.axo

IO Variants: 2


Variant: 1

Inlets

frac32.positive Dry/wet mix

int32.positive Stage delay in sample periods

int32.positive Number of stages, 0 = bypass

frac32buffer.bipolar Input

frac32buffer.bipolar Modulation

frac32.bipolar Feedback amount

bool32 Use soft saturation in the feedback loop

Outlets

frac32buffer.bipolar Mix output

Attributes

combo wordsize

spinner maxdelay

spinner maxstages

Declaration
attr_wordsize
#define PHASER32B_DELAY_SIZE attr_maxdelay
#define PHASER32B_SECTIONS attr_maxstages
#define PHASER32B_32_FB_SAT

#ifdef PHASER32B_32_BIT
    int32_t delay_line[PHASER32B_DELAY_SIZE * PHASER32B_SECTIONS];
#else
    int16_t delay_line[PHASER32B_DELAY_SIZE * PHASER32B_SECTIONS];
#endif

int32_t old_out;
int32_t dpos;
int32_t delay_size;
Init
for (int i = 0; i < PHASER32B_DELAY_SIZE * PHASER32B_SECTIONS; i++) {
  delay_line[i] = 0;
}
dpos = 0;
delay_size = 1;
old_out = 0;
Audio Rate
// Delay bounds
delay_size = inlet_delay;
if (delay_size > PHASER32B_DELAY_SIZE) {
  delay_size = PHASER32B_DELAY_SIZE;
} else if (delay_size < 1) {
  delay_size = 1;
}

int32_t stages = inlet_stages;
if (stages < 0) {
  stages = 0;
} else if (stages > PHASER32B_SECTIONS) {
  stages = PHASER32B_SECTIONS;
}

#ifdef PHASER32B_32_FB_SAT
// soft saturation distortion: y=1.5*x-0.5*x^3
if (inlet_saturate) {
  // int32_t ts      = __SSAT(old_out,28);
  int32_t tsq31 = old_out << 3;
  int32_t tsq31p3 = ___SMMUL(tsq31, ___SMMUL(tsq31, tsq31));
  old_out = old_out + (old_out >> 1) - (tsq31p3);
}
#endif

// Input
int32_t dout, din, allpass;

allpass = ___SMMLA(inlet_feedback << 3, old_out << 2, inlet_in);
allpass = __SSAT(allpass, 30);

// 16 or 32 bit filters
#ifdef PHASER32B_32_BIT
int32_t g2 = inlet_mod;
g2 = __SSAT(g2 << 2, 31);
int32_t *dptr = delay_line + dpos;
#else
int32_t g2 = inlet_mod;
g2 = __SSAT(g2 << 3, 31);
int16_t *dptr = delay_line + dpos;
#endif

for (int i = 0; i < stages; ++i) {
#ifdef PHASER32B_32_BIT
  dout = *dptr;
  din = ___SMMLA(g2, dout << 2, allpass);
  din = __SSAT(din, 30);
  *dptr = din;
  allpass = ___SMMLS(g2, din << 2, dout);
  dptr += PHASER32B_DELAY_SIZE;
#else
  dout = *dptr << 16;
  din = ___SMMLA(g2, dout, allpass >> 1);
  din = __SSAT(din, 30);
  *dptr = din >> 15;
  allpass = ___SMMLS(g2, din << 1, dout >> 1) << 1;
  dptr += PHASER32B_DELAY_SIZE;
#endif
}

allpass = __SSAT(allpass, 28);
int32_t wet = ___SMMUL(inlet_mix << 3, allpass << 2);
outlet_out = ___SMMLA(((1 << 27) - inlet_mix) << 3, inlet_in << 2, wet);
old_out = allpass;

if (++dpos >= delay_size) {
  dpos = 0;
}

Variant: 2

Inlets

bool32.rising Reset LFO phase

int32.positive Stage delay in sample periods, added to delay param

int32.positive Number of stages, added to stages param

frac32buffer.bipolar Input

frac32buffer.bipolar Modulation

Outlets

frac32buffer.bipolar Mix output

frac32.bipolar LFO output

Parameters

frac32.u.map.ratio LFO square pulse width

int32 1-5 = tri, sine, saw+, saw-, square

int32 Stage delay in sample perdiods

int32 Number of stages

bool32.tgl Use soft saturation in the feedback loop

frac32.u.map Dry/wet mix

frac32.s.map Manual frequency

frac32.s.map Feedback gain

frac32.u.map.squaregain LFO amount

frac32.s.map.lfopitch LFO frequency

Attributes

spinner maxdelay

spinner maxstages

combo wordsize

Declaration
attr_wordsize
#define PHASER32_DELAY_SIZE attr_maxdelay
#define PHASER32_SECTIONS attr_maxstages
#define PHASER32_32_FB_SAT

#ifdef PHASER32_32_BIT
    int32_t delay_line[PHASER32_DELAY_SIZE * PHASER32_SECTIONS];
#else
    int16_t delay_line[PHASER32_DELAY_SIZE * PHASER32_SECTIONS];
#endif

int32_t old_out;
int32_t dpos;
uint32_t phase;
uint32_t old_reset;
int32_t lfo_out;
int32_t lfo_out_interp;
int32_t _prev;
int32_t _step;
int32_t _i;

__attribute__((always_inline)) __STATIC_INLINE int32_t ___ABS(int32_t op1) {
  int32_t result;
  __ASM volatile("movs  %0, %1\n"
                 "it    mi\n"
                 "rsbmi %0, %0, #0"
                 : "=r"(result)
                 : "r"(op1));
  return (result);
};
Init
for (int i = 0; i < PHASER32_DELAY_SIZE * PHASER32_SECTIONS; i++) {
  delay_line[i] = 0;
}
dpos = 0;
phase = 0;
old_reset = 0;
old_out = 0;
Control Rate
if (inlet_reset && !old_reset) {
  phase = 0;
} else {
  int32_t freq;
  MTOFEXTENDED(param_lfofreq, freq);
  phase += freq >> 2;
}
old_reset = inlet_reset;

switch (param_lfowave) {
case 1:
  // Triangle
  lfo_out = (phase >> 4) - (1 << 27);
  lfo_out = (1 << 27) - ___ABS(lfo_out << 1);
  break;

case 2:
  // Sine
  SINE2TINTERP(phase, lfo_out)
  lfo_out = (lfo_out >> 4);
  break;

case 3:
  // Saw rising
  lfo_out = (phase >> 4) - (1 << 27);
  break;

case 4:
  // Saw falling
  lfo_out = -((phase >> 4) - (1 << 27));
  break;

case 5:
  // Square
  if ((phase >> 5) > param_lfopw) {
    lfo_out = -(1 << 27);
  } else {
    lfo_out = (1 << 27) - 1;
  }
  break;
}

outlet_lfo = lfo_out;
// lfo_out = ___SMMUL( param_lfoamt<<3, lfo_out<<2 );
lfo_out = ___SMMUL(param_lfoamt, lfo_out << 2);
_step = (lfo_out - _prev) >> 4;
_i = _prev;
_prev = lfo_out;
Audio Rate
// LFO smoothing
lfo_out_interp = _i;
_i += _step;

// Delay bounds
int32_t delay_size = param_delay + inlet_delay;
if (delay_size > PHASER32_DELAY_SIZE) {
  delay_size = PHASER32_DELAY_SIZE;
} else if (delay_size < 1) {
  delay_size = 1;
}

int32_t stages = param_stages + inlet_stages;
if (stages < 0) {
  stages = 0;
} else if (stages > PHASER32_SECTIONS) {
  stages = PHASER32_SECTIONS;
}

#ifdef PHASER32_32_FB_SAT
// soft saturation distortion: y=1.5*x-0.5*x^3
if (param_saturate) {
  int32_t tsq31 = old_out << 3;
  int32_t tsq31p3 = ___SMMUL(tsq31, ___SMMUL(tsq31, tsq31));
  old_out = old_out + (old_out >> 1) - (tsq31p3);
}
#endif

// Input
int32_t dout, din, allpass;

allpass = ___SMMLA(param_feedback << 3, old_out << 2, inlet_in);
allpass = __SSAT(allpass, 30);

// 16 or 32 bit filters
#ifdef PHASER32_32_BIT
int32_t g2 = inlet_mod + lfo_out_interp - param_manual;
g2 = __SSAT(g2 << 2, 31);
int32_t *dptr = delay_line + dpos;
#else
int32_t g2 = inlet_mod + lfo_out_interp - param_manual;
g2 = __SSAT(g2 << 3, 31);
int16_t *dptr = delay_line + dpos;
#endif

for (int i = 0; i < stages; ++i) {
#ifdef PHASER32_32_BIT
  dout = *dptr;
  din = ___SMMLA(g2, dout << 2, allpass);
  din = __SSAT(din, 30);
  *dptr = din;
  allpass = ___SMMLS(g2, din << 2, dout);
  dptr += PHASER32_DELAY_SIZE;
#else
  dout = *dptr << 16;
  din = ___SMMLA(g2, dout, allpass >> 1);
  din = __SSAT(din, 30);
  *dptr = din >> 15;
  allpass = ___SMMLS(g2, din << 1, dout >> 1) << 1;
  dptr += PHASER32_DELAY_SIZE;
#endif
}

allpass = __SSAT(allpass, 28);
int32_t wet = ___SMMUL(param_mix << 3, allpass << 2);
outlet_out = ___SMMLA(((1 << 27) - param_mix) << 3, inlet_in << 2, wet);
old_out = allpass;

if (++dpos >= delay_size) {
  dpos = 0;
}

Privacy

© 2024 Zrna Research