Basic question - getting value from MIDI controller

Hey, I’m new to SuperCollider, so please excuse a very basic question. I’m trying to just control the frequency of a SinOsc with a MIDI-controller slider. Why doesn’t this work, and how can I get it to work? (Isn’t global-variable “a” just being set to the incoming value from the MIDI controller?

s.boot;
(
SynthDef(\testOsc, {
    | freq=440 |

    Out.ar([0, 1], SinOsc.ar(freq, 0, 0.5));
}).add;
)

(
MIDIClient.init;
MIDIIn.connectAll;
a = MIDIFunc.cc({arg first; first.postln}, 13, 0);
z = Synth.new(\testOsc, [\freq, a]);
z.scope;
)

i think from the docs that you’re using it wrong. see one of the examples from the bottom of http://doc.sccode.org/Classes/MIDIFunc.html

b = MIDIFunc.cc({arg ...args; args.postln}, 1, 1); // match cc1, chan 1
b.free; // cleanup

the first argument to .cc is a callback function which is called on every midi event and the arguments ...args contains the stuff you want, so you need to put the logic inside the cb function. see the func description here for how to craft it http://doc.sccode.org/Classes/MIDIFunc.html#*new and get the midi values.

Hi htor,

Thanks for your help. Since ...args returns an array, a[0] should return the first value of that array (or b as you have it), correct? However, this still does not work:

z = Synth.new(\testOsc, [\freq, a[0]]);

Ah, okay, I think I understand better. We need to set a variable to the value of arg[0] with an anonymous function inside of MIDIFunc.cc. Am I close with this one? (Still doesn’t compile unfortunately…)

(
MIDIClient.init;
MIDIIn.connectAll;
a = MIDIFunc.cc({arg ...args; v = args[0] }, 13, 0);
z = Synth.new(\testOsc, [\freq, v]);
z.scope;
)

Just setting a variable won’t update the synth. (It takes the value of the variable at the time of constructing the synth and doesn’t keep a “link”.) What you can do instead depends on what you want to achieve:

  1. if you want to update the frequency of an already sounding synth, you can use the set method in the MIDIFunc.cc, e.g. z.set(\freq, args[…]). Make sure the Synth is already alive before you try to call set on it.

  2. if instead you want to sound a completely new note at the time of receiving a cc message, you can instantiate a new Synth in the MIDIFunc

To get a feeling about the contents of arguments like arg or args, you can use methods like postln or debug(“my message”), e.g. args.debug(“value of args”) in the MIDIFunc. These will print out the contents to the post window.

hi, am sorry if this is really basic, but could you please explain a bit more how you use the set method within a MIDIFunc? And also if the arg …args thing remains like this? It looks really weird to me and I am a bit confused :smiling_face:

my synth is called \shower and I would like to update the \pitch via the MIDI-CC messages of a controller-knob:


MIDIFunc.cc({\shower.set(\pitch, {arg ...args}, ccNum: 1, chan: 0)});

thank you very much :innocent:

Hi jsn,

so if you’ve connected your midi controller with:

MIDIIn.connectAll

and then made it listen to cc 1 with this:

MIDIFunc.cc({arg ...args; args.postln}, 1); // match cc 1

When you move your controller now you will get an array of values posted in the post window, kind of like this:

[ 0, 1, 0, -1316835968 ]
[ 1, 1, 0, -1316835968 ]
[ 2, 1, 0, -1316835968 ]
[ 4, 1, 0, -1316835968 ]
[ 6, 1, 0, -1316835968 ]
[ 8, 1, 0, -1316835968 ]

This is the args.postln posting information: [value, number, channel, source].
Value is the value that the midi controller is outputting.
Number is the cc number, 1 in this case as the MIDIFunc is listening for it.
Channel is the midi channel.
Source is the midi source id.

Since it’s the value part of the info from ‘args’ that you want, you would like to grab the first item in the array args[0], the value, to be sent to your synth. Something like this:

x= Synth(\shower); //start your synth first
MIDIFunc.cc({ arg ...args; x.set(\pitch, args[0]); }, 1);
1 Like