2 * Copyright (C) 2006-2017 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2006 Hans Fugal <hans@fugal.net>
4 * Copyright (C) 2007-2015 David Robillard <d@drobilla.net>
5 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
6 * Copyright (C) 2015-2017 Ben Loftis <ben@harrisonconsoles.com>
7 * Copyright (C) 2015-2017 Nick Mainsbridge <mainsbridge@gmail.com>
8 * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
9 * Copyright (C) 2015 Colin Fletcher <colin.m.fletcher@googlemail.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #ifndef __ardour_tempo_h__
27 #define __ardour_tempo_h__
33 #include <glibmm/threads.h>
36 #include "pbd/enum_convert.h"
38 #include "pbd/stateful.h"
39 #include "pbd/statefuldestructible.h"
41 #include "temporal/beats.h"
43 #include "ardour/ardour.h"
46 class FrameposPlusBeatsTest;
47 class FrameposMinusBeatsTest;
56 // Find a better place for these
57 LIBARDOUR_API bool bbt_time_to_string (const Timecode::BBT_Time& bbt, std::string& str);
58 LIBARDOUR_API bool string_to_bbt_time (const std::string& str, Timecode::BBT_Time& bbt);
60 /** Tempo, the speed at which musical time progresses (BPM). */
61 class LIBARDOUR_API Tempo {
64 * @param npm Note Types per minute
65 * @param type Note Type (default `4': quarter note)
67 Tempo (double npm, double type=4.0) // defaulting to quarter note
68 : _note_types_per_minute (npm), _note_type (type), _end_note_types_per_minute (npm) {}
69 Tempo (double start_npm, double type, double end_npm)
70 : _note_types_per_minute (start_npm), _note_type (type), _end_note_types_per_minute (end_npm) {}
72 double note_types_per_minute () const { return _note_types_per_minute; }
73 double note_types_per_minute (double note_type) const { return (_note_types_per_minute / _note_type) * note_type; }
74 void set_note_types_per_minute (double npm) { _note_types_per_minute = npm; }
75 double note_type () const { return _note_type; }
77 double quarter_notes_per_minute () const { return note_types_per_minute (4.0); }
78 double pulses_per_minute () const { return note_types_per_minute (1.0); }
80 double end_note_types_per_minute () const { return _end_note_types_per_minute; }
81 double end_note_types_per_minute (double note_type) const { return (_end_note_types_per_minute / _note_type) * note_type; }
82 void set_end_note_types_per_minute (double npm) { _end_note_types_per_minute = npm; }
84 double end_quarter_notes_per_minute () const { return end_note_types_per_minute (4.0); }
85 double end_pulses_per_minute () const { return end_note_types_per_minute (1.0); }
87 /** audio samples per note type.
88 * if you want an instantaneous value for this, use TempoMap::samples_per_quarter_note_at() instead.
89 * @param sr samplerate
91 double samples_per_note_type (samplecnt_t sr) const {
92 return (60.0 * sr) / _note_types_per_minute;
94 /** audio samples per quarter note.
95 * if you want an instantaneous value for this, use TempoMap::samples_per_quarter_note_at() instead.
96 * @param sr samplerate
98 double samples_per_quarter_note (samplecnt_t sr) const {
99 return (60.0 * sr) / quarter_notes_per_minute ();
103 double _note_types_per_minute;
105 double _end_note_types_per_minute;
108 /** Meter, or time signature (beats per bar, and which note type is a beat). */
109 class LIBARDOUR_API Meter {
111 Meter (double dpb, double bt)
112 : _divisions_per_bar (dpb), _note_type (bt) {}
114 double divisions_per_bar () const { return _divisions_per_bar; }
115 double note_divisor() const { return _note_type; }
117 double samples_per_bar (const Tempo&, samplecnt_t sr) const;
118 double samples_per_grid (const Tempo&, samplecnt_t sr) const;
120 inline bool operator==(const Meter& other)
121 { return _divisions_per_bar == other.divisions_per_bar() && _note_type == other.note_divisor(); }
124 /** The number of divisions in a bar. This is a floating point value because
125 there are musical traditions on our planet that do not limit
126 themselves to integral numbers of beats per bar.
128 double _divisions_per_bar;
130 /** The type of "note" that a division represents. For example, 4.0 is
131 a quarter (crotchet) note, 8.0 is an eighth (quaver) note, etc.
136 /** A section of timeline with a certain Tempo or Meter. */
137 class LIBARDOUR_API MetricSection {
139 MetricSection (double pulse, double minute, PositionLockStyle pls, bool is_tempo, samplecnt_t sample_rate)
140 : _pulse (pulse), _minute (minute), _initial (false), _position_lock_style (pls), _is_tempo (is_tempo), _sample_rate (sample_rate) {}
142 virtual ~MetricSection() {}
144 const double& pulse () const { return _pulse; }
145 void set_pulse (double pulse) { _pulse = pulse; }
147 double minute() const { return _minute; }
148 virtual void set_minute (double m) {
152 samplepos_t sample () const { return sample_at_minute (_minute); }
154 void set_initial (bool yn) { _initial = yn; }
155 bool initial() const { return _initial; }
157 /* MeterSections are not stateful in the full sense,
158 but we do want them to control their own
159 XML state information.
161 virtual XMLNode& get_state() const = 0;
163 virtual int set_state (const XMLNode&, int version);
165 PositionLockStyle position_lock_style () const { return _position_lock_style; }
166 void set_position_lock_style (PositionLockStyle ps) { _position_lock_style = ps; }
167 bool is_tempo () const { return _is_tempo; }
169 samplepos_t sample_at_minute (const double& time) const;
170 double minute_at_sample (const samplepos_t sample) const;
173 void add_state_to_node (XMLNode& node) const;
180 PositionLockStyle _position_lock_style;
181 const bool _is_tempo;
182 samplecnt_t _sample_rate;
185 /** A section of timeline with a certain Meter. */
186 class LIBARDOUR_API MeterSection : public MetricSection, public Meter {
188 MeterSection (double pulse, double minute, double beat, const Timecode::BBT_Time& bbt, double bpb, double note_type, PositionLockStyle pls, samplecnt_t sr)
189 : MetricSection (pulse, minute, pls, false, sr), Meter (bpb, note_type), _bbt (bbt), _beat (beat) {}
191 MeterSection (const XMLNode&, const samplecnt_t sample_rate);
193 static const std::string xml_state_node_name;
195 XMLNode& get_state() const;
197 void set_beat (std::pair<double, Timecode::BBT_Time>& w) {
202 const Timecode::BBT_Time& bbt() const { return _bbt; }
203 const double& beat () const { return _beat; }
204 void set_beat (double beat) { _beat = beat; }
207 Timecode::BBT_Time _bbt;
211 /** A section of timeline with a certain Tempo. */
212 class LIBARDOUR_API TempoSection : public MetricSection, public Tempo {
219 TempoSection (const double& pulse, const double& minute, Tempo tempo, PositionLockStyle pls, samplecnt_t sr)
220 : MetricSection (pulse, minute, pls, true, sr), Tempo (tempo), _c (0.0), _active (true), _locked_to_meter (false), _clamped (false) {}
222 TempoSection (const XMLNode&, const samplecnt_t sample_rate);
224 static const std::string xml_state_node_name;
226 XMLNode& get_state() const;
228 double c () const { return _c; }
229 void set_c (double c) { _c = c; }
231 Type type () const { if (note_types_per_minute() == end_note_types_per_minute()) { return Constant; } else { return Ramp; } }
233 bool active () const { return _active; }
234 void set_active (bool yn) { _active = yn; }
236 bool locked_to_meter () const { return _locked_to_meter; }
237 void set_locked_to_meter (bool yn) { _locked_to_meter = yn; }
239 bool clamped () const { return _clamped; }
240 void set_clamped (bool yn) { _clamped = yn; }
242 Tempo tempo_at_minute (const double& minute) const;
243 double minute_at_ntpm (const double& ntpm, const double& pulse) const;
245 Tempo tempo_at_pulse (const double& pulse) const;
246 double pulse_at_ntpm (const double& ntpm, const double& minute) const;
248 double pulse_at_minute (const double& minute) const;
249 double minute_at_pulse (const double& pulse) const;
251 double compute_c_pulse (const double& end_ntpm, const double& end_pulse) const;
252 double compute_c_minute (const double& end_ntpm, const double& end_minute) const;
254 double pulse_at_sample (const samplepos_t sample) const;
255 samplepos_t sample_at_pulse (const double& pulse) const;
257 Timecode::BBT_Time legacy_bbt () { return _legacy_bbt; }
261 /* tempo ramp functions. zero-based with time in minutes,
262 * 'tick tempo' in ticks per minute and tempo in bpm.
263 * time relative to section start.
265 double a_func (double end_tpm, double c_func) const;
266 double c_func (double end_tpm, double end_time) const;
268 double _tempo_at_time (const double& time) const;
269 double _time_at_tempo (const double& tempo) const;
271 double _tempo_at_pulse (const double& pulse) const;
272 double _pulse_at_tempo (const double& tempo) const;
274 double _pulse_at_time (const double& time) const;
275 double _time_at_pulse (const double& pulse) const;
277 /* this value provides a fractional offset into the bar in which
278 the tempo section is located in. A value of 0.0 indicates that
279 it occurs on the first beat of the bar, a value of 0.5 indicates
280 that it occurs halfway through the bar and so on.
282 this enables us to keep the tempo change at the same relative
283 position within the bar if/when the meter changes.
288 bool _locked_to_meter;
290 Timecode::BBT_Time _legacy_bbt;
293 typedef std::list<MetricSection*> Metrics;
295 /** Helper class to keep track of the Meter *AND* Tempo in effect
296 at a given point in time.
298 class LIBARDOUR_API TempoMetric {
300 TempoMetric (const Meter& m, const Tempo& t)
301 : _meter (&m), _tempo (&t), _minute (0.0), _pulse (0.0) {}
303 void set_tempo (const Tempo& t) { _tempo = &t; }
304 void set_meter (const Meter& m) { _meter = &m; }
305 void set_minute (double m) { _minute = m; }
306 void set_pulse (const double& p) { _pulse = p; }
308 void set_metric (const MetricSection* section) {
309 const MeterSection* meter;
310 const TempoSection* tempo;
311 if ((meter = dynamic_cast<const MeterSection*>(section))) {
313 } else if ((tempo = dynamic_cast<const TempoSection*>(section))) {
317 set_minute (section->minute());
318 set_pulse (section->pulse());
321 const Meter& meter() const { return *_meter; }
322 const Tempo& tempo() const { return *_tempo; }
323 double minute() const { return _minute; }
324 const double& pulse() const { return _pulse; }
333 /** Tempo Map - mapping of timecode to musical time.
334 * convert audio-samples, sample-rate to Bar/Beat/Tick, Meter/Tempo
336 class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
339 TempoMap (samplecnt_t sample_rate);
342 TempoMap& operator= (TempoMap const &);
344 /* measure-based stuff */
359 BBTPoint (const MeterSection& m, const Tempo& t, samplepos_t f,
360 uint32_t b, uint32_t e, double qnote)
361 : meter (m), tempo (t), sample (f), bar (b), beat (e), qn (qnote) {}
363 Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); }
364 operator Timecode::BBT_Time() const { return bbt(); }
365 operator samplepos_t() const { return sample; }
366 bool is_bar() const { return beat == 1; }
369 template<class T> void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) {
370 Glib::Threads::RWLock::ReaderLock lm (lock);
371 (obj.*method)(_metrics);
374 void get_grid (std::vector<BBTPoint>&,
375 samplepos_t start, samplepos_t end, uint32_t bar_mod = 0);
377 static const Tempo& default_tempo() { return _default_tempo; }
378 static const Meter& default_meter() { return _default_meter; }
380 /* because tempi may be ramped, this is only valid for the instant requested.*/
381 double samples_per_quarter_note_at (const samplepos_t, const samplecnt_t sr) const;
383 const TempoSection& tempo_section_at_sample (samplepos_t sample) const;
384 TempoSection& tempo_section_at_sample (samplepos_t sample);
385 const MeterSection& meter_section_at_sample (samplepos_t sample) const;
386 const MeterSection& meter_section_at_beat (double beat) const;
388 TempoSection* previous_tempo_section (TempoSection*) const;
389 TempoSection* next_tempo_section (TempoSection*) const;
391 /** add a tempo section locked to pls. ignored values will be set in recompute_tempi()
392 * @param pulse pulse position of new section. ignored if \param pls == AudioTime
393 * @param sample frame position of new section. ignored if \param pls == MusicTime
394 * @param pls the position lock style
396 TempoSection* add_tempo (const Tempo&, const double& pulse, const samplepos_t sample, PositionLockStyle pls);
398 /** add a meter section locked to \param pls . ignored values will be set in recompute_meters()
399 * @param meter the Meter to be added
400 * @param where bbt position of new section
401 * @param sample frame position of new section. ignored if \param pls == MusicTime
403 * note that \param sample may also be ignored if it would create an un-solvable map
404 * (previous audio-locked tempi may place the requested beat at an earlier time than sample)
405 * in which case the new meter will be placed at the specified BBT.
406 * @param pls the position lock style
408 * adding an audio-locked meter will add a meter-locked tempo section at the meter position.
409 * the meter-locked tempo tempo will be the Tempo at the beat
411 MeterSection* add_meter (const Meter& meter, const Timecode::BBT_Time& where, samplepos_t sample, PositionLockStyle pls);
413 void remove_tempo (const TempoSection&, bool send_signal);
414 void remove_meter (const MeterSection&, bool send_signal);
416 void replace_tempo (TempoSection&, const Tempo&, const double& pulse, const samplepos_t sample, PositionLockStyle pls);
418 void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where, samplepos_t sample, PositionLockStyle pls);
420 MusicSample round_to_bar (samplepos_t sample, RoundMode dir);
421 MusicSample round_to_beat (samplepos_t sample, RoundMode dir);
422 MusicSample round_to_quarter_note_subdivision (samplepos_t fr, int sub_num, RoundMode dir);
424 void set_length (samplepos_t samples);
426 XMLNode& get_state (void);
427 int set_state (const XMLNode&, int version);
429 void dump (std::ostream&) const;
432 TempoMetric metric_at (Timecode::BBT_Time bbt) const;
434 /** Return the TempoMetric at sample @p t, and point @p last to the latest
435 * metric change <= t, if it is non-NULL.
437 TempoMetric metric_at (samplepos_t, Metrics::const_iterator* last=NULL) const;
439 Metrics::const_iterator metrics_end() { return _metrics.end(); }
441 void change_existing_tempo_at (samplepos_t, double bpm, double note_type, double end_ntpm);
442 void change_initial_tempo (double ntpm, double note_type, double end_ntpm);
444 void insert_time (samplepos_t, samplecnt_t);
445 bool remove_time (samplepos_t where, samplecnt_t amount); //returns true if anything was moved
447 int n_tempos () const;
448 int n_meters () const;
450 samplecnt_t sample_rate () const { return _sample_rate; }
452 /* TEMPO- AND METER-SENSITIVE FUNCTIONS
454 bbt_at_sample(), sample_at_bbt(), beat_at_sample(), sample_at_beat()
455 and bbt_duration_at()
456 are all sensitive to tempo and meter, and will give answers
457 that align with the grid formed by tempo and meter sections.
459 They SHOULD NOT be used to determine the position of events
460 whose location is canonically defined in Temporal::Beats.
463 double beat_at_sample (const samplecnt_t sample) const;
464 samplepos_t sample_at_beat (const double& beat) const;
466 const Meter& meter_at_sample (samplepos_t) const;
468 /* bbt - it's nearly always better to use meter-based beat (above)
469 unless tick resolution is desirable.
471 Timecode::BBT_Time bbt_at_sample (samplepos_t when);
472 Timecode::BBT_Time bbt_at_sample_rt (samplepos_t when);
473 samplepos_t sample_at_bbt (const Timecode::BBT_Time&);
475 double beat_at_bbt (const Timecode::BBT_Time& bbt);
476 Timecode::BBT_Time bbt_at_beat (const double& beats);
478 double quarter_note_at_bbt (const Timecode::BBT_Time& bbt);
479 double quarter_note_at_bbt_rt (const Timecode::BBT_Time& bbt);
480 Timecode::BBT_Time bbt_at_quarter_note (const double& quarter_note);
482 samplecnt_t bbt_duration_at (samplepos_t, const Timecode::BBT_Time&, int dir);
483 samplepos_t samplepos_plus_bbt (samplepos_t pos, Timecode::BBT_Time b) const;
485 /* TEMPO-SENSITIVE FUNCTIONS
487 These next 2 functions will all take tempo in account and should be
488 used to determine position (and in the last case, distance in beats)
489 when tempo matters but meter does not.
491 They SHOULD be used to determine the position of events
492 whose location is canonically defined in Temporal::Beats.
495 samplepos_t samplepos_plus_qn (samplepos_t, Temporal::Beats) const;
496 Temporal::Beats framewalk_to_qn (samplepos_t pos, samplecnt_t distance) const;
498 /* quarter note related functions are also tempo-sensitive and ignore meter.
499 quarter notes may be compared with and assigned to Temporal::Beats.
501 double quarter_note_at_sample (const samplepos_t sample) const;
502 double quarter_note_at_sample_rt (const samplepos_t sample) const;
503 samplepos_t sample_at_quarter_note (const double quarter_note) const;
505 samplecnt_t samples_between_quarter_notes (const double start, const double end) const;
506 double quarter_notes_between_samples (const samplecnt_t start, const samplecnt_t end) const;
508 double quarter_note_at_beat (const double beat) const;
509 double beat_at_quarter_note (const double beat) const;
511 /* obtain a musical subdivision via a sample position and magic note divisor.*/
512 double exact_qn_at_sample (const samplepos_t sample, const int32_t sub_num) const;
513 double exact_beat_at_sample (const samplepos_t sample, const int32_t sub_num) const;
515 Tempo tempo_at_sample (const samplepos_t sample) const;
516 samplepos_t sample_at_tempo (const Tempo& tempo) const;
517 Tempo tempo_at_quarter_note (const double& beat) const;
518 double quarter_note_at_tempo (const Tempo& tempo) const;
520 void gui_set_tempo_position (TempoSection*, const samplepos_t sample, const int& sub_num);
521 void gui_set_meter_position (MeterSection*, const samplepos_t sample);
522 bool gui_change_tempo (TempoSection*, const Tempo& bpm);
523 void gui_stretch_tempo (TempoSection* tempo, const samplepos_t sample, const samplepos_t end_sample, const double start_qnote, const double end_qnote);
524 void gui_stretch_tempo_end (TempoSection* tempo, const samplepos_t sample, const samplepos_t end_sample);
525 bool gui_twist_tempi (TempoSection* first, const Tempo& bpm, const samplepos_t sample, const samplepos_t end_sample);
527 std::pair<double, samplepos_t> predict_tempo_position (TempoSection* section, const Timecode::BBT_Time& bbt);
528 bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt);
530 PBD::Signal1<void,const PBD::PropertyChange&> MetricPositionChanged;
531 void fix_legacy_session();
532 void fix_legacy_end_session();
534 samplepos_t music_origin ();
537 /* prevent copy construction */
538 TempoMap (TempoMap const&);
540 TempoSection* previous_tempo_section_locked (const Metrics& metrics, TempoSection*) const;
541 TempoSection* next_tempo_section_locked (const Metrics& metrics, TempoSection*) const;
543 double beat_at_minute_locked (const Metrics& metrics, const double& minute) const;
544 double minute_at_beat_locked (const Metrics& metrics, const double& beat) const;
546 double pulse_at_beat_locked (const Metrics& metrics, const double& beat) const;
547 double beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const;
549 double pulse_at_minute_locked (const Metrics& metrics, const double& minute) const;
550 double minute_at_pulse_locked (const Metrics& metrics, const double& pulse) const;
552 Tempo tempo_at_minute_locked (const Metrics& metrics, const double& minute) const;
553 double minute_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const;
555 Tempo tempo_at_pulse_locked (const Metrics& metrics, const double& pulse) const;
556 double pulse_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const;
558 Timecode::BBT_Time bbt_at_minute_locked (const Metrics& metrics, const double& minute) const;
559 double minute_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time&) const;
561 double beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const ;
562 Timecode::BBT_Time bbt_at_beat_locked (const Metrics& metrics, const double& beats) const;
564 double pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const;
565 Timecode::BBT_Time bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const;
567 double minutes_between_quarter_notes_locked (const Metrics& metrics, const double start_qn, const double end_qn) const;
568 double quarter_notes_between_samples_locked (const Metrics& metrics, const samplecnt_t start, const samplecnt_t end) const;
570 const TempoSection& tempo_section_at_minute_locked (const Metrics& metrics, double minute) const;
571 TempoSection& tempo_section_at_minute_locked (const Metrics& metrics, double minute);
572 const TempoSection& tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const;
574 const MeterSection& meter_section_at_minute_locked (const Metrics& metrics, double minute) const;
575 const MeterSection& meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const;
577 bool check_solved (const Metrics& metrics) const;
578 bool set_active_tempi (const Metrics& metrics, const samplepos_t sample);
580 bool solve_map_minute (Metrics& metrics, TempoSection* section, const double& minute);
581 bool solve_map_pulse (Metrics& metrics, TempoSection* section, const double& pulse);
582 bool solve_map_minute (Metrics& metrics, MeterSection* section, const double& minute);
583 bool solve_map_bbt (Metrics& metrics, MeterSection* section, const Timecode::BBT_Time& bbt);
585 double exact_beat_at_sample_locked (const Metrics& metrics, const samplepos_t sample, const int32_t sub_num) const;
586 double exact_qn_at_sample_locked (const Metrics& metrics, const samplepos_t sample, const int32_t sub_num) const;
588 double minute_at_sample (const samplepos_t sample) const;
589 samplepos_t sample_at_minute (const double minute) const;
591 friend class ::BBTTest;
592 friend class ::FrameposPlusBeatsTest;
593 friend class ::FrameposMinusBeatsTest;
594 friend class ::TempoTest;
596 static Tempo _default_tempo;
597 static Meter _default_meter;
600 samplecnt_t _sample_rate;
601 mutable Glib::Threads::RWLock lock;
603 void recompute_tempi (Metrics& metrics);
604 void recompute_meters (Metrics& metrics);
605 void recompute_map (Metrics& metrics, samplepos_t end = -1);
607 MusicSample round_to_type (samplepos_t fr, RoundMode dir, BBTPointType);
609 const MeterSection& first_meter() const;
610 MeterSection& first_meter();
611 const TempoSection& first_tempo() const;
612 TempoSection& first_tempo();
614 void do_insert (MetricSection* section);
616 TempoSection* add_tempo_locked (const Tempo&, double pulse, double minute
617 , PositionLockStyle pls, bool recompute, bool locked_to_meter = false, bool clamped = false);
619 MeterSection* add_meter_locked (const Meter&, const Timecode::BBT_Time& where, samplepos_t sample, PositionLockStyle pls, bool recompute);
621 bool remove_tempo_locked (const TempoSection&);
622 bool remove_meter_locked (const MeterSection&);
624 TempoSection* copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section) const;
625 MeterSection* copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section) const;
628 }; /* namespace ARDOUR */
630 LIBARDOUR_API std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&);
631 LIBARDOUR_API std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&);
632 LIBARDOUR_API std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&);
635 DEFINE_ENUM_CONVERT (ARDOUR::TempoSection::Type)
638 #endif /* __ardour_tempo_h__ */