X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fardour%2Ftempo.h;h=a04f1bb072b19033f68f10d7b304a962ae0b0a74;hb=a223b96725c68a4e41c9f2f5675756c274730889;hp=9a2248414224f1e778109ead4f039a4cdee0eb95;hpb=dbfe991cd862aa1d420c65c9808e5f4e199995ed;p=ardour.git diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index 9a22484142..a04f1bb072 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -27,6 +27,7 @@ #include #include "pbd/undo.h" + #include "pbd/stateful.h" #include "pbd/statefuldestructible.h" @@ -54,15 +55,22 @@ class LIBARDOUR_API Tempo { Tempo (double bpm, double type=4.0) // defaulting to quarter note : _beats_per_minute (bpm), _note_type(type) {} - double beats_per_minute () const { return _beats_per_minute;} - double ticks_per_minute () const { return _beats_per_minute * Timecode::BBT_Time::ticks_per_beat;} - double note_type () const { return _note_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; } + double note_type () const { return _note_type; } + double pulses_per_minute () const { return _beats_per_minute / _note_type; } /** audio samples per beat * @param sr samplerate */ double frames_per_beat (framecnt_t sr) const { return (60.0 * sr) / _beats_per_minute; } + double frames_per_pulse (framecnt_t sr) const { + return (_note_type * 60.0 * sr) / _beats_per_minute; + } protected: double _beats_per_minute; @@ -97,26 +105,21 @@ class LIBARDOUR_API Meter { /** A section of timeline with a certain Tempo or Meter. */ class LIBARDOUR_API MetricSection { public: - MetricSection (const Timecode::BBT_Time& start) - : _start (start), _frame (0), _movable (true) {} - MetricSection (framepos_t start) - : _frame (start), _movable (true) {} + MetricSection (double pulse, framepos_t frame, PositionLockStyle pls) + : _pulse (pulse), _frame (frame), _movable (true), _position_lock_style (pls) {} virtual ~MetricSection() {} - const Timecode::BBT_Time& start() const { return _start; } - framepos_t frame() const { return _frame; } - - void set_movable (bool yn) { _movable = yn; } - bool movable() const { return _movable; } + 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; } - virtual void set_start (const Timecode::BBT_Time& w) { - _start = w; - } + void set_movable (bool yn) { _movable = yn; } + bool movable() const { return _movable; } /* MeterSections are not stateful in the full sense, but we do want them to control their own @@ -124,82 +127,105 @@ class LIBARDOUR_API MetricSection { */ virtual XMLNode& get_state() const = 0; - private: - Timecode::BBT_Time _start; + PositionLockStyle position_lock_style () const { return _position_lock_style; } + void set_position_lock_style (PositionLockStyle ps) { _position_lock_style = ps; } + +private: + double _pulse; framepos_t _frame; bool _movable; + PositionLockStyle _position_lock_style; }; /** A section of timeline with a certain Meter. */ class LIBARDOUR_API MeterSection : public MetricSection, public Meter { public: - MeterSection (const Timecode::BBT_Time& start, double bpb, double note_type) - : MetricSection (start), Meter (bpb, note_type) {} - MeterSection (framepos_t start, double bpb, double note_type) - : MetricSection (start), Meter (bpb, note_type) {} + 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 (const XMLNode&); static const std::string xml_state_node_name; XMLNode& get_state() const; + + 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; } + void set_beat (double beat) { _beat = beat; } + +private: + Timecode::BBT_Time _bbt; + double _beat; }; /** A section of timeline with a certain Tempo. */ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { public: - enum TempoSectionType { + enum Type { Ramp, Constant, }; - TempoSection (const Timecode::BBT_Time& start, double qpm, double note_type, TempoSectionType tempo_type) - : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0), _type (tempo_type) {} - TempoSection (framepos_t start, double qpm, double note_type, TempoSectionType tempo_type) - : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0), _type (tempo_type) {} + 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 XMLNode&); static const std::string xml_state_node_name; XMLNode& get_state() const; - void update_bar_offset_from_bbt (const Meter&); - void update_bbt_time_from_bar_offset (const Meter&); - double bar_offset() const { return _bar_offset; } + double c_func () const { return _c_func; } + void set_c_func (double c_func) { _c_func = c_func; } + + void set_type (Type type); + Type type () const { return _type; } + + bool active () const { return _active; } + void set_active (bool yn) { _active = yn; } - void set_type (TempoSectionType type); - TempoSectionType type () const { return _type; } + bool locked_to_meter () const { return _locked_to_meter; } + void set_locked_to_meter (bool yn) { _locked_to_meter = yn; } - double tempo_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const; - framepos_t frame_at_tempo (double tempo, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const; + 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; - double tick_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const; - framepos_t frame_at_tick (double tick, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) 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 beat_at_frame (framepos_t frame, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) const; - framepos_t frame_at_beat (double beat, double end_bpm, framepos_t end_frame, framecnt_t frame_rate) 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_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; + + Timecode::BBT_Time legacy_bbt () { return _legacy_bbt; } private: - framecnt_t minute_to_frame (double time, framecnt_t frame_rate) const; - double frame_to_minute (framecnt_t frame, framecnt_t frame_rate) const; + 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. */ + double a_func (double end_tpm, double c_func) const; double c_func (double end_tpm, double end_time) const; - double a_func (double begin_tpm, double end_tpm, double end_time) const; - double tempo_at_time (double time, double end_bpm, double end_time) const; - double time_at_tempo (double tempo, double end_bpm, double end_time) const; - double tick_tempo_at_time (double time, double end_tpm, double end_time) const; - double time_at_tick_tempo (double tick_tempo, 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 tick_at_time (double time, double end_tpm, double end_time) const; - double time_at_tick (double tick, double end_tpm, double end_time) const; + double pulse_tempo_at_pulse (const double& pulse) const; + double pulse_at_pulse_tempo (const double& pulse_tempo) const; - double beat_at_time (double time, double end_tpm, double end_time) const; - double time_at_beat (double beat, double end_tpm, double end_time) 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 @@ -209,8 +235,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. */ - double _bar_offset; - TempoSectionType _type; + Type _type; + double _c_func; + bool _active; + bool _locked_to_meter; + Timecode::BBT_Time _legacy_bbt; }; typedef std::list Metrics; @@ -226,7 +255,7 @@ class LIBARDOUR_API TempoMetric { 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_start (const Timecode::BBT_Time& t) { _start = t; } + void set_pulse (const double& p) { _pulse = p; } void set_metric (const MetricSection* section) { const MeterSection* meter; @@ -237,20 +266,20 @@ class LIBARDOUR_API TempoMetric { set_tempo(*tempo); } - set_frame(section->frame()); - set_start(section->start()); + set_frame (section->frame()); + set_pulse (section->pulse()); } const Meter& meter() const { return *_meter; } const Tempo& tempo() const { return *_tempo; } framepos_t frame() const { return _frame; } - const Timecode::BBT_Time& start() const { return _start; } + const double& pulse() const { return _pulse; } private: const Meter* _meter; const Tempo* _tempo; framepos_t _frame; - Timecode::BBT_Time _start; + double _pulse; }; /** Tempo Map - mapping of timecode to musical time. @@ -271,14 +300,15 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible struct BBTPoint { framepos_t frame; - const MeterSection* meter; - const Tempo* tempo; + Meter meter; + Tempo tempo; + double c; uint32_t bar; uint32_t beat; BBTPoint (const MeterSection& m, const Tempo& t, framepos_t f, - uint32_t b, uint32_t e) - : frame (f), meter (&m), tempo (&t), bar (b), beat (e) {} + 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) {} Timecode::BBT_Time bbt() const { return Timecode::BBT_Time (bar, beat, 0); } operator Timecode::BBT_Time() const { return bbt(); } @@ -288,16 +318,81 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible template void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) { Glib::Threads::RWLock::ReaderLock lm (lock); - (obj.*method)(metrics); + (obj.*method)(_metrics); } void get_grid (std::vector&, framepos_t start, framepos_t end); + static const Tempo& default_tempo() { return _default_tempo; } + static const Meter& default_meter() { return _default_meter; } + + /* because tempos may be ramped, this is only valid for the instant requested.*/ + double frames_per_beat_at (const framepos_t&, const framecnt_t& sr) const; + + const TempoSection& tempo_section_at_frame (framepos_t frame) const; + const MeterSection& meter_section_at_frame (framepos_t frame) const; + const MeterSection& meter_section_at_beat (double beat) const; + + /** add a tempo section locked to pls. ignored values will be set in recompute_tempos() + * @param pulse pulse position of new section. ignored if pls == AudioTime + * @param frame 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); + + /** add an meter section locked to pls.. ignored values will be set in recompute_meters() + * @param beat beat position of new section + * @param where bbt position of new section + * @param frame frame position of new section. ignored if pls == MusicTime + */ + MeterSection* add_meter (const Meter&, const double& beat, const Timecode::BBT_Time& where, const framepos_t& frame, PositionLockStyle pls); + + void remove_tempo (const TempoSection&, bool send_signal); + void remove_meter (const MeterSection&, bool send_signal); + + 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); + + 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 set_length (framepos_t frames); + + XMLNode& get_state (void); + int set_state (const XMLNode&, int version); + + void dump (const Metrics& metrics, 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 + * metric change <= t, if it is non-NULL. + */ + TempoMetric metric_at (framepos_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 insert_time (framepos_t, framecnt_t); + bool remove_time (framepos_t where, framecnt_t amount); //returns true if anything was moved + + int n_tempos () const; + int n_meters () const; + + framecnt_t frame_rate () const { return _frame_rate; } + /* 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() + bbt_at_frame(), frame_at_bbt(), beat_at_frame(), frame_at_beat(), tempo_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. @@ -305,15 +400,34 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible 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; + + Tempo tempo_at_frame (const framepos_t& frame) const; + framepos_t frame_at_tempo (const Tempo& tempo) const; + + Tempo tempo_at_beat (const double& beat) const; + + const Meter& meter_at_frame (framepos_t) const; + + /* you probably only need to use pulses when moving tempos */ + double pulse_at_beat (const double& beat) const; + double beat_at_pulse (const double& pulse) const; + + double pulse_at_frame (const framecnt_t& frame) const; + framecnt_t frame_at_pulse (const double& pulse) const; - double tick_at_frame (framecnt_t frame) const; - framecnt_t frame_at_tick (double tick) const; + /* bbt - it's nearly always better to use beats.*/ + Timecode::BBT_Time bbt_at_frame (framepos_t when); + Timecode::BBT_Time bbt_at_frame_rt (framepos_t when); + framepos_t frame_at_bbt (const Timecode::BBT_Time&); - double beat_at_frame (framecnt_t frame) const; - framecnt_t frame_at_beat (double beat) const; + double beat_at_bbt (const Timecode::BBT_Time& bbt); + Timecode::BBT_Time bbt_at_beat (const double& beats); + + double pulse_at_bbt (const Timecode::BBT_Time& bbt); + Timecode::BBT_Time bbt_at_pulse (const double& pulse); - framepos_t frame_time (const Timecode::BBT_Time&); framecnt_t bbt_duration_at (framepos_t, const Timecode::BBT_Time&, int dir); /* TEMPO-SENSITIVE FUNCTIONS @@ -331,60 +445,53 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible framepos_t framepos_minus_beats (framepos_t, Evoral::Beats) const; Evoral::Beats framewalk_to_beats (framepos_t pos, framecnt_t distance) const; - static const Tempo& default_tempo() { return _default_tempo; } - static const Meter& default_meter() { return _default_meter; } - - const Tempo tempo_at (framepos_t) const; - double frames_per_beat_at (framepos_t, framecnt_t sr) const; - - const Meter& meter_at (framepos_t) const; - - const TempoSection& tempo_section_at (framepos_t) const; - TempoSection* tempo_section_after (framepos_t) const; - const MeterSection& meter_section_at (framepos_t) const; + void gui_move_tempo (TempoSection*, const framepos_t& frame); + void gui_move_meter (MeterSection*, const framepos_t& frame); + 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); - void add_tempo (const Tempo&, Timecode::BBT_Time where, TempoSection::TempoSectionType type); - void add_meter (const Meter&, Timecode::BBT_Time where); + std::pair predict_tempo_position (TempoSection* section, const Timecode::BBT_Time& bbt); + bool can_solve_bbt (TempoSection* section, const Timecode::BBT_Time& bbt); - void remove_tempo (const TempoSection&, bool send_signal); - void remove_meter (const MeterSection&, bool send_signal); + PBD::Signal0 MetricPositionChanged; + void fix_legacy_session(); - void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where, TempoSection::TempoSectionType type); - void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where); +private: - 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); + 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; - void set_length (framepos_t frames); + double pulse_at_beat_locked (const Metrics& metrics, const double& beat) const; + double beat_at_pulse_locked (const Metrics& metrics, const double& pulse) const; - XMLNode& get_state (void); - int set_state (const XMLNode&, int version); - - void dump (std::ostream&) const; - void clear (); + 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; - TempoMetric metric_at (Timecode::BBT_Time bbt) const; + Tempo tempo_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const; + framepos_t frame_at_tempo_locked (const Metrics& metrics, const Tempo& tempo) const; - /** Return the TempoMetric at frame @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; + Timecode::BBT_Time bbt_at_frame_locked (const Metrics& metrics, const framepos_t& frame) const; + framepos_t frame_at_bbt_locked (const Metrics& metrics, const Timecode::BBT_Time&) const; - Metrics::const_iterator metrics_end() { return metrics.end(); } + 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; - void change_existing_tempo_at (framepos_t, double bpm, double note_type); - void change_initial_tempo (double bpm, double note_type); + 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; - void insert_time (framepos_t, framecnt_t); - bool remove_time (framepos_t where, framecnt_t amount); //returns true if anything was moved + const TempoSection& tempo_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const; + const TempoSection& tempo_section_at_beat_locked (const Metrics& metrics, const double& beat) const; - int n_tempos () const; - int n_meters () const; + const MeterSection& meter_section_at_frame_locked (const Metrics& metrics, framepos_t frame) const; + const MeterSection& meter_section_at_beat_locked (const Metrics& metrics, const double& beat) const; - framecnt_t frame_rate () const { return _frame_rate; } + bool check_solved (const Metrics& metrics) const; + bool set_active_tempos (const Metrics& metrics, const framepos_t& frame); - private: + bool solve_map_frame (Metrics& metrics, TempoSection* section, const framepos_t& frame); + 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_bbt (Metrics& metrics, MeterSection* section, const Timecode::BBT_Time& bbt); friend class ::BBTTest; friend class ::FrameposPlusBeatsTest; @@ -393,15 +500,13 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible static Tempo _default_tempo; static Meter _default_meter; - Metrics metrics; + Metrics _metrics; framecnt_t _frame_rate; mutable Glib::Threads::RWLock lock; - void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1); - - void _extend_map (TempoSection* tempo, MeterSection* meter, - Metrics::iterator next_metric, - Timecode::BBT_Time current, framepos_t current_frame, framepos_t end); + void recompute_tempos (Metrics& metrics); + void recompute_meters (Metrics& metrics); + void recompute_map (Metrics& metrics, framepos_t end = -1); framepos_t round_to_type (framepos_t fr, RoundMode dir, BBTPointType); @@ -410,17 +515,19 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible const TempoSection& first_tempo() const; TempoSection& first_tempo(); - Timecode::BBT_Time beats_to_bbt (double beats); - int32_t bars_in_meter_section (MeterSection* ms) const; - void do_insert (MetricSection* section); - void add_tempo_locked (const Tempo&, Timecode::BBT_Time where, bool recompute, TempoSection::TempoSectionType type); - void add_meter_locked (const Meter&, Timecode::BBT_Time where, bool recompute); + TempoSection* add_tempo_locked (const Tempo&, double pulse, framepos_t frame + , TempoSection::Type type, PositionLockStyle pls, bool recompute, bool locked_to_meter = false); + + MeterSection* add_meter_locked (const Meter&, double beat, const Timecode::BBT_Time& where, framepos_t frame + , 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); }; }; /* namespace ARDOUR */