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:
- Pbind generates an event.
- EventStreamPlayer plays the event.
- The event sends note-on now, and schedules note-off for one beat later.
- 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.
- 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