I’m working on a new live electronics project. Without going into too much unnecessary detail, I’d like to record into a buffer and process it live. I’ve copied the initial idea from this video.
Because I’m keen to do a lot of different time-stretching, reverse etc. of the buffer, and because I’d like to have different phrases running through different synths, I’ve worked out I need a number of buffers. At the moment I’m working with 5, so that one buffer is recording while the other four are being used.
The question I’m confronted with now is how to have multiple synths running, each playing a different buffer, but then free each synth before the buffer it’s playing is overwritten to avoid weird artefacts, clicking etc. I figure this should all be part of the same Routine - something like this:
~synths = Array.new(5);
(
Tdef(\bufferAlternate, {
loop {
5.do {
|i|
// free the running Synth
~synths[i].set(\gate, 0);
// record to buffer
~recordBuffers.set(\buf, ~bufs[i]);
~bufLength.wait;
// trigger the synth when the buffer is finished recording
synths = synths.add(Synth(\granular, [buf: i]));
};
1.wait;
}
}).play;
)
Here’s the full code I’m working with - I don’t know if it’s super relevant, but in case it’s helpful. Granular synth based pretty closely on an Alik Rustamoff video.
(
~numBufs = 5;
~bufLength = 15;
~bufs = ~numBufs.collect { |i| Buffer.alloc(s, s.sampleRate * ~bufLength, bufnum: i) };
~micBus = Bus.audio(s, 1);
~pointerBus = Bus.audio(s, 1);
SynthDef(\mic, {
var sig = SoundIn.ar(\in.kr(0) * \amp.kr(0.dbamp));
// var sig = In.ar(\in.kr(0));
Out.ar(\out.kr(0), sig);
}).add;
SynthDef(\pointer, {
arg buf = 0;
var sig = Phasor.ar(0, BufRateScale.kr(buf), 0, BufFrames.kr(buf));
Out.ar(\out.kr(0), sig);
}).add;
SynthDef(\rec, {
var pointer = In.ar(\pointerIn.kr(0), 1);
var sig = In.ar(\micIn.kr(0), 1);
BufWr.ar(sig, \buf.kr(0), pointer);
}).add;
SynthDef(\granular, {
arg tRate = 20, rate = 1, posRate = 1, tRateMF = 0, tRateMD = 0, rateMF = 0, rateMD = 0, posRateMF = 0, posRateMD = 0;
var buf = \buf.kr(0, 0.5);
var trig = Impulse.ar(tRate.lag(0.05));
var bufFrames = BufFrames.ir(buf);
var tRateMod = { SinOsc.ar(tRateMF, Rand(0.0, 2pi)) * tRateMD};
var rateMod = { SinOsc.ar(rateMF, Rand(0.0, 2pi)) * rateMD};
var posRateMod = { SinOsc.ar(posRateMF, Rand(0.0, 2pi)) * posRateMD};
var phasor, sig, env;
tRate = tRate + tRateMod.dup;
posRate = posRate + posRateMod.dup;
rate = rate + rateMod.dup;
phasor = Phasor.ar(
trig: 0.0,
rate: posRate * BufRateScale.kr(buf),
start: \startPos.kr(0.0, 0.5),
end: \endPos.kr(1.0) * bufFrames
);
sig = GrainBuf.ar(
numChannels: 1,
trigger: trig,
dur: tRate.reciprocal * \overlap.kr(2, 2),
sndbuf: buf,
rate: rate,
pos: phasor / bufFrames,
interp: 2,
pan: 0,
envbufnum: -1,
maxGrains: 512
);
sig = sig * \amp.kr(-0.dbamp);
Out.ar(\out.kr(0), sig);
}).add;
Tdef(\bufferAlternate, {
loop {
5.do {
|i|
~recordBuffers.set(\buf, ~bufs[i]);
~bufLength.wait;
};
1.wait;
}
});
Tdef(\synthBufAlternate, {
loop {
5.do {
|i|
var buf = (i+1);
~synth.set(
\buf, ~bufs[buf],
\rate, [1, 0.5, 2, 0.25, 1.5, 0.75].choose,
\posRate, rrand(0.25, 5) * [-1, 1].choose,
\tRateMF, rrand(0.0, 5.0),
\tRateMD, rrand(0.0, 5.0),
\overlap, rrand(0.02, 20),
\startPos, rrand(0, 1),
\endPos, rrand(0, 1)
);
~bufLength * ~numBufs.wait;
};
1.wait;
}
});
)
// process: record buffer, trigger synth. Before recording over buffer, free the synth.
// final routine
(
Routine({
~micGroup = Group.new;
~pointerGroup = Group.after(~micGroup);
~recGroup = Group.after(~pointerGroup);
~granGroup = Group.after(~recGroup);
Synth(\mic, [in: 0, out: ~micBus], ~micGroup);
Synth(\pointer, [buf: ~bufs[0], out: ~pointerBus], ~pointerGroup);
~recordBuffers = Synth(\rec, [pointerIn: ~pointerBus, micIn: ~micBus, buf: ~bufs[0]], ~recGroup);
Tdef(\bufferAlternate).play;
~bufLength.wait;
~synth = Synth(\granular, [bufs: ~bufs[0]]);
~bufLength.wait;
Tdef(\synthBufAlternate).play;
}).play;
)
I’m super grateful for any help.
Cheers,
Jordan