Created
September 6, 2019 11:16
-
-
Save antonhornquist/b3f0de19fecbeb873745df4023108a07 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
( | |
var nvoices = 7; | |
var pg; | |
var effect; | |
var buffers; | |
var voices; | |
var mixBus; | |
var phases; | |
var levels; | |
var seek_tasks; | |
// disk read | |
var readBuf = { arg i, path; | |
if(buffers[i].notNil, { | |
if (File.exists(path), { | |
// TODO: load stereo files and duplicate GrainBuf for stereo granulation | |
var newbuf = Buffer.readChannel(s, path, 0, -1, [0], { | |
voices[i].set(\buf, newbuf); | |
buffers[i].free; | |
buffers[i] = newbuf; | |
}); | |
}); | |
}); | |
}; | |
var alloc = { | |
buffers = Array.fill(nvoices, { arg i; | |
Buffer.alloc( | |
s, | |
s.sampleRate * 1, | |
); | |
}); | |
SynthDef(\synth, { | |
arg out, phase_out, level_out, buf, | |
gate=0, pos=0, speed=1, jitter=0, | |
size=0.1, density=20, pitch=1, spread=0, gain=1, envscale=1, | |
freeze=0, t_reset_pos=0; | |
var grain_trig; | |
var jitter_sig; | |
var buf_dur; | |
var pan_sig; | |
var buf_pos; | |
var pos_sig; | |
var sig; | |
var env; | |
var level; | |
grain_trig = Impulse.kr(density); | |
buf_dur = BufDur.kr(buf); | |
pan_sig = TRand.kr(trig: grain_trig, | |
lo: spread.neg, | |
hi: spread); | |
jitter_sig = TRand.kr(trig: grain_trig, | |
lo: buf_dur.reciprocal.neg * jitter, | |
hi: buf_dur.reciprocal * jitter); | |
buf_pos = Phasor.kr(trig: t_reset_pos, | |
rate: buf_dur.reciprocal / ControlRate.ir * speed, | |
resetPos: pos); | |
pos_sig = Wrap.kr(Select.kr(freeze, [buf_pos, pos])); | |
sig = GrainBuf.ar(2, grain_trig, size, buf, pitch, pos_sig + jitter_sig, 2, pan_sig); | |
env = EnvGen.kr(Env.asr(1, 1, 1), gate: gate, timeScale: envscale); | |
level = env; | |
Out.ar(out, sig * level * gain); | |
Out.kr(phase_out, pos_sig); | |
// ignore gain for level out | |
Out.kr(level_out, level); | |
}).add; | |
SynthDef(\effect, { | |
arg in, out, mix=0.5, room=0.5, damp=0.5; | |
var sig = In.ar(in, 2); | |
sig = FreeVerb.ar(sig, mix, room, damp); | |
Out.ar(out, sig); | |
}).add; | |
s.sync; | |
// mix bus for all synth outputs | |
mixBus = Bus.audio(s, 2); | |
effect = Synth.new(\effect, [\in, mixBus.index, \out, 0]); | |
phases = Array.fill(nvoices, { arg i; Bus.control(context.server); }); | |
levels = Array.fill(nvoices, { arg i; Bus.control(context.server); }); | |
pg = ParGroup.before(effect); | |
voices = Array.fill(nvoices, { arg i; | |
Synth.new(\synth, [ | |
\out, mixBus.index, | |
\phase_out, phases[i].index, | |
\level_out, levels[i].index, | |
\buf, buffers[i], | |
], target: pg); | |
}); | |
s.sync; | |
NornsCmddef('reverb_mix', "f", { arg value; effect.set(\mix, value); }); | |
NornsCmddef('reverb_room', "f", { arg value; effect.set(\room, value); }); | |
NornsCmddef('reverb_damp', "f", { arg value; effect.set(\damp, value); }); | |
NornsCmddef('read', "is", { arg voice, path; readBuf.value(voice - 1, path); }); | |
NornsCmddef('seek', "if", { arg argVoice, argPos; | |
var voice = argVoice - 1; | |
var lvl, pos; | |
var seek_rate = 1 / 750; | |
seek_tasks[voice].stop; | |
// TODO: async get | |
lvl = levels[voice].getSynchronous(); | |
if (false, { // disable seeking until fully implemented | |
var step; | |
var target_pos; | |
// TODO: async get | |
pos = phases[voice].getSynchronous(); | |
voices[voice].set(\freeze, 1); | |
target_pos = argPos; | |
step = (target_pos - pos) * seek_rate; | |
seek_tasks[voice] = Routine { | |
while({ abs(target_pos - pos) > abs(step) }, { | |
pos = pos + step; | |
voices[voice].set(\pos, pos); | |
seek_rate.wait; | |
}); | |
voices[voice].set(\pos, target_pos); | |
voices[voice].set(\freeze, 0); | |
voices[voice].set(\t_reset_pos, 1); | |
}; | |
seek_tasks[voice].play(); | |
}, { | |
pos = argPos; | |
voices[voice].set(\pos, pos); | |
voices[voice].set(\t_reset_pos, 1); | |
voices[voice].set(\freeze, 0); | |
}); | |
}); | |
NornsCmddef('gate', "ii", { arg argVoice, gate; | |
var voice = argVoice - 1; | |
voices[voice].set(\gate, msg[2]); | |
}); | |
NornsCmddef('speed', "if", { arg argVoice, speed; | |
var voice = argVoice - 1; | |
voices[voice].set(\speed, speed); | |
}); | |
NornsCmddef('jitter', "if", { arg argVoice, jitter; | |
var voice = argVoice - 1; | |
voices[voice].set(\jitter, jitter); | |
}); | |
NornsCmddef('jitter', "if", { arg argVoice, jitter; | |
var voice = argVoice - 1; | |
voices[voice].set(\jitter, jitter); | |
}); | |
NornsCmddef('size', "if", { arg argVoice, size; | |
var voice = argVoice - 1; | |
voices[voice].set(\size, size); | |
}); | |
NornsCmddef('density', "if", { arg argVoice, density; | |
var voice = argVoice - 1; | |
voices[voice].set(\density, density); | |
}); | |
NornsCmddef('pitch', "if", { arg argVoice, pitch; | |
var voice = argVoice - 1; | |
voices[voice].set(\pitch, pitch); | |
}); | |
NornsCmddef('spread', "if", { arg argVoice, spread; | |
var voice = argVoice - 1; | |
voices[voice].set(\spread, spread); | |
}); | |
NornsCmddef('volume', "if", { arg argVoice, volume; | |
var voice = argVoice - 1; | |
voices[voice].set(\volume, volume); | |
}); | |
NornsCmddef('envscale', "if", { arg argVoice, envscale; | |
var voice = argVoice - 1; | |
voices[voice].set(\envscale, envscale); | |
}); | |
nvoices.do({ arg i; | |
NornsPolldef( | |
"phase_" ++ (i+1), | |
{ | |
var val = phases[i].getSynchronous; | |
val | |
} | |
); | |
NornsPolldef( | |
"level_" ++ (i+1), | |
{ | |
var val = levels[i].getSynchronous; | |
val | |
} | |
); | |
}); | |
seek_tasks = Array.fill(nvoices, { arg i; | |
Routine {} | |
}); | |
}; | |
var free = { | |
voices.do({ arg voice; voice.free; }); | |
phases.do({ arg bus; bus.free; }); | |
levels.do({ arg bus; bus.free; }); | |
buffers.do({ arg b; b.free; }); | |
effect.free; | |
mixBus.free; | |
}; | |
[alloc, free]; | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment