Synchronising for Rémi

This commit is contained in:
2024-01-21 16:19:41 +01:00
parent 7eeb172dba
commit 1777d5758c
16 changed files with 565 additions and 312 deletions

View File

@ -9,12 +9,14 @@
since: "2023",
schelp: "BuboQuark",
dependencies: [
"https://github.com/cappelnord/BenoitLib",
"https://github.com/scztt/Singleton.quark",
"https://github.com/scztt/Require.quark",
"https://github.com/dmorgan-github/Pdv",
"https://github.com/supercollider-quarks/Bjorklund",
"https://github.com/adcxyz/SafetyNet",
"https://github.com/madskjeldgaard/nodeproxygui2",
"https://github.com/capital-G/sc-grids",
],
url: "https://raphaelforment.fr",
isCompatible: {Main.versionAtLeast(3, 1)},

View File

@ -1 +0,0 @@
Eu : Pbjorklund2 {}

View File

@ -10,98 +10,70 @@
^Pindex(pat, this[1], repeats)
}
findShortcuts {
arg pattern;
var short, correctedPattern;
correctedPattern = List.new();
short = Dictionary.newFrom([
// Instrument
\i, \instrument,
// Notes
\n, \note,
\mn, \midinote,
\vel, \velocity,
\deg, \degree,
\off, \timingOffset,
\o, \octave,
\f, \freq,
\det, \detune,
// Durations
\d, \dur,
\l, \legato,
// Amplitude
\p, \pan,
// Envelope
\a, \attack,
\d, \decay,
\s, \sustain,
\r, \release,
// Filter control
\r, \resonance,
\ff, \ffreq,
// Modulation
\m, \mod,
\mo, \midout,
\c, \midichan,
\st, \stretch,
\rt, \root,
\scl, \scale,
]);
// shortcuts are turned into regular keys;
pattern.do({| element |
if (short.includesKey(element),
{correctedPattern.add(short[element])},
{correctedPattern.add(element)}
);
});
^correctedPattern;
}
pat {
arg quant=4, fade=0.05;
var proxyName = this[0];
var newArray = this[1..] ++ [\type, \buboEvent];
currentEnvironment.at(proxyName.asSymbol).quant_(quant);
currentEnvironment.at(proxyName.asSymbol).fadeTime = fade;
currentEnvironment.at(proxyName.asSymbol)[0] = Pbind(*(this.findShortcuts(newArray)));
currentEnvironment.at(proxyName.asSymbol)[0] = Pbind(*(EventShortener.findShortcuts(newArray)));
^currentEnvironment.at(proxyName.asSymbol);
}
pwrap {
arg maxIndex, startIndex=0, repeats=inf;
^PwrapSeq(this, maxIndex, startIndex, repeats)
}
p {
^Pbind(*(this.findShortcuts(this)))
^Pbind(*(Eventshortener.findShortcuts(this)))
}
euclid {
eu {
arg repeats=inf;
^Pbjorklund2(this[0], this[1], repeats);
var divisor = 1;
if (this[3] != nil, { divisor = this[3] });
^Pbjorklund2(this[0], this[1], repeats, this[2]) / divisor;
}
pseq { arg repeats=inf, offset=0;
^Pseq(this, repeats, offset);
pseq {
arg repeats=inf;
^Pseq(this, repeats);
}
pshuf { arg repeats=1;
pshuf {
arg repeats=1;
^Pshuf(this, repeats);
}
prand { arg repeats=inf;
prand {
arg repeats=inf;
^Prand(this, repeats);
}
pxrand { arg repeats=inf;
pxrand {
arg repeats=inf;
^Pxrand(this, repeats);
}
pwrand { arg weights, repeats=1;
pwrand {
arg weights, repeats=1;
^Pwrand(this, weights.normalizeSum, repeats);
}
pwhite { arg repeats=inf;
pwhite {
arg repeats=inf;
^Pwhite(this[0], this[1], repeats);
}
pseries { arg repeats=inf;
pseries {
arg repeats=inf;
^Pseries(this[0], this[1], repeats);
}
pbrown {
arg repeats=inf;
^Pbrown(this[0], this[1], this[2], repeats);
}
}

View File

@ -8,13 +8,7 @@ Boot {
*new {
arg configPath, samplePath, serverOptions;
var p; var c; var t; var s;
var banner = "┳┓ ┓ ┳┓\n"
"┣┫┓┏┣┓┏┓ ┣┫┏┓┏┓╋\n"
"┻┛┗┻┗┛┗┛ ┻┛┗┛┗┛┗";
var ready = "┓ ┳┓┏┏┓ ┏┓┏┓┳┓┏┓ ┳┓┏┓┏┓┳┓┓┏\n"
"┃ ┃┃┃┣ ┃ ┃┃┃┃┣ ┣┫┣ ┣┫┃┃┗┫\n"
"┗┛┻┗┛┗┛ ┗┛┗┛┻┛┗┛ ┛┗┗┛┛┗┻┛┗┛";
this.fancyPrint(banner, 40);
BuboUtils.fancyPrint(BuboUtils.banner, 40);
if (serverOptions == nil,
{
@ -55,29 +49,18 @@ Boot {
Server.default.waitForBoot({
"-> Loading config from: %".format(configPath ? (this.localPath +/+ "Startup.scd")).postln;
(configPath ? (this.localPath +/+ "Startup.scd")).load;
Safety.setLimit(0.8);
this.fancyPrint(ready, 40);
Safety.all;
Safety(s).defName = \safeLimit;
Safety.setLimit(1);
BuboUtils.fancyPrint(BuboUtils.ready, 40);
this.installServerTreeBehavior();
this.clock.enableMeterSync();
});
}
*fancyPrint {
arg message, length;
var separator= length.collect({
arg index;
if (index % 2 == 0, "=", "-")
});
separator = separator.join("");
[separator, message, separator].do({
arg each;
each.postln;
});
}
*installServerTreeBehavior {
CmdPeriod.add({
this.fancyPrint("\nBubo SuperCollider Session\nTempo: % | Peers: %\nCPU: % | Peak: %\n".format(
BuboUtils.fancyPrint("\nBubo SuperCollider Session\nTempo: % | Peers: %\nCPU: % | Peak: %\n".format(
this.clock.tempo * 60, this.clock.numPeers,
Server.default.avgCPU.round(2),
Server.default.peakCPU.round(2)), 40)
@ -88,6 +71,7 @@ Boot {
{ ~buf = Bank(~sp)[~nb % Bank(~sp).buffers.size]; }
);
if (~nb == nil) {~nb = 0};
if (~sp == nil) {~sp = 'default'};
~type = \note;
currentEnvironment.play;
});

16
Classes/BuboEnv.sc Normal file
View File

@ -0,0 +1,16 @@
+ Env {
*rand {
arg numSegs=8, dur=1, bipolar=true;
var env, levels, times, curves, minLevel;
levels = {rrand(-1.0, 1.0)}!numSegs+1;
minLevel = bipolar.asInteger.neg;
levels = levels.normalize(minLevel, 1);
times = {exprand(1,10)}!numSegs;
times = times.normalizeSum * dur;
curves = {rrand(-4.0,4.0)}!numSegs;
env = this.new(levels, times, curves);
^env;
}
}

View File

@ -1,5 +1,7 @@
+ NodeProxy {
/* Simple FX chain management */
fx {
arg number=1, wet=1, function = {|in| in};
this[number] = \filter -> function;
@ -34,4 +36,54 @@
this.set(("wet" ++ number).asSymbol, wet);
^this;
}
/* Player-like syntax sugar */
=> {
arg pattern;
pattern = EventShortener.findShortcuts(pattern);
pattern = pattern ++ [\type, \buboEvent];
this[0] = Pbind(*pattern);
this.quant = 4; this.fadeTime = 0.01;
^this
}
/* FIX: Completely broken. What is the event type
* BuboEvent should fall back to after tweaking
* the pattern to my liking?
*/
-> {
arg pattern;
pattern = EventShortener.findShortcuts(pattern);
// pattern = pattern ++ [\type, \buboMonoEvent];
this[0] = Pmono(*pattern);
this.quant = 4;
this.fadeTime = 0.01;
}
f {
arg value;
this.fadeTime = value;
^this
}
p {
arg quant, fade;
this.quant = quant;
this.fadeTime = fade;
this.play(fadeTime: fade);
^this
}
s {
arg duration;
this.stop(fadeTime: duration)
^this
}
/ {
arg pattern;
this.stop(1);
^this
}
}

30
Classes/BuboUtils.sc Normal file
View File

@ -0,0 +1,30 @@
BuboUtils {
*banner {
var banner = "┳┓ ┓ ┳┓\n"
"┣┫┓┏┣┓┏┓ ┣┫┏┓┏┓╋\n"
"┻┛┗┻┗┛┗┛ ┻┛┗┛┗┛┗";
^banner
}
*ready {
var ready = "┓ ┳┓┏┏┓ ┏┓┏┓┳┓┏┓ ┳┓┏┓┏┓┳┓┓┏\n"
"┃ ┃┃┃┣ ┃ ┃┃┃┃┣ ┣┫┣ ┣┫┃┃┗┫\n"
"┗┛┻┗┛┗┛ ┗┛┗┛┻┛┗┛ ┛┗┗┛┛┗┻┛┗┛";
^ready
}
*fancyPrint {
arg message, length;
var separator= length.collect({
arg index;
if (index % 2 == 0, "=", "-")
});
separator = separator.join("");
[separator, message, separator].do({
arg each;
each.postln;
});
}
}

View File

@ -3,4 +3,4 @@ p = currentEnvironment;
c = currentEnvironment.clock;
"Loading SynthDefs".postln;
"Synthdefs.scd".loadRelative;
// m = MIDIOut.newByName("MIDI", "Bus 1");
m = MIDIControl();

View File

@ -16,124 +16,86 @@ f.vardel = {
* This is the sampler used for 90% of sampling duties.
*/
(
z = SynthDef.new(\s, {
arg buf, out=0, freq=440, rate=1, amp=1, begin=0, end=1, pan=0, attack=0.01, release=1, loop=0;
var sig;
var env = EnvGen.ar(Env.perc(attack, release, doneAction: 2));
var startPos = begin * BufFrames.kr(buf);
var endPos = end * BufFrames.kr(buf); // TODO: unused
z = SynthDef.new(\player, {
arg buf;
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(
numChannels: 1,
bufnum: buf,
rate:BufRateScale.kr(buf) * (rate * freq / 60.midicps),
rate:BufRateScale.kr(buf) * (\rate.kr(1) * \freq.kr(400) / 60.midicps),
trigger: 1, startPos:startPos,
loop:loop, doneAction: 2);
sig = sig * amp;
sig = Pan2.ar(sig * env, pan);
OffsetOut.ar(out, sig)
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)
}).add;
d.s = z;
d.player = z;
);
/*
* Stereo variant
*/
(
z = SynthDef.new(\splayer, {
arg buf;
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(
numChannels: 2,
bufnum: buf,
rate:BufRateScale.kr(buf) * (\rate.kr(1) * \freq.kr(400) / 60.midicps),
trigger: 1, startPos:startPos,
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)
}).add;
d.splayer = 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));
env = EnvGen.ar(
Env.linen(
\attack.kr(0.01),
\sustain.kr(0),
\release.kr(1)
),1,1,0,1,2);
sig = SinOscFB.ar(
\freq.kr(400),
\fb.kr(0),
1
);
sig = sig * env;
OffsetOut.ar(\out.kr(0), Pan2.ar(sig, \pan.kr(0), \amp.kr(-6.dbamp)));
}).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(\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);
z = SynthDef(\omi, {
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;
var volume = IEnvGen.ar(env, line) * \amp.kr(-6.dbamp);
var sig;
freq = max(0, freq * speed * (1 + (accelerate * line)));
sig = MiOmi.ar(pit: freq.cpsmidi);
Out.ar(out, Pan2.ar(sig * volume, pan));
sig = MiOmi.ar(pit: \freq.kr(400).cpsmidi);
OffsetOut.ar(\out.kr(0), Pan2.ar(sig * volume, \pan.kr(0)));
}).add;
d.omi = z;
);
@ -141,52 +103,33 @@ f.vardel = {
(
[
'analog', 'waveshape',
'fm', 'grain',
'additive', 'wavetable',
'chord', 'speech',
'swarm', 'noise',
'particle', 'string',
'modal', 'bass',
'snare', 'hat'
'Panalog', 'Pwaveshape', 'Pfm', 'Pgrain',
'Padditive', 'Pwavetable', 'Pchord', 'Pspeech',
'Pswarm', 'Pnoise', 'Pparticle', 'Pstring',
'Pmodal', 'Pbass', 'Psnare', 'Phat'
].do({arg name, index;
var synth;
synth = SynthDef(name, {
arg out,
freq=440,
attack=0.01,
decay=0.3,
sustain=0.5,
release=1.0,
pan=0,
speed=1,
accelerate=0,
amp=1,
alt=1,
timbre=0.5,
harm=0.5,
morph=0.5,
level=1,
gate=1,
lpgdecay=0,
lpgcolour=0,
mode=0;
var env = EnvGen.ar(Env.adsr(attack, decay, sustain, release, curve: [2, -4, -4]), doneAction: Done.freeSelf, gate: gate);
var sig;
freq = max(0, freq * speed * (1 + (accelerate * env)));
sig = MiPlaits.ar(
pitch: freq.cpsmidi,
timbre: timbre,
harm: harm,
engine: index,
morph: morph,
level: level,
decay: lpgdecay,
lpg_colour: lpgcolour,
var env = EnvGen.ar(
Env.perc(
\attack.kr(0.01),
\release.kr(1)
), doneAction: Done.freeSelf
);
sig = Pan2.ar(sig[0], pan);
sig = sig * env * amp;
OffsetOut.ar(out, sig);
var sig;
sig = MiPlaits.ar(
pitch: \freq.kr(400).cpsmidi,
timbre: \timbre.kr(0),
harm: \harm.kr(0),
engine: index,
morph: \morph.kr(0),
level: \level.kr(1),
decay: \lpgdecay.kr(0),
lpg_colour: \lpgcolour.kr(0),
);
sig = Pan2.ar(sig[0], \pan.kr(0));
sig = sig * env * \amp.kr(-6.dbamp);
OffsetOut.ar(\out.kr(0), sig);
}).add;
d.put(name, synth);
});
@ -194,68 +137,91 @@ f.vardel = {
(
['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({
[
'Bcsaw',
'Bmorph',
'Bsaw_square',
'Bsine_triangle',
'Bbuzz',
'Bsquare_sub',
'Bsaw_sub',
'Bsquare_sync',
'Bsaw_sync',
'Bt_saw',
'Bt_square',
'Bt_triangle',
'Bt_sine',
'Bt_ring_mod',
'Bsaw_swarm',
'Bsaw_comb',
'Btoy',
'Bfilter_lp',
'Bfilter_pk',
'Bfilter_bp',
'Bfilter_hp',
'Bvosim',
'Bvowel',
'Bvowel_fof',
'Bharmonics',
'Bbfm',
'Bfeedback_fm',
'Bchaotic_feedback_fm',
'Bplucked',
'Bbowed',
'Bblown',
'Bfluted',
'Bstruck_bell',
'Bstruck_drum',
'Bbkick',
'Bcymbal',
'Bbsnare',
'Bbwavetable',
'Bwave_map',
'Bwave_line',
'Bwave_paraphonic',
'Bfiltered_noise',
'Btwin_peaks_noise',
'Bclocked_noise',
'Bgranular_cloud',
'Bparticle_noise',
'Bdigital_modulation',
'Bquestion_mark'].do({
arg name, index;
var synth;
synth = SynthDef(name, {
arg out,
freq=440,
amp=1,
attack=0.01,
decay=0.3,
sustain=0.5,
release=1.0,
pan=0,begin=0,
end=1,speed=1,
accelerate=0,
timbre=0.5,
color=0.5,
ws=0,bits=0,
resamp=0,
decim=32,
gate=1;
var sig;
var env = EnvGen.ar(Env.adsr(attack, decay, sustain, release, curve: [2, -4, -4]), doneAction: Done.freeSelf, gate: gate);
freq = max(0, freq * speed * (1 + (accelerate * env)));
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 * env * amp, pan));
var env = EnvGen.ar(Env.perc(\attack.kr(0.01), \release.kr(1)), doneAction: Done.freeSelf);
var freq = \freq.kr;
sig = MiBraids.ar(
pitch: freq.cpsmidi,
timbre: \timbre.kr(0),
color: \color.kr(0),
resamp: 0,
decim: \decim.kr(32),
model: index,
ws: \ws.kr(0),
bits: \bits.kr(0)
);
OffsetOut.ar(\out.kr(0), Pan2.ar(sig * env * \amp.kr(-6.dbamp), \pan.kr(0)));
}).add;
d.put(name, synth);
});
);
(
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,
z = SynthDef(\tides, {
var env = Env.perc(\attack.kr(0.01), \release.kr(1)).ar(2);
var sig = MiTides.ar(
freq: \freq.kr(400),
shape: \shape.kr(0),
slope: \slope.kr(0),
smooth: \smooth.kr(0),
shift: \shift.kr(0),
output_mode: \mode.kr(2),
ramp_mode: 1,
rate: 1
);
Out.ar(out, Pan2.ar(sig * volume, pan));
OffsetOut.ar(\out.kr(0), Pan2.ar(sig * env * \amp.kr(-6.dbamp), \pan.kr(0)));
}).add;
d.tides = z;
);

View File

@ -0,0 +1,135 @@
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;
};
});
}
}

50
Classes/EventShortener.sc Normal file
View File

@ -0,0 +1,50 @@
EventShortener {
*findShortcuts {
arg pattern;
var short, correctedPattern;
correctedPattern = List.new();
short = Dictionary.newFrom([
// Instrument
\i, \instrument,
// Notes
\n, \note,
\mn, \midinote,
\vel, \velocity,
\deg, \degree,
\off, \timingOffset,
\o, \octave,
\f, \freq,
\det, \detune,
// Durations
\d, \dur,
\l, \legato,
// Amplitude
\p, \pan,
// Envelope
\a, \attack,
\d, \decay,
\s, \sustain,
\r, \release,
// Filter control
\r, \resonance,
\ff, \ffreq,
// Modulation
\m, \mod,
\mo, \midout,
\c, \midichan,
\st, \stretch,
\rt, \root,
\scl, \scale,
]);
// shortcuts are turned into regular keys;
pattern.do({| element |
if (short.includesKey(element),
{correctedPattern.add(short[element])},
{correctedPattern.add(element)}
);
});
^correctedPattern;
}
}

View File

@ -1,7 +0,0 @@
FScope {
*new {
^Server.default.freqscope.window.alwaysOnTop_(true);
}
}

View File

@ -1,3 +1,43 @@
Scope {
*new {
^Server.default.scope.window.alwaysOnTop_(true);
}
}
Meter {
*new {
var window = Window.new(
"Meter",
Rect.new(left: 0, top: 0, width: 680, height: 250),
resizable: false,
border: true,
scroll: false
);
var meters = ServerMeterView.new(
Server.default, window,
0@0, 16, 16
);
window.front;
window.alwaysOnTop = true;
^window
}
}
FScope {
*new {
^Server.default.freqscope.window.alwaysOnTop_(true);
}
}
Gui {
*new {

View File

@ -1,28 +0,0 @@
Scope {
*new {
^Server.default.scope.window.alwaysOnTop_(true);
}
}
Meter {
*new {
var window = Window.new(
"Meter",
Rect.new(left: 0, top: 0, width: 680, height: 250),
resizable: false,
border: true,
scroll: false
);
var meters = ServerMeterView.new(
Server.default, window,
0@0, 16, 16
);
window.front;
window.alwaysOnTop = true;
^window
}
}

30
Classes/Patterns/PXo.sc Normal file
View File

@ -0,0 +1,30 @@
Pxo {
*new {
arg expression, divisor=1, repeats=inf;
var xoExp = Array.new(maxSize: expression.size);
expression.do({
arg char, i;
if (char == $x, {xoExp.add(1, i)}, {xoExp.add(Rest(), i)})
});
xoExp = xoExp.collect({arg item; item / divisor});
^Pseq.new(xoExp, repeats)
}
}
Ptx {
*new {
arg expression, repeats=inf;
var xoExp = Array.new(maxSize: expression.size);
expression.do({
arg char, i;
switch(char)
{$@} {xoExp.add(2, i)}
{$O} {xoExp.add(1, i)}
{$o} {xoExp.add(0.5, i)}
{$°} {xoExp.add(0.25, i)}
{} {xoExp.add(Rest(), i)};
});
^Pseq.new(xoExp, repeats)
}
}

View File

@ -0,0 +1,12 @@
/* This one is taken from Mads Kjeldgaard's */
/* https://github.com/madskjeldgaard/Monolithic/blob/main/Classes/Pattern/PwrapSeq.sc */
PwrapSeq{
*new{
arg array, maxIndex, startIndex=0, repeats=inf;
var indexPat = Pseries.new(startIndex, 1, length: inf) % (maxIndex+1);
^Pindex.new(listPat: array, indexPat: indexPat, repeats: repeats)
}
}