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