1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 // $Id: eventlist.cpp,v 1.7.2.3 2009/11/05 03:14:35 terminator356 Exp $
5 //
6 // (C) Copyright 2000-2003 Werner Schweer (ws@seh.de)
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; version 2 of
11 // the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 //
22 //=========================================================
23
24 #include "tempo.h"
25 #include "event.h"
26 #include "xml.h"
27
28 namespace MusECore {
29
30 //---------------------------------------------------------
31 // readEventList
32 //---------------------------------------------------------
33
read(Xml & xml,const char * name,bool midi)34 void EventList::read(Xml& xml, const char* name, bool midi)
35 {
36 for (;;) {
37 Xml::Token token = xml.parse();
38 const QString& tag = xml.s1();
39 switch (token) {
40 case Xml::Error:
41 case Xml::End:
42 return;
43 case Xml::TagStart:
44 if (tag == "event") {
45 Event e(midi ? Note : Wave);
46 e.read(xml);
47 add(e);
48 }
49 else
50 xml.unknown("readEventList");
51 break;
52 case Xml::TagEnd:
53 if (tag == name)
54 return;
55 default:
56 break;
57 }
58 }
59 }
60
61 //---------------------------------------------------------
62 // add
63 //---------------------------------------------------------
64
add(Event event)65 iEvent EventList::add(Event event)
66 {
67 // Changed by Tim. An event list containing wave events should be sorted by
68 // frames. WaveTrack::fetchData() relies on the sorting order, and
69 // there was a bug that waveparts were sometimes muted because of
70 // incorrect sorting order (by ticks).
71 // Also, when the tempo map is changed, every wave event would have to be
72 // re-added to the event list so that the proper sorting order (by ticks)
73 // could be achieved.
74 // Note that in a med file, the tempo list is loaded AFTER all the tracks.
75 // There was a bug that all the wave events' tick values were not correct,
76 // since they were computed BEFORE the tempo map was loaded.
77
78 // From cppreference.com about the insert hint parameter (we now use C++11):
79 // hint -
80 // iterator, used as a suggestion as to where to start the search (until C++11)
81 // iterator to the position before which the new element will be inserted (since C++11)
82 // ------
83
84 if(event.type() == Wave)
85 return insert(std::pair<const unsigned, Event> (event.frame(), event));
86
87 unsigned key = event.tick();
88 if(event.type() == Note) // Place notes after controllers.
89 {
90 iEvent i = upper_bound(key);
91 return insert(i, std::pair<const unsigned, Event> (key, event));
92 }
93 else
94 {
95 // REMOVE Tim. Ctrl. Changed comment.
96 //
97 // // REMOVE Tim. citem. ctl. Added. It seems we must allow multiple controller events
98 // // if they are to be moved, dragged, and dropped.
99
100 // NOTE: Due to the companion controller cache, it is FORBIDDEN to have multiple controller events at the same time
101 // with the same controller number. The cache has no way of linking specific entries with those multiple events.
102 // If the cache has multiple events, it can crash the operations system when deleting cache items.
103 // It is tempting to catch that at a low level like the event list.
104 // But it would only be there to catch rare mistakes, and may slow other legitimate additions, and be redundant
105 // in many cases where a search is already done.
106 // Also, if add() is called as part of an (undo) operation, we have no mechanism to return a flag indicating success -
107 // not when add() is called in the realtime thread. Not even in non-realtime stage 1 when Song::applyOperation() is called.
108 // So to preserve speed, we RELY on catching that at higher levels such as the add event dialog or during song loading.
109
110 // if(event.type() == Controller)
111 // {
112 // EventRange er = equal_range(key);
113 // iEvent i = er.second;
114 // iEvent loc = i;
115 // const int data_a = event.dataA();
116 // while(i != er.first)
117 // {
118 // --i;
119 // // Special: There must be only ONE value per controller per position.
120 // // If there is already a controller value for this controller number
121 // // at this position, just replace it and return.
122 // //
123 // // This is meant as a last line of defense against accidental multiple
124 // // controller values at a given time. The rule of thumb when executing
125 // // add event commands is you must check beforehand whether an event
126 // // exists and tell the command system to delete it so that the undo
127 // // system can remember what was replaced.
128 // // In some cases the command/undo system may do that for you.
129 // // But simply relying on this low-level catch-all is not good, the undo
130 // // system won't remember what was deleted.
131 // if(i->second.type() == Controller && i->second.dataA() == data_a)
132 // {
133 // i->second.setB(event.dataB());
134 // return i;
135 // }
136 // if(i->second.type() == Note)
137 // loc = i;
138 // }
139 // return insert(loc, std::pair<const unsigned, Event> (key, event));
140 // }
141 // else
142 // {
143
144 iEvent i = lower_bound(key);
145 while(i != end() && i->first == key && i->second.type() != Note)
146 ++i;
147 return insert(i, std::pair<const unsigned, Event> (key, event));
148 // }
149 }
150 return end();
151 }
152
153 //---------------------------------------------------------
154 // move
155 //---------------------------------------------------------
156
move(Event & event,unsigned tick)157 void EventList::move(Event& event, unsigned tick)
158 {
159 iEvent i = find(event);
160 if(i != end())
161 erase(i);
162
163 if(event.type() == Wave)
164 {
165 insert(std::pair<const unsigned, Event> (MusEGlobal::tempomap.tick2frame(tick), event));
166 return;
167 }
168
169 if(event.type() == Note) // Place notes after controllers.
170 {
171 iEvent i = upper_bound(tick);
172 insert(i, std::pair<const unsigned, Event> (tick, event));
173 return;
174 }
175 else
176 {
177 iEvent i = lower_bound(tick);
178 while(i != end() && i->first == tick && i->second.type() != Note)
179 ++i;
180 insert(i, std::pair<const unsigned, Event> (tick, event));
181 return;
182 }
183 }
184
185 //---------------------------------------------------------
186 // find
187 //---------------------------------------------------------
188
find(const Event & event)189 iEvent EventList::find(const Event& event)
190 {
191 EventRange range = equal_range(event.posValue());
192
193 for (iEvent i = range.first; i != range.second; ++i) {
194 if (i->second == event)
195 return i;
196 }
197 return end();
198 }
199
find(const Event & event) const200 ciEvent EventList::find(const Event& event) const
201 {
202 cEventRange range = equal_range(event.posValue());
203
204
205 for (ciEvent i = range.first; i != range.second; ++i) {
206 if (i->second == event)
207 return i;
208 }
209 return end();
210 }
211
findSimilar(const Event & event)212 iEvent EventList::findSimilar(const Event& event)
213 {
214 EventRange range = equal_range(event.posValue());
215
216 for (iEvent i = range.first; i != range.second; ++i) {
217 if (i->second.isSimilarTo(event))
218 return i;
219 }
220 return end();
221 }
222
findSimilar(const Event & event) const223 ciEvent EventList::findSimilar(const Event& event) const
224 {
225 cEventRange range = equal_range(event.posValue());
226
227
228 for (ciEvent i = range.first; i != range.second; ++i) {
229 if (i->second.isSimilarTo(event))
230 return i;
231 }
232 return end();
233 }
234
findSimilarType(const Event & event,EventList & list,bool compareTime,bool compareA,bool compareB,bool compareC,bool compareWavePath,bool compareWavePos,bool compareWaveStartPos) const235 int EventList::findSimilarType(const Event& event, EventList& list,
236 bool compareTime,
237 bool compareA, bool compareB, bool compareC,
238 bool compareWavePath, bool compareWavePos, bool compareWaveStartPos) const
239 {
240 int cnt = 0;
241 cEventRange range = compareTime ? equal_range(event.posValue()) : cEventRange(begin(), end());
242 for(ciEvent i = range.first; i != range.second; ++i)
243 {
244 const Event& e = i->second;
245 if(e.isSimilarType(event,
246 false, // Do not compare time, that's handled above.
247 compareA, compareB, compareC,
248 compareWavePath, compareWavePos, compareWaveStartPos))
249 {
250 // REMOVE Tim. ctrl. Changed.
251 // ++cnt;
252 // list.add(e);
253 if(list.add(e) != list.end())
254 ++cnt;
255 }
256 }
257 return cnt;
258 }
259
findId(const Event & event)260 iEvent EventList::findId(const Event& event)
261 {
262 EventRange range = equal_range(event.posValue());
263
264 for (iEvent i = range.first; i != range.second; ++i) {
265 if (i->second.id() == event.id())
266 return i;
267 }
268 return end();
269 }
270
findId(const Event & event) const271 ciEvent EventList::findId(const Event& event) const
272 {
273 cEventRange range = equal_range(event.posValue());
274
275
276 for (ciEvent i = range.first; i != range.second; ++i) {
277 if (i->second.id() == event.id())
278 return i;
279 }
280 return end();
281 }
282
findId(unsigned t,EventID_t id)283 iEvent EventList::findId(unsigned t, EventID_t id)
284 {
285 EventRange range = equal_range(t);
286 for (iEvent i = range.first; i != range.second; ++i) {
287 if (i->second.id() == id)
288 return i;
289 }
290 return end();
291 }
292
findId(unsigned t,EventID_t id) const293 ciEvent EventList::findId(unsigned t, EventID_t id) const
294 {
295 cEventRange range = equal_range(t);
296 for (ciEvent i = range.first; i != range.second; ++i) {
297 if (i->second.id() == id)
298 return i;
299 }
300 return end();
301 }
302
findId(EventID_t id)303 iEvent EventList::findId(EventID_t id)
304 {
305 for (iEvent i = begin(); i != end(); ++i) {
306 if (i->second.id() == id)
307 return i;
308 }
309 return end();
310 }
311
findId(EventID_t id) const312 ciEvent EventList::findId(EventID_t id) const
313 {
314 for (ciEvent i = begin(); i != end(); ++i) {
315 if (i->second.id() == id)
316 return i;
317 }
318 return end();
319 }
320
findWithId(const Event & event)321 iEvent EventList::findWithId(const Event& event)
322 {
323 EventRange range = equal_range(event.posValue());
324
325 for (iEvent i = range.first; i != range.second; ++i) {
326 if (i->second == event || i->second.id() == event.id())
327 return i;
328 }
329 return end();
330 }
331
findWithId(const Event & event) const332 ciEvent EventList::findWithId(const Event& event) const
333 {
334 cEventRange range = equal_range(event.posValue());
335
336
337 for (ciEvent i = range.first; i != range.second; ++i) {
338 if (i->second == event || i->second.id() == event.id())
339 return i;
340 }
341 return end();
342 }
343
344 //---------------------------------------------------------
345 // dump
346 //---------------------------------------------------------
347
dump() const348 void EventList::dump() const
349 {
350 for (ciEvent i = begin(); i != end(); ++i)
351 i->second.dump();
352 }
353
evrange(bool wave,RelevantSelectedEvents_t relevant,int * numEvents,int ctrlNum) const354 PosLen EventList::evrange(bool wave, RelevantSelectedEvents_t relevant, int* numEvents, int ctrlNum) const
355 {
356 PosLen res;
357 res.setType(wave ? Pos::FRAMES : Pos::TICKS);
358
359 int e_found = 0;
360 bool first_found = false;
361 unsigned start_time = 0;
362 unsigned end_time = 0;
363 for(ciEvent ie = begin(); ie != end(); ++ie)
364 {
365 const Event& e = ie->second;
366 // Only events of the given type are considered.
367 const EventType et = e.type();
368 switch(et)
369 {
370 case Note:
371 if(wave || (relevant & NotesRelevant) == NoEventsRelevant)
372 continue;
373 // Don't add Note event types if they have no length.
374 // Hm, it is possible for zero-length events to be
375 // accidentally present in the list. So the user should
376 // at least be allowed to cut and paste them. The EventList
377 // class will probably be correcting this condition anyway
378 // when adding the event to the list.
379 //if(e.lenValue() == 0)
380 // continue;
381 if(!first_found)
382 {
383 start_time = e.posValue();
384 first_found = true;
385 }
386 if(e.endPosValue() > end_time)
387 end_time = e.endPosValue();
388 ++e_found;
389 break;
390
391 case Wave:
392 if(!wave || (relevant & WaveRelevant) == NoEventsRelevant)
393 continue;
394 // Don't add Wave event types if they have no length.
395 //if(e.lenValue() == 0)
396 // continue;
397 if(!first_found)
398 {
399 start_time = e.posValue();
400 first_found = true;
401 }
402 if(e.endPosValue() > end_time)
403 end_time = e.endPosValue();
404 ++e_found;
405 break;
406
407 case Controller:
408 case Meta:
409 case Sysex:
410 if(wave)
411 continue;
412 switch(et)
413 {
414 case Controller:
415 if((relevant & ControllersRelevant) == NoEventsRelevant)
416 continue;
417 if(ctrlNum >= 0 && e.dataA() != ctrlNum)
418 continue;
419 break;
420
421 case Meta:
422 if((relevant & MetaRelevant) == NoEventsRelevant)
423 continue;
424 break;
425
426 case Sysex:
427 if((relevant & SysexRelevant) == NoEventsRelevant)
428 continue;
429 break;
430
431 default:
432 continue;
433 break;
434 }
435 // For these events, even if duplicates are already found at this position,
436 // the range is still the same, which simplifies this code - go ahead and count it...
437
438 if(!first_found)
439 {
440 start_time = e.posValue();
441 first_found = true;
442 }
443 // For these events, minimum 1 unit time, to qualify as a valid 'range'.
444 if((e.posValue() + 1) > end_time)
445 end_time = e.posValue() + 1;
446 ++e_found;
447 break;
448 }
449 }
450
451 res.setPosValue(start_time);
452 res.setLenValue(end_time - start_time);
453 *numEvents = e_found;
454 return res;
455 }
456
findControllers(bool wave,FindMidiCtlsList_t * outList,int findCtl) const457 void EventList::findControllers(bool wave, FindMidiCtlsList_t* outList, int findCtl) const
458 {
459 for(ciEvent ie = cbegin(); ie != cend(); ++ie)
460 {
461 const Event& e = ie->second;
462 const EventType et = e.type();
463 switch(et)
464 {
465 case Note:
466 case Meta:
467 case Sysex:
468 continue;
469 break;
470
471 case Wave:
472 if(!wave)
473 continue;
474 // TODO Audio controllers.
475 //list->insert( ? );
476 break;
477
478 case Controller:
479 if(wave)
480 continue;
481 if(findCtl < 0 || findCtl == e.dataA())
482 {
483 const PosLen epl = e.posLen();
484 FindMidiCtlsListInsResPair_t pres = outList->insert(FindMidiCtlsPair_t(e.dataA(), epl));
485 if(!pres.second)
486 {
487 iFindMidiCtlsList ifml = pres.first;
488 PosLen& fml = ifml->second;
489 if(fml > epl)
490 fml = epl;
491 }
492 }
493 break;
494 }
495 }
496 }
497
498 // REMOVE Tim. ctrl. Added.
findControllerAt(const Event & event) const499 ciEvent EventList::findControllerAt(const Event& event) const
500 {
501 cEventRange range = equal_range(event.posValue());
502 const int ctlnum = event.dataA();
503 for (ciEvent i = range.first; i != range.second; ++i) {
504 if (i->second.type() == Controller && i->second.dataA() == ctlnum)
505 return i;
506 }
507 return cend();
508 }
509
510 // REMOVE Tim. ctrl. Added.
findControllerAt(const Event & event)511 iEvent EventList::findControllerAt(const Event& event)
512 {
513 EventRange range = equal_range(event.posValue());
514 const int ctlnum = event.dataA();
515 for (iEvent i = range.first; i != range.second; ++i) {
516 if (i->second.type() == Controller && i->second.dataA() == ctlnum)
517 return i;
518 }
519 return end();
520 }
521
522 // REMOVE Tim. ctrl. Added.
controllerValueExists(const Event & event) const523 bool EventList::controllerValueExists(const Event& event) const
524 {
525 cEventRange range = equal_range(event.posValue());
526 const int ctlnum = event.dataA();
527 for (ciEvent i = range.first; i != range.second; ++i) {
528 if (i->second.type() == Controller && i->second.dataA() == ctlnum)
529 return true;
530 }
531 return false;
532 }
533
534 } // namespace MusECore
535