summaryrefslogtreecommitdiffstats
path: root/src/base/Event.h
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-01 18:37:05 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-01 18:37:05 +0000
commit145364a8af6a1fec06556221e66d4b724a62fc9a (patch)
tree53bd71a544008c518034f208d64c932dc2883f50 /src/base/Event.h
downloadrosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.tar.gz
rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.zip
Added old abandoned KDE3 version of the RoseGarden MIDI tool
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/rosegarden@1097595 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/base/Event.h')
-rw-r--r--src/base/Event.h584
1 files changed, 584 insertions, 0 deletions
diff --git a/src/base/Event.h b/src/base/Event.h
new file mode 100644
index 0000000..f236681
--- /dev/null
+++ b/src/base/Event.h
@@ -0,0 +1,584 @@
+// -*- c-basic-offset: 4 -*-
+
+
+/*
+ Rosegarden
+ A sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <[email protected]>,
+ Chris Cannam <[email protected]>,
+ Richard Bown <[email protected]>
+
+ The moral right of the authors to claim authorship of this work
+ has been asserted.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+#ifndef _EVENT_H_
+#define _EVENT_H_
+
+#include "PropertyMap.h"
+#include "Exception.h"
+
+#include <string>
+#include <vector>
+#ifndef NDEBUG
+#include <iostream>
+#include <ctime>
+#endif
+
+
+namespace Rosegarden
+{
+
+typedef long timeT;
+
+/**
+ * The Event class represents an event with some basic attributes and
+ * an arbitrary number of properties of dynamically-determined name
+ * and type.
+ *
+ * An Event has a type; a duration, often zero for events other than
+ * notes; an absolute time, the time at which the event begins, which
+ * is used to order events within a Segment; and a "sub-ordering", used
+ * to determine an order for events that have the same absolute time
+ * (for example to ensure that the clef always appears before the key
+ * signature at the start of a piece). Besides these, an event can
+ * have any number of properties, which are typed values stored and
+ * retrieved by name. Properties may be persistent or non-persistent,
+ * depending on whether they are saved to file with the rest of the
+ * event data or are considered to be only cached values that can be
+ * recomputed at will if necessary.
+ */
+
+class Event
+{
+public:
+ class NoData : public Exception {
+ public:
+ NoData(std::string property) :
+ Exception("No data found for property " + property) { }
+ NoData(std::string property, std::string file, int line) :
+ Exception("No data found for property " + property, file, line) { }
+ };
+
+ class BadType : public Exception {
+ public:
+ BadType(std::string property, std::string expected, std::string actl) :
+ Exception("Bad type for " + property + " (expected " +
+ expected + ", found " + actl + ")") { }
+ BadType(std::string property, std::string expected, std::string actual,
+ std::string file, int line) :
+ Exception("Bad type for " + property + " (expected " +
+ expected + ", found " + actual + ")", file, line) { }
+ };
+
+ Event(const std::string &type,
+ timeT absoluteTime, timeT duration = 0, short subOrdering = 0) :
+ m_data(new EventData(type, absoluteTime, duration, subOrdering)),
+ m_nonPersistentProperties(0) { }
+
+ Event(const std::string &type,
+ timeT absoluteTime, timeT duration, short subOrdering,
+ timeT notationAbsoluteTime, timeT notationDuration) :
+ m_data(new EventData(type, absoluteTime, duration, subOrdering)),
+ m_nonPersistentProperties(0) {
+ setNotationAbsoluteTime(notationAbsoluteTime);
+ setNotationDuration(notationDuration);
+ }
+
+ Event(const Event &e) :
+ m_nonPersistentProperties(0) { share(e); }
+
+ // these ctors can't use default args: default has to be obtained from e
+
+ Event(const Event &e, timeT absoluteTime) :
+ m_nonPersistentProperties(0) {
+ share(e);
+ unshare();
+ m_data->m_absoluteTime = absoluteTime;
+ setNotationAbsoluteTime(absoluteTime);
+ setNotationDuration(m_data->m_duration);
+ }
+
+ Event(const Event &e, timeT absoluteTime, timeT duration) :
+ m_nonPersistentProperties(0) {
+ share(e);
+ unshare();
+ m_data->m_absoluteTime = absoluteTime;
+ m_data->m_duration = duration;
+ setNotationAbsoluteTime(absoluteTime);
+ setNotationDuration(duration);
+ }
+
+ Event(const Event &e, timeT absoluteTime, timeT duration, short subOrdering):
+ m_nonPersistentProperties(0) {
+ share(e);
+ unshare();
+ m_data->m_absoluteTime = absoluteTime;
+ m_data->m_duration = duration;
+ m_data->m_subOrdering = subOrdering;
+ setNotationAbsoluteTime(absoluteTime);
+ setNotationDuration(duration);
+ }
+
+ Event(const Event &e, timeT absoluteTime, timeT duration, short subOrdering,
+ timeT notationAbsoluteTime) :
+ m_nonPersistentProperties(0) {
+ share(e);
+ unshare();
+ m_data->m_absoluteTime = absoluteTime;
+ m_data->m_duration = duration;
+ m_data->m_subOrdering = subOrdering;
+ setNotationAbsoluteTime(notationAbsoluteTime);
+ setNotationDuration(duration);
+ }
+
+ Event(const Event &e, timeT absoluteTime, timeT duration, short subOrdering,
+ timeT notationAbsoluteTime, timeT notationDuration) :
+ m_nonPersistentProperties(0) {
+ share(e);
+ unshare();
+ m_data->m_absoluteTime = absoluteTime;
+ m_data->m_duration = duration;
+ m_data->m_subOrdering = subOrdering;
+ setNotationAbsoluteTime(notationAbsoluteTime);
+ setNotationDuration(notationDuration);
+ }
+
+ ~Event() { lose(); }
+
+ Event *copyMoving(timeT offset) const {
+ return new Event(*this,
+ m_data->m_absoluteTime + offset,
+ m_data->m_duration,
+ m_data->m_subOrdering,
+ getNotationAbsoluteTime() + offset,
+ getNotationDuration());
+ }
+
+ Event &operator=(const Event &e) {
+ if (&e != this) { lose(); share(e); }
+ return *this;
+ }
+
+ friend bool operator<(const Event&, const Event&);
+
+ // Accessors
+ const std::string &getType() const { return m_data->m_type; }
+ bool isa(const std::string &t) const { return (m_data->m_type == t); }
+ timeT getAbsoluteTime() const { return m_data->m_absoluteTime; }
+ timeT getDuration() const { return m_data->m_duration; }
+ short getSubOrdering() const { return m_data->m_subOrdering; }
+
+ bool has(const PropertyName &name) const;
+
+ template <PropertyType P>
+ typename PropertyDefn<P>::basic_type get(const PropertyName &name) const;
+ // throw (NoData, BadType);
+
+ // no throw, returns bool
+ template <PropertyType P>
+ bool get(const PropertyName &name, typename PropertyDefn<P>::basic_type &val) const;
+
+ template <PropertyType P>
+ bool isPersistent(const PropertyName &name) const;
+ // throw (NoData);
+
+ template <PropertyType P>
+ void setPersistence(const PropertyName &name, bool persistent);
+ // throw (NoData);
+
+ PropertyType getPropertyType(const PropertyName &name) const;
+ // throw (NoData);
+
+ std::string getPropertyTypeAsString(const PropertyName &name) const;
+ // throw (NoData);
+
+ std::string getAsString(const PropertyName &name) const;
+ // throw (NoData);
+
+ template <PropertyType P>
+ void set(const PropertyName &name, typename PropertyDefn<P>::basic_type value,
+ bool persistent = true);
+ // throw (BadType);
+
+ // set non-persistent, but only if there's no persistent value already
+ template <PropertyType P>
+ void setMaybe(const PropertyName &name, typename PropertyDefn<P>::basic_type value);
+ // throw (BadType);
+
+ template <PropertyType P>
+ void setFromString(const PropertyName &name, std::string value,
+ bool persistent = true);
+ // throw (BadType);
+
+ void unset(const PropertyName &name);
+
+ timeT getNotationAbsoluteTime() const { return m_data->getNotationTime(); }
+ timeT getNotationDuration() const { return m_data->getNotationDuration(); }
+
+ typedef std::vector<PropertyName> PropertyNames;
+ PropertyNames getPropertyNames() const;
+ PropertyNames getPersistentPropertyNames() const;
+ PropertyNames getNonPersistentPropertyNames() const;
+
+ void clearNonPersistentProperties();
+
+ struct EventCmp
+ {
+ bool operator()(const Event &e1, const Event &e2) const {
+ return e1 < e2;
+ }
+ bool operator()(const Event *e1, const Event *e2) const {
+ return *e1 < *e2;
+ }
+ };
+
+ struct EventEndCmp
+ {
+ bool operator()(const Event &e1, const Event &e2) const {
+ return e1.getAbsoluteTime() + e1.getDuration() <=
+ e2.getAbsoluteTime() + e2.getDuration();
+ }
+ bool operator()(const Event *e1, const Event *e2) const {
+ return e1->getAbsoluteTime() + e1->getDuration() <=
+ e2->getAbsoluteTime() + e2->getDuration();
+ }
+ };
+
+ static bool compareEvent2Time(const Event *e, timeT t) {
+ return e->getAbsoluteTime() < t;
+ }
+
+ static bool compareTime2Event(timeT t, const Event *e) {
+ return t < e->getAbsoluteTime();
+ }
+
+ // approximate, for debugging and inspection purposes
+ size_t getStorageSize() const;
+
+ /**
+ * Get the XML string representing the object.
+ */
+ std::string toXmlString();
+
+ /**
+ * Get the XML string representing the object. If the absolute
+ * time of the event differs from the given absolute time, include
+ * the difference between the two as a timeOffset attribute.
+ * If expectedTime == 0, include an absoluteTime attribute instead.
+ */
+ std::string toXmlString(timeT expectedTime);
+
+#ifndef NDEBUG
+ void dump(std::ostream&) const;
+#else
+ void dump(std::ostream&) const {}
+#endif
+ static void dumpStats(std::ostream&);
+
+protected:
+ // these are for subclasses such as XmlStorableEvent
+
+ Event() :
+ m_data(new EventData("", 0, 0, 0)),
+ m_nonPersistentProperties(0) { }
+
+ void setType(const std::string &t) { unshare(); m_data->m_type = t; }
+ void setAbsoluteTime(timeT t) { unshare(); m_data->m_absoluteTime = t; }
+ void setDuration(timeT d) { unshare(); m_data->m_duration = d; }
+ void setSubOrdering(short o) { unshare(); m_data->m_subOrdering = o; }
+ void setNotationAbsoluteTime(timeT t) { unshare(); m_data->setNotationTime(t); }
+ void setNotationDuration(timeT d) { unshare(); m_data->setNotationDuration(d); }
+
+private:
+ bool operator==(const Event &); // not implemented
+
+ struct EventData // Data that are shared between shallow-copied instances
+ {
+ EventData(const std::string &type,
+ timeT absoluteTime, timeT duration, short subOrdering);
+ EventData(const std::string &type,
+ timeT absoluteTime, timeT duration, short subOrdering,
+ const PropertyMap *properties);
+ EventData *unshare();
+ ~EventData();
+ unsigned int m_refCount;
+
+ std::string m_type;
+ timeT m_absoluteTime;
+ timeT m_duration;
+ short m_subOrdering;
+
+ PropertyMap *m_properties;
+
+ // These are properties because we don't care so much about
+ // raw speed in get/set, but we do care about storage size for
+ // events that don't have them or that have zero values:
+ timeT getNotationTime() const;
+ timeT getNotationDuration() const;
+ void setNotationTime(timeT t) {
+ setTime(NotationTime, t, m_absoluteTime);
+ }
+ void setNotationDuration(timeT d) {
+ setTime(NotationDuration, d, m_duration);
+ }
+
+ private:
+ EventData(const EventData &);
+ EventData &operator=(const EventData &);
+ static PropertyName NotationTime;
+ static PropertyName NotationDuration;
+ void setTime(const PropertyName &name, timeT value, timeT deft);
+ };
+
+ EventData *m_data;
+ PropertyMap *m_nonPersistentProperties; // Unique to an instance
+
+ void share(const Event &e) {
+ m_data = e.m_data;
+ m_data->m_refCount++;
+ }
+
+ bool unshare() { // returns true if unshare was necessary
+ if (m_data->m_refCount > 1) {
+ m_data = m_data->unshare();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void lose() {
+ if (--m_data->m_refCount == 0) delete m_data;
+ delete m_nonPersistentProperties;
+ m_nonPersistentProperties = 0;
+ }
+
+ // returned iterator (in i) only valid if return map value is non-zero
+ PropertyMap *find(const PropertyName &name, PropertyMap::iterator &i);
+
+ const PropertyMap *find(const PropertyName &name,
+ PropertyMap::const_iterator &i) const {
+ PropertyMap::iterator j;
+ PropertyMap *map = const_cast<Event *>(this)->find(name, j);
+ i = j;
+ return map;
+ }
+
+ PropertyMap::iterator insert(const PropertyPair &pair, bool persistent) {
+ PropertyMap **map =
+ (persistent ? &m_data->m_properties : &m_nonPersistentProperties);
+ if (!*map) *map = new PropertyMap();
+ return (*map)->insert(pair).first;
+ }
+
+#ifndef NDEBUG
+ static int m_getCount;
+ static int m_setCount;
+ static int m_setMaybeCount;
+ static int m_hasCount;
+ static int m_unsetCount;
+ static clock_t m_lastStats;
+#endif
+};
+
+
+template <PropertyType P>
+bool
+Event::get(const PropertyName &name, typename PropertyDefn<P>::basic_type &val) const
+{
+#ifndef NDEBUG
+ ++m_getCount;
+#endif
+
+ PropertyMap::const_iterator i;
+ const PropertyMap *map = find(name, i);
+
+ if (map) {
+
+ PropertyStoreBase *sb = i->second;
+ if (sb->getType() == P) {
+ val = (static_cast<PropertyStore<P> *>(sb))->getData();
+ return true;
+ }
+ else {
+#ifndef NDEBUG
+ std::cerr << "Event::get() Error: Attempt to get property \"" << name
+ << "\" as " << PropertyDefn<P>::typeName() <<", actual type is "
+ << sb->getTypeName() << std::endl;
+#endif
+ return false;
+ }
+
+ } else {
+ return false;
+ }
+}
+
+
+template <PropertyType P>
+typename PropertyDefn<P>::basic_type
+Event::get(const PropertyName &name) const
+ // throw (NoData, BadType)
+{
+#ifndef NDEBUG
+ ++m_getCount;
+#endif
+
+ PropertyMap::const_iterator i;
+ const PropertyMap *map = find(name, i);
+
+ if (map) {
+
+ PropertyStoreBase *sb = i->second;
+ if (sb->getType() == P)
+ return (static_cast<PropertyStore<P> *>(sb))->getData();
+ else {
+ throw BadType(name.getName(),
+ PropertyDefn<P>::typeName(), sb->getTypeName(),
+ __FILE__, __LINE__);
+ }
+
+ } else {
+
+#ifndef NDEBUG
+ std::cerr << "Event::get(): Error dump follows:" << std::endl;
+ dump(std::cerr);
+#endif
+ throw NoData(name.getName(), __FILE__, __LINE__);
+ }
+}
+
+
+template <PropertyType P>
+bool
+Event::isPersistent(const PropertyName &name) const
+ // throw (NoData)
+{
+ PropertyMap::const_iterator i;
+ const PropertyMap *map = find(name, i);
+
+ if (map) {
+ return (map == m_data->m_properties);
+ } else {
+ throw NoData(name.getName(), __FILE__, __LINE__);
+ }
+}
+
+
+template <PropertyType P>
+void
+Event::setPersistence(const PropertyName &name, bool persistent)
+ // throw (NoData)
+{
+ unshare();
+ PropertyMap::iterator i;
+ PropertyMap *map = find(name, i);
+
+ if (map) {
+ insert(*i, persistent);
+ map->erase(i);
+ } else {
+ throw NoData(name.getName(), __FILE__, __LINE__);
+ }
+}
+
+
+template <PropertyType P>
+void
+Event::set(const PropertyName &name, typename PropertyDefn<P>::basic_type value,
+ bool persistent)
+ // throw (BadType)
+{
+#ifndef NDEBUG
+ ++m_setCount;
+#endif
+
+ // this is a little slow, could bear improvement
+
+ unshare();
+ PropertyMap::iterator i;
+ PropertyMap *map = find(name, i);
+
+ if (map) {
+ bool persistentBefore = (map == m_data->m_properties);
+ if (persistentBefore != persistent) {
+ i = insert(*i, persistent);
+ map->erase(name);
+ }
+
+ PropertyStoreBase *sb = i->second;
+ if (sb->getType() == P) {
+ (static_cast<PropertyStore<P> *>(sb))->setData(value);
+ } else {
+ throw BadType(name.getName(),
+ PropertyDefn<P>::typeName(), sb->getTypeName(),
+ __FILE__, __LINE__);
+ }
+
+ } else {
+ PropertyStoreBase *p = new PropertyStore<P>(value);
+ insert(PropertyPair(name, p), persistent);
+ }
+}
+
+
+
+// setMaybe<> is actually called rather more frequently than set<>, so
+// it makes sense for best performance to implement it separately
+// rather than through calls to has, isPersistent and set<>
+
+template <PropertyType P>
+void
+Event::setMaybe(const PropertyName &name, typename PropertyDefn<P>::basic_type value)
+ // throw (BadType)
+{
+#ifndef NDEBUG
+ ++m_setMaybeCount;
+#endif
+
+ unshare();
+ PropertyMap::iterator i;
+ PropertyMap *map = find(name, i);
+
+ if (map) {
+ if (map == m_data->m_properties) return; // persistent, so ignore it
+
+ PropertyStoreBase *sb = i->second;
+
+ if (sb->getType() == P) {
+ (static_cast<PropertyStore<P> *>(sb))->setData(value);
+ } else {
+ throw BadType(name.getName(),
+ PropertyDefn<P>::typeName(), sb->getTypeName(),
+ __FILE__, __LINE__);
+ }
+ } else {
+ PropertyStoreBase *p = new PropertyStore<P>(value);
+ insert(PropertyPair(name, p), false);
+ }
+}
+
+
+template <PropertyType P>
+void
+Event::setFromString(const PropertyName &name, std::string value, bool persistent)
+ // throw (BadType)
+{
+ set<P>(name, PropertyDefn<P>::parse(value), persistent);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+
+}
+
+#endif