Skip to content

Commit

Permalink
protosynth: add superspreader
Browse files Browse the repository at this point in the history
  • Loading branch information
JoepVanlier committed Sep 15, 2024
1 parent ebf5c54 commit 9078441
Show file tree
Hide file tree
Showing 2 changed files with 381 additions and 15 deletions.
292 changes: 292 additions & 0 deletions protosynth/protosynth_dependencies/saike_proto_synth_spreader.jsfx-inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
@init
function calc_smooth_coeff(cutoff)
instance()
global(srate)
local(g)
(
g = tan($pi * cutoff / srate);
g /(1 + g)
);

function smooth(target)
global(smooth_coeff)
local(y, v)
instance(s)
(
v = smooth_coeff * (target - s);
y = v + s;
s = y + v;
y
);

function init_butter2(f0)
global(srate)
local(g)
instance(
<?k = 1; loop(2, printf("k_%d, a1_%d, a2_%d, a3_%d, ", k, k, k, k); k += 1);?>
)
(
g = tan($pi * f0 / srate);

k_1 = 1.84775906552; // 1 / Q
k_2 = 0.76536684415;

<?
k = 1;
loop(2,
printf("a1_%d = 1 / (1 + g * (g + k_%d));", k, k);
printf("a2_%d = g * a1_%d;", k, k);
printf("a3_%d = g * a2_%d;", k, k);
k += 1;
);
?>
);

function eval_butter2(v0)
global()
local(v1, v2, v3)
instance(
<?k = 1; loop(2, printf("ic1eq_%d, ic2eq_%d, k_%d, a1_%d, a2_%d, a3_%d, ", k, k, k, k, k, k); k += 1);?>
)
(
<?
k = 1;
loop(2,
printf("v3 = v0 - ic2eq_%d;", k);
printf("v1 = a1_%d * ic1eq_%d + a2_%d * v3;", k, k, k);
printf("v2 = ic2eq_%d + a2_%d * ic1eq_%d + a3_%d * v3;", k, k, k, k);
printf("ic1eq_%d = v1 + v1 - ic1eq_%d;", k, k);
printf("ic2eq_%d = v2 + v2 - ic2eq_%d;", k, k);
printf("v0 = v0 - k_%d * v1 - v2;", k);

k += 1;
);
?>
);


function eval_butter2_2(v0)
global()
local(v1, v2, v3)
instance(
<?k = 1; loop(2, printf("ic3eq_%d, ic4eq_%d, k_%d, a1_%d, a2_%d, a3_%d, ", k, k, k, k, k, k); k += 1);?>
)
(
<?
k = 1;
loop(2,
printf("v3 = v0 - ic4eq_%d;", k);
printf("v1 = a1_%d * ic3eq_%d + a2_%d * v3;", k, k, k);
printf("v2 = ic4eq_%d + a2_%d * ic3eq_%d + a3_%d * v3;", k, k, k, k);
printf("ic3eq_%d = v1 + v1 - ic3eq_%d;", k, k);
printf("ic4eq_%d = v2 + v2 - ic4eq_%d;", k, k);
printf("v0 = v0 - k_%d * v1 - v2;", k);

k += 1;
);
?>
);

function _init_spreader_buffer(freemem, in_buffer_size, window_in)
instance(buf, p0, p2, buffer_size, half_buffer, window)
global()
local()
(
buffer_size = in_buffer_size;
half_buffer = in_buffer_size / 2;
window = window_in;
p0 = 0;
p2 = floor(rand() * (buffer_size - 1));
buf = freemem;

buf + buffer_size
);

function spreader_update_parameters(spread_slider, mix)
local(detune_fade, detuned_gain, spread)
global()
instance(
<?i=0; loop(12, printf("shifter%d, ", i); i += 1;)?>
dry_gain, total_gain, spread_gain,
)
(
// Wrangle input parameters
detune_fade = min(10.0 * spread_slider, 1.0);
detuned_gain = (mix >= 100.0) ? 1.0 : 0.01 * mix;
dry_gain = (mix <= 100.0) ? 1.0 : (detune_fade < 1.0) ? max(0.5 * (1.0 - detune_fade), (200.0 - mix) / 100.0) : (200.0 - mix) / 100.0;
spread_gain = detuned_gain * detune_fade;
total_gain = (spread_gain == 0.0) ? 1.0 : (1.41 / (1.0 + 2.4494897427831780981972840747059 * spread_gain));
spread = 0.5 * spread_slider * spread_slider;

// Set individual pitch shifter pitches
shifter0.out_delta = pow(0.893, spread);
shifter1.out_delta = pow(0.939, spread);
shifter2.out_delta = pow(0.98, spread);
shifter3.out_delta = pow(1.02, spread);
shifter4.out_delta = pow(1.064, spread);
shifter5.out_delta = pow(1.11, spread);

shifter6.out_delta = pow(1.0 / 0.893, spread);
shifter7.out_delta = pow(1.0 / 0.939, spread);
shifter8.out_delta = pow(1.0 / 0.98, spread);
shifter9.out_delta = pow(1.0 / 1.02, spread);
shifter10.out_delta = pow(1.0 / 1.064, spread);
shifter11.out_delta = pow(1.0 / 1.11, spread);
);

