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.

336 lines
10KB

  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. MidiMessageSequence::MidiMessageSequence()
  19. {
  20. }
  21. MidiMessageSequence::MidiMessageSequence (const MidiMessageSequence& other)
  22. {
  23. list.ensureStorageAllocated (other.list.size());
  24. for (int i = 0; i < other.list.size(); ++i)
  25. list.add (new MidiEventHolder (other.list.getUnchecked(i)->message));
  26. }
  27. MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence& other)
  28. {
  29. MidiMessageSequence otherCopy (other);
  30. swapWith (otherCopy);
  31. return *this;
  32. }
  33. void MidiMessageSequence::swapWith (MidiMessageSequence& other) noexcept
  34. {
  35. list.swapWithArray (other.list);
  36. }
  37. MidiMessageSequence::~MidiMessageSequence()
  38. {
  39. }
  40. void MidiMessageSequence::clear()
  41. {
  42. list.clear();
  43. }
  44. int MidiMessageSequence::getNumEvents() const
  45. {
  46. return list.size();
  47. }
  48. MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (const int index) const
  49. {
  50. return list [index];
  51. }
  52. double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const
  53. {
  54. if (const MidiEventHolder* const meh = list [index])
  55. if (meh->noteOffObject != nullptr)
  56. return meh->noteOffObject->message.getTimeStamp();
  57. return 0.0;
  58. }
  59. int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const
  60. {
  61. if (const MidiEventHolder* const meh = list [index])
  62. return list.indexOf (meh->noteOffObject);
  63. return -1;
  64. }
  65. int MidiMessageSequence::getIndexOf (MidiEventHolder* const event) const
  66. {
  67. return list.indexOf (event);
  68. }
  69. int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const
  70. {
  71. const int numEvents = list.size();
  72. int i;
  73. for (i = 0; i < numEvents; ++i)
  74. if (list.getUnchecked(i)->message.getTimeStamp() >= timeStamp)
  75. break;
  76. return i;
  77. }
  78. //==============================================================================
  79. double MidiMessageSequence::getStartTime() const
  80. {
  81. return getEventTime (0);
  82. }
  83. double MidiMessageSequence::getEndTime() const
  84. {
  85. return getEventTime (list.size() - 1);
  86. }
  87. double MidiMessageSequence::getEventTime (const int index) const
  88. {
  89. if (const MidiEventHolder* const meh = list [index])
  90. return meh->message.getTimeStamp();
  91. return 0.0;
  92. }
  93. //==============================================================================
  94. MidiMessageSequence::MidiEventHolder* MidiMessageSequence::addEvent (const MidiMessage& newMessage,
  95. double timeAdjustment)
  96. {
  97. MidiEventHolder* const newOne = new MidiEventHolder (newMessage);
  98. timeAdjustment += newMessage.getTimeStamp();
  99. newOne->message.setTimeStamp (timeAdjustment);
  100. int i;
  101. for (i = list.size(); --i >= 0;)
  102. if (list.getUnchecked(i)->message.getTimeStamp() <= timeAdjustment)
  103. break;
  104. list.insert (i + 1, newOne);
  105. return newOne;
  106. }
  107. void MidiMessageSequence::deleteEvent (const int index,
  108. const bool deleteMatchingNoteUp)
  109. {
  110. if (isPositiveAndBelow (index, list.size()))
  111. {
  112. if (deleteMatchingNoteUp)
  113. deleteEvent (getIndexOfMatchingKeyUp (index), false);
  114. list.remove (index);
  115. }
  116. }
  117. struct MidiMessageSequenceSorter
  118. {
  119. static int compareElements (const MidiMessageSequence::MidiEventHolder* const first,
  120. const MidiMessageSequence::MidiEventHolder* const second) noexcept
  121. {
  122. const double diff = first->message.getTimeStamp() - second->message.getTimeStamp();
  123. return (diff > 0) - (diff < 0);
  124. }
  125. };
  126. void MidiMessageSequence::addSequence (const MidiMessageSequence& other,
  127. double timeAdjustment,
  128. double firstAllowableTime,
  129. double endOfAllowableDestTimes)
  130. {
  131. firstAllowableTime -= timeAdjustment;
  132. endOfAllowableDestTimes -= timeAdjustment;
  133. for (int i = 0; i < other.list.size(); ++i)
  134. {
  135. const MidiMessage& m = other.list.getUnchecked(i)->message;
  136. const double t = m.getTimeStamp();
  137. if (t >= firstAllowableTime && t < endOfAllowableDestTimes)
  138. {
  139. MidiEventHolder* const newOne = new MidiEventHolder (m);
  140. newOne->message.setTimeStamp (timeAdjustment + t);
  141. list.add (newOne);
  142. }
  143. }
  144. sort();
  145. }
  146. //==============================================================================
  147. void MidiMessageSequence::sort()
  148. {
  149. MidiMessageSequenceSorter sorter;
  150. list.sort (sorter, true);
  151. }
  152. void MidiMessageSequence::updateMatchedPairs()
  153. {
  154. for (int i = 0; i < list.size(); ++i)
  155. {
  156. MidiEventHolder* const meh = list.getUnchecked(i);
  157. const MidiMessage& m1 = meh->message;
  158. if (m1.isNoteOn())
  159. {
  160. meh->noteOffObject = nullptr;
  161. const int note = m1.getNoteNumber();
  162. const int chan = m1.getChannel();
  163. const int len = list.size();
  164. for (int j = i + 1; j < len; ++j)
  165. {
  166. const MidiMessage& m = list.getUnchecked(j)->message;
  167. if (m.getNoteNumber() == note && m.getChannel() == chan)
  168. {
  169. if (m.isNoteOff())
  170. {
  171. meh->noteOffObject = list[j];
  172. break;
  173. }
  174. else if (m.isNoteOn())
  175. {
  176. MidiEventHolder* const newEvent = new MidiEventHolder (MidiMessage::noteOff (chan, note));
  177. list.insert (j, newEvent);
  178. newEvent->message.setTimeStamp (m.getTimeStamp());
  179. meh->noteOffObject = newEvent;
  180. break;
  181. }
  182. }
  183. }
  184. }
  185. }
  186. }
  187. void MidiMessageSequence::addTimeToMessages (const double delta)
  188. {
  189. for (int i = list.size(); --i >= 0;)
  190. {
  191. MidiMessage& mm = list.getUnchecked(i)->message;
  192. mm.setTimeStamp (mm.getTimeStamp() + delta);
  193. }
  194. }
  195. //==============================================================================
  196. void MidiMessageSequence::extractMidiChannelMessages (const int channelNumberToExtract,
  197. MidiMessageSequence& destSequence,
  198. const bool alsoIncludeMetaEvents) const
  199. {
  200. for (int i = 0; i < list.size(); ++i)
  201. {
  202. const MidiMessage& mm = list.getUnchecked(i)->message;
  203. if (mm.isForChannel (channelNumberToExtract) || (alsoIncludeMetaEvents && mm.isMetaEvent()))
  204. destSequence.addEvent (mm);
  205. }
  206. }
  207. void MidiMessageSequence::extractSysExMessages (MidiMessageSequence& destSequence) const
  208. {
  209. for (int i = 0; i < list.size(); ++i)
  210. {
  211. const MidiMessage& mm = list.getUnchecked(i)->message;
  212. if (mm.isSysEx())
  213. destSequence.addEvent (mm);
  214. }
  215. }
  216. void MidiMessageSequence::deleteMidiChannelMessages (const int channelNumberToRemove)
  217. {
  218. for (int i = list.size(); --i >= 0;)
  219. if (list.getUnchecked(i)->message.isForChannel (channelNumberToRemove))
  220. list.remove(i);
  221. }
  222. void MidiMessageSequence::deleteSysExMessages()
  223. {
  224. for (int i = list.size(); --i >= 0;)
  225. if (list.getUnchecked(i)->message.isSysEx())
  226. list.remove(i);
  227. }
  228. //==============================================================================
  229. void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumber,
  230. const double time,
  231. OwnedArray<MidiMessage>& dest)
  232. {
  233. bool doneProg = false;
  234. bool donePitchWheel = false;
  235. Array <int> doneControllers;
  236. doneControllers.ensureStorageAllocated (32);
  237. for (int i = list.size(); --i >= 0;)
  238. {
  239. const MidiMessage& mm = list.getUnchecked(i)->message;
  240. if (mm.isForChannel (channelNumber) && mm.getTimeStamp() <= time)
  241. {
  242. if (mm.isProgramChange())
  243. {
  244. if (! doneProg)
  245. {
  246. dest.add (new MidiMessage (mm, 0.0));
  247. doneProg = true;
  248. }
  249. }
  250. else if (mm.isController())
  251. {
  252. if (! doneControllers.contains (mm.getControllerNumber()))
  253. {
  254. dest.add (new MidiMessage (mm, 0.0));
  255. doneControllers.add (mm.getControllerNumber());
  256. }
  257. }
  258. else if (mm.isPitchWheel())
  259. {
  260. if (! donePitchWheel)
  261. {
  262. dest.add (new MidiMessage (mm, 0.0));
  263. donePitchWheel = true;
  264. }
  265. }
  266. }
  267. }
  268. }
  269. //==============================================================================
  270. MidiMessageSequence::MidiEventHolder::MidiEventHolder (const MidiMessage& mm)
  271. : message (mm),
  272. noteOffObject (nullptr)
  273. {
  274. }
  275. MidiMessageSequence::MidiEventHolder::~MidiEventHolder()
  276. {
  277. }