Combine note on/off messages

Although notOff messages are nothing but noteOn with zero velocity, they are filtered out from MIDIdef. noteOn. But I noticed, that control messages (if physically exist as buttons) keep booth values - with velocity 127 when pressed and velocity 0 when released. So it is very convenient to test “if” functions, start or stop something etc. when two different values are generated within MIDIDef. cc

Here is wrong example, but I just want to illustrate how I think or MIDIDef. noteOn can be used. Is it possible to set noteOn args correctly? If not, what other methods you would suggest?

MIDIIn.connectAll;

m = MIDIOut(0);

MIDIdef.noteOn(\onA, {
	arg vel, nn, chan;
	 m.noteOn(chan, nn, vel);
}, [0,1,2,3,4,5,6,7]
);

MIDIdef.noteOff(\offA, {
	arg vel, nn, chan;
	MIDIdef.set(\onA, [chan, nn, vel]);  // with this I whant to rewrite noteOn values
}, [0,1,2,3,4,5,6,7]
);

There is actually a separate note off message in the midi spec, which includes a velocity parameter that some controllers use to indicate how gentle your release was: MIDI Specification: Note-Off

The spec declares that note on messages with 0 velocity should be treated as note offs: MIDI Specification: Note-On

But, if you want them to be treated as note ons, you can set MIDIIn.noteOnZeroAsNoteOff = false

1 Like

Yes, this is exactly what I was trying to achieve. Thanks, Eric!

One thing to be aware of is that MIDIIn.noteOnZeroAsNoteOff = false allows MIDI note-on messages with velocity = 0 to be passed through to a noteOn responder, but it does not convert incoming noteOff messages (status byte 0x80 to 0x8F) into note-on with velocity = 0. (I did actually test this by sending “128 60 12” through Pd [midiout] to SC – SC receives it always as a note off message, regardless of the flag.)

So this flag is useful only for devices or software that send note-off as “note-on, velocity 0.” (It happens that Max and Pure Data do it this way, but it shouldn’t be inferred that the Max/Pd way is the only correct or the ideal way.)

If you’re using the same SC code with devices that send the note-off message type, then you would still have to register a noteOff function.

hjh

Thanks for comment. I Just need that for “has changed” like behavior so “if” test can give to different results when pressed or released.

I understand, but I’m saying two things:

  1. If you use noteOnZeroAsNoteOff then your code is specific to MIDI sources that send note-off as a note-on with velocity = 0. This is not guaranteed – your thread starts with the assertion that “noteOff messages are nothing but noteOn with zero velocity” but this is not universally true. If you need to use it with a different device at some time in the future, and that device sends true note-offs, then you will have to rewrite it anyway. So that flag gives you what you want for now, but there’s a risk of the code not being future-proof.

  2. You can still get the “changed” behavior. What I would do is encapsulate the state into a factory function that builds the responders:

(
~makeNoteChangedResponder = { |name|
	var playing = false;
	var func = { |num, shouldPlay|
		if(shouldPlay != playing) {
			"Changed to %!\n".postf(playing);
			playing = shouldPlay;  // save for next
		};
	};
	MIDIdef.noteOn(name, { |vel, num|
		func.value(num, vel > 0);
	});
	MIDIdef.noteOff(name, { |vel, num|
		func.value(num, false); // always off here
	});
};
)

You can add other conditions as needed, or pass in the actual velocity.

I realized that you would prefer not to define both a noteOn and noteOff responder, but that’s a preference – there is no limitation in terms of functionality.

hjh