diff --git a/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm b/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm index 1a6879078e..aad5da8f28 100644 --- a/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm +++ b/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm @@ -1755,6 +1755,9 @@ private: Array parameterGroups; //============================================================================== + // According to the docs, this is the maximum size of a MIDIPacketList. + static constexpr UInt32 packetListBytes = 65536; + AudioUnitEvent auEvent; mutable Array presetsArray; CriticalSection incomingMidiLock; @@ -1762,6 +1765,7 @@ private: AudioTimeStamp lastTimeStamp; int totalInChannels, totalOutChannels; HeapBlock pulledSucceeded; + HeapBlock packetList { packetListBytes, 1 }; ThreadLocalValue inParameterChangedCallback; @@ -1858,37 +1862,55 @@ private: void pushMidiOutput (UInt32 nFrames) noexcept { - UInt32 numPackets = 0; - size_t dataSize = 0; + MIDIPacket* end = nullptr; + + const auto init = [&] + { + end = MIDIPacketListInit (packetList); + }; + + const auto send = [&] + { + midiCallback.midiOutputCallback (midiCallback.userData, &lastTimeStamp, 0, packetList); + }; + + const auto add = [&] (const MidiMessageMetadata& metadata) + { + end = MIDIPacketListAdd (packetList, + packetListBytes, + end, + static_cast (metadata.samplePosition), + static_cast (metadata.numBytes), + metadata.data); + }; + + init(); for (const auto metadata : midiEvents) { jassert (isPositiveAndBelow (metadata.samplePosition, nFrames)); ignoreUnused (nFrames); - dataSize += (size_t) metadata.numBytes; - ++numPackets; + add (metadata); + + if (end == nullptr) + { + send(); + init(); + add (metadata); + + if (end == nullptr) + { + // If this is hit, the size of this midi packet exceeds the maximum size of + // a MIDIPacketList. Large SysEx messages should be broken up into smaller + // chunks. + jassertfalse; + init(); + } + } } - MIDIPacket* p; - const size_t packetMembersSize = sizeof (MIDIPacket) - sizeof (p->data); // NB: GCC chokes on "sizeof (MidiMessage::data)" - const size_t packetListMembersSize = sizeof (MIDIPacketList) - sizeof (p->data); - - HeapBlock packetList; - packetList.malloc (packetListMembersSize + packetMembersSize * numPackets + dataSize, 1); - packetList->numPackets = numPackets; - - p = packetList->packet; - - for (const auto metadata : midiEvents) - { - p->timeStamp = (MIDITimeStamp) metadata.samplePosition; - p->length = (UInt16) metadata.numBytes; - memcpy (p->data, metadata.data, (size_t) metadata.numBytes); - p = MIDIPacketNext (p); - } - - midiCallback.midiOutputCallback (midiCallback.userData, &lastTimeStamp, 0, packetList); + send(); } void GetAudioBufferList (bool isInput, int busIdx, AudioBufferList*& bufferList, bool& interleaved, int& numChannels)