1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 
4 /*
5     Rosegarden
6     A sequencer and musical notation editor.
7     Copyright 2000-2021 the Rosegarden development team.
8     See the AUTHORS file for more details.
9 
10     This program is free software; you can redistribute it and/or
11     modify it under the terms of the GNU General Public License as
12     published by the Free Software Foundation; either version 2 of the
13     License, or (at your option) any later version.  See the file
14     COPYING included with this distribution for more information.
15 */
16 
17 #ifndef RG_EVENT_H
18 #define RG_EVENT_H
19 
20 #include "PropertyMap.h"
21 #include "Exception.h"
22 #include "TimeT.h"
23 #include "misc/Debug.h"
24 
25 #include <rosegardenprivate_export.h>
26 
27 #include <string>
28 #include <vector>
29 #include <iostream>
30 
31 
32 namespace Rosegarden
33 {
34 
35 
36 /// A generic Event.
37 /**
38  * The Event class represents an event of arbitrary type with some basic
39  * common attributes and an arbitrary number of properties of dynamically-
40  * determined name and type.
41  *
42  * An Event has a type; a duration, often zero for events other than
43  * notes; an absolute time, the time at which the event begins, which
44  * is used to order events within a Segment; and a "sub-ordering", used
45  * to determine an order for events that have the same absolute time
46  * (for example to ensure that the clef always appears before the key
47  * signature at the start of a piece).  Besides these, an event can
48  * have any number of properties, which are typed values stored and
49  * retrieved by name.  Properties may be persistent or non-persistent,
50  * depending on whether they are saved to file with the rest of the
51  * event data or are considered to be only cached values that can be
52  * recomputed at will if necessary.
53  *
54  * Segment is the primary container of Event objects.
55  *
56  * This class is both generic and polymorphic without using C++ language
57  * features (templates and inheritance) to implement those qualities.
58  * It would be interesting to explore whether inheritance/polymorphism
59  * would lead to an easier to understand and faster implementation of
60  * Event.  The concrete types like Note would inherit directly from Event
61  * and would provide member objects without using properties and a
62  * PropertyMap.  One key downside is that older versions of rg would then
63  * be unable to preserve properties that they do not understand.
64  * Not sure that's a very big deal given that the properties have been
65  * pretty stable for quite a while.
66  *
67  * There are concrete types such as Note (in NotationTypes.h) and
68  * ProgramChange (in MidiTypes.h) which can create Event objects as
69  * needed.  Generally, the concrete types provide a "getAs*Event()" routine
70  * to create a corresponding Event object.
71  */
72 class ROSEGARDENPRIVATE_EXPORT Event
73 {
74 public:
75 
76     // *** Exceptions
77 
78     /// Attempt to access a property that is not present in the Event
79     class NoData : public Exception {
80     public:
NoData(const std::string & property)81         NoData(const std::string &property) :
82             Exception("No data found for property " + property)
83         { }
NoData(const std::string & property,const std::string & file,int line)84         NoData(const std::string &property, const std::string &file, int line) :
85             Exception("No data found for property " + property, file, line)
86         { }
87     };
88 
89     /// Attempt to access a property with the wrong type
90     class BadType : public Exception {
91     public:
BadType(const std::string & property,const std::string & expected,const std::string & actual)92         BadType(const std::string &property, const std::string &expected, const std::string &actual) :
93             Exception("Bad type for " + property + " (expected " +
94                       expected + ", found " + actual + ")")
95         { }
BadType(const std::string & property,const std::string & expected,const std::string & actual,const std::string & file,int line)96         BadType(const std::string &property, const std::string &expected, const std::string &actual,
97                 const std::string &file, int line) :
98             Exception("Bad type for " + property + " (expected " +
99                       expected + ", found " + actual + ")", file, line)
100         { }
101     };
102 
103     // *** Constructors
104 
105     Event(const std::string &type,
106           timeT absoluteTime, timeT duration = 0, short subOrdering = 0) :
m_data(new EventData (type,absoluteTime,duration,subOrdering))107         m_data(new EventData(type, absoluteTime, duration, subOrdering)),
108         m_nonPersistentProperties(nullptr)
109     { }
110 
Event(const std::string & type,timeT absoluteTime,timeT duration,short subOrdering,timeT notationAbsoluteTime,timeT notationDuration)111     Event(const std::string &type,
112           timeT absoluteTime, timeT duration, short subOrdering,
113           timeT notationAbsoluteTime, timeT notationDuration) :
114         m_data(new EventData(type, absoluteTime, duration, subOrdering)),
115         m_nonPersistentProperties(nullptr)
116     {
117         setNotationAbsoluteTime(notationAbsoluteTime);
118         setNotationDuration(notationDuration);
119     }
120 
121     // these ctors can't use default args: default has to be obtained from e
122 
Event(const Event & e,timeT absoluteTime)123     Event(const Event &e, timeT absoluteTime) :
124         m_nonPersistentProperties(nullptr)
125     {
126         share(e);
127         unshare();
128         m_data->m_absoluteTime = absoluteTime;
129         setNotationAbsoluteTime(absoluteTime);
130         setNotationDuration(m_data->m_duration);
131     }
132 
Event(const Event & e,timeT absoluteTime,timeT duration)133     Event(const Event &e, timeT absoluteTime, timeT duration) :
134         m_nonPersistentProperties(nullptr)
135     {
136         share(e);
137         unshare();
138         m_data->m_absoluteTime = absoluteTime;
139         m_data->m_duration = duration;
140         setNotationAbsoluteTime(absoluteTime);
141         setNotationDuration(duration);
142     }
143 
Event(const Event & e,timeT absoluteTime,timeT duration,short subOrdering)144     Event(const Event &e, timeT absoluteTime,
145           timeT duration, short subOrdering):
146         m_nonPersistentProperties(nullptr)
147     {
148         share(e);
149         unshare();
150         m_data->m_absoluteTime = absoluteTime;
151         m_data->m_duration = duration;
152         m_data->m_subOrdering = subOrdering;
153         setNotationAbsoluteTime(absoluteTime);
154         setNotationDuration(duration);
155     }
156 
Event(const Event & e,timeT absoluteTime,timeT duration,short subOrdering,timeT notationAbsoluteTime)157     Event(const Event &e, timeT absoluteTime, timeT duration, short subOrdering,
158           timeT notationAbsoluteTime) :
159         m_nonPersistentProperties(nullptr)
160     {
161         share(e);
162         unshare();
163         m_data->m_absoluteTime = absoluteTime;
164         m_data->m_duration = duration;
165         m_data->m_subOrdering = subOrdering;
166         setNotationAbsoluteTime(notationAbsoluteTime);
167         setNotationDuration(duration);
168     }
169 
Event(const Event & e,timeT absoluteTime,timeT duration,short subOrdering,timeT notationAbsoluteTime,timeT notationDuration)170     Event(const Event &e, timeT absoluteTime, timeT duration, short subOrdering,
171           timeT notationAbsoluteTime, timeT notationDuration) :
172         m_nonPersistentProperties(nullptr)
173     {
174         share(e);
175         unshare();
176         m_data->m_absoluteTime = absoluteTime;
177         m_data->m_duration = duration;
178         m_data->m_subOrdering = subOrdering;
179         setNotationAbsoluteTime(notationAbsoluteTime);
180         setNotationDuration(notationDuration);
181     }
182 
~Event()183     ~Event()  { lose(); }
184 
Event(const Event & e)185     Event(const Event &e) :
186         m_nonPersistentProperties(nullptr)
187     {
188         share(e);
189     }
190 
191     Event &operator=(const Event &e)
192     {
193         // If they aren't the same...
194         if (&e != this) {
195             lose();
196             share(e);
197         }
198 
199         return *this;
200     }
201 
copyMoving(timeT offset)202     Event *copyMoving(timeT offset) const
203     {
204         return new Event(*this,
205                          m_data->m_absoluteTime + offset,
206                          m_data->m_duration,
207                          m_data->m_subOrdering,
208                          getNotationAbsoluteTime() + offset,
209                          getNotationDuration());
210     }
211 
212     // check if the events are copies
213     bool isCopyOf(const Event &e) const;
214 
215     friend bool operator<(const Event&, const Event&);
216 
217     /// Type of the Event (E.g. Note, Accidental, Key, etc...)
218     /**
219      * See NotationTypes.h and MidiTypes.h for more examples.
220      */
getType()221     std::string getType() const
222     {
223         if (!m_data) {
224             RG_DEBUG << "Event::getType(): FATAL: m_data == nullptr.  Crash likely.";
225             return "";
226         }
227         return m_data->m_type;
228     }
229     /// Check Event type.
isa(const std::string & type)230     bool isa(const std::string &type) const  { return (m_data->m_type == type); }
231 
getAbsoluteTime()232     timeT getAbsoluteTime() const  { return m_data->m_absoluteTime; }
getNotationAbsoluteTime()233     timeT getNotationAbsoluteTime() const  { return m_data->getNotationTime(); }
234     /// Move Event in time without any ancillary coordination.
235     /**
236      * UNSAFE.  Don't call this unless you know exactly what you're doing.
237      */
238     void unsafeChangeTime(timeT offset);
239 
getDuration()240     timeT getDuration() const  { return m_data->m_duration; }
getNotationDuration()241     timeT getNotationDuration() const  { return m_data->getNotationDuration(); }
242     /**
243      * Returns the greater of getDuration() or getNotationDuration() for Note
244      * Events.  Returns getDuration() for all other Event types.
245      *
246      * \author Tito Latini
247      */
248     timeT getGreaterDuration();
249 
getSubOrdering()250     short getSubOrdering() const  { return m_data->m_subOrdering; }
251 
252     /**
253      * Return whether this Event's section of a triggered ornament
254      * is masked, for use when the Event is part of a multiple-tied-note
255      * ornament trigger.  Uses the TRIGGER_EXPAND property.
256      */
257     bool maskedInTrigger() const;
258 
259     // *** Properties (name/value pairs)
260 
261     /**
262      * Tests if the Event has the property/data in parameter
263      */
264     bool has(const PropertyName &name) const;
265 
266     /// Get the value for a property
267     /**
268      * \returns The value of the property.
269      * \throws NoData
270      * \throws BadType
271      */
272     template <PropertyType P>
273     typename PropertyDefn<P>::basic_type get(const PropertyName &name) const;
274 
275     /// Get the value for a property
276     /**
277      * \returns true if the property value was successfully retrieved.
278      */
279     template <PropertyType P>
280     bool get(const PropertyName &name, typename PropertyDefn<P>::basic_type &val) const;
281 
282     /// Get the value for a property as a std::string
283     /**
284      * \throws NoData
285      */
286     std::string getAsString(const PropertyName &name) const;
287 
288     /**
289      * Tests if the specified property/data is persistent (is copied
290      * when duplicating the Event) or not
291      * \throws NoData
292      */
293     template <PropertyType P>
294     bool isPersistent(const PropertyName &name) const;
295 
296     /**
297      * \throws NoData
298      */
299     PropertyType getPropertyType(const PropertyName &name) const;
300 
301     /**
302      * \throws NoData
303      */
304     std::string getPropertyTypeAsString(const PropertyName &name) const;
305 
306     /// Set the value for a property.
307     /**
308      * If the property/data already exists, this function just modifies the
309      * stored value, and if not, it creates the association.
310      *
311      * \throws BadType
312      */
313     template <PropertyType P>
314     void set(const PropertyName &name, typename PropertyDefn<P>::basic_type value,
315              bool persistent = true);
316 
317     /// Set the value for a property if it doesn't exist as a persistent value.
318     /**
319      * \throws BadType
320      */
321     template <PropertyType P>
322     void setMaybe(const PropertyName &name, typename PropertyDefn<P>::basic_type value);
323 
324     /// Destroy a property.
325     /**
326      * Does nothing if the property does not exist.
327      */
328     void unset(const PropertyName &name);
329 
330     typedef std::vector<PropertyName> PropertyNames;
331     PropertyNames getPersistentPropertyNames() const;
332     PropertyNames getNonPersistentPropertyNames() const;
333 
334     /**
335      * Destroy all the non persistent properties.
336      */
337     void clearNonPersistentProperties();
338 
339     /// Compare Event objects using Event::operator<.
340     /**
341      * Used when creating sets and multisets of Event objects, like Segment.
342      */
343     struct EventCmp
344     {
operatorEventCmp345         bool operator()(const Event *e1, const Event *e2) const
346         {
347             return *e1 < *e2;
348         }
349     };
350 
351     /// Compare Event objects based on their end times.
352     /**
353      * Used for example in classes that export to other formats, like
354      * Lilypond.
355      */
356     struct EventEndCmp
357     {
operatorEventEndCmp358         bool operator()(const Event *e1, const Event *e2) const
359         {
360             return e1->getAbsoluteTime() + e1->getDuration() <=
361                 e2->getAbsoluteTime() + e2->getDuration();
362         }
363     };
364 
365     /// Get the XML string representing the object.
366     /**
367      * If the absolute time of the event differs from the expected time,
368      * include the difference between the two as a timeOffset attribute.
369      * If expectedTime == 0, include an absoluteTime attribute instead.
370      */
371     std::string toXmlString(timeT expectedTime) const;
372 
373     // *** DEBUG
374 
375     /// Approximate.  For debugging and inspection purposes.
376     size_t getStorageSize() const;
377 
378     // UNUSED
379     static void dumpStats(std::ostream &);
380 
381 protected:
382 
383     // Interface for subclasses such as XmlStorableEvent.
384 
Event()385     Event() :
386         m_data(new EventData("", 0, 0, 0)),
387         m_nonPersistentProperties(nullptr)
388     { }
389 
setType(const std::string & t)390     void setType(const std::string &t) { unshare(); m_data->m_type = t; }
setAbsoluteTime(timeT t)391     void setAbsoluteTime(timeT t)      { unshare(); m_data->m_absoluteTime = t; }
setDuration(timeT d)392     void setDuration(timeT d)          { unshare(); m_data->m_duration = d; }
setSubOrdering(short o)393     void setSubOrdering(short o)       { unshare(); m_data->m_subOrdering = o; }
setNotationAbsoluteTime(timeT t)394     void setNotationAbsoluteTime(timeT t) { unshare(); m_data->setNotationTime(t); }
setNotationDuration(timeT d)395     void setNotationDuration(timeT d) { unshare(); m_data->setNotationDuration(d); }
396 
397 private:
398     friend QDebug &operator<<(QDebug &dbg, const Event &event);
399 
400     /// Data that are shared between shallow-copied instances
401     struct EventData
402     {
403         EventData(const std::string &type,
404                   timeT absoluteTime, timeT duration, short subOrdering);
405         EventData(const std::string &type,
406                   timeT absoluteTime, timeT duration, short subOrdering,
407                   const PropertyMap *properties);
408         /// Make a unique copy.  Used for Copy On Write.
409         EventData *unshare();
410         ~EventData();
411         unsigned int m_refCount;
412 
413         std::string m_type;
414         timeT m_absoluteTime;
415         timeT m_duration;
416         short m_subOrdering;
417 
418         PropertyMap *m_properties;
419 
420         // These are properties because we don't care so much about
421         // raw speed in get/set, but we do care about storage size for
422         // events that don't have them or that have zero values:
setNotationTimeEventData423         void setNotationTime(timeT t)
424             { setTime(NotationTime, t, m_absoluteTime); }
425         timeT getNotationTime() const;
setNotationDurationEventData426         void setNotationDuration(timeT d)
427             { setTime(NotationDuration, d, m_duration); }
428         timeT getNotationDuration() const;
429 
430     private:
431         EventData(const EventData &);
432         EventData &operator=(const EventData &);
433 
434         static PropertyName NotationTime;
435         static PropertyName NotationDuration;
436 
437         /// Add the time property unless (t == deft).
438         void setTime(const PropertyName &name, timeT t, timeT deft);
439     };
440 
441     // ??? This is a reference counted smart pointer supporting Copy
442     //     On Write.  We probably can't replace it with a QSharedPointer.
443     //     It would be more interesting to make Copy On Write disable-able
444     //     and see if it makes any sort of performance or memory difference.
445     //     Might also be a good idea to see if C++11 move semantics would help.
446     EventData *m_data;
447     // ??? This doesn't seem to participate in Copy On Write, so a
448     //     QSharedPointer should simplify managing this.
449     PropertyMap *m_nonPersistentProperties; // Unique to an instance
450 
share(const Event & e)451     void share(const Event &e)
452     {
453         m_data = e.m_data;
454         m_data->m_refCount++;
455     }
456 
457     /// Makes a copy.  Used for Copy On Write.
458     /**
459      * Returns true if unshare was actually necessary.
460      */
unshare()461     bool unshare()
462     {
463         if (m_data->m_refCount > 1) {
464             m_data = m_data->unshare();
465             return true;
466         } else {
467             return false;
468         }
469     }
470 
471     /// Dereference and delete.
lose()472     void lose()
473     {
474         if (--m_data->m_refCount == 0) {
475             delete m_data;
476             m_data = nullptr;
477         }
478         delete m_nonPersistentProperties;
479         m_nonPersistentProperties = nullptr;
480     }
481 
482     /// Find a property in both the persistent and non-persistent properties.
483     /**
484      * @param[in]  name The property to find.
485      * @param[out] i    An iterator pointing to the property that was found.
486      *                  Invalid if the function return value is nullptr.
487      * \return The map in which the property was found.  Returns nullptr
488      *         otherwise.
489      */
490     PropertyMap *find(const PropertyName &name, PropertyMap::iterator &i);
491 
492     /// Find a property in both the persistent and non-persistent properties.
493     /**
494      * @param[in]  name The property to find.
495      * @param[out] i    An iterator pointing to the property that was found.
496      *                  Invalid if the function return value is nullptr.
497      * \return The map in which the property was found.  Returns nullptr
498      *         otherwise.
499      */
find(const PropertyName & name,PropertyMap::const_iterator & i)500     const PropertyMap *find(const PropertyName &name,
501                             PropertyMap::const_iterator &i) const
502     {
503         PropertyMap::iterator j;
504         PropertyMap *map = const_cast<Event *>(this)->find(name, j);
505         i = j;
506         return map;
507     }
508 
insert(const PropertyPair & pair,bool persistent)509     PropertyMap::iterator insert(const PropertyPair &pair, bool persistent)
510     {
511         PropertyMap **map =
512             (persistent ? &m_data->m_properties : &m_nonPersistentProperties);
513 
514         // If the map hasn't been created yet, create it.
515         if (!*map)
516             *map = new PropertyMap();
517 
518         return (*map)->insert(pair).first;
519     }
520 
521 #ifndef NDEBUG
522     static int m_getCount;
523     static int m_setCount;
524     static int m_setMaybeCount;
525     static int m_hasCount;
526     static int m_unsetCount;
527     static clock_t m_lastStats;
528 #endif
529 };
530 
531 extern ROSEGARDENPRIVATE_EXPORT QDebug &operator<<(QDebug &dbg, const Event &event);
532 
533 template <PropertyType P>
534 bool
get(const PropertyName & name,typename PropertyDefn<P>::basic_type & val)535 Event::get(const PropertyName &name,
536            typename PropertyDefn<P>::basic_type &val) const
537 {
538 #ifndef NDEBUG
539     ++m_getCount;
540 #endif
541 
542     PropertyMap::const_iterator i;
543     const PropertyMap *map = find(name, i);
544 
545     // Not found?  Bail.
546     if (!map)
547         return false;
548 
549     PropertyStoreBase *sb = i->second;
550     if (sb->getType() == P) {
551         val = (static_cast<PropertyStore<P> *>(sb))->getData();
552         return true;
553     } else {
554 #ifndef NDEBUG
555         RG_DEBUG << "get() Error: Attempt to get property \"" << name.getName() << "\" as" << PropertyDefn<P>::typeName() <<", actual type is" << sb->getTypeName();
556 #endif
557         return false;
558     }
559 }
560 
561 template <PropertyType P>
562 typename PropertyDefn<P>::basic_type
get(const PropertyName & name)563 Event::get(const PropertyName &name) const
564     // throw (NoData, BadType)
565 {
566 #ifndef NDEBUG
567     ++m_getCount;
568 #endif
569 
570     PropertyMap::const_iterator i;
571     const PropertyMap *map = find(name, i);
572 
573     if (map) {
574 
575         PropertyStoreBase *sb = i->second;
576         if (sb->getType() == P)
577             return (static_cast<PropertyStore<P> *>(sb))->getData();
578         else {
579             throw BadType(name.getName(),
580                           PropertyDefn<P>::typeName(), sb->getTypeName(),
581                           __FILE__, __LINE__);
582         }
583 
584     } else {
585 
586 #ifndef NDEBUG
587         RG_DEBUG << "Event::get(): Property" << name.getName().c_str() << "not found for Event:";
588         RG_DEBUG << *this;
589 #endif
590         throw NoData(name.getName(), __FILE__, __LINE__);
591     }
592 }
593 
594 
595 template <PropertyType P>
596 bool
isPersistent(const PropertyName & name)597 Event::isPersistent(const PropertyName &name) const
598     // throw (NoData)
599 {
600     PropertyMap::const_iterator i;
601     const PropertyMap *map = find(name, i);
602 
603     if (!map)
604         throw NoData(name.getName(), __FILE__, __LINE__);
605 
606     return (map == m_data->m_properties);
607 }
608 
609 
610 template <PropertyType P>
611 void
set(const PropertyName & name,typename PropertyDefn<P>::basic_type value,bool persistent)612 Event::set(const PropertyName &name, typename PropertyDefn<P>::basic_type value,
613            bool persistent)
614     // throw (BadType)
615 {
616 #ifndef NDEBUG
617     ++m_setCount;
618 #endif
619 
620     // this is a little slow, could bear improvement
621 
622     // Copy on Write
623     unshare();
624 
625     PropertyMap::iterator i;
626     PropertyMap *map = find(name, i);
627 
628     // If found, update.
629     if (map) {
630         bool persistentBefore = (map == m_data->m_properties);
631         if (persistentBefore != persistent) {
632             i = insert(*i, persistent);
633             map->erase(name);
634         }
635 
636         PropertyStoreBase *sb = i->second;
637         if (sb->getType() == P) {
638             (static_cast<PropertyStore<P> *>(sb))->setData(value);
639         } else {
640             throw BadType(name.getName(),
641                           PropertyDefn<P>::typeName(), sb->getTypeName(),
642                           __FILE__, __LINE__);
643         }
644 
645     } else {  // Create
646         PropertyStoreBase *p = new PropertyStore<P>(value);
647         insert(PropertyPair(name, p), persistent);
648     }
649 }
650 
651 
652 template <PropertyType P>
653 void
setMaybe(const PropertyName & name,typename PropertyDefn<P>::basic_type value)654 Event::setMaybe(const PropertyName &name, typename PropertyDefn<P>::basic_type value)
655     // throw (BadType)
656 {
657     // setMaybe<> is actually called rather more frequently than set<>, so
658     // it makes sense for best performance to implement it separately
659     // rather than through calls to has, isPersistent and set<>
660 
661 #ifndef NDEBUG
662     ++m_setMaybeCount;
663 #endif
664 
665     // Copy On Write
666     unshare();
667 
668     PropertyMap::iterator i;
669     PropertyMap *map = find(name, i);
670 
671     // If found, update only if not persistent
672     if (map) {
673         // If persistent, bail.
674         if (map == m_data->m_properties)
675             return;
676 
677         PropertyStoreBase *sb = i->second;
678 
679         if (sb->getType() == P) {
680             (static_cast<PropertyStore<P> *>(sb))->setData(value);
681         } else {
682             throw BadType(name.getName(),
683                           PropertyDefn<P>::typeName(), sb->getTypeName(),
684                           __FILE__, __LINE__);
685         }
686     } else {  // Create
687         PropertyStoreBase *p = new PropertyStore<P>(value);
688         insert(PropertyPair(name, p),
689                false);  // persistent
690     }
691 }
692 
693 
694 }
695 
696 #endif
697