Tempo ramps - tempo drags respect the snap modifier. add some documentation.
authornick_m <mainsbridge@gmail.com>
Mon, 28 Mar 2016 18:31:06 +0000 (05:31 +1100)
committernick_m <mainsbridge@gmail.com>
Fri, 27 May 2016 13:38:13 +0000 (23:38 +1000)
gtk2_ardour/editor_drag.cc
libs/ardour/ardour/tempo.h
libs/ardour/tempo.cc

index b6083281ab392c05e9f55b83465729d2a6f20807..e04a73fcf1efe188185bc831fbe1f0b6eb467049 100644 (file)
@@ -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);
index 2a28a65f5b4332a3a9d9e38c6a3dea4f61e1085c..7a26a609e3c3146ab3b58729bf6bf02c5bb2a764 100644 (file)
@@ -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; }
index fec74ccfe0341bb6989762b3b69b8a942c71a17b..13b98c613bcac7ae43c740c0d3bcbcf55f85877e 100644 (file)
@@ -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;
                }