Hello!
What OS are you on? I believe that the way operating systems specify MIDI ports might be different.
I’m on MacOS, so if you are as well, things should work as described. Otherwise check out the help docs for MIDI.
The function itself should work the same, no matter you OS, except the argument for specifying which controller you want (the srcID
key)
If you have a specific controller in mind, but have several, and want the function to ignore others, you can figure out its srcID
by first evaluating MIDIClient.init
and then MIDIIn.connectAll
.
If not you can skip this next part.
See what all the sources are by providing MIDIClient
the sources
message to get an array of all your MIDI inputs.
MIDIClient.init;
MIDIIn.connectAll;
MIDIClient.sources;
/* mine returns the following in the post window
-> [ MIDIEndPoint("Console 1 Fader", "Console 1 Fader", -881897415), MIDIEndPoint("Sensel Morph", "Sensel Morph", 1281011945), MIDIEndPoint("Console 1", "Console 1", -920073526), MIDIEndPoint("TOUCHE_SE", "Main Port", 1922042393), MIDIEndPoint("TOUCHE_SE", "Control Port", -1670561750) ]
srcID
in the MIDIdef
actually is looking for the uid
, which is the long string of numbers in each list).
A good way to get it that ties it to the controller rather than the order it’s initialized in is to use MIDIIn.findPort
.
For instance I set this up with the Sensel Morph, so this code returns its uid
:
MIDIIn.findPort("Sensel Morph", "Sensel Morph").uid
If I wanted to use the Touche, I would have written MIDIIn.findPort("TOUCHE_SE", "Main Port").uid
.
The function itself exploits the fact that you can get or set the volume with s.volume
or s.volume = someDecibelValue
. The dB range is -90 to +6. Since MIDI CC ranges from 0 to 127, I used the linlin
message to scale MIDI to dB. This allows for linear response. If you want some sort of curve, you can try .lincurve(0, 127, -90, 6, -4)
, where the -4 is the curve, negative values create a more exponential response, the lower the value the more exponential.
And then it’s just a matter of setting s.volume
equal to that scaled value.
(
var mididb;
MIDIdef.cc(\globalVol, { |val, cc, chan, key|
// server volume mapped -90 though 6dB
mididb = val.linlin(0, 127, -90, 6);
// mididb.postln;
// mididb = mididb.round(0.001) // optional to quantize a bit
s.volume = mididb;
},
ccNum: 74, // change to desired CC value here
chan: nil, // leave nil for all channels, or specify. note! that channel count starts at 0 (MIDI Ch 1 == 0)
srcID: MIDIIn.findPort("Sensel Morph", "Sensel Morph").uid, // set nil to listen to all connected controllers, or specify a uid
);
MIDIdef.cc(\globalVol).permanent = true; // if this isn't set to true, cmd + period will kill the def
)
If you want this control to always work, and not need to be custom loaded, you can stick it in your startup file (file menu drop down > open startup file).
You’ll need to run
MIDIClient.init;
MIDIIn.connectAll;
first, so you can stick the def below those two lines.
And the best place to put is probably inside the s.waitForBoot
function. If you don’t have one in your start up file, you can create one and place it in your startup file (you can only have one waitForBoot
):
s.waitForBoot {
MIDIClient.init;
MIDIIn.connectAll;
(
var mididb;
MIDIdef.cc(\globalVol, { |val, cc, chan, key|
// server volume mapped -90 though 6dB
mididb = val.linlin(0, 127, -90, 6);
// mididb.postln;
// mididb = mididb.round(0.001) // optional to quantize a bit
s.volume = mididb;
},
ccNum: 74, // change to desired CC value here
chan: nil, // leave nil for all channels, or specify. note! that channel count starts at 0 (MIDI Ch 1 == 0)
srcID: MIDIIn.findPort("Sensel Morph", "Sensel Morph").uid, // set nil to listen to all connected controllers, or specify a uid
);
MIDIdef.cc(\globalVol).permanent = true; // if this isn't set to true, cmd + period will kill the def
);
};