Tempo ramps - replace ugly bootstrapping code in TempoMap::frame_time() with new...
[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/threads.h>
28
29 #include "pbd/undo.h"
30
31 #include "pbd/stateful.h"
32 #include "pbd/statefuldestructible.h"
33
34 #include "evoral/Beats.hpp"
35
36 #include "ardour/ardour.h"
37
38 class BBTTest;
39 class FrameposPlusBeatsTest;
40 class TempoTest;
41 class XMLNode;
42
43 namespace ARDOUR {
44
45 class Meter;
46 class TempoMap;
47
48 /** Tempo, the speed at which musical time progresses (BPM). */
49 class LIBARDOUR_API Tempo {
50   public:
51         /**
52          * @param bpm Beats Per Minute
53          * @param type Note Type (default `4': quarter note)
54          */
55         Tempo (double bpm, double type=4.0) // defaulting to quarter note
56                 : _beats_per_minute (bpm), _note_type(type) {}
57
58         double beats_per_minute () const { return _beats_per_minute; }
59
60         double ticks_per_minute () const { return _beats_per_minute * Timecode::BBT_Time::ticks_per_beat;}
61         double note_type () const { return _note_type;}
62         /** audio samples per beat
63          * @param sr samplerate
64          */
65         double frames_per_beat (framecnt_t sr) const {
66                 return (60.0 * sr) / _beats_per_minute;
67         }
68
69   protected:
70         double _beats_per_minute;
71         double _note_type;
72 };
73
74 /** Meter, or time signature (beats per bar, and which note type is a beat). */
75 class LIBARDOUR_API Meter {
76   public:
77         Meter (double dpb, double bt)
78                 : _divisions_per_bar (dpb), _note_type (bt) {}
79
80         double divisions_per_bar () const { return _divisions_per_bar; }
81         double note_divisor() const { return _note_type; }
82
83         double frames_per_bar (const Tempo&, framecnt_t sr) const;
84         double frames_per_grid (const Tempo&, framecnt_t sr) const;
85
86   protected:
87         /** The number of divisions in a bar.  This is a floating point value because
88             there are musical traditions on our planet that do not limit
89             themselves to integral numbers of beats per bar.
90         */
91         double _divisions_per_bar;
92
93         /** The type of "note" that a division represents.  For example, 4.0 is
94             a quarter (crotchet) note, 8.0 is an eighth (quaver) note, etc.
95         */
96         double _note_type;
97 };
98
99 /** A section of timeline with a certain Tempo or Meter. */
100 class LIBARDOUR_API MetricSection {
101   public:
102         MetricSection (double start)
103                 : _beat (start), _frame (0), _movable (true), _position_lock_style (MusicTime) {}
104         MetricSection (framepos_t frame)
105                 : _beat (0), _frame (frame), _movable (true), _position_lock_style (MusicTime) {}
106
107         virtual ~MetricSection() {}
108         const double start () const { return _beat; }
109
110         const double& beat() const { return _beat; }
111         void set_beat (double beat) { _beat = beat;}
112
113         framepos_t frame() const { return _frame; }
114         virtual void set_frame (framepos_t f) {
115                 _frame = f;
116         }
117
118         void set_movable (bool yn) { _movable = yn; }
119         bool movable() const { return _movable; }
120
121         /* MeterSections are not stateful in the full sense,
122            but we do want them to control their own
123            XML state information.
124         */
125         virtual XMLNode& get_state() const = 0;
126         PositionLockStyle position_lock_style () const { return _position_lock_style; }
127         void set_position_lock_style (PositionLockStyle ps) { _position_lock_style = ps; }
128
129 private:
130         double             _beat;
131         framepos_t         _frame;
132         bool               _movable;
133         PositionLockStyle  _position_lock_style;
134 };
135
136 /** A section of timeline with a certain Meter. */
137 class LIBARDOUR_API MeterSection : public MetricSection, public Meter {
138   public:
139         MeterSection (double start, const Timecode::BBT_Time& bbt, double bpb, double note_type)
140                 : MetricSection (start), Meter (bpb, note_type), _bbt (bbt) {}
141         MeterSection (framepos_t frame, double bpb, double note_type)
142                 : MetricSection (frame), Meter (bpb, note_type) {}
143         MeterSection (const XMLNode&);
144
145         static const std::string xml_state_node_name;
146
147         XMLNode& get_state() const;
148
149         void set_start (std::pair<double, Timecode::BBT_Time>& w) {
150                 set_beat (w.first);
151                 _bbt = w.second;
152         }
153         const Timecode::BBT_Time& bbt() const { return _bbt; }
154 private:
155         Timecode::BBT_Time _bbt;
156 };
157
158 /** A section of timeline with a certain Tempo. */
159 class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
160   public:
161         enum Type {
162                 Ramp,
163                 Constant,
164         };
165
166         TempoSection (const double& start, double qpm, double note_type, Type tempo_type)
167                 : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0), _type (tempo_type)  {}
168         TempoSection (framepos_t frame, double qpm, double note_type, Type tempo_type)
169                 : MetricSection (frame), Tempo (qpm, note_type), _bar_offset (-1.0), _type (tempo_type) {}
170         TempoSection (const XMLNode&);
171
172         static const std::string xml_state_node_name;
173
174         XMLNode& get_state() const;
175
176         void set_start (const double& w) {
177                 set_beat (w);
178         }
179
180         void update_bar_offset_from_bbt (const Meter&);
181         void update_bbt_time_from_bar_offset (const Meter&);
182         double bar_offset() const { return _bar_offset; }
183
184         void set_type (Type type);
185         Type type () const { return _type; }
186
187         double tempo_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const;
188         framepos_t frame_at_tempo (double tempo, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const;
189
190         double tick_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const;
191         framepos_t frame_at_tick (double tick, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const;
192
193         double beat_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const;
194         framepos_t frame_at_beat (double beat, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const;
195
196         Timecode::BBT_Time legacy_bbt () { return _legacy_bbt; }
197
198   private:
199
200         framecnt_t minute_to_frame (double time, framecnt_t frame_rate) const;
201         double frame_to_minute (framecnt_t frame, framecnt_t frame_rate) const;
202
203         /*  tempo ramp functions. zero-based with time in minutes,
204          * 'tick tempo' in ticks per minute and tempo in bpm.
205          *  time relative to section start.
206          */
207         double c_func (double end_tpm, double end_time) const;
208         double a_func (double begin_tpm, double end_tpm, double end_time) const;
209
210         double tempo_at_time (double time, double end_bpm, double end_time) const;
211         double time_at_tempo (double tempo, double end_bpm, double end_time) const;
212         double tick_tempo_at_time (double time, double end_tpm, double end_time) const;
213         double time_at_tick_tempo (double tick_tempo, double end_tpm, double end_time) const;
214
215         double tick_at_time (double time, double end_tpm, double end_time) const;
216         double time_at_tick (double tick, double end_tpm, double end_time) const;
217
218         double beat_at_time (double time, double end_tpm, double end_time) const;
219         double time_at_beat (double beat, double end_tpm, double end_time) const;
220
221         /* this value provides a fractional offset into the bar in which
222            the tempo section is located in. A value of 0.0 indicates that
223            it occurs on the first beat of the bar, a value of 0.5 indicates
224            that it occurs halfway through the bar and so on.
225
226            this enables us to keep the tempo change at the same relative
227            position within the bar if/when the meter changes.
228         */
229         double _bar_offset;
230         Type _type;
231         Timecode::BBT_Time _legacy_bbt;
232 };
233
234 typedef std::list<MetricSection*> Metrics;
235
236 /** Helper class to keep track of the Meter *AND* Tempo in effect
237     at a given point in time.
238 */
239 class LIBARDOUR_API TempoMetric {
240   public:
241         TempoMetric (const Meter& m, const Tempo& t)
242                 : _meter (&m), _tempo (&t), _frame (0) {}
243
244         void set_tempo (const Tempo& t)              { _tempo = &t; }
245         void set_meter (const Meter& m)              { _meter = &m; }
246         void set_frame (framepos_t f)                { _frame = f; }
247         void set_start (const double& t)             { _start = t; }
248
249         void set_metric (const MetricSection* section) {
250                 const MeterSection* meter;
251                 const TempoSection* tempo;
252                 if ((meter = dynamic_cast<const MeterSection*>(section))) {
253                         set_meter(*meter);
254                 } else if ((tempo = dynamic_cast<const TempoSection*>(section))) {
255                         set_tempo(*tempo);
256                 }
257
258                 set_frame(section->frame());
259                 set_start(section->start());
260         }
261
262         const Meter&              meter() const { return *_meter; }
263         const Tempo&              tempo() const { return *_tempo; }
264         framepos_t                frame() const { return _frame; }
265         const double& start() const { return _start; }
266
267   private:
268         const Meter*       _meter;
269         const Tempo*       _tempo;
270         framepos_t         _frame;
271         double             _start;
272 };
273
274 /** Tempo Map - mapping of timecode to musical time.
275  * convert audio-samples, sample-rate to Bar/Beat/Tick, Meter/Tempo
276  */
277 class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
278 {
279   public:
280         TempoMap (framecnt_t frame_rate);
281         ~TempoMap();
282
283         /* measure-based stuff */
284
285         enum BBTPointType {
286                 Bar,
287                 Beat,
288         };
289
290         struct BBTPoint {
291                 framepos_t          frame;
292                 const MeterSection* meter;
293                 const Tempo* tempo;
294                 uint32_t            bar;
295                 uint32_t            beat;
296
297                 BBTPoint (const MeterSection& m, const Tempo& t, framepos_t f,
298                           uint32_t b, uint32_t e)
299                         : frame (f), meter (&m), tempo (&t), bar (b), beat (e) {}
300
301                 Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); }
302                 operator Timecode::BBT_Time() const { return bbt(); }
303                 operator framepos_t() const { return frame; }
304                 bool is_bar() const { return beat == 1; }
305         };
306
307         template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
308                 Glib::Threads::RWLock::ReaderLock lm (lock);
309                 (obj.*method)(metrics);
310         }
311
312         void get_grid (std::vector<BBTPoint>&,
313                        framepos_t start, framepos_t end);
314
315         /* TEMPO- AND METER-SENSITIVE FUNCTIONS
316
317            bbt_time(), beat_at_frame(), frame_at_beat(), tick_at_frame(),
318            frame_at_tick(),frame_time() and bbt_duration_at()
319            are all sensitive to tempo and meter, and will give answers
320            that align with the grid formed by tempo and meter sections.
321
322            They SHOULD NOT be used to determine the position of events
323            whose location is canonically defined in beats.
324         */
325
326         void bbt_time (framepos_t when, Timecode::BBT_Time&);
327
328         double tick_at_frame (framecnt_t frame) const;
329         framecnt_t frame_at_tick (double tick) const;
330
331         double beat_at_frame (framecnt_t frame) const;
332         framecnt_t frame_at_beat (double beat) const;
333
334         framepos_t frame_time (const Timecode::BBT_Time&);
335         framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir);
336
337         /* TEMPO-SENSITIVE FUNCTIONS
338
339            These next 4 functions will all take tempo in account and should be
340            used to determine position (and in the last case, distance in beats)
341            when tempo matters but meter does not.
342
343            They SHOULD be used to determine the position of events
344            whose location is canonically defined in beats.
345         */
346
347         framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b) const;
348         framepos_t framepos_plus_beats (framepos_t, Evoral::Beats) const;
349         framepos_t framepos_minus_beats (framepos_t, Evoral::Beats) const;
350         Evoral::Beats framewalk_to_beats (framepos_t pos, framecnt_t distance) const;
351
352         static const Tempo& default_tempo() { return _default_tempo; }
353         static const Meter& default_meter() { return _default_meter; }
354
355         const Tempo tempo_at (framepos_t) const;
356         double frames_per_beat_at (framepos_t, framecnt_t sr) const;
357
358         const Meter& meter_at (framepos_t) const;
359
360         const TempoSection& tempo_section_at (framepos_t) const;
361         const MeterSection& meter_section_at (framepos_t) const;
362
363         void add_tempo (const Tempo&, double where, TempoSection::Type type);
364         void add_meter (const Meter&, double start, Timecode::BBT_Time where);
365
366         void remove_tempo (const TempoSection&, bool send_signal);
367         void remove_meter (const MeterSection&, bool send_signal);
368
369         void replace_tempo (const TempoSection&, const Tempo&, const double& where, TempoSection::Type type);
370         void gui_set_tempo_frame (TempoSection&, framepos_t where, double beat);
371         void replace_meter (const MeterSection&, const Meter&, const double& start, const Timecode::BBT_Time& where);
372
373         framepos_t round_to_bar  (framepos_t frame, RoundMode dir);
374         framepos_t round_to_beat (framepos_t frame, RoundMode dir);
375         framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir);
376
377         void set_length (framepos_t frames);
378
379         XMLNode& get_state (void);
380         int set_state (const XMLNode&, int version);
381
382         void dump (std::ostream&) const;
383         void clear ();
384
385         TempoMetric metric_at (Timecode::BBT_Time bbt) const;
386
387         /** Return the TempoMetric at frame @p t, and point @p last to the latest
388          * metric change <= t, if it is non-NULL.
389          */
390         TempoMetric metric_at (framepos_t, Metrics::const_iterator* last=NULL) const;
391
392         Metrics::const_iterator metrics_end() { return metrics.end(); }
393
394         void change_existing_tempo_at (framepos_t, double bpm, double note_type);
395         void change_initial_tempo (double bpm, double note_type);
396
397         void insert_time (framepos_t, framecnt_t);
398         bool remove_time (framepos_t where, framecnt_t amount);  //returns true if anything was moved
399
400         int n_tempos () const;
401         int n_meters () const;
402
403         framecnt_t frame_rate () const { return _frame_rate; }
404
405         PBD::Signal0<void> MetricPositionChanged;
406
407         double bbt_to_beats (Timecode::BBT_Time bbt);
408
409 private:
410
411         friend class ::BBTTest;
412         friend class ::FrameposPlusBeatsTest;
413         friend class ::TempoTest;
414
415         static Tempo    _default_tempo;
416         static Meter    _default_meter;
417
418         Metrics                       metrics;
419         framecnt_t                    _frame_rate;
420         mutable Glib::Threads::RWLock lock;
421
422         void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1);
423
424         void _extend_map (TempoSection* tempo, MeterSection* meter,
425                           Metrics::iterator next_metric,
426                           Timecode::BBT_Time current, framepos_t current_frame, framepos_t end);
427
428         framepos_t round_to_type (framepos_t fr, RoundMode dir, BBTPointType);
429
430         const MeterSection& first_meter() const;
431         MeterSection&       first_meter();
432         const TempoSection& first_tempo() const;
433         TempoSection&       first_tempo();
434
435         Timecode::BBT_Time beats_to_bbt (double beats);
436
437         void do_insert (MetricSection* section);
438
439         void add_tempo_locked (const Tempo&, double where, bool recompute, TempoSection::Type type);
440         void add_meter_locked (const Meter&, double start, Timecode::BBT_Time where, bool recompute);
441
442         bool remove_tempo_locked (const TempoSection&);
443         bool remove_meter_locked (const MeterSection&);
444
445 };
446
447 }; /* namespace ARDOUR */
448
449 std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&);
450 std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&);
451 std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&);
452
453 #endif /* __ardour_tempo_h__ */