X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fardour%2Ftempo.h;h=e8f40e4236b65eafb36ce6b415bf0d7b8311d265;hb=8d007e8a77f9d3225fae72324b788ab74d68ed2b;hp=8fa5ed45a0242104f51d9fe78bafee09ae3d687f;hpb=cf806123ca5faaef483f898daba3f7bd38ec62eb;p=ardour.git diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index 8fa5ed45a0..e8f40e4236 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -27,10 +27,11 @@ #include #include "pbd/undo.h" + #include "pbd/stateful.h" #include "pbd/statefuldestructible.h" -#include "evoral/types.hpp" +#include "evoral/Beats.hpp" #include "ardour/ardour.h" @@ -47,11 +48,20 @@ class TempoMap; /** Tempo, the speed at which musical time progresses (BPM). */ class LIBARDOUR_API Tempo { public: + /** + * @param bpm Beats 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) {} - double beats_per_minute () const { return _beats_per_minute;} + 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;} + /** audio samples per beat + * @param sr samplerate + */ double frames_per_beat (framecnt_t sr) const { return (60.0 * sr) / _beats_per_minute; } @@ -90,9 +100,9 @@ class LIBARDOUR_API Meter { class LIBARDOUR_API MetricSection { public: MetricSection (const Timecode::BBT_Time& start) - : _start (start), _frame (0), _movable (true) {} + : _start (start), _frame (0), _movable (true), _position_lock_style (MusicTime) {} MetricSection (framepos_t start) - : _frame (start), _movable (true) {} + : _frame (start), _movable (true), _position_lock_style (MusicTime) {} virtual ~MetricSection() {} @@ -115,11 +125,15 @@ class LIBARDOUR_API MetricSection { XML state information. */ virtual XMLNode& get_state() const = 0; + PositionLockStyle position_lock_style () const { return _position_lock_style; } + void set_position_lock_style (PositionLockStyle ps) { _position_lock_style = ps; } + +private: - private: Timecode::BBT_Time _start; framepos_t _frame; bool _movable; + PositionLockStyle _position_lock_style; }; /** A section of timeline with a certain Meter. */ @@ -139,10 +153,15 @@ class LIBARDOUR_API MeterSection : public MetricSection, public Meter { /** A section of timeline with a certain Tempo. */ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { public: - TempoSection (const Timecode::BBT_Time& start, double qpm, double note_type) - : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0) {} - TempoSection (framepos_t start, double qpm, double note_type) - : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0) {} + enum Type { + Ramp, + Constant, + }; + + TempoSection (const Timecode::BBT_Time& start, double qpm, double note_type, Type tempo_type) + : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0), _type (tempo_type) {} + TempoSection (framepos_t start, double qpm, double note_type, Type tempo_type) + : MetricSection (start), Tempo (qpm, note_type), _bar_offset (-1.0), _type (tempo_type) {} TempoSection (const XMLNode&); static const std::string xml_state_node_name; @@ -153,16 +172,51 @@ class LIBARDOUR_API TempoSection : public MetricSection, public Tempo { void update_bbt_time_from_bar_offset (const Meter&); double bar_offset() const { return _bar_offset; } + void set_type (Type type); + Type type () const { return _type; } + + 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 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 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; + 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; + + /* 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 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 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 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; + /* this value provides a fractional offset into the bar in which the tempo section is located in. A value of 0.0 indicates that it occurs on the first beat of the bar, a value of 0.5 indicates that it occurs halfway through the bar and so on. - + this enables us to keep the tempo change at the same relative position within the bar if/when the meter changes. */ double _bar_offset; + Type _type; }; typedef std::list Metrics; @@ -205,6 +259,9 @@ class LIBARDOUR_API TempoMetric { Timecode::BBT_Time _start; }; +/** Tempo Map - mapping of timecode to musical time. + * convert audio-samples, sample-rate to Bar/Beat/Tick, Meter/Tempo + */ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible { public: @@ -221,86 +278,90 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible struct BBTPoint { framepos_t frame; const MeterSection* meter; - const TempoSection* tempo; + const Tempo* tempo; uint32_t bar; uint32_t beat; - - BBTPoint (const MeterSection& m, const TempoSection& t, framepos_t f, + + 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) {} - + 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; } bool is_bar() const { return beat == 1; } }; - typedef std::vector BBTPointList; - template void apply_with_metrics (T& obj, void (T::*method)(const Metrics&)) { Glib::Threads::RWLock::ReaderLock lm (lock); (obj.*method)(metrics); } - void get_grid (BBTPointList::const_iterator&, BBTPointList::const_iterator&, + void get_grid (std::vector&, framepos_t start, framepos_t end); - - /* TEMPO- AND METER-SENSITIVE FUNCTIONS - bbt_time(), bbt_time_rt(), frame_time() and bbt_duration_at() + /* 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 + + 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&); - /* realtime safe variant of ::bbt_time(), will throw - std::logic_error if the map is not large enough - to provide an answer. - */ - void bbt_time_rt (framepos_t when, Timecode::BBT_Time&); + double tick_at_frame (framecnt_t frame) const; + framecnt_t frame_at_tick (double tick) const; + + double beat_at_frame (framecnt_t frame) const; + framecnt_t frame_at_beat (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 + 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::MusicalTime) const; - framepos_t framepos_minus_beats (framepos_t, Evoral::MusicalTime) const; - Evoral::MusicalTime framewalk_to_beats (framepos_t pos, framecnt_t distance) 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; static const Tempo& default_tempo() { return _default_tempo; } static const Meter& default_meter() { return _default_meter; } - const Tempo& tempo_at (framepos_t) const; + 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 add_tempo (const Tempo&, Timecode::BBT_Time where); + void add_tempo (const Tempo&, Timecode::BBT_Time where, TempoSection::Type type); void add_meter (const Meter&, Timecode::BBT_Time where); void remove_tempo (const TempoSection&, bool send_signal); void remove_meter (const MeterSection&, bool send_signal); - void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where); + void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where, TempoSection::Type type); + void gui_set_tempo_frame (TempoSection&, framepos_t where); void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where); - framepos_t round_to_bar (framepos_t frame, int dir); - framepos_t round_to_beat (framepos_t frame, int dir); - framepos_t round_to_beat_subdivision (framepos_t fr, int sub_num, int dir); - framepos_t round_to_tick (framepos_t frame, int dir); + 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); @@ -323,46 +384,52 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible 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; } - private: + PBD::Signal0 MetricPositionChanged; + +private: friend class ::BBTTest; friend class ::FrameposPlusBeatsTest; friend class ::TempoTest; - + static Tempo _default_tempo; static Meter _default_meter; Metrics metrics; framecnt_t _frame_rate; mutable Glib::Threads::RWLock lock; - BBTPointList _map; void recompute_map (bool reassign_tempo_bbt, framepos_t end = -1); - void extend_map (framepos_t end); - void require_map_to (framepos_t pos); - void require_map_to (const Timecode::BBT_Time&); - void _extend_map (TempoSection* tempo, MeterSection* meter, + + void _extend_map (TempoSection* tempo, MeterSection* meter, Metrics::iterator next_metric, - Timecode::BBT_Time current, framepos_t current_frame, framepos_t end); - - BBTPointList::const_iterator bbt_before_or_at (framepos_t); - BBTPointList::const_iterator bbt_before_or_at (const Timecode::BBT_Time&); - BBTPointList::const_iterator bbt_after_or_at (framepos_t); - - framepos_t round_to_type (framepos_t fr, int dir, BBTPointType); - void bbt_time (framepos_t, Timecode::BBT_Time&, const BBTPointList::const_iterator&); - framecnt_t bbt_duration_at_unlocked (const Timecode::BBT_Time& when, const Timecode::BBT_Time& bbt, int dir); - + Timecode::BBT_Time current, framepos_t current_frame, framepos_t end); + + framepos_t round_to_type (framepos_t fr, RoundMode dir, BBTPointType); + const MeterSection& first_meter() const; + MeterSection& first_meter(); 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::Type type); + void add_meter_locked (const Meter&, Timecode::BBT_Time where, bool recompute); + + bool remove_tempo_locked (const TempoSection&); + bool remove_meter_locked (const MeterSection&); + }; }; /* namespace ARDOUR */