Tidy up tempo.h and add some documentation.
[ardour.git] / libs / ardour / ardour / tempo.h
1 /*
2     Copyright (C) 2000 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #ifndef __ardour_tempo_h__
21 #define __ardour_tempo_h__
22
23 #include <list>
24 #include <string>
25 #include <vector>
26 #include <cmath>
27 #include <glibmm/threads.h>
28
29 #include "pbd/undo.h"
30 #include "pbd/stateful.h"
31 #include "pbd/statefuldestructible.h"
32
33 #include "evoral/types.hpp"
34
35 #include "ardour/ardour.h"
36
37 class BBTTest;
38 class FrameposPlusBeatsTest;
39 class TempoTest;
40 class XMLNode;
41
42 namespace ARDOUR {
43
44 class Meter;
45 class TempoMap;
46
47 /** Tempo, the speed at which musical time progresses (BPM). */
48 class Tempo {
49   public:
50         Tempo (double bpm, double type=4.0) // defaulting to quarter note
51                 : _beats_per_minute (bpm), _note_type(type) {}
52
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;
57         }
58
59   protected:
60         double _beats_per_minute;
61         double _note_type;
62 };
63
64 /** Meter, or time signature (beats per bar, and which note type is a beat). */
65 class Meter {
66   public:
67         Meter (double dpb, double bt)
68                 : _divisions_per_bar (dpb), _note_type (bt) {}
69
70         double divisions_per_bar () const { return _divisions_per_bar; }
71         double note_divisor() const { return _note_type; }
72
73         double frames_per_bar (const Tempo&, framecnt_t sr) const;
74         double frames_per_grid (const Tempo&, framecnt_t sr) const;
75
76   protected:
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.
80         */
81         double _divisions_per_bar;
82
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.
85         */
86         double _note_type;
87 };
88
89 /** A section of timeline with a certain Tempo or Meter. */
90 class MetricSection {
91   public:
92         MetricSection (const Timecode::BBT_Time& start)
93                 : _start (start), _frame (0), _movable (true) {}
94         MetricSection (framepos_t start)
95                 : _frame (start), _movable (true) {}
96
97         virtual ~MetricSection() {}
98
99         const Timecode::BBT_Time& start() const { return _start; }
100         framepos_t                frame() const { return _frame; }
101
102         void set_movable (bool yn) { _movable = yn; }
103         bool movable() const { return _movable; }
104
105         virtual void set_frame (framepos_t f) {
106                 _frame = f;
107         }
108
109         virtual void set_start (const Timecode::BBT_Time& w) {
110                 _start = w;
111         }
112
113         /* MeterSections are not stateful in the full sense,
114            but we do want them to control their own
115            XML state information.
116         */
117         virtual XMLNode& get_state() const = 0;
118
119   private:
120         Timecode::BBT_Time _start;
121         framepos_t         _frame;
122         bool               _movable;
123 };
124
125 /** A section of timeline with a certain Meter. */
126 class MeterSection : public MetricSection, public Meter {
127   public:
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&);
133
134         static const std::string xml_state_node_name;
135
136         XMLNode& get_state() const;
137 };
138
139 /** A section of timeline with a certain Tempo. */
140 class TempoSection : public MetricSection, public Tempo {
141   public:
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&);
147
148         static const std::string xml_state_node_name;
149
150         XMLNode& get_state() const;
151
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; }
155
156   private:
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.
161            
162            this enables us to keep the tempo change at the same relative
163            position within the bar if/when the meter changes.
164         */
165         double _bar_offset;
166 };
167
168 typedef std::list<MetricSection*> Metrics;
169
170 /** Helper class to keep track of the Meter *AND* Tempo in effect
171     at a given point in time.
172 */
173 class TempoMetric {
174   public:
175         TempoMetric (const Meter& m, const Tempo& t)
176                 : _meter (&m), _tempo (&t), _frame (0) {}
177
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; }
182
183         const Meter&              meter() const { return *_meter; }
184         const Tempo&              tempo() const { return *_tempo; }
185         framepos_t                frame() const { return _frame; }
186         const Timecode::BBT_Time& start() const { return _start; }
187
188   private:
189         const Meter*       _meter;
190         const Tempo*       _tempo;
191         framepos_t         _frame;
192         Timecode::BBT_Time _start;
193 };
194
195 class TempoMap : public PBD::StatefulDestructible
196 {
197   public:
198         TempoMap (framecnt_t frame_rate);
199         ~TempoMap();
200
201         /* measure-based stuff */
202
203         enum BBTPointType {
204                 Bar,
205                 Beat,
206         };
207
208         struct BBTPoint {
209                 framepos_t          frame;
210                 const MeterSection* meter;
211                 const TempoSection* tempo;
212                 uint32_t            bar;
213                 uint32_t            beat;
214             
215                 BBTPoint (const MeterSection& m, const TempoSection& t, framepos_t f,
216                           uint32_t b, uint32_t e)
217                         : frame (f), meter (&m), tempo (&t), bar (b), beat (e) {}
218                 
219                 Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); }
220                 operator Timecode::BBT_Time() const { return bbt(); }
221                 operator framepos_t() const { return frame; }
222                 bool is_bar() const { return beat == 1; }
223         };
224
225         typedef std::vector<BBTPoint> BBTPointList;
226
227         template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
228                 Glib::Threads::RWLock::ReaderLock lm (lock);
229                 (obj.*method)(metrics);
230         }
231
232         void get_grid (BBTPointList::const_iterator&, BBTPointList::const_iterator&, 
233                        framepos_t start, framepos_t end);
234         
235         /* TEMPO- AND METER-SENSITIVE FUNCTIONS 
236
237            bbt_time(), bbt_time_rt(), frame_time() and bbt_duration_at()
238            are all sensitive to tempo and meter, and will give answers
239            that align with the grid formed by tempo and meter sections.
240            
241            They SHOULD NOT be used to determine the position of events 
242            whose location is canonically defined in beats.
243         */
244
245         void bbt_time (framepos_t when, Timecode::BBT_Time&);
246
247         /* realtime safe variant of ::bbt_time(), will throw 
248            std::logic_error if the map is not large enough
249            to provide an answer.
250         */
251         void       bbt_time_rt (framepos_t when, Timecode::BBT_Time&);
252         framepos_t frame_time (const Timecode::BBT_Time&);
253         framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir);
254
255         /* TEMPO-SENSITIVE FUNCTIONS
256            
257            These next 4 functions will all take tempo in account and should be
258            used to determine position (and in the last case, distance in beats)
259            when tempo matters but meter does not.
260
261            They SHOULD be used to determine the position of events 
262            whose location is canonically defined in beats.
263         */
264
265         framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b) const;
266         framepos_t framepos_plus_beats (framepos_t, Evoral::MusicalTime) const;
267         framepos_t framepos_minus_beats (framepos_t, Evoral::MusicalTime) const;
268         Evoral::MusicalTime framewalk_to_beats (framepos_t pos, framecnt_t distance) const;
269
270         static const Tempo& default_tempo() { return _default_tempo; }
271         static const Meter& default_meter() { return _default_meter; }
272
273         const Tempo& tempo_at (framepos_t) const;
274         const Meter& meter_at (framepos_t) const;
275
276         const TempoSection& tempo_section_at (framepos_t) const;
277
278         void add_tempo (const Tempo&, Timecode::BBT_Time where);
279         void add_meter (const Meter&, Timecode::BBT_Time where);
280
281         void remove_tempo (const TempoSection&, bool send_signal);
282         void remove_meter (const MeterSection&, bool send_signal);
283
284         void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where);
285         void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where);
286
287         framepos_t round_to_bar  (framepos_t frame, int dir);
288         framepos_t round_to_beat (framepos_t frame, int dir);
289         framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, int dir);
290         framepos_t round_to_tick (framepos_t frame, int dir);
291
292         void set_length (framepos_t frames);
293
294         XMLNode& get_state (void);
295         int set_state (const XMLNode&, int version);
296
297         void dump (std::ostream&) const;
298         void clear ();
299
300         TempoMetric metric_at (Timecode::BBT_Time bbt) const;
301         TempoMetric metric_at (framepos_t) const;
302
303         void change_existing_tempo_at (framepos_t, double bpm, double note_type);
304         void change_initial_tempo (double bpm, double note_type);
305
306         void insert_time (framepos_t, framecnt_t);
307
308         int n_tempos () const;
309         int n_meters () const;
310
311         framecnt_t frame_rate () const { return _frame_rate; }
312
313   private:
314
315         friend class ::BBTTest;
316         friend class ::FrameposPlusBeatsTest;
317         friend class ::TempoTest;
318         
319         static Tempo    _default_tempo;
320         static Meter    _default_meter;
321
322         Metrics                       metrics;
323         framecnt_t                    _frame_rate;
324         mutable Glib::Threads::RWLock lock;
325         BBTPointList                  _map;
326
327         void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1);
328         void extend_map (framepos_t end);
329         void require_map_to (framepos_t pos);
330         void require_map_to (const Timecode::BBT_Time&);
331         void _extend_map (TempoSection* tempo, MeterSection* meter, 
332                           Metrics::iterator next_metric,
333                           Timecode::BBT_Time current, framepos_t current_frame, framepos_t end);
334
335         BBTPointList::const_iterator bbt_before_or_at (framepos_t);
336         BBTPointList::const_iterator bbt_before_or_at (const Timecode::BBT_Time&);
337         BBTPointList::const_iterator bbt_after_or_at (framepos_t);
338         
339         framepos_t round_to_type (framepos_t fr, int dir, BBTPointType);
340         void bbt_time (framepos_t, Timecode::BBT_Time&, const BBTPointList::const_iterator&);
341         framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir);
342         
343         const MeterSection& first_meter() const;
344         const TempoSection& first_tempo() const;
345         
346         void do_insert (MetricSection* section);
347 };
348
349 }; /* namespace ARDOUR */
350
351 std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&);
352 std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&);
353 std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&);
354
355 #endif /* __ardour_tempo_h__ */