From 000a6d358601f3278a53ac7e8a5dcf8a59b50720 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 2 Apr 2023 16:10:23 +1000 Subject: [PATCH 01/19] Cacky, not-working multitrack --- grains.scd | 177 ++++++++++++++++++++++++----------------------------- 1 file changed, 79 insertions(+), 98 deletions(-) diff --git a/grains.scd b/grains.scd index 1352d29..a80987b 100644 --- a/grains.scd +++ b/grains.scd @@ -2,14 +2,33 @@ ( Server.default.options.inDevice_("Scarlett 2i2 USB"); -Server.default.options.outDevice_("Scarlett 2i2 USB"); +//Server.default.options.outDevice_("Scarlett 2i2 USB"); ) Server.killAll; ~frippbuffer.write("/Users/mike/Music/SuperCollider Recordings/slow.aiff"); - +~frippbuffer.isNil; ( +~ntracks = 4; + +~makebuffers = { + if( ~frippbuffers.isNil.not, { + ~frippbuffers.do({ |b| b.free }); + ~frippbuffers.free; + }); + + ~frippbuffers = Array.new(~ntracks); + + ~currentfripp = 0; + + (1..~ntracks).do( { |i| + ~frippbuffers.add(Buffer.alloc(s, s.sampleRate * ~buflen, 1)); + }); +}; + + + ~to = TouchOSC("192.168.0.209", 9000); ~usbinput = 2; @@ -181,9 +200,8 @@ fork { ~pitch = SynthDef( \pitch, - { - arg out, posb, triggerb, track=1, dir=1, detune=0.0, chorus=0, harmonics=2, pitch=0, quant=1; + arg out, posb, triggerb, track=1, dir=1, detune=0.0, chorus=0, harmonics=2, pitch=0; var tracking, base, chor, det, csig, dsig; csig = Latch.kr(WhiteNoise.kr(), In.kr(triggerb)); dsig = Latch.kr(WhiteNoise.kr(), In.kr(triggerb)); @@ -196,35 +214,25 @@ fork { ).play(s, [ \out, ~pitchb, \triggerb, ~triggerb, \posb, ~playbacklfob, \dir, 1, \track, 0]); -// pitch gets quantised to octaves from 3 below to 3 above. -// NOTE: the pitch TouchOSC control is -1 to 1, not 0 to 1 -// min/max gets ignored because I'm overloading the ctrlset/get +~makebuffers.value(); -// TODO: fixme, - -// ~to.slider('/grainfx/pitch', -1, 1, 1, -// { |self| ~granulator.set("rate", self.v) }, - -// { |self, ctrlv | self.v = 2.pow((ctrlv * 3).floor) }, -// { |self| self.v.log2.floor / 3; } -// ); - - - -// buffer recorder - -~frippbuffer = Buffer.alloc(s, s.sampleRate * ~buflen, 1); ~bufrecorder = SynthDef( \fripp_record, { - arg in = 2, fb = 4, buffer = 0, mix = 0.25, record = 0.0, feedback = 0.0; - var insig, fbsig; - insig = record * In.ar(in, 1); - fbsig = feedback * Mix.ar(In.ar(fb, 2)); - RecordBuf.ar(insig + fbsig, buffer, 0, mix, 1 - mix, loop: 1) + arg in = 2, fb = 4, bufindex = 0, mix = 0.25, record = 0.0, feedback = 0.0; + var insig = record * In.ar(in, 1); + RecordBuf.ar(insig, ~frippbuffers[bufindex], 0, mix, 1 - mix, loop: 1) } -).play(s, [\in, ~recordb, \record, 1.0, \fb, ~granulatorb, \out, 0, \buffer, ~frippbuffer], \addToTail); +).play(s, [ + \in, ~recordb, + \record, 1.0, +// \fb, ~granulatorb, + \out, 0, + \bufindex, ~currentfripp, + \addToTail +] +); // the main granulator synth @@ -246,7 +254,7 @@ fork { } ).play(s, [ \out, ~granulatorb, - \buffer, ~frippbuffer, + \buffer, ~frippbuffers[~currentfripp], \posb, ~playbacklfob, \triggerb, ~triggerb, \pitchb, ~pitchb, @@ -327,7 +335,7 @@ fork { ) - +// why can't this all be in the same block? ( @@ -341,20 +349,27 @@ OSCdef.freeAll; if( v > 0, { var sp = ~to.v('/grains/speed')[0]; ~buflen = ~to.v('/grains/buflen'); - [ "resetting buffer to", ~buflen ].postln; - ~newbuffer = Buffer.alloc(s, s.sampleRate * ~buflen, 1); - ~granulator.set(\buffer, ~newbuffer); - ~bufrecorder.set(\buffer, ~newbuffer); - if( ~frippbuffer.isNil.not, { ~frippbuffer.free }); - ~frippbuffer = ~newbuffer; + [ "resetting buffers to", ~buflen ].postln; + ~makebuffers.value(); + ~granulator.set(\buffer, ~frippbuffers[~currentfripp]); + ~bufrecorder.set(\buffer, ~frippbuffers[~currentfripp]); + ~playbacklfo.set(\speed, sp / ~buflen); }); }); -~to.slider('/mix', 0.25, TouchOSCScale(0, 1), { |v| ~bufrecorder.set(\mix, v) } ); -~to.slider('/gain', 0.5, TouchOSCScale(0, 1), { |v| ~granulator.set(\amp, v) } ); -~to.slider('/passthrough', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) } ); +~to.button('/track', 0, { |v| + var buffer = ~frippbuffers[v]; + if( buffer.isNil.not, { + ~granulator.set(\buffer, buffer); + ~bufrecorder.set(\buffer, buffer); + [ "set track to", v, buffer ].postln; + }, { + [ "Bad track index", v ].postln; + }); +}); + ~to.slider('/feedback', 0, TouchOSCScale(0, 0.25), { |v| ~bufrecorder.set(\feedback, v) } ); @@ -408,19 +423,17 @@ OSCdef.freeAll; }); }); +~to.button('/grains/speedquant', 0, { |v| +}); + +~to.slider('/grains/step', 4, TouchOSCScale(1, 8), { |v| + ~grainstep.set(\steps, v.floor); +}); + + + ~to.button('/grains/dust', 0, { |v| ~trigger.set(\dust, v) }); -~to.slider('/grains/blur', 0, TouchOSCScale(0, 1), { |v| ~granulator.set(\blur, v) }); - - -// todo vvv quantise speed should be swappable - -// var trate, qspeed; -// qspeed = 2.pow(v[0].floor); -// ~playbacklfo.set(\speed, qspeed / ~buflen); -// [ "speed", v[0], qspeed, qspeed / ~buflen ].postln; -// trate = 2.pow(v[1].floor) / ~buflen; -// ~granulator.set(\trate, trate); - +~to.slider('/grains/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.set(\blur, v) }); ~to.slider('/grains/size', 0.1, TouchOSCScale(0, 0.5),{ @@ -429,24 +442,26 @@ OSCdef.freeAll; // Page 2: grainfx +~to.slider('/grainfx/mix', 0.25, TouchOSCScale(0, 1), { |v| + ~bufrecorder.set(\mix, v); +}); +~to.slider('/grainfx/gain', 0.5, TouchOSCScale(0, 1), { |v| ~granulator.set(\amp, v) } ); +~to.slider('/grainfx/pt', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) } ); + ~to.button('/grainfx/back', 0, { |v| ~pitch.set(\dir, if( v > 0, { -1 }, { 1}))}); - ~to.button('/grainfx/slope', 1, { |v| ~pitch.set(\track, v) }); - - ~to.slider('/grainfx/pan', 0, TouchOSCScale(-1, 1), { |v| ~granulator.set(\pan, v) }); ~to.slider('/grainfx/track', 0.5, TouchOSCScale(-1, 1), { |v| ~granulator.set(\track, v) }); ~to.slider('/grainfx/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.set(\jitter, v) }); ~to.button('/grainfx/chorus', 0, { |v| ~pitch.set(\chorus, v) }); - ~to.slider('/grainfx/detune', 0, TouchOSCScale(0, 0.059), { |v| ~pitch.set(\detune, v) }); - ~to.slider('/grainfx/pitch', 0, TouchOSCScale(-2, 2), { |v| ~pitch.set(\pitch, v.round) }); ~to.button('/grainfx/quant', 1, { |v| - ~pitch.set(\quant, v); + // ~pitch.set(\quant, v); + // just re-call the value setter for harmonics when toggled ~to.v_('/grainfx/harmonics', ~to.v('/grainfx/harmonics')); }); @@ -503,6 +518,9 @@ OSCdef.freeAll; ) +// old, slow buffer position display - to-do- this would be better in a GUI element +// on the laptop + ( ~posdisplay = Task.new({ @@ -518,48 +536,9 @@ OSCdef.freeAll; ~posdisplay.start; ) -~posdisplay.stop; - -~pitch.set(\harmonics, 1.5); - -~pitchb.scope - -~trigger.set(\dust,0); - -( -~testpitchb = Bus.control(s, 1); - -~test = SynthDef( - \testpitch, - { - arg out, triggerb; - var csig, dsig, chor; - csig = Latch.kr(WhiteNoise.kr(), In.kr(triggerb)); - //dsig = Latch.kr(WhiteNoise.kr(), In.kr(triggerb)); - chor = 2.pow((csig * 2).round); - Out.kr(out, chor); - } -).play(s, [ \out, ~testpitchb, \triggerb, ~triggerb ]); -) - -~test.free - -2.pow(3) --2.49.round - -0.4.asFraction(3) - -( -~trig2 = SynthDef( - \trig2, - { - arg out, freq=1, dust=0; - Out.kr(out, Impulse.kr(freq) * (1 - dust)) + (Dust.kr(freq) * dust); -} -).play(s, [ \out, ~triggerb, \freq, 120, \dust, 0 ]); -~frippbuffer.write("/Users/mike/Music/SuperCollider Recordings/slow.aiff"); +~frippbuffers[~currentfripp].write("/Users/mike/Music/SuperCollider Recordings/test.aiff"); ( ~monitor = SynthDef( @@ -578,6 +557,8 @@ OSCdef.freeAll; ~pitchb.scope() -// s.sync(); // this needs to be done in a routine because it calls yield -// sidebar - +~frippbuffers.plot; + +~bufrecorder.set(\buffer, ~frippbuffers[1]); + From 8a74f8612f2308eb0073e0e43a255858ef541892 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 2 Apr 2023 16:31:52 +1000 Subject: [PATCH 02/19] Multitrack is working for recording --- NOTES.md | 33 ++++++++------------------------- grains.scd | 54 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/NOTES.md b/NOTES.md index 151fa96..1250418 100644 --- a/NOTES.md +++ b/NOTES.md @@ -1,31 +1,14 @@ # TODO -## Granulator +- quantise playback speed to rational values +- display the playback and harmonics when quantised -Fix chorus and detune - why isn't it being triggered? +- multiple grain buffers - TouchOsc interface to select which to send to +- play back all buffers? -Add pitch shifting - -Change harmonics for chorus - -Lock harmonics to octaves / ratios - -## Effects chain - -Add an effects chain like with midilooper - --> filter -> reverb -> out +- rhythm controls + - number of steps in step granulator + - modulate grain level in time with playback + - sync LFOs to playback - -## LFO mod - -Add the new-style lfo mods to filter - -## More LFO mods - -Allow other settings to be modulated - -## Input filter - -Switch in and out a single input filter like distort, peak FFT, etc, \ No newline at end of file diff --git a/grains.scd b/grains.scd index a80987b..ea488df 100644 --- a/grains.scd +++ b/grains.scd @@ -217,23 +217,32 @@ fork { ~makebuffers.value(); -~bufrecorder = SynthDef( +SynthDef( \fripp_record, { - arg in = 2, fb = 4, bufindex = 0, mix = 0.25, record = 0.0, feedback = 0.0; + arg in = 2, buffer = 0, mix = 0.25, record = 0.0; var insig = record * In.ar(in, 1); - RecordBuf.ar(insig, ~frippbuffers[bufindex], 0, mix, 1 - mix, loop: 1) + RecordBuf.ar(insig, buffer, 0, mix, 1 - mix, loop: 1) } -).play(s, [ - \in, ~recordb, - \record, 1.0, -// \fb, ~granulatorb, - \out, 0, - \bufindex, ~currentfripp, - \addToTail -] -); +).add; +~bufrecorders = Array.new(~ntracks); + +~frippbuffers.do({ + | buffer, index | + ~bufrecorders.add(Synth.new( + \fripp_record, + [ + \in, ~recordb, + \record, 0.0, + \buffer, buffer + ], + s, + \addToTail + )) +}); + +~bufrecorder = ~bufrecorders[0]; // the main granulator synth @@ -347,14 +356,15 @@ OSCdef.freeAll; ~to.button('/reset', 0, { | v | if( v > 0, { - var sp = ~to.v('/grains/speed')[0]; - ~buflen = ~to.v('/grains/buflen'); - [ "resetting buffers to", ~buflen ].postln; - ~makebuffers.value(); - ~granulator.set(\buffer, ~frippbuffers[~currentfripp]); - ~bufrecorder.set(\buffer, ~frippbuffers[~currentfripp]); - - ~playbacklfo.set(\speed, sp / ~buflen); + "TODO: rewrite this for multitrack".postln; + // var sp = ~to.v('/grains/speed')[0]; + // ~buflen = ~to.v('/grains/buflen'); + // [ "resetting buffers to", ~buflen ].postln; + // ~makebuffers.value(); + // ~granulator.set(\buffer, ~frippbuffers[~currentfripp]); + // ~bufrecorder.set(\buffer, ~frippbuffers[~currentfripp]); + // + // ~playbacklfo.set(\speed, sp / ~buflen); }); }); @@ -362,8 +372,10 @@ OSCdef.freeAll; ~to.button('/track', 0, { |v| var buffer = ~frippbuffers[v]; if( buffer.isNil.not, { + ~bufrecorder.set(\record, 0.0); + ~bufrecorder = ~bufrecorders[v]; + ~bufrecorder.set(\record, ~to.v('/record')); ~granulator.set(\buffer, buffer); - ~bufrecorder.set(\buffer, buffer); [ "set track to", v, buffer ].postln; }, { [ "Bad track index", v ].postln; From 86fe427429da40a6c713eff18658ce739f92ae90 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 2 Apr 2023 17:59:53 +1000 Subject: [PATCH 03/19] Multitrack is working - needed a separate recorder and granulator for each buffer, and it's still creaky --- grains.scd | 110 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/grains.scd b/grains.scd index ea488df..8dd0d17 100644 --- a/grains.scd +++ b/grains.scd @@ -8,6 +8,33 @@ Server.killAll; ~frippbuffer.write("/Users/mike/Music/SuperCollider Recordings/slow.aiff"); ~frippbuffer.isNil; + +( +SynthDef( + \fripp_record, + { + arg in = 2, buffer = 0, mix = 0.25, record = 0.0; + var insig = record * In.ar(in, 1); + RecordBuf.ar(insig, buffer, 0, mix, 1 - mix, loop: 1) + } +).add; + + +SynthDef( + \grainsynth, + { + arg out=0, buffer, blen, pitchb, triggerb, posb, modb, size=0.1, amp=0.5, pan=0, track=0.25, jitter=0, blur=0.0; + var pitch, trigger, chor, pos, pans, grains, filtfreq; + trigger = In.kr(triggerb); + pitch = In.kr(pitchb); + pos = Wrap.kr(In.kr(posb, 1) + WhiteNoise.kr(blur), 0, 1); + pans = pan + WhiteNoise.kr(jitter) + (track * (In.kr(posb, 1) - 1)); + grains = TGrains.ar(2, trigger, buffer, pitch, pos * blen, size, pans, amp); + Out.ar(out, grains); + } +).add; +) + ( ~ntracks = 4; @@ -217,15 +244,6 @@ fork { ~makebuffers.value(); -SynthDef( - \fripp_record, - { - arg in = 2, buffer = 0, mix = 0.25, record = 0.0; - var insig = record * In.ar(in, 1); - RecordBuf.ar(insig, buffer, 0, mix, 1 - mix, loop: 1) - } -).add; - ~bufrecorders = Array.new(~ntracks); ~frippbuffers.do({ @@ -244,32 +262,31 @@ SynthDef( ~bufrecorder = ~bufrecorders[0]; -// the main granulator synth +// the granulators +~granulators = Array.new(~ntracks); +~grainmodes = Array.fill(~ntracks, 0); -~granulator = SynthDef( - \grainsynth, - { - arg out=0, buffer, pitchb, triggerb, posb, modb, size=0.1, amp=1.0, pan=0, track=0.25, jitter=0, blur=0.0; - var pitch, blen, trigger, chor, pos, pans, grains, filtfreq; - //trigger = Impulse.kr(120); - trigger = In.kr(triggerb); - pitch = In.kr(pitchb); - blen = BufDur.kr(buffer); - pos = Wrap.kr(In.kr(posb, 1) + WhiteNoise.kr(blur), 0, 1); - pans = pan + WhiteNoise.kr(jitter) + (track * (In.kr(posb, 1) - 1)); - grains = TGrains.ar(2, trigger, buffer, pitch, pos * blen, size, pans, amp); - Out.ar(out, grains); - } -).play(s, [ - \out, ~granulatorb, - \buffer, ~frippbuffers[~currentfripp], - \posb, ~playbacklfob, - \triggerb, ~triggerb, - \pitchb, ~pitchb, - \modb, ~lfob, - \size, 0.1 -]); +~frippbuffers.do({ + | buffer, index | + [ "Grain synth: ", buffer, index ].postln; + ~granulators.add(Synth.new( + \grainsynth, + [ + \out, ~granulatorb, + \buffer, buffer, + \blen, ~buflen, + \posb, ~playbacklfob, + \triggerb, ~triggerb, + \pitchb, ~pitchb, + \modb, ~lfob, + \size, 0.1 + ], + s + )) +}); + +~granulator = ~granulators[0]; // mixing and effects @@ -372,17 +389,27 @@ OSCdef.freeAll; ~to.button('/track', 0, { |v| var buffer = ~frippbuffers[v]; if( buffer.isNil.not, { + [ "set track to", v, buffer ].postln; ~bufrecorder.set(\record, 0.0); + ~bufrecorder.set(\mix, 0.0); // stop unselected track fading out ~bufrecorder = ~bufrecorders[v]; ~bufrecorder.set(\record, ~to.v('/record')); - ~granulator.set(\buffer, buffer); - [ "set track to", v, buffer ].postln; + ~granulator = ~granulators[v]; + ~to.v_('/grainfx/mix', 0); // will always be 0 because we turned it off + ~granulator.get(\amp, { | v | ~to.v_('/grainfx/gain', v) }); + ~granulator.get(\blur, { | v | ~to.v_('/grains/blur', v) }); + ~granulator.get(\size, { | v | ~to.v_('/grains/size', v) }); + ~granulator.get(\pan, { | v | ~to.v_('/grainfx/pan', v) }); + ~granulator.get(\track, { | v | ~to.v_('/grainfx/track', v) }); + ~granulator.get(\jitter, { | v | ~to.v_('/grainfx/jitter', v) }); + // todo - set the grainmode based on what this one has }, { [ "Bad track index", v ].postln; }); }); + ~to.slider('/feedback', 0, TouchOSCScale(0, 0.25), { |v| ~bufrecorder.set(\feedback, v) } ); @@ -426,6 +453,7 @@ OSCdef.freeAll; ~to.button('/grains/mode', 0, { |v| var mode = ~modes[v]; if( mode.isNil.not, { + [ "granulator is", ~granulator ].postln; ~granulator.set(\posb, mode[1]); ~playbacklfo = mode[0]; ~playbacklfob = mode[1]; @@ -454,10 +482,10 @@ OSCdef.freeAll; // Page 2: grainfx -~to.slider('/grainfx/mix', 0.25, TouchOSCScale(0, 1), { |v| +~to.slider('/grainfx/mix', 0.25, TouchOSCScale(0, 1), { |v| ~bufrecorder.set(\mix, v); }); -~to.slider('/grainfx/gain', 0.5, TouchOSCScale(0, 1), { |v| ~granulator.set(\amp, v) } ); +~to.slider('/grainfx/gain', 0.5, TouchOSCScale(0, 1), { |v| ~granulator.set(\amp, v) } ); ~to.slider('/grainfx/pt', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) } ); ~to.button('/grainfx/back', 0, { |v| ~pitch.set(\dir, if( v > 0, { -1 }, { 1}))}); @@ -574,3 +602,11 @@ OSCdef.freeAll; ~bufrecorder.set(\buffer, ~frippbuffers[1]); +~granulators[0].get(\buffer, {|v| v.postln}); + +( +~frippbuffers.do({ + |b, i| + b.write("/Users/mike/Music/SuperCollider Recordings/buffer" ++ i.asString ++ ".aiff"); +}); +) From fdf92ef4bab79897e959d3b59cb250a3008a2bed Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Fri, 7 Apr 2023 16:16:05 +1000 Subject: [PATCH 04/19] Refactoring with granulator in a quark --- NOTES.md | 10 ++++++++++ grains.scd | 57 ++++++++++++------------------------------------------ 2 files changed, 22 insertions(+), 45 deletions(-) diff --git a/NOTES.md b/NOTES.md index 1250418..25716a2 100644 --- a/NOTES.md +++ b/NOTES.md @@ -6,6 +6,16 @@ - multiple grain buffers - TouchOsc interface to select which to send to - play back all buffers? +- refactor for multitrack + - which controls are per-track and which are global? sort these out in the UI + - encapsulate a grainstrack in an object? + +- auto-mix: base the mix level on how loud the incoming signal is so that tracks don't fade out + +- fancier playback: + - intertwine different rates and directions + + - rhythm controls - number of steps in step granulator - modulate grain level in time with playback diff --git a/grains.scd b/grains.scd index 8dd0d17..96ee03d 100644 --- a/grains.scd +++ b/grains.scd @@ -9,53 +9,11 @@ Server.killAll; ~frippbuffer.isNil; -( -SynthDef( - \fripp_record, - { - arg in = 2, buffer = 0, mix = 0.25, record = 0.0; - var insig = record * In.ar(in, 1); - RecordBuf.ar(insig, buffer, 0, mix, 1 - mix, loop: 1) - } -).add; -SynthDef( - \grainsynth, - { - arg out=0, buffer, blen, pitchb, triggerb, posb, modb, size=0.1, amp=0.5, pan=0, track=0.25, jitter=0, blur=0.0; - var pitch, trigger, chor, pos, pans, grains, filtfreq; - trigger = In.kr(triggerb); - pitch = In.kr(pitchb); - pos = Wrap.kr(In.kr(posb, 1) + WhiteNoise.kr(blur), 0, 1); - pans = pan + WhiteNoise.kr(jitter) + (track * (In.kr(posb, 1) - 1)); - grains = TGrains.ar(2, trigger, buffer, pitch, pos * blen, size, pans, amp); - Out.ar(out, grains); - } -).add; -) - -( - -~ntracks = 4; - -~makebuffers = { - if( ~frippbuffers.isNil.not, { - ~frippbuffers.do({ |b| b.free }); - ~frippbuffers.free; - }); - - ~frippbuffers = Array.new(~ntracks); - - ~currentfripp = 0; - - (1..~ntracks).do( { |i| - ~frippbuffers.add(Buffer.alloc(s, s.sampleRate * ~buflen, 1)); - }); -}; - +( ~to = TouchOSC("192.168.0.209", 9000); ~usbinput = 2; @@ -241,9 +199,17 @@ fork { ).play(s, [ \out, ~pitchb, \triggerb, ~triggerb, \posb, ~playbacklfob, \dir, 1, \track, 0]); +) + +s +Granulator.init(s) + +~g3 = Granulator.new(4, ~recordb, ~granulatorb, ~playbacklfob, ~triggerb, ~pitchb); + +~g.recorder.set(\record, 1.0); ~makebuffers.value(); - +( ~bufrecorders = Array.new(~ntracks); ~frippbuffers.do({ @@ -288,6 +254,8 @@ fork { ~granulator = ~granulators[0]; +) +( // mixing and effects ~fxb = Bus.audio(s, 2); @@ -361,7 +329,6 @@ fork { ) -// why can't this all be in the same block? ( From 0b589bc0928ea738844c9bf44a3bf86bd8d07c25 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 9 Apr 2023 11:42:17 +1000 Subject: [PATCH 05/19] Effects into separate files --- effects.scd | 73 +++++++++++++++++++++++++++++++++++++++++++++++ input_effects.scd | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 effects.scd create mode 100644 input_effects.scd diff --git a/effects.scd b/effects.scd new file mode 100644 index 0000000..85508cc --- /dev/null +++ b/effects.scd @@ -0,0 +1,73 @@ + + +( +// output effects mixing and effects + +~fxb = Bus.audio(s, 2); +~filterb = Bus.audio(s, 2); +~grainsb = Bus.audio(s, 2); +~delayb = Bus.audio(s, 2); +~reverbb = Bus.audio(s, 2); + + + +~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)); + } +).play(s, [\in, ~usbinput, \gbus, ~granulatorb, \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); + + + + + + +// delay always passes through 100% of its input + amp % of the delay + + +~delay = SynthDef( + \delay, { + arg in, out, maxdelay=1, delaytime=0.2, decaytime=0.1, amp=0.5; + var sig = In.ar(in, 2), del; + del = CombC.ar(sig, maxdelay, delaytime, decaytime, amp); + Out.ar(out, sig + del); + } + ).play(s, [ \in, ~filterb, \out, ~delayb ], \addToTail); + +// try taking out the reverb because I think it causes noises + + ~reverb = SynthDef( + \reverb, { + arg in, out, mix=0.33, room=0.5, damp=0.5, amp=0.25; + var input = In.ar(in, 2); + Out.ar(out, input + FreeVerb2.ar(input[0], input[1], mix, room, damp, amp)); + } + ).play(s, [ \in, ~delayb, \out, 0 ], \addToTail); + +) diff --git a/input_effects.scd b/input_effects.scd new file mode 100644 index 0000000..dcadd80 --- /dev/null +++ b/input_effects.scd @@ -0,0 +1,53 @@ +( + +~fuzzbox = SynthDef( + \fuzzbox, + { + arg in=2, out=4, distort=0.1, decay=0.999; + var raw, cross, pf; + raw = In.ar(in, 1).softclip; + cross = CrossoverDistortion.ar(raw, 0.5, 0.5); + pf = PeakFollower.ar(raw, decay); + Out.ar(out, ((1 - distort) * raw) + (distort * pf * cross)); + } +).play(s, [\in, ~usbinput, \out, ~recordb, \distort, 0 ]); + +// ~decimator = SynthDef( +// \decimator, +// { +// arg in=2, out=4, modb, rate=10000, smooth=0.5; +// var raw, mod, decimated; +// raw = In.ar(in, 1); +// mod = In.kr (modb, 1); +// decimated = SmoothDecimator.ar(raw, rate + (0.2 * rate * mod), smooth); +// Out.ar(out, decimated); +// } +// ).play(s, [\in, ~usbinput, \out, ~recordb, \modb, ~lfob, \rate, 10000 ]); +// + +// ~localmax = SynthDef( +// \localmax, +// { +// arg in=2, out=4, threshold=25; +// var chain; +// chain = FFT(LocalBuf(2048), In.ar(in, 1).distort); +// chain = PV_LocalMax(chain, threshold); +// Out.ar(out, IFFT.ar(chain)); +// } +// ).play(s, [\in, ~usbinput, \out, ~recordb, \threshold, 25 ]); +// + +// ~scramble = SynthDef( +// \scramble, +// { +// arg in=2, out=4, shift=1; +// var chain; +// chain = FFT(LocalBuf(2048), In.ar(in, 1).distort); +// chain = PV_BinScramble(chain, 0.5, 0.2, Impulse.kr(shift)); +// Out.ar(out, IFFT.ar(chain)); +// } +// ).play(s, [\in, ~usbinput, \out, ~recordb, \shift, 1 ]); +// + + +) \ No newline at end of file From 30202f3add2d441b63d59d9f048fb815f91dd533 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 9 Apr 2023 11:46:05 +1000 Subject: [PATCH 06/19] Split more stuff out --- control.scd | 64 +++++++++++++ grains.scd | 271 ++++++++++++---------------------------------------- synths.scd | 46 +++++++++ 3 files changed, 169 insertions(+), 212 deletions(-) create mode 100644 control.scd create mode 100644 synths.scd diff --git a/control.scd b/control.scd new file mode 100644 index 0000000..9944f15 --- /dev/null +++ b/control.scd @@ -0,0 +1,64 @@ + +( +// audio buses and other control stuff + +// recordb = input to bufrecorder + + +~recordb = Bus.audio(s, 1); + +~inmixer = SynthDef( + \input_null, + { + arg in1 = 2, in2 = 3, out = 4; + Out.ar(out, In.ar(in1) + In.ar(in2)); + } +).play(s, [\in1, ~usbinput1, \in2, ~usbinput2, \out, ~recordb]); + +~granulatorb = Bus.audio(s, 2); + +// LFO buses and synths + +~lfoab = Bus.control(s, 1); +~lfobb = Bus.control(s, 1); +~lfocb = Bus.control(s, 1); + +~lfoa = Synth(\lfo, [\out, ~lfoab ]); +~lfob = Synth(\lfo, [\out, ~lfobb ]); +~lfoc = Synth(\lfo, [\out, ~lfocb ]); + +// a kr synth which triggers grains + +~triggerb = Bus.control(s, 1); + +~trigger = SynthDef( + \trigger, + { + arg out, freq=1, dust=0; + Out.kr(out, (Impulse.kr(freq) * (1 - dust)) + (Dust.kr(freq) * dust)); +} +).play(s, [ \out, ~triggerb, \freq, 120, \dust, 0 ]); + + + +// a kr synth which is used to control the granulator +// playback rate. + +~pitchb = Bus.control(s, 1); + +~pitch = SynthDef( + \pitch, + { + arg out, posb, triggerb, track=1, dir=1, detune=0.0, chorus=0, harmonics=2, pitch=0; + var tracking, base, chor, det, csig, dsig; + csig = Latch.kr(WhiteNoise.kr(), In.kr(triggerb)); + dsig = Latch.kr(WhiteNoise.kr(), In.kr(triggerb)); + tracking = Schmidt.kr(Slope.kr(posb), 0, 0) * 2 - 1; + base = 2.pow(pitch) * dir * (track * tracking + (1 - track)); + det = detune * dsig + 1; + chor = chorus * harmonics.pow((csig * 2).round) + (1 - chorus); + Out.kr(out, base * chor * det); + } +).play(s, [ \out, ~pitchb, \triggerb, ~triggerb, \posb, ~playbacklfob, \dir, 1, \track, 0]); + +) diff --git a/grains.scd b/grains.scd index 96ee03d..4f6fb34 100644 --- a/grains.scd +++ b/grains.scd @@ -9,123 +9,71 @@ Server.killAll; ~frippbuffer.isNil; - - - - ( ~to = TouchOSC("192.168.0.209", 9000); ~usbinput = 2; - ~usbinput1 = 2; - ~usbinput2 = 3; - ~buflen = 4.0; ~beatsperbar = 4; -// trying setting the playback LFOs before the controls +~posb0 = Bus.control(s, 1); +~posb1 = Bus.control(s, 1); +~posb2 = Bus.control(s, 1); +~posb3 = Bus.control(s, 1); -// granulator playback modes -// each of these is a control bus with a synth that drives the pattern -// the granulator mode control switches between them +SynthDef(\pos_sin, { + arg out, speed=1; + Out.kr(out, 0.5 + SinOsc.kr(speed * 0.5, 0, 0.5)); +}).add; -// more ideas for modules: scramble - do a permutation of ABCDEFGH slots +SynthDef(\pos_saw, { + arg out, speed=1; + Out.kr(out, 0.5 + LFSaw.kr(speed, 0, 0.5)); +}).add; -// todo - encapsulate these in a class +SynthDef(\pos_reverse, { + arg out, speed=1; + Out.kr(out, 0.5 - LFSaw.kr(speed, 0, 0.5)); +}).add; +SynthDef(\pos_step, { + arg out, speed=1, steps=8; + var stepwise = LFSaw.kr(speed, 0.0, 0.5 * steps, 0.5 * steps).floor; + Out.kr(out, stepwise / steps); +}).add; -~grainsinb = Bus.control(s, 1); +SynthDef(\pos_rand, { + arg out=5, speed=1; + Out.kr(out, 0.5 + WhiteNoise.kr(0.5)); +}).add; -~grainsin = SynthDef( - \grainsin, - { - arg out=5, speed=1; - Out.kr(out, 0.5 + SinOsc.kr(speed * 0.5, 0, 0.5)); - } -).play(s, [\out, ~grainsinb, \speed, 1]); - -~grainsawb = Bus.control(s, 1); - -~grainsaw = SynthDef( - \grainsaw, - { - arg out=5, speed=1; - Out.kr(out, 0.5 + LFSaw.kr(speed, 0, 0.5)); - } -).play(s, [\out, ~grainsawb, \speed, 1]); - -~grainreverseb = Bus.control(s, 1); - -~grainreverse = SynthDef( - \grainreverse, - { - arg out=5, speed=1; - Out.kr(out, 0.5 - LFSaw.kr(speed, 0, 0.5)); - } -).play(s, [\out, ~grainreverseb, \speed, 1]); - -~graintrib = Bus.control(s, 1); - -~graintri = SynthDef( - \graintri, - { - arg out=5, speed=1; - Out.kr(out, 0.5 + LFTri.kr(speed, 0, 0.5)); - } -).play(s, [\out, ~graintrib, \speed, 1]); - - -~grainstepb = Bus.control(s, 1); - -~grainstep = SynthDef( - \grainstep, - { - arg out=5, speed=1, steps=8; - var stepwise = LFSaw.kr(speed, 0.0, 0.5 * steps, 0.5 * steps).floor; - Out.kr(out, stepwise / steps); - } -).play(s, [\out, ~grainstepb, \speed, 1]); - - -~grainrandb = Bus.control(s, 1); - -~grainrand = SynthDef( - \grainrand, - { - arg out=5, speed=1; - Out.kr(out, 0.5 + WhiteNoise.kr(0.5)); - } -).play(s, [\out, ~grainrandb, \speed, 1]); +SynthDef( \lfo, { + arg out, freq=1, amp=0; + Out.kr(out, SinOsc.kr(freq, 0, amp)); +}).add; +) ~modes = [ - [ ~grainsaw, ~grainsawb, "saw" ], - [ ~grainreverse, ~grainreverseb, "reverse", ], - [ ~grainsin, ~grainsinb, "sine" ], - [ ~grainstep, ~grainstepb, "step" ], - [ ~grainrand, ~grainrandb, "random" ] + [ "saw", \pos_saw ], + [ "reverse", \pos_reverse ], + [ "sine", \pos_sine ], + [ "step", \pos_step ], + [ "random", \pos_rand ] ]; -~playbacklfo = ~modes[0][0]; -~playbacklfob = ~modes[0][1]; -// audio buses + +( +// audio buses and other control stuff // recordb = input to bufrecorder ~recordb = Bus.audio(s, 1); -// ~infilter = SynthDef( -// \input_null, -// { -// arg in = 2, out = 4; -// Out.ar(out, In.ar(in)); -// } -// ).play(s, [\in, ~usbinput, \out, ~recordb]); - ~inmixer = SynthDef( \input_null, { @@ -134,7 +82,6 @@ Server.killAll; } ).play(s, [\in1, ~usbinput1, \in2, ~usbinput2, \out, ~recordb]); - ~granulatorb = Bus.audio(s, 2); // LFO buses and synths @@ -143,26 +90,9 @@ Server.killAll; ~lfobb = Bus.control(s, 1); ~lfocb = Bus.control(s, 1); - -fork { - SynthDef( - \lfo, - { - arg out=5, freq=1, amp=0; - Out.kr(out, SinOsc.kr(freq, 0, amp)); - } - ).add; - - 1.wait; - - ~lfoa = Synth(\lfo, [\out, ~lfoab ]); - ~lfob = Synth(\lfo, [\out, ~lfobb ]); - ~lfoc = Synth(\lfo, [\out, ~lfocb ]); - "LFOs initialised".postln; -}; - - - +~lfoa = Synth(\lfo, [\out, ~lfoab ]); +~lfob = Synth(\lfo, [\out, ~lfobb ]); +~lfoc = Synth(\lfo, [\out, ~lfocb ]); // a kr synth which triggers grains @@ -201,7 +131,6 @@ fork { ) -s Granulator.init(s) ~g3 = Granulator.new(4, ~recordb, ~granulatorb, ~playbacklfob, ~triggerb, ~pitchb); @@ -254,78 +183,6 @@ Granulator.init(s) ~granulator = ~granulators[0]; -) -( -// mixing and effects - -~fxb = Bus.audio(s, 2); -~filterb = Bus.audio(s, 2); -~grainsb = Bus.audio(s, 2); -~delayb = Bus.audio(s, 2); -~reverbb = Bus.audio(s, 2); - -~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)); - } -).play(s, [\in, ~usbinput, \gbus, ~granulatorb, \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); - - - - - - -// delay always passes through 100% of its input + amp % of the delay - - -~delay = SynthDef( - \delay, { - arg in, out, maxdelay=1, delaytime=0.2, decaytime=0.1, amp=0.5; - var sig = In.ar(in, 2), del; - del = CombC.ar(sig, maxdelay, delaytime, decaytime, amp); - Out.ar(out, sig + del); - } - ).play(s, [ \in, ~filterb, \out, ~delayb ], \addToTail); - -// try taking out the reverb because I think it causes noises - - ~reverb = SynthDef( - \reverb, { - arg in, out, mix=0.33, room=0.5, damp=0.5, amp=0.25; - var input = In.ar(in, 2); - Out.ar(out, input + FreeVerb2.ar(input[0], input[1], mix, room, damp, amp)); - } - ).play(s, [ \in, ~delayb, \out, 0 ], \addToTail); - - ) @@ -340,15 +197,10 @@ OSCdef.freeAll; ~to.button('/reset', 0, { | v | if( v > 0, { - "TODO: rewrite this for multitrack".postln; - // var sp = ~to.v('/grains/speed')[0]; - // ~buflen = ~to.v('/grains/buflen'); - // [ "resetting buffers to", ~buflen ].postln; - // ~makebuffers.value(); - // ~granulator.set(\buffer, ~frippbuffers[~currentfripp]); - // ~bufrecorder.set(\buffer, ~frippbuffers[~currentfripp]); - // - // ~playbacklfo.set(\speed, sp / ~buflen); + var sp = ~to.v('/grains/speed')[0]; + ~buflen = ~to.v('/grains/buflen'); + ~granulators.do({|g, i| g.reset(~buflen) } + ~playbacklfo.set(\speed, sp / ~buflen); }); }); @@ -363,12 +215,12 @@ OSCdef.freeAll; ~bufrecorder.set(\record, ~to.v('/record')); ~granulator = ~granulators[v]; ~to.v_('/grainfx/mix', 0); // will always be 0 because we turned it off - ~granulator.get(\amp, { | v | ~to.v_('/grainfx/gain', v) }); - ~granulator.get(\blur, { | v | ~to.v_('/grains/blur', v) }); - ~granulator.get(\size, { | v | ~to.v_('/grains/size', v) }); - ~granulator.get(\pan, { | v | ~to.v_('/grainfx/pan', v) }); - ~granulator.get(\track, { | v | ~to.v_('/grainfx/track', v) }); - ~granulator.get(\jitter, { | v | ~to.v_('/grainfx/jitter', v) }); + // ~granulator.get(\amp, { | v | ~to.v_('/grainfx/gain', v) }); + // ~granulator.get(\blur, { | v | ~to.v_('/grains/blur', v) }); + // ~granulator.get(\size, { | v | ~to.v_('/grains/size', v) }); + // ~granulator.get(\pan, { | v | ~to.v_('/grainfx/pan', v) }); + // ~granulator.get(\track, { | v | ~to.v_('/grainfx/track', v) }); + // ~granulator.get(\jitter, { | v | ~to.v_('/grainfx/jitter', v) }); // todo - set the grainmode based on what this one has }, { [ "Bad track index", v ].postln; @@ -421,7 +273,7 @@ OSCdef.freeAll; var mode = ~modes[v]; if( mode.isNil.not, { [ "granulator is", ~granulator ].postln; - ~granulator.set(\posb, mode[1]); + ~granulator.posb_(mode[1]); ~playbacklfo = mode[0]; ~playbacklfob = mode[1]; ~playbacklfo.set(\speed, ~to.v('/grains/speed')[0] / ~buflen); @@ -440,26 +292,21 @@ OSCdef.freeAll; ~to.button('/grains/dust', 0, { |v| ~trigger.set(\dust, v) }); -~to.slider('/grains/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.set(\blur, v) }); - - -~to.slider('/grains/size', 0.1, TouchOSCScale(0, 0.5),{ - |v| ~granulator.set(\size, v) -}); +~to.slider('/grains/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.blur_(v) }); +~to.slider('/grains/size', 0.1, TouchOSCScale(0, 0.5),{ |v| ~granulator.size_(v) }); // Page 2: grainfx -~to.slider('/grainfx/mix', 0.25, TouchOSCScale(0, 1), { |v| - ~bufrecorder.set(\mix, v); +~to.slider('/grainfx/mix', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.mix_(v); }); -~to.slider('/grainfx/gain', 0.5, TouchOSCScale(0, 1), { |v| ~granulator.set(\amp, v) } ); +~to.slider('/grainfx/gain', 0.5, TouchOSCScale(0, 1), { |v| ~granulator.gain_(v) } ); ~to.slider('/grainfx/pt', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) } ); ~to.button('/grainfx/back', 0, { |v| ~pitch.set(\dir, if( v > 0, { -1 }, { 1}))}); ~to.button('/grainfx/slope', 1, { |v| ~pitch.set(\track, v) }); -~to.slider('/grainfx/pan', 0, TouchOSCScale(-1, 1), { |v| ~granulator.set(\pan, v) }); -~to.slider('/grainfx/track', 0.5, TouchOSCScale(-1, 1), { |v| ~granulator.set(\track, v) }); -~to.slider('/grainfx/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.set(\jitter, v) }); +~to.slider('/grainfx/pan', 0, TouchOSCScale(-1, 1), { |v| ~granulator.pan_(v) }); +~to.slider('/grainfx/track', 0.5, TouchOSCScale(-1, 1), { |v| ~granulator.track_(v) }); +~to.slider('/grainfx/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.jitter_(v) }); ~to.button('/grainfx/chorus', 0, { |v| ~pitch.set(\chorus, v) }); diff --git a/synths.scd b/synths.scd new file mode 100644 index 0000000..952caed --- /dev/null +++ b/synths.scd @@ -0,0 +1,46 @@ +( + +~usbinput = 2; +~usbinput1 = 2; +~usbinput2 = 3; + +~buflen = 4.0; +~beatsperbar = 4; + +~posb0 = Bus.control(s, 1); +~posb1 = Bus.control(s, 1); +~posb2 = Bus.control(s, 1); +~posb3 = Bus.control(s, 1); + +SynthDef(\pos_sin, { + arg out, speed=1; + Out.kr(out, 0.5 + SinOsc.kr(speed * 0.5, 0, 0.5)); +}).add; + +SynthDef(\pos_saw, { + arg out, speed=1; + Out.kr(out, 0.5 + LFSaw.kr(speed, 0, 0.5)); +}).add; + +SynthDef(\pos_reverse, { + arg out, speed=1; + Out.kr(out, 0.5 - LFSaw.kr(speed, 0, 0.5)); +}).add; + +SynthDef(\pos_step, { + arg out, speed=1, steps=8; + var stepwise = LFSaw.kr(speed, 0.0, 0.5 * steps, 0.5 * steps).floor; + Out.kr(out, stepwise / steps); +}).add; + +SynthDef(\pos_rand, { + arg out=5, speed=1; + Out.kr(out, 0.5 + WhiteNoise.kr(0.5)); +}).add; + +SynthDef( \lfo, { + arg out, freq=1, amp=0; + Out.kr(out, SinOsc.kr(freq, 0, amp)); +}).add; + +) From 0b91c0dc9e000105f83547acdf7a5dbecc7a78b7 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 9 Apr 2023 11:46:19 +1000 Subject: [PATCH 07/19] grains -> main --- grains.scd => main.scd | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename grains.scd => main.scd (100%) diff --git a/grains.scd b/main.scd similarity index 100% rename from grains.scd rename to main.scd From e32a30b6fcf48c4b2a36e9ee40f059146ad9eae4 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 9 Apr 2023 11:48:46 +1000 Subject: [PATCH 08/19] added .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store From 7b8fde4afc58e2d2deda3d16d007ab6e4b8f62cd Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 9 Apr 2023 12:12:36 +1000 Subject: [PATCH 09/19] TouchOSC stuff to interface.scd --- interface.scd | 186 +++++++++++++++++++++++++++++ main.scd | 316 +------------------------------------------------- 2 files changed, 189 insertions(+), 313 deletions(-) create mode 100644 interface.scd diff --git a/interface.scd b/interface.scd new file mode 100644 index 0000000..a942b59 --- /dev/null +++ b/interface.scd @@ -0,0 +1,186 @@ +( +~to = TouchOSC("192.168.0.209", 9000); + + +OSCdef.freeAll; + +~to.button('/record', 1, { | v | ~bufrecorder.set(\record, v) }); + + +~to.button('/reset', 0, { | v | + if( v > 0, { + var sp = ~to.v('/grains/speed')[0]; + ~buflen = ~to.v('/grains/buflen'); + ~granulators.do({|g, i| g.reset(~buflen) } + ~playbacklfo.set(\speed, sp / ~buflen); + }); +}); + + +~to.button('/track', 0, { |v| + var buffer = ~frippbuffers[v]; + if( buffer.isNil.not, { + [ "set track to", v, buffer ].postln; + ~bufrecorder.set(\record, 0.0); + ~bufrecorder.set(\mix, 0.0); // stop unselected track fading out + ~bufrecorder = ~bufrecorders[v]; + ~bufrecorder.set(\record, ~to.v('/record')); + ~granulator = ~granulators[v]; + ~to.v_('/grainfx/mix', 0); // will always be 0 because we turned it off + // ~granulator.get(\amp, { | v | ~to.v_('/grainfx/gain', v) }); + // ~granulator.get(\blur, { | v | ~to.v_('/grains/blur', v) }); + // ~granulator.get(\size, { | v | ~to.v_('/grains/size', v) }); + // ~granulator.get(\pan, { | v | ~to.v_('/grainfx/pan', v) }); + // ~granulator.get(\track, { | v | ~to.v_('/grainfx/track', v) }); + // ~granulator.get(\jitter, { | v | ~to.v_('/grainfx/jitter', v) }); + // todo - set the grainmode based on what this one has + }, { + [ "Bad track index", v ].postln; + }); +}); + + + +~to.slider('/feedback', 0, TouchOSCScale(0, 0.25), { |v| + ~bufrecorder.set(\feedback, v) } ); + +~to.button('/grains/bpm', "~", {}); + +~tapper = TapBeats(); + +~to.button('/grains/tap', 0, { | v, t | + if( v > 0, { + ~tapper.tap(t); + if( ~tapper.bpm.isNil.not, { + ~to.v_('/grains/bpm', ~tapper.bpm.round(1)); + }) + }) +}); + + +~to.button('/grains/bpmsend', 0, { | v | + if( ~tapper.bpm.isNil.not, { + var bl = ~beatsperbar * ~tapper.bpm; + ~to.v_('/grains/buflen', bl); + ~to.v_('/reset', 1); + }); +}); + +// 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), {}); + + +// this is a write-only control to display where the buffer playback is at + +~to.slider('/grains/buffer', 0, TouchOSCScale(0, 1), {}); + +~to.xy('/grains/speed', [ 1, 120 ], TouchOSCScale(0, 2), TouchOSCScale(0, 640), { | v | + ~playbacklfo.set(\speed, v[0] / ~buflen); + ~trigger.set(\freq, v[1]); +}); + +~to.button('/grains/mode', 0, { |v| + var mode = ~modes[v]; + if( mode.isNil.not, { + [ "granulator is", ~granulator ].postln; + ~granulator.posb_(mode[1]); + ~playbacklfo = mode[0]; + ~playbacklfob = mode[1]; + ~playbacklfo.set(\speed, ~to.v('/grains/speed')[0] / ~buflen); + }, { + [ "Bad mode index", v ].postln; + }); +}); + +~to.button('/grains/speedquant', 0, { |v| +}); + +~to.slider('/grains/step', 4, TouchOSCScale(1, 8), { |v| + ~grainstep.set(\steps, v.floor); +}); + + + +~to.button('/grains/dust', 0, { |v| ~trigger.set(\dust, v) }); +~to.slider('/grains/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.blur_(v) }); +~to.slider('/grains/size', 0.1, TouchOSCScale(0, 0.5),{ |v| ~granulator.size_(v) }); + +// Page 2: grainfx + +~to.slider('/grainfx/mix', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.mix_(v); +}); +~to.slider('/grainfx/gain', 0.5, TouchOSCScale(0, 1), { |v| ~granulator.gain_(v) } ); +~to.slider('/grainfx/pt', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) } ); + +~to.button('/grainfx/back', 0, { |v| ~pitch.set(\dir, if( v > 0, { -1 }, { 1}))}); +~to.button('/grainfx/slope', 1, { |v| ~pitch.set(\track, v) }); +~to.slider('/grainfx/pan', 0, TouchOSCScale(-1, 1), { |v| ~granulator.pan_(v) }); +~to.slider('/grainfx/track', 0.5, TouchOSCScale(-1, 1), { |v| ~granulator.track_(v) }); +~to.slider('/grainfx/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.jitter_(v) }); + + +~to.button('/grainfx/chorus', 0, { |v| ~pitch.set(\chorus, v) }); +~to.slider('/grainfx/detune', 0, TouchOSCScale(0, 0.059), { |v| ~pitch.set(\detune, v) }); +~to.slider('/grainfx/pitch', 0, TouchOSCScale(-2, 2), { |v| ~pitch.set(\pitch, v.round) }); + +~to.button('/grainfx/quant', 1, { |v| + // ~pitch.set(\quant, v); + // just re-call the value setter for harmonics when toggled + ~to.v_('/grainfx/harmonics', ~to.v('/grainfx/harmonics')); +}); + +~to.slider('/grainfx/harmonics', 2, TouchOSCScale(0.1, 4), { |v| + if(~to.v('/grainfx/quant') > 0, { + ~pitch.set(\harmonics, v.round); + }, + { + ~pitch.set(\harmonics, v); + }); +}); + + +~to.slider( + '/fx/filterfreq', + 10000, TouchOSCScaleExp(100, 10000), { |v| ~filter.set(\freq, v) } +); + +~to.slider('/fx/grainmix', 1.0, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\grains, v) } ); + + +~to.slider('/fx/filtermix', 0.8, TouchOSCScale(0, 1), { |v| ~filter.set(\amp, v) } ); + +~to.button('/fx/filtermoda', 1, { |v| ~filtermod.set(\a, v) }); +~to.button('/fx/filtermodb', 0, { |v| ~filtermod.set(\b, v) }); +~to.button('/fx/filtermodc', 0, { |v| ~filtermod.set(\c, v) }); + + +~to.slider('/fx/delay', 0.2,TouchOSCScale(0, 1), { |v| ~delay.set(\delaytime, v) } ); +~to.slider('/fx/decay', 1, TouchOSCScale(0, 5), { |v| ~delay.set(\decaytime, v) } ); + +~to.slider('/fx/delaymix', 0.2, TouchOSCScale(0, 1), { |v| ~delay.set(\amp, v) } ); + + +~to.slider('/fx/reverbwet', 0.33,TouchOSCScale(0, 1), { |v| ~reverb.set(\mix, v) } ); +~to.slider('/fx/reverbroom', 0.5,TouchOSCScale(0, 1), { |v| ~reverb.set(\room, v) } ); +~to.slider('/fx/reverbdamp', 0.5,TouchOSCScale(0, 1), { |v| ~reverb.set(\damp, v) } ); + +~to.slider('/fx/reverbmix', 0.2, TouchOSCScale(0, 1), { |v| ~reverb.set(\amp, v) } ); + + + +// note - the three LFOs have different rate ranges + +~to.slider('/lfos/afreq', 0.5,TouchOSCScale(0.001, 2), { |v| ~lfoa.set(\freq, v) } ); +~to.slider('/lfos/aamp', 0, TouchOSCScale(0, 1), { |v| ~lfoa.set(\amp, v) }); + +~to.slider('/lfos/bfreq', 0.5,TouchOSCScale(0.01, 20), { |v| ~lfob.set(\freq, v) } ); +~to.slider('/lfos/bamp', 0, TouchOSCScale(0, 1), { |v| ~lfob.set(\amp, v) }); + +~to.slider('/lfos/cfreq', 0.5,TouchOSCScale(0.1, 200), { |v| ~lfoc.set(\freq, v) } ); +~to.slider('/lfos/camp', 0, TouchOSCScale(0, 1), { |v| ~lfoc.set(\amp, v) }); + + +) + diff --git a/main.scd b/main.scd index 4f6fb34..ad48d70 100644 --- a/main.scd +++ b/main.scd @@ -9,53 +9,9 @@ Server.killAll; ~frippbuffer.isNil; -( -~to = TouchOSC("192.168.0.209", 9000); - -~usbinput = 2; -~usbinput1 = 2; -~usbinput2 = 3; - -~buflen = 4.0; -~beatsperbar = 4; - -~posb0 = Bus.control(s, 1); -~posb1 = Bus.control(s, 1); -~posb2 = Bus.control(s, 1); -~posb3 = Bus.control(s, 1); - -SynthDef(\pos_sin, { - arg out, speed=1; - Out.kr(out, 0.5 + SinOsc.kr(speed * 0.5, 0, 0.5)); -}).add; - -SynthDef(\pos_saw, { - arg out, speed=1; - Out.kr(out, 0.5 + LFSaw.kr(speed, 0, 0.5)); -}).add; - -SynthDef(\pos_reverse, { - arg out, speed=1; - Out.kr(out, 0.5 - LFSaw.kr(speed, 0, 0.5)); -}).add; - -SynthDef(\pos_step, { - arg out, speed=1, steps=8; - var stepwise = LFSaw.kr(speed, 0.0, 0.5 * steps, 0.5 * steps).floor; - Out.kr(out, stepwise / steps); -}).add; - -SynthDef(\pos_rand, { - arg out=5, speed=1; - Out.kr(out, 0.5 + WhiteNoise.kr(0.5)); -}).add; - -SynthDef( \lfo, { - arg out, freq=1, amp=0; - Out.kr(out, SinOsc.kr(freq, 0, amp)); -}).add; - -) +("./synths.scd").loadRelative; +("./control.scd").loadRelative; +("./effects.scd").loadRelative; ~modes = [ [ "saw", \pos_saw ], @@ -66,70 +22,6 @@ SynthDef( \lfo, { ]; -( -// audio buses and other control stuff - -// recordb = input to bufrecorder - - -~recordb = Bus.audio(s, 1); - -~inmixer = SynthDef( - \input_null, - { - arg in1 = 2, in2 = 3, out = 4; - Out.ar(out, In.ar(in1) + In.ar(in2)); - } -).play(s, [\in1, ~usbinput1, \in2, ~usbinput2, \out, ~recordb]); - -~granulatorb = Bus.audio(s, 2); - -// LFO buses and synths - -~lfoab = Bus.control(s, 1); -~lfobb = Bus.control(s, 1); -~lfocb = Bus.control(s, 1); - -~lfoa = Synth(\lfo, [\out, ~lfoab ]); -~lfob = Synth(\lfo, [\out, ~lfobb ]); -~lfoc = Synth(\lfo, [\out, ~lfocb ]); - -// a kr synth which triggers grains - -~triggerb = Bus.control(s, 1); - -~trigger = SynthDef( - \trigger, - { - arg out, freq=1, dust=0; - Out.kr(out, (Impulse.kr(freq) * (1 - dust)) + (Dust.kr(freq) * dust)); -} -).play(s, [ \out, ~triggerb, \freq, 120, \dust, 0 ]); - - - -// a kr synth which is used to control the granulator -// playback rate. - -~pitchb = Bus.control(s, 1); - -~pitch = SynthDef( - \pitch, - { - arg out, posb, triggerb, track=1, dir=1, detune=0.0, chorus=0, harmonics=2, pitch=0; - var tracking, base, chor, det, csig, dsig; - csig = Latch.kr(WhiteNoise.kr(), In.kr(triggerb)); - dsig = Latch.kr(WhiteNoise.kr(), In.kr(triggerb)); - tracking = Schmidt.kr(Slope.kr(posb), 0, 0) * 2 - 1; - base = 2.pow(pitch) * dir * (track * tracking + (1 - track)); - det = detune * dsig + 1; - chor = chorus * harmonics.pow((csig * 2).round) + (1 - chorus); - Out.kr(out, base * chor * det); - } -).play(s, [ \out, ~pitchb, \triggerb, ~triggerb, \posb, ~playbacklfob, \dir, 1, \track, 0]); - - -) Granulator.init(s) @@ -187,208 +79,6 @@ Granulator.init(s) -( - - -OSCdef.freeAll; - -~to.button('/record', 1, { | v | ~bufrecorder.set(\record, v) }); - - -~to.button('/reset', 0, { | v | - if( v > 0, { - var sp = ~to.v('/grains/speed')[0]; - ~buflen = ~to.v('/grains/buflen'); - ~granulators.do({|g, i| g.reset(~buflen) } - ~playbacklfo.set(\speed, sp / ~buflen); - }); -}); - - -~to.button('/track', 0, { |v| - var buffer = ~frippbuffers[v]; - if( buffer.isNil.not, { - [ "set track to", v, buffer ].postln; - ~bufrecorder.set(\record, 0.0); - ~bufrecorder.set(\mix, 0.0); // stop unselected track fading out - ~bufrecorder = ~bufrecorders[v]; - ~bufrecorder.set(\record, ~to.v('/record')); - ~granulator = ~granulators[v]; - ~to.v_('/grainfx/mix', 0); // will always be 0 because we turned it off - // ~granulator.get(\amp, { | v | ~to.v_('/grainfx/gain', v) }); - // ~granulator.get(\blur, { | v | ~to.v_('/grains/blur', v) }); - // ~granulator.get(\size, { | v | ~to.v_('/grains/size', v) }); - // ~granulator.get(\pan, { | v | ~to.v_('/grainfx/pan', v) }); - // ~granulator.get(\track, { | v | ~to.v_('/grainfx/track', v) }); - // ~granulator.get(\jitter, { | v | ~to.v_('/grainfx/jitter', v) }); - // todo - set the grainmode based on what this one has - }, { - [ "Bad track index", v ].postln; - }); -}); - - - -~to.slider('/feedback', 0, TouchOSCScale(0, 0.25), { |v| - ~bufrecorder.set(\feedback, v) } ); - -~to.button('/grains/bpm', "~", {}); - -~tapper = TapBeats(); - -~to.button('/grains/tap', 0, { | v, t | - if( v > 0, { - ~tapper.tap(t); - if( ~tapper.bpm.isNil.not, { - ~to.v_('/grains/bpm', ~tapper.bpm.round(1)); - }) - }) -}); - - -~to.button('/grains/bpmsend', 0, { | v | - if( ~tapper.bpm.isNil.not, { - var bl = ~beatsperbar * ~tapper.bpm; - ~to.v_('/grains/buflen', bl); - ~to.v_('/reset', 1); - }); -}); - -// 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), {}); - - -// this is a write-only control to display where the buffer playback is at - -~to.slider('/grains/buffer', 0, TouchOSCScale(0, 1), {}); - -~to.xy('/grains/speed', [ 1, 120 ], TouchOSCScale(0, 2), TouchOSCScale(0, 640), { | v | - ~playbacklfo.set(\speed, v[0] / ~buflen); - ~trigger.set(\freq, v[1]); -}); - -~to.button('/grains/mode', 0, { |v| - var mode = ~modes[v]; - if( mode.isNil.not, { - [ "granulator is", ~granulator ].postln; - ~granulator.posb_(mode[1]); - ~playbacklfo = mode[0]; - ~playbacklfob = mode[1]; - ~playbacklfo.set(\speed, ~to.v('/grains/speed')[0] / ~buflen); - }, { - [ "Bad mode index", v ].postln; - }); -}); - -~to.button('/grains/speedquant', 0, { |v| -}); - -~to.slider('/grains/step', 4, TouchOSCScale(1, 8), { |v| - ~grainstep.set(\steps, v.floor); -}); - - - -~to.button('/grains/dust', 0, { |v| ~trigger.set(\dust, v) }); -~to.slider('/grains/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.blur_(v) }); -~to.slider('/grains/size', 0.1, TouchOSCScale(0, 0.5),{ |v| ~granulator.size_(v) }); - -// Page 2: grainfx - -~to.slider('/grainfx/mix', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.mix_(v); -}); -~to.slider('/grainfx/gain', 0.5, TouchOSCScale(0, 1), { |v| ~granulator.gain_(v) } ); -~to.slider('/grainfx/pt', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) } ); - -~to.button('/grainfx/back', 0, { |v| ~pitch.set(\dir, if( v > 0, { -1 }, { 1}))}); -~to.button('/grainfx/slope', 1, { |v| ~pitch.set(\track, v) }); -~to.slider('/grainfx/pan', 0, TouchOSCScale(-1, 1), { |v| ~granulator.pan_(v) }); -~to.slider('/grainfx/track', 0.5, TouchOSCScale(-1, 1), { |v| ~granulator.track_(v) }); -~to.slider('/grainfx/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.jitter_(v) }); - - -~to.button('/grainfx/chorus', 0, { |v| ~pitch.set(\chorus, v) }); -~to.slider('/grainfx/detune', 0, TouchOSCScale(0, 0.059), { |v| ~pitch.set(\detune, v) }); -~to.slider('/grainfx/pitch', 0, TouchOSCScale(-2, 2), { |v| ~pitch.set(\pitch, v.round) }); - -~to.button('/grainfx/quant', 1, { |v| - // ~pitch.set(\quant, v); - // just re-call the value setter for harmonics when toggled - ~to.v_('/grainfx/harmonics', ~to.v('/grainfx/harmonics')); -}); - -~to.slider('/grainfx/harmonics', 2, TouchOSCScale(0.1, 4), { |v| - if(~to.v('/grainfx/quant') > 0, { - ~pitch.set(\harmonics, v.round); - }, - { - ~pitch.set(\harmonics, v); - }); -}); - - -~to.slider( - '/fx/filterfreq', - 10000, TouchOSCScaleExp(100, 10000), { |v| ~filter.set(\freq, v) } -); - -~to.slider('/fx/grainmix', 1.0, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\grains, v) } ); - - -~to.slider('/fx/filtermix', 0.8, TouchOSCScale(0, 1), { |v| ~filter.set(\amp, v) } ); - -~to.button('/fx/filtermoda', 1, { |v| ~filtermod.set(\a, v) }); -~to.button('/fx/filtermodb', 0, { |v| ~filtermod.set(\b, v) }); -~to.button('/fx/filtermodc', 0, { |v| ~filtermod.set(\c, v) }); - - -~to.slider('/fx/delay', 0.2,TouchOSCScale(0, 1), { |v| ~delay.set(\delaytime, v) } ); -~to.slider('/fx/decay', 1, TouchOSCScale(0, 5), { |v| ~delay.set(\decaytime, v) } ); - -~to.slider('/fx/delaymix', 0.2, TouchOSCScale(0, 1), { |v| ~delay.set(\amp, v) } ); - - -~to.slider('/fx/reverbwet', 0.33,TouchOSCScale(0, 1), { |v| ~reverb.set(\mix, v) } ); -~to.slider('/fx/reverbroom', 0.5,TouchOSCScale(0, 1), { |v| ~reverb.set(\room, v) } ); -~to.slider('/fx/reverbdamp', 0.5,TouchOSCScale(0, 1), { |v| ~reverb.set(\damp, v) } ); - -~to.slider('/fx/reverbmix', 0.2, TouchOSCScale(0, 1), { |v| ~reverb.set(\amp, v) } ); - - - -// note - the three LFOs have different rate ranges - -~to.slider('/lfos/afreq', 0.5,TouchOSCScale(0.001, 2), { |v| ~lfoa.set(\freq, v) } ); -~to.slider('/lfos/aamp', 0, TouchOSCScale(0, 1), { |v| ~lfoa.set(\amp, v) }); - -~to.slider('/lfos/bfreq', 0.5,TouchOSCScale(0.01, 20), { |v| ~lfob.set(\freq, v) } ); -~to.slider('/lfos/bamp', 0, TouchOSCScale(0, 1), { |v| ~lfob.set(\amp, v) }); - -~to.slider('/lfos/cfreq', 0.5,TouchOSCScale(0.1, 200), { |v| ~lfoc.set(\freq, v) } ); -~to.slider('/lfos/camp', 0, TouchOSCScale(0, 1), { |v| ~lfoc.set(\amp, v) }); - - -) - -// old, slow buffer position display - to-do- this would be better in a GUI element -// on the laptop - -( - -~posdisplay = Task.new({ - { - ~playbacklfob.get({ | v | - ~to.v_('/grains/buffer', v) - }); - 0.02.wait; - }.loop; -}); - - -~posdisplay.start; -) From 735a1712ea313646b33dcbab957cc5be787482c2 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 9 Apr 2023 12:31:39 +1000 Subject: [PATCH 10/19] spare parts --- monitor.scd | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 monitor.scd diff --git a/monitor.scd b/monitor.scd new file mode 100644 index 0000000..4cac1fe --- /dev/null +++ b/monitor.scd @@ -0,0 +1,36 @@ +~frippbuffers[~currentfripp].write("/Users/mike/Music/SuperCollider Recordings/test.aiff"); + +~frippbuffer.write("/Users/mike/Music/SuperCollider Recordings/slow.aiff"); +~frippbuffer.isNil; + + +( +~monitor = SynthDef( + \monitor_synth, + { + arg in=2, out=0; + Out.ar(out, In.ar(in, 2)) + } +).play(s, [\in, ~fxb, \out, 0 ], \addToTail); + +) + +~monitor.set(\in, ~reverbb) + +~monitor.free + +~pitchb.scope() + +~frippbuffers.plot; + +~bufrecorder.set(\buffer, ~frippbuffers[1]); + + +~granulators[0].get(\buffer, {|v| v.postln}); + +( +~frippbuffers.do({ + |b, i| + b.write("/Users/mike/Music/SuperCollider Recordings/buffer" ++ i.asString ++ ".aiff"); +}); +) From dfc508ee02ebec284904202b02ebbbd9ba8dca10 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 9 Apr 2023 12:32:11 +1000 Subject: [PATCH 11/19] Multiple pb control synths working in basic ways --- control.scd | 2 +- effects.scd | 2 +- main.scd | 70 ++++++++++++++++++++++++++--------------------------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/control.scd b/control.scd index 9944f15..8600b70 100644 --- a/control.scd +++ b/control.scd @@ -15,7 +15,7 @@ } ).play(s, [\in1, ~usbinput1, \in2, ~usbinput2, \out, ~recordb]); -~granulatorb = Bus.audio(s, 2); +~grb = Bus.audio(s, 2); // LFO buses and synths diff --git a/effects.scd b/effects.scd index 85508cc..fbd7e39 100644 --- a/effects.scd +++ b/effects.scd @@ -17,7 +17,7 @@ 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)); } -).play(s, [\in, ~usbinput, \gbus, ~granulatorb, \out, ~fxb ], \addToTail); +).play(s, [\in, ~usbinput, \gbus, ~grb, \out, ~fxb ], \addToTail); ~filtermodb = Bus.control(s, 1); diff --git a/main.scd b/main.scd index ad48d70..dc582f8 100644 --- a/main.scd +++ b/main.scd @@ -5,14 +5,21 @@ Server.default.options.inDevice_("Scarlett 2i2 USB"); //Server.default.options.outDevice_("Scarlett 2i2 USB"); ) Server.killAll; -~frippbuffer.write("/Users/mike/Music/SuperCollider Recordings/slow.aiff"); -~frippbuffer.isNil; ("./synths.scd").loadRelative; ("./control.scd").loadRelative; ("./effects.scd").loadRelative; +Granulator.init(s); + + + + + +( +// set up four position buffers with synths + ~modes = [ [ "saw", \pos_saw ], [ "reverse", \pos_reverse ], @@ -21,9 +28,34 @@ Server.killAll; [ "random", \pos_rand ] ]; +~granulators = Array.new(4); +~posb = Array.new(4); +~possynth = Array.new(4); + +(0..3).do({ + var pb = Bus.control(s, 1), ps; + ~posb.add(pb); + ps = Synth(\pos_saw, [ \out, pb ]); + ~possynth.add(ps); +}); + +) + +( + +(0..3).do({ |i| + var pb = ~posb.at(i); + ~granulators.add(Granulator.new(~buflen, ~recordb, ~outb, pb, ~triggerb, ~pitchb)); +}); + +) + +~granulators[1].record(1.0); +~possynth[0].set(\speed,200); + +("./interface.scd").loadRelative; -Granulator.init(s) ~g3 = Granulator.new(4, ~recordb, ~granulatorb, ~playbacklfob, ~triggerb, ~pitchb); @@ -82,35 +114,3 @@ Granulator.init(s) -~frippbuffers[~currentfripp].write("/Users/mike/Music/SuperCollider Recordings/test.aiff"); - -( -~monitor = SynthDef( - \monitor_synth, - { - arg in=2, out=0; - Out.ar(out, In.ar(in, 2)) - } -).play(s, [\in, ~fxb, \out, 0 ], \addToTail); - -) - -~monitor.set(\in, ~reverbb) - -~monitor.free - -~pitchb.scope() - -~frippbuffers.plot; - -~bufrecorder.set(\buffer, ~frippbuffers[1]); - - -~granulators[0].get(\buffer, {|v| v.postln}); - -( -~frippbuffers.do({ - |b, i| - b.write("/Users/mike/Music/SuperCollider Recordings/buffer" ++ i.asString ++ ".aiff"); -}); -) From 7149bca2e327ec3f6bf315b3eb7dccaff5eb0c5c Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 9 Apr 2023 15:10:04 +1000 Subject: [PATCH 12/19] About half of the touchosc stuff is now working --- NOTES.md | 29 ++++++++ interface.scd | 189 ++++++++++++++++++++++---------------------------- main.scd | 79 +++++---------------- synths.scd | 9 +-- 4 files changed, 128 insertions(+), 178 deletions(-) diff --git a/NOTES.md b/NOTES.md index 25716a2..98f40a4 100644 --- a/NOTES.md +++ b/NOTES.md @@ -21,4 +21,33 @@ - modulate grain level in time with playback - sync LFOs to playback +TODO list - touchosch +URL TO SC +grains/buflen Y Y +grains/reset Y Y +grains/record0..3 Y Y +grains/mode0..3 Y Y +grains/speed0..3 Y Y +grains/dust Y Y +grains/slope Y Y +grains/back Y Y +grains/trigger Y Y +grains/speedlock +grains/speedquant +grains/mix0 Y +grains/mix1 Y +grains/mix2 Y +grains/mix3 Y + +trackselect + +track/record +track/mode +track/speed +track/size +track/blur +track/mix +track/pan +track/track +track/jitter \ No newline at end of file diff --git a/interface.scd b/interface.scd index a942b59..7cb5f45 100644 --- a/interface.scd +++ b/interface.scd @@ -4,67 +4,41 @@ OSCdef.freeAll; -~to.button('/record', 1, { | v | ~bufrecorder.set(\record, v) }); ~to.button('/reset', 0, { | v | if( v > 0, { var sp = ~to.v('/grains/speed')[0]; ~buflen = ~to.v('/grains/buflen'); - ~granulators.do({|g, i| g.reset(~buflen) } + ~granulators.do({|g, i| g.reset(~buflen) }); ~playbacklfo.set(\speed, sp / ~buflen); }); }); - -~to.button('/track', 0, { |v| - var buffer = ~frippbuffers[v]; - if( buffer.isNil.not, { - [ "set track to", v, buffer ].postln; - ~bufrecorder.set(\record, 0.0); - ~bufrecorder.set(\mix, 0.0); // stop unselected track fading out - ~bufrecorder = ~bufrecorders[v]; - ~bufrecorder.set(\record, ~to.v('/record')); - ~granulator = ~granulators[v]; - ~to.v_('/grainfx/mix', 0); // will always be 0 because we turned it off - // ~granulator.get(\amp, { | v | ~to.v_('/grainfx/gain', v) }); - // ~granulator.get(\blur, { | v | ~to.v_('/grains/blur', v) }); - // ~granulator.get(\size, { | v | ~to.v_('/grains/size', v) }); - // ~granulator.get(\pan, { | v | ~to.v_('/grainfx/pan', v) }); - // ~granulator.get(\track, { | v | ~to.v_('/grainfx/track', v) }); - // ~granulator.get(\jitter, { | v | ~to.v_('/grainfx/jitter', v) }); - // todo - set the grainmode based on what this one has - }, { - [ "Bad track index", v ].postln; - }); -}); + // ~to.button('/trackselect', 0, { |v| + // var buffer = ~frippbuffers[v]; + // if( buffer.isNil.not, { + // [ "set track to", v, buffer ].postln; + // ~bufrecorder.set(\record, 0.0); + // ~bufrecorder.set(\mix, 0.0); // stop unselected track fading out + // ~bufrecorder = ~bufrecorders[v]; + // ~bufrecorder.set(\record, ~to.v('/record')); + // ~granulator = ~granulators[v]; + // ~to.v_('/grainfx/mix', 0); // will always be 0 because we turned it off + // // ~granulator.get(\amp, { | v | ~to.v_('/grainfx/gain', v) }); + // // ~granulator.get(\blur, { | v | ~to.v_('/grains/blur', v) }); + // // ~granulator.get(\size, { | v | ~to.v_('/grains/size', v) }); + // // ~granulator.get(\pan, { | v | ~to.v_('/grainfx/pan', v) }); + // // ~granulator.get(\track, { | v | ~to.v_('/grainfx/track', v) }); + // // ~granulator.get(\jitter, { | v | ~to.v_('/grainfx/jitter', v) }); + // // todo - set the grainmode based on what this one has + // }, { + // [ "Bad track index", v ].postln; + // }); + // }); -~to.slider('/feedback', 0, TouchOSCScale(0, 0.25), { |v| - ~bufrecorder.set(\feedback, v) } ); - -~to.button('/grains/bpm', "~", {}); - -~tapper = TapBeats(); - -~to.button('/grains/tap', 0, { | v, t | - if( v > 0, { - ~tapper.tap(t); - if( ~tapper.bpm.isNil.not, { - ~to.v_('/grains/bpm', ~tapper.bpm.round(1)); - }) - }) -}); - - -~to.button('/grains/bpmsend', 0, { | v | - if( ~tapper.bpm.isNil.not, { - var bl = ~beatsperbar * ~tapper.bpm; - ~to.v_('/grains/buflen', bl); - ~to.v_('/reset', 1); - }); -}); // 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 @@ -72,75 +46,74 @@ OSCdef.freeAll; ~to.slider('/grains/buflen', ~buflen, TouchOSCScale(0.1, 10.0), {}); -// this is a write-only control to display where the buffer playback is at +~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.slider('/grains/buffer', 0, TouchOSCScale(0, 1), {}); +~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.xy('/grains/speed', [ 1, 120 ], TouchOSCScale(0, 2), TouchOSCScale(0, 640), { | v | - ~playbacklfo.set(\speed, v[0] / ~buflen); - ~trigger.set(\freq, v[1]); -}); +( +~to.slider('/grains/speed0', 1, TouchOSCScale(0, 2), { |v| ~possynths[0].set(\speed, v) }); +~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| ~possynths[1].set(\speed, v) }); +~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| ~possynths[2].set(\speed, v) }); +~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| ~possynths[3].set(\speed, v) }); +) -~to.button('/grains/mode', 0, { |v| - var mode = ~modes[v]; - if( mode.isNil.not, { - [ "granulator is", ~granulator ].postln; - ~granulator.posb_(mode[1]); - ~playbacklfo = mode[0]; - ~playbacklfob = mode[1]; - ~playbacklfo.set(\speed, ~to.v('/grains/speed')[0] / ~buflen); - }, { - [ "Bad mode index", v ].postln; - }); -}); +( +~to.slider('/grains/mix0', 0.5, TouchOSCScale(0, 1), { | v | ~granulators[0].gain(v) }); +~to.slider('/grains/mix1', 0.5, TouchOSCScale(0, 1),{ | v | ~granulators[1].gain(v) }); +~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/speedquant', 0, { |v| }); -~to.slider('/grains/step', 4, TouchOSCScale(1, 8), { |v| - ~grainstep.set(\steps, v.floor); -}); +~to.slider('/grains/trigger', 120, TouchOSCScale(0, 640), { |v| ~trigger.set(\freq, v) }); +~to.button('/grains/dust', 0, { |v| ~trigger.set(\dust, v) }); +~to.button('/grains/back', 0, { |v| ~pitch.set(\dir, if( v > 0, { -1 }, { 1}))}); +~to.button('/grains/slope', 1, { |v| ~pitch.set(\track, v) }); +) +// Page 2: track +// ~to.slider('/track/mix', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.mix_(v); +// }); -~to.button('/grains/dust', 0, { |v| ~trigger.set(\dust, v) }); -~to.slider('/grains/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.blur_(v) }); -~to.slider('/grains/size', 0.1, TouchOSCScale(0, 0.5),{ |v| ~granulator.size_(v) }); - -// Page 2: grainfx - -~to.slider('/grainfx/mix', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.mix_(v); -}); -~to.slider('/grainfx/gain', 0.5, TouchOSCScale(0, 1), { |v| ~granulator.gain_(v) } ); -~to.slider('/grainfx/pt', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) } ); - -~to.button('/grainfx/back', 0, { |v| ~pitch.set(\dir, if( v > 0, { -1 }, { 1}))}); -~to.button('/grainfx/slope', 1, { |v| ~pitch.set(\track, v) }); -~to.slider('/grainfx/pan', 0, TouchOSCScale(-1, 1), { |v| ~granulator.pan_(v) }); -~to.slider('/grainfx/track', 0.5, TouchOSCScale(-1, 1), { |v| ~granulator.track_(v) }); -~to.slider('/grainfx/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.jitter_(v) }); - - -~to.button('/grainfx/chorus', 0, { |v| ~pitch.set(\chorus, v) }); -~to.slider('/grainfx/detune', 0, TouchOSCScale(0, 0.059), { |v| ~pitch.set(\detune, v) }); -~to.slider('/grainfx/pitch', 0, TouchOSCScale(-2, 2), { |v| ~pitch.set(\pitch, v.round) }); - -~to.button('/grainfx/quant', 1, { |v| - // ~pitch.set(\quant, v); - // just re-call the value setter for harmonics when toggled - ~to.v_('/grainfx/harmonics', ~to.v('/grainfx/harmonics')); -}); - -~to.slider('/grainfx/harmonics', 2, TouchOSCScale(0.1, 4), { |v| - if(~to.v('/grainfx/quant') > 0, { - ~pitch.set(\harmonics, v.round); - }, - { - ~pitch.set(\harmonics, v); - }); -}); - + // ~to.slider('/grainfx/pan', 0, TouchOSCScale(-1, 1), { |v| ~granulator.pan_(v) }); + // ~to.slider('/grainfx/track', 0.5, TouchOSCScale(-1, 1), { |v| ~granulator.track_(v) }); + // ~to.slider('/grainfx/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.jitter_(v) }); + // + // + // ~to.slider('/grains/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.blur_(v) }); + // ~to.slider('/grains/size', 0.1, TouchOSCScale(0, 0.5),{ |v| ~granulator.size_(v) }); + // + // + // ~to.button('/grainfx/chorus', 0, { |v| ~pitch.set(\chorus, v) }); + // ~to.slider('/grainfx/detune', 0, TouchOSCScale(0, 0.059), { |v| ~pitch.set(\detune, v) }); + // ~to.slider('/grainfx/pitch', 0, TouchOSCScale(-2, 2), { |v| ~pitch.set(\pitch, v.round) }); + // + // ~to.button('/grainfx/quant', 1, { |v| + // // ~pitch.set(\quant, v); + // // just re-call the value setter for harmonics when toggled + // ~to.v_('/grainfx/harmonics', ~to.v('/grainfx/harmonics')); + // }); + // + // ~to.slider('/grainfx/harmonics', 2, TouchOSCScale(0.1, 4), { |v| + // if(~to.v('/grainfx/quant') > 0, { + // ~pitch.set(\harmonics, v.round); + // }, + // { + // ~pitch.set(\harmonics, v); + // }); + // }); +( ~to.slider( '/fx/filterfreq', 10000, TouchOSCScaleExp(100, 10000), { |v| ~filter.set(\freq, v) } diff --git a/main.scd b/main.scd index dc582f8..1007cca 100644 --- a/main.scd +++ b/main.scd @@ -13,10 +13,6 @@ Server.killAll; Granulator.init(s); - - - - ( // set up four position buffers with synths @@ -25,23 +21,20 @@ Granulator.init(s); [ "reverse", \pos_reverse ], [ "sine", \pos_sine ], [ "step", \pos_step ], - [ "random", \pos_rand ] + [ "random", \pos_random ] ]; ~granulators = Array.new(4); ~posb = Array.new(4); -~possynth = Array.new(4); +~possynths = Array.new(4); (0..3).do({ var pb = Bus.control(s, 1), ps; ~posb.add(pb); ps = Synth(\pos_saw, [ \out, pb ]); - ~possynth.add(ps); + ~possynths.add(ps); }); -) - -( (0..3).do({ |i| var pb = ~posb.at(i); @@ -50,64 +43,24 @@ Granulator.init(s); ) -~granulators[1].record(1.0); -~possynth[0].set(\speed,200); +( +~setmode = { + arg track, mode; + var synth = ~modes[mode][1]; + ~possynths[track].get(\speed, { | speed | + + ~possynths[track].free; + ~possynths[track] = Synth(synth, [\out, ~posb[track], \speed, speed]); + }); +} +) + +~granulators[0].gain(1); ("./interface.scd").loadRelative; -~g3 = Granulator.new(4, ~recordb, ~granulatorb, ~playbacklfob, ~triggerb, ~pitchb); - -~g.recorder.set(\record, 1.0); -~makebuffers.value(); - -( -~bufrecorders = Array.new(~ntracks); - -~frippbuffers.do({ - | buffer, index | - ~bufrecorders.add(Synth.new( - \fripp_record, - [ - \in, ~recordb, - \record, 0.0, - \buffer, buffer - ], - s, - \addToTail - )) -}); - -~bufrecorder = ~bufrecorders[0]; - -// the granulators - -~granulators = Array.new(~ntracks); -~grainmodes = Array.fill(~ntracks, 0); - -~frippbuffers.do({ - | buffer, index | - [ "Grain synth: ", buffer, index ].postln; - ~granulators.add(Synth.new( - \grainsynth, - [ - \out, ~granulatorb, - \buffer, buffer, - \blen, ~buflen, - \posb, ~playbacklfob, - \triggerb, ~triggerb, - \pitchb, ~pitchb, - \modb, ~lfob, - \size, 0.1 - ], - s - )) -}); - -~granulator = ~granulators[0]; - -) diff --git a/synths.scd b/synths.scd index 952caed..2ff256a 100644 --- a/synths.scd +++ b/synths.scd @@ -7,12 +7,7 @@ ~buflen = 4.0; ~beatsperbar = 4; -~posb0 = Bus.control(s, 1); -~posb1 = Bus.control(s, 1); -~posb2 = Bus.control(s, 1); -~posb3 = Bus.control(s, 1); - -SynthDef(\pos_sin, { +SynthDef(\pos_sine, { arg out, speed=1; Out.kr(out, 0.5 + SinOsc.kr(speed * 0.5, 0, 0.5)); }).add; @@ -33,7 +28,7 @@ SynthDef(\pos_step, { Out.kr(out, stepwise / steps); }).add; -SynthDef(\pos_rand, { +SynthDef(\pos_random, { arg out=5, speed=1; Out.kr(out, 0.5 + WhiteNoise.kr(0.5)); }).add; From dd1292f5bd45a4a349d8385b8d8cb31dd4d4d81c Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 9 Apr 2023 15:32:36 +1000 Subject: [PATCH 13/19] TouchOSC interface basics are all working --- interface.scd | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/interface.scd b/interface.scd index 7cb5f45..907a5cb 100644 --- a/interface.scd +++ b/interface.scd @@ -1,3 +1,5 @@ + + ( ~to = TouchOSC("192.168.0.209", 9000); @@ -10,8 +12,11 @@ OSCdef.freeAll; if( v > 0, { var sp = ~to.v('/grains/speed')[0]; ~buflen = ~to.v('/grains/buflen'); - ~granulators.do({|g, i| g.reset(~buflen) }); - ~playbacklfo.set(\speed, sp / ~buflen); + (0..3).do({|i| + var speed = ~to.v('/grains/speed' ++ i); + ~granulators[i].reset(~buflen); + ~possynths[i].set(\speed, speed / ~buflen); + }); }); }); @@ -55,23 +60,17 @@ OSCdef.freeAll; ~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| ~possynths[0].set(\speed, v) }); ~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| ~possynths[1].set(\speed, v) }); ~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| ~possynths[2].set(\speed, v) }); ~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| ~possynths[3].set(\speed, v) }); -) -( ~to.slider('/grains/mix0', 0.5, TouchOSCScale(0, 1), { | v | ~granulators[0].gain(v) }); ~to.slider('/grains/mix1', 0.5, TouchOSCScale(0, 1),{ | v | ~granulators[1].gain(v) }); ~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.slider('/grains/trigger', 120, TouchOSCScale(0, 640), { |v| ~trigger.set(\freq, v) }); @@ -79,7 +78,7 @@ OSCdef.freeAll; ~to.button('/grains/dust', 0, { |v| ~trigger.set(\dust, v) }); ~to.button('/grains/back', 0, { |v| ~pitch.set(\dir, if( v > 0, { -1 }, { 1}))}); ~to.button('/grains/slope', 1, { |v| ~pitch.set(\track, v) }); -) + // Page 2: track // ~to.slider('/track/mix', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.mix_(v); @@ -113,12 +112,12 @@ OSCdef.freeAll; // }); // }); -( ~to.slider( '/fx/filterfreq', 10000, TouchOSCScaleExp(100, 10000), { |v| ~filter.set(\freq, v) } ); + ~to.slider('/fx/grainmix', 1.0, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\grains, v) } ); From 0040840850497ba13bf2161b0ba01aeebc58cb31 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 9 Apr 2023 16:44:59 +1000 Subject: [PATCH 14/19] Track selection is just about not broken --- interface.scd | 119 ++++++++++++++++++++++++-------------------------- main.scd | 2 +- 2 files changed, 58 insertions(+), 63 deletions(-) diff --git a/interface.scd b/interface.scd index 907a5cb..6be15a2 100644 --- a/interface.scd +++ b/interface.scd @@ -1,8 +1,13 @@ +v = 1.0; + +v.asInt ( ~to = TouchOSC("192.168.0.209", 9000); +~speeds = [ 1, 1, 1, 1 ]; + OSCdef.freeAll; @@ -20,29 +25,23 @@ OSCdef.freeAll; }); }); - // ~to.button('/trackselect', 0, { |v| - // var buffer = ~frippbuffers[v]; - // if( buffer.isNil.not, { - // [ "set track to", v, buffer ].postln; - // ~bufrecorder.set(\record, 0.0); - // ~bufrecorder.set(\mix, 0.0); // stop unselected track fading out - // ~bufrecorder = ~bufrecorders[v]; - // ~bufrecorder.set(\record, ~to.v('/record')); - // ~granulator = ~granulators[v]; - // ~to.v_('/grainfx/mix', 0); // will always be 0 because we turned it off - // // ~granulator.get(\amp, { | v | ~to.v_('/grainfx/gain', v) }); - // // ~granulator.get(\blur, { | v | ~to.v_('/grains/blur', v) }); - // // ~granulator.get(\size, { | v | ~to.v_('/grains/size', v) }); - // // ~granulator.get(\pan, { | v | ~to.v_('/grainfx/pan', v) }); - // // ~granulator.get(\track, { | v | ~to.v_('/grainfx/track', v) }); - // // ~granulator.get(\jitter, { | v | ~to.v_('/grainfx/jitter', v) }); - // // todo - set the grainmode based on what this one has - // }, { - // [ "Bad track index", v ].postln; - // }); - // }); +// when selecting a track, sets all the controls on the track page to this one +~to.button('/trackselect', 0, { |v| + ~tracknum = v.asInteger; + ~granulator = ~granulators[~tracknum]; + ~to.v_('/track/record', ~granulator.record); + ~to.v_('/track/mode', ~granulator.mode); + ~to.v_('/track/speed', ~speeds[~tracknum]); + + ~to.v_('/track/blur', ~granulator.blur); + ~to.v_('/track/size', ~granulator.size); + ~to.v_('/track/mix', ~granulator.mix); + ~to.v_('/track/pan', ~granulator.pan); + ~to.v_('/track/track', ~granulator.track); + ~to.v_('/track/jitter', ~granulator.jitter); +}); // note: ~buflen is the variable for buffer length, which only gets set to @@ -51,25 +50,28 @@ OSCdef.freeAll; ~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 | ~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/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| ~possynths[0].set(\speed, v) }); -~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| ~possynths[1].set(\speed, v) }); -~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| ~possynths[2].set(\speed, v) }); -~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| ~possynths[3].set(\speed, v) }); +~to.slider('/grains/speed0', 1, TouchOSCScale(0, 2), { |v| ~speeds[0] = v; ~possynths[0].set(\speed, v) }); +~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| ~speeds[1] = v; ~possynths[1].set(\speed, v) +}); +~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| ~speeds[2] = v; ~possynths[2].set(\speed, v) }); +~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| ~speeds[3] = v; ~possynths[3].set(\speed, v) }); -~to.slider('/grains/mix0', 0.5, TouchOSCScale(0, 1), { | v | ~granulators[0].gain(v) }); -~to.slider('/grains/mix1', 0.5, TouchOSCScale(0, 1),{ | v | ~granulators[1].gain(v) }); -~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.slider('/grains/passthrough', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) }); + +~to.slider('/grains/mix0', 0.5, TouchOSCScale(0, 1), { | v | ~granulators[0].gain_(v) }); +~to.slider('/grains/mix1', 0.5, TouchOSCScale(0, 1),{ | v | ~granulators[1].gain_(v) }); +~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| }); @@ -79,38 +81,31 @@ OSCdef.freeAll; ~to.button('/grains/back', 0, { |v| ~pitch.set(\dir, if( v > 0, { -1 }, { 1}))}); ~to.button('/grains/slope', 1, { |v| ~pitch.set(\track, v) }); +~to.button('/grains/chorus', 0, { |v| ~pitch.set(\chorus, v) }); +~to.slider('/grains/detune', 0, TouchOSCScale(0, 0.059), { |v| ~pitch.set(\detune, v) }); +~to.slider('/grains/pitch', 0, TouchOSCScale(-2, 2), { |v| ~pitch.set(\pitch, v.round) }); + + // Page 2: track -// ~to.slider('/track/mix', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.mix_(v); -// }); +// these just set the value on the first page + +~to.button('/track/record', 0, { | v | ~to.v_('grains/record' ++ ~tracknum, v) }); +~to.button('/track/mode', 0, { | v | ~to.v_('grains/mode' ++ ~tracknum, v) }); +~to.slider('/track/speed', 1, TouchOSCScale(0, 2), { |v| ~to.v_('grains/speed' ++ ~tracknum, v) }); + +// these set the values on the actual granulator + +~to.slider('/track/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.blur_(v) }); +~to.slider('/track/size', 0.1, TouchOSCScale(0, 0.5), { |v| ~granulator.size_(v) }); + +~to.slider('/track/mix', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.mix_(v); }); +~to.slider('/track/pan', 0, TouchOSCScale(-1, 1), { |v| ~granulator.pan_(v) }); +~to.slider('/track/track', 0.5, TouchOSCScale(-1, 1), { |v| ~granulator.track_(v) }); +~to.slider('/track/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.jitter_(v) }); + + - // ~to.slider('/grainfx/pan', 0, TouchOSCScale(-1, 1), { |v| ~granulator.pan_(v) }); - // ~to.slider('/grainfx/track', 0.5, TouchOSCScale(-1, 1), { |v| ~granulator.track_(v) }); - // ~to.slider('/grainfx/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.jitter_(v) }); - // - // - // ~to.slider('/grains/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.blur_(v) }); - // ~to.slider('/grains/size', 0.1, TouchOSCScale(0, 0.5),{ |v| ~granulator.size_(v) }); - // - // - // ~to.button('/grainfx/chorus', 0, { |v| ~pitch.set(\chorus, v) }); - // ~to.slider('/grainfx/detune', 0, TouchOSCScale(0, 0.059), { |v| ~pitch.set(\detune, v) }); - // ~to.slider('/grainfx/pitch', 0, TouchOSCScale(-2, 2), { |v| ~pitch.set(\pitch, v.round) }); - // - // ~to.button('/grainfx/quant', 1, { |v| - // // ~pitch.set(\quant, v); - // // just re-call the value setter for harmonics when toggled - // ~to.v_('/grainfx/harmonics', ~to.v('/grainfx/harmonics')); - // }); - // - // ~to.slider('/grainfx/harmonics', 2, TouchOSCScale(0.1, 4), { |v| - // if(~to.v('/grainfx/quant') > 0, { - // ~pitch.set(\harmonics, v.round); - // }, - // { - // ~pitch.set(\harmonics, v); - // }); - // }); ~to.slider( '/fx/filterfreq', diff --git a/main.scd b/main.scd index 1007cca..985eafd 100644 --- a/main.scd +++ b/main.scd @@ -48,10 +48,10 @@ Granulator.init(s); arg track, mode; var synth = ~modes[mode][1]; ~possynths[track].get(\speed, { | speed | - ~possynths[track].free; ~possynths[track] = Synth(synth, [\out, ~posb[track], \speed, speed]); }); + ~granulators[track].mode_(mode); } ) From 90c7df0227e8e76ee056bf268339db11549a92f0 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Mon, 10 Apr 2023 16:25:04 +1000 Subject: [PATCH 15/19] Further bout of refactoring - pitch and trigger are now in the Granulator class --- control.scd | 33 --------------------------------- interface.scd | 34 ++++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 47 deletions(-) diff --git a/control.scd b/control.scd index 8600b70..a0ae3ab 100644 --- a/control.scd +++ b/control.scd @@ -27,38 +27,5 @@ ~lfob = Synth(\lfo, [\out, ~lfobb ]); ~lfoc = Synth(\lfo, [\out, ~lfocb ]); -// a kr synth which triggers grains - -~triggerb = Bus.control(s, 1); - -~trigger = SynthDef( - \trigger, - { - arg out, freq=1, dust=0; - Out.kr(out, (Impulse.kr(freq) * (1 - dust)) + (Dust.kr(freq) * dust)); -} -).play(s, [ \out, ~triggerb, \freq, 120, \dust, 0 ]); - - - -// a kr synth which is used to control the granulator -// playback rate. - -~pitchb = Bus.control(s, 1); - -~pitch = SynthDef( - \pitch, - { - arg out, posb, triggerb, track=1, dir=1, detune=0.0, chorus=0, harmonics=2, pitch=0; - var tracking, base, chor, det, csig, dsig; - csig = Latch.kr(WhiteNoise.kr(), In.kr(triggerb)); - dsig = Latch.kr(WhiteNoise.kr(), In.kr(triggerb)); - tracking = Schmidt.kr(Slope.kr(posb), 0, 0) * 2 - 1; - base = 2.pow(pitch) * dir * (track * tracking + (1 - track)); - det = detune * dsig + 1; - chor = chorus * harmonics.pow((csig * 2).round) + (1 - chorus); - Out.kr(out, base * chor * det); - } -).play(s, [ \out, ~pitchb, \triggerb, ~triggerb, \posb, ~playbacklfob, \dir, 1, \track, 0]); ) diff --git a/interface.scd b/interface.scd index 6be15a2..aa10726 100644 --- a/interface.scd +++ b/interface.scd @@ -40,7 +40,13 @@ OSCdef.freeAll; ~to.v_('/track/mix', ~granulator.mix); ~to.v_('/track/pan', ~granulator.pan); ~to.v_('/track/track', ~granulator.track); - ~to.v_('/track/jitter', ~granulator.jitter); + ~to.v_('/track/jitter', ~granulator.jitter); + ~to.v_('/track/dust', ~granulator.dust); + ~to.v_('/track/slope', ~granulator.slope); + ~to.v_('/track/back', ~granulator.back); + ~to.v_('/track/chorus', ~granulator.chorus); + ~to.v_('/track/detune', ~granulator.detune); + ~to.v_('/track/pitch', ~granulator.pitch); }); @@ -75,30 +81,30 @@ OSCdef.freeAll; ~to.button('/grains/speedquant', 0, { |v| }); -~to.slider('/grains/trigger', 120, TouchOSCScale(0, 640), { |v| ~trigger.set(\freq, v) }); - -~to.button('/grains/dust', 0, { |v| ~trigger.set(\dust, v) }); -~to.button('/grains/back', 0, { |v| ~pitch.set(\dir, if( v > 0, { -1 }, { 1}))}); -~to.button('/grains/slope', 1, { |v| ~pitch.set(\track, v) }); - -~to.button('/grains/chorus', 0, { |v| ~pitch.set(\chorus, v) }); -~to.slider('/grains/detune', 0, TouchOSCScale(0, 0.059), { |v| ~pitch.set(\detune, v) }); -~to.slider('/grains/pitch', 0, TouchOSCScale(-2, 2), { |v| ~pitch.set(\pitch, v.round) }); - - // Page 2: track -// these just set the value on the first page +// record, mode and speed have controls on both pages - the controls for them here just +// call the v_ setter on the front page controls ~to.button('/track/record', 0, { | v | ~to.v_('grains/record' ++ ~tracknum, v) }); ~to.button('/track/mode', 0, { | v | ~to.v_('grains/mode' ++ ~tracknum, v) }); ~to.slider('/track/speed', 1, TouchOSCScale(0, 2), { |v| ~to.v_('grains/speed' ++ ~tracknum, v) }); -// these set the values on the actual granulator +// the rest of this page's controls set the values on the current granulator ~to.slider('/track/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.blur_(v) }); ~to.slider('/track/size', 0.1, TouchOSCScale(0, 0.5), { |v| ~granulator.size_(v) }); +~to.slider('/track/trigger', 120, TouchOSCScale(0, 640), { |v| ~granulator.trigger_(v) }); + +~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/chorus', 0, { |v| ~granulator.chorus_(v) }); +~to.slider('/track/detune', 0, TouchOSCScale(0, 0.059), { |v| ~granulator.detune_(v) }); +~to.slider('/track/pitch', 0, TouchOSCScale(-2, 2), { |v| ~granulator.pitch_(v.round) }); + ~to.slider('/track/mix', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.mix_(v); }); ~to.slider('/track/pan', 0, TouchOSCScale(-1, 1), { |v| ~granulator.pan_(v) }); ~to.slider('/track/track', 0.5, TouchOSCScale(-1, 1), { |v| ~granulator.track_(v) }); From d2564c575785a1c986f7a333faaef030a96f396e Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Mon, 10 Apr 2023 17:13:43 +1000 Subject: [PATCH 16/19] Still trying to get all the little bits of the interface code right --- interface.scd | 36 ++++++++++++++++++++++++------------ main.scd | 5 ----- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/interface.scd b/interface.scd index aa10726..a8b2ae2 100644 --- a/interface.scd +++ b/interface.scd @@ -1,8 +1,4 @@ -v = 1.0; - -v.asInt - ( ~to = TouchOSC("192.168.0.209", 9000); @@ -33,6 +29,7 @@ OSCdef.freeAll; ~granulator = ~granulators[~tracknum]; ~to.v_('/track/record', ~granulator.record); ~to.v_('/track/mode', ~granulator.mode); + ~to.v_('/track/trigger',~granulator.trigger); ~to.v_('/track/speed', ~speeds[~tracknum]); ~to.v_('/track/blur', ~granulator.blur); @@ -61,16 +58,31 @@ OSCdef.freeAll; ~to.button('/grains/record2', 0, { | v | ~granulators[2].record_(v) }); ~to.button('/grains/record3', 0, { | v | ~granulators[3].record_(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.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| ~speeds[0] = v; ~possynths[0].set(\speed, v) }); -~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| ~speeds[1] = v; ~possynths[1].set(\speed, v) +~to.slider('/grains/speed0', 1, TouchOSCScale(0, 2), { |v| + ~speeds[0] = v; + ~possynths[0].set(\speed, v / ~buflen); + ~speeds.postln; +}); +~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| + ~speeds[1] = v; + ~possynths[1].set(\speed, v / ~buflen); + ~speeds.postln; +}); +~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| + ~speeds[2] = v; + ~possynths[2].set(\speed, v / ~buflen); + ~speeds.postln; +}); +~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| + ~speeds[3] = v; + ~possynths[3].set(\speed, v / ~buflen); + ~speeds.postln; }); -~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| ~speeds[2] = v; ~possynths[2].set(\speed, v) }); -~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| ~speeds[3] = v; ~possynths[3].set(\speed, v) }); ~to.slider('/grains/passthrough', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) }); diff --git a/main.scd b/main.scd index 985eafd..c5a8ca9 100644 --- a/main.scd +++ b/main.scd @@ -41,9 +41,6 @@ Granulator.init(s); ~granulators.add(Granulator.new(~buflen, ~recordb, ~outb, pb, ~triggerb, ~pitchb)); }); -) - -( ~setmode = { arg track, mode; var synth = ~modes[mode][1]; @@ -55,8 +52,6 @@ Granulator.init(s); } ) -~granulators[0].gain(1); - ("./interface.scd").loadRelative; From c8ab06dfc472409dc902f17882a4a79a7af1ba0b Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sat, 15 Apr 2023 16:03:16 +1000 Subject: [PATCH 17/19] Working out a lot of kinks in the interface --- interface.scd | 73 +++++++++++++++++++++++++++++---------------------- main.scd | 16 +++++++---- 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/interface.scd b/interface.scd index a8b2ae2..d0e3fe1 100644 --- a/interface.scd +++ b/interface.scd @@ -1,9 +1,12 @@ + ( ~to = TouchOSC("192.168.0.209", 9000); ~speeds = [ 1, 1, 1, 1 ]; +~tracknum = 0; +~granulator = ~granulators[0]; OSCdef.freeAll; @@ -21,30 +24,9 @@ OSCdef.freeAll; }); }); - -// when selecting a track, sets all the controls on the track page to this one - -~to.button('/trackselect', 0, { |v| - ~tracknum = v.asInteger; - ~granulator = ~granulators[~tracknum]; - ~to.v_('/track/record', ~granulator.record); - ~to.v_('/track/mode', ~granulator.mode); - ~to.v_('/track/trigger',~granulator.trigger); - ~to.v_('/track/speed', ~speeds[~tracknum]); - - ~to.v_('/track/blur', ~granulator.blur); - ~to.v_('/track/size', ~granulator.size); - ~to.v_('/track/mix', ~granulator.mix); - ~to.v_('/track/pan', ~granulator.pan); - ~to.v_('/track/track', ~granulator.track); - ~to.v_('/track/jitter', ~granulator.jitter); - ~to.v_('/track/dust', ~granulator.dust); - ~to.v_('/track/slope', ~granulator.slope); - ~to.v_('/track/back', ~granulator.back); - ~to.v_('/track/chorus', ~granulator.chorus); - ~to.v_('/track/detune', ~granulator.detune); - ~to.v_('/track/pitch', ~granulator.pitch); -}); +// Problem - when you press the record, mode or speed control on the grains page, +// it doesn't update the track until you change tracks. How to make this work +// without a loop (one control sets another control, which sets the first control...)? // note: ~buflen is the variable for buffer length, which only gets set to @@ -66,22 +48,18 @@ OSCdef.freeAll; ~to.slider('/grains/speed0', 1, TouchOSCScale(0, 2), { |v| ~speeds[0] = v; ~possynths[0].set(\speed, v / ~buflen); - ~speeds.postln; }); ~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| ~speeds[1] = v; ~possynths[1].set(\speed, v / ~buflen); - ~speeds.postln; }); ~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| ~speeds[2] = v; ~possynths[2].set(\speed, v / ~buflen); - ~speeds.postln; }); ~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| ~speeds[3] = v; ~possynths[3].set(\speed, v / ~buflen); - ~speeds.postln; }); ~to.slider('/grains/passthrough', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) }); @@ -98,9 +76,16 @@ OSCdef.freeAll; // record, mode and speed have controls on both pages - the controls for them here just // call the v_ setter on the front page controls -~to.button('/track/record', 0, { | v | ~to.v_('grains/record' ++ ~tracknum, v) }); -~to.button('/track/mode', 0, { | v | ~to.v_('grains/mode' ++ ~tracknum, v) }); -~to.slider('/track/speed', 1, TouchOSCScale(0, 2), { |v| ~to.v_('grains/speed' ++ ~tracknum, v) }); +~trackctrl = { | base, n | ("/grains/" ++ base ++ n).asSymbol }; + + +~to.button('/track/record', 0, { | v | + ~to.v_(~trackctrl.value("record", ~tracknum), v) +}); +~to.button('/track/mode', 0, { | v | + ~to.v_(~trackctrl.value("mode", ~tracknum), v) }); +~to.slider('/track/speed', 1, TouchOSCScale(0, 2), { |v| + ~to.v_(~trackctrl.value("speed", ~tracknum), v) }); // the rest of this page's controls set the values on the current granulator @@ -123,6 +108,32 @@ OSCdef.freeAll; ~to.slider('/track/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.jitter_(v) }); +// define track selector after the track controls are defined + +~to.button('/trackselect', 0, { |v| + ~tracknum = v.asInteger; + ~granulator = ~granulators[~tracknum]; + [ "granulator", ~granulator, "record", ~granulator.record ].postln; + ~to.v_('/track/record', ~granulator.record); + ~to.v_('/track/mode', ~granulator.mode); + ~to.v_('/track/trigger',~granulator.trigger); + ~to.v_('/track/speed', ~speeds[~tracknum]); + + ~to.v_('/track/blur', ~granulator.blur); + ~to.v_('/track/size', ~granulator.size); + ~to.v_('/track/mix', ~granulator.mix); + ~to.v_('/track/pan', ~granulator.pan); + ~to.v_('/track/track', ~granulator.track); + ~to.v_('/track/jitter', ~granulator.jitter); + ~to.v_('/track/dust', ~granulator.dust); + ~to.v_('/track/slope', ~granulator.slope); + ~to.v_('/track/back', ~granulator.back); + ~to.v_('/track/chorus', ~granulator.chorus); + ~to.v_('/track/detune', ~granulator.detune); + ~to.v_('/track/pitch', ~granulator.pitch); +}); + + ~to.slider( diff --git a/main.scd b/main.scd index c5a8ca9..9a8411a 100644 --- a/main.scd +++ b/main.scd @@ -14,7 +14,6 @@ Server.killAll; Granulator.init(s); ( -// set up four position buffers with synths ~modes = [ [ "saw", \pos_saw ], @@ -52,12 +51,19 @@ Granulator.init(s); } ) + ("./interface.scd").loadRelative; - - - - +~to.controls.keys.do({|k, i| i.postln; k.postln;~to.controls[k].postln}); +~to.controls['/grains/speed0'] +~to.v_(, 0); + +~to.controls.at(~trackctrl.value('speed')).isNil.not + +a = "string" +b = 'string' + +a.asSymbol From 4c5cc176f3f1af5040f67447bc886364b1b1feb1 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Sun, 16 Apr 2023 17:45:15 +1000 Subject: [PATCH 18/19] Fixed interface glitches, made trigger/size have an xy control --- interface.scd | 85 ++++++++++++++------------------------------------- main.scd | 9 +++--- 2 files changed, 28 insertions(+), 66 deletions(-) diff --git a/interface.scd b/interface.scd index d0e3fe1..e4dece2 100644 --- a/interface.scd +++ b/interface.scd @@ -1,9 +1,9 @@ +// FIXME: the touchosc stuff is crashing on intialisation ( ~to = TouchOSC("192.168.0.209", 9000); -~speeds = [ 1, 1, 1, 1 ]; ~tracknum = 0; ~granulator = ~granulators[0]; @@ -11,7 +11,6 @@ OSCdef.freeAll; - ~to.button('/reset', 0, { | v | if( v > 0, { var sp = ~to.v('/grains/speed')[0]; @@ -24,17 +23,12 @@ OSCdef.freeAll; }); }); -// Problem - when you press the record, mode or speed control on the grains page, -// it doesn't update the track until you change tracks. How to make this work -// without a loop (one control sets another control, which sets the first control...)? - // 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) }); @@ -45,22 +39,10 @@ OSCdef.freeAll; ~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| - ~speeds[0] = v; - ~possynths[0].set(\speed, v / ~buflen); -}); -~to.slider('/grains/speed1', 1, TouchOSCScale(0, 2), { |v| - ~speeds[1] = v; - ~possynths[1].set(\speed, v / ~buflen); -}); -~to.slider('/grains/speed2', 1, TouchOSCScale(0, 2), { |v| - ~speeds[2] = v; - ~possynths[2].set(\speed, v / ~buflen); -}); -~to.slider('/grains/speed3', 1, TouchOSCScale(0, 2), { |v| - ~speeds[3] = v; - ~possynths[3].set(\speed, v / ~buflen); -}); +~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/passthrough', 0.75, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\passthrough, v) }); @@ -71,28 +53,16 @@ OSCdef.freeAll; ~to.button('/grains/speedquant', 0, { |v| }); + // Page 2: track -// record, mode and speed have controls on both pages - the controls for them here just -// call the v_ setter on the front page controls -~trackctrl = { | base, n | ("/grains/" ++ base ++ n).asSymbol }; - - -~to.button('/track/record', 0, { | v | - ~to.v_(~trackctrl.value("record", ~tracknum), v) +~to.xy('/track/triggersize', [ 120, 0.1 ], TouchOSCScale(0, 640), TouchOSCScale(0, 0.5), { |v| + ~granulator.trigger_(v[0]); + ~granulator.size_(v[1]); }); -~to.button('/track/mode', 0, { | v | - ~to.v_(~trackctrl.value("mode", ~tracknum), v) }); -~to.slider('/track/speed', 1, TouchOSCScale(0, 2), { |v| - ~to.v_(~trackctrl.value("speed", ~tracknum), v) }); - -// the rest of this page's controls set the values on the current granulator ~to.slider('/track/blur', 0, TouchOSCScale(0, 0.25), { |v| ~granulator.blur_(v) }); -~to.slider('/track/size', 0.1, TouchOSCScale(0, 0.5), { |v| ~granulator.size_(v) }); - -~to.slider('/track/trigger', 120, TouchOSCScale(0, 640), { |v| ~granulator.trigger_(v) }); ~to.button('/track/dust', 0, { |v| ~granulator.dust_(v) }); ~to.button('/track/back', 0, { |v| ~granulator.back_(v)}); @@ -108,30 +78,24 @@ OSCdef.freeAll; ~to.slider('/track/jitter', 0.25, TouchOSCScale(0, 1), { |v| ~granulator.jitter_(v) }); -// define track selector after the track controls are defined ~to.button('/trackselect', 0, { |v| - ~tracknum = v.asInteger; - ~granulator = ~granulators[~tracknum]; - [ "granulator", ~granulator, "record", ~granulator.record ].postln; - ~to.v_('/track/record', ~granulator.record); - ~to.v_('/track/mode', ~granulator.mode); - ~to.v_('/track/trigger',~granulator.trigger); - ~to.v_('/track/speed', ~speeds[~tracknum]); + ~tracknum = v.asInteger; + ~granulator = ~granulators[~tracknum]; - ~to.v_('/track/blur', ~granulator.blur); - ~to.v_('/track/size', ~granulator.size); + ~to.v_('/track/triggersize', [~granulator.trigger, ~granulator.size]); + ~to.v_('/track/blur', ~granulator.blur); ~to.v_('/track/mix', ~granulator.mix); - ~to.v_('/track/pan', ~granulator.pan); - ~to.v_('/track/track', ~granulator.track); - ~to.v_('/track/jitter', ~granulator.jitter); - ~to.v_('/track/dust', ~granulator.dust); - ~to.v_('/track/slope', ~granulator.slope); - ~to.v_('/track/back', ~granulator.back); - ~to.v_('/track/chorus', ~granulator.chorus); - ~to.v_('/track/detune', ~granulator.detune); - ~to.v_('/track/pitch', ~granulator.pitch); -}); + ~to.v_('/track/pan', ~granulator.pan); + ~to.v_('/track/track', ~granulator.track); + ~to.v_('/track/jitter', ~granulator.jitter); + ~to.v_('/track/dust', ~granulator.dust); + ~to.v_('/track/slope', ~granulator.slope); + ~to.v_('/track/back', ~granulator.back); + ~to.v_('/track/chorus', ~granulator.chorus); + ~to.v_('/track/detune', ~granulator.detune); + ~to.v_('/track/pitch', ~granulator.pitch); + }); @@ -143,10 +107,7 @@ OSCdef.freeAll; ~to.slider('/fx/grainmix', 1.0, TouchOSCScale(0, 1), { |v| ~grainmixer.set(\grains, v) } ); - - ~to.slider('/fx/filtermix', 0.8, TouchOSCScale(0, 1), { |v| ~filter.set(\amp, v) } ); - ~to.button('/fx/filtermoda', 1, { |v| ~filtermod.set(\a, v) }); ~to.button('/fx/filtermodb', 0, { |v| ~filtermod.set(\b, v) }); ~to.button('/fx/filtermodc', 0, { |v| ~filtermod.set(\c, v) }); diff --git a/main.scd b/main.scd index 9a8411a..e491e41 100644 --- a/main.scd +++ b/main.scd @@ -30,14 +30,14 @@ Granulator.init(s); (0..3).do({ var pb = Bus.control(s, 1), ps; ~posb.add(pb); - ps = Synth(\pos_saw, [ \out, pb ]); + ps = Synth(\pos_saw, [ \out, pb, \speed, 1 / ~buflen ]); ~possynths.add(ps); }); (0..3).do({ |i| var pb = ~posb.at(i); - ~granulators.add(Granulator.new(~buflen, ~recordb, ~outb, pb, ~triggerb, ~pitchb)); + ~granulators.add(Granulator.new(~buflen, ~recordb, ~fxb, pb, ~triggerb, ~pitchb)); }); ~setmode = { @@ -55,7 +55,7 @@ Granulator.init(s); ("./interface.scd").loadRelative; ~to.controls.keys.do({|k, i| i.postln; k.postln;~to.controls[k].postln}); -~to.controls['/grains/speed0'] +~to.controls['/track/speed'].send_(0.1); ~to.v_(, 0); ~to.controls.at(~trackctrl.value('speed')).isNil.not @@ -67,4 +67,5 @@ a.asSymbol - +~possynths[0].get(\speed, {|v| v.postln}); +~possynths[0].set(\speed, 20 / ~buflen) \ No newline at end of file From e249d39f7f61c48aa6880ccb82a988a1bb886d25 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Mon, 24 Apr 2023 15:54:24 +1000 Subject: [PATCH 19/19] Got server syncing working, moved granulator setup to its own file --- TODO.md | 44 +++++++++++++------------------- control.scd | 1 + effects.scd | 1 + granulator.scd | 40 +++++++++++++++++++++++++++++ main.scd | 68 +++++++++----------------------------------------- 5 files changed, 71 insertions(+), 83 deletions(-) create mode 100644 granulator.scd diff --git a/TODO.md b/TODO.md index 84d729b..af238f4 100644 --- a/TODO.md +++ b/TODO.md @@ -1,37 +1,27 @@ TODO ==== -## Basic interface stuff +Monday-Tuesday to-do -Write default settings to the interface on startup <-- done +Use server.sync to speed up booting -Try to get all the common interfaces on one page +- re-route the effects so that it goes + +input -> filter -> delay -> granulator -> reverb + +not input -> granulator -> effects + +Synchronise speeds across granulators + +Quantise speeds + +that's enough! +-- -## Musical +Later: -Test things like really rapid playback +vibrato and tremolo -Pitch-shifting (tuned and untuned) - -LFO Modulate the filter <-- done - -LFO Modulate the granulator settings - -Separate panel for input effects: distort and overdrive - -Sync timining of granule playback to buffer length / speed - -Timing based on beat detection - - -## Advanced interface - -Save current patch / load patch <-- Done - -Save the current buffer! - if this is incorporated with current settings, it's a way to save how the granulator is playing, and then resume. Which is good for live stuff and also for overdubbing - -SuperCollider seems to have the ability to read and write files, but not scan directories, so the patch-saver will have to maintain its own index file - -patch = file with settings, including a link to the buffer sample \ No newline at end of file +more playback modes \ No newline at end of file diff --git a/control.scd b/control.scd index a0ae3ab..f130326 100644 --- a/control.scd +++ b/control.scd @@ -27,5 +27,6 @@ ~lfob = Synth(\lfo, [\out, ~lfobb ]); ~lfoc = Synth(\lfo, [\out, ~lfocb ]); +"LFOs running".postln; ) diff --git a/effects.scd b/effects.scd index fbd7e39..55a242c 100644 --- a/effects.scd +++ b/effects.scd @@ -70,4 +70,5 @@ } ).play(s, [ \in, ~delayb, \out, 0 ], \addToTail); +"Effects running".postln; ) diff --git a/granulator.scd b/granulator.scd new file mode 100644 index 0000000..7326b64 --- /dev/null +++ b/granulator.scd @@ -0,0 +1,40 @@ + +( +~modes = [ + [ "saw", \pos_saw ], + [ "reverse", \pos_reverse ], + [ "sine", \pos_sine ], + [ "step", \pos_step ], + [ "random", \pos_random ] +]; + +~granulators = Array.new(4); +~posb = Array.new(4); +~possynths = Array.new(4); + +(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); +}); + + +(0..3).do({ |i| + var pb = ~posb.at(i); + ~granulators.add(Granulator.new(~buflen, ~recordb, ~fxb, pb, ~triggerb, ~pitchb)); +}); + +~setmode = { + arg track, mode; + var synth = ~modes[mode][1]; + ~possynths[track].get(\speed, { | speed | + ~possynths[track].free; + ~possynths[track] = Synth(synth, [\out, ~posb[track], \speed, speed]); + }); + ~granulators[track].mode_(mode); +}; + +"Granulator running".postln; + +) \ No newline at end of file diff --git a/main.scd b/main.scd index e491e41..79ea333 100644 --- a/main.scd +++ b/main.scd @@ -2,70 +2,26 @@ ( Server.default.options.inDevice_("Scarlett 2i2 USB"); +Server.default.options.hardwareBufferSize_(1024); //Server.default.options.outDevice_("Scarlett 2i2 USB"); ) Server.killAll; - -("./synths.scd").loadRelative; -("./control.scd").loadRelative; -("./effects.scd").loadRelative; - -Granulator.init(s); - ( +Routine.run({ -~modes = [ - [ "saw", \pos_saw ], - [ "reverse", \pos_reverse ], - [ "sine", \pos_sine ], - [ "step", \pos_step ], - [ "random", \pos_random ] -]; + ("./synths.scd").loadRelative; + Granulator.init(s); -~granulators = Array.new(4); -~posb = Array.new(4); -~possynths = Array.new(4); + s.sync; -(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); + "Synths loaded".postln; + + ("./control.scd").loadRelative; + ("./effects.scd").loadRelative; + ("./granulator.scd").loadRelative; + s.sync; + ("./interface.scd").loadRelative; }); - - -(0..3).do({ |i| - var pb = ~posb.at(i); - ~granulators.add(Granulator.new(~buflen, ~recordb, ~fxb, pb, ~triggerb, ~pitchb)); -}); - -~setmode = { - arg track, mode; - var synth = ~modes[mode][1]; - ~possynths[track].get(\speed, { | speed | - ~possynths[track].free; - ~possynths[track] = Synth(synth, [\out, ~posb[track], \speed, speed]); - }); - ~granulators[track].mode_(mode); -} ) - -("./interface.scd").loadRelative; - -~to.controls.keys.do({|k, i| i.postln; k.postln;~to.controls[k].postln}); -~to.controls['/track/speed'].send_(0.1); -~to.v_(, 0); - -~to.controls.at(~trackctrl.value('speed')).isNil.not - -a = "string" -b = 'string' - -a.asSymbol - - - -~possynths[0].get(\speed, {|v| v.postln}); -~possynths[0].set(\speed, 20 / ~buflen) \ No newline at end of file