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.

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