remove Evoral types.cpp since it is no longer required
[ardour.git] / libs / evoral / evoral / Beats.hpp
1 /* This file is part of Evoral.
2  * Copyright (C) 2008-2015 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_BEATS_HPP
20 #define EVORAL_BEATS_HPP
21
22 #include <float.h>
23 #include <math.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26
27 #include <iostream>
28 #include <limits>
29
30 #include "evoral/visibility.h"
31
32 namespace Evoral {
33
34 /** Musical time in beats. */
35 class /*LIBEVORAL_API*/ Beats {
36 public:
37         LIBEVORAL_API static const int32_t PPQN = 1920;
38
39         Beats() : _beats(0), _ticks(0) {}
40
41         /** Normalize so ticks is within PPQN. */
42         void normalize() {
43                 // First, fix negative ticks with positive beats
44                 if (_beats >= 0) {
45                         while (_ticks < 0) {
46                                 --_beats;
47                                 _ticks += PPQN;
48                         }
49                 }
50
51                 // Work with positive beats and ticks to normalize
52                 const int32_t sign  = _beats < 0 ? -1 : 1;
53                 int32_t       beats = abs(_beats);
54                 int32_t       ticks = abs(_ticks);
55
56                 // Fix ticks greater than 1 beat
57                 while (ticks >= PPQN) {
58                         ++beats;
59                         ticks -= PPQN;
60                 }
61
62                 // Set fields with appropriate sign
63                 _beats = sign * beats;
64                 _ticks = sign * ticks;
65         }
66
67         /** Create from a precise BT time. */
68         explicit Beats(int32_t b, int32_t t) : _beats(b), _ticks(t) {
69                 normalize();
70         }
71
72         /** Create from a real number of beats. */
73         explicit Beats(double time) {
74                 double       whole;
75                 const double frac = modf(time, &whole);
76
77                 _beats = whole;
78                 _ticks = frac * PPQN;
79         }
80
81         /** Create from an integer number of beats. */
82         static Beats beats(int32_t beats) {
83                 return Beats(beats, 0);
84         }
85
86         /** Create from ticks at the standard PPQN. */
87         static Beats ticks(int32_t ticks) {
88                 return Beats(0, ticks);
89         }
90
91         /** Create from ticks at a given rate.
92          *
93          * Note this can also be used to create from frames by setting ppqn to the
94          * number of samples per beat.  Note the resulting Beats will, like all
95          * others, have the default PPQN, so this is a potentially lossy
96          * conversion.
97          */
98         static Beats ticks_at_rate(int64_t ticks, uint32_t ppqn) {
99                 return Beats(ticks / ppqn, (ticks % ppqn) * PPQN / ppqn);
100         }
101
102         Beats& operator=(double time) {
103                 double       whole;
104                 const double frac = modf(time, &whole);
105
106                 _beats = whole;
107                 _ticks = frac * PPQN;
108                 return *this;
109         }
110
111         Beats& operator=(const Beats& other) {
112                 _beats = other._beats;
113                 _ticks = other._ticks;
114                 return *this;
115         }
116
117         Beats round_to_beat() const {
118                 return (_ticks >= (PPQN/2)) ? Beats (_beats + 1, 0) : Beats (_beats, 0);
119         }
120
121         Beats round_up_to_beat() const {
122                 return (_ticks == 0) ? *this : Beats(_beats + 1, 0);
123         }
124
125         Beats round_down_to_beat() const {
126                 return Beats(_beats, 0);
127         }
128
129         Beats snap_to(const Evoral::Beats& snap) const {
130                 const double snap_time = snap.to_double();
131                 return Beats(ceil(to_double() / snap_time) * snap_time);
132         }
133
134         inline bool operator==(const Beats& b) const {
135                 return _beats == b._beats && _ticks == b._ticks;
136         }
137
138         inline bool operator==(double t) const {
139                 /* Acceptable tolerance is 1 tick. */
140                 return fabs(to_double() - t) <= (1.0 / PPQN);
141         }
142
143         inline bool operator==(int beats) const {
144                 return _beats == beats;
145         }
146
147         inline bool operator!=(const Beats& b) const {
148                 return !operator==(b);
149         }
150
151         inline bool operator<(const Beats& b) const {
152                 return _beats < b._beats || (_beats == b._beats && _ticks < b._ticks);
153         }
154
155         inline bool operator<=(const Beats& b) const {
156                 return _beats < b._beats || (_beats == b._beats && _ticks <= b._ticks);
157         }
158
159         inline bool operator>(const Beats& b) const {
160                 return _beats > b._beats || (_beats == b._beats && _ticks > b._ticks);
161         }
162
163         inline bool operator>=(const Beats& b) const {
164                 return _beats > b._beats || (_beats == b._beats && _ticks >= b._ticks);
165         }
166
167         inline bool operator<(double b) const {
168                 /* Acceptable tolerance is 1 tick. */
169                 const double time = to_double();
170                 if (fabs(time - b) <= (1.0 / PPQN)) {
171                         return false;  /* Effectively identical. */
172                 } else {
173                         return time < b;
174                 }
175         }
176
177         inline bool operator<=(double b) const {
178                 return operator==(b) || operator<(b);
179         }
180
181         inline bool operator>(double b) const {
182                 /* Acceptable tolerance is 1 tick. */
183                 const double time = to_double();
184                 if (fabs(time - b) <= (1.0 / PPQN)) {
185                         return false;  /* Effectively identical. */
186                 } else {
187                         return time > b;
188                 }
189         }
190
191         inline bool operator>=(double b) const {
192                 return operator==(b) || operator>(b);
193         }
194
195         Beats operator+(const Beats& b) const {
196                 return Beats(_beats + b._beats, _ticks + b._ticks);
197         }
198
199         Beats operator-(const Beats& b) const {
200                 return Beats(_beats - b._beats, _ticks - b._ticks);
201         }
202
203         Beats operator+(double d) const {
204                 return Beats(to_double() + d);
205         }
206
207         Beats operator-(double d) const {
208                 return Beats(to_double() - d);
209         }
210
211         Beats operator+(int b) const {
212                 return Beats (_beats + b, _ticks);
213         }
214
215         Beats operator-(int b) const {
216                 return Beats (_beats - b, _ticks);
217         }
218
219         Beats& operator+=(int b) {
220                 _beats += b;
221                 return *this;
222         }
223
224         Beats& operator-=(int b) {
225                 _beats -= b;
226                 return *this;
227         }
228
229         Beats operator-() const {
230                 return Beats(-_beats, -_ticks);
231         }
232
233         template<typename Number>
234         Beats operator*(Number factor) const {
235                 return Beats(_beats * factor, _ticks * factor);
236         }
237
238         template<typename Number>
239         Beats operator/(Number factor) const {
240                 return ticks ((_beats * PPQN + _ticks) / factor);
241         }
242
243         Beats& operator+=(const Beats& b) {
244                 _beats += b._beats;
245                 _ticks += b._ticks;
246                 normalize();
247                 return *this;
248         }
249
250         Beats& operator-=(const Beats& b) {
251                 _beats -= b._beats;
252                 _ticks -= b._ticks;
253                 normalize();
254                 return *this;
255         }
256
257         double  to_double()              const { return (double)_beats + (_ticks / (double)PPQN); }
258         int64_t to_ticks()               const { return (int64_t)_beats * PPQN + _ticks; }
259         int64_t to_ticks(uint32_t ppqn)  const { return (int64_t)_beats * ppqn + (_ticks * ppqn / PPQN); }
260
261         int32_t get_beats() const { return _beats; }
262         int32_t get_ticks() const { return _ticks; }
263
264         bool operator!() const { return _beats == 0 && _ticks == 0; }
265
266         static Beats tick() { return Beats(0, 1); }
267
268 private:
269         int32_t _beats;
270         int32_t _ticks;
271 };
272
273 /*
274   TIL, several horrible hours later, that sometimes the compiler looks in the
275   namespace of a type (Evoral::Beats in this case) for an operator, and
276   does *NOT* look in the global namespace.
277
278   C++ is proof that hell exists and we are living in it.  In any case, move
279   these to the global namespace and PBD::Property's loopy
280   virtual-method-in-a-template will bite you.
281 */
282
283 inline std::ostream&
284 operator<<(std::ostream& os, const Beats& t)
285 {
286         os << t.get_beats() << '.' << t.get_ticks();
287         return os;
288 }
289
290 inline std::istream&
291 operator>>(std::istream& is, Beats& t)
292 {
293         double beats;
294         is >> beats;
295         t = Beats(beats);
296         return is;
297 }
298
299 } // namespace Evoral
300
301 namespace PBD {
302         namespace DEBUG {
303                 LIBEVORAL_API extern uint64_t Beats;
304         }
305 }
306
307 namespace std {
308         template<>
309         struct numeric_limits<Evoral::Beats> {
310                 static Evoral::Beats lowest() {
311                         return Evoral::Beats(std::numeric_limits<int32_t>::min(),
312                                              std::numeric_limits<int32_t>::min());
313                 }
314
315                 /* We don't define min() since this has different behaviour for integral and floating point types,
316                    but Beats is used as both.  Better to avoid providing a min at all
317                    than a confusing one. */
318
319                 static Evoral::Beats max() {
320                         return Evoral::Beats(std::numeric_limits<int32_t>::max(),
321                                              std::numeric_limits<int32_t>::max());
322                 }
323         };
324 }
325
326 #endif // EVORAL_BEATS_HPP