Fix test build.
[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/thread.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 XMLNode;
38 class BBTTest;
39
40 namespace ARDOUR {
41
42 class Meter;
43 class TempoMap;
44
45 class Tempo {
46   public:
47         Tempo (double bpm, double type=4.0) // defaulting to quarter note
48                 : _beats_per_minute (bpm), _note_type(type) {}
49
50         double beats_per_minute () const { return _beats_per_minute;}
51         double note_type () const { return _note_type;}
52         double frames_per_beat (framecnt_t sr) const;
53
54   protected:
55         double _beats_per_minute;
56         double _note_type;
57 };
58
59 class Meter {
60   public:
61         Meter (double dpb, double bt)
62                 : _divisions_per_bar (dpb), _note_type (bt) {}
63
64         double divisions_per_bar () const { return _divisions_per_bar; }
65         double note_divisor() const { return _note_type; }
66
67         double frames_per_bar (const Tempo&, framecnt_t sr) const;
68         double frames_per_division (const Tempo&, framecnt_t sr) const;
69
70   protected:
71         /** The number of divisions in a bar.  This is a floating point value because
72             there are musical traditions on our planet that do not limit
73             themselves to integral numbers of beats per bar.
74         */
75         double _divisions_per_bar;
76
77         /** The type of "note" that a division represents.  For example, 4.0 is
78             a quarter (crotchet) note, 8.0 is an eighth (quaver) note, etc.
79         */
80         double _note_type;
81 };
82
83 class MetricSection {
84   public:
85         MetricSection (const Timecode::BBT_Time& start)
86                 : _start (start), _frame (0), _movable (true) {}
87         MetricSection (framepos_t start)
88                 : _frame (start), _movable (true) {}
89
90         virtual ~MetricSection() {}
91
92         const Timecode::BBT_Time& start() const { return _start; }
93         framepos_t                frame() const { return _frame; }
94
95         void set_movable (bool yn) { _movable = yn; }
96         bool movable() const { return _movable; }
97
98         virtual void set_frame (framepos_t f) {
99                 _frame = f;
100         }
101
102         virtual void set_start (const Timecode::BBT_Time& w) {
103                 _start = w;
104         }
105
106         /* MeterSections are not stateful in the full sense,
107            but we do want them to control their own
108            XML state information.
109         */
110         virtual XMLNode& get_state() const = 0;
111
112         int compare (const MetricSection&) const;
113         bool operator== (const MetricSection& other) const;
114         bool operator!= (const MetricSection& other) const;
115
116   private:
117         Timecode::BBT_Time _start;
118         framepos_t         _frame;
119         bool               _movable;
120 };
121
122 class MeterSection : public MetricSection, public Meter {
123   public:
124         MeterSection (const Timecode::BBT_Time& start, double bpb, double note_type)
125                 : MetricSection (start), Meter (bpb, note_type) {}
126         MeterSection (framepos_t start, double bpb, double note_type)
127                 : MetricSection (start), Meter (bpb, note_type) {}
128         MeterSection (const XMLNode&);
129
130         static const std::string xml_state_node_name;
131
132         XMLNode& get_state() const;
133 };
134
135 class TempoSection : public MetricSection, public Tempo {
136   public:
137         TempoSection (const Timecode::BBT_Time& start, double qpm, double note_type)
138                 : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0)  {}
139         TempoSection (framepos_t start, double qpm, double note_type)
140                 : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0) {}
141         TempoSection (const XMLNode&);
142
143         static const std::string xml_state_node_name;
144
145         XMLNode& get_state() const;
146
147         void update_bar_offset_from_bbt (const Meter&);
148         void update_bbt_time_from_bar_offset (const Meter&);
149         double bar_offset() const { return _bar_offset; }
150
151   private:
152         /* this value provides a fractional offset into the bar in which
153            the tempo section is located in. A value of 0.0 indicates that
154            it occurs on the first beat of the bar, a value of 0.5 indicates
155            that it occurs halfway through the bar and so on.
156            
157            this enables us to keep the tempo change at the same relative
158            position within the bar if/when the meter changes.
159         */
160         double _bar_offset;
161 };
162
163 typedef std::list<MetricSection*> Metrics;
164
165 /** Helper class that we use to be able to keep track of which
166     meter *AND* tempo are in effect at a given point in time.
167 */
168 class TempoMetric {
169   public:
170         TempoMetric (const Meter& m, const Tempo& t) : _meter (&m), _tempo (&t), _frame (0) {}
171
172         void set_tempo (const Tempo& t)    { _tempo = &t; }
173         void set_meter (const Meter& m)    { _meter = &m; }
174         void set_frame (framepos_t f)      { _frame = f; }
175         void set_start (const Timecode::BBT_Time& t) { _start = t; }
176
177         const Meter&    meter() const { return *_meter; }
178         const Tempo&    tempo() const { return *_tempo; }
179         framepos_t      frame() const { return _frame; }
180         const Timecode::BBT_Time& start() const { return _start; }
181
182   private:
183         const Meter*       _meter;
184         const Tempo*       _tempo;
185         framepos_t         _frame;
186         Timecode::BBT_Time _start;
187 };
188
189 class TempoMap : public PBD::StatefulDestructible
190 {
191   public:
192         TempoMap (framecnt_t frame_rate);
193         ~TempoMap();
194
195         /* measure-based stuff */
196
197         enum BBTPointType {
198                 Bar,
199                 Beat,
200         };
201
202         struct BBTPoint {
203             BBTPointType type;
204             framepos_t  frame;
205             const Meter* meter;
206             const Tempo* tempo;
207             uint32_t bar;
208             uint32_t beat;
209             
210             Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); }
211             operator Timecode::BBT_Time() const { return bbt(); }
212             operator framepos_t() const { return frame; }
213             
214             BBTPoint (const Meter& m, const Tempo& t, framepos_t f,
215                       BBTPointType ty, uint32_t b, uint32_t e)
216                     : type (ty), frame (f), meter (&m), tempo (&t), bar (b), beat (e) {}
217         };
218
219         typedef std::vector<BBTPoint> BBTPointList;
220
221         template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
222                 Glib::RWLock::ReaderLock lm (lock);
223                 (obj.*method)(*metrics);
224         }
225
226         const BBTPointList& map() const { return _map ; }
227         void map (BBTPointList&, framepos_t start, framepos_t end);
228         
229         void      bbt_time (framepos_t when, Timecode::BBT_Time&);
230         framecnt_t frame_time (const Timecode::BBT_Time&);
231         framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir);
232
233         static const Tempo& default_tempo() { return _default_tempo; }
234         static const Meter& default_meter() { return _default_meter; }
235
236         const Tempo& tempo_at (framepos_t) const;
237         const Meter& meter_at (framepos_t) const;
238
239         const TempoSection& tempo_section_at (framepos_t) const;
240
241         void add_tempo(const Tempo&, Timecode::BBT_Time where);
242         void add_meter(const Meter&, Timecode::BBT_Time where);
243
244         void remove_tempo(const TempoSection&, bool send_signal);
245         void remove_meter(const MeterSection&, bool send_signal);
246
247         void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where);
248         void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where);
249
250         framepos_t round_to_bar  (framepos_t frame, int dir);
251         framepos_t round_to_beat (framepos_t frame, int dir);
252         framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, int dir);
253         framepos_t round_to_tick (framepos_t frame, int dir);
254
255         void set_length (framepos_t frames);
256
257         XMLNode& get_state (void);
258         int set_state (const XMLNode&, int version);
259
260         void dump (std::ostream&) const;
261         void clear ();
262
263         TempoMetric metric_at (Timecode::BBT_Time bbt) const;
264         TempoMetric metric_at (framepos_t) const;
265
266         framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b);
267         framepos_t framepos_plus_beats (framepos_t, Evoral::MusicalTime);
268         framepos_t framepos_minus_beats (framepos_t, Evoral::MusicalTime);
269         Evoral::MusicalTime framewalk_to_beats (framepos_t pos, framecnt_t distance);
270
271         void change_existing_tempo_at (framepos_t, double bpm, double note_type);
272         void change_initial_tempo (double bpm, double note_type);
273
274         void insert_time (framepos_t, framecnt_t);
275
276         int n_tempos () const;
277         int n_meters () const;
278
279         framecnt_t frame_rate () const { return _frame_rate; }
280
281   private:
282
283         friend class ::BBTTest;
284         
285         static Tempo    _default_tempo;
286         static Meter    _default_meter;
287
288         Metrics*             metrics;
289         framecnt_t          _frame_rate;
290         framepos_t           last_bbt_when;
291         bool                 last_bbt_valid;
292         Timecode::BBT_Time   last_bbt;
293         mutable Glib::RWLock lock;
294         BBTPointList          _map;
295
296         void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1);
297         void require_map_to (framepos_t pos);
298         void require_map_to (const Timecode::BBT_Time&);
299
300     BBTPointList::const_iterator bbt_before_or_at (framepos_t);
301     BBTPointList::const_iterator bbt_after_or_at (framepos_t);
302     BBTPointList::const_iterator bbt_point_for (const Timecode::BBT_Time&);
303
304         void timestamp_metrics_from_audio_time ();
305
306         framepos_t round_to_type (framepos_t fr, int dir, BBTPointType);
307
308         void bbt_time_unlocked (framepos_t, Timecode::BBT_Time&);
309
310     framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir);
311
312         const MeterSection& first_meter() const;
313         const TempoSection& first_tempo() const;
314
315         int move_metric_section (MetricSection&, const Timecode::BBT_Time& to);
316         void do_insert (MetricSection* section);
317
318         Timecode::BBT_Time bbt_add (const Timecode::BBT_Time&, const Timecode::BBT_Time&, const TempoMetric&) const;
319         Timecode::BBT_Time bbt_add (const Timecode::BBT_Time& a, const Timecode::BBT_Time& b) const;
320         Timecode::BBT_Time bbt_subtract (const Timecode::BBT_Time&, const Timecode::BBT_Time&) const;
321 };
322
323 }; /* namespace ARDOUR */
324
325 std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&);
326 std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&);
327 std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&);
328
329 #endif /* __ardour_tempo_h__ */