Revert "add operator bool() to Evoral::Beats"
[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
26 #include <iostream>
27 #include <limits>
28
29 #include "evoral/visibility.h"
30
31 namespace Evoral {
32
33 /** Musical time in beats. */
34 class /*LIBEVORAL_API*/ Beats {
35 public:
36         LIBEVORAL_API static const double PPQN;
37
38         Beats() : _time(0.0) {}
39
40         /** Create from a real number of beats. */
41         explicit Beats(double time) : _time(time) {}
42
43         /** Create from an integer number of beats. */
44         static Beats beats(int32_t beats) {
45                 return Beats((double)beats);
46         }
47
48         /** Create from ticks at the standard PPQN. */
49         static Beats ticks(uint32_t ticks) {
50                 return Beats(ticks / PPQN);
51         }
52
53         /** Create from ticks at a given rate.
54          *
55          * Note this can also be used to create from frames by setting ppqn to the
56          * number of samples per beat.
57          */
58         static Beats ticks_at_rate(uint64_t ticks, uint32_t ppqn) {
59                 return Beats((double)ticks / (double)ppqn);
60         }
61
62         Beats& operator=(const Beats& other) {
63                 _time = other._time;
64                 return *this;
65         }
66
67         Beats round_up_to_beat() const {
68                 return Evoral::Beats(ceil(_time));
69         }
70
71         Beats round_down_to_beat() const {
72                 return Evoral::Beats(floor(_time));
73         }
74
75         Beats snap_to(const Evoral::Beats& snap) const {
76                 return Beats(ceil(_time / snap._time) * snap._time);
77         }
78
79         inline bool operator==(const Beats& b) const {
80                 /* Acceptable tolerance is 1 tick. */
81                 return fabs(_time - b._time) <= (1.0 / PPQN);
82         }
83
84         inline bool operator==(double t) const {
85                 /* Acceptable tolerance is 1 tick. */
86                 return fabs(_time - t) <= (1.0 / PPQN);
87         }
88
89         inline bool operator==(int beats) const {
90                 /* Acceptable tolerance is 1 tick. */
91                 return fabs(_time - beats) <= (1.0 / PPQN);
92         }
93
94         inline bool operator!=(const Beats& b) const {
95                 return !operator==(b);
96         }
97
98         inline bool operator<(const Beats& b) const {
99                 /* Acceptable tolerance is 1 tick. */
100                 if (fabs(_time - b._time) <= (1.0 / PPQN)) {
101                         return false;  /* Effectively identical. */
102                 } else {
103                         return _time < b._time;
104                 }
105         }
106
107         inline bool operator<=(const Beats& b) const {
108                 return operator==(b) || operator<(b);
109         }
110
111         inline bool operator>(const Beats& b) const {
112                 /* Acceptable tolerance is 1 tick. */
113                 if (fabs(_time - b._time) <= (1.0 / PPQN)) {
114                         return false;  /* Effectively identical. */
115                 } else {
116                         return _time > b._time;
117                 }
118         }
119
120         inline bool operator>=(const Beats& b) const {
121                 return operator==(b) || operator>(b);
122         }
123
124         inline bool operator<(double b) const {
125                 /* Acceptable tolerance is 1 tick. */
126                 if (fabs(_time - b) <= (1.0 / PPQN)) {
127                         return false;  /* Effectively identical. */
128                 } else {
129                         return _time < b;
130                 }
131         }
132
133         inline bool operator<=(double b) const {
134                 return operator==(b) || operator<(b);
135         }
136
137         inline bool operator>(double b) const {
138                 /* Acceptable tolerance is 1 tick. */
139                 if (fabs(_time - b) <= (1.0 / PPQN)) {
140                         return false;  /* Effectively identical. */
141                 } else {
142                         return _time > b;
143                 }
144         }
145
146         inline bool operator>=(double b) const {
147                 return operator==(b) || operator>(b);
148         }
149
150         Beats operator+(const Beats& b) const {
151                 return Beats(_time + b._time);
152         }
153
154         Beats operator-(const Beats& b) const {
155                 return Beats(_time - b._time);
156         }
157
158         Beats operator+(double d) const {
159                 return Beats(_time + d);
160         }
161
162         Beats operator-(double d) const {
163                 return Beats(_time - d);
164         }
165
166         Beats operator-() const {
167                 return Beats(-_time);
168         }
169
170         template<typename Number>
171         Beats operator*(Number factor) const {
172                 return Beats(_time * factor);
173         }
174
175         Beats& operator+=(const Beats& b) {
176                 _time += b._time;
177                 return *this;
178         }
179
180         Beats& operator-=(const Beats& b) {
181                 _time -= b._time;
182                 return *this;
183         }
184
185         double   to_double()              const { return _time; }
186         uint64_t to_ticks()               const { return lrint(_time * PPQN); }
187         uint64_t to_ticks(uint32_t ppqn)  const { return lrint(_time * ppqn); }
188
189         uint32_t get_beats() const { return floor(_time); }
190         uint32_t get_ticks() const { return (uint32_t)lrint(fmod(_time, 1.0) * PPQN); }
191
192         bool operator!() const { return _time == 0; }
193
194         static Beats min()  { return Beats(DBL_MIN); }
195         static Beats max()  { return Beats(DBL_MAX); }
196         static Beats tick() { return Beats(1.0 / PPQN); }
197
198 private:
199         double _time;
200 };
201
202 extern LIBEVORAL_API const Beats MaxBeats;
203 extern LIBEVORAL_API const Beats MinBeats;
204
205 /*
206   TIL, several horrible hours later, that sometimes the compiler looks in the
207   namespace of a type (Evoral::Beats in this case) for an operator, and
208   does *NOT* look in the global namespace.
209
210   C++ is proof that hell exists and we are living in it.  In any case, move
211   these to the global namespace and PBD::Property's loopy
212   virtual-method-in-a-template will bite you.
213 */
214
215 inline std::ostream&
216 operator<<(std::ostream& os, const Beats& t)
217 {
218         os << t.to_double();
219         return os;
220 }
221
222 inline std::istream&
223 operator>>(std::istream& is, Beats& t)
224 {
225         double beats;
226         is >> beats;
227         t = Beats(beats);
228         return is;
229 }
230
231 } // namespace Evoral
232
233 namespace PBD {
234         namespace DEBUG {
235                 LIBEVORAL_API extern uint64_t Beats;
236         }
237 }
238
239 namespace std {
240         template<>
241         struct numeric_limits<Evoral::Beats> {
242                 static Evoral::Beats min() { return Evoral::Beats::min(); }
243                 static Evoral::Beats max() { return Evoral::Beats::max(); }
244         };
245 }
246
247 #endif // EVORAL_BEATS_HPP