// title: sync looper // author: ovo // description: // synchronized loop // code: /* _______SYNC_LOOPER__________ */ ( s.waitForBoot{ SynthDef(\syncPhs, {|sync=8, buf, rate=1, t_start=0, t_rec=0, t_stop=0| var phs, dur; dur = Timer.kr(t_rec+t_stop); phs = Phasor.ar(t_start, BufRateScale.kr(buf)*rate,0, BufFrames.kr(buf)); SendReply.kr(t_stop, '/loopStopRec', dur); OffsetOut.ar(sync,phs); }).send(s); SynthDef(\syncPlay, {|out=0, sync=8, buf, rate=1, amp=1, stop, atk=0.003, rel=100| var snd, phs, env, gate; phs = In.ar(sync); gate = A2K.kr(phs) < (BufSamples.kr(buf)-(BufSampleRate.ir(buf)/rel)); gate = gate-stop; env = EnvGen.kr(Env.asr(atk,1,rel.reciprocal), gate); snd = BufRd.ar(1, buf, phs, 1); snd = snd*env; OffsetOut.ar(out,snd*amp); }).send(s); SynthDef(\syncRec, {|sync=8, buf, in=0| var snd, phs, input; input = SoundIn.ar(in); // input = In.ar(in); phs = In.ar(sync); snd = BufWr.ar(input, buf, phs, 0); }).send(s); SynthDef(\send, { |in=0,out=0,amp=1| var son; son = In.ar(in); OffsetOut.ar(out,son*amp); }).send(s); ~loop = (); ~gLoop = Group.new(s); s.sync; ~gLoopPlay = Group.new(~gLoop, 'addAfter').run(false); s.sync; ~loop.put(\sync, Bus.audio(s, 1)); ~loop.put(\bus, Bus.audio(s, 1)); ~loop.put(\buffer, Buffer.alloc(s, s.sampleRate * 60, 1)); // max record : 60 sec ~loop.put(\bufs, List.newClear); ~loop.put(\plays, List.newClear); ~loop.put(\bpm, 0); s.sync; ~loop.put(\phasor, Synth(\syncPhs, [\buf, ~loop.buffer, \sync, ~loop.sync], ~gLoop, 'addToHead')); ~loop.put(\rec, Synth(\syncRec, [\buf, ~loop.buffer, \sync, ~loop.sync, \in, 0], ~gLoop, 'addToTail').run(false)); ~loop.put(\out, Synth(\send, [\in, ~loop.bus, \out, 0], ~gLoopPlay, 'addToTail')); s.sync; NodeWatcher.register(~loop.rec); NodeWatcher.register(~gLoopPlay); Fdef(\loopRec, { if( ~loop.bufs.size == 0, { ~loop.phasor.set(\t_start, 1, \rate, 1, \t_rec, 1) }); ~loop.rec.run; "LOOP REC".postln; }); Fdef(\loopStopRec, {|dur| var i; ~loop.rec.run(false); if(~loop.bufs.size==0, { ~loop.bufs.add(Buffer.alloc(s, dur)); ~loop.phasor.set(\buf, ~loop.bufs[0]); Fdef(\loopBPM).value; },{ ~loop.bufs.add(Buffer.alloc(s, ~loop.bufs[0].numFrames))} ); i = ~loop.bufs.size-1; ~loop.buffer.copyData(~loop.bufs[i]); ~loop.buffer.zero; "LOOP REC STOP".postln; }); Fdef(\loopPlay, { var i = ~loop.bufs.size-1; ~gLoopPlay.run; ~loop.plays.add(Synth(\syncPlay, [\buf, ~loop.bufs[i], \sync, ~loop.sync, \out, ~loop.bus], ~loop.out, 'addBefore')); }); Tdef(\loopStopPlay, { if( ~gLoopPlay.isRunning, { ~gLoopPlay.set(\stop, 1); 0.01.wait; ~gLoopPlay.run(false); "LOOP STOP".postln; },{ ~gLoopPlay.run.set(\atk, 0.01, \stop, 0); ~loop.phasor.set(\t_start, 1, \rate, 1); // restart phasor "LOOP PLAY".postln; }); }).stop; Fdef(\loopUndo, { var x = ~loop.bufs.size-1; ~loop.rec.run(false); ~loop.plays[x].set(\stop, 1); ~loop.bufs[x].free; ~loop.bufs.removeAt(x); ~loop.plays[x].free; ~loop.plays.removeAt(x); if(~loop.bufs.size == 0, { ~loop.phasor.set(\buf, ~loop.buffer); }); "LOOP UNDO".postln; }); Fdef(\loopClear,{ ~loop.bufs.do{|x| x.free }; ~loop.bufs.clear; ~loop.plays.do{|x| x.free }; ~loop.plays.clear; ~loop.phasor.set(\buf, ~loop.buffer); ~loop.rec.run(false); "LOOP CLEAR".postln; }); Fdef(\loopBPM, {|beats=4, bars=4| var bpm; bpm = 60/((~loop.bufs[0].numFrames/s.sampleRate)/(beats*bars)); ~loop.bpm = bpm; "LOOP BPM : ".post; bpm.postln; }); Fdef(\loopFree, { ~gLoop.freeAll; ~gLoop.free; ~gLoopPlay.freeAll; ~gLoopPlay.free; ~loop.buffer.free; ~loop.bufs.do{|x| x.free}; ~loop.sync.free; ~loop.bus.free; "LOOP FREE".postln; }); Fdef(\loopTrig, { if(~loop.rec.isRunning, {~loop.phasor.set(\t_stop, 1)},{Fdef(\loopRec).value}); }); OSCdef(\loopDur, {|m| var dur= m[3]*s.sampleRate; Fdef(\loopStopRec).value(dur); Fdef(\loopPlay).value; }, '\loopStopRec'); "SYNC_LOOP OK !".postln; }) /* Fdef(\loopTrig).value; // start/stop record Tdef(\loopStopPlay).play; Fdef(\loopBPM).value; Fdef(\loopUndo).value; // undo last record Fdef(\loopClear).value; // clear all records Fdef(\loopFree).value // free loop from server ~loop.plays[0].run(false); // stop first loop ~gLoop.run(false); // pause all players ~gLoop.run; // resume all players ~gLoopPlay.run; ~gLoopPlay.run(false); ~loop.phasor.set(\rate, 1); // change rate speed ~loop.plays.do{|x| x.run(2.rand.asBoolean)}; // rand stop/play itens ~loop.bufs[0].plot ( MIDIClient.init; MIDIIn.connectAll; MIDIdef.program(\sstep, {|k,f,c| var x; // k.postln; x = case { k==5 }{ Fdef(\loopTrig).value } { k==4 }{ Tdef(\loopStopPlay).play } { k==2 }{ Fdef(\loopUndo).value } { k==1 }{ Fdef(\loopClear).value } }); ) */