1 /* This file is part of Evoral.
2 * Copyright (C) 2008-2015 David Robillard <http://drobilla.net>
3 * Copyright (C) 2000-2008 Paul Davis
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
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.
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
19 #ifndef EVORAL_BEATS_HPP
20 #define EVORAL_BEATS_HPP
29 #include "evoral/visibility.h"
33 /** Musical time in beats. */
34 class /*LIBEVORAL_API*/ Beats {
36 LIBEVORAL_API static const double PPQN;
38 Beats() : _time(0.0) {}
40 /** Create from a real number of beats. */
41 explicit Beats(double time) : _time(time) {}
43 /** Create from an integer number of beats. */
44 static Beats beats(int32_t beats) {
45 return Beats((double)beats);
48 /** Create from ticks at the standard PPQN. */
49 static Beats ticks(uint32_t ticks) {
50 return Beats(ticks / PPQN);
53 /** Create from ticks at a given rate.
55 * Note this can also be used to create from frames by setting ppqn to the
56 * number of samples per beat.
58 static Beats ticks_at_rate(uint64_t ticks, uint32_t ppqn) {
59 return Beats((double)ticks / (double)ppqn);
62 Beats& operator=(const Beats& other) {
67 Beats round_up_to_beat() const {
68 return Evoral::Beats(ceil(_time));
71 Beats round_down_to_beat() const {
72 return Evoral::Beats(floor(_time));
75 Beats snap_to(const Evoral::Beats& snap) const {
76 return Beats(ceil(_time / snap._time) * snap._time);
79 inline bool operator==(const Beats& b) const {
80 /* Acceptable tolerance is 1 tick. */
81 return fabs(_time - b._time) <= (1.0 / PPQN);
84 inline bool operator==(double t) const {
85 /* Acceptable tolerance is 1 tick. */
86 return fabs(_time - t) <= (1.0 / PPQN);
89 inline bool operator==(int beats) const {
90 /* Acceptable tolerance is 1 tick. */
91 return fabs(_time - beats) <= (1.0 / PPQN);
94 inline bool operator!=(const Beats& b) const {
95 return !operator==(b);
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. */
103 return _time < b._time;
107 inline bool operator<=(const Beats& b) const {
108 return operator==(b) || operator<(b);
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. */
116 return _time > b._time;
120 inline bool operator>=(const Beats& b) const {
121 return operator==(b) || operator>(b);
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. */
133 inline bool operator<=(double b) const {
134 return operator==(b) || operator<(b);
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. */
146 inline bool operator>=(double b) const {
147 return operator==(b) || operator>(b);
150 Beats operator+(const Beats& b) const {
151 return Beats(_time + b._time);
154 Beats operator-(const Beats& b) const {
155 return Beats(_time - b._time);
158 Beats operator+(double d) const {
159 return Beats(_time + d);
162 Beats operator-(double d) const {
163 return Beats(_time - d);
166 Beats operator-() const {
167 return Beats(-_time);
170 template<typename Number>
171 Beats operator*(Number factor) const {
172 return Beats(_time * factor);
175 Beats& operator+=(const Beats& b) {
180 Beats& operator-=(const Beats& b) {
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); }
189 uint32_t get_beats() const { return floor(_time); }
190 uint32_t get_ticks() const { return (uint32_t)lrint(fmod(_time, 1.0) * PPQN); }
192 bool operator!() const { return _time == 0; }
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); }
202 extern LIBEVORAL_API const Beats MaxBeats;
203 extern LIBEVORAL_API const Beats MinBeats;
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.
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.
216 operator<<(std::ostream& os, const Beats& t)
223 operator>>(std::istream& is, Beats& t)
231 } // namespace Evoral
235 LIBEVORAL_API extern uint64_t Beats;
241 struct numeric_limits<Evoral::Beats> {
242 static Evoral::Beats min() { return Evoral::Beats::min(); }
243 static Evoral::Beats max() { return Evoral::Beats::max(); }
247 #endif // EVORAL_BEATS_HPP