New Class to handle UI
[juce-lv2.git] / juce / source / src / audio / midi / juce_MidiMessageSequence.cpp
blob3297b916ca2e16e4cb9bfdaecd03882eadc806c7
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../core/juce_StandardHeader.h"
28 BEGIN_JUCE_NAMESPACE
30 #include "juce_MidiMessageSequence.h"
31 #include "../../containers/juce_Array.h"
34 //==============================================================================
35 MidiMessageSequence::MidiMessageSequence()
39 MidiMessageSequence::MidiMessageSequence (const MidiMessageSequence& other)
41 list.ensureStorageAllocated (other.list.size());
43 for (int i = 0; i < other.list.size(); ++i)
44 list.add (new MidiEventHolder (other.list.getUnchecked(i)->message));
47 MidiMessageSequence& MidiMessageSequence::operator= (const MidiMessageSequence& other)
49 MidiMessageSequence otherCopy (other);
50 swapWith (otherCopy);
51 return *this;
54 void MidiMessageSequence::swapWith (MidiMessageSequence& other) noexcept
56 list.swapWithArray (other.list);
59 MidiMessageSequence::~MidiMessageSequence()
63 void MidiMessageSequence::clear()
65 list.clear();
68 int MidiMessageSequence::getNumEvents() const
70 return list.size();
73 MidiMessageSequence::MidiEventHolder* MidiMessageSequence::getEventPointer (const int index) const
75 return list [index];
78 double MidiMessageSequence::getTimeOfMatchingKeyUp (const int index) const
80 const MidiEventHolder* const meh = list [index];
82 if (meh != nullptr && meh->noteOffObject != nullptr)
83 return meh->noteOffObject->message.getTimeStamp();
84 else
85 return 0.0;
88 int MidiMessageSequence::getIndexOfMatchingKeyUp (const int index) const
90 const MidiEventHolder* const meh = list [index];
92 return meh != nullptr ? list.indexOf (meh->noteOffObject) : -1;
95 int MidiMessageSequence::getIndexOf (MidiEventHolder* const event) const
97 return list.indexOf (event);
100 int MidiMessageSequence::getNextIndexAtTime (const double timeStamp) const
102 const int numEvents = list.size();
104 int i;
105 for (i = 0; i < numEvents; ++i)
106 if (list.getUnchecked(i)->message.getTimeStamp() >= timeStamp)
107 break;
109 return i;
112 //==============================================================================
113 double MidiMessageSequence::getStartTime() const
115 if (list.size() > 0)
116 return list.getUnchecked(0)->message.getTimeStamp();
117 else
118 return 0;
121 double MidiMessageSequence::getEndTime() const
123 if (list.size() > 0)
124 return list.getLast()->message.getTimeStamp();
125 else
126 return 0;
129 double MidiMessageSequence::getEventTime (const int index) const
131 if (isPositiveAndBelow (index, list.size()))
132 return list.getUnchecked (index)->message.getTimeStamp();
134 return 0.0;
137 //==============================================================================
138 void MidiMessageSequence::addEvent (const MidiMessage& newMessage,
139 double timeAdjustment)
141 MidiEventHolder* const newOne = new MidiEventHolder (newMessage);
143 timeAdjustment += newMessage.getTimeStamp();
144 newOne->message.setTimeStamp (timeAdjustment);
146 int i;
147 for (i = list.size(); --i >= 0;)
148 if (list.getUnchecked(i)->message.getTimeStamp() <= timeAdjustment)
149 break;
151 list.insert (i + 1, newOne);
154 void MidiMessageSequence::deleteEvent (const int index,
155 const bool deleteMatchingNoteUp)
157 if (isPositiveAndBelow (index, list.size()))
159 if (deleteMatchingNoteUp)
160 deleteEvent (getIndexOfMatchingKeyUp (index), false);
162 list.remove (index);
166 void MidiMessageSequence::addSequence (const MidiMessageSequence& other,
167 double timeAdjustment,
168 double firstAllowableTime,
169 double endOfAllowableDestTimes)
171 firstAllowableTime -= timeAdjustment;
172 endOfAllowableDestTimes -= timeAdjustment;
174 for (int i = 0; i < other.list.size(); ++i)
176 const MidiMessage& m = other.list.getUnchecked(i)->message;
177 const double t = m.getTimeStamp();
179 if (t >= firstAllowableTime && t < endOfAllowableDestTimes)
181 MidiEventHolder* const newOne = new MidiEventHolder (m);
182 newOne->message.setTimeStamp (timeAdjustment + t);
184 list.add (newOne);
188 sort();
191 //==============================================================================
192 int MidiMessageSequence::compareElements (const MidiMessageSequence::MidiEventHolder* const first,
193 const MidiMessageSequence::MidiEventHolder* const second) noexcept
195 const double diff = first->message.getTimeStamp()
196 - second->message.getTimeStamp();
198 return (diff > 0) - (diff < 0);
201 void MidiMessageSequence::sort()
203 list.sort (*this, true);
206 //==============================================================================
207 void MidiMessageSequence::updateMatchedPairs()
209 for (int i = 0; i < list.size(); ++i)
211 const MidiMessage& m1 = list.getUnchecked(i)->message;
213 if (m1.isNoteOn())
215 list.getUnchecked(i)->noteOffObject = nullptr;
216 const int note = m1.getNoteNumber();
217 const int chan = m1.getChannel();
218 const int len = list.size();
220 for (int j = i + 1; j < len; ++j)
222 const MidiMessage& m = list.getUnchecked(j)->message;
224 if (m.getNoteNumber() == note && m.getChannel() == chan)
226 if (m.isNoteOff())
228 list.getUnchecked(i)->noteOffObject = list[j];
229 break;
231 else if (m.isNoteOn())
233 list.insert (j, new MidiEventHolder (MidiMessage::noteOff (chan, note)));
234 list.getUnchecked(j)->message.setTimeStamp (m.getTimeStamp());
235 list.getUnchecked(i)->noteOffObject = list[j];
236 break;
244 void MidiMessageSequence::addTimeToMessages (const double delta)
246 for (int i = list.size(); --i >= 0;)
247 list.getUnchecked (i)->message.setTimeStamp (list.getUnchecked (i)->message.getTimeStamp()
248 + delta);
251 //==============================================================================
252 void MidiMessageSequence::extractMidiChannelMessages (const int channelNumberToExtract,
253 MidiMessageSequence& destSequence,
254 const bool alsoIncludeMetaEvents) const
256 for (int i = 0; i < list.size(); ++i)
258 const MidiMessage& mm = list.getUnchecked(i)->message;
260 if (mm.isForChannel (channelNumberToExtract)
261 || (alsoIncludeMetaEvents && mm.isMetaEvent()))
263 destSequence.addEvent (mm);
268 void MidiMessageSequence::extractSysExMessages (MidiMessageSequence& destSequence) const
270 for (int i = 0; i < list.size(); ++i)
272 const MidiMessage& mm = list.getUnchecked(i)->message;
274 if (mm.isSysEx())
275 destSequence.addEvent (mm);
279 void MidiMessageSequence::deleteMidiChannelMessages (const int channelNumberToRemove)
281 for (int i = list.size(); --i >= 0;)
282 if (list.getUnchecked(i)->message.isForChannel (channelNumberToRemove))
283 list.remove(i);
286 void MidiMessageSequence::deleteSysExMessages()
288 for (int i = list.size(); --i >= 0;)
289 if (list.getUnchecked(i)->message.isSysEx())
290 list.remove(i);
293 //==============================================================================
294 void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumber,
295 const double time,
296 OwnedArray<MidiMessage>& dest)
298 bool doneProg = false;
299 bool donePitchWheel = false;
300 Array <int> doneControllers;
301 doneControllers.ensureStorageAllocated (32);
303 for (int i = list.size(); --i >= 0;)
305 const MidiMessage& mm = list.getUnchecked(i)->message;
307 if (mm.isForChannel (channelNumber)
308 && mm.getTimeStamp() <= time)
310 if (mm.isProgramChange())
312 if (! doneProg)
314 dest.add (new MidiMessage (mm, 0.0));
315 doneProg = true;
318 else if (mm.isController())
320 if (! doneControllers.contains (mm.getControllerNumber()))
322 dest.add (new MidiMessage (mm, 0.0));
323 doneControllers.add (mm.getControllerNumber());
326 else if (mm.isPitchWheel())
328 if (! donePitchWheel)
330 dest.add (new MidiMessage (mm, 0.0));
331 donePitchWheel = true;
339 //==============================================================================
340 MidiMessageSequence::MidiEventHolder::MidiEventHolder (const MidiMessage& message_)
341 : message (message_),
342 noteOffObject (nullptr)
346 MidiMessageSequence::MidiEventHolder::~MidiEventHolder()
350 END_JUCE_NAMESPACE