partially revert some of the recent work on tempo to reflect new understanding of...
[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
39 class BBTTest;
40 class FrameposPlusBeatsTest;
41 class TempoTest;
42
43 namespace ARDOUR {
44
45 class Meter;
46 class TempoMap;
47
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
57   protected:
58         double _beats_per_minute;
59         double _note_type;
60 };
61
62 class Meter {
63   public:
64         Meter (double dpb, double bt)
65                 : _divisions_per_bar (dpb), _note_type (bt) {}
66
67         double divisions_per_bar () const { return _divisions_per_bar; }
68         double note_divisor() const { return _note_type; }
69
70         double frames_per_bar (const Tempo&, framecnt_t sr) const;
71         double frames_per_grid (const Tempo&, framecnt_t sr) const;
72
73   protected:
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.
77         */
78         double _divisions_per_bar;
79
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.
82         */
83         double _note_type;
84 };
85
86 class MetricSection {
87   public:
88         MetricSection (const Timecode::BBT_Time& start)
89                 : _start (start), _frame (0), _movable (true) {}
90         MetricSection (framepos_t start)
91                 : _frame (start), _movable (true) {}
92
93         virtual ~MetricSection() {}
94
95         const Timecode::BBT_Time& start() const { return _start; }
96         framepos_t                frame() const { return _frame; }
97
98         void set_movable (bool yn) { _movable = yn; }
99         bool movable() const { return _movable; }
100
101         virtual void set_frame (framepos_t f) {
102                 _frame = f;
103         }
104
105         virtual void set_start (const Timecode::BBT_Time& w) {
106                 _start = w;
107         }
108
109         /* MeterSections are not stateful in the full sense,
110            but we do want them to control their own
111            XML state information.
112         */
113         virtual XMLNode& get_state() const = 0;
114
115         int compare (const MetricSection&) const;
116         bool operator== (const MetricSection& other) const;
117         bool operator!= (const MetricSection& other) const;
118
119   private:
120         Timecode::BBT_Time _start;
121         framepos_t         _frame;
122         bool               _movable;
123 };
124
125 class MeterSection : public MetricSection, public Meter {
126   public:
127         MeterSection (const Timecode::BBT_Time& start, double bpb, double note_type)
128                 : MetricSection (start), Meter (bpb, note_type) {}
129         MeterSection (framepos_t start, double bpb, double note_type)
130                 : MetricSection (start), Meter (bpb, note_type) {}
131         MeterSection (const XMLNode&);
132
133         static const std::string xml_state_node_name;
134
135         XMLNode& get_state() const;
136 };
137
138 class TempoSection : public MetricSection, public Tempo {
139   public:
140         TempoSection (const Timecode::BBT_Time& start, double qpm, double note_type)
141                 : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0)  {}
142         TempoSection (framepos_t start, double qpm, double note_type)
143                 : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0) {}
144         TempoSection (const XMLNode&);
145
146         static const std::string xml_state_node_name;
147
148         XMLNode& get_state() const;
149
150         void update_bar_offset_from_bbt (const Meter&);
151         void update_bbt_time_from_bar_offset (const Meter&);
152         double bar_offset() const { return _bar_offset; }
153
154   private:
155         /* this value provides a fractional offset into the bar in which
156            the tempo section is located in. A value of 0.0 indicates that
157            it occurs on the first beat of the bar, a value of 0.5 indicates
158            that it occurs halfway through the bar and so on.
159            
160            this enables us to keep the tempo change at the same relative
161            position within the bar if/when the meter changes.
162         */
163         double _bar_offset;
164 };
165
166 typedef std::list<MetricSection*> Metrics;
167
168 /** Helper class that we use to be able to keep track of which
169     meter *AND* tempo are in effect at a given point in time.
170 */
171 class TempoMetric {
172   public:
173         TempoMetric (const Meter& m, const Tempo& t) : _meter (&m), _tempo (&t), _frame (0) {}
174
175         void set_tempo (const Tempo& t)    { _tempo = &t; }
176         void set_meter (const Meter& m)    { _meter = &m; }
177         void set_frame (framepos_t f)      { _frame = f; }
178         void set_start (const Timecode::BBT_Time& t) { _start = t; }
179
180         const Meter&    meter() const { return *_meter; }
181         const Tempo&    tempo() const { return *_tempo; }
182         framepos_t      frame() const { return _frame; }
183         const Timecode::BBT_Time& start() const { return _start; }
184
185   private:
186         const Meter*       _meter;
187         const Tempo*       _tempo;
188         framepos_t         _frame;
189         Timecode::BBT_Time _start;
190 };
191
192 class TempoMap : public PBD::StatefulDestructible
193 {
194   public:
195         TempoMap (framecnt_t frame_rate);
196         ~TempoMap();
197
198         /* measure-based stuff */
199
200         enum BBTPointType {
201                 Bar,
202                 Beat,
203         };
204
205         struct BBTPoint {
206             framepos_t  frame;
207             const MeterSection* meter;
208             const TempoSection* tempo;
209             uint32_t bar;
210             uint32_t beat;
211             
212             BBTPoint (const MeterSection& m, const TempoSection& t, framepos_t f,
213                       uint32_t b, uint32_t e)
214                     : frame (f), meter (&m), tempo (&t), bar (b), beat (e) {}
215
216             Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); }
217             operator Timecode::BBT_Time() const { return bbt(); }
218             operator framepos_t() const { return frame; }
219             bool is_bar() const { return beat == 1; }
220         };
221
222         typedef std::vector<BBTPoint> BBTPointList;
223
224         template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
225                 Glib::RWLock::ReaderLock lm (lock);
226                 (obj.*method)(metrics);
227         }
228
229         void get_grid (BBTPointList::const_iterator&, BBTPointList::const_iterator&, 
230                        framepos_t start, framepos_t end);
231         
232         /* TEMPO- AND METER-SENSITIVE FUNCTIONS 
233
234            bbt_time(), bbt_time_rt(), frame_time() and bbt_duration_at()
235            are all sensitive to tempo and meter, and will give answers
236            that align with the grid formed by tempo and meter sections.
237            
238            They SHOULD NOT be used to determine the position of events 
239            whose location is canonically defined in beats.
240         */
241
242         void       bbt_time (framepos_t when, Timecode::BBT_Time&);
243         /* realtime safe variant of ::bbt_time(), will throw 
244            std::logic_error if the map is not large enough
245            to provide an answer.
246         */
247         void       bbt_time_rt (framepos_t when, Timecode::BBT_Time&);
248         framecnt_t frame_time (const Timecode::BBT_Time&);
249         framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir);
250
251         /* TEMPO-SENSITIVE FUNCTIONS
252            
253            These next 4 functions will all take tempo in account and should be
254            used to determine position (and in the last case, distance in beats)
255            when tempo matters but meter does not.
256
257            They SHOULD be used to determine the position of events 
258            whose location is canonically defined in beats.
259         */
260
261         framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b) const;
262         framepos_t framepos_plus_beats (framepos_t, Evoral::MusicalTime) const;
263         framepos_t framepos_minus_beats (framepos_t, Evoral::MusicalTime) const;
264         Evoral::MusicalTime framewalk_to_beats (framepos_t pos, framecnt_t distance) const;
265
266         static const Tempo& default_tempo() { return _default_tempo; }
267         static const Meter& default_meter() { return _default_meter; }
268
269         const Tempo& tempo_at (framepos_t) const;
270         const Meter& meter_at (framepos_t) const;
271
272         const TempoSection& tempo_section_at (framepos_t) const;
273
274         void add_tempo(const Tempo&, Timecode::BBT_Time where);
275         void add_meter(const Meter&, Timecode::BBT_Time where);
276
277         void remove_tempo(const TempoSection&, bool send_signal);
278         void remove_meter(const MeterSection&, bool send_signal);
279
280         void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where);
281         void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where);
282
283         framepos_t round_to_bar  (framepos_t frame, int dir);
284         framepos_t round_to_beat (framepos_t frame, int dir);
285         framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, int dir);
286         framepos_t round_to_tick (framepos_t frame, int dir);
287
288         void set_length (framepos_t frames);
289
290         XMLNode& get_state (void);
291         int set_state (const XMLNode&, int version);
292
293         void dump (std::ostream&) const;
294         void clear ();
295
296         TempoMetric metric_at (Timecode::BBT_Time bbt) const;
297         TempoMetric metric_at (framepos_t) const;
298
299
300         void change_existing_tempo_at (framepos_t, double bpm, double note_type);
301         void change_initial_tempo (double bpm, double note_type);
302
303         void insert_time (framepos_t, framecnt_t);
304
305         int n_tempos () const;
306         int n_meters () const;
307
308         framecnt_t frame_rate () const { return _frame_rate; }
309
310   private:
311
312         friend class ::BBTTest;
313         friend class ::FrameposPlusBeatsTest;
314         friend class ::TempoTest;
315         
316         static Tempo    _default_tempo;
317         static Meter    _default_meter;
318
319         Metrics              metrics;
320         framecnt_t          _frame_rate;
321         mutable Glib::RWLock lock;
322         BBTPointList        _map;
323
324         void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1);
325         void extend_map (framepos_t end);
326         void require_map_to (framepos_t pos);
327         void require_map_to (const Timecode::BBT_Time&);
328         void _extend_map (TempoSection* tempo, MeterSection* meter, 
329                           Metrics::iterator next_metric,
330                           Timecode::BBT_Time current, framepos_t current_frame, framepos_t end);
331
332         BBTPointList::const_iterator bbt_before_or_at (framepos_t);
333         BBTPointList::const_iterator bbt_before_or_at (const Timecode::BBT_Time&);
334         BBTPointList::const_iterator bbt_after_or_at (framepos_t);
335         
336         framepos_t round_to_type (framepos_t fr, int dir, BBTPointType);
337         void bbt_time (framepos_t, Timecode::BBT_Time&, const BBTPointList::const_iterator&);
338         framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir);
339         
340         const MeterSection& first_meter() const;
341         const TempoSection& first_tempo() const;
342         
343         void do_insert (MetricSection* section);
344 };
345
346 }; /* namespace ARDOUR */
347
348 std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&);
349 std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&);
350 std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&);
351
352 #endif /* __ardour_tempo_h__ */