X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fardour%2Ftempo.h;h=c200eafadc9257d7e21b37da134f16fb59fd0281;hb=c656aaab3c0c66ea0cde210950af341a3d71c559;hp=f3b94e05ee8e9f9f25127365d6245119a302b3fc;hpb=d1a075110afa8efe1944ba7a9a2ba6be985c8291;p=ardour.git diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index f3b94e05ee..c200eafadc 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -27,16 +27,18 @@ #include #include "pbd/undo.h" +#include "pbd/enum_convert.h" #include "pbd/stateful.h" #include "pbd/statefuldestructible.h" -#include "evoral/Beats.hpp" +#include "temporal/beats.h" #include "ardour/ardour.h" class BBTTest; class FrameposPlusBeatsTest; +class FrameposMinusBeatsTest; class TempoTest; class XMLNode; @@ -45,36 +47,56 @@ namespace ARDOUR { class Meter; class TempoMap; +// Find a better place for these +LIBARDOUR_API bool bbt_time_to_string (const Timecode::BBT_Time& bbt, std::string& str); +LIBARDOUR_API bool string_to_bbt_time (const std::string& str, Timecode::BBT_Time& bbt); + /** Tempo, the speed at which musical time progresses (BPM). */ class LIBARDOUR_API Tempo { public: /** - * @param bpm Beats Per Minute + * @param npm Note Types per minute * @param type Note Type (default `4': quarter note) */ - Tempo (double bpm, double type=4.0) // defaulting to quarter note - : _beats_per_minute (bpm), _note_type(type) {} - - /* ..or more aptly 'pulse divisions per minute'. - Nothing to do with actual beats, which are defined by the meter and tempo. - */ - double beats_per_minute () const { return _beats_per_minute; } - void set_beats_per_minute (double bpm) { _beats_per_minute = bpm; } + Tempo (double npm, double type=4.0) // defaulting to quarter note + : _note_types_per_minute (npm), _note_type (type), _end_note_types_per_minute (npm) {} + Tempo (double start_npm, double type, double end_npm) + : _note_types_per_minute (start_npm), _note_type (type), _end_note_types_per_minute (end_npm) {} + + double note_types_per_minute () const { return _note_types_per_minute; } + double note_types_per_minute (double note_type) const { return (_note_types_per_minute / _note_type) * note_type; } + void set_note_types_per_minute (double npm) { _note_types_per_minute = npm; } double note_type () const { return _note_type; } - double pulses_per_minute () const { return _beats_per_minute / _note_type; } - /** audio samples per beat + + double quarter_notes_per_minute () const { return note_types_per_minute (4.0); } + double pulses_per_minute () const { return note_types_per_minute (1.0); } + + double end_note_types_per_minute () const { return _end_note_types_per_minute; } + double end_note_types_per_minute (double note_type) const { return (_end_note_types_per_minute / _note_type) * note_type; } + void set_end_note_types_per_minute (double npm) { _end_note_types_per_minute = npm; } + + double end_quarter_notes_per_minute () const { return end_note_types_per_minute (4.0); } + double end_pulses_per_minute () const { return end_note_types_per_minute (1.0); } + + /** audio samples per note type. + * if you want an instantaneous value for this, use TempoMap::samples_per_quarter_note_at() instead. * @param sr samplerate */ - double frames_per_beat (framecnt_t sr) const { - return (60.0 * sr) / _beats_per_minute; + double samples_per_note_type (samplecnt_t sr) const { + return (60.0 * sr) / _note_types_per_minute; } - double frames_per_pulse (framecnt_t sr) const { - return (_note_type * 60.0 * sr) / _beats_per_minute; + /** audio samples per quarter note. + * if you want an instantaneous value for this, use TempoMap::samples_per_quarter_note_at() instead. + * @param sr samplerate + */ + double samples_per_quarter_note (samplecnt_t sr) const { + return (60.0 * sr) / quarter_notes_per_minute (); } protected: - double _beats_per_minute; + double _note_types_per_minute; double _note_type; + double _end_note_types_per_minute; }; /** Meter, or time signature (beats per bar, and which note type is a beat). */ @@ -86,8 +108,11 @@ class LIBARDOUR_API Meter { double divisions_per_bar () const { return _divisions_per_bar; } double note_divisor() const { return _note_type; } - double frames_per_bar (const Tempo&, framecnt_t sr) const; - double frames_per_grid (const Tempo&, framecnt_t sr) const; + double samples_per_bar (const Tempo&, samplecnt_t sr) const; + double samples_per_grid (const Tempo&, samplecnt_t sr) const; + + inline bool operator==(const Meter& other) + { return _divisions_per_bar == other.divisions_per_bar() && _note_type == other.note_divisor(); } protected: /** The number of divisions in a bar. This is a floating point value because @@ -105,21 +130,23 @@ class LIBARDOUR_API Meter { /** A section of timeline with a certain Tempo or Meter. */ class LIBARDOUR_API MetricSection { public: - MetricSection (double pulse, framepos_t frame, PositionLockStyle pls) - : _pulse (pulse), _frame (frame), _movable (true), _position_lock_style (pls) {} + MetricSection (double pulse, double minute, PositionLockStyle pls, bool is_tempo, samplecnt_t sample_rate) + : _pulse (pulse), _minute (minute), _initial (false), _position_lock_style (pls), _is_tempo (is_tempo), _sample_rate (sample_rate) {} virtual ~MetricSection() {} const double& pulse () const { return _pulse; } void set_pulse (double pulse) { _pulse = pulse; } - framepos_t frame() const { return _frame; } - virtual void set_frame (framepos_t f) { - _frame = f; + double minute() const { return _minute; } + virtual void set_minute (double m) { + _minute = m; } - void set_movable (bool yn) { _movable = yn; } - bool movable() const { return _movable; } + samplepos_t sample () const { return sample_at_minute (_minute); } + + void set_initial (bool yn) { _initial = yn; } + bool initial() const { return _initial; } /* MeterSections are not stateful in the full sense, but we do want them to control their own @@ -127,38 +154,47 @@ class LIBARDOUR_API MetricSection { */ virtual XMLNode& get_state() const = 0; + virtual int set_state (const XMLNode&, int version); + PositionLockStyle position_lock_style () const { return _position_lock_style; } void set_position_lock_style (PositionLockStyle ps) { _position_lock_style = ps; } + bool is_tempo () const { return _is_tempo; } + + samplepos_t sample_at_minute (const double& time) const; + double minute_at_sample (const samplepos_t sample) const; + +protected: + void add_state_to_node (XMLNode& node) const; private: + double _pulse; - framepos_t _frame; - bool _movable; + double _minute; + bool _initial; PositionLockStyle _position_lock_style; + const bool _is_tempo; + samplecnt_t _sample_rate; }; /** A section of timeline with a certain Meter. */ class LIBARDOUR_API MeterSection : public MetricSection, public Meter { public: - MeterSection (double pulse, framepos_t frame, double beat, const Timecode::BBT_Time& bbt, double bpb, double note_type, PositionLockStyle pls) - : MetricSection (pulse, frame, pls), Meter (bpb, note_type), _bbt (bbt), _beat (beat) {} + MeterSection (double pulse, double minute, double beat, const Timecode::BBT_Time& bbt, double bpb, double note_type, PositionLockStyle pls, samplecnt_t sr) + : MetricSection (pulse, minute, pls, false, sr), Meter (bpb, note_type), _bbt (bbt), _beat (beat) {} - MeterSection (const XMLNode&); + MeterSection (const XMLNode&, const samplecnt_t sample_rate); static const std::string xml_state_node_name; XMLNode& get_state() const; - void set_pulse (double w) { - MetricSection::set_pulse (w); - } void set_beat (std::pair& w) { _beat = w.first; _bbt = w.second; } const Timecode::BBT_Time& bbt() const { return _bbt; } - const double& beat () const { return _beat; } + const double& beat () const { return _beat; } void set_beat (double beat) { _beat = beat; } private: @@ -174,20 +210,19 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { Constant, }; - TempoSection (const double& pulse, const framepos_t& frame, double qpm, double note_type, Type tempo_type, PositionLockStyle pls) - : MetricSection (pulse, frame, pls), Tempo (qpm, note_type), _type (tempo_type), _c_func (0.0), _active (true), _locked_to_meter (false) {} + TempoSection (const double& pulse, const double& minute, Tempo tempo, PositionLockStyle pls, samplecnt_t sr) + : MetricSection (pulse, minute, pls, true, sr), Tempo (tempo), _c (0.0), _active (true), _locked_to_meter (false), _clamped (false) {} - TempoSection (const XMLNode&); + TempoSection (const XMLNode&, const samplecnt_t sample_rate); static const std::string xml_state_node_name; XMLNode& get_state() const; - double c_func () const { return _c_func; } - void set_c_func (double c_func) { _c_func = c_func; } + double c () const { return _c; } + void set_c (double c) { _c = c; } - void set_type (Type type); - Type type () const { return _type; } + Type type () const { if (note_types_per_minute() == end_note_types_per_minute()) { return Constant; } else { return Ramp; } } bool active () const { return _active; } void set_active (bool yn) { _active = yn; } @@ -195,25 +230,28 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { bool locked_to_meter () const { return _locked_to_meter; } void set_locked_to_meter (bool yn) { _locked_to_meter = yn; } - double tempo_at_frame (const framepos_t& frame, const framecnt_t& frame_rate) const; - framepos_t frame_at_tempo (const double& ppm, const double& beat, const framecnt_t& frame_rate) const; + bool clamped () const { return _clamped; } + void set_clamped (bool yn) { _clamped = yn; } + + Tempo tempo_at_minute (const double& minute) const; + double minute_at_ntpm (const double& ntpm, const double& pulse) const; + + Tempo tempo_at_pulse (const double& pulse) const; + double pulse_at_ntpm (const double& ntpm, const double& minute) const; - double tempo_at_pulse (const double& pulse) const; - double pulse_at_tempo (const double& ppm, const framepos_t& frame, const framecnt_t& frame_rate) const; + double pulse_at_minute (const double& minute) const; + double minute_at_pulse (const double& pulse) const; - double pulse_at_frame (const framepos_t& frame, const framecnt_t& frame_rate) const; - frameoffset_t frame_at_pulse (const double& pulse, const framecnt_t& frame_rate) const; + double compute_c_pulse (const double& end_ntpm, const double& end_pulse) const; + double compute_c_minute (const double& end_ntpm, const double& end_minute) const; - double compute_c_func_pulse (const double& end_bpm, const double& end_pulse, const framecnt_t& frame_rate); - double compute_c_func_frame (const double& end_bpm, const framepos_t& end_frame, const framecnt_t& frame_rate) const; + double pulse_at_sample (const samplepos_t sample) const; + samplepos_t sample_at_pulse (const double& pulse) const; Timecode::BBT_Time legacy_bbt () { return _legacy_bbt; } private: - framepos_t minute_to_frame (const double& time, const framecnt_t& frame_rate) const; - double frame_to_minute (const framepos_t& frame, const framecnt_t& frame_rate) const; - /* tempo ramp functions. zero-based with time in minutes, * 'tick tempo' in ticks per minute and tempo in bpm. * time relative to section start. @@ -221,14 +259,14 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { double a_func (double end_tpm, double c_func) const; double c_func (double end_tpm, double end_time) const; - double pulse_tempo_at_time (const double& time) const; - double time_at_pulse_tempo (const double& pulse_tempo) const; + double _tempo_at_time (const double& time) const; + double _time_at_tempo (const double& tempo) const; - double pulse_tempo_at_pulse (const double& pulse) const; - double pulse_at_pulse_tempo (const double& pulse_tempo) const; + double _tempo_at_pulse (const double& pulse) const; + double _pulse_at_tempo (const double& tempo) const; - double pulse_at_time (const double& time) const; - double time_at_pulse (const double& pulse) const; + double _pulse_at_time (const double& time) const; + double _time_at_pulse (const double& pulse) const; /* this value provides a fractional offset into the bar in which the tempo section is located in. A value of 0.0 indicates that @@ -238,10 +276,11 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { this enables us to keep the tempo change at the same relative position within the bar if/when the meter changes. */ - Type _type; - double _c_func; + + double _c; bool _active; bool _locked_to_meter; + bool _clamped; Timecode::BBT_Time _legacy_bbt; }; @@ -253,11 +292,11 @@ typedef std::list Metrics; class LIBARDOUR_API TempoMetric { public: TempoMetric (const Meter& m, const Tempo& t) - : _meter (&m), _tempo (&t), _frame (0) {} + : _meter (&m), _tempo (&t), _minute (0.0), _pulse (0.0) {} void set_tempo (const Tempo& t) { _tempo = &t; } void set_meter (const Meter& m) { _meter = &m; } - void set_frame (framepos_t f) { _frame = f; } + void set_minute (double m) { _minute = m; } void set_pulse (const double& p) { _pulse = p; } void set_metric (const MetricSection* section) { @@ -269,19 +308,19 @@ class LIBARDOUR_API TempoMetric { set_tempo(*tempo); } - set_frame (section->frame()); + set_minute (section->minute()); set_pulse (section->pulse()); } const Meter& meter() const { return *_meter; } const Tempo& tempo() const { return *_tempo; } - framepos_t frame() const { return _frame; } + double minute() const { return _minute; } const double& pulse() const { return _pulse; } private: const Meter* _meter; const Tempo* _tempo; - framepos_t _frame; + double _minute; double _pulse; }; @@ -291,9 +330,11 @@ class LIBARDOUR_API TempoMetric { class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible { public: - TempoMap (framecnt_t frame_rate); + TempoMap (samplecnt_t sample_rate); ~TempoMap(); + TempoMap& operator= (TempoMap const &); + /* measure-based stuff */ enum BBTPointType { @@ -302,20 +343,20 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible }; struct BBTPoint { - framepos_t frame; Meter meter; Tempo tempo; - double c; + samplepos_t sample; uint32_t bar; uint32_t beat; + double qn; - BBTPoint (const MeterSection& m, const Tempo& t, framepos_t f, - uint32_t b, uint32_t e, double func_c) - : frame (f), meter (m.divisions_per_bar(), m.note_divisor()), tempo (t.beats_per_minute(), t.note_type()), c (func_c), bar (b), beat (e) {} + BBTPoint (const MeterSection& m, const Tempo& t, samplepos_t f, + uint32_t b, uint32_t e, double qnote) + : meter (m), tempo (t), sample (f), bar (b), beat (e), qn (qnote) {} Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); } operator Timecode::BBT_Time() const { return bbt(); } - operator framepos_t() const { return frame; } + operator samplepos_t() const { return sample; } bool is_bar() const { return beat == 1; } }; @@ -325,183 +366,238 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible } void get_grid (std::vector&, - framepos_t start, framepos_t end); - - /* TEMPO- AND METER-SENSITIVE FUNCTIONS - - bbt_time(), beat_at_frame(), frame_at_beat(), tick_at_frame(), - frame_at_tick(),frame_time() and bbt_duration_at() - are all sensitive to tempo and meter, and will give answers - that align with the grid formed by tempo and meter sections. - - They SHOULD NOT be used to determine the position of events - whose location is canonically defined in beats. - */ - - void bbt_time (framepos_t when, Timecode::BBT_Time&); - - double beat_at_frame (const framecnt_t& frame) const; - framecnt_t frame_at_beat (const double& beat) const; - - framepos_t frame_time (const Timecode::BBT_Time&); - framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir); - - /* TEMPO-SENSITIVE FUNCTIONS - - These next 4 functions will all take tempo in account and should be - used to determine position (and in the last case, distance in beats) - when tempo matters but meter does not. - - They SHOULD be used to determine the position of events - whose location is canonically defined in beats. - */ - - framepos_t framepos_plus_bbt (framepos_t pos, Timecode::BBT_Time b) const; - framepos_t framepos_plus_beats (framepos_t, Evoral::Beats) const; - framepos_t framepos_minus_beats (framepos_t, Evoral::Beats) const; - Evoral::Beats framewalk_to_beats (framepos_t pos, framecnt_t distance) const; + samplepos_t start, samplepos_t end, uint32_t bar_mod = 0); static const Tempo& default_tempo() { return _default_tempo; } static const Meter& default_meter() { return _default_meter; } - const Tempo tempo_at (const framepos_t& frame) const; - double frames_per_beat_at (const framepos_t&, const framecnt_t& sr) const; + /* because tempi may be ramped, this is only valid for the instant requested.*/ + double samples_per_quarter_note_at (const samplepos_t, const samplecnt_t sr) const; - const Meter& meter_at (framepos_t) const; - - const TempoSection& tempo_section_at (framepos_t frame) const; - const MeterSection& meter_section_at (framepos_t frame) const; + const TempoSection& tempo_section_at_sample (samplepos_t sample) const; + TempoSection& tempo_section_at_sample (samplepos_t sample); + const MeterSection& meter_section_at_sample (samplepos_t sample) const; const MeterSection& meter_section_at_beat (double beat) const; + TempoSection* previous_tempo_section (TempoSection*) const; + TempoSection* next_tempo_section (TempoSection*) const; - /** add a tempo section locked to pls. ignored values are set in recompute_tempos() + /** add a tempo section locked to pls. ignored values will be set in recompute_tempi() * @param pulse pulse position of new section. ignored if pls == AudioTime - * @param frame frame position of new section. ignored if pls == MusicTime + * @param sample frame position of new section. ignored if pls == MusicTime * @param type type of new tempo section (Ramp, Constant) */ - TempoSection* add_tempo (const Tempo&, const double& pulse, const framepos_t& frame, TempoSection::Type type, PositionLockStyle pls); + TempoSection* add_tempo (const Tempo&, const double& pulse, const samplepos_t sample, PositionLockStyle pls); - /** add an meter section locked to pls.. ignored values are set in recompute_meters() - * @param beat beat position of new section + /** add a meter section locked to pls.. ignored values will be set in recompute_meters() + * @param meter the Meter to be added * @param where bbt position of new section - * @param frame frame position of new section. ignored if pls == MusicTime + * @param sample frame position of new section. ignored if pls == MusicTime + * note that @sample may also be ignored if it would create an un-solvable map + * (previous audio-locked tempi may place the requested beat at an earlier time than sample) + * in which case the new meter will be placed at the specified BBT. + * @param pls the position lock style + * + * adding an audio-locked meter will add a meter-locked tempo section at the meter position. + * the meter-locked tempo tempo will be the Tempo at @beat */ - MeterSection* add_meter (const Meter&, const double& beat, const Timecode::BBT_Time& where, const framepos_t& frame, PositionLockStyle pls); + MeterSection* add_meter (const Meter& meter, const Timecode::BBT_Time& where, samplepos_t sample, PositionLockStyle pls); void remove_tempo (const TempoSection&, bool send_signal); void remove_meter (const MeterSection&, bool send_signal); - framepos_t predict_tempo_frame (TempoSection* section, const Timecode::BBT_Time& bbt); - double predict_tempo_pulse (TempoSection* section, const Timecode::BBT_Time& bbt); - - void replace_tempo (const TempoSection&, const Tempo&, const double& pulse, const framepos_t& frame - , TempoSection::Type type, PositionLockStyle pls); - - void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where, const framepos_t& frame - , PositionLockStyle pls); - - void gui_move_tempo_frame (TempoSection*, const framepos_t& frame); - void gui_move_tempo_beat (TempoSection*, const double& beat); - void gui_move_meter_frame (MeterSection*, const framepos_t& frame); - void gui_move_meter_bbt (MeterSection*, const Timecode::BBT_Time& bbt); - bool gui_change_tempo (TempoSection*, const Tempo& bpm); - void gui_dilate_tempo (TempoSection* tempo, const framepos_t& frame, const framepos_t& end_frame, const double& pulse); - - bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt); + void replace_tempo (TempoSection&, const Tempo&, const double& pulse, const samplepos_t sample, PositionLockStyle pls); - framepos_t round_to_bar (framepos_t frame, RoundMode dir); - framepos_t round_to_beat (framepos_t frame, RoundMode dir); - framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir); - void round_bbt (Timecode::BBT_Time& when, const int32_t& snap_divisor, RoundMode dir); + void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where, samplepos_t sample, PositionLockStyle pls); - void set_length (framepos_t frames); + MusicSample round_to_bar (samplepos_t sample, RoundMode dir); + MusicSample round_to_beat (samplepos_t sample, RoundMode dir); + MusicSample round_to_quarter_note_subdivision (samplepos_t fr, int sub_num, RoundMode dir); - void fix_legacy_session(); + void set_length (samplepos_t samples); XMLNode& get_state (void); int set_state (const XMLNode&, int version); - void dump (const Metrics& metrics, std::ostream&) const; + void dump (std::ostream&) const; void clear (); TempoMetric metric_at (Timecode::BBT_Time bbt) const; - /** Return the TempoMetric at frame @p t, and point @p last to the latest + /** Return the TempoMetric at sample @p t, and point @p last to the latest * metric change <= t, if it is non-NULL. */ - TempoMetric metric_at (framepos_t, Metrics::const_iterator* last=NULL) const; + TempoMetric metric_at (samplepos_t, Metrics::const_iterator* last=NULL) const; Metrics::const_iterator metrics_end() { return _metrics.end(); } - void change_existing_tempo_at (framepos_t, double bpm, double note_type); - void change_initial_tempo (double bpm, double note_type); + void change_existing_tempo_at (samplepos_t, double bpm, double note_type, double end_ntpm); + void change_initial_tempo (double ntpm, double note_type, double end_ntpm); - void insert_time (framepos_t, framecnt_t); - bool remove_time (framepos_t where, framecnt_t amount); //returns true if anything was moved + void insert_time (samplepos_t, samplecnt_t); + bool remove_time (samplepos_t where, samplecnt_t amount); //returns true if anything was moved int n_tempos () const; int n_meters () const; - framecnt_t frame_rate () const { return _frame_rate; } + samplecnt_t sample_rate () const { return _sample_rate; } + + /* TEMPO- AND METER-SENSITIVE FUNCTIONS + + bbt_at_sample(), sample_at_bbt(), beat_at_sample(), sample_at_beat() + and bbt_duration_at() + are all sensitive to tempo and meter, and will give answers + that align with the grid formed by tempo and meter sections. + + They SHOULD NOT be used to determine the position of events + whose location is canonically defined in Temporal::Beats. + */ + + double beat_at_sample (const samplecnt_t sample) const; + samplepos_t sample_at_beat (const double& beat) const; + + const Meter& meter_at_sample (samplepos_t) const; + + /* bbt - it's nearly always better to use meter-based beat (above) + unless tick resolution is desirable. + */ + Timecode::BBT_Time bbt_at_sample (samplepos_t when); + Timecode::BBT_Time bbt_at_sample_rt (samplepos_t when); + samplepos_t sample_at_bbt (const Timecode::BBT_Time&); + + double beat_at_bbt (const Timecode::BBT_Time& bbt); + Timecode::BBT_Time bbt_at_beat (const double& beats); + + double quarter_note_at_bbt (const Timecode::BBT_Time& bbt); + double quarter_note_at_bbt_rt (const Timecode::BBT_Time& bbt); + Timecode::BBT_Time bbt_at_quarter_note (const double& quarter_note); + + samplecnt_t bbt_duration_at (samplepos_t, const Timecode::BBT_Time&, int dir); + samplepos_t samplepos_plus_bbt (samplepos_t pos, Timecode::BBT_Time b) const; + + /* TEMPO-SENSITIVE FUNCTIONS + + These next 2 functions will all take tempo in account and should be + used to determine position (and in the last case, distance in beats) + when tempo matters but meter does not. + + They SHOULD be used to determine the position of events + whose location is canonically defined in Temporal::Beats. + */ + + samplepos_t samplepos_plus_qn (samplepos_t, Temporal::Beats) const; + Temporal::Beats framewalk_to_qn (samplepos_t pos, samplecnt_t distance) const; + + /* quarter note related functions are also tempo-sensitive and ignore meter. + quarter notes may be compared with and assigned to Temporal::Beats. + */ + double quarter_note_at_sample (const samplepos_t sample) const; + double quarter_note_at_sample_rt (const samplepos_t sample) const; + samplepos_t sample_at_quarter_note (const double quarter_note) const; + + samplecnt_t samples_between_quarter_notes (const double start, const double end) const; + double quarter_notes_between_samples (const samplecnt_t start, const samplecnt_t end) const; + + double quarter_note_at_beat (const double beat) const; + double beat_at_quarter_note (const double beat) const; + + /* obtain a musical subdivision via a sample position and magic note divisor.*/ + double exact_qn_at_sample (const samplepos_t sample, const int32_t sub_num) const; + double exact_beat_at_sample (const samplepos_t sample, const int32_t sub_num) const; - double bbt_to_beats (const Timecode::BBT_Time& bbt); - Timecode::BBT_Time beats_to_bbt (const double& beats); - Timecode::BBT_Time pulse_to_bbt (const double& pulse); + Tempo tempo_at_sample (const samplepos_t sample) const; + samplepos_t sample_at_tempo (const Tempo& tempo) const; + Tempo tempo_at_quarter_note (const double& beat) const; + double quarter_note_at_tempo (const Tempo& tempo) const; - double pulse_at_beat (const double& beat) const; - double beat_at_pulse (const double& pulse) const; + void gui_set_tempo_position (TempoSection*, const samplepos_t sample, const int& sub_num); + void gui_set_meter_position (MeterSection*, const samplepos_t sample); + bool gui_change_tempo (TempoSection*, const Tempo& bpm); + void gui_stretch_tempo (TempoSection* tempo, const samplepos_t sample, const samplepos_t end_sample, const double start_qnote, const double end_qnote); + void gui_stretch_tempo_end (TempoSection* tempo, const samplepos_t sample, const samplepos_t end_sample); + bool gui_twist_tempi (TempoSection* first, const Tempo& bpm, const samplepos_t sample, const samplepos_t end_sample); - double pulse_at_frame (const framecnt_t& frame) const; - framecnt_t frame_at_pulse (const double& pulse) const; + std::pair predict_tempo_position (TempoSection* section, const Timecode::BBT_Time& bbt); + bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt); - PBD::Signal0 MetricPositionChanged; + PBD::Signal1 MetricPositionChanged; + void fix_legacy_session(); + void fix_legacy_end_session(); + + samplepos_t music_origin (); private: + /* prevent copy construction */ + TempoMap (TempoMap const&); + + TempoSection* previous_tempo_section_locked (const Metrics& metrics, TempoSection*) const; + TempoSection* next_tempo_section_locked (const Metrics& metrics, TempoSection*) const; + + double beat_at_minute_locked (const Metrics& metrics, const double& minute) const; + double minute_at_beat_locked (const Metrics& metrics, const double& beat) const; + double pulse_at_beat_locked (const Metrics& metrics, const double& beat) const; double beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const; - double pulse_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const; - framecnt_t frame_at_pulse_locked (const Metrics& metrics, const double& pulse) const; + double pulse_at_minute_locked (const Metrics& metrics, const double& minute) const; + double minute_at_pulse_locked (const Metrics& metrics, const double& pulse) const; + + Tempo tempo_at_minute_locked (const Metrics& metrics, const double& minute) const; + double minute_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const; + + Tempo tempo_at_pulse_locked (const Metrics& metrics, const double& pulse) const; + double pulse_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const; - double beat_at_frame_locked (const Metrics& metrics, const framecnt_t& frame) const; - framecnt_t frame_at_beat_locked (const Metrics& metrics, const double& beat) const; + Timecode::BBT_Time bbt_at_minute_locked (const Metrics& metrics, const double& minute) const; + double minute_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time&) const; - double bbt_to_beats_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const ; - Timecode::BBT_Time beats_to_bbt_locked (const Metrics& metrics, const double& beats) const; + double beat_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const ; + Timecode::BBT_Time bbt_at_beat_locked (const Metrics& metrics, const double& beats) const; - framepos_t frame_time_locked (const Metrics& metrics, const Timecode::BBT_Time&) const; + double pulse_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time& bbt) const; + Timecode::BBT_Time bbt_at_pulse_locked (const Metrics& metrics, const double& pulse) const; - const TempoSection& tempo_section_at_locked (const Metrics& metrics, framepos_t frame) const; + double minutes_between_quarter_notes_locked (const Metrics& metrics, const double start_qn, const double end_qn) const; + double quarter_notes_between_samples_locked (const Metrics& metrics, const samplecnt_t start, const samplecnt_t end) const; + + const TempoSection& tempo_section_at_minute_locked (const Metrics& metrics, double minute) const; + TempoSection& tempo_section_at_minute_locked (const Metrics& metrics, double minute); const TempoSection& tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const; - const TempoSection& tempo_section_at_pulse_locked (const Metrics& metrics, const double& pulse) const; - const Tempo tempo_at_locked (const Metrics& metrics, const framepos_t& frame) const; - const MeterSection& meter_section_at_locked (const Metrics& metrics, framepos_t frame) const; + const MeterSection& meter_section_at_minute_locked (const Metrics& metrics, double minute) const; const MeterSection& meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const; bool check_solved (const Metrics& metrics) const; - bool set_active_tempos (const Metrics& metrics, const framepos_t& frame); - bool solve_map_frame (Metrics& metrics, TempoSection* section, const framepos_t& frame); + bool set_active_tempi (const Metrics& metrics, const samplepos_t sample); + + bool solve_map_minute (Metrics& metrics, TempoSection* section, const double& minute); bool solve_map_pulse (Metrics& metrics, TempoSection* section, const double& pulse); - bool solve_map_frame (Metrics& metrics, MeterSection* section, const framepos_t& frame); + bool solve_map_minute (Metrics& metrics, MeterSection* section, const double& minute); bool solve_map_bbt (Metrics& metrics, MeterSection* section, const Timecode::BBT_Time& bbt); + double exact_beat_at_sample_locked (const Metrics& metrics, const samplepos_t sample, const int32_t sub_num) const; + double exact_qn_at_sample_locked (const Metrics& metrics, const samplepos_t sample, const int32_t sub_num) const; + + double minute_at_sample (const samplepos_t sample) const; + samplepos_t sample_at_minute (const double minute) const; + friend class ::BBTTest; friend class ::FrameposPlusBeatsTest; + friend class ::FrameposMinusBeatsTest; friend class ::TempoTest; static Tempo _default_tempo; static Meter _default_meter; Metrics _metrics; - framecnt_t _frame_rate; + samplecnt_t _sample_rate; mutable Glib::Threads::RWLock lock; - void recompute_tempos (Metrics& metrics); + void recompute_tempi (Metrics& metrics); void recompute_meters (Metrics& metrics); - void recompute_map (Metrics& metrics, framepos_t end = -1); + void recompute_map (Metrics& metrics, samplepos_t end = -1); - framepos_t round_to_type (framepos_t fr, RoundMode dir, BBTPointType); + MusicSample round_to_type (samplepos_t fr, RoundMode dir, BBTPointType); const MeterSection& first_meter() const; MeterSection& first_meter(); @@ -510,23 +606,26 @@ private: void do_insert (MetricSection* section); - TempoSection* add_tempo_locked (const Tempo&, double pulse, framepos_t frame - , TempoSection::Type type, PositionLockStyle pls, bool recompute, bool locked_to_meter = false); + TempoSection* add_tempo_locked (const Tempo&, double pulse, double minute + , PositionLockStyle pls, bool recompute, bool locked_to_meter = false, bool clamped = false); - MeterSection* add_meter_locked (const Meter&, double beat, const Timecode::BBT_Time& where, framepos_t frame - , PositionLockStyle pls, bool recompute); + MeterSection* add_meter_locked (const Meter&, const Timecode::BBT_Time& where, samplepos_t sample, PositionLockStyle pls, bool recompute); bool remove_tempo_locked (const TempoSection&); bool remove_meter_locked (const MeterSection&); - TempoSection* copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section); - MeterSection* copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section); + TempoSection* copy_metrics_and_point (const Metrics& metrics, Metrics& copy, TempoSection* section) const; + MeterSection* copy_metrics_and_point (const Metrics& metrics, Metrics& copy, MeterSection* section) const; }; }; /* namespace ARDOUR */ -std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&); -std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&); -std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&); +LIBARDOUR_API std::ostream& operator<< (std::ostream&, const ARDOUR::Meter&); +LIBARDOUR_API std::ostream& operator<< (std::ostream&, const ARDOUR::Tempo&); +LIBARDOUR_API std::ostream& operator<< (std::ostream&, const ARDOUR::MetricSection&); + +namespace PBD { + DEFINE_ENUM_CONVERT (ARDOUR::TempoSection::Type) +} #endif /* __ardour_tempo_h__ */