Note off in pbind

I’m sending patterns from SC to a VST. There’s a weird glitch i can’t seem to solve: whenever i stop the Pbind and then resume it, the VST fails to play the FIRST note, because the last midi event it received right before me stopping the Pbind was a noteOn, not a noteOff, and therefore the first noteOn event with the same note number gets ignored until the corresponding noteOff has been sent. That’s what i think is happening btw,
I only realised this thanks to midimonitor.app. does this make sense?
And more importantly, how do I fix it?

for reference, here’s my Pbind:

~x.stop; ~x = Pbind(\type, \midi, \chan, 3, \midicmd, \noteOn, \midiout, m, \midinote, Prand([40, 41, 42, 43], inf), \dur, 1, \amp, Pseq([1], inf), \legato, 1).play;

thanks!
n

1 Like

Hm, the \midi event’s \note subtype will send the note-off even if the pattern player has been stopped.

But it sends the note-off according to the event’s timing. Stopping the pattern player only prevents new events from being played – it doesn’t affect the scheduling of anything that prior events had done. (This is true for SC synths too.)

So I guess what is happening is:

  1. Pbind generates an event.
  2. EventStreamPlayer plays the event.
  3. The event sends note-on now, and schedules note-off for one beat later.
  4. In the middle of this one beat, you do ~x.stop and immediately ~x = Pbind(...).play. This will start immediately – it doesn’t wait for the next beat.
  5. At this point, if the Pbind generates the same note number as the last event to be played (25% chance of that, in your pattern), then the event will immediately produce a note-on for a note that hasn’t had its note-off.

One possible solution might be to .play(quant: 1) (wait for the next beat) or .play(quant: -1) (wait for the next bar line). This might still fail in some cases but it’s better than nothing.

Or, you could wrap Pbind into something that will do a cleanup action.

~x.stop;
~x = Pfset(
	nil,
	Pbind(\type, \midi, \chan, 3, \midicmd, \noteOn, \midiout, m, \midinote, Prand([40, 41, 42, 43], inf), \dur, 1, \amp, Pseq([1], inf), \legato, 1),
	{ 128.do { |n| m.noteOff(3, n) } }  // this is cleanup
).play;

That’s a bit verbose, but you could simplify by creating a function to wrap and play the pattern.

~playMIDI = { |pattern|
	Pfset(nil, pattern, { 128.do { |n| m.noteOff(3, n) } }).play;
};

// then
~x.stop;
~x = ~playMIDI.(Pbind(...));

hjh

2 Likes

Still to test extensively, but Pfset’s cleanupFunc looks like a really nice solution (which i did not know of). Thanks!!