Pattern midi control

hi there,

help appreciated. I am working on osx 15.6.1 with supercollider 3.14.0.
I copied more or less from the help doc and it worked a view days ago:

MIDIClient.init;

// MIDI target
~midiOut = MIDIOut.newByName("Univer Inter", "Univer Inter").latency_(Server.default.latency);

(
Pbindef(\modul,
    \type, \midi,
    \midicmd, \noteOn,
	\midiout, "~midiOut",    // MIDI target
    \chan, [0, 1],
    \degree, Pwhite(-7, 12, inf),
	\sustain, Pseq([Pwhite(0.2, 0.8, 1), 0.8, 3], inf),
    \dur, Pseq([1, 1, 4], inf),
).play(quant: 1);
//).quant = 1;
)

I get the following error message

-> Pbindef('modul', 'type', 'midi', 'midicmd', 'noteOn', 'midiout', "~midiOut", 'chan', [0, 1], 'degree', Pwhite(-7, 12), 'sustain', Pseq([Pwhite(0.2, 0.8, 1), 0.8, 3], inf), 'dur', Pseq([1, 1, 4], inf))
ERROR: Message 'uid' not understood.
Perhaps you misspelled 'add', or meant to call 'uid' on another receiver?
RECEIVER:
Instance of String {    (0x1444b7238, gc=40, fmt=07, flg=10, set=02)
  indexed slots [8]
      0 : ~
      1 : m
      2 : i
      3 : d
      4 : i
      5 : O
      6 : u
      7 : t
}
ARGS:
KEYWORD ARGUMENTS:
PATH: /Users/sebastianlex/supercollider/learning_again/daily/2025-08-31_midi.scd

