diff --git a/control.scd b/control.scd index b0a62af..09647b0 100644 --- a/control.scd +++ b/control.scd @@ -3,7 +3,7 @@ //input mixing, effects and lfos -~inputb = Bus.audio(s, 1); +~inputb = Bus.audio(s, 1); // bypassing this one for now ~infxb = Bus.audio(s, 1); ~inmixer = SynthDef( @@ -12,7 +12,7 @@ arg in1 = 2, in2 = 3, out = 4; Out.ar(out, In.ar(in1) + In.ar(in2)); } -).play(s, [\in1, ~usbinput1, \in2, ~usbinput2, \out, ~inputb]); +).play(s, [\in1, ~usbinput1, \in2, ~usbinput2, \out, ~infxb]); // LFO buses and synths @@ -27,31 +27,6 @@ "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 9ddcfed..fc9e4b6 100644 --- a/effects.scd +++ b/effects.scd @@ -5,6 +5,7 @@ ~outfxb = Bus.audio(s, 2); +~filterb = Bus.audio(s, 2); ~delayb = Bus.audio(s, 2); ~reverbb = Bus.audio(s, 2); @@ -20,6 +21,34 @@ +// filter is after grains again + +~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, ~outfxb, \out, ~filterb, \mod, ~filtermodb, \amp, 0.5], \addToTail); + + + // delay always passes through 100% of its input + amp % of the delay @@ -31,9 +60,8 @@ del = CombC.ar(sig, maxdelay, delaytime, decaytime, amp); Out.ar(out, sig + del); } - ).play(s, [ \in, ~outfxb, \out, ~delayb ], \addToTail); + ).play(s, [ \in, ~filterb, \out, ~delayb ], \addToTail); -// try taking out the reverb because I think it causes noises ~reverb = SynthDef( \reverb, { diff --git a/granulator.scd b/granulator.scd index 017fabb..1151a31 100644 --- a/granulator.scd +++ b/granulator.scd @@ -6,7 +6,6 @@ [ "reverse", \pos_reverse ], [ "sine", \pos_sine ], [ "step", \pos_step ], - [ "random", \pos_random ] ]; ~outputDir = Platform.recordingsDir +/+ "GrainBuffers"; @@ -15,15 +14,17 @@ ~grainsb = Bus.audio(s, 2); ~granulators = Array.new(4); +~grainmodes = [ 0, 0, 0, 0 ]; // keep track of mode so don't swap if not needed +~speeds = [ 1, 1, 1, 1 ]; // hacky speed quantisation ~posb = Array.new(4); ~rectriggerb = Array.new(4); -~possynths = Array.new(4); -~triggersynths = Array.new(4); +~patterns = [ nil, nil, nil, nil ]; +~players = [ nil, nil, nil, nil ]; +~loopsynths = [ nil, nil, nil, nil ]; // create the control busses (0..3).do({ - var ps; ~posb.add(Bus.control(s, 1)); ~rectriggerb.add(Bus.control(s, 1)); }); @@ -35,29 +36,59 @@ ~granulators.add(Granulator.new(~buflen, ~infxb, ~grainsb, pb, rtb)); }); +// set up the Patterns which drive the position synths -// 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 +// (0..3).do({ |i| +// ~patterns.add(~makePattern.value(i, 0, ~speeds[i])); +// }); +// +// (0..3).do({|i| +// ~players.add(~patterns[i].play(~tc, quant: ~beatsperbar)) +// }); ~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] ]); + ~grainmodes[track] = mode; + if(~players[track].isNil.not,{ + ~players[track].stop; + ~patterns[track].free; }); - ~granulators[track].mode_(mode); + ~patterns[track] = ~makePattern.value(track, mode, ~speeds[track]); + ~players[track] = ~patterns[track].play(~tc, quant: ~beatsperbar); }; +~setspeed = { + arg track, speed; + if( ~speeds[track] != speed, { + ~speeds[track] = speed; + ~players[track].stop; + ~patterns[track].free; + ~patterns[track] = ~makePattern.value(track, ~grainmodes[track], ~speeds[track]); + ~players[track] = ~patterns[track].play(~tc, quant: ~beatsperbar); + }); +}; + + +~makePattern = { + arg track, mode, speed; + var ptrig, ppos, synth = ~modes[mode][1]; + // note: trigger is going off the base tempoclock, not the playback speed - I think this is + // the right thing to do but I'm not sure yet + ptrig = Pbind( + \instrument, \trigger, + \dur, ~beatsperbar, + \out, ~rectriggerb[track] + ); + ppos = Pbind( + \instrument, synth, + \dur, ~beatsperbar / speed, + \length, ~buflen / speed, + \out, ~posb[track] + ); + Ppar([ptrig, ppos]); +}; + + ~dumpbuffers = { |prefix| (0..3).do({|i| var filename = ~outputDir +/+ prefix ++ 'buffer' ++ i.asString ++ '.aiff'; diff --git a/interface.scd b/interface.scd index 279e862..e5295a0 100644 --- a/interface.scd +++ b/interface.scd @@ -36,25 +36,6 @@ OSCdef.freeAll; }; -// 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. @@ -85,15 +66,17 @@ OSCdef.freeAll; ~to.slider('/grains/buflen', ~buflen, TouchOSCScale(0.1, 10.0), {}); -~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.button('/grains/mode0', 0, { |v| ~setmode.value(0, v) }); +~to.button('/grains/mode1', 0, { |v| ~setmode.value(1, v) }); +~to.button('/grains/mode2', 0, { |v| ~setmode.value(2, v) }); +~to.button('/grains/mode3', 0, { |v| ~setmode.value(3, v) }); -~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) }); +// needs work + +~to.slider('/grains/speed0', 1, TouchOSCScale(0, 2), { |v| ~setspeed.value(0, ~quantspeed.value(v)) }); +~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| ~setspeed.value(1, ~quantspeed.value(v)) }); +~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| ~setspeed.value(2, ~quantspeed.value(v)) }); +~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| ~setspeed.value(3, ~quantspeed.value(v)) }); ~to.slider('/grains/passthrough', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) }); @@ -105,7 +88,7 @@ OSCdef.freeAll; ~to.button('/grains/lock', 0, { |v| ~speedlock = v }); -~to.button('/grains/quant', 0, { |v| ~speedquant = v }); +~to.button('/grains/quant', 1, { |v| ~speedquant = v }); ~to.button('/grains/metronome', 0, { |v| if( v == 1, { @@ -120,16 +103,16 @@ OSCdef.freeAll; // Page 2: track -~to.xy('/track/triggersize', [ 100, 0.125 ], TouchOSCScale(0, 400), TouchOSCScale(0, 1.5), { |v| +~to.xy('/track/triggersize', [ 100, 0.125 ], TouchOSCScale(0, 200), TouchOSCScale(0, 1), { |v| ~granulator.trigger_(v[0]); ~granulator.size_(v[1]); }); -~to.slider('/track/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.blur_(v) }); +~to.slider('/track/blur', 0, TouchOSCScale(0, 1.0), { |v| ~granulator.blur_(v) }); ~to.button('/track/dust', 0, { |v| ~granulator.dust_(v) }); ~to.button('/track/back', 0, { |v| ~granulator.back_(v)}); -~to.button('/track/slope', 0, { |v| ~granulator.slope_(v) }); +~to.button('/track/slope', 1, { |v| ~granulator.slope_(v) }); ~to.button('/track/chorus', 0, { |v| ~granulator.chorus_(v) }); ~to.slider('/track/harmonics', 2, TouchOSCScale(0.5, 3), { |v| diff --git a/main.scd b/main.scd index 8564112..89bb301 100644 --- a/main.scd +++ b/main.scd @@ -15,7 +15,7 @@ Routine.run({ ~usbinput1 = 2; ~usbinput2 = 3; - ~bpm = 55; + ~bpm = 90; ~bps = ~bpm / 60; ~beatsperbar = 4; ~buflen = ~beatsperbar / ~bps; @@ -25,7 +25,6 @@ Routine.run({ ~tc = TempoClock.new(~bps); - ~touchosc_ip = "192.168.0.209"; ("./synths.scd").loadRelative; @@ -39,9 +38,9 @@ Routine.run({ s.sync; ("./sequencer.scd").loadRelative; s.sync; + "please wait for the interface to load...".postln; + ~buflen.sleep; ("./interface.scd").loadRelative; + "ok go!".postln; }); ) - - - diff --git a/sequencer.scd b/sequencer.scd index ce93b85..da45d47 100644 --- a/sequencer.scd +++ b/sequencer.scd @@ -2,14 +2,6 @@ ( -SynthDef(\metronome, { - arg out=0, amp=1, pan=0, filter=1000, atk=0.01, rel=0.1; - var sig, env; - env = EnvGen.kr(Env.perc(atk, rel, amp), doneAction: Done.freeSelf); - sig = HPF.ar(WhiteNoise.ar(), filter); - Out.ar(out, Pan2.ar(sig * env, pan)); -} -).add; ~metrob = Bus.audio(s, 2); @@ -21,7 +13,7 @@ SynthDef(\metronome, { ~metronome = Pbind( \instrument, \metronome, - \dur, 1, + \dur, ~beatsperbar, \amp, 0.5, \pan, 0, \out, ~metrob diff --git a/synths.scd b/synths.scd index 594ace5..d573fde 100644 --- a/synths.scd +++ b/synths.scd @@ -1,30 +1,26 @@ ( -SynthDef(\pos_sine, { - arg out, speed=1; - Out.kr(out, 0.5 + SinOsc.kr(speed * 0.5, -0.5pi, 0.5)); -}).add; - SynthDef(\pos_saw, { - arg out, speed=1; - Out.kr(out, 0.5 + LFSaw.kr(speed, 1, 0.5, 0)); -}).add; + arg out, length=1; + Out.kr(out, EnvGen.kr(Env([0, 1], length), doneAction: Done.freeSelf)) +}).add(); + +SynthDef(\pos_sine, { + arg out, length=1; + Out.kr(out, EnvGen.kr(Env.sine(length, 1), doneAction: Done.freeSelf)) +}).add(); SynthDef(\pos_reverse, { - arg out, speed=1; - Out.kr(out, 0.5 - LFSaw.kr(speed, 1, 0.5, 0)); -}).add; + arg out, length=1; + Out.kr(out, EnvGen.kr(Env([1, 0], length), doneAction: Done.freeSelf)) +}).add(); SynthDef(\pos_step, { - arg out, speed=1, steps=8; - var stepwise = LFSaw.kr(speed, 1, 0.5 * steps, 0.5 * steps).floor; - Out.kr(out, stepwise / steps); -}).add; + arg out, length=1; + var levels = (0..8) / 8, times = (length / 8) ! 7; + Out.kr(out, EnvGen.kr(Env(levels: levels, times: times, curve: \hold), doneAction: Done.freeSelf)); +}).add(); -SynthDef(\pos_random, { - arg out=5, speed=1; - Out.kr(out, 0.5 + WhiteNoise.kr(0.5)); -}).add; SynthDef(\lfo, { arg out, freq=1, amp=0; @@ -33,7 +29,17 @@ SynthDef(\lfo, { SynthDef(\trigger, { arg out=1; - Out.kr(out, Impulse.kr(0)) + Out.kr(out, EnvGen.kr(Env.perc(0.001, 0.2, 2), levelScale:2.0, levelBias:-1,doneAction:Done.freeSelf)); }).add; + +SynthDef(\metronome, { + arg out=0, amp=1, pan=0, filter=1000, atk=0.01, rel=0.1; + var sig, env; + env = EnvGen.kr(Env.perc(atk, rel, amp), doneAction: Done.freeSelf); + sig = HPF.ar(WhiteNoise.ar(), filter); + Out.ar(out, Pan2.ar(sig * env, pan)); +} +).add; + )