From 775e7efed7a77f967a08a03e01d92643ffc7fe06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Forment?= Date: Wed, 1 May 2024 11:16:06 +0200 Subject: [PATCH] =?UTF-8?q?mise=20=C3=A0=20jour=20pour=20performance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Classes/BuboBoot.sc | 1 + Classes/BuboNodeProxy.sc | 10 ++ Classes/Configuration/Startup.scd | 6 +- Classes/Configuration/Synthdefs.scd | 90 +++++++++------ Classes/Controllers/MIDIMix.sc | 135 ---------------------- Classes/PseudoUgen/Safe.sc | 10 ++ test.scd | 171 ++++++++++++++++++++++++++++ 7 files changed, 252 insertions(+), 171 deletions(-) delete mode 100644 Classes/Controllers/MIDIMix.sc create mode 100644 Classes/PseudoUgen/Safe.sc create mode 100644 test.scd diff --git a/Classes/BuboBoot.sc b/Classes/BuboBoot.sc index 4c56c43..db37f87 100644 --- a/Classes/BuboBoot.sc +++ b/Classes/BuboBoot.sc @@ -56,6 +56,7 @@ Boot { d.dirt = SuperDirt(2, s); d.dirt.fileExtensions = ["wav","aif","aiff","aifc","mp3"]; d.dirt.loadSoundFiles("/Users/bubo/Library/Application\ Support/Sardine/SON/*"); + d.dirt.loadSoundFiles("/Users/bubo/.config/livecoding/samples/*"); d.dirt.doNotReadYet = true; d.dirt.start(57120, [ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]); ( diff --git a/Classes/BuboNodeProxy.sc b/Classes/BuboNodeProxy.sc index 880bdfc..98def6f 100644 --- a/Classes/BuboNodeProxy.sc +++ b/Classes/BuboNodeProxy.sc @@ -37,6 +37,16 @@ ^this; } + /* Syntax for sending MIDI messages */ + >> { + arg pattern; + pattern = EventShortener.findShortcuts(pattern); + pattern = pattern ++ [type: 'midi']; + this[0] = Pbind(*pattern); + this.quant = 4; this.fadeTime = 0.01; + ^this + } + /* Player-like syntax sugar */ => { arg pattern; diff --git a/Classes/Configuration/Startup.scd b/Classes/Configuration/Startup.scd index 651a818..d28cb49 100644 --- a/Classes/Configuration/Startup.scd +++ b/Classes/Configuration/Startup.scd @@ -1,5 +1,9 @@ +// Setting up MIDI for hardware performances +"Initialising MIDI...".postln; MIDIClient.init; p = currentEnvironment; c = currentEnvironment.clock; -"Loading SynthDefs".postln; + +// Space for loading custom SynthDefs +"Loading SynthDefs...".postln; "Synthdefs.scd".loadRelative; diff --git a/Classes/Configuration/Synthdefs.scd b/Classes/Configuration/Synthdefs.scd index bc57a46..12fdb98 100644 --- a/Classes/Configuration/Synthdefs.scd +++ b/Classes/Configuration/Synthdefs.scd @@ -6,24 +6,10 @@ d.params = { arg obj, name; obj[name].allControlNames.do({arg i; i.postln;}); }; d.list = { arg obj; obj.keys.do({arg i; i.postln}); }; ); -f.vardel = { - arg in; - HPF.ar(CombC.ar(in, 2, c.beatDur / [1, 2], 2), - SinOsc.ar(c.beatDur * 4).range(500, 2000)); -}; - -/* -* This is the sampler used for 90% of sampling duties. -*/ ( z = SynthDef.new(\player, { - arg buf; - var sig, env = EnvGen.ar( - Env.perc( - \attack.kr(0.01), - \release.kr(1), - doneAction: 2) - ); + arg buf, out; + var sig, env = EnvGen.ar(Env.perc(\attack.kr(0.01), \release.kr(1)), doneAction: 2); var startPos = \begin.kr(0) * BufFrames.kr(buf); var endPos = \end.kr(1) * BufFrames.kr(buf); // TODO: unused sig = PlayBuf.ar( @@ -34,7 +20,7 @@ f.vardel = { loop:\loop.kr(0), doneAction: 2); sig = sig * \amp.kr(-6.dbamp); sig = Pan2.ar(sig * env, \pan.kr(0)); - OffsetOut.ar(\out.kr(0), sig) + OffsetOut.ar(out, sig) }).add; d.player = z; ); @@ -45,12 +31,12 @@ f.vardel = { */ ( z = SynthDef.new(\splayer, { - arg buf; + arg buf, out; var sig, env = EnvGen.ar( - Env.perc( - \attack.kr(0.01), - \release.kr(1), - doneAction: 2) + Env.perc( + \attack.kr(0.01), + \release.kr(1)), + doneAction: 2 ); var startPos = \begin.kr(0) * BufFrames.kr(buf); var endPos = \end.kr(1) * BufFrames.kr(buf); // TODO: unused @@ -62,13 +48,14 @@ f.vardel = { loop:\loop.kr(0), doneAction: 2); sig = sig * \amp.kr(-6.dbamp); sig = Pan2.ar(sig * env, \pan.kr(0)); - OffsetOut.ar(\out.kr(0), sig) + OffsetOut.ar(out, sig) }).add; d.splayer = z; ); ( z = SynthDef(\sinfb, { + arg out; var sig, env; env = EnvGen.ar( Env.linen( @@ -82,20 +69,21 @@ f.vardel = { 1 ); sig = sig * env; - OffsetOut.ar(\out.kr(0), Pan2.ar(sig, \pan.kr(0), \amp.kr(-6.dbamp))); + OffsetOut.ar(out, Pan2.ar(sig, \pan.kr(0), \amp.kr(-6.dbamp))); }).add; d.sinfb = z; ); ( z = SynthDef(\omi, { + arg out; var envLength = \sustain.kr(1) * (\end.kr(1) - \begin.kr(0)) / \speed.kr(1); var line = Line.ar(\begin.kr, \end.kr, envLength, doneAction: Done.freeSelf); var env = Env.asr; var volume = IEnvGen.ar(env, line) * \amp.kr(-6.dbamp); var sig; sig = MiOmi.ar(pit: \freq.kr(400).cpsmidi); - OffsetOut.ar(\out.kr(0), Pan2.ar(sig * volume, \pan.kr(0))); + OffsetOut.ar(out, Pan2.ar(sig * volume, \pan.kr(0))); }).add; d.omi = z; ); @@ -107,14 +95,17 @@ f.vardel = { 'Padditive', 'Pwavetable', 'Pchord', 'Pspeech', 'Pswarm', 'Pnoise', 'Pparticle', 'Pstring', 'Pmodal', 'Pbass', 'Psnare', 'Phat' - ].do({arg name, index; + ].do({ + arg name, index; var synth; synth = SynthDef(name, { + arg out; var env = EnvGen.ar( Env.perc( \attack.kr(0.01), \release.kr(1) - ), doneAction: Done.freeSelf + ), + doneAction: Done.freeSelf ); var sig; sig = MiPlaits.ar( @@ -129,7 +120,7 @@ f.vardel = { ); sig = Pan2.ar(sig[0], \pan.kr(0)); sig = sig * env * \amp.kr(-6.dbamp); - OffsetOut.ar(\out.kr(0), sig); + OffsetOut.ar(out, sig); }).add; d.put(name, synth); }); @@ -189,6 +180,7 @@ f.vardel = { arg name, index; var synth; synth = SynthDef(name, { + arg out; var sig; var env = EnvGen.ar(Env.perc(\attack.kr(0.01), \release.kr(1)), doneAction: Done.freeSelf); var freq = \freq.kr; @@ -202,7 +194,7 @@ f.vardel = { ws: \ws.kr(0), bits: \bits.kr(0) ); - OffsetOut.ar(\out.kr(0), Pan2.ar(sig * env * \amp.kr(-6.dbamp), \pan.kr(0))); + OffsetOut.ar(out, Pan2.ar(sig * env * \amp.kr(-6.dbamp), \pan.kr(0))); }).add; d.put(name, synth); }); @@ -210,6 +202,7 @@ f.vardel = { ( z = SynthDef(\tides, { + arg out; var env = Env.perc(\attack.kr(0.01), \release.kr(1)).ar(2); var sig = MiTides.ar( freq: \freq.kr(400), @@ -221,7 +214,10 @@ f.vardel = { ramp_mode: 1, rate: 1 ); - OffsetOut.ar(\out.kr(0), Pan2.ar(sig * env * \amp.kr(-6.dbamp), \pan.kr(0))); + OffsetOut.ar(out, + Pan2.ar(sig * env * \amp.kr(-6.dbamp), + \pan.kr(0) + )); }).add; d.tides = z; ); @@ -241,7 +237,7 @@ f.vardel = { ); var env = Env.perc(\attack.kr(0.01), releaseTime: \release.kr(2.0)).kr(doneAction: 2); var sound = pink * env; - Out.ar(out, Pan2.ar(sound, pos: \pan.kr(0.0))) + OffsetOut.ar(out, Pan2.ar(sound, pos: \pan.kr(0.0))) }).add; d.pink = z; ); @@ -249,7 +245,7 @@ f.vardel = { ( z = SynthDef('kick', { - |out=0, freq, mul=512, vsweep=0.5, hold=0.25, release=0.25, amp=0.5, pan=0| + arg out, freq, mul=512, vsweep=0.5, hold=0.25, release=0.25, amp=0.5, pan=0; var p0, p1, p, freq0, freq1, freqEnv, sig; p0 = 0.006699687; p1 = 0.00001884606; @@ -261,11 +257,35 @@ f.vardel = { sig = SinOsc.ar(freqEnv); sig = sig * EnvGen.ar(Env([1,1,0], [hold,release], [0,0]), doneAction: Done.freeSelf) * amp; sig = Pan2.ar(sig, pan); - Out.ar(out, sig); + OffsetOut.ar(out, sig); }).add; d.kick = z; ); + + + +( + z = SynthDef('kraut', { + /* + * time: frequency sweep time + * tune: frequency division + * harmonics: nb of harmonics + * curve: distortion + * modSpeed: frequency bias + */ + arg out; + var sweepFreq = XLine.ar(\freq.kr(400) * 1.99, \freq.kr, \attack.kr(0.05) / \time.kr(2)); + var frequencyBias = SinOsc.ar(\modSpeed.kr(1)).range(0.90, 1); + var sin = SinOscFB.ar([ + sweepFreq * \tune.kr(1) * frequencyBias, + sweepFreq / \tune.kr * frequencyBias], + feedback: \harmonics.kr(0.25)); + var env = Env.perc(\attack.kr, \release.kr(0.5)).ar(doneAction: 2); + var sound = Safe.ar(sin.lincurve(-1, 1, -1, 1, \curve.kr(4))); + OffsetOut.ar(out, DirtPan.ar(sound, ~dirt.numChannels, \pan.kr(0), env)) + }).add; + d.kraut = z; +); + z = nil; // We don't need that variable anymore - - diff --git a/Classes/Controllers/MIDIMix.sc b/Classes/Controllers/MIDIMix.sc deleted file mode 100644 index 2e4ddd3..0000000 --- a/Classes/Controllers/MIDIMix.sc +++ /dev/null @@ -1,135 +0,0 @@ -// ControllerValue { -// -// /* -// * A ControllerValue represents a MIDI Controller value. -// * It has a minimum and maximum value, and a curve. This -// * is used to convert from the MIDI value to a value that -// * is considered usable by the user. -// * -// * The curve is similar to the one used by the Env object. -// */ -// -// var <>min = 0; -// var <>max = 1; -// var <>curve = 0; -// var <>currentValue; -// var <>bipolar = false; -// -// *new { -// arg min, max, curve; -// ^super.new.init() -// } -// -// init { -// this.min = min; -// this.max = max; -// this.curve = curve; -// this.currentValue = Bus.control; -// this.bipolar = false; -// } -// -// set { -// arg value; -// // If bipolar is true, then the value must go from -1 to 1 -// var conversion = value.lincurve( -// inMin: 0, -// inMax: 127, -// outMin: this.min.neg, -// outMax: this.max, -// curve: this.curve -// ); -// this.currentValue.set(conversion); -// ^this.currentValue; -// } -// -// } -// -// -// MIDIControl { -// -// /* -// * This is my personal MIDI controller interface. I am using a -// * MIDIMix. It has 8 faders, 24 knobs, and 16 buttons. I am only -// * using the knobs and faders. Two buttons are used to change "bank" -// * (increments the CC number value). -// */ -// -// var <>currentBank = 0; -// var <>values; -// -// *new { -// ^super.new.init() -// } -// -// init { -// this.values = IdentityDictionary.new(); -// this.connect(); this.installCallbacks(); -// } -// -// getInit { -// arg number; -// if (this.values[number] == nil) { -// this.values[number] = ControllerValue.new( -// min: 0, max: 127, curve: 0 -// ); -// ^this.values[number] -// } { -// ^this.values[number] -// } -// } -// -// setCurve { -// arg number, curve; -// this.getInit(number).curve = curve; -// } -// -// setBounds { -// arg number, min, max; -// var controller = this.getInit(number); -// controller.min = min; -// controller.max = max; -// } -// -// at { -// arg number; -// var control = this.getInit(number); -// var choices = ( -// value: this.getInit(number).currentValue.getSynchronous, -// bus: this.getInit(number).currentValue, -// map: this.getInit(number).currentValue.asMap, -// kr: In.kr(this.getInit(number).currentValue), -// ); -// ^choices -// } -// -// connect { -// MIDIClient.init; -// MIDIIn.connectAll(verbose: true); -// } -// -// installCallbacks { -// MIDIIn.addFuncTo(\control, { -// arg src, chan, num, val; -// ("CONTROL:" + (num + (this.currentBank * 24)) + "=>" + val).postln; -// this.getInit(num + (this.currentBank * 24)).set(val); -// }); -// MIDIIn.addFuncTo(\noteOn, { -// arg src, chan, num, val; -// "Changing bank".postln; -// if (chan == 8 && num == 22) { -// if (this.currentBank > 0) { -// this.currentBank = this.currentBank - 1; -// }; -// this.currentBank.postln; -// }; -// if (chan == 8 && num == 24) { -// if (this.currentBank < 3) { -// this.currentBank = this.currentBank + 1; -// }; -// this.currentBank.postln; -// }; -// }); -// } -// } -// - diff --git a/Classes/PseudoUgen/Safe.sc b/Classes/PseudoUgen/Safe.sc new file mode 100644 index 0000000..e0f4021 --- /dev/null +++ b/Classes/PseudoUgen/Safe.sc @@ -0,0 +1,10 @@ +Safe { + /* + * This pseudo-ugen is meant to be used on chaotic or unpredictible + * signals. It can help taming them, making sure that you don't blow + * your ears or speakers. + */ + *ar { arg signal; + ^LeakDC.ar(Limiter.ar(signal)) + } +} diff --git a/test.scd b/test.scd new file mode 100644 index 0000000..e524c76 --- /dev/null +++ b/test.scd @@ -0,0 +1,171 @@ +Boot() + +c.tempo = 1.5 + +// Gestion manuelle avec une sorte de console virtuelle + +( +~kick => [i: "splayer", nb: 0, sp: "kick", db:0]; +~snare => [i: "splayer", nb: 0, sp: "snare", db:0, dur: 2]; +~hat => [i: "splayer", + nb: 0, + sp: "hat", + release: 0.1, db:0, + dur: [0.25, 0.25, 0.25, 0.125, 0.125].pseq(inf) +]; +) + +( +~master = { + var snare = MiVerb.ar(CombC.ar(~snare.ar(2), 2, c.dur / 3, 1.5), time: 0.5); + var hat = ~hat.ar(2); + var kick = MiVerb.ar(~kick.ar(2), time: 0.2); + [snare, kick, hat].sum +}; +~master.fadeTime = 4 +) +~master.play; + +~master.clear(8) + +// L'idée ici doit être de pouvoir jouer avec un step sequencer +// Le son d'une routine dans un autre proxy et traitement (comment ?) + +// ... ProxySpace.push(s.boot) +( +~step = r { + /* + * How can I output these events on the NodeProxy Output? + */ + loop { + (instrument: "Pwaveshape", + scale: Scale.minorPentatonic, + release: 1, harm: 0.25, + degree: 8.rand); + (1/4).wait; + (instrument: "Panalog", + scale: Scale.minorPentatonic, + release: 1, harm: 1.rand, + degree: 8.rand + 12); + (instrument: "Panalog", + scale: Scale.minorPentatonic, + release: 1, harm: 1.rand, + degree: 8.rand - 24); + (1/4).wait; + } +}; +) + +( +~master = { + /* + * I would like to add reverb to ~step here. + */ + MiVerb.ar(~step.ar(2), time: 0.9) +} +) + +~master.play; + + +Tdef.help + +Boot() + + +( +SynthDef(\lplay, + {arg out, buf = 0, amp = 0.5, pan = 0, rel=15, dur = 8; + var sig,env ; + sig = Mix.ar(PlayBuf.ar(2,buf,BufRateScale.ir(buf) * ((BufFrames.ir(buf)/s.sampleRate)*c.tempo/dur),1,0,doneAction:2)); + env = EnvGen.ar(Env.linen(0.0,rel,0),doneAction:2); + sig = sig * env; + sig = sig * amp; + Out.ar(out,Pan2.ar(sig,pan)); +}).add; +) + + +( +~test2 => [ + i: "lplay", nb: [0,10].pwhite, + sp: "amen1", dur: 1, rel: 32]; +~test2.play; +) + +( +~test => [i: "splayer", + nb: 0, + sp: "amen1", + dur: 16]; +~test.play; +) + +// Debugging stuff + +Boot() + +( +~step = r { + loop { + (out: ~step.bus, + instrument: "Panalog", + release: 1, harm: [0, 1].pwhite, + degree: 8.rand).play; + (1/4).wait; + (out: ~step.bus, + instrument: "Panalog", + harm: [0, 1.0].pwhite, + release: 1, degree: 8.rand + 12).play; + (1/4).wait; + } +}; +~step.mold(2); +) + +~step.scope // WARNING: Can't scope unintitialized bus + +"awake".help + +// J'étudie comment fonctionne spawn et awake + +Boot() + +( +~bleep = { + var sig = MiPlaits.ar( + \freq.kr(300).cpsmidi, + engine: LFNoise0.kr(c.dur * 2).range(0,8), + harm: 0.5, morph: 0.5, timbre: 0.5 + ) * Env.perc( + \attack.kr(0.01), + \release.kr(0.5) + ).kr(doneAction: 2); + sig = RLPF.ar(sig, LFNoise2.kr(c.dur).range(200,1200), 0.3); + Safe.ar(sig ! 2 * 0.5) +}; +~bleep.awake_(false); +~bleep.play; +) + +( +~bleepverb = { + Limiter.ar(MiVerb.ar(~bleep.ar, time: 0.5)) +}; +~bleepverb.play; +) + + +~d = Tdef(\d, { + loop { + ~bleep.spawn([ + freq: [50, 100, 200, 400].choose / [2, 1].choose, + fb: 1.rand, release: [1, 2, 0.25][c.beats % 4]]); + [0.5, 1/4, 1/2].choose.wait; + ~bleep.spawn([ + freq: 2 / [50, 100, 200, 400].choose / [2, 1].choose, + fb: 1.rand, release: 2]); + [0.5, 1/4, 1/2].choose.wait; + } +}); +