«XL Kaos Looper» by axl99
on 29 Nov'11 22:32 inAn 'all-in-one' live looping synth with the ability to switch between the regular loop player and one that loops smaller fractions of the loop. Inspired by the Korg Kaoss Pad looper.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
(
SynthDef('kaoslooper', {arg in=0, out=0, buf, gate=1, t_rec=0, t_reset=1, t_chop=0, plvl=1, switch=0,
frombeat=0, grainsize=1, numbeats=4, numsubcycles=4, amp=1.0, wet=0.5;
var dry, loopgate, time, grainlength, grainframes, subcycles, cycles, grains, trigcounter,
grainstart, grainend, rlvl, xfade, playenv, prelevelenv, env, player, phase, grainer, fx;
// controls loopgate and rlvl
trigcounter = PulseCount.kr(t_rec, t_reset);
// for the fader and for loopbuf as a trigger
xfade = Lag.kr(switch.linlin(0, 1, -1, 1), 0.1);
// audio input.
dry = SoundIn.ar(in ! 2, 2);
// loopgate is opened when closing the loop and reset by t_reset
loopgate = trigcounter > 1;
playenv = EnvGen.kr(Env.asr(0.05, 1.0, 0.05), loopgate);
env = EnvGen.kr(Env.asr(0.04, 1, 0.04), gate, doneAction:2);
prelevelenv = 1 - EnvGen.kr(Env.asr(0.1, 1, 0.1), t_chop);
// controls writing into buffer
rlvl = EnvGen.kr(Env.asr(0.05, 1.0, 0.05), trigcounter % 2);
// outputs the length of the loop. reset by loopgate (which becomes one on first rec trig and is 1 until reset)
time = Latch.kr(Timer.kr(t_rec), loopgate);
// length of smallest subdivision (default 16) of loop length
grainlength = time / (numbeats * numsubcycles);
grainframes = (grainlength * SampleRate.ir).round(1);
// make new grain starts and lengths derived from grainsize and frombeat
grainstart = grainframes * frombeat * numsubcycles;
grainend = grainstart + (grainframes * grainsize);
// triggers on every subcycle
subcycles = TDuty.kr(grainlength, loopgate, 1) * loopgate;
// triggers at each loop cycle beginning + extra trigger at start of first recording
cycles = Trig.kr(PulseCount.kr(subcycles, t_reset) % (numbeats * numsubcycles), 0.01) + Trig.kr(trigcounter, 0.01);
// triggers on every grain (subcycles retriggers?!)
grains = TDuty.kr(grainlength * grainsize, switch, 1);
// players and recorder
player = PlayBuf.ar(2, buf, BufRateScale.kr(buf), cycles, loop:1);
//grainer is a BufRd triggered by grains
phase = Phasor.ar(grains, 1, grainstart, grainend, grainstart);
grainer = BufRd.ar(2, buf, phase);
RecordBuf.ar(dry <! player, buf, recLevel: rlvl, preLevel:plvl, loop:1, trigger: cycles);
fx = LinXFade2.ar(player, grainer, xfade, playenv);
// output fader between player and grainer
Out.ar(out, XFade2.ar(dry, fx, wet * 2 - 1 ) * env * amp);
}).add;
)
// allocate buffer. Your loops should be shorter than the buffer
b = Buffer.alloc(s, s.sampleRate * 16, 2)
// start synth
l = Synth('kaoslooper', ['in', 0, 'buf', b])
// start recording first loop
l.set(\t_rec, 1)
// stop recording, start looping
l.set(\t_rec, 1)
// switch to stutter thingy
l.set(\switch, 1)
// default is 4 beats with 4 subcycles each
// start from beat 1
l.set(\frombeat, 1)
// go back to beat 0
l.set(\frombeat, 1)
// change number of repeated subcycles
l.set(\grainsize, 2)
// switch back to regular loop
l.set(\switch, 0)
// overdub
l.set(\t_trig, 1)
// stop overdubbing
l.set(\t_trig, 1)
// reset if you want to record a new loop
l.set(\t_reset, 1)
b.zero
//The End, clean up
l.release
b.free
reception
edit 2019: fixed bugs and made a SynthDef out of it.
This is great, thanks, but… it always overdubs? l.set(\t_trig, 1) does not do anything, there is no argument called t_trig?