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"
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
);
54 void MidiMessageSequence::swapWith (MidiMessageSequence
& other
) noexcept
56 list
.swapWithArray (other
.list
);
59 MidiMessageSequence::~MidiMessageSequence()
63 void MidiMessageSequence::clear()
68 int MidiMessageSequence::getNumEvents() const
73 MidiMessageSequence::MidiEventHolder
* MidiMessageSequence::getEventPointer (const int index
) const
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();
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();
105 for (i
= 0; i
< numEvents
; ++i
)
106 if (list
.getUnchecked(i
)->message
.getTimeStamp() >= timeStamp
)
112 //==============================================================================
113 double MidiMessageSequence::getStartTime() const
116 return list
.getUnchecked(0)->message
.getTimeStamp();
121 double MidiMessageSequence::getEndTime() const
124 return list
.getLast()->message
.getTimeStamp();
129 double MidiMessageSequence::getEventTime (const int index
) const
131 if (isPositiveAndBelow (index
, list
.size()))
132 return list
.getUnchecked (index
)->message
.getTimeStamp();
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
);
147 for (i
= list
.size(); --i
>= 0;)
148 if (list
.getUnchecked(i
)->message
.getTimeStamp() <= timeAdjustment
)
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);
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
);
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
;
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
)
228 list
.getUnchecked(i
)->noteOffObject
= list
[j
];
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
];
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()
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
;
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
))
286 void MidiMessageSequence::deleteSysExMessages()
288 for (int i
= list
.size(); --i
>= 0;)
289 if (list
.getUnchecked(i
)->message
.isSysEx())
293 //==============================================================================
294 void MidiMessageSequence::createControllerUpdatesForTime (const int channelNumber
,
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())
314 dest
.add (new MidiMessage (mm
, 0.0));
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()