{
   "description" : "An '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.",
   "ancestor_list" : [],
   "author" : "axl99",
   "name" : "XL Kaos Looper",
   "is_private" : null,
   "id" : "1-QL",
   "code" : "(\r\nSynthDef('kaoslooper', {arg in=0, out=0, buf, gate=1, t_rec=0, t_reset=1, t_chop=0, plvl=1, switch=0,\r\n\tfrombeat=0, grainsize=1, numbeats=4, numsubcycles=4, amp=1.0, wet=0.5;\r\n\tvar dry, loopgate, time, grainlength, grainframes, subcycles, cycles, grains, trigcounter,\r\n\tgrainstart, grainend, rlvl, xfade, playenv, prelevelenv, env, player, phase, grainer, fx;\r\n\r\n\t// controls loopgate and rlvl\r\n\ttrigcounter = PulseCount.kr(t_rec, t_reset);\r\n\t// for the fader and for loopbuf as a trigger\r\n\txfade = Lag.kr(switch.linlin(0, 1, -1, 1), 0.1);\r\n\r\n\t// audio input.\r\n\tdry = SoundIn.ar(in ! 2, 2);\r\n\r\n\t// loopgate is opened when closing the loop and reset by t_reset\r\n\tloopgate = trigcounter > 1;\r\n\tplayenv = EnvGen.kr(Env.asr(0.05, 1.0, 0.05), loopgate);\r\n\tenv = EnvGen.kr(Env.asr(0.04, 1, 0.04), gate, doneAction:2);\r\n\tprelevelenv = 1 - EnvGen.kr(Env.asr(0.1, 1, 0.1), t_chop);\r\n\r\n\t// controls writing into buffer\r\n\trlvl = EnvGen.kr(Env.asr(0.05, 1.0, 0.05), trigcounter % 2);\r\n\r\n\t// outputs the length of the loop. reset by loopgate (which becomes one on first rec trig and is 1 until reset)\r\n\ttime = Latch.kr(Timer.kr(t_rec), loopgate);\r\n\t// length of smallest subdivision (default 16) of loop length\r\n\tgrainlength = time / (numbeats * numsubcycles);\r\n\tgrainframes = (grainlength * SampleRate.ir).round(1);\r\n\r\n\t// make new grain starts and lengths derived from grainsize and frombeat\r\n\tgrainstart = grainframes * frombeat * numsubcycles;\r\n\tgrainend = grainstart + (grainframes * grainsize);\r\n\r\n\t// triggers on every subcycle\r\n\tsubcycles = TDuty.kr(grainlength, loopgate, 1) * loopgate;\r\n\t// triggers at each loop cycle beginning + extra trigger at start of first recording\r\n\tcycles = Trig.kr(PulseCount.kr(subcycles, t_reset) % (numbeats * numsubcycles), 0.01) + Trig.kr(trigcounter, 0.01);\r\n\t// triggers on every grain (subcycles retriggers?!)\r\n\tgrains = TDuty.kr(grainlength * grainsize, switch, 1);\r\n\r\n\t// players and recorder\r\n\tplayer = PlayBuf.ar(2, buf, BufRateScale.kr(buf), cycles, loop:1);\r\n\t//grainer is a BufRd triggered by grains\r\n\tphase = Phasor.ar(grains, 1, grainstart, grainend, grainstart);\r\n\tgrainer = BufRd.ar(2, buf, phase);\r\n\tRecordBuf.ar(dry <! player, buf, recLevel: rlvl, preLevel:plvl, loop:1, trigger: cycles);\r\n\tfx = LinXFade2.ar(player, grainer, xfade, playenv);\r\n\t// output fader between player and grainer\r\n\tOut.ar(out, XFade2.ar(dry, fx, wet * 2 - 1 ) * env * amp);\r\n}).add;\r\n)\r\n\r\n// allocate buffer. Your loops should be shorter than the buffer\r\nb = Buffer.alloc(s, s.sampleRate * 16, 2)\r\n\r\n// start synth\r\nl = Synth('kaoslooper', ['in', 0, 'buf', b])\r\n\r\n// start recording first loop\r\nl.set(\\t_rec, 1)\r\n// stop recording, start looping\r\nl.set(\\t_rec, 1)\r\n\r\n// switch to stutter thingy\r\nl.set(\\switch, 1)\r\n\r\n// default is 4 beats with 4 subcycles each\r\n\r\n// start from beat 1\r\nl.set(\\frombeat, 1)\r\n\r\n// go back to beat 0\r\nl.set(\\frombeat, 1)\r\n\r\n// change number of repeated subcycles\r\nl.set(\\grainsize, 2)\r\n\r\n// switch back to regular loop\r\nl.set(\\switch, 0)\r\n\r\n// overdub\r\nl.set(\\t_trig, 1)\r\n\r\n// stop overdubbing\r\nl.set(\\t_trig, 1)\r\n\r\n// reset if you want to record a new loop\r\nl.set(\\t_reset, 1)\r\nb.zero\r\n\r\n\r\n//The End, clean up\r\nl.release \r\nb.free",
   "labels" : [
      "looper",
      "live looping",
      "kaoss pad"
   ]
}