PROTECTED CALL STACK:
	Meta_MethodError:new	0x14083d640
		arg this = DoesNotUnderstandError
		arg what = nil
		arg receiver = ~midiOut
	Meta_DoesNotUnderstandError:new	0x14083fe00
		arg this = DoesNotUnderstandError
		arg receiver = ~midiOut
		arg selector = uid
		arg args = []
		arg keywordArgumentPairs = []
	Object:doesNotUnderstand	0x1402b43c0
		arg this = ~midiOut
		arg selector = uid
		arg args = nil
		arg kwargs = nil
	a FunctionDef	0x141b0b2c0
		sourceCode = "#{|server|
						var freqs, lag, dur, sustain, strum;
						var bndl, midiout, hasGate, midicmd;

						freqs = ~freq = ~detunedFreq.value;

						~amp = ~amp.value;
						~midinote = (freqs.cpsmidi).round(1).asInteger;
						strum = ~strum;
						lag = ~lag;
						sustain = ~sustain = ~sustain.value;
						midiout = ~midiout.value;
						~uid ?? { ~uid = midiout.uid };  // mainly for sysex cmd
						hasGate = ~hasGate ? true;
						midicmd = ~midicmd;
						bndl = ~midiEventFunctions[midicm...etc..."
		arg server = localhost
		var freqs = 783.9908719635
		var lag = 0.0
		var dur = nil
		var sustain = 0.60756022930145
		var strum = 0.0
		var bndl = nil
		var midiout = ~midiOut
		var hasGate = nil
		var midicmd = nil
	a FunctionDef	0x141afddc0
		sourceCode = "#{
					var tempo, server, eventTypes, parentType;

					parentType = ~parentTypes[~type];
					parentType !? { currentEnvironment.parent = parentType };

					server = ~server = ~server ? Server.default;

					~finish.value(currentEnvironment);

					tempo = ~tempo;
					tempo !? { thisThread.clock.tempo = tempo };


					if(currentEnvironment.isRest.not) {
						eventTypes = ~eventTypes;
						(eventTypes[~type] ?? { eventTypes[\\note] }).value(server)
					};

					~callback.value(current...etc..."
		var tempo = nil
		var server = localhost
		var eventTypes = ('fadeBus': a Function, 'freeAllocWrite': a Function, 'tree': a Function, 'instr': a Function, 
  'on': a Function, 'load': a Function, 'freeBuffer': a Function, 'group': a Function, 'freeAllocRead': a Function, 
  'allocWrite': a Function, 'cue': a Function, 'grain': a Function, 'Synth': a Function, 'freeAllocWriteID': a Function, 
  'alloc': a Function, 'rest': a Function, 'sine2': a Function, 'sine1': a Function, 'midi': a Function, 
  'set': a Function, 'setProperties': a Function, 'parGroup': a Functio...etc...
		var parentType = nil
	a FunctionDef	0x141aa72c0
		sourceCode = "<an open Function>"
	a FunctionDef	0x141a9ffc0
		sourceCode = "<an open Function>"
	Function:prTry	0x140b510c0
		arg this = a Function
		var result = nil
		var thread = a Routine
		var next = a Function
		var wasInProtectedFunc = true
	Function:protect	0x140b50640
		arg this = a Function
		arg handler = a Function
		var result = nil
	Environment:use	0x141a9fb40
		arg this = ('degree': 11, 'dur': 1, 'midiout': ~midiOut, 'amp': 0.1, 
  'sustain': 0.60756022930145, 'server': localhost, 'midinote': 79, 'midicmd': noteOn, 'freq': 783.9908719635, 
  'chan': [0, 1], 'type': midi)
		arg function = a Function
		var result = nil
		var saveEnvir = Environment[(midiOut -> a MIDIOut)]
	Event:play	0x141aa7080
		arg this = ('degree': 11, 'dur': 1, 'midiout': ~midiOut, 'amp': 0.1, 
  'sustain': 0.60756022930145, 'server': localhost, 'midinote': 79, 'midicmd': noteOn, 'freq': 783.9908719635, 
  'chan': [0, 1], 'type': midi)
	Event:playAndDelta	0x141ae0400
		arg this = ('degree': 11, 'dur': 1, 'midiout': ~midiOut, 'amp': 0.1, 
  'sustain': 0.60756022930145, 'server': localhost, 'midinote': 79, 'midicmd': noteOn, 'freq': 783.9908719635, 
  'chan': [0, 1], 'type': midi)
		arg cleanup = an EventStreamCleanup
		arg mute = false
	EventStreamPlayer:prNext	0x1413f7800
		arg this = an EventStreamPlayer
		arg inTime = 828.0
		var nextTime = nil
		var outEvent = ('degree': 11, 'dur': 1, 'midiout': ~midiOut, 'amp': 0.1, 
  'sustain': 0.60756022930145, 'server': localhost, 'midinote': 79, 'midicmd': noteOn, 'freq': 783.9908719635, 
  'chan': [0, 1], 'type': midi)
		var roundedBeat = nil
		var deltaFromRounded = nil
	a FunctionDef	0x1413f5640
		sourceCode = "<an open Function>"
	Function:prTry	0x140b510c0
		arg this = a Function
		var result = nil
		var thread = a Routine
		var next = nil
		var wasInProtectedFunc = false
	
CALL STACK:
	DoesNotUnderstandError:reportError
		arg this = <instance of DoesNotUnderstandError>
	Nil:handleError
		arg this = nil
		arg error = <instance of DoesNotUnderstandError>
	Thread:handleError
		arg this = <instance of Thread>
		arg error = <instance of DoesNotUnderstandError>
	Thread:handleError
		arg this = <instance of Routine>
		arg error = <instance of DoesNotUnderstandError>
	Object:throw
		arg this = <instance of DoesNotUnderstandError>
	Function:protect
		arg this = <instance of Function>
		arg handler = <instance of Function>
		var result = <instance of DoesNotUnderstandError>
	Routine:prStart
		arg this = <instance of Routine>
		arg inval = 828.0
^^ ERROR: Message 'uid' not understood.
Perhaps you misspelled 'add', or meant to call 'uid' on another receiver?
RECEIVER: ~midiOut

Maybe this:

\midiout, "~midiOut",    // MIDI target

should be:

	\midiout, ~midiOut,    // MIDI target

Best,
Paul

1 Like

what paul said.
Also (slightly OT), just because I found this out a few days ago: The MIDIOut doc contains a faulty example that implies that you can send bend cmds along with noteons, and (from what I understand), you can’t.
So the following won’t send bend messages:

a = Pbind(\degree, Prand([1, 2, 3, [0, 5]], inf), \bend, Pwhite(0, 76, inf));

instead, this will

Pbind(\midicmd, \bend, \val, Pwhite(0, 76, inf))

and one has to Ppar this with a note pattern to coordinate bends or other non-noteOn commands with \midicmd. E.g.:

MIDIClient.init;
m = MIDIOut(0);  // Linux users: MIDIOut(0, MIDIClient.destinations[0].uid);

d = Pbind(\dur, Pseq([0.3,0.3,0.3,0.2,0.2]);

a = Pbind(\midicmd, \noteOn, \degree, Prand([1, 2, 3, [0, 5]], inf)) <> d;

b = Pbind(\midicmd, \control, \control, Pwhite(0, 76, inf)) <> d;

(Ppar([a,b]) <> (type: \midi, midiout: m)).play;

It may also be possible that one can do, e.g., Pbidn(\midicmd, [\control, \noteOn]), but I can’t try this now.

1 Like

Good catch, right, that example should be changed. (Also the 0-75 range for pitch bend? Don’t think so.)

That isn’t supported. I think it wouldn’t be too difficult, but a potential problem is that multiple commands use the same event data keys: if midiCmd == [\touch, \bend], both of those use val, but touch’s val should be 0 - 127 while bend’s should be 0 - 16383. So there would be limitations that aren’t obvious.

One workaround is a callback function to perform extra events:

a = Pbind(
	\type, \midi,
	\midiout, m,
	\degree, Prand([1, 2, 3, [0, 5]], inf),
	\bend, Pwhite(-6000, 6000, inf) + 8192,
	\callback, {
		~midiout.bend(0, ~bend)
	}
).play;

hjh

2 Likes

thank you! that solved it.

(but why?)

(but why?)

~midiOut is an environmental variable which the interpreter will resolve to whatever you assigned to it, "~midiOut" is a string which the interpreter won’t resolve to anything because it doesn’t know that it should. computers are dumb that way.

1 Like