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