MIDIClient.init; // initialize MIDI m = MIDIOut(0); // get the first output device
Routine { // use a Routine (aka a thread) for synchronization with the server s = Server.default; s.boot; s.sync; // wait for the server to be ready
// a control-rate bus which our synth will write to
~lfo_out_bus = Bus.control(s, 1);
// make a new synthdef (a control-rate sine)...
~lfo = SynthDef.new(\lfo, {
arg hz=1, out, mul=1, add=0;
Out.kr(out, SinOsc.kr(hz, mul:mul, add:add));
}).play(target:s, ///... and play it on the server...
args: [ //... with some arguments...
\out, ~lfo_out_bus.index // ... including the target bus
]
);
// now there are different things we could do to read the bus.
// here, we'll just explicitly read values from it in an endless loop.
inf.do {
~lfo_out_bus.get(
// getting a bus value is asnychronous, so the method takes a callback...
{
arg val; // ...whose argument is the bus value.
var scaled; // the value is in [-1, 1], so we want to rescale it
scaled = (val+1)/2 * 127;
postln(scaled);
m.control(1, 10, scaled); // send it out on CC 10, channel 1 (or 2 if your client is 1-based!)
}
);
0.1.wait; // initiate a read every 100 milliseconds
// (we could go faster but this is so we don't choke on the print statements)
}
}.play; // make everything go
/// if we want to, say, modulate the LFO speed with another lfo, /// another control bus is the way to do it
// this is a bit hacky, but we'll just make another routine here... Routine { 8.wait; // ... and use it to wait for some arbitrary time for the earlier stuff to happen ~lfo_hz_bus = Bus.control(s, 1); // make another bus ~lfo.map(\hz, ~lfo_hz_bus); // map it to the synth ~lfo_mod = Synth.new(\lfo, // we already sent this def to the server args: [ \hz, 0.2, // slower \add:1.1, // scaled up to [0.1, 2.1] \out, ~lfo_hz_bus.index // and sending to the modulation bus ], target: ~lfo, addAction:\addBefore // make sure the modulator executes before its destination ); }.play; // make it go
I am also using this solution but the outgoing MIDI control values have discontinuities and produce clicks. So there needs to be an interpolation - but how would that work (since it is not on the server)?