Big cleanup

This commit is contained in:
2024-01-05 16:18:18 +01:00
parent afda9b886e
commit ef107a9277
14 changed files with 91 additions and 337 deletions

View File

@ -1,5 +1,6 @@
/*
* This file is taken from: https://gist.github.com/scztt/73a2ae402d9765294ae8f72979d1720e
* I have added a method to list the samples in the bank.
*/
Bank : Singleton {

View File

@ -55,16 +55,6 @@
^correctedPattern;
}
// pat {
// arg node_proxy, quant=4, fade=0.05;
// var newArray = this ++ [\type, \buboEvent];
// node_proxy.quant_(quant);
// node_proxy.fadeTime = fade;
// node_proxy[0] = Pbind(*(this.findShortcuts(newArray)));
// ^node_proxy;
// }
pat {
arg quant=4, fade=0.05;
var proxyName = this[0];

View File

@ -1,3 +0,0 @@
+ Ndef {
}

View File

@ -1,2 +0,0 @@
+ Pbind {
}

View File

@ -1,5 +0,0 @@
PlotTree {
*new {
^Server.default.plotTree.window.alwaysOnTop_(true);
}
}

View File

@ -1,4 +1,5 @@
+ String {
sp {
arg sampleNumber = 0, repeats=inf;
^Pindex(Bank(this), sampleNumber, repeats);
@ -7,4 +8,5 @@
p {
^Pdv.parse(this)
}
}

View File

@ -3,4 +3,5 @@ FScope {
*new {
^Server.default.freqscope.window.alwaysOnTop_(true);
}
}

View File

@ -1,5 +1,7 @@
Gui {
*new {
^Server.default.makeGui.window.alwaysOnTop_(true);
}
}

View File

@ -3,4 +3,5 @@ Scope {
*new {
^Server.default.scope.window.alwaysOnTop_(true);
}
}

View File

@ -1,3 +0,0 @@
c = currentEnvironment.clock;
MIDIClient.init;
m = MIDIOut.newByName("MIDI", "Bus 1");

View File

@ -1,291 +0,0 @@
d = (); // This is a storage area for synthesizers
f = (); // This is a storage for various FX functions
(
d.info = { arg obj, name; obj[name].allControlNames.do({arg i; i.postln;}); };
d.show = { 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));
};
(
z = SynthDef.new(\sampler, {
arg buf, rate=1, amp=1, pan=0, attack=0.01, release=1, loop=0;
var sig;
var env = EnvGen.ar(Env.perc(attack, release, doneAction: 2));
var startPos = 0;
sig = PlayBuf.ar(
numChannels: 1,
bufnum: buf,
rate:BufRateScale.kr(buf) * rate,
trigger: 1, startPos:startPos,
loop:loop, doneAction: 2);
sig = sig * amp;
sig = Pan2.ar(sig * env, pan);
Out.ar(0, sig);
}).add;
d.sampler = z;
);
(
z = SynthDef.new(\revsampler, {
arg buf, rate=1, amp=1, pan=0, attack=0.01, release=1, loop=1;
var sig;
var env = EnvGen.ar(Env.perc(attack, release, doneAction: 2));
var startPos = 0;
sig = PlayBuf.ar(
numChannels: 1,
bufnum: buf,
rate:BufRateScale.kr(buf) * rate,
trigger: 1, startPos:startPos,
loop:loop, doneAction: 2);
sig = sig * amp;
sig = Pan2.ar(sig * env, pan);
Out.ar(0, sig);
}).add;
d.revsampler = z;
);
(
z = SynthDef(\sinfb, {
arg freq = 440, atk = 0.01, sus = 0, rel = 1, fb = 0, amp = 0.3, out = 0, pan=0;
var sig, env;
env = EnvGen.ar(Env.linen(atk,sus,rel),1,1,0,1,2);
sig = SinOscFB.ar(freq,fb,1);
sig = sig*env;
Out.ar(out,Pan2.ar(sig,pan,amp));
}).add;
d.sinfb = z;
);
(
z = SynthDef(\kick2, {
var snd;
snd = DC.ar(0);
snd = snd + (HPF.ar(Hasher.ar(Sweep.ar), 1320) * Env.perc(0.003, 0.03).ar * 0.5);
snd = snd + (SinOsc.ar(XLine.ar(750, 161, 0.02)) * Env.perc(0.0005, 0.02).ar);
snd = snd + (SinOsc.ar(XLine.ar(167, 52, 0.04)) * Env.perc(0.0005, 0.3).ar(2));
snd = snd.tanh;
Out.ar(\out.kr(0), Pan2.ar(snd, \pan.kr(0), \amp.kr(0.9)));
}).add;
d.kick2 = z;
);
(
z = SynthDef(\kick3, {
var snd;
snd = DC.ar(0);
snd = snd + (SinOsc.ar(XLine.ar(1500, 800, 0.01)) * Env.perc(0.0005, 0.01, curve: \lin).ar);
snd = snd + (BPF.ar(Impulse.ar(0) * SampleRate.ir / 48000, 6100, 1.0) * 3.dbamp);
snd = snd + (BPF.ar(Hasher.ar(Sweep.ar), 300, 0.9) * Env.perc(0.001, 0.02).ar);
snd = snd + (SinOsc.ar(XLine.ar(472, 60, 0.045)) * Env.perc(0.0001, 0.3, curve: \lin).delay(0.005).ar(2));
snd = snd.tanh;
Out.ar(\out.kr(0), Pan2.ar(snd, \pan.kr(0), \amp.kr(0.1)));
}).add;
d.kick3 = z;
);
(
z = SynthDef("snare", {arg amp = 0.1, freq = 100, att = 0.01, rel = 0.2, ffreq = 2000, pan = 0;
var env, snd1, snd2, sum;
env = Env.perc(att, rel, amp).kr;
snd1 = HPF.ar(
in: WhiteNoise.ar,
freq: ffreq
);
snd2 = SinOsc.ar(freq: freq);
sum = snd1 + snd2;
sum = sum * env;
Out.ar(0, Pan2.ar(sum, pan));
DetectSilence.ar(sum, doneAction: 2);
}).add;
d.snare = z;
);
(
z = SynthDef("hihat", {arg amp = 0.5, att = 0.01, rel = 0.2, ffreq = 6000, pan = 0;
var env, snd;
env = Env.perc(
attackTime: att,
releaseTime: rel,
level: amp*1.2
).kr;
snd = WhiteNoise.ar;
snd = HPF.ar(in: snd, freq: ffreq);
snd = snd * env;
Out.ar(0, Pan2.ar(snd, pan));
DetectSilence.ar(snd, doneAction: 2);
}).add;
d.hihat = z;
);
(
z = SynthDef(\kick1, {
var snd;
snd = DC.ar(0);
snd = snd + (SinOsc.ar(XLine.ar(800, 400, 0.01)) * Env.perc(0.0005, 0.01).ar);
snd = snd + (BPF.ar(Hasher.ar(Sweep.ar), XLine.ar(800, 100, 0.01), 0.6) * Env.perc(0.001, 0.02).delay(0.001).ar);
snd = snd + (SinOsc.ar(XLine.ar(172, 50, 0.01)) * Env.perc(0.0001, 0.3, 1, \lin).delay(0.005).ar(2));
snd = snd.tanh;
Out.ar(\out.kr(0), Pan2.ar(snd, \pan.kr(0), \amp.kr(0.1)));
}).add;
d.kick1 = z;
);
(
z = SynthDef(\braids, {|out=0,freq=440,amp=0.5,sustain=1,pan=0,begin=0,end=1,speed=1,accelerate=0,timbre=0.5,color=0.5,model=0|
var envLength = sustain*(end-begin)/speed;
var line = Line.ar(begin, end, envLength, doneAction: Done.freeSelf);
var env = Env.asr;
var volume = IEnvGen.ar(env, line) * amp;
var sig;
freq = max(0, freq * speed * (1 + (accelerate * line)));
sig = MiBraids.ar(pitch: freq.cpsmidi, timbre: timbre, color: color, model: model);
Out.ar(out, Pan2.ar(sig * volume, pan));
}).add;
d.braids = z;
);
(
z = SynthDef(\omi, {|out=0,freq=440,amp=0.5,sustain=1,pan=0,begin=0,end=1,speed=1,accelerate=0|
var envLength = sustain*(end-begin)/speed;
var line = Line.ar(begin, end, envLength, doneAction: Done.freeSelf);
var env = Env.asr;
var volume = IEnvGen.ar(env, line) * amp;
var sig;
freq = max(0, freq * speed * (1 + (accelerate * line)));
sig = MiOmi.ar(pit: freq.cpsmidi);
Out.ar(out, Pan2.ar(sig * volume, pan));
}).add;
d.omi = z;
);
(
[
'analog', 'waveshape',
'fm', 'grain',
'additive', 'wavetable',
'chord', 'speech',
'swarm', 'noise',
'particle', 'string',
'modal', 'bass',
'snare', 'hat'
].do({arg name, index;
var synth;
[name, index].postln;
synth = SynthDef(name, {|out=0,freq=440,sustain=1,pan=0,begin=0,end=1,speed=1,accelerate=0,
amp=0.5,timbre=0.5,harm=0.5,morph=0.5,level=1,lpgdecay=0,lpgcolour=0,mode=0|
var envLength = sustain*(end-begin)/speed;
var line = Line.ar(begin, end, envLength, doneAction: Done.freeSelf);
var env = Env.asr;
var volume = IEnvGen.ar(env, line) * amp;
var sig;
freq = max(0, freq * speed * (1 + (accelerate * line)));
sig = MiPlaits.ar(
pitch: freq.cpsmidi,
timbre: timbre,
harm: harm,
engine: index,
morph: morph,
level: level,
decay: lpgdecay,
lpg_colour: lpgcolour,
);
sig = Select.ar(mode, sig);
Out.ar(out, Pan2.ar(sig * volume, pan));
}).add;
d.put(name, synth);
});
);
(
['csaw', 'morph', 'saw_square', 'sine_triangle',
'buzz', 'square_sub', 'saw_sub', 'square_sync',
'saw_sync', 'triple_saw', 'triple_square',
'triple_triangle', 'triple_sine', 'triple_ring_mod',
'saw_swarm', 'saw_comb', 'toy', 'filter_lp',
'filter_pk', 'filter_bp', 'filter_hp', 'vosim',
'vowel', 'vowel_fof', 'harmonics', 'bfm', 'feedback_fm',
'chaotic_feedback_fm', 'plucked', 'bowed', 'blown', 'fluted',
'struck_bell', 'struck_drum', 'bkick', 'cymbal', 'bsnare',
'bwavetable', 'wave_map', 'wave_line', 'wave_paraphonic',
'filtered_noise', 'twin_peaks_noise', 'clocked_noise',
'granular_cloud', 'particle_noise', 'digital_modulation',
'question_mark'].do({
arg name, index;
var synth;
synth = SynthDef(name, {|out=0,freq=440,amp=0.5,sustain=1,pan=0,begin=0,end=1,speed=1,accelerate=0,timbre=0.5,color=0.5,ws=0,bits=0, resamp=0, decim=32|
var envLength = sustain*(end-begin)/speed;
var line = Line.ar(begin, end, envLength, doneAction: Done.freeSelf);
var env = Env.asr;
var volume = IEnvGen.ar(env, line) * amp;
var sig;
freq = max(0, freq * speed * (1 + (accelerate * line)));
sig = MiBraids.ar(pitch: freq.cpsmidi, timbre: timbre, resamp: 0, decim: decim, color: color, model: index, ws: ws, bits:bits);
Out.ar(out, Pan2.ar(sig * volume, pan));
}).add;
d.put(name, synth);
});
);
(
z = SynthDef(\plaits, {|out=0,freq=440,sustain=1,pan=0,begin=0,end=1,speed=1,accelerate=0,
amp=0.5,timbre=0.5,engine=0,harm=0.5,morph=0.5,level=1,lpgdecay=0,lpgcolour=0,mode=0|
var envLength = sustain*(end-begin)/speed;
var line = Line.ar(begin, end, envLength, doneAction: Done.freeSelf);
var env = Env.asr;
var volume = IEnvGen.ar(env, line) * amp;
var sig;
freq = max(0, freq * speed * (1 + (accelerate * line)));
sig = MiPlaits.ar(
pitch: freq.cpsmidi,
timbre: timbre,
harm: harm,
engine: engine,
morph: morph,
level: level,
decay: lpgdecay,
lpg_colour: lpgcolour,
);
sig = Select.ar(mode, sig);
Out.ar(out, Pan2.ar(sig * volume, pan));
}).add;
d.plaits = z;
);
(
z = SynthDef(\tides, {|out=0,freq=440,amp=0.5,sustain=1,pan=0,begin=0,end=1,speed=1,accelerate=0,tidesshape=0.5,slope=0.5,tidessmooth=0.5,shift=0.5,mode=2|
var envLength = sustain*(end-begin)/speed;
var line = Line.ar(begin, end, envLength, doneAction: Done.freeSelf);
var env = Env.asr;
var volume = IEnvGen.ar(env, line) * amp;
var sig;
freq = max(0, freq * speed * (1 + (accelerate * line)));
sig = MiTides.ar(
freq: freq,
shape: tidesshape,
slope: slope,
smooth: tidessmooth,
shift: shift,
output_mode: mode,
ramp_mode: 1,
rate: 1
);
Out.ar(out, Pan2.ar(sig * volume, pan));
}).add;
d.tides = z;
);
z = nil; // We don't need that variable anymore

107
README.md
View File

@ -1,7 +1,10 @@
# BuboQuark: Simple, hassle-free live coding
This repository is a collection of tools and methods that I use to make live coding easier on **SuperCollider**. My aim is to make that setup easy to install on my other computers. This repository is not bringing anything new or interesting. This is merely a default configuration for my **SuperCollider** install. It's just a bunch of scripts that I use to make my life easier and I am no expert. I rely heavily on **JITLib** and other Quarks that I find useful.
This repository is a collection of methods and hacks that I found to make live
coding easier on **SuperCollider**. A secondary goal is to make that setup easy
to install on other computers. This Quark is not bringing a lot of new features
and it twists the langauge in a way that is highly personal. Internally, it
relies a lot on **JITLib**, **Patterns** and **NodeProxies**.
## Installation
@ -9,32 +12,71 @@ To install the **BuboQuark**, simply run the following command in your favorite
```bash
Quarks.install("https://github.com/Bubobubobubobubo/BuboQuark")
```
To make use of the existing synth definitions, you will have to install the
[mi-Ugens](https://github.com/v7b1/mi-UGens), a collection of **SuperCollider**
UGens taken from Mutable Instruments module designs. Note that it is also
preferable to install [sc3-plugins](https://github.com/supercollider/sc3-plugins), the official **UGen** extension suite for **SuperCollider**.
## Usage
All the other dependencies will be installed automatically when installing the
**Quark**.
This quark brings syntax shortcuts and minor improvements (_highly personal matter_) to make **SuperCollider** easier to handle on stage.
## How to use BuboQuark?
### Boot method
The main goal of **BuboQuark** is to provide everything you need to live code right out of the box. It is a balance between staying close to the initial language features while offering convenient shortcuts when possible:
There is a `Boot()` class that acts as a configuration file for my setup. This configuration file is rather classic:
- **boot** the server with a suitable configuration for live coding
- **facililate** the use of patterns and blending with audio functions
- **simplify** the use of `NodeProxy` roles for FX and mixing
- **synchonize** the clock with other applications
- **share** the audio signals easily with other applications
- raises the conservative options of `Server.default`
**SuperCollider** already possesses everything you need to do so. It is just not pre-arranged by default.
It is a programming language after all, you have to do some work to get it right.
### Booting the server
There is a `Boot()` pseudo-class that acts as a configuration file. This configuration file is rather classic:
- raises the conservative options of `Server.default` to allow more connexions,
more buffers, etc.
- set the ProxySpace clock to use `LinkClock` for syncing with other
applications
- pushes everything into a `ProxySpace`
- set paths for samples and synthdefs
- install a `StageLimiter` not to blow up my speakers
- make the default environment a **JITLib** `ProxySpace`
- Set custom default paths for sample and SynthDefs loading
- Install a `StageLimiter` not to blow up the speakers
The `LinkClock` is accessible through the `c` global variable.
The `Boot()` constructor takes three arguments:
**Note:** I put my configuration into `./config/livecoding/` and there should be a folder named `samples/` and a file called `Synthdefs.scd`.
- `configPath`: path to a `.scd` configuration file that will be automatically
loaded
- `samplePath`: path to a folder containing your audio samples (in sub-folders)
- `soundDevice`: name of the sound device to use
All of these arguments are optional. However, they will default to my
configuration if not set. If you want to set one option but not the others, use
keywords arguments or `nil` values: `Boot(soundDevice: "BlackHole 16ch")`.
### Controlling the clock
The `LinkClock` is accessible through the `c` global variable. Be careful not to
override it. It behaves like a regular `TempoClock` with the usual methods.
There are a few useful methods to control it and to use it efficiently:
- `c.tempo` : set or get the current tempo (will change other peers tempo)
- `c.beatDur` : duration of a beat
I use these methods very frequently when writing delay lines and time-based
effects.
### Events
I am using some Events as classes to store some of the things I want to load with each session (FX templates, SynthDef reference, etc). I am using :
I am using some Events as pseudo-classes to store some things I want to keep track on during the session (FX templates, SynthDef reference, etc). I am using :
- `d`: **D**efinitions (`SynthDefs`)
- `f`: **F**X templates (DSP functions with a simple name)
- `d.list` : list all the available SynthDefs
- `d.params('synth_name')` : list the parameters of a SynthDef
- `f`: **F**X templates (DSP functions accessible through a simple name)
To use one of the effects, you can use the following syntax:
@ -42,43 +84,57 @@ To use one of the effects, you can use the following syntax:
~my_ndef.fx(100, 0.5, f[\vardel]);
```
### Simplified useful commands
These are not really hard-coded. They are in my `.scd` configuration files. You
can ignore this section entirely if you do things differently!
### Simplified Server/Gui Control
I like when SC panels stay on top of other applications by default:
- `Panic()`: shortcut for `CmdPeriod.run`.
- `Boot(path)`: boot my config (**hardcoded** path or user specified path)
- `Scope()`: a scope that always stays on top!
- `FScope()`: a frequency scope that always stay on top!
- `Gui()`: a server GUI window that always stay on top!
### Patterns
### Pattern tweaks
Patterns are powerful but writing them is long and can lead to a lot of typing errors. Moreover, they are often centered around list manipulation. **BuboQuark** defines a few helpers to transform a regular `Array` into various patterns:
```supercollider
[1, 2, 3, 4].pseq
```
Consider the source as a documentation.
### Patterns
Consider the source as a documentation. You will find all the additional methods
in `BuboString` or `BuboArray`. I am not entirely convinced by shortening the
most complex Pattern types because they are complex after all. Consider blending
the regular syntax with shortcuts when necessary.
I don't like using keys because of the backslash (`\`), a symbol that is really hard to type on AZERTY keyboards. For that reason, I much prefer the `[instrument: 'plaits', dur: 2]` syntax. I added a `.pat` method to convert an array into a `Pbind`. There are optional arguments to specify the `fadeTime` and `quant` for that pattern. Demo:
### Pbind
I don't like using keys because of the backslash (`\`), a symbol that is really hard to type on **AZERTY** keyboards. For that reason, I much prefer the `["my_pattern", instrument: 'plaits', dur: 2]` syntax. I added a `.pat` method to convert an array into a `Pbind`. There are optional arguments to specify the `fadeTime` and `quant` for that pattern. Demo:
```supercollider
(
[
"name_of_pattern",
instrument: 'sinfb',
rel: Pbrown(0.1, 0.5, 0.125, inf),
note: Place([Pxrand([0, 3, 7, 10], 12), 0, 3, 5, 0, 12, 0, 7, 5, [5, 10, 7].pwhite(1)], inf),
octave: [Pxrand([5, 6, 4], 4)].pxrand(inf), dur: Pbjorklund2(6, 8, inf) / 2,
legato: 0.1
].pat(~test).play;
].pat.play;
)
```
`.pat` take a few optional arguments:
- `quant` (defaults to `4`): pattern quantization (**LinkClock**)
- `fade` (defaults to `0.05`): fading time (**NodeProxy**)
There is also the `.p` function that will just turn the array into a `Pbind` without any additional behavior. This is useful when dealing with classic `NodeProxy Roles` like `\set` and `\xset`.
### NodeProxy
The `NodeProxy` roles are somewhat verbose. I have tried to make the syntax easier on the eye by creating the `fx`, `wet` and `infx` methods. Here is a demo of how I use it:
The `NodeProxy` roles are sometimes a bit verbose to my taste. I have tried to make the syntax easier on the eye by creating the `fx`, `wet` and `infx` methods. Here is a demo of how I use it:
```supercollider
(
@ -90,3 +146,8 @@ The `NodeProxy` roles are somewhat verbose. I have tried to make the syntax easi
~test.wet(10, 0.5) // bring the reverb up with the wet method
```
There is also `.fxin` and `.wet` functions, shortcuts for the `\filter` and
`\filterIn` NodeProxy mechanisms. I have also added some rather shady functions
that automatically pick up a slot for a specific fx: `fx1`, `fx2`, up to `fx9`.