From f880ac583184045476a733bb0b2e6313ea016a17 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 17 Sep 2023 10:11:31 +1000 Subject: [PATCH] Added a trigger to sync the recorder with the playback buffer Also turns off granulator input mix when recording stops --- granulator.scd | 31 ++++++++++++++++++----- interface.scd | 69 +++++++++++++++++++++++++++++++++++++++++--------- main.scd | 15 ++++++++++- synths.scd | 12 ++++++--- 4 files changed, 104 insertions(+), 23 deletions(-) diff --git a/granulator.scd b/granulator.scd index f10d263..b92d226 100644 --- a/granulator.scd +++ b/granulator.scd @@ -12,32 +12,49 @@ ~granulators = Array.new(4); ~posb = Array.new(4); +~rectriggerb = Array.new(4); ~possynths = Array.new(4); +~triggersynths = Array.new(4); + +// create the control busses (0..3).do({ - var pb = Bus.control(s, 1), ps; - ~posb.add(pb); - ps = Synth(\pos_saw, [ \out, pb, \speed, 1 / ~buflen ]); - ~possynths.add(ps); + var ps; + ~posb.add(Bus.control(s, 1)); + ~rectriggerb.add(Bus.control(s, 1)); }); +// start the granulators (0..3).do({ |i| - var pb = ~posb.at(i); - ~granulators.add(Granulator.new(~buflen, ~infxb, ~grainsb, pb, ~triggerb, ~pitchb)); + var pb = ~posb[i], rtb = ~rectriggerb[i]; + ~granulators.add(Granulator.new(~buflen, ~infxb, ~grainsb, pb, rtb)); }); +"Granulators running".postln; + +// launch the pos synths and triggers to sync the buffer recorders + +(0..3).do({ |i| + var pb = ~posb[i], rtb = ~rectriggerb[i]; + ~possynths.add(Synth(\pos_saw, [ \out, pb, \speed, 1 / ~buflen ])); + ~triggersynths.add(Synth(\trigger, [ \out, rtb ])); +}); + +// TODO - retrigger the buffer records when changing the length etc + ~setmode = { arg track, mode; var synth = ~modes[mode][1]; ~possynths[track].get(\speed, { | speed | ~possynths[track].free; + ~triggersynths[track].free; ~possynths[track] = Synth(synth, [\out, ~posb[track], \speed, speed]); + ~triggersynths[track] = Synth(\trigger, [ \out, ~rectriggerb[track] ]); }); ~granulators[track].mode_(mode); }; -"Granulator running".postln; ) diff --git a/interface.scd b/interface.scd index e4dece2..fbc1742 100644 --- a/interface.scd +++ b/interface.scd @@ -1,5 +1,6 @@ -// FIXME: the touchosc stuff is crashing on intialisation + +~quantspeed.value(2); ( ~to = TouchOSC("192.168.0.209", 9000); @@ -8,10 +9,13 @@ ~tracknum = 0; ~granulator = ~granulators[0]; +~speedlock = 0; +~speedquant = 0; + OSCdef.freeAll; -~to.button('/reset', 0, { | v | +~to.button('/grains/reset', 0, { | v | if( v > 0, { var sp = ~to.v('/grains/speed')[0]; ~buflen = ~to.v('/grains/buflen'); @@ -23,26 +27,65 @@ OSCdef.freeAll; }); }); +~quantspeed = { |v| 2.pow((v * 4).round - 5) }; + +// control ganging is hella laggy, do it in TouchOSC + +~setspeed = { | track, v | + var speed, qv = if(~speedquant > 0, { ~quantspeed.value(v) }, { v }); + speed = qv / ~buflen; + if(~speedlock > 0, { + (0..3).do({|n| + ~possynths[n].set(\speed, speed); + if( n != track, { + var url = ("/grains/speed" ++ n).asSymbol; + ~to.s_(url, v); + }); + }); + }, + { ~possynths[track].set(\speed, speed) }); +}; + +// setrecord: toggles record on (1) or off (0) for a track, and also sets the +// track's input mix to 0 so that it doesn't start fadeing out. If the track +// is the currently selected track, set its touchosc control to 0. + +~setrecord = { | track, v | + ~granulators[track].record_(v); + [ v, track, ~tracknum ].postln; + if(v == 0, { + ~granulators[track].mix_(0); + if( track == ~tracknum, { ~to.v_('/track/mix', 0); }); + }); +}; + + // note: ~buflen is the variable for buffer length, which only gets set to // ~to.v('/grains/buflen') when the buffer is reset with the clear button ~to.slider('/grains/buflen', ~buflen, TouchOSCScale(0.1, 10.0), {}); -~to.button('/grains/record0', 0, { | v | ~granulators[0].record_(v) }); -~to.button('/grains/record1', 0, { | v | ~granulators[1].record_(v) }); -~to.button('/grains/record2', 0, { | v | ~granulators[2].record_(v) }); -~to.button('/grains/record3', 0, { | v | ~granulators[3].record_(v) }); + + + +~to.button('/grains/record0', 0, { | v | ~setrecord.value(0, v) }); +~to.button('/grains/record1', 0, { | v | ~setrecord.value(1, v) }); +~to.button('/grains/record2', 0, { | v | ~setrecord.value(2, v) }); +~to.button('/grains/record3', 0, { | v | ~setrecord.value(3, v) }); + + ~to.button('/grains/mode0', 0, { |v| ~granulators[0].mode_(v); ~setmode.value(0, v) }); ~to.button('/grains/mode1', 0, { |v| ~granulators[1].mode_(v); ~setmode.value(1, v) }); ~to.button('/grains/mode2', 0, { |v| ~granulators[2].mode_(v); ~setmode.value(2, v) }); ~to.button('/grains/mode3', 0, { |v| ~granulators[3].mode_(v); ~setmode.value(3, v) }); -~to.slider('/grains/speed0', 1, TouchOSCScale(0, 2), { |v| ~possynths[0].set(\speed, v / ~buflen); }); -~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| ~possynths[1].set(\speed, v / ~buflen); }); -~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| ~possynths[2].set(\speed, v / ~buflen); }); -~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| ~possynths[3].set(\speed, v / ~buflen); }); +~to.slider('/grains/speed0', 1, TouchOSCScale(0, 2), { |v| ~setspeed.value(0, v) }); +~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| ~setspeed.value(1, v) }); +~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| ~setspeed.value(2, v) }); +~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| ~setspeed.value(3, v) }); + ~to.slider('/grains/passthrough', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) }); @@ -51,13 +94,15 @@ OSCdef.freeAll; ~to.slider('/grains/mix2', 0.5, TouchOSCScale(0, 1),{ | v | ~granulators[2].gain_(v) }); ~to.slider('/grains/mix3', 0.5, TouchOSCScale(0, 1),{ | v | ~granulators[3].gain_(v) }); -~to.button('/grains/speedquant', 0, { |v| }); +~to.button('/grains/lock', 0, { |v| ~speedlock = v }); + +~to.button('/grains/quant', 0, { |v| ~speedquant = v }); // Page 2: track -~to.xy('/track/triggersize', [ 120, 0.1 ], TouchOSCScale(0, 640), TouchOSCScale(0, 0.5), { |v| +~to.xy('/track/triggersize', [ 320, 0.25 ], TouchOSCScale(0, 640), TouchOSCScale(0, 0.5), { |v| ~granulator.trigger_(v[0]); ~granulator.size_(v[1]); }); diff --git a/main.scd b/main.scd index 47661a5..60094f0 100644 --- a/main.scd +++ b/main.scd @@ -3,7 +3,8 @@ ( Server.default.options.inDevice_("Scarlett 2i2 USB"); Server.default.options.hardwareBufferSize_(1024); -//Server.default.options.outDevice_("Scarlett 2i2 USB"); +Server.default.options.outDevice_("Scarlett 2i2 USB"); +//Server.default.options.outDevice_("External Headphones"); ) Server.killAll; @@ -25,3 +26,15 @@ Routine.run({ + + + +("./synths.scd").loadRelative; +Granulator.init(s); +("./control.scd").loadRelative; +("./granulator.scd").loadRelative; +("./effects.scd").loadRelative; +("./interface.scd").loadRelative; + + + diff --git a/synths.scd b/synths.scd index 2ff256a..9940ecd 100644 --- a/synths.scd +++ b/synths.scd @@ -14,12 +14,12 @@ SynthDef(\pos_sine, { SynthDef(\pos_saw, { arg out, speed=1; - Out.kr(out, 0.5 + LFSaw.kr(speed, 0, 0.5)); + Out.kr(out, 0.5 + LFSaw.kr(speed, 0, 0.5, 0.5)); }).add; SynthDef(\pos_reverse, { arg out, speed=1; - Out.kr(out, 0.5 - LFSaw.kr(speed, 0, 0.5)); + Out.kr(out, 0.5 - LFSaw.kr(speed, 0, 0.5, 0.5)); }).add; SynthDef(\pos_step, { @@ -33,9 +33,15 @@ SynthDef(\pos_random, { Out.kr(out, 0.5 + WhiteNoise.kr(0.5)); }).add; -SynthDef( \lfo, { +SynthDef(\lfo, { arg out, freq=1, amp=0; Out.kr(out, SinOsc.kr(freq, 0, amp)); }).add; +SynthDef(\trigger, { + arg out=1; + Out.kr(out, Impulse.kr(0)) +}).add; + + )