2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #ifndef __ardour_tempo_h__
21 #define __ardour_tempo_h__
27 #include <glibmm/thread.h>
30 #include "pbd/stateful.h"
31 #include "pbd/statefuldestructible.h"
33 #include "evoral/types.hpp"
35 #include "ardour/ardour.h"
40 class FrameposPlusBeatsTest;
50 Tempo (double bpm, double type=4.0) // defaulting to quarter note
51 : _beats_per_minute (bpm), _note_type(type) {}
53 double beats_per_minute () const { return _beats_per_minute;}
54 double note_type () const { return _note_type;}
55 double frames_per_beat (framecnt_t sr) const;
58 double _beats_per_minute;
64 Meter (double dpb, double bt)
65 : _divisions_per_bar (dpb), _note_type (bt) {}
67 double divisions_per_bar () const { return _divisions_per_bar; }
68 double note_divisor() const { return _note_type; }
70 double frames_per_bar (const Tempo&, framecnt_t sr) const;
71 double frames_per_grid (const Tempo&, framecnt_t sr) const;
74 /** The number of divisions in a bar. This is a floating point value because
75 there are musical traditions on our planet that do not limit
76 themselves to integral numbers of beats per bar.
78 double _divisions_per_bar;
80 /** The type of "note" that a division represents. For example, 4.0 is
81 a quarter (crotchet) note, 8.0 is an eighth (quaver) note, etc.
88 MetricSection (const Timecode::BBT_Time& start)
89 : _start (start), _frame (0), _movable (true) {}
90 MetricSection (framepos_t start)
91 : _frame (start), _movable (true) {}
93 virtual ~MetricSection() {}
95 const Timecode::BBT_Time& start() const { return _start; }
96 framepos_t frame() const { return _frame; }
98 void set_movable (bool yn) { _movable = yn; }
99 bool movable() const { return _movable; }
101 virtual void set_frame (framepos_t f) {
105 virtual void set_start (const Timecode::BBT_Time& w) {
109 /* MeterSections are not stateful in the full sense,
110 but we do want them to control their own
111 XML state information.
113 virtual XMLNode& get_state() const = 0;
116 Timecode::BBT_Time _start;
121 class MeterSection : public MetricSection, public Meter {
123 MeterSection (const Timecode::BBT_Time& start, double bpb, double note_type)
124 : MetricSection (start), Meter (bpb, note_type) {}
125 MeterSection (framepos_t start, double bpb, double note_type)
126 : MetricSection (start), Meter (bpb, note_type) {}
127 MeterSection (const XMLNode&);
129 static const std::string xml_state_node_name;
131 XMLNode& get_state() const;
134 class TempoSection : public MetricSection, public Tempo {
136 TempoSection (const Timecode::BBT_Time& start, double qpm, double note_type)
137 : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0) {}
138 TempoSection (framepos_t start, double qpm, double note_type)
139 : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0) {}
140 TempoSection (const XMLNode&);
142 static const std::string xml_state_node_name;
144 XMLNode& get_state() const;
146 void update_bar_offset_from_bbt (const Meter&);
147 void update_bbt_time_from_bar_offset (const Meter&);
148 double bar_offset() const { return _bar_offset; }
151 /* this value provides a fractional offset into the bar in which
152 the tempo section is located in. A value of 0.0 indicates that
153 it occurs on the first beat of the bar, a value of 0.5 indicates
154 that it occurs halfway through the bar and so on.
156 this enables us to keep the tempo change at the same relative
157 position within the bar if/when the meter changes.
162 typedef std::list<MetricSection*> Metrics;
164 /** Helper class that we use to be able to keep track of which
165 meter *AND* tempo are in effect at a given point in time.
169 TempoMetric (const Meter& m, const Tempo& t) : _meter (&m), _tempo (&t), _frame (0) {}
171 void set_tempo (const Tempo& t) { _tempo = &t; }
172 void set_meter (const Meter& m) { _meter = &m; }
173 void set_frame (framepos_t f) { _frame = f; }
174 void set_start (const Timecode::BBT_Time& t) { _start = t; }
176 const Meter& meter() const { return *_meter; }
177 const Tempo& tempo() const { return *_tempo; }
178 framepos_t frame() const { return _frame; }
179 const Timecode::BBT_Time& start() const { return _start; }
185 Timecode::BBT_Time _start;
188 class TempoMap : public PBD::StatefulDestructible
191 TempoMap (framecnt_t frame_rate);
194 /* measure-based stuff */
203 const MeterSection* meter;
204 const TempoSection* tempo;
208 BBTPoint (const MeterSection& m, const TempoSection& t, framepos_t f,
209 uint32_t b, uint32_t e)
210 : frame (f), meter (&m), tempo (&t), bar (b), beat (e) {}
212 Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); }
213 operator Timecode::BBT_Time() const { return bbt(); }
214 operator framepos_t() const { return frame; }
215 bool is_bar() const { return beat == 1; }
218 typedef std::vector<BBTPoint> BBTPointList;
220 template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
221 Glib::RWLock::ReaderLock lm (lock);
222 (obj.*method)(metrics);
225 void get_grid (BBTPointList::const_iterator&, BBTPointList::const_iterator&,
226 framepos_t start, framepos_t end);
228 /* TEMPO- AND METER-SENSITIVE FUNCTIONS
230 bbt_time(), bbt_time_rt(), frame_time() and bbt_duration_at()
231 are all sensitive to tempo and meter, and will give answers
232 that align with the grid formed by tempo and meter sections.
234 They SHOULD NOT be used to determine the position of events
235 whose location is canonically defined in beats.
238 void bbt_time (framepos_t when, Timecode::BBT_Time&);
239 /* realtime safe variant of ::bbt_time(), will throw
240 std::logic_error if the map is not large enough
241 to provide an answer.
243 void bbt_time_rt (framepos_t when, Timecode::BBT_Time&);
244 framepos_t frame_time (const Timecode::BBT_Time&);
245 framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir);
247 /* TEMPO-SENSITIVE FUNCTIONS
249 These next 4 functions will all take tempo in account and should be
250 used to determine position (and in the last case, distance in beats)
251 when tempo matters but meter does not.
253 They SHOULD be used to determine the position of events
254 whose location is canonically defined in beats.
257 framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b) const;
258 framepos_t framepos_plus_beats (framepos_t, Evoral::MusicalTime) const;
259 framepos_t framepos_minus_beats (framepos_t, Evoral::MusicalTime) const;
260 Evoral::MusicalTime framewalk_to_beats (framepos_t pos, framecnt_t distance) const;
262 static const Tempo& default_tempo() { return _default_tempo; }
263 static const Meter& default_meter() { return _default_meter; }
265 const Tempo& tempo_at (framepos_t) const;
266 const Meter& meter_at (framepos_t) const;
268 const TempoSection& tempo_section_at (framepos_t) const;
270 void add_tempo(const Tempo&, Timecode::BBT_Time where);
271 void add_meter(const Meter&, Timecode::BBT_Time where);
273 void remove_tempo(const TempoSection&, bool send_signal);
274 void remove_meter(const MeterSection&, bool send_signal);
276 void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where);
277 void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where);
279 framepos_t round_to_bar (framepos_t frame, int dir);
280 framepos_t round_to_beat (framepos_t frame, int dir);
281 framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, int dir);
282 framepos_t round_to_tick (framepos_t frame, int dir);
284 void set_length (framepos_t frames);
286 XMLNode& get_state (void);
287 int set_state (const XMLNode&, int version);
289 void dump (std::ostream&) const;
292 TempoMetric metric_at (Timecode::BBT_Time bbt) const;
293 TempoMetric metric_at (framepos_t) const;
296 void change_existing_tempo_at (framepos_t, double bpm, double note_type);
297 void change_initial_tempo (double bpm, double note_type);
299 void insert_time (framepos_t, framecnt_t);
301 int n_tempos () const;
302 int n_meters () const;
304 framecnt_t frame_rate () const { return _frame_rate; }
308 friend class ::BBTTest;
309 friend class ::FrameposPlusBeatsTest;
310 friend class ::TempoTest;
312 static Tempo _default_tempo;
313 static Meter _default_meter;
316 framecnt_t _frame_rate;
317 mutable Glib::RWLock lock;
320 void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1);
321 void extend_map (framepos_t end);
322 void require_map_to (framepos_t pos);
323 void require_map_to (const Timecode::BBT_Time&);
324 void _extend_map (TempoSection* tempo, MeterSection* meter,
325 Metrics::iterator next_metric,
326 Timecode::BBT_Time current, framepos_t current_frame, framepos_t end);
328 BBTPointList::const_iterator bbt_before_or_at (framepos_t);
329 BBTPointList::const_iterator bbt_before_or_at (const Timecode::BBT_Time&);
330 BBTPointList::const_iterator bbt_after_or_at (framepos_t);
332 framepos_t round_to_type (framepos_t fr, int dir, BBTPointType);
333 void bbt_time (framepos_t, Timecode::BBT_Time&, const BBTPointList::const_iterator&);
334 framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir);
336 const MeterSection& first_meter() const;
337 const TempoSection& first_tempo() const;
339 void do_insert (MetricSection* section);
342 }; /* namespace ARDOUR */
344 std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&);
345 std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&);
346 std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&);
348 #endif /* __ardour_tempo_h__ */