/* algoforte #3 (220105b) code for first track of "algoforte01" - a two-tracker release on my bandcamp: https://music.lukaprincic.si or https://bandcamp.com/lukaprincic track 2 is a live performance of most the ideas in here with some changes that seem to be necessary for live coding performance. :/ to use this code you need to be able to send midi out to either virtual instrument that plays a grand piano (a sampler or similar). i personally used Salamander Grand Piano SFZ loaded into Renoise. you can also use disklavier if you have one handy nearby. by starting MIDIClient.init (and waiting for a second or two) and then m=MIDIOut(0) a midi output/input is created for SC. the midi out from SC must go into midi input of the sampler/piano, use test Pbindef to test. midichannel on sampler/piano: 1 (in SC: 0) route audio output from piano back to SC and disconnect it from main output (speakers). this is easily done using JACK. requirement for this patch is also DEINDUGens which include JPverb */ // helpers: s.boot s.meter s.plotTree // init midi MIDIClient.init(1,1); // create output on channel 1 m = MIDIOut(0) // connect. m.connect // test Pbindef(\testmidi, \type, \midi, \midicmd, \noteOn, \midiout, m, \chan, 0, \amp, 0.5).play Pbindef(\testmidi).stop // processing input from piano ( Ndef(\inDSPout, { var snd, flt, rev, dly; snd = SoundIn.ar([0,1]); snd = snd * LFPulse.kr(LFNoise1.kr(1/5).range(3,20), 0, 0.5).range(LFNoise1.kr(1/10).range(0.6,1),1).lag(0.00001); flt = BPF.ar(snd, LFNoise1.kr([1/4,1/5]).exprange(500,5000), 0.3, 2); // ?? dly = CombL.ar(flt + snd, 1, SinOsc.ar([1/60, 1/70]).range(1, 1.2), 10, 0.3 * LFNoise1.kr(1/10).range(0.4,1) , snd); rev = JPverb.ar(flt + snd, 6, 0, 20) * LFNoise1.kr(1/10).range(0.4,1); snd = snd + dly + rev * 0.8; Limiter.ar(snd, 0.8); }) ) Ndef(\inDSPout).fadeTime = 4 Ndef(\inDSPout).play(fadeTime:5) // when needed: Ndef(\inDSPout).end(30) Ndef(\inDSPout).stop ( Pbindef(\p220105b, \type, \midi, \midicmd, \noteOn, \midiout, m, \chan, 0, \dur, Pseq([ Pn(1/2, 50), Pseq([1, 1/2, Pn(1/4,4), 2], 20), // 7*20 Pseq([ 1, 1/2, Pn(1/4, 2), Prand([2, 1/2, Pn(1/3,3)]), Pwrand([1/2, Pn(1/8,4)], [0.9, 0.1]), Pwrand([1/2, 6,], [0.9, 0.1]), ], 10 * 5 ), Pn(1/2, 60) ]) * Pwhite(0.99,1.2), \amp, Pseq([0.6, Pwhite(0.2,0.5,3), 0.5, Pwhite(0.2,0.5,2)], inf) * Pwhite(1, 1.1), \degree, Place([0, 0, 2, 0, [2, 3, 5]],inf), // cycle of 5 \scale, Scale.minor, \mtranspose, Pseq([ 0, 5, 7, [2,5], [3,6], [0,2] [0,5,7], [0,5,9], [3,5,7,10], [2,5,9,11], [0,4,7,11] + 7, [5,4,7,11], [0,4,-7] ],inf) + Pseq([ Pn(0, 50 + (7*20)), Pseq([Pn(0,50), Pn(3,20), Pn(-2,20)], 3)], inf), // (50+140+(3x90)) \ctranspose, Pseq([ Pn(0, 50+140), Pseq([Pn(0,60), Pn(5, 60), Pn(0,60), Pn(7,60)]), // (4*60+50+140) Pn(0,inf) // ]) + Pseq([ Pn(0,300), Pwrand([0, 5, 7], [0.9, 0.05, 0.05], 100), Pn(0, inf)]), \octave, Pwrand([5,[5,6],[4,6]], [0.8,0.1,0.1], inf), \legato, Pwhite(0.5,4) ).play ) // allocate new buffer b = Buffer.alloc(s, s.sampleRate*10, 1) // start recording into buffer via 'in' Ndef(\recbuf, {var sn=\in.ar(0!2); RecordBuf.ar(sn[0], b)}) // plug output from inDSPout to in of \recbuf Ndef(\recbuf) <<>.in Ndef(\inDSPout) // is there something being recorded in a buffer? b.plot // when needed - stop recording to a buffer Ndef(\recbuf).clear // GRANULATE THE CONTENTS OF THE BUFFER ( Ndef(\gran, { var snd = GrainBuf.ar(2, trigger: Impulse.ar(LFNoise1.kr(1/10!3).exprange(1, 80) * LFNoise0.ar(100).range(0.7,1.1)), dur: LFNoise1.ar(1).range(0.08,0.1), sndbuf: b, rate:[1,1/2,2], pos:LFNoise1.kr(1/20!3).range(0,1), pan: LFNoise0.ar(100).range(-1,1) ); snd = LPF.ar(snd, LFNoise1.kr(1/10!3).exprange(500,10000)); snd = Mix(snd); snd = JPverb.ar(snd, LFNoise1.kr(1/10!2).range(1,10)) + snd; Limiter.ar(Mix(snd), 0.8) * Env.circle([0.01,0.3,0.01],90,\cub).kr * 0.5; }) ) Ndef(\gran).fadeTime = 5 Ndef(\gran).play Ndef(\gran).end(30) // fadeout Ndef(\gran).stop // stop immediately (send note offs)