return two iterators into the Bars|Beats list of the tempo map rather than making...
[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_division (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             BBTPointType type;
207             framepos_t  frame;
208             const Meter* meter;
209             const Tempo* tempo;
210             uint32_t bar;
211             uint32_t beat;
212             
213             Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); }
214             operator Timecode::BBT_Time() const { return bbt(); }
215             operator framepos_t() const { return frame; }
216             
217             BBTPoint (const Meter& m, const Tempo& t, framepos_t f,
218                       BBTPointType ty, uint32_t b, uint32_t e)
219                     : type (ty), frame (f), meter (&m), tempo (&t), bar (b), beat (e) {}
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         const BBTPointList& map() const { return _map ; }
230
231         void map (BBTPointList::const_iterator&, BBTPointList::const_iterator&, 
232                   framepos_t start, framepos_t end);
233         
234         void      bbt_time (framepos_t when, Timecode::BBT_Time&);
235         framecnt_t frame_time (const Timecode::BBT_Time&);
236         framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir);
237
238         static const Tempo& default_tempo() { return _default_tempo; }
239         static const Meter& default_meter() { return _default_meter; }
240
241         const Tempo& tempo_at (framepos_t) const;
242         const Meter& meter_at (framepos_t) const;
243
244         const TempoSection& tempo_section_at (framepos_t) const;
245
246         void add_tempo(const Tempo&, Timecode::BBT_Time where);
247         void add_meter(const Meter&, Timecode::BBT_Time where);
248
249         void remove_tempo(const TempoSection&, bool send_signal);
250         void remove_meter(const MeterSection&, bool send_signal);
251
252         void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where);
253         void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where);
254
255         framepos_t round_to_bar  (framepos_t frame, int dir);
256         framepos_t round_to_beat (framepos_t frame, int dir);
257         framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, int dir);
258         framepos_t round_to_tick (framepos_t frame, int dir);
259
260         void set_length (framepos_t frames);
261
262         XMLNode& get_state (void);
263         int set_state (const XMLNode&, int version);
264
265         void dump (std::ostream&) const;
266         void clear ();
267
268         TempoMetric metric_at (Timecode::BBT_Time bbt) const;
269         TempoMetric metric_at (framepos_t) const;
270
271         framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b);
272         framepos_t framepos_plus_beats (framepos_t, Evoral::MusicalTime);
273         framepos_t framepos_minus_beats (framepos_t, Evoral::MusicalTime);
274         Evoral::MusicalTime framewalk_to_beats (framepos_t pos, framecnt_t distance);
275
276         void change_existing_tempo_at (framepos_t, double bpm, double note_type);
277         void change_initial_tempo (double bpm, double note_type);
278
279         void insert_time (framepos_t, framecnt_t);
280
281         int n_tempos () const;
282         int n_meters () const;
283
284         framecnt_t frame_rate () const { return _frame_rate; }
285
286   private:
287
288         friend class ::BBTTest;
289         friend class ::FrameposPlusBeatsTest;
290         friend class ::TempoTest;
291         
292         static Tempo    _default_tempo;
293         static Meter    _default_meter;
294
295         Metrics*             metrics;
296         framecnt_t          _frame_rate;
297         framepos_t           last_bbt_when;
298         bool                 last_bbt_valid;
299         Timecode::BBT_Time   last_bbt;
300         mutable Glib::RWLock lock;
301         BBTPointList          _map;
302
303         void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1);
304         void require_map_to (framepos_t pos);
305         void require_map_to (const Timecode::BBT_Time&);
306
307     BBTPointList::const_iterator bbt_before_or_at (framepos_t);
308     BBTPointList::const_iterator bbt_after_or_at (framepos_t);
309     BBTPointList::const_iterator bbt_point_for (const Timecode::BBT_Time&);
310
311         void timestamp_metrics_from_audio_time ();
312
313         framepos_t round_to_type (framepos_t fr, int dir, BBTPointType);
314
315         void bbt_time_unlocked (framepos_t, Timecode::BBT_Time&, const BBTPointList::const_iterator&);
316
317     framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir);
318
319         const MeterSection& first_meter() const;
320         const TempoSection& first_tempo() const;
321
322         int move_metric_section (MetricSection&, const Timecode::BBT_Time& to);
323         void do_insert (MetricSection* section);
324
325         Timecode::BBT_Time bbt_add (const Timecode::BBT_Time&, const Timecode::BBT_Time&, const TempoMetric&) const;
326         Timecode::BBT_Time bbt_add (const Timecode::BBT_Time& a, const Timecode::BBT_Time& b) const;
327         Timecode::BBT_Time bbt_subtract (const Timecode::BBT_Time&, const Timecode::BBT_Time&) const;
328 };
329
330 }; /* namespace ARDOUR */
331
332 std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&);
333 std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&);
334 std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&);
335
336 #endif /* __ardour_tempo_h__ */