A very common pattern in SuperCollider is to have a responder (GUI, MIDI, OSC, HID…) that controls a resource.
playerThingy = Something(....);
guiControl = AGuiWidget(...)
.action_({ |view|
playerThingy.setSomeControl(... value based on view...);
});
This is a general pattern that can be used in many contexts… including this one. The resource is the MonoPortaVoicer. The MIDIdefs are the responders.
Also, a useful methodology in cases like this is to be figure out how to control the resource programmatically first – only after you’re sure you can get the desired result by code, then you can put that code into the responders. (A development principle of “solve one problem at a time” – instead of thinking “how do I use MIDI to control this object that I never used before” = two problems muddled into one, you could think “1/ how do I use this object? 2/ how do I do #1 with MIDI” = step by step, solve two problems in turn).
So, MonoPortaVoicer first:
(
SynthDef(\lead, { |out, gate = 1,
freq = 440, freqlag = 0.1, detun = 1.008, pan = 0,
ffreq = 1200, ffreqMul = 3, ffreqDcy = 0.15, rq = 0.2,
atk = 0.005, dcy = 0.2, sus = 0.6, rel = 0.1|
// Voicer uses 'gate' for velocity
var amp = Latch.kr(gate, gate).linlin(0, 1, 0.05, 0.25);
var freqs = Lag.kr(freq, freqlag) * [1, detun];
var filtEg = EnvGen.kr(Env([ffreqMul, ffreqMul, 1], [0, ffreqDcy], \exp), gate);
var eg = EnvGen.kr(Env.adsr(atk, dcy, sus, rel), gate, doneAction: 2);
var sig = Saw.ar(freqs).sum;
sig = RLPF.ar(sig, (ffreq * filtEg).clip(20, 20000), rq);
Out.ar(out, Pan2.ar(sig, pan, amp * eg));
}).add;
)
v = MonoPortaVoicer(1, \lead);
v.portaTime = 0.15;
v.trigger(60.midicps, 0.5); // plays C
v.trigger(64.midicps, 0.5); // glides to E
// let go of E -- glides back to C
v.release(64.midicps);
// after this, no more keys are held
// so the note fully releases
v.release(60.midicps);
Then for MIDI, all that is necessary is to take the control statements (which were just worked out) and put them into the MIDIdefs:
(
MIDIdef.noteOn(\on, { |vel, num|
v.trigger(num.midicps, vel/127);
});
MIDIdef.noteOff(\off, { |vel, num|
v.release(num.midicps);
});
)
hjh