14ba36acdf2069cb712fa2ece75c6a75b241cbdb
[ardour.git] / libs / evoral / evoral / types.hpp
1 /* This file is part of Evoral.
2  * Copyright (C) 2008 David Robillard <http://drobilla.net>
3  * Copyright (C) 2000-2008 Paul Davis
4  *
5  * Evoral is free software; you can redistribute it and/or modify it under the
6  * terms of the GNU General Public License as published by the Free Software
7  * Foundation; either version 2 of the License, or (at your option) any later
8  * version.
9  *
10  * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #ifndef EVORAL_TYPES_HPP
20 #define EVORAL_TYPES_HPP
21
22 #include <float.h>
23 #include <math.h>
24 #include <stdint.h>
25
26 #include <iostream>
27 #include <limits>
28 #include <list>
29
30 #include "evoral/visibility.h"
31
32 #include "pbd/debug.h"
33
34 namespace Evoral {
35
36 /** ID of an event (note or other). This must be operable on by glib
37     atomic ops
38 */
39 typedef int32_t event_id_t;
40
41 /** Musical time: beats relative to some defined origin */
42 class /*LIBEVORAL_API*/ MusicalTime {
43 public:
44         LIBEVORAL_API static const double PPQN;
45
46         MusicalTime() : _time(0.0) {}
47
48         /** Create from a real number of beats. */
49         explicit MusicalTime(double time) : _time(time) {}
50
51         /** Create from an integer number of beats. */
52         static MusicalTime beats(int32_t beats) {
53                 return MusicalTime((double)beats);
54         }
55
56         /** Create from ticks at the standard PPQN. */
57         static MusicalTime ticks(uint32_t ticks) {
58                 return MusicalTime(ticks / PPQN);
59         }
60
61         /** Create from ticks at a given rate.
62          *
63          * Note this can also be used to create from frames by setting ppqn to the
64          * number of samples per beat.
65          */
66         static MusicalTime ticks_at_rate(uint64_t ticks, uint32_t ppqn) {
67                 return MusicalTime((double)ticks / (double)ppqn);
68         }
69
70         MusicalTime& operator=(const MusicalTime& other) {
71                 _time = other._time;
72                 return *this;
73         }
74
75         MusicalTime round_up_to_beat() const {
76                 return Evoral::MusicalTime(ceil(_time));
77         }
78
79         MusicalTime round_down_to_beat() const {
80                 return Evoral::MusicalTime(floor(_time));
81         }
82
83         MusicalTime snap_to(const Evoral::MusicalTime& snap) const {
84                 return MusicalTime(ceil(_time / snap._time) * snap._time);
85         }
86
87         inline bool operator==(const MusicalTime& b) const {
88                 /* Acceptable tolerance is 1 tick. */
89                 return fabs(_time - b._time) <= (1.0 / PPQN);
90         }
91
92         inline bool operator==(double t) const {
93                 /* Acceptable tolerance is 1 tick. */
94                 return fabs(_time - t) <= (1.0 / PPQN);
95         }
96
97         inline bool operator==(int beats) const {
98                 /* Acceptable tolerance is 1 tick. */
99                 return fabs(_time - beats) <= (1.0 / PPQN);
100         }
101
102         inline bool operator!=(const MusicalTime& b) const {
103                 return !operator==(b);
104         }
105
106         inline bool operator<(const MusicalTime& b) const {
107                 /* Acceptable tolerance is 1 tick. */
108                 if (fabs(_time - b._time) <= (1.0 / PPQN)) {
109                         return false;  /* Effectively identical. */
110                 } else {
111                         return _time < b._time;
112                 }
113         }
114
115         inline bool operator<=(const MusicalTime& b) const {
116                 return operator==(b) || operator<(b);
117         }
118
119         inline bool operator>(const MusicalTime& b) const {
120                 /* Acceptable tolerance is 1 tick. */
121                 if (fabs(_time - b._time) <= (1.0 / PPQN)) {
122                         return false;  /* Effectively identical. */
123                 } else {
124                         return _time > b._time;
125                 }
126         }
127
128         inline bool operator>=(const MusicalTime& b) const {
129                 return operator==(b) || operator>(b);
130         }
131
132         inline bool operator<(double b) const {
133                 /* Acceptable tolerance is 1 tick. */
134                 if (fabs(_time - b) <= (1.0 / PPQN)) {
135                         return false;  /* Effectively identical. */
136                 } else {
137                         return _time < b;
138                 }
139         }
140
141         inline bool operator<=(double b) const {
142                 return operator==(b) || operator<(b);
143         }
144
145         inline bool operator>(double b) const {
146                 /* Acceptable tolerance is 1 tick. */
147                 if (fabs(_time - b) <= (1.0 / PPQN)) {
148                         return false;  /* Effectively identical. */
149                 } else {
150                         return _time > b;
151                 }
152         }
153
154         inline bool operator>=(double b) const {
155                 return operator==(b) || operator>(b);
156         }
157
158         MusicalTime operator+(const MusicalTime& b) const {
159                 return MusicalTime(_time + b._time);
160         }
161
162         MusicalTime operator-(const MusicalTime& b) const {
163                 return MusicalTime(_time - b._time);
164         }
165
166         MusicalTime operator+(double d) const {
167                 return MusicalTime(_time + d);
168         }
169
170         MusicalTime operator-(double d) const {
171                 return MusicalTime(_time - d);
172         }
173
174         MusicalTime operator-() const {
175                 return MusicalTime(-_time);
176         }
177
178         template<typename Number>
179         MusicalTime operator*(Number factor) const {
180                 return MusicalTime(_time * factor);
181         }
182
183         MusicalTime& operator+=(const MusicalTime& b) {
184                 _time += b._time;
185                 return *this;
186         }
187
188         MusicalTime& operator-=(const MusicalTime& b) {
189                 _time -= b._time;
190                 return *this;
191         }
192
193         double   to_double()              const { return _time; }
194         uint64_t to_ticks()               const { return lrint(_time * PPQN); }
195         uint64_t to_ticks(uint32_t ppqn)  const { return lrint(_time * ppqn); }
196
197         uint32_t get_beats() const { return floor(_time); }
198         uint32_t get_ticks() const { return (uint32_t)lrint(fmod(_time, 1.0) * PPQN); }
199
200         bool operator!() const { return _time == 0; }
201
202         static MusicalTime min()  { return MusicalTime(DBL_MIN); }
203         static MusicalTime max()  { return MusicalTime(DBL_MAX); }
204         static MusicalTime tick() { return MusicalTime(1.0 / PPQN); }
205
206 private:
207         double _time;
208 };
209
210 extern LIBEVORAL_API const MusicalTime MaxMusicalTime;
211 extern LIBEVORAL_API const MusicalTime MinMusicalTime;
212
213 /** Type of an event (opaque, mapped by application) */
214 typedef uint32_t EventType;
215
216 /*
217   TIL, several horrible hours later, that sometimes the compiler looks in the
218   namespace of a type (Evoral::MusicalTime in this case) for an operator, and
219   does *NOT* look in the global namespace.
220
221   C++ is proof that hell exists and we are living in it.  In any case, move
222   these to the global namespace and PBD::Property's loopy
223   virtual-method-in-a-template will bite you.
224 */
225
226 inline std::ostream&
227 operator<<(std::ostream& os, const MusicalTime& t)
228 {
229         os << t.to_double();
230         return os;
231 }
232
233 inline std::istream&
234 operator>>(std::istream& is, MusicalTime& t)
235 {
236         double beats;
237         is >> beats;
238         t = MusicalTime(beats);
239         return is;
240 }
241
242 } // namespace Evoral
243
244 namespace PBD {
245         namespace DEBUG {
246                 LIBEVORAL_API extern uint64_t Sequence;
247                 LIBEVORAL_API extern uint64_t Note;
248                 LIBEVORAL_API extern uint64_t ControlList;
249                 LIBEVORAL_API extern uint64_t MusicalTime;
250         }
251 }
252
253 namespace std {
254         template<>
255         struct numeric_limits<Evoral::MusicalTime> {
256                 static Evoral::MusicalTime min() { return Evoral::MusicalTime::min(); }
257                 static Evoral::MusicalTime max() { return Evoral::MusicalTime::max(); }
258         };
259 }
260
261 #endif // EVORAL_TYPES_HPP