diff options
author | nick_m <mainsbridge@gmail.com> | 2016-03-29 05:31:06 +1100 |
---|---|---|
committer | nick_m <mainsbridge@gmail.com> | 2016-05-27 23:38:13 +1000 |
commit | a9714de9b97045083d2d6b656808e19572ac44a2 (patch) | |
tree | d9d34a376dd885b1d04ce2032211f905f76e2d14 | |
parent | 354567e5a72c3d24fb13d8b47a51b1c3859918ea (diff) |
Tempo ramps - tempo drags respect the snap modifier. add some documentation.
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 66 | ||||
-rw-r--r-- | libs/ardour/ardour/tempo.h | 3 | ||||
-rw-r--r-- | libs/ardour/tempo.cc | 35 |
3 files changed, 66 insertions, 38 deletions
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index b6083281ab..e04a73fcf1 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -3318,29 +3318,6 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move) framepos_t pf; double beat = 0.0; - - if (!_editor->snap_musical()) { - pf = adjusted_current_frame (event); - } else { - pf = adjusted_current_frame (event, false); - Timecode::BBT_Time when; - _editor->session()->tempo_map().bbt_time (pf, when); - if (_real_section->position_lock_style() == MusicTime) { - if (_editor->snap_type() == SnapToBar) { - _editor->session()->tempo_map().round_bbt (when, -1); - } else { - _editor->session()->tempo_map().round_bbt (when, _editor->get_grid_beat_divisions (0)); - } - beat = _editor->session()->tempo_map().bbt_to_beats (when); - } else { - if (_editor->snap_type() == SnapToBar) { - _editor->session()->tempo_map().round_bbt (when, -1); - } else { - _editor->session()->tempo_map().round_bbt (when, _editor->get_grid_beat_divisions (0)); - } - pf = _editor->session()->tempo_map().predict_tempo_frame (_real_section, Tempo (_real_section->beats_per_minute(), _real_section->note_type()), when); - } - } Tempo const tp = _marker->tempo(); if (Keyboard::modifier_state_equals (event->button.state, ArdourKeyboard::constraint_modifier ())) { @@ -3350,12 +3327,47 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move) strs << new_bpm; show_verbose_cursor_text (strs.str()); } else if (_movable) { - - if (_real_section->position_lock_style() == MusicTime) { - _editor->session()->tempo_map().gui_move_tempo_beat (_real_section, tp, beat); + if (!_editor->snap_musical()) { + pf = adjusted_current_frame (event); } else { - _editor->session()->tempo_map().gui_move_tempo_frame (_real_section, tp, pf); + pf = adjusted_current_frame (event, false); + bool use_snap; + + if (Keyboard::modifier_state_equals (event->button.state, ArdourKeyboard::snap_modifier ())) { + if (_editor->snap_mode() == Editing::SnapOff) { + use_snap = true; + } else { + use_snap = false; + } + } else { + if (_editor->snap_mode() == Editing::SnapOff) { + use_snap = false; + } else { + use_snap = true; + } + } + + Timecode::BBT_Time when; + _editor->session()->tempo_map().bbt_time (pf, when); + if (_real_section->position_lock_style() == MusicTime) { + if (use_snap && _editor->snap_type() == SnapToBar) { + _editor->session()->tempo_map().round_bbt (when, -1); + } else if (use_snap) { + _editor->session()->tempo_map().round_bbt (when, _editor->get_grid_beat_divisions (0)); + } + beat = _editor->session()->tempo_map().bbt_to_beats (when); + _editor->session()->tempo_map().gui_move_tempo_beat (_real_section, tp, beat); + } else { + if (use_snap && _editor->snap_type() == SnapToBar) { + _editor->session()->tempo_map().round_bbt (when, -1); + } else if (use_snap) { + _editor->session()->tempo_map().round_bbt (when, _editor->get_grid_beat_divisions (0)); + } + pf = _editor->session()->tempo_map().predict_tempo_frame (_real_section, Tempo (_real_section->beats_per_minute(), _real_section->note_type()), when); + _editor->session()->tempo_map().gui_move_tempo_frame (_real_section, tp, pf); + } } + show_verbose_cursor_time (pf); } _marker->set_position (pf); diff --git a/libs/ardour/ardour/tempo.h b/libs/ardour/ardour/tempo.h index 2a28a65f5b..7a26a609e3 100644 --- a/libs/ardour/ardour/tempo.h +++ b/libs/ardour/ardour/tempo.h @@ -55,6 +55,9 @@ class LIBARDOUR_API Tempo { 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; } double note_type () const { return _note_type; } diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc index fec74ccfe0..13b98c613b 100644 --- a/libs/ardour/tempo.cc +++ b/libs/ardour/tempo.cc @@ -604,7 +604,28 @@ MeterSection::get_state() const } /***********************************************************************/ - +/* + Tempo Map Overview + + We have tempos, which are nice to think of in whole pulses per minute, + and meters which divide tempo pulses into bars (via divisions_per_bar) + and beats (via note_divisor). + Tempos and meters may be locked to audio or music. + Because the notion of a beat cannot be determined without both tempo and meter, the first tempo + and first meter are special. they must move together, and must be locked to audio. + Audio locked tempos which lie before the first meter are made inactive. + They will be re-activated if the first meter is again placed before them. + + Both tempos and meters have a pulse position and a frame position. + Recomputing the tempo map is the process where the 'missing' position + (pulse in the case of AudioTime and frame for MusicTime) is calculated + based on the lock preference (position_lock_style). + + It is important to keep the _metrics in an order that makes sense. + Because ramped MusicTime and AudioTime tempos can interact with each other + and cause reordering, care must be taken to keep _metrics in a solved state. + Solved means ordered by frame or pulse with frame-accurate precision (see check_solved()). +*/ struct MetricSectionSorter { bool operator() (const MetricSection* a, const MetricSection* b) { return a->pulse() < b->pulse(); @@ -2004,18 +2025,10 @@ TempoMap::check_solved (Metrics& metrics, bool by_frame) if ((by_frame && t->frame() < prev_ts->frame()) || (!by_frame && t->pulse() < prev_ts->pulse())) { return false; } - if (by_frame && t->frame() != prev_ts->frame_at_pulse (t->pulse(), _frame_rate)) { + /* precision check ensures pulses and frames align independent of lock style.*/ + if (t->frame() != prev_ts->frame_at_pulse (t->pulse(), _frame_rate)) { return false; } - /* - if (!by_frame && fabs (t->pulse() - prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate)) > 0.00001) { - std::cerr << "beat precision too low for bpm: " << t->beats_per_minute() << std::endl << - " |error :" << t->pulse() - prev_ts->pulse_at_tempo (t->pulses_per_minute(), t->frame(), _frame_rate) << std::endl << - "|frame at beat :" << prev_ts->frame_at_pulse (t->pulse(), _frame_rate) << std::endl << - " |frame at tempo : " << prev_ts->frame_at_tempo (t->pulses_per_minute(), t->pulse(), _frame_rate) << std::endl; - return false; - } - */ } prev_ts = t; } |