IO Variants: 2
Variant: 1
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
frac32buffer.bipolar Mix output
combo wordsize
spinner maxdelay
spinner maxstages
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;
for (int i = 0; i < PHASER32B_DELAY_SIZE * PHASER32B_SECTIONS; i++) {
delay_line[i] = 0;
}
dpos = 0;
delay_size = 1;
old_out = 0;
// 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
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
frac32buffer.bipolar Mix output
frac32.bipolar LFO output
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
spinner maxdelay
spinner maxstages
combo wordsize
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);
};
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;
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;
// 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;
}