From a5a4e69f379e61fcf05f5cbff793e65a6f4f0eee Mon Sep 17 00:00:00 2001 From: jules Date: Sat, 5 May 2012 12:53:52 +0100 Subject: [PATCH] Midi parsing fix for embedded realtime messages, and CoreMidi fix for sending large packets. --- .../native/juce_MidiDataConcatenator.h | 49 +++++++++++++++---- .../native/juce_mac_CoreMidi.cpp | 44 +++++++++++------ 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h b/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h index 0ff8060b6b..7cfaa646d1 100644 --- a/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h +++ b/modules/juce_audio_devices/native/juce_MidiDataConcatenator.h @@ -37,13 +37,14 @@ public: //============================================================================== MidiDataConcatenator (const int initialBufferSize) : pendingData ((size_t) initialBufferSize), - pendingBytes (0), pendingDataTime (0) + pendingBytes (0), runningStatus (0), pendingDataTime (0) { } void reset() { pendingBytes = 0; + runningStatus = 0; pendingDataTime = 0; } @@ -57,18 +58,48 @@ public: if (pendingBytes > 0 || d[0] == 0xf0) { processSysex (d, numBytes, time, input, callback); + runningStatus = 0; } else { - int used = 0; - const MidiMessage m (d, numBytes, used, 0, time); + int len = 0; + uint8 data[3]; - if (used <= 0) - break; // malformed message.. + while (numBytes > 0) + { + // If there's a realtime message embedded in the middle of + // the normal message, handle it now.. + if (*d >= 0xf8 && *d <= 0xfe) + { + const MidiMessage m (*d++, time); + callback.handleIncomingMidiMessage (input, m); + --numBytes; + } + else + { + if (len == 0 && *d < 0x80 && runningStatus >= 0x80) + data[len++] = runningStatus; + + data[len++] = *d++; + --numBytes; - callback.handleIncomingMidiMessage (input, m); - numBytes -= used; - d += used; + if (len >= MidiMessage::getMessageLengthFromFirstByte (data[0])) + break; + } + } + + if (len > 0) + { + int used = 0; + const MidiMessage m (data, len, used, 0, time); + + if (used <= 0) + break; // malformed message.. + + jassert (used == len); + callback.handleIncomingMidiMessage (input, m); + runningStatus = data[0]; + } } } } @@ -133,7 +164,7 @@ private: } MemoryBlock pendingData; - int pendingBytes; + int pendingBytes, runningStatus; double pendingDataTime; JUCE_DECLARE_NON_COPYABLE (MidiDataConcatenator); diff --git a/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp b/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp index 7fdca6344f..31d6240c28 100644 --- a/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp +++ b/modules/juce_audio_devices/native/juce_mac_CoreMidi.cpp @@ -359,24 +359,27 @@ MidiOutput::~MidiOutput() void MidiOutput::sendMessageNow (const MidiMessage& message) { - CoreMidiHelpers::MidiPortAndEndpoint* const mpe = static_cast (internal); - #if JUCE_IOS const MIDITimeStamp timeStamp = mach_absolute_time(); #else const MIDITimeStamp timeStamp = AudioGetCurrentHostTime(); #endif + HeapBlock allocatedPackets; + MIDIPacketList stackPacket; + MIDIPacketList* packetToSend = &stackPacket; + const size_t dataSize = (size_t) message.getRawDataSize(); + if (message.isSysEx()) { const int maxPacketSize = 256; - int pos = 0, bytesLeft = message.getRawDataSize(); + int pos = 0, bytesLeft = (int) dataSize; const int numPackets = (bytesLeft + maxPacketSize - 1) / maxPacketSize; - HeapBlock packets; - packets.malloc ((size_t) (32 * numPackets + message.getRawDataSize()), 1); - packets->numPackets = (UInt32) numPackets; + allocatedPackets.malloc ((size_t) (32 * numPackets + dataSize), 1); + packetToSend = allocatedPackets; + packetToSend->numPackets = (UInt32) numPackets; - MIDIPacket* p = packets->packet; + MIDIPacket* p = packetToSend->packet; for (int i = 0; i < numPackets; ++i) { @@ -387,19 +390,30 @@ void MidiOutput::sendMessageNow (const MidiMessage& message) bytesLeft -= p->length; p = MIDIPacketNext (p); } + } + else if (dataSize < 65536) // max packet size + { + const size_t stackCapacity = sizeof (stackPacket.packet->data); - mpe->send (packets); + if (dataSize > stackCapacity) + { + allocatedPackets.malloc ((sizeof (MIDIPacketList) - stackCapacity) + dataSize, 1); + packetToSend = allocatedPackets; + } + + packetToSend->numPackets = 1; + MIDIPacket& p = *(packetToSend->packet); + p.timeStamp = timeStamp; + p.length = (UInt16) dataSize; + memcpy (p.data, message.getRawData(), dataSize); } else { - MIDIPacketList packets; - packets.numPackets = 1; - packets.packet[0].timeStamp = timeStamp; - packets.packet[0].length = (UInt16) message.getRawDataSize(); - *(int*) (packets.packet[0].data) = *(const int*) message.getRawData(); - - mpe->send (&packets); + jassertfalse; // packet too large to send! + return; } + + static_cast (internal)->send (packetToSend); } //==============================================================================