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/threads.h>
30 #include "pbd/stateful.h"
31 #include "pbd/statefuldestructible.h"
33 #include "evoral/types.hpp"
35 #include "ardour/ardour.h"
38 class FrameposPlusBeatsTest;
47 /** Tempo, the speed at which musical time progresses (BPM). */
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 {
56 return (60.0 * sr) / _beats_per_minute;
60 double _beats_per_minute;
64 /** Meter, or time signature (beats per bar, and which note type is a beat). */
67 Meter (double dpb, double bt)
68 : _divisions_per_bar (dpb), _note_type (bt) {}
70 double divisions_per_bar () const { return _divisions_per_bar; }
71 double note_divisor() const { return _note_type; }
73 double frames_per_bar (const Tempo&, framecnt_t sr) const;
74 double frames_per_grid (const Tempo&, framecnt_t sr) const;
77 /** The number of divisions in a bar. This is a floating point value because
78 there are musical traditions on our planet that do not limit
79 themselves to integral numbers of beats per bar.
81 double _divisions_per_bar;
83 /** The type of "note" that a division represents. For example, 4.0 is
84 a quarter (crotchet) note, 8.0 is an eighth (quaver) note, etc.
89 /** A section of timeline with a certain Tempo or Meter. */
92 MetricSection (const Timecode::BBT_Time& start)
93 : _start (start), _frame (0), _movable (true) {}
94 MetricSection (framepos_t start)
95 : _frame (start), _movable (true) {}
97 virtual ~MetricSection() {}
99 const Timecode::BBT_Time& start() const { return _start; }
100 framepos_t frame() const { return _frame; }
102 void set_movable (bool yn) { _movable = yn; }
103 bool movable() const { return _movable; }
105 virtual void set_frame (framepos_t f) {
109 virtual void set_start (const Timecode::BBT_Time& w) {
113 /* MeterSections are not stateful in the full sense,
114 but we do want them to control their own
115 XML state information.
117 virtual XMLNode& get_state() const = 0;
120 Timecode::BBT_Time _start;
125 /** A section of timeline with a certain Meter. */
126 class MeterSection : public MetricSection, public Meter {
128 MeterSection (const Timecode::BBT_Time& start, double bpb, double note_type)
129 : MetricSection (start), Meter (bpb, note_type) {}
130 MeterSection (framepos_t start, double bpb, double note_type)
131 : MetricSection (start), Meter (bpb, note_type) {}
132 MeterSection (const XMLNode&);
134 static const std::string xml_state_node_name;
136 XMLNode& get_state() const;
139 /** A section of timeline with a certain Tempo. */
140 class TempoSection : public MetricSection, public Tempo {
142 TempoSection (const Timecode::BBT_Time& start, double qpm, double note_type)
143 : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0) {}
144 TempoSection (framepos_t start, double qpm, double note_type)
145 : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0) {}
146 TempoSection (const XMLNode&);
148 static const std::string xml_state_node_name;
150 XMLNode& get_state() const;
152 void update_bar_offset_from_bbt (const Meter&);
153 void update_bbt_time_from_bar_offset (const Meter&);
154 double bar_offset() const { return _bar_offset; }
157 /* this value provides a fractional offset into the bar in which
158 the tempo section is located in. A value of 0.0 indicates that
159 it occurs on the first beat of the bar, a value of 0.5 indicates
160 that it occurs halfway through the bar and so on.
162 this enables us to keep the tempo change at the same relative
163 position within the bar if/when the meter changes.
168 typedef std::list<MetricSection*> Metrics;
170 /** Helper class to keep track of the Meter *AND* Tempo in effect
171 at a given point in time.
175 TempoMetric (const Meter& m, const Tempo& t)
176 : _meter (&m), _tempo (&t), _frame (0) {}
178 void set_tempo (const Tempo& t) { _tempo = &t; }
179 void set_meter (const Meter& m) { _meter = &m; }
180 void set_frame (framepos_t f) { _frame = f; }
181 void set_start (const Timecode::BBT_Time& t) { _start = t; }
183 void set_metric (const MetricSection* section) {
184 const MeterSection* meter;
185 const TempoSection* tempo;
186 if ((meter = dynamic_cast<const MeterSection*>(section))) {
188 } else if ((tempo = dynamic_cast<const TempoSection*>(section))) {
192 set_frame(section->frame());
193 set_start(section->start());
196 const Meter& meter() const { return *_meter; }
197 const Tempo& tempo() const { return *_tempo; }
198 framepos_t frame() const { return _frame; }
199 const Timecode::BBT_Time& start() const { return _start; }
205 Timecode::BBT_Time _start;
208 class TempoMap : public PBD::StatefulDestructible
211 TempoMap (framecnt_t frame_rate);
214 /* measure-based stuff */
223 const MeterSection* meter;
224 const TempoSection* tempo;
228 BBTPoint (const MeterSection& m, const TempoSection& t, framepos_t f,
229 uint32_t b, uint32_t e)
230 : frame (f), meter (&m), tempo (&t), bar (b), beat (e) {}
232 Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); }
233 operator Timecode::BBT_Time() const { return bbt(); }
234 operator framepos_t() const { return frame; }
235 bool is_bar() const { return beat == 1; }
238 typedef std::vector<BBTPoint> BBTPointList;
240 template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
241 Glib::Threads::RWLock::ReaderLock lm (lock);
242 (obj.*method)(metrics);
245 void get_grid (BBTPointList::const_iterator&, BBTPointList::const_iterator&,
246 framepos_t start, framepos_t end);
248 /* TEMPO- AND METER-SENSITIVE FUNCTIONS
250 bbt_time(), bbt_time_rt(), frame_time() and bbt_duration_at()
251 are all sensitive to tempo and meter, and will give answers
252 that align with the grid formed by tempo and meter sections.
254 They SHOULD NOT be used to determine the position of events
255 whose location is canonically defined in beats.
258 void bbt_time (framepos_t when, Timecode::BBT_Time&);
260 /* realtime safe variant of ::bbt_time(), will throw
261 std::logic_error if the map is not large enough
262 to provide an answer.
264 void bbt_time_rt (framepos_t when, Timecode::BBT_Time&);
265 framepos_t frame_time (const Timecode::BBT_Time&);
266 framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir);
268 /* TEMPO-SENSITIVE FUNCTIONS
270 These next 4 functions will all take tempo in account and should be
271 used to determine position (and in the last case, distance in beats)
272 when tempo matters but meter does not.
274 They SHOULD be used to determine the position of events
275 whose location is canonically defined in beats.
278 framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b) const;
279 framepos_t framepos_plus_beats (framepos_t, Evoral::MusicalTime) const;
280 framepos_t framepos_minus_beats (framepos_t, Evoral::MusicalTime) const;
281 Evoral::MusicalTime framewalk_to_beats (framepos_t pos, framecnt_t distance) const;
283 static const Tempo& default_tempo() { return _default_tempo; }
284 static const Meter& default_meter() { return _default_meter; }
286 const Tempo& tempo_at (framepos_t) const;
287 const Meter& meter_at (framepos_t) const;
289 const TempoSection& tempo_section_at (framepos_t) const;
291 void add_tempo (const Tempo&, Timecode::BBT_Time where);
292 void add_meter (const Meter&, Timecode::BBT_Time where);
294 void remove_tempo (const TempoSection&, bool send_signal);
295 void remove_meter (const MeterSection&, bool send_signal);
297 void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where);
298 void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where);
300 framepos_t round_to_bar (framepos_t frame, int dir);
301 framepos_t round_to_beat (framepos_t frame, int dir);
302 framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, int dir);
303 framepos_t round_to_tick (framepos_t frame, int dir);
305 void set_length (framepos_t frames);
307 XMLNode& get_state (void);
308 int set_state (const XMLNode&, int version);
310 void dump (std::ostream&) const;
313 TempoMetric metric_at (Timecode::BBT_Time bbt) const;
315 /** Return the TempoMetric at frame @p t, and point @p last to the latest
316 * metric change <= t, if it is non-NULL.
318 TempoMetric metric_at (framepos_t, Metrics::const_iterator* last=NULL) const;
320 Metrics::const_iterator metrics_end() { return metrics.end(); }
322 void change_existing_tempo_at (framepos_t, double bpm, double note_type);
323 void change_initial_tempo (double bpm, double note_type);
325 void insert_time (framepos_t, framecnt_t);
327 int n_tempos () const;
328 int n_meters () const;
330 framecnt_t frame_rate () const { return _frame_rate; }
334 friend class ::BBTTest;
335 friend class ::FrameposPlusBeatsTest;
336 friend class ::TempoTest;
338 static Tempo _default_tempo;
339 static Meter _default_meter;
342 framecnt_t _frame_rate;
343 mutable Glib::Threads::RWLock lock;
346 void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1);
347 void extend_map (framepos_t end);
348 void require_map_to (framepos_t pos);
349 void require_map_to (const Timecode::BBT_Time&);
350 void _extend_map (TempoSection* tempo, MeterSection* meter,
351 Metrics::iterator next_metric,
352 Timecode::BBT_Time current, framepos_t current_frame, framepos_t end);
354 BBTPointList::const_iterator bbt_before_or_at (framepos_t);
355 BBTPointList::const_iterator bbt_before_or_at (const Timecode::BBT_Time&);
356 BBTPointList::const_iterator bbt_after_or_at (framepos_t);
358 framepos_t round_to_type (framepos_t fr, int dir, BBTPointType);
359 void bbt_time (framepos_t, Timecode::BBT_Time&, const BBTPointList::const_iterator&);
360 framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir);
362 const MeterSection& first_meter() const;
363 const TempoSection& first_tempo() const;
365 void do_insert (MetricSection* section);
368 }; /* namespace ARDOUR */
370 std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&);
371 std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&);
372 std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&);
374 #endif /* __ardour_tempo_h__ */