The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
5.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCE_MIDIDATACONCATENATOR_JUCEHEADER__
  19. #define __JUCE_MIDIDATACONCATENATOR_JUCEHEADER__
  20. //==============================================================================
  21. /**
  22. Helper class that takes chunks of incoming midi bytes, packages them into
  23. messages, and dispatches them to a midi callback.
  24. */
  25. class MidiDataConcatenator
  26. {
  27. public:
  28. //==============================================================================
  29. MidiDataConcatenator (const int initialBufferSize)
  30. : pendingData ((size_t) initialBufferSize),
  31. pendingDataTime (0), pendingBytes (0), runningStatus (0)
  32. {
  33. }
  34. void reset()
  35. {
  36. pendingBytes = 0;
  37. runningStatus = 0;
  38. pendingDataTime = 0;
  39. }
  40. template <typename UserDataType, typename CallbackType>
  41. void pushMidiData (const void* inputData, int numBytes, double time,
  42. UserDataType* input, CallbackType& callback)
  43. {
  44. const uint8* d = static_cast <const uint8*> (inputData);
  45. while (numBytes > 0)
  46. {
  47. if (pendingBytes > 0 || d[0] == 0xf0)
  48. {
  49. processSysex (d, numBytes, time, input, callback);
  50. runningStatus = 0;
  51. }
  52. else
  53. {
  54. int len = 0;
  55. uint8 data[3];
  56. while (numBytes > 0)
  57. {
  58. // If there's a realtime message embedded in the middle of
  59. // the normal message, handle it now..
  60. if (*d >= 0xf8 && *d <= 0xfe)
  61. {
  62. const MidiMessage m (*d++, time);
  63. callback.handleIncomingMidiMessage (input, m);
  64. --numBytes;
  65. }
  66. else
  67. {
  68. if (len == 0 && *d < 0x80 && runningStatus >= 0x80)
  69. data[len++] = runningStatus;
  70. data[len++] = *d++;
  71. --numBytes;
  72. if (len >= MidiMessage::getMessageLengthFromFirstByte (data[0]))
  73. break;
  74. }
  75. }
  76. if (len > 0)
  77. {
  78. int used = 0;
  79. const MidiMessage m (data, len, used, 0, time);
  80. if (used <= 0)
  81. break; // malformed message..
  82. jassert (used == len);
  83. callback.handleIncomingMidiMessage (input, m);
  84. runningStatus = data[0];
  85. }
  86. }
  87. }
  88. }
  89. private:
  90. template <typename UserDataType, typename CallbackType>
  91. void processSysex (const uint8*& d, int& numBytes, double time,
  92. UserDataType* input, CallbackType& callback)
  93. {
  94. if (*d == 0xf0)
  95. {
  96. pendingBytes = 0;
  97. pendingDataTime = time;
  98. }
  99. pendingData.ensureSize ((size_t) (pendingBytes + numBytes), false);
  100. uint8* totalMessage = static_cast<uint8*> (pendingData.getData());
  101. uint8* dest = totalMessage + pendingBytes;
  102. do
  103. {
  104. if (pendingBytes > 0 && *d >= 0x80)
  105. {
  106. if (*d >= 0xfa || *d == 0xf8)
  107. {
  108. callback.handleIncomingMidiMessage (input, MidiMessage (*d, time));
  109. ++d;
  110. --numBytes;
  111. }
  112. else
  113. {
  114. if (*d == 0xf7)
  115. {
  116. *dest++ = *d++;
  117. pendingBytes++;
  118. --numBytes;
  119. }
  120. break;
  121. }
  122. }
  123. else
  124. {
  125. *dest++ = *d++;
  126. pendingBytes++;
  127. --numBytes;
  128. }
  129. }
  130. while (numBytes > 0);
  131. if (pendingBytes > 0)
  132. {
  133. if (totalMessage [pendingBytes - 1] == 0xf7)
  134. {
  135. callback.handleIncomingMidiMessage (input, MidiMessage (totalMessage, pendingBytes, pendingDataTime));
  136. pendingBytes = 0;
  137. }
  138. else
  139. {
  140. callback.handlePartialSysexMessage (input, totalMessage, pendingBytes, pendingDataTime);
  141. }
  142. }
  143. }
  144. MemoryBlock pendingData;
  145. double pendingDataTime;
  146. int pendingBytes;
  147. uint8 runningStatus;
  148. JUCE_DECLARE_NON_COPYABLE (MidiDataConcatenator);
  149. };
  150. #endif // __JUCE_MIDIDATACONCATENATOR_JUCEHEADER__