e82639ef517f405efa0463f53acbd0521063eab1
[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 <sigc++/signal.h>
34
35 #include "ardour/ardour.h"
36
37 class XMLNode;
38
39 using std::list;
40 using std::vector;
41
42 namespace ARDOUR {
43 class Meter;
44 class Tempo {
45   public:
46         Tempo (double bpm, double type=4.0) // defaulting to quarter note
47                 : _beats_per_minute (bpm), _note_type(type) {} 
48
49         double beats_per_minute () const { return _beats_per_minute;}
50         double note_type () const { return _note_type;}
51         double frames_per_beat (nframes_t sr, const Meter& meter) const;
52
53   protected:
54         double _beats_per_minute;
55         double _note_type;
56 };
57
58 class Meter {
59   public:
60         static const double ticks_per_beat;
61
62         Meter (double bpb, double bt) 
63                 : _beats_per_bar (bpb), _note_type (bt) {}
64
65         double beats_per_bar () const { return _beats_per_bar; }
66         double note_divisor() const { return _note_type; }
67         
68         double frames_per_bar (const Tempo&, nframes_t sr) const;
69
70   protected:
71         /** The number of beats in a bar.  This is a real 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 _beats_per_bar;
76
77         /** The type of "note" that a beat 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 BBT_Time& start)
86                 : _start (start), _frame (0), _movable (true) {}
87         MetricSection (nframes_t start)
88                 : _frame (start), _movable (true) {}
89
90         virtual ~MetricSection() {}
91
92         const BBT_Time& start() const { return _start; }
93         nframes_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 (nframes_t f) {
99                 _frame = f;
100         }
101
102         virtual void set_start (const 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   private:
113         BBT_Time       _start;
114         nframes_t      _frame;
115         bool           _movable;
116 };
117
118 class MeterSection : public MetricSection, public Meter {
119   public:
120         MeterSection (const BBT_Time& start, double bpb, double note_type)
121                 : MetricSection (start), Meter (bpb, note_type) {}
122         MeterSection (nframes_t start, double bpb, double note_type)
123                 : MetricSection (start), Meter (bpb, note_type) {}
124         MeterSection (const XMLNode&);
125
126         static const string xml_state_node_name;
127
128         XMLNode& get_state() const;
129 };
130
131 class TempoSection : public MetricSection, public Tempo {
132   public:
133         TempoSection (const BBT_Time& start, double qpm, double note_type)
134                 : MetricSection (start), Tempo (qpm, note_type) {}
135         TempoSection (nframes_t start, double qpm, double note_type)
136                 : MetricSection (start), Tempo (qpm, note_type) {}
137         TempoSection (const XMLNode&);
138
139         static const string xml_state_node_name;
140
141         XMLNode& get_state() const;
142 };
143
144 typedef list<MetricSection*> Metrics;
145
146 class TempoMap : public PBD::StatefulDestructible
147 {
148   public:
149         TempoMap (nframes_t frame_rate);
150         ~TempoMap();
151
152         /* measure-based stuff */
153
154         enum BBTPointType {
155                 Bar,
156                 Beat,
157         };
158
159         struct BBTPoint {
160             BBTPointType type;
161             nframes_t frame;
162             const Meter* meter;
163             const Tempo* tempo;
164             uint32_t bar;
165             uint32_t beat;
166             
167             BBTPoint (const Meter& m, const Tempo& t, nframes_t f,
168                                 BBTPointType ty, uint32_t b, uint32_t e) 
169                     : type (ty), frame (f), meter (&m), tempo (&t), bar (b), beat (e) {}
170         };
171
172         typedef vector<BBTPoint> BBTPointList;
173         
174         template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
175                 Glib::RWLock::ReaderLock lm (lock);
176                 (obj.*method)(*metrics);
177         }
178
179         BBTPointList *get_points (nframes_t start, nframes_t end) const;
180
181         void      bbt_time (nframes_t when, BBT_Time&) const;
182         nframes_t frame_time (const BBT_Time&) const;
183         nframes_t bbt_duration_at (nframes_t, const BBT_Time&, int dir) const;
184
185         static const Tempo& default_tempo() { return _default_tempo; }
186         static const Meter& default_meter() { return _default_meter; }
187
188         const Tempo& tempo_at (nframes_t);
189         const Meter& meter_at (nframes_t);
190
191         const TempoSection& tempo_section_at (nframes_t);
192
193         void add_tempo(const Tempo&, BBT_Time where);
194         void add_meter(const Meter&, BBT_Time where);
195
196         void add_tempo(const Tempo&, nframes_t where);
197         void add_meter(const Meter&, nframes_t where);
198
199         void move_tempo (TempoSection&, const BBT_Time& to);
200         void move_meter (MeterSection&, const BBT_Time& to);
201         
202         void remove_tempo(const TempoSection&);
203         void remove_meter(const MeterSection&);
204
205         void replace_tempo (TempoSection& existing, const Tempo& replacement);
206         void replace_meter (MeterSection& existing, const Meter& replacement);
207
208         nframes_t round_to_bar  (nframes_t frame, int dir);
209         nframes_t round_to_beat (nframes_t frame, int dir);
210         nframes_t round_to_beat_subdivision (nframes_t fr, int sub_num);
211         nframes_t round_to_tick (nframes_t frame, int dir);
212
213         void set_length (nframes_t frames);
214
215         XMLNode& get_state (void);
216         int set_state (const XMLNode&);
217
218         void dump (std::ostream&) const;
219         void clear ();
220
221         /** Helper class that we use to be able to keep track of which
222             meter *AND* tempo are in effect at a given point in time.
223         */
224         class Metric {
225           public:
226                 Metric (const Meter& m, const Tempo& t) : _meter (&m), _tempo (&t), _frame (0) {}
227                 
228                 void set_tempo (const Tempo& t)    { _tempo = &t; }
229                 void set_meter (const Meter& m)    { _meter = &m; }
230                 void set_frame (nframes_t f)       { _frame = f; }
231                 void set_start (const BBT_Time& t) { _start = t; }
232                 
233                 const Meter&    meter() const { return *_meter; }
234                 const Tempo&    tempo() const { return *_tempo; }
235                 nframes_t       frame() const { return _frame; }
236                 const BBT_Time& start() const { return _start; }
237                 
238           private:
239                 const Meter*   _meter;
240                 const Tempo*   _tempo;
241                 nframes_t      _frame;
242                 BBT_Time       _start;
243         };
244
245         Metric metric_at (BBT_Time bbt) const;
246         Metric metric_at (nframes_t) const;
247         void bbt_time_with_metric (nframes_t, BBT_Time&, const Metric&) const;
248
249         void change_existing_tempo_at (nframes_t, double bpm, double note_type);
250         void change_initial_tempo (double bpm, double note_type);
251
252         int n_tempos () const;
253         int n_meters () const;
254
255         sigc::signal<void,ARDOUR::Change> StateChanged;
256
257   private:
258         static Tempo    _default_tempo;
259         static Meter    _default_meter;
260
261         Metrics*             metrics;
262         nframes_t           _frame_rate;
263         nframes_t            last_bbt_when;
264         bool                 last_bbt_valid;
265         BBT_Time             last_bbt;
266         mutable Glib::RWLock lock;
267         
268         void timestamp_metrics (bool use_bbt);
269
270         nframes_t round_to_type (nframes_t fr, int dir, BBTPointType);
271
272         nframes_t frame_time_unlocked (const BBT_Time&) const;
273
274         void bbt_time_unlocked (nframes_t, BBT_Time&) const;
275
276         nframes_t bbt_duration_at_unlocked (const BBT_Time& when, const BBT_Time& bbt, int dir) const;
277
278         const MeterSection& first_meter() const;
279         const TempoSection& first_tempo() const;
280
281         nframes_t count_frames_between (const BBT_Time&, const BBT_Time&) const;
282         nframes_t count_frames_between_metrics (const Meter&, const Tempo&,
283                         const BBT_Time&, const BBT_Time&) const;
284
285         int move_metric_section (MetricSection&, const BBT_Time& to);
286         void do_insert (MetricSection* section, bool with_bbt);
287 };
288
289 }; /* namespace ARDOUR */
290
291 #endif /* __ardour_tempo_h__ */