( // Load buffers Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/crawling-stems/lead.wav", channels:[0], bufnum: 0); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/crawling-stems/perc mel solo.wav", channels:[0], bufnum: 1); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/crawling-stems/bass.wav", channels:[0], bufnum: 2); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/crawling-stems/drums.wav", channels:[0], bufnum: 3); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/crawling-stems/break.wav", channels:[0], bufnum: 4); ) ( // Granulator Ndef(\granulator, { |bufnum=0, tFreq=20, overlap=2, rate=1, posStart=0.0, tFreqMF=0, tFreqMD=0, rateMF=0, rateMD=0, posRateMF=0, posRateMD=0, granDur=4| var samplePhasor, phasor, gran, env, bufrd; var bufFrames = BufFrames.ir(bufnum); var t; var tFreqMod = SinOsc.ar(tFreqMF, Rand(0.0, 2pi)) * tFreqMD; var rateMod = SinOsc.ar(rateMF, Rand(0.0, 2pi)) * rateMD; var posRateMod = SinOsc.ar(posRateMF, Rand(0.0, 2pi)) * posRateMD; var playTrig = Impulse.ar(\playTrFr.kr(0.5)); tFreq = tFreq + tFreqMod.dup; rate = rate + rateMod.dup; t = Impulse.ar(tFreq); samplePhasor = EnvGen.ar(Env([0, 0, bufFrames], [0, bufFrames / SampleRate.ir], curve: 0), gate: playTrig); phasor = EnvGen.ar(Env([posStart, posStart, 1], [0, granDur], curve: 0), gate: playTrig); bufrd = BufRd.ar(1, bufnum, samplePhasor, interpolation: 4); bufrd = LeakDC.ar(bufrd); gran = GrainBufJ.ar( numChannels: 1, trigger: t, dur: tFreq.reciprocal * overlap, sndbuf: bufnum, rate: rate, pos: phasor + posRateMod.dup, interp: 2, pan: 0, envbufnum: -1, maxGrains: 512, loop: 0 ) * EnvGen.ar(Env.perc(0.001, granDur * \grainGate.kr(1), curve: \granCurve.kr(-4)), gate: playTrig); Mix([ bufrd * \dry.kr(1.0), gran * \wet.kr(0.5) ]) }); Ndef(\granulator).addSpec( \overlap, [0.001, 40, \exp], \rate, [-2, 2], \posStart, [0.0, 1.0], \tFreq, \widefreq, \tFreqMF, [0.0,80], \tFreqMD, [0.0,20], \rateMF, [0.0,80], \rateMD, [0.0,2], \posRateMF, [0.0,80], \posRateMD, [0.0,2], \dry, [0.0,1], \wet, [0.0,1], \playTrFr, [0.0,1], \granDur, [0.0,8], \granCurve, [-10,10], \grainGate, [0,1], \bufnum, [0, 4, \lin, 1] ).edit; ) ( // MIDI Mappings for Channel 2 (MIDI channels are zero-indexed) MIDIdef.cc(\gran_bufnum, { |val, num, chan| if(chan == 1, { Ndef(\granulator).set(\bufnum, val.linlin(0,127,0,4).round(1)) }); }, ccnum: 1); MIDIdef.cc(\gran_posStart, { |val, num, chan| if(chan == 1, { Ndef(\granulator).set(\posStart, val.linlin(0,127,0,1)) }); }, ccnum: 2); MIDIdef.cc(\gran_tf, { |val, num, chan| if(chan == 1, { Ndef(\granulator).set(1\tFreq, val.linexp(0,127,0.1,100)) }); }, ccnum: 3); MIDIdef.cc(\gran_overlap, { |val, num, chan| if(chan == 1, { Ndef(\granulator).set(\overlap, val.linexp(0,127,0.01,20)) }); }, ccnum: 4); MIDIdef.cc(\gran_rate, { |val, num, chan| if(chan == 1, { Ndef(\granulator).set(\rate, val.linlin(0,127,-2,2)) }); }, ccnum: 5); MIDIdef.cc(\gran_posRateMD, { |val, num, chan| if(chan == 1, { Ndef(\granulator).set(\posRateMD, val.linlin(0,127,0,2)) }); }, ccnum: 6); MIDIdef.cc(\gran_dry, { |val, num, chan| if(chan == 1, { Ndef(\granulator).set(\dry, val.linlin(0,127,0,1)) }); }, ccnum: 7); MIDIdef.cc(\gran_wet, { |val, num, chan| if(chan == 1, { Ndef(\granulator).set(\wet, val.linlin(0,127,0,1)) }); }, ccnum: 8); )