/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-11 by Raw Material Software Ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License (Version 2), as published by the Free Software Foundation. A copy of the license is included in the JUCE distribution, or can be found online at www.gnu.org/licenses. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #ifndef __JUCE_MIDIDATACONCATENATOR_JUCEHEADER__ #define __JUCE_MIDIDATACONCATENATOR_JUCEHEADER__ //============================================================================== /** Helper class that takes chunks of incoming midi bytes, packages them into messages, and dispatches them to a midi callback. */ class MidiDataConcatenator { public: //============================================================================== MidiDataConcatenator (const int initialBufferSize) : pendingData ((size_t) initialBufferSize), pendingBytes (0), pendingDataTime (0) { } void reset() { pendingBytes = 0; pendingDataTime = 0; } void pushMidiData (const void* data, int numBytes, double time, MidiInput* input, MidiInputCallback& callback) { const uint8* d = static_cast (data); while (numBytes > 0) { if (pendingBytes > 0 || d[0] == 0xf0) { processSysex (d, numBytes, time, input, callback); } else { int used = 0; const MidiMessage m (d, numBytes, used, 0, time); if (used <= 0) break; // malformed message.. callback.handleIncomingMidiMessage (input, m); numBytes -= used; d += used; } } } private: void processSysex (const uint8*& d, int& numBytes, double time, MidiInput* input, MidiInputCallback& callback) { if (*d == 0xf0) { pendingBytes = 0; pendingDataTime = time; } pendingData.ensureSize ((size_t) (pendingBytes + numBytes), false); uint8* totalMessage = static_cast (pendingData.getData()); uint8* dest = totalMessage + pendingBytes; do { if (pendingBytes > 0 && *d >= 0x80) { if (*d >= 0xfa || *d == 0xf8) { callback.handleIncomingMidiMessage (input, MidiMessage (*d, time)); ++d; --numBytes; } else { if (*d == 0xf7) { *dest++ = *d++; pendingBytes++; --numBytes; } break; } } else { *dest++ = *d++; pendingBytes++; --numBytes; } } while (numBytes > 0); if (pendingBytes > 0) { if (totalMessage [pendingBytes - 1] == 0xf7) { callback.handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime)); pendingBytes = 0; } else { callback.handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime); } } } MemoryBlock pendingData; int pendingBytes; double pendingDataTime; JUCE_DECLARE_NON_COPYABLE (MidiDataConcatenator); }; #endif // __JUCE_MIDIDATACONCATENATOR_JUCEHEADER__