summaryrefslogtreecommitdiff
path: root/libs/evoral/evoral
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2014-11-22 04:05:42 -0500
committerDavid Robillard <d@drobilla.net>2014-11-22 04:05:42 -0500
commitc1cfa12d6e5136d2e3e5501e83ff74c5009a9e60 (patch)
tree56d2811bc8b9d6f2a5accfa8e497ddd5976c7c7a /libs/evoral/evoral
parentcae74309a583c29dd6cc2081425c2e7b673ea13e (diff)
Wrap MusicalTime in a class.
This lets us get a more explicit handle on time conversions, and is the main step towards using actual beat:tick time and getting away from floating point precision problems.
Diffstat (limited to 'libs/evoral/evoral')
-rw-r--r--libs/evoral/evoral/Event.hpp16
-rw-r--r--libs/evoral/evoral/Note.hpp10
-rw-r--r--libs/evoral/evoral/PatchChange.hpp4
-rw-r--r--libs/evoral/evoral/Sequence.hpp14
-rw-r--r--libs/evoral/evoral/types.hpp205
5 files changed, 193 insertions, 56 deletions
diff --git a/libs/evoral/evoral/Event.hpp b/libs/evoral/evoral/Event.hpp
index 59e5612e0e..059b64225b 100644
--- a/libs/evoral/evoral/Event.hpp
+++ b/libs/evoral/evoral/Event.hpp
@@ -48,7 +48,7 @@ template<typename Time>
class LIBEVORAL_API Event {
public:
#ifdef EVORAL_EVENT_ALLOC
- Event (EventType type=0, Time time=0, uint32_t size=0, uint8_t* buf=NULL, bool alloc=false);
+ Event (EventType type=0, Time time=Time(), uint32_t size=0, uint8_t* buf=NULL, bool alloc=false);
/** Copy \a copy.
*
@@ -114,11 +114,11 @@ public:
}
inline void clear() {
- _type = 0;
- _original_time = 0;
- _nominal_time = 0;
- _size = 0;
- _buf = NULL;
+ _type = 0;
+ _original_time = Time();
+ _nominal_time = Time();
+ _size = 0;
+ _buf = NULL;
}
#else
@@ -154,9 +154,6 @@ protected:
#endif
};
-} // namespace Evoral
-
-
template<typename Time>
/*LIBEVORAL_API*/ std::ostream& operator<<(std::ostream& o, const Evoral::Event<Time>& ev) {
o << "Event #" << ev.id() << " type = " << ev.event_type() << " @ " << ev.time();
@@ -168,6 +165,7 @@ template<typename Time>
return o;
}
+} // namespace Evoral
#endif // EVORAL_EVENT_HPP
diff --git a/libs/evoral/evoral/Note.hpp b/libs/evoral/evoral/Note.hpp
index 5401271621..87c8a9fe83 100644
--- a/libs/evoral/evoral/Note.hpp
+++ b/libs/evoral/evoral/Note.hpp
@@ -39,16 +39,16 @@ class LIBEVORAL_LOCAL Note {
class LIBEVORAL_TEMPLATE_API Note {
#endif
public:
- Note(uint8_t chan=0, Time time=0, Time len=0, uint8_t note=0, uint8_t vel=0x40);
+ Note(uint8_t chan=0, Time time=Time(), Time len=Time(), uint8_t note=0, uint8_t vel=0x40);
Note(const Note<Time>& copy);
~Note();
const Note<Time>& operator=(const Note<Time>& copy);
inline bool operator==(const Note<Time>& other) {
- return musical_time_equal (time(), other.time()) &&
+ return time() == other.time() &&
note() == other.note() &&
- musical_time_equal (length(), other.length()) &&
+ length() == other.length() &&
velocity() == other.velocity() &&
off_velocity() == other.off_velocity() &&
channel() == other.channel();
@@ -109,8 +109,6 @@ private:
MIDIEvent<Time> _off_event;
};
-} // namespace Evoral
-
template<typename Time>
/*LIBEVORAL_API*/ std::ostream& operator<<(std::ostream& o, const Evoral::Note<Time>& n) {
o << "Note #" << n.id() << ": pitch = " << (int) n.note()
@@ -120,6 +118,8 @@ template<typename Time>
return o;
}
+} // namespace Evoral
+
#ifdef COMPILER_MSVC
#include "../src/Note.impl"
#endif
diff --git a/libs/evoral/evoral/PatchChange.hpp b/libs/evoral/evoral/PatchChange.hpp
index 48ed0f9c13..39ea421242 100644
--- a/libs/evoral/evoral/PatchChange.hpp
+++ b/libs/evoral/evoral/PatchChange.hpp
@@ -120,7 +120,7 @@ public:
uint8_t channel () const { return _program_change.buffer()[0] & 0xf; }
inline bool operator< (const PatchChange<Time>& o) const {
- if (!musical_time_equal (time(), o.time())) {
+ if (time() != o.time()) {
return time() < o.time();
}
@@ -132,7 +132,7 @@ public:
}
inline bool operator== (const PatchChange<Time>& o) const {
- return (musical_time_equal (time(), o.time()) && program() == o.program() && bank() == o.bank());
+ return (time() == o.time() && program() == o.program() && bank() == o.bank());
}
/** The PatchChange is made up of messages() MIDI messages; this method returns them by index.
diff --git a/libs/evoral/evoral/Sequence.hpp b/libs/evoral/evoral/Sequence.hpp
index 484afa8459..e40c4da925 100644
--- a/libs/evoral/evoral/Sequence.hpp
+++ b/libs/evoral/evoral/Sequence.hpp
@@ -105,7 +105,7 @@ public:
ResolveStuckNotes
};
- void end_write (StuckNoteOption, Time when = 0);
+ void end_write (StuckNoteOption, Time when = Time());
void append(const Event<Time>& ev, Evoral::event_id_t evid);
@@ -127,7 +127,7 @@ public:
struct EarlierNoteComparator {
inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
const boost::shared_ptr< const Note<Time> > b) const {
- return musical_time_less_than (a->time(), b->time());
+ return a->time() < b->time();
}
};
@@ -135,7 +135,7 @@ public:
typedef const Note<Time>* value_type;
inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
const boost::shared_ptr< const Note<Time> > b) const {
- return musical_time_greater_than (a->time(), b->time());
+ return a->time() > b->time();
}
};
@@ -143,7 +143,7 @@ public:
typedef const Note<Time>* value_type;
inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
const boost::shared_ptr< const Note<Time> > b) const {
- return musical_time_greater_than (a->end_time(), b->end_time());
+ return a->end_time() > b->end_time();
}
};
@@ -187,7 +187,7 @@ public:
struct EarlierSysExComparator {
inline bool operator() (constSysExPtr a, constSysExPtr b) const {
- return musical_time_less_than (a->time(), b->time());
+ return a->time() < b->time();
}
};
@@ -200,7 +200,7 @@ public:
struct EarlierPatchChangeComparator {
inline bool operator() (constPatchChangePtr a, constPatchChangePtr b) const {
- return musical_time_less_than (a->time(), b->time());
+ return a->time() < b->time();
}
};
@@ -262,7 +262,7 @@ public:
};
const_iterator begin (
- Time t = 0,
+ Time t = Time(),
bool force_discrete = false,
std::set<Evoral::Parameter> const & f = std::set<Evoral::Parameter> ()) const {
return const_iterator (*this, t, force_discrete, f);
diff --git a/libs/evoral/evoral/types.hpp b/libs/evoral/evoral/types.hpp
index b642fba4c2..d3913f0979 100644
--- a/libs/evoral/evoral/types.hpp
+++ b/libs/evoral/evoral/types.hpp
@@ -19,15 +19,18 @@
#ifndef EVORAL_TYPES_HPP
#define EVORAL_TYPES_HPP
+#include <float.h>
+#include <math.h>
#include <stdint.h>
-#include <list>
-#include <cmath>
-#include <cfloat>
-#include "pbd/debug.h"
+#include <iostream>
+#include <limits>
+#include <list>
#include "evoral/visibility.h"
+#include "pbd/debug.h"
+
namespace Evoral {
/** ID of an event (note or other). This must be operable on by glib
@@ -36,47 +39,174 @@ namespace Evoral {
typedef int32_t event_id_t;
/** Musical time: beats relative to some defined origin */
-typedef double MusicalTime;
+class LIBEVORAL_API MusicalTime {
+public:
+ MusicalTime() : _time(0.0) {}
-const MusicalTime MaxMusicalTime = DBL_MAX;
-const MusicalTime MinMusicalTime = DBL_MIN;
+ /** Create from a real number of beats. */
+ explicit MusicalTime(double time) : _time(time) {}
-static inline bool musical_time_equal (MusicalTime a, MusicalTime b) {
- /* acceptable tolerance is 1 tick. Nice if there was no magic number here
- * -> Timecode::BBT_Time::ticks_per_beat */
- return fabs (a - b) <= (1.0/1920.0);
-}
+ /** Create from an integer number of beats. */
+ static MusicalTime beats(int32_t beats) {
+ return MusicalTime((double)beats);
+ }
-static inline bool musical_time_less_than (MusicalTime a, MusicalTime b) {
- /* acceptable tolerance is 1 tick. Nice if there was no magic number here */
- if (fabs (a - b) <= (1.0/1920.0)) {
- return false; /* effectively identical */
- } else {
- return a < b;
+ /** Create from ticks at the standard PPQN. */
+ static MusicalTime ticks(uint32_t ticks) {
+ return MusicalTime(ticks / _ppqn);
}
-}
-static inline bool musical_time_greater_than (MusicalTime a, MusicalTime b) {
- /* acceptable tolerance is 1 tick. Nice if there was no magic number here */
- if (fabs (a - b) <= (1.0/1920.0)) {
- return false; /* effectively identical */
- } else {
- return a > b;
+ /** Create from ticks at a given rate.
+ *
+ * Note this can also be used to create from frames by setting ppqn to the
+ * number of samples per beat.
+ */
+ static MusicalTime ticks_at_rate(uint64_t ticks, uint32_t ppqn) {
+ return MusicalTime((double)ticks / (double)ppqn);
}
-}
-static inline bool musical_time_greater_or_equal_to (MusicalTime a, MusicalTime b) {
- /* acceptable tolerance is 1 tick. Nice if there was no magic number here */
- if (fabs (a - b) <= (1.0/1920.0)) {
- return true; /* effectively identical, note the "or_equal_to" */
- } else {
- return a >= b;
+ MusicalTime& operator=(const MusicalTime& other) {
+ _time = other._time;
+ return *this;
+ }
+
+ MusicalTime round_up_to_beat() const {
+ return Evoral::MusicalTime(ceil(_time));
+ }
+
+ MusicalTime round_down_to_beat() const {
+ return Evoral::MusicalTime(floor(_time));
+ }
+
+ MusicalTime snap_to(const Evoral::MusicalTime& snap) const {
+ return MusicalTime(ceil(_time / snap._time) * snap._time);
+ }
+
+ inline bool operator==(const MusicalTime& b) const {
+ /* Acceptable tolerance is 1 tick. */
+ return fabs(_time - b._time) <= (1.0/_ppqn);
+ }
+
+ inline bool operator==(double t) const {
+ /* Acceptable tolerance is 1 tick. */
+ return fabs(_time - t) <= (1.0/_ppqn);
+ }
+
+ inline bool operator==(int beats) const {
+ /* Acceptable tolerance is 1 tick. */
+ return fabs(_time - beats) <= (1.0/_ppqn);
+ }
+
+ inline bool operator!=(const MusicalTime& b) const {
+ return !operator==(b);
+ }
+
+ inline bool operator<(const MusicalTime& b) const {
+ /* Acceptable tolerance is 1 tick. */
+ if (fabs(_time - b._time) <= (1.0/_ppqn)) {
+ return false; /* Effectively identical. */
+ } else {
+ return _time < b._time;
+ }
+ }
+
+ inline bool operator<=(const MusicalTime& b) const {
+ return operator==(b) || operator<(b);
+ }
+
+ inline bool operator>(const MusicalTime& b) const {
+ /* Acceptable tolerance is 1 tick. */
+ if (fabs(_time - b._time) <= (1.0/_ppqn)) {
+ return false; /* Effectively identical. */
+ } else {
+ return _time > b._time;
+ }
}
-}
+
+ inline bool operator>=(const MusicalTime& b) const {
+ /* Acceptable tolerance is 1 tick. */
+ if (fabs(_time - b._time) <= (1.0/_ppqn)) {
+ return true; /* Effectively identical. */
+ } else {
+ return _time >= b._time;
+ }
+ }
+
+ MusicalTime operator+(const MusicalTime& b) const {
+ return MusicalTime(_time + b._time);
+ }
+
+ MusicalTime operator-(const MusicalTime& b) const {
+ return MusicalTime(_time - b._time);
+ }
+
+ MusicalTime operator-() const {
+ return MusicalTime(-_time);
+ }
+
+ template<typename Number>
+ MusicalTime operator*(Number factor) const {
+ return MusicalTime(_time * factor);
+ }
+
+ MusicalTime& operator+=(const MusicalTime& b) {
+ _time += b._time;
+ return *this;
+ }
+
+ MusicalTime& operator-=(const MusicalTime& b) {
+ _time -= b._time;
+ return *this;
+ }
+
+ double to_double() const { return _time; }
+ uint64_t to_ticks() const { return lrint(_time * _ppqn); }
+ uint64_t to_ticks(uint32_t ppqn) const { return lrint(_time * ppqn); }
+
+ operator bool() const { return _time != 0; }
+
+ static MusicalTime min() { return MusicalTime(DBL_MIN); }
+ static MusicalTime max() { return MusicalTime(DBL_MAX); }
+ static MusicalTime tick() { return MusicalTime(1.0 / _ppqn); }
+
+private:
+ static const double _ppqn = 1920.0; /* TODO: Make configurable. */
+
+ double _time;
+};
+
+const MusicalTime MaxMusicalTime = Evoral::MusicalTime::max();
+const MusicalTime MinMusicalTime = Evoral::MusicalTime::min();
/** Type of an event (opaque, mapped by application) */
typedef uint32_t EventType;
+/*
+ TIL, several horrible hours later, that sometimes the compiler looks in the
+ namespace of a type (Evoral::MusicalTime in this case) for an operator, and
+ does *NOT* look in the global namespace.
+
+ C++ is proof that hell exists and we are living in it. In any case, move
+ these to the global namespace and PBD::Property's loopy
+ virtual-method-in-a-template will bite you.
+*/
+
+inline std::ostream&
+operator<<(std::ostream& os, const MusicalTime& t)
+{
+ os << t.to_double();
+ return os;
+}
+
+inline std::istream&
+operator>>(std::istream& is, MusicalTime& t)
+{
+ double beats;
+ is >> beats;
+ t = MusicalTime(beats);
+ return is;
+}
+
} // namespace Evoral
namespace PBD {
@@ -84,7 +214,16 @@ namespace PBD {
LIBEVORAL_API extern uint64_t Sequence;
LIBEVORAL_API extern uint64_t Note;
LIBEVORAL_API extern uint64_t ControlList;
+ LIBEVORAL_API extern uint64_t MusicalTime;
}
}
+namespace std {
+ template<>
+ struct numeric_limits<Evoral::MusicalTime> {
+ static Evoral::MusicalTime min() { return Evoral::MusicalTime::min(); }
+ static Evoral::MusicalTime max() { return Evoral::MusicalTime::max(); }
+ };
+}
+
#endif // EVORAL_TYPES_HPP