AUv3 - clarification of MIDI Event times

Hi JUCE devs,

Just a quick question about the AU layer interpretation of MIDI Event times.

juce_AUv3_Wrapper.mm uses this callback function:

AUMIDIOutputEventBlock midiOutputEventBlock = nullptr;

Which has this signature:

/*!	@typedef	AUMIDIOutputEventBlock
	@brief		Block to provide MIDI output events to the host.
	@param eventSampleTime
		The timestamp associated with the MIDI data in this chunk.
	@param cable
		The virtual cable number associated with this MIDI data.
	@param length
		The number of bytes of MIDI data in the provided event(s).
	@param midiBytes
		One or more valid MIDI 1.0 events, except sysex which must always be sent as the only event
		in the chunk.
*/
typedef OSStatus (^AUMIDIOutputEventBlock)(AUEventSampleTime eventSampleTime, uint8_t cable, NSInteger length, const uint8_t *midiBytes);

The definition of AUEventSampleTime is:

/*!	@typedef	AUEventSampleTime
	@brief		Expresses time as a sample count.
	@discussion
		Sample times are normally positive, but hosts can propagate HAL sample times through audio
		units, and HAL sample times can be small negative numbers.
*/
typedef int64_t AUEventSampleTime;

The way that I read the above is that the AU framework expects the ‘sample position’ to be an absolute sample position (‘eventSampleTime’), but the Apple documentation here is ambiguous.

The JUCE code clearly assumes that the ‘sample position’ is relative to the start of the ‘chunk’ (so in each ‘chunk’ the sample position values would be from zero up to the last sample index).

Have you a view on whether or not the AUv3 meaning of eventSampleTime in the context of AUMIDIOutputEventBlock is an absolute time, or relative to the start of the ‘chunk’?

If it is the latter, then all is good. If not, then I guess the AUv3 implemention should be changed to pass an absolute MIDI event time.

Either way, I think it’d help to clarify the documentation for processBlock, to state unambiguously that the MIDI Event times are all intended to be relative to the start of the block.

Best wishes, Pete

I note from here:

http://devnotes.kymatica.com/ios_midi_timestamps.html

You can now send one or more MIDI events from your internalRenderBlock like this, where frameOffset is the sample offset within the current buffer for the event.

if(THIS->_midiOutput) {
    unsigned char data[] = {0x90,60,100};
    THIS->_midiOutput( timestamp->mSampleTime + frameOffset, 0, 3, data );
}

Pete

When I tested this in Logic, the output events definitely appeared to use absolute timestamps. You can test this by putting two instances of the MIDILoggerPluginDemo in series in a Logic project. The timestamps of all events should match up in both instances.

This was broken until recently in JUCE, but it should work correctly on the develop branch. Please try it out, and let us know if you’re still seeing problems.

This is the relevant change:

1 Like

@reuk

Aha, that was exactly the fix I was about to suggest!

NB I’ve been seeing problems on iOS with AUM with hanging notes on stop of transport control, and this is what led me to the question being asked…

Best wishes,

Pete