Last active
March 30, 2018 20:08
-
-
Save albertoventurini/43f86d156deb3ba64ef9734c792d3f9c to your computer and use it in GitHub Desktop.
Multi oscillator synth written in Supercollider
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
( | |
s.meter; | |
s.freqscope; | |
s.plotTree; | |
) | |
( | |
var g0 = Group.new(s); // g0 = main synth group | |
var g1 = Group.after(g0); // g1 = effect group | |
var b0 = Bus.audio(s); | |
var b1 = Bus.audio(s); | |
var makeSlider, makeChoice; | |
var getBus; | |
var busses = Dictionary.new(0); | |
var choices = Dictionary.new(0); | |
var notes = Array.newClear(128); | |
Window.closeAll; | |
w = Window("gui", Rect(750, 50, 1200, 800)).front; | |
w.view.decorator_(FlowLayout(w.bounds, 15@15, 7@7)); | |
makeChoice = { | |
arg name, items, initValue = 0; | |
var view, menu, bus; | |
bus = Bus.control(s); | |
busses.put(name, bus); | |
view = CompositeView(w, 200@100); | |
menu = PopUpMenu(view, 200@50) | |
.items_(items) | |
.action_({ |obj| | |
obj.value.postln; | |
bus.set(obj.value); | |
//choices.add(name -> obj.item); | |
}); | |
StaticText(view, Rect(0, 60, 80, 20)).string_(name); | |
menu.valueAction = initValue; | |
}; | |
makeChoice.value("osc1_type", items: [\sin, \tri, \saw, \pulse]); | |
makeChoice.value("osc1_octave", items: [-2, -1, 0, 1, 2], initValue: 2); | |
makeChoice.value("osc2_type", items: [\sin, \tri, \saw, \pulse]); | |
makeChoice.value("osc2_octave", items: [-2, -1, 0, 1, 2], initValue: 2); | |
makeChoice.value("osc3_type", items: [\sin, \tri, \saw, \pulse]); | |
makeChoice.value("osc3_octave", items: [-2, -1, 0, 1, 2], initValue: 2); | |
makeSlider = { | |
arg name, min = 0, max = 1, initValue = 0, exponential = false; | |
var view, slider, numberBox, value, onUpdate, valToSlider, sliderToVal, bus; | |
bus = Bus.control(s); | |
busses.put(name, bus); | |
bus.set(initValue); | |
onUpdate = { |val| | |
val.postln; | |
bus.set(val); | |
}; | |
// Transform a number from the range (min, max) to the range (0, 1) | |
valToSlider = { |val| | |
if(exponential, val.explin(min, max, 0, 1), val.linlin(min, max, 0, 1)); | |
}; | |
// Transform a number in the range (0, 1) to the range (min, max) | |
sliderToVal = { |val| | |
if(exponential, val.linexp(0, 1, min, max), val.linlin(0, 1, min, max)); | |
}; | |
view = CompositeView(w, 120@200); | |
slider = Slider(view, Rect(0, 0, 30, 120)); | |
numberBox = NumberBox(view, Rect(0, 125, 80, 25)).clipLo_(min).clipHi_(max).decimals_(4); | |
slider.action = { |obj| | |
var val = sliderToVal.value(obj.value); | |
numberBox.value_(val); | |
onUpdate.value(val); | |
}; | |
numberBox.action = { |obj| | |
var sliderVal = valToSlider.value(obj.value); | |
slider.value_(sliderVal); | |
onUpdate.value(obj.value); | |
}; | |
StaticText(view, Rect(0, 150, 80, 20)).string_(name); | |
numberBox.valueAction_(initValue); | |
}; | |
makeSlider.value("lfo1_freq", 0, 10, 1); | |
makeSlider.value("osc1_amp", 0, 1, 0.1); | |
makeSlider.value("osc2_amp", 0, 1, 0.1); | |
makeSlider.value("osc3_amp", 0, 1, 0.1); | |
makeSlider.value("osc1_detune", 0.9, 1.1, 1); | |
makeSlider.value("osc2_detune", 0.9, 1.1, 1); | |
makeSlider.value("osc3_detune", 0.9, 1.1, 1); | |
makeSlider.value("osc1_pw", 0, 1, 0.7); | |
makeSlider.value("osc2_pw", 0, 1, 0.34); | |
makeSlider.value("osc3_pw", 0, 1, 0.49); | |
makeSlider.value("attack", 0, 5, 0.1); | |
makeSlider.value("decay", 0, 1, 0); | |
makeSlider.value("sustain", 0, 1, 1); | |
makeSlider.value("release", 0, 5, 1); | |
makeSlider.value("filter_cutoff", 220, 15000, 220, exponential: true); | |
makeSlider.value("filter_res", 0.05, 0.95, 0.5); | |
makeSlider.value("filter_attack", 0, 5, 0); | |
makeSlider.value("filter_decay", 0, 1, 0); | |
makeSlider.value("filter_sustain", 0, 1, 1); | |
makeSlider.value("filter_release", 0, 5, 5); | |
SynthDef.new(\synth, { | |
arg freq = 440, outbus = 0, gate = 1, amp = 0.15, ffreqBus = 0, rqBus = 0; | |
var osc1, osc2, osc3, lfo1, sig, env, ffreq, rq, pw1, pw2, pw3, fenv, getOsc; | |
lfo1 = SinOsc.kr(In.kr(busses["lfo1_freq"])).range(0.9, 1.1); | |
getOsc = { |name| | |
var detune = In.kr(busses[name ++ "_detune"]); | |
var amp = In.kr(busses[name ++ "_amp"]); | |
var pulseWidth = In.kr(busses[name ++ "_pw"]); | |
var octave = pow(2, In.kr(busses[name ++ "_octave"]) - 2); | |
Select.ar(which: In.kr(busses[name ++ "_type"]), array: [ | |
SinOsc.ar(freq * detune * octave, mul: amp)!2, | |
LFTri.ar(freq * detune * octave, mul: amp)!2, | |
VarSaw.ar(freq * detune * octave, width: pulseWidth * lfo1, mul: amp)!2, | |
Pulse.ar(freq * detune * octave, width: pulseWidth * lfo1, mul: amp)!2 | |
]); | |
}; | |
osc1 = getOsc.value("osc1"); | |
osc2 = getOsc.value("osc2"); | |
osc3 = getOsc.value("osc3"); | |
env = EnvGen.kr(Env.adsr(In.kr(busses["attack"]), In.kr(busses["decay"]), In.kr(busses["sustain"]), In.kr(busses["release"])), gate, doneAction: 2); | |
sig = Mix.ar([osc1, osc2, osc3]); | |
sig = sig * env * amp; | |
ffreq = In.kr(busses["filter_cutoff"]); | |
fenv = EnvGen.kr(Env.adsr(In.kr(busses["filter_attack"]), In.kr(busses["filter_decay"]), In.kr(busses["filter_sustain"]), In.kr(busses["filter_release"])), gate, doneAction: 2); | |
ffreq = ffreq * fenv; | |
rq = In.kr(busses["filter_res"]); | |
//rq = 0.5; | |
sig = RLPF.ar(sig, ffreq, rq); | |
Out.ar(outbus, sig); | |
}).add; | |
MIDIdef.noteOn(\noteOn, { | |
arg vel, nn, chan, src; | |
[vel, nn, chan, src].postln; | |
notes[nn] = Synth.new(\synth, [ | |
\freq, nn.midicps, | |
\gate, 1, | |
\outbus, 0, | |
\osc1_type, 123 | |
], g0); | |
}); | |
MIDIdef.noteOff(\noteOff, { | |
arg vel, nn; | |
[vel, nn].postln; | |
notes[nn].set(\gate, 0); | |
notes[nn] = nil; | |
}); | |
) | |
( | |
MIDIClient.init; | |
MIDIIn.connectAll; | |
) | |
( | |
~notes = [30, 34, 37, 42, 46, 49]; | |
p = Pdef(\pattern, | |
Pbind( | |
\instrument, \synth, | |
\midinote, Prand(~notes.collect({ |n| n + 12 }), inf), | |
\dur, 0.25 | |
) | |
).play; | |
) | |
p.stop; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment