MIDIClient.init; MIDIIn.connectAll; ( // b = Buffer.read(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/trax/01-Acheinu_Kol_Beit_Israel.wav"); b = Buffer.readChannel(s, "/home/lcoogan/snd/ardour/hebrewian_rue/export/hebrewian_rue_r1_lead.wav", channels:[0], bufnum: 0); b = Buffer.readChannel(s, "/home/lcoogan/snd/ardour/hebrewian_rue/export/hebrewian_rue_r1_harm.wav", channels:[0], bufnum: 1); ) ( Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/crawling-stems/lead.const.wav", channels:[0], bufnum: 0); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/crawling-stems/perc mel solo.const.wav", channels:[0], bufnum: 1); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/crawling-stems/bass.const.wav", channels:[0], bufnum: 2); ) ( Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/trax/01-Cantor_Samual_Malavsky_Shomea_Kol_Bichios.wav", channels:[0], bufnum: 0); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/trax/02-Cantor_Mordechai_Hershman_Baruch_Hashem_Bayom.wav", channels:[0], bufnum: 1); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/trax/03-Acheinu_Kol_Beit_Israel.wav", channels:[0], bufnum: 2); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/trax/04-Cantor_Samuel_Malavsky_Zechor.wav", channels:[0], bufnum: 3); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/trax/05-Cantor_Zavel_Kwartin_Ribono_Shel_Olam.wav", channels:[0], bufnum: 4); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/trax/06-Cantor_Zevulun_Zavel_Kwartin_sings_Tiher.wav", channels:[0], bufnum: 5); Buffer.readChannel(s, "/home/lcoogan/snd/live/2025-04-26.Basic_City_Brewery/trax/07-Izak_Algazi_Efendi_Kamti_Be_ashmoret.wav", channels:0, bufnum: 6); ) ( SynthDef(\granulator_compressor, { |bufnum, tFreq=20, overlap=2, rate=1, tFreqMF=0, tFreqMD=0, rateMF=0, rateMD=0, posRateMD=0, posRateMF=0, granDur=4| var dry, gran, env, bufFrames, tFreqMod, rateMod, posRateMod, playTrig; var t, samplePhasor, phasor, bufrd; var in, e, o, r, c, bias, lookahead, kneelag, drywet, compressed; var attack = \attack.kr(0.01); var release = \release.kr(0.1); // === GRANULATOR SECTION === bufFrames = BufFrames.ir(bufnum); tFreqMod = SinOsc.ar(tFreqMF, Rand(0.0, 2pi)) * tFreqMD; rateMod = SinOsc.ar(rateMF, Rand(0.0, 2pi)) * rateMD; posRateMod = SinOsc.ar(posRateMF, Rand(0.0, 2pi)) * posRateMD; 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([0, 0, 1], [0, granDur], curve: 0), gate: playTrig); bufrd = BufRd.ar( numChannels: 1, bufnum: bufnum, phase: 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); dry = bufrd * \dry.kr(1.0) + gran * \wet.kr(0.5); // summed dry + wet dry = LeakDC.ar(dry); // === COMPRESSOR SECTION === in = dry * \trim.kr(0).dbamp; // input to compressor e = in.mean; e = HPF.ar(e, \hpf.kr(50)); e = EnvDetect.ar(e, attack, release); o = e.ampdb.excess(\threshold.kr(-6)); r = \ratio.kr(4); c = (max(o, 0.0)) * (r.reciprocal - 1); kneelag = attack * \knee.kr(0.0); c = c.lag(kneelag); c = c.dbamp; lookahead = \lookahead.kr(0); in = DelayC.ar(in, 0.5, lookahead.lag(0.4)); compressed = in * c; compressed = compressed * \gain.kr(0).dbamp; bias = K2A.ar(\bias.kr(0.0)); compressed = Select.ar(\saturate.kr(1), [compressed, (compressed + bias).softclip - bias]); compressed = LeakDC.ar(compressed); drywet = \dry_wet.kr(1); compressed = Mix([ compressed * drywet, DelayC.ar(dry * (1 - drywet), 0.5, lookahead.lag(0.4)) ]); Out.ar(0, compressed); }).add; ) ( x = Synth(\granulator_compressor, [\bufnum, b]); y = Synth(\granulator_compressor2, [\bufnum, b]); ) x.free; ( var paramMap = ( 0: [\wet, 0, 1], 1: [\bufnum, 0, 4], 2: [\rate, -2, 2], 3: [\posRate, 0, 4], 4: [\tFreq, 0, 80], 5: [\tFreqMF, 0, 80], 6: [\tFreqMD, 0, 20], 7: [\rateMF, 0, 80], 8: [\rateMD, 0, 2], 9: [\posRateMF, 0, 80], 10: [\posRateMD, 0, 2], 11: [\playTrFr, 0, 1], 12: [\granDur, 0, 8], 13: [\granCurve, -10, 10], 14: [\grainGate, 0, 1], 15: [\overlap, 0.001, 40, \exp], 16: [\attack, 0.0000001, 0.1, \exp], 17: [\release, 0.0000001, 0.4, \exp], 18: [\threshold, -120, 0], // flipped key/value to array 19: [\trim, 0, 60], 20: [\gain, -40, 40], 21: [\ratio, 1, 20, \exp], 22: [\dry_wet, 0, 1], 23: [\hpf, 10, 1000], // fixed missing bracket 24: [\knee, 0.0, 10], // fixed missing bracket 25: [\lookahead, 0.0, 1], // fixed missing bracket 26: [\saturate, \switch], // you may want to define how to handle \switch 27: [\bias, 0.0, 1.0] ); MIDIIn.control = { |src, chan, num, val| if (chan == 2) { var mapping = paramMap[num]; if (mapping.notNil) { var param = mapping[0]; var min = mapping[1]; var max = mapping[2]; var scaleType = mapping[3] ?? \lin; // default to lin if not specified var mappedVal = (scaleType == \exp) .if { val.linexp(0, 127, min, max) } { val.linlin(0, 127, min, max) }; x.set(param, mappedVal); ("Setting " ++ param ++ " to " ++ mappedVal).postln; }; }; }; ) ( SynthDef(\granulator_compressor2, { |bufnum, tFreq=20, overlap=2, rate=1, tFreqMF=0, tFreqMD=0, rateMF=0, rateMD=0, posRateMD=0, posRateMF=0, granDur=4| var dry, gran, env, bufFrames, tFreqMod, rateMod, posRateMod, playTrig; var t, samplePhasor, phasor, bufrd; var in, e, o, r, c, bias, lookahead, kneelag, drywet, compressed; var attack = \attack.kr(0.01); var release = \release.kr(0.1); // === GRANULATOR SECTION === bufFrames = BufFrames.ir(bufnum); tFreqMod = SinOsc.ar(tFreqMF, Rand(0.0, 2pi)) * tFreqMD; rateMod = SinOsc.ar(rateMF, Rand(0.0, 2pi)) * rateMD; posRateMod = SinOsc.ar(posRateMF, Rand(0.0, 2pi)) * posRateMD; 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([0, 0, 1], [0, granDur], curve: 0), gate: playTrig); bufrd = BufRd.ar( numChannels: 1, bufnum: bufnum, phase: 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); dry = bufrd * \dry.kr(1.0) + gran * \wet.kr(0.5); // summed dry + wet dry = LeakDC.ar(dry); // === COMPRESSOR SECTION === in = dry * \trim.kr(0).dbamp; // input to compressor e = in.mean; e = HPF.ar(e, \hpf.kr(50)); e = EnvDetect.ar(e, attack, release); o = e.ampdb.excess(\threshold.kr(-6)); r = \ratio.kr(4); c = (max(o, 0.0)) * (r.reciprocal - 1); kneelag = attack * \knee.kr(0.0); c = c.lag(kneelag); c = c.dbamp; lookahead = \lookahead.kr(0); in = DelayC.ar(in, 0.5, lookahead.lag(0.4)); compressed = in * c; compressed = compressed * \gain.kr(0).dbamp; bias = K2A.ar(\bias.kr(0.0)); compressed = Select.ar(\saturate.kr(1), [compressed, (compressed + bias).softclip - bias]); compressed = LeakDC.ar(compressed); drywet = \dry_wet.kr(1); compressed = Mix([ compressed * drywet, DelayC.ar(dry * (1 - drywet), 0.5, lookahead.lag(0.4)) ]); Out.ar(0, compressed); }).add; ) ( var paramMap = ( 0: [\wet, 0, 1], 1: [\bufnum, 0, 4], 2: [\rate, -2, 2], 3: [\posRate, 0, 4], 4: [\tFreq, 0, 80], 5: [\tFreqMF, 0, 80], 6: [\tFreqMD, 0, 20], 7: [\rateMF, 0, 80], 8: [\rateMD, 0, 2], 9: [\posRateMF, 0, 80], 10: [\posRateMD, 0, 2], 11: [\playTrFr, 0, 1], 12: [\granDur, 0, 8], 13: [\granCurve, -10, 10], 14: [\grainGate, 0, 1], 15: [\overlap, 0.001, 40, \exp], 16: [\attack, 0.0000001, 0.1, \exp], 17: [\release, 0.0000001, 0.4, \exp], 18: [\threshold, -120, 0], // flipped key/value to array 19: [\trim, 0, 60], 20: [\gain, -40, 40], 21: [\ratio, 1, 20, \exp], 22: [\dry_wet, 0, 1], 23: [\hpf, 10, 1000], // fixed missing bracket 24: [\knee, 0.0, 10], // fixed missing bracket 25: [\lookahead, 0.0, 1], // fixed missing bracket 26: [\saturate, \switch], // you may want to define how to handle \switch 27: [\bias, 0.0, 1.0] ); MIDIIn.control = { |src, chan, num, val| if (chan == 3) { var mapping = paramMap[num]; if (mapping.notNil) { var param = mapping[0]; var min = mapping[1]; var max = mapping[2]; var scaleType = mapping[3] ?? \lin; // default to lin if not specified var mappedVal = (scaleType == \exp) .if { val.linexp(0, 127, min, max) } { val.linlin(0, 127, min, max) }; y.set(param, mappedVal); ("Setting " ++ param ++ " to " ++ mappedVal).postln; }; }; }; )