function _spreadshifter_tick(data)
instance(buf, p0, p2)
global()
local(p1i, p1f, p2i, x3, x3a, x3b, x4, x4a, x4b, fade34)
instance(out_delta, test, buffer_size, half_buffer, window)
(
p0 -= 1;
(p0 < 0) ? ( p0 += buffer_size; );
buf[p0] = data;

p2 -= out_delta;
(p2 < 0) ? ( p2 += buffer_size; );

p1i = floor(p2);
p1f = p2 - p1i;
x3a = buf[p1i];

p1i += 1;
(p1i >= buffer_size) ? ( p1i -= buffer_size; );

x3b = buf[p1i];
x3 = x3a + p1f * (x3b - x3a);

p2i = (p1i + half_buffer);
(p2i >= buffer_size) ? ( p2i -= buffer_size; );
x4a = buf[p2i];

p2i += 1;
(p2i >= buffer_size) ? ( p2i -= buffer_size; );

x4b = buf[p2i];
x4 = x4a + p1f * (x4b - x4a);

p2i = (p1i - p0);
(p2i < 0) ? ( p2i += buffer_size; );

fade34 = window[p2i];

x4 + fade34 * (x3 - x4)
);

function init_follower(atk, release)
local()
instance(at, rt, LPF)
global(srate)
(
at = ( atk > 0 ) ? exp(-1.0/(.0005 * atk * srate)) : 0;
rt = exp(-1.0/(.0005 * release * srate));
);

function eval_follower(x)
local()
instance(state, at, rt, x)
global()
(
x > state ? (
state = at * state + ( 1.0 - at ) * x;
) : (
state = rt * state + ( 1.0 - rt ) * x;
);

state
);

function spreader_tick(inL, inR, reconstruct_envelope, reset_env)
global()
local(delayed_in, total_out, avg, side)
instance(
window,
buffer_size, half_buffer,
delayL, delayR, delay_ix, read_ix, read_ix2, outL, outR,
<?i=0; loop(12, printf("shifter%d, ", i); i += 1;)?>
dry_gain, total_gain, spread_gain,
env_follower, env_follower2, env_correction, follower_state, zero_time, smooth_total_gain, smooth_total_gain.smooth,
filt,
)
(
// Delay the main signal
delayL[delay_ix] = inL;
delayR[delay_ix] = inR;
delay_ix += 1;
(delay_ix >= buffer_size) ? delay_ix -= buffer_size;
read_ix = delay_ix - half_buffer;
(read_ix < 0) ? ( read_ix += buffer_size; );

// Process the chorus
outL = outR = 0;
<?i = 0; loop(6, printf("outL += shifter%d._spreadshifter_tick(inL);", i); i += 1; );?>
<?i = 6; loop(6, printf("outR += shifter%d._spreadshifter_tick(inR);", i); i += 1; );?>

(reconstruct_envelope == 1) ? (
read_ix2 = read_ix - 1;
(read_ix2 < 0) ? ( read_ix2 += buffer_size; );
delayed_in = max(abs(delayL[read_ix] - delayL[read_ix2]), abs(delayR[read_ix] - delayR[read_ix2]));
total_out = follower_state * max(abs(outL), abs(outR));
follower_state = env_follower2.eval_follower(env_follower.eval_follower((total_out + delayed_in) > 0.001) > 0.2);
env_correction = follower_state;
) : (reconstruct_envelope == 2) ? (
reset_env ? (
zero_time = 1024;
);
(zero_time > 0) ? (
env_correction = window[zero_time];
zero_time -= 1;
) : (
env_correction += 0.01 * (1.0 - env_correction);
);
) : (
env_correction = 1;
);

smooth_total_gain = smooth_total_gain.smooth(total_gain);

outL = filt.eval_butter2(outL);
outR = filt.eval_butter2_2(outR);

outL = (dry_gain * delayL[read_ix] + outL * spread_gain * env_correction) * smooth_total_gain;
outR = (dry_gain * delayR[read_ix] + outR * spread_gain * env_correction) * smooth_total_gain;
);

function init_spreader(freemem, _buffer_size)
local(i)
global()
instance(
<?i=0; loop(12, printf("shifter%d, ", i); i += 1;)?>
delayL, delayR, buffer_size, half_buffer, delay_ix, window, env_follower, env_follower2,
)
(
buffer_size = _buffer_size;
half_buffer = _buffer_size / 2;
freemem = (window = freemem) + buffer_size;
i = 0;
loop(buffer_size,
window[i] = 0.5 - 0.5 * cos(2.0 * $PI * i / buffer_size);
i += 1;
);

freemem = (delayL = freemem) + buffer_size;
freemem = (delayR = freemem) + buffer_size;

delay_ix = 0;

<?
i = 0;
loop(12,
printf("freemem = shifter%d._init_spreader_buffer(freemem, buffer_size, window);", i);
i += 1;
);
?>

env_follower.init_follower(0, 50);
env_follower2.init_follower(1, 50);

freemem
);

Loading

0 comments on commit 9078441

Please sign in to comment.