diff --git a/control.scd b/control.scd index f130326..b0a62af 100644 --- a/control.scd +++ b/control.scd @@ -1,11 +1,10 @@ ( -// audio buses and other control stuff -// recordb = input to bufrecorder +//input mixing, effects and lfos - -~recordb = Bus.audio(s, 1); +~inputb = Bus.audio(s, 1); +~infxb = Bus.audio(s, 1); ~inmixer = SynthDef( \input_null, @@ -13,9 +12,8 @@ arg in1 = 2, in2 = 3, out = 4; Out.ar(out, In.ar(in1) + In.ar(in2)); } -).play(s, [\in1, ~usbinput1, \in2, ~usbinput2, \out, ~recordb]); +).play(s, [\in1, ~usbinput1, \in2, ~usbinput2, \out, ~inputb]); -~grb = Bus.audio(s, 2); // LFO buses and synths @@ -29,4 +27,31 @@ "LFOs running".postln; +// filter is now before grains + +~filtermodb = Bus.control(s, 1); + +~filtermod = SynthDef( + \filtermod, { + arg out, a = 1.0, b = 0.0, c = 0.0; + var siga, sigb, sigc; + siga = In.kr(~lfoab) * a; + sigb = In.kr(~lfobb) * b; + sigc = In.kr(~lfocb) * c; + Out.kr(out, Wrap.kr(siga + sigb + sigc, -1, 1)); + } +).play(s, [\out, ~filtermodb, \a, 1, \b, 0, \c, 0 ]); + + +~filter = SynthDef( + \filter, { + arg in, out, mod, freq=10000, res=0.3, amp=1.0; + var filt, lfo; + lfo = LinExp.kr(In.kr(mod, 1), -1, 1, freq * 0.5, freq * 2); + filt = RLPF.ar(In.ar(in, 2) * amp, lfo, res); + Out.ar(out, filt); + } +).play(s, [ \in, ~inputb, \out, ~infxb, \mod, ~filtermodb, \amp, 0.5], \addToTail); + + ) diff --git a/effects.scd b/effects.scd index 55a242c..9ddcfed 100644 --- a/effects.scd +++ b/effects.scd @@ -1,11 +1,10 @@ +// this is just output effects now ( -// output effects mixing and effects -~fxb = Bus.audio(s, 2); -~filterb = Bus.audio(s, 2); -~grainsb = Bus.audio(s, 2); + +~outfxb = Bus.audio(s, 2); ~delayb = Bus.audio(s, 2); ~reverbb = Bus.audio(s, 2); @@ -14,36 +13,10 @@ ~grainmixer = SynthDef( \grain_mixer, { - arg in=2, gbus=4, out=0, passthrough=0.75, grains=0.75; - Out.ar(out, (grains * In.ar(gbus, 2)) + (passthrough * In.ar(~recordb, 1) ! 2)); + arg in=2, grainb=4, out=0, passthrough=0.75, grains=1; + Out.ar(out, (grains * In.ar(grainb, 2)) + (passthrough * In.ar(in, 1) ! 2)); } -).play(s, [\in, ~usbinput, \gbus, ~grb, \out, ~fxb ], \addToTail); - -~filtermodb = Bus.control(s, 1); - -~filtermod = SynthDef( - \filtermod, { - arg out, a = 1.0, b = 0.0, c = 0.0; - var siga, sigb, sigc; - siga = In.kr(~lfoab) * a; - sigb = In.kr(~lfobb) * b; - sigc = In.kr(~lfocb) * c; - Out.kr(out, Wrap.kr(siga + sigb + sigc, -1, 1)); - } -).play(s, [\out, ~filtermodb, \a, 1, \b, 0, \c, 0 ]); - - -~filter = SynthDef( - \filter, { - arg in, out, mod, freq=10000, res=0.3, amp=1.0; - var filt, lfo; - lfo = LinExp.kr(In.kr(mod, 1), -1, 1, freq * 0.5, freq * 2); - filt = RLPF.ar(In.ar(in, 2) * amp, lfo, res); - Out.ar(out, filt); - } -).play(s, [ \in, ~fxb, \out, ~filterb, \mod, ~filtermodb, \amp, 0.5 ], \addToTail); - - +).play(s, [\in, ~infxb, \grainb, ~grainsb, \out, ~outfxb ], \addToTail); @@ -58,7 +31,7 @@ del = CombC.ar(sig, maxdelay, delaytime, decaytime, amp); Out.ar(out, sig + del); } - ).play(s, [ \in, ~filterb, \out, ~delayb ], \addToTail); + ).play(s, [ \in, ~outfxb, \out, ~delayb ], \addToTail); // try taking out the reverb because I think it causes noises @@ -72,3 +45,4 @@ "Effects running".postln; ) + diff --git a/granulator.scd b/granulator.scd index 7326b64..017fabb 100644 --- a/granulator.scd +++ b/granulator.scd @@ -1,4 +1,5 @@ + ( ~modes = [ [ "saw", \pos_saw ], @@ -8,33 +9,59 @@ [ "random", \pos_random ] ]; +~outputDir = Platform.recordingsDir +/+ "GrainBuffers"; + + +~grainsb = Bus.audio(s, 2); + ~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, ~recordb, ~fxb, pb, ~triggerb, ~pitchb)); + var pb = ~posb[i], rtb = ~rectriggerb[i]; + ~granulators.add(Granulator.new(~buflen, ~infxb, ~grainsb, pb, rtb)); }); + +// 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; - -) \ No newline at end of file +~dumpbuffers = { |prefix| + (0..3).do({|i| + var filename = ~outputDir +/+ prefix ++ 'buffer' ++ i.asString ++ '.aiff'; + ~granulators[i].buffer.write(filename); + }); +} +) diff --git a/interface.scd b/interface.scd index e4dece2..fb9b69c 100644 --- a/interface.scd +++ b/interface.scd @@ -1,5 +1,4 @@ -// FIXME: the touchosc stuff is crashing on intialisation ( ~to = TouchOSC("192.168.0.209", 9000); @@ -8,10 +7,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 +25,77 @@ OSCdef.freeAll; }); }); +~quantspeed = { |v| 2.pow((v * 4 + 0.5).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; + [ "setspeed", v, qv, speed ].postln; + 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. +// keeps the level for each track in an array and resets it + +~mixlevel = Array.new(4); + +(0..3).do({~mixlevel.add(0.25)}); + + +~setrecord = { | track, v | + ~granulators[track].record_(v); + [ v, track, ~tracknum ].postln; + if(v == 0, { + ~mixlevel[track] = ~granulators[track].mix; + ~granulators[track].mix_(0); + }, + { + ~granulators[track].mix_(~mixlevel[track]); + }); + if( track == ~tracknum, { ~to.v_('/track/mix', ~granulators[track].mix); }) +}; + + // 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 +104,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]); }); @@ -66,7 +121,7 @@ OSCdef.freeAll; ~to.button('/track/dust', 0, { |v| ~granulator.dust_(v) }); ~to.button('/track/back', 0, { |v| ~granulator.back_(v)}); -~to.button('/track/slope', 1, { |v| ~granulator.slope_(v) }); +~to.button('/track/slope', 0, { |v| ~granulator.slope_(v) }); ~to.button('/track/chorus', 0, { |v| ~granulator.chorus_(v) }); ~to.slider('/track/detune', 0, TouchOSCScale(0, 0.059), { |v| ~granulator.detune_(v) }); diff --git a/main.scd b/main.scd index 79ea333..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; @@ -12,16 +13,28 @@ Routine.run({ ("./synths.scd").loadRelative; Granulator.init(s); - s.sync; - - "Synths loaded".postln; - ("./control.scd").loadRelative; - ("./effects.scd").loadRelative; + s.sync; ("./granulator.scd").loadRelative; s.sync; + ("./effects.scd").loadRelative; + s.sync; ("./interface.scd").loadRelative; }); ) + + + + + +("./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; + + )