grainer

granulizer effect. continuously buffers audio and plays it back both forward and backwards at the same time "freeze" stops the recording to the buffer, causing to repeat the sample over and over. "size" sets the grain size "rate" sets the grain rate "reverse" reverses play direction (gated: high is reverse) when "jump" goes high, the "change" value will be added to the play offset, smoothed out by the "speed" parameter (higher value is faster response) "wet" and "dry" control the mix of original and grained audio. delaylength output is used to connect to my "clock2timing" module. This way the "size" of the delay can be synced to host tempo. Use ratiomaxVCA to set ratio to host tempo.
Author: Remco van der Most
License: BSD
Github: sss/fx/grainer.axo

Inlets

frac32.bipolar rate

frac32buffer wave input

bool32 freeze

bool32 reverse

bool32 jump

frac32 size

frac32 change

frac32 speed

frac32 wet

frac32 dry

Outlets

frac32buffer out

int32 delaylength

Parameters

frac32.u.map size

frac32.u.map speed

frac32.s.map.pitch rate

frac32.s.map change

frac32.s.map wet

frac32.s.map dry

Attributes

combo size

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);
int32_t *array;
uint32_t writepos;
uint32_t phase;
int32_t size;
int32_t count;
int32_t can;
int ttrig;
Init
static int32_t _array[attr_poly][1 << attr_size]
    __attribute__((section(".sdram")));
array = &_array[parent->polyIndex][0];
int i;
writepos = 0;
for (i = 0; i < LENGTH; i++)
  array[i] = 0;
Control Rate
int32_t freq;
MTOFEXTENDED(param_rate + inlet_rate, freq)
freq = inlet_reverse > 0 ? freq : -freq;
size = param_size + inlet_size;
outlet_delaylength = attr_size;
int32_t speed = __USAT(param_speed + inlet_speed, 27);
speed = ___SMMUL(speed << 3, speed << 2);
speed = ___SMMUL(speed << 3, speed << 2);
Audio Rate
phase += freq >> 8;
// phase+=(1<<31)/12000;
uint32_t pos = phase >> 5;
// count=pos+(freq>>11)>(1<<27)?count+(param_walk<<5):count;
if ((inlet_jump > 0) && !ttrig) {
  count += (param_change + inlet_change) << 3;
  ttrig = 1;
} else if (!(inlet_jump > 0)) {
  ttrig = 0;
}
can = can + ___SMMUL((count - can) << 3, speed << 2);
pos = pos + can & ((1 << 27) - 1);

if (!(inlet_freeze > 0)) {
  writepos = (writepos + 1) & LENGTHMASK;
  array[writepos] = __SSAT(inlet_in << 1, 32);
}

uint32_t tmp_d = __USAT(___SMMUL(pos << 3, size << 2), 27);
uint32_t tmp_di = writepos - (tmp_d >> (27 - LENGTHPOW));
uint32_t tmp_w1 = (tmp_d << (LENGTHPOW + 3)) & 0x3FFFFFFF;
uint32_t tmp_w2 = (1 << 30) - tmp_w1;
int32_t tmp_a1 = array[tmp_di & LENGTHMASK];
int32_t tmp_a2 = array[(tmp_di + 1) & LENGTHMASK];
int32_t tmp_ra = ___SMMUL(tmp_a1, tmp_w1);
tmp_ra = ___SMMLA(tmp_a2, tmp_w2, tmp_ra);

tmp_d = __USAT(___SMMUL(((1 << 27) - pos) << 3, size << 2), 27);
tmp_di = writepos - (tmp_d >> (27 - LENGTHPOW));
tmp_w1 = (tmp_d << (LENGTHPOW + 3)) & 0x3FFFFFFF;
tmp_w2 = (1 << 30) - tmp_w1;
tmp_a1 = array[tmp_di & LENGTHMASK];
tmp_a2 = array[(tmp_di + 1) & LENGTHMASK];
int32_t tmp_rb = ___SMMUL(tmp_a1, tmp_w1);
tmp_rb = ___SMMLA(tmp_a2, tmp_w2, tmp_rb);

outlet_out = ___SMMUL((tmp_ra + tmp_rb) << 2, (param_wet + inlet_wet) << 3) +
             ___SMMUL(inlet_in << 3, (param_dry + inlet_dry) << 2);

Privacy

© 2024 Zrna Research