Tempo ramps - more bbt dragging work.
authornick_m <mainsbridge@gmail.com>
Tue, 17 May 2016 14:12:28 +0000 (00:12 +1000)
committernick_m <mainsbridge@gmail.com>
Fri, 27 May 2016 13:38:16 +0000 (23:38 +1000)
- display prev tempo and tempo at mouse while dragging
- simplify ramp dilation somewhat.

gtk2_ardour/editor.h
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_drag.h
gtk2_ardour/editor_tempodisplay.cc
libs/ardour/ardour/tempo.h
libs/ardour/tempo.cc

index 6057326ab3a500a0063a168be205ff247be1b5be..0fd9fccec188e6b3cefc45f993af26f2e189dcbf 100644 (file)
@@ -2254,6 +2254,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
        friend class RegionSpliceDrag;
        friend class RegionRippleDrag;
        friend class TrimDrag;
+       friend class BBTRulerDrag;
        friend class MeterMarkerDrag;
        friend class TempoMarkerDrag;
        friend class CursorDrag;
index 4ccb1c0ba5d97394d1372347b263a412b2dd66af..3533eb8163500d6aee3ae3f53b6c8f3ba6eb96f7 100644 (file)
@@ -3478,32 +3478,47 @@ TempoMarkerDrag::aborted (bool moved)
 
 BBTRulerDrag::BBTRulerDrag (Editor* e, ArdourCanvas::Item* i)
        : Drag (e, i)
+       , _pulse (0.0)
+       , _beat (0.0)
        , _tempo (0)
        , before_state (0)
 {
        DEBUG_TRACE (DEBUG::Drags, "New BBTRulerDrag\n");
+
 }
 
 void
 BBTRulerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 {
        Drag::start_grab (event, cursor);
+
        TempoMap& map (_editor->session()->tempo_map());
        ostringstream sstr;
-       sstr << fixed << setprecision(3) << map.tempo_at (adjusted_current_frame (event)).beats_per_minute();
-       show_verbose_cursor_text (sstr.str());
-       _tempo = const_cast<TempoSection*> (&map.tempo_section_at (adjusted_current_frame (event, false)));
 
-       if (!_tempo) {
-               Drag::abort();
-       }
+       _tempo = const_cast<TempoSection*> (&map.tempo_section_at (raw_grab_frame()));
+       sstr << "^" << fixed << setprecision(3) << map.tempo_at (adjusted_current_frame (event)).beats_per_minute() << "\n";
+       sstr << "<" << fixed << setprecision(3) << _tempo->beats_per_minute();
+       show_verbose_cursor_text (sstr.str());
+       finished (event, false);
 }
 
 void
 BBTRulerDrag::setup_pointer_frame_offset ()
 {
        TempoMap& map (_editor->session()->tempo_map());
-       _pointer_frame_offset = raw_grab_frame() - map.frame_at_beat (floor (map.beat_at_frame (raw_grab_frame())));
+       const double beat_at_frame = map.beat_at_frame (raw_grab_frame());
+       const uint32_t divisions = _editor->get_grid_beat_divisions (0);
+       if (divisions > 0) {
+               _beat = floor (beat_at_frame) + (floor (((beat_at_frame - floor (beat_at_frame)) * divisions)) / divisions);
+       } else {
+               /* while it makes some sense for the user to determine the division to 'grab',
+                  grabbing a bar often leads to confusing results wrt the actual tempo section being altered
+                  and the result over steep tempo curves. Use sixteenths.
+               */
+               _beat = floor (beat_at_frame) + (floor (((beat_at_frame - floor (beat_at_frame)) * 4)) / 4);
+       }
+       _pulse = map.pulse_at_beat (_beat);
+       _pointer_frame_offset = raw_grab_frame() - map.frame_at_beat (_beat);
 }
 
 void
@@ -3521,10 +3536,11 @@ BBTRulerDrag::motion (GdkEvent* event, bool first_move)
 
        if (Keyboard::modifier_state_contains (event->button.state, ArdourKeyboard::constraint_modifier())) {
                /* adjust previous tempo to match pointer frame */
-               _editor->session()->tempo_map().gui_dilate_tempo (_tempo, last_pointer_frame(), pf);
+               _editor->session()->tempo_map().gui_dilate_tempo (_tempo, map.frame_at_pulse (_pulse), pf, _pulse);
        }
        ostringstream sstr;
-       sstr << fixed << setprecision(3) << map.tempo_at (pf).beats_per_minute();
+       sstr << "^" << fixed << setprecision(3) << map.tempo_at (pf).beats_per_minute() << "\n";
+       sstr << "<" << fixed << setprecision(3) << _tempo->beats_per_minute();
        show_verbose_cursor_text (sstr.str());
 }
 
index f75c9a681dc89c27de90318abee21b6217967a53..abec31a00b48fdf365adabc8f6bf7cad126ce3ac 100644 (file)
@@ -764,6 +764,8 @@ public:
        void setup_pointer_frame_offset ();
 
 private:
+       double _pulse;
+       double _beat;
        ARDOUR::TempoSection* _tempo;
        XMLNode* before_state;
 };
index 0b133e30514b361e1bf47b89b13158a762198591..435ee90a2181f656398339b81288e2454f5b432f 100644 (file)
@@ -244,7 +244,8 @@ Editor::compute_current_bbt_points (std::vector<TempoMap::BBTPoint>& grid, frame
 
        /* prevent negative values of leftmost from creeping into tempomap
         */
-       _session->tempo_map().get_grid (grid, max (leftmost, (framepos_t) 0), rightmost);
+       const double lower_beat = floor (_session->tempo_map().beat_at_frame (leftmost));
+       _session->tempo_map().get_grid (grid, max (_session->tempo_map().frame_at_beat (lower_beat), (framepos_t) 0), rightmost);
 }
 
 void
index 81fad2e0fcf46c69f5d4f9e08358ab630bb3e825..9274758958d2010f9e3671a83220ca9605df7ffc 100644 (file)
@@ -398,9 +398,8 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
        void gui_move_meter (MeterSection*, const framepos_t& frame);
        void gui_move_meter (MeterSection*, const Timecode::BBT_Time& bbt);
        bool gui_change_tempo (TempoSection*, const Tempo& bpm);
-       void gui_dilate_next_tempo (const framepos_t& frame, const framepos_t& end_frame);
        void gui_dilate_tempo (MeterSection*, const framepos_t& frame);
-       void gui_dilate_tempo (TempoSection* tempo, const framepos_t& frame, const framepos_t& end_frame);
+       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);
 
index e3d25948de4dbc9b4d9fffea9491617caf5a4042..b4982ebe2b6cf08576e27cb47dbfacea9aef8a3f 100644 (file)
@@ -2783,118 +2783,16 @@ TempoMap::gui_dilate_tempo (MeterSection* ms, const framepos_t& frame)
 }
 
 void
-TempoMap::gui_dilate_next_tempo (const framepos_t& frame, const framepos_t& end_frame)
-{
-       Metrics future_map;
-       TempoSection* ts = 0;
-
-       {
-               Glib::Threads::RWLock::WriterLock lm (lock);
-
-               for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
-                       TempoSection* t = 0;
-                       if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
-                               if (t->frame() > end_frame) {
-                                       ts = t;
-                                       break;
-                               }
-                       }
-               }
-
-               if (!ts) {
-                       ts = const_cast<TempoSection*>(&tempo_section_at_locked (_metrics, frame - 1));
-               }
-
-               TempoSection* next_t = copy_metrics_and_point (_metrics, future_map, ts);
-               TempoSection* prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (future_map, next_t->frame() - 1));
-               TempoSection* prev_to_prev_t = 0;
-               const frameoffset_t fr_off = end_frame - frame;
-
-               if (prev_t && prev_t->pulse() > 0.0) {
-                       prev_to_prev_t = const_cast<TempoSection*>(&tempo_section_at_locked (future_map, prev_t->frame() - 1));
-               }
-
-
-               /* the change in frames is the result of changing the slope of at most 2 previous tempo sections.
-                  constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
-               */
-               double contribution = 0.0;
-
-               if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
-                       contribution = prev_t->beats_per_minute() / (prev_t->beats_per_minute() + next_t->beats_per_minute());
-               }
-
-               frameoffset_t prev_t_frame_contribution = fr_off;
-
-               const double start_tempo = prev_t->tempo_at_frame (frame, _frame_rate);
-               const double end_tempo = prev_t->tempo_at_frame (frame + prev_t_frame_contribution, _frame_rate);
-               const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
-               const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
-               double new_bpm;
-
-               if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
-
-                       if (prev_t->position_lock_style() == MusicTime) {
-                               if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
-                                       new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame())
-                                                                               / (double) ((frame + prev_t_frame_contribution) - prev_t->frame()));
-
-                               } else {
-                                       /* prev to prev is irrelevant */
-
-                                       if (start_pulse != prev_t->pulse()) {
-                                               new_bpm = prev_t->beats_per_minute() * ((start_pulse - prev_t->pulse()) / (end_pulse - prev_t->pulse()));
-                                       } else {
-                                               new_bpm = prev_t->beats_per_minute();
-                                       }
-                               }
-                       } else {
-                               /* AudioTime */
-                               if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
-                                       new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame())
-                                                                               / (double) ((frame + prev_t_frame_contribution) - prev_t->frame()));
-                               } else {
-                                       /* prev_to_prev_t is irrelevant */
-
-                                       if (end_frame != prev_t->frame()) {
-                                               new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame()) / (double) (end_frame - prev_t->frame()));
-                                       } else {
-                                               new_bpm = prev_t->beats_per_minute();
-                                       }
-                               }
-                       }
-               } else {
-                       const double end_minute = ((next_t->frame() + prev_t_frame_contribution - prev_t->frame()) / (double) _frame_rate) / 60.0;
-                       const double pulse_delta_at_next = prev_t->pulse_at_frame ((next_t->frame()) + prev_t_frame_contribution, _frame_rate) - next_t->pulse();
-                       const double target_pulse = (next_t->pulse() - prev_t->pulse()) + (pulse_delta_at_next);
-
-                       new_bpm = (prev_t->tempo_at_frame (next_t->frame() - prev_t_frame_contribution, _frame_rate)) * (double) prev_t->note_type();
-
-               }
-
-               next_t->set_beats_per_minute (new_bpm);
-               recompute_tempos (future_map);
-               recompute_meters (future_map);
-
-               if (check_solved (future_map, true)) {
-                       ts->set_beats_per_minute (new_bpm);
-                       recompute_tempos (_metrics);
-                       recompute_meters (_metrics);
-               }
-       }
-
-       Metrics::const_iterator d = future_map.begin();
-       while (d != future_map.end()) {
-               delete (*d);
-               ++d;
-       }
-
-       MetricPositionChanged (); // Emit Signal
-}
+TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame, const double& pulse)
+{
+       /*
+         Ts (future prev_t)   Tnext
+         |                    |
+         |     [drag^]        |
+         |----------|----------
+               e_f  pulse(frame)
+       */
 
-void
-TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const framepos_t& end_frame)
-{
        Metrics future_map;
 
        {
@@ -2926,22 +2824,23 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra
                   constant to constant is straightforward, as the tempo prev to prev_t has constant slope.
                */
                double contribution = 0.0;
+               double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
 
                if (next_t && prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
                        contribution = (prev_t->frame() - prev_to_prev_t->frame()) / (double) (next_t->frame() - prev_to_prev_t->frame());
                }
 
                frameoffset_t prev_t_frame_contribution = fr_off - (contribution * (double) fr_off);
-               const double start_pulse = prev_t->pulse_at_frame (frame, _frame_rate);
-               const double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
+               double end_pulse = prev_t->pulse_at_frame (end_frame, _frame_rate);
                double new_bpm;
 
                if (prev_t->type() == TempoSection::Constant || prev_t->c_func() == 0.0) {
 
                        if (prev_t->position_lock_style() == MusicTime) {
                                if (prev_to_prev_t && prev_to_prev_t->type() == TempoSection::Ramp) {
-                                       new_bpm = prev_t->beats_per_minute() * ((frame - prev_t->frame())
-                                                                               / (double) ((frame + prev_t_frame_contribution) - prev_t->frame()));
+
+                                       new_bpm = prev_t->beats_per_minute() * ((frame - prev_to_prev_t->frame())
+                                                                               / (double) ((frame + prev_t_frame_contribution) - prev_to_prev_t->frame()));
 
                                } else {
                                        /* prev to prev is irrelevant */
@@ -2968,14 +2867,21 @@ TempoMap::gui_dilate_tempo (TempoSection* ts, const framepos_t& frame, const fra
                                }
                        }
                } else {
-                       const frameoffset_t halfway = ((next_t->frame() + prev_t->frame()) / 2.0);
-                       const frameoffset_t halfway_off = halfway + prev_t_frame_contribution;
-                       const double halfway_pulse = prev_t->pulse_at_frame (halfway, _frame_rate);
-                       const double halfway_off_minute = ((halfway_off - prev_t->frame()) / (double) _frame_rate) / 60.0;
 
-                       new_bpm = (((halfway_pulse - prev_t->pulse()) * prev_t->c_func())
-                                  / (exp (halfway_off_minute * prev_t->c_func()) - 1.0)) * (double) prev_t->note_type();
+                       double frame_ratio;
+                       double pulse_ratio;
+                       const framepos_t pulse_pos = prev_t->frame_at_pulse (pulse, _frame_rate);
+
+                       if (prev_to_prev_t) {
 
+                               frame_ratio = (((pulse_pos - fr_off) - prev_to_prev_t->frame()) / (double) ((pulse_pos) - prev_to_prev_t->frame()));
+                               pulse_ratio = ((start_pulse - prev_to_prev_t->pulse()) / (double) (end_pulse - prev_to_prev_t->pulse()));
+                       } else {
+
+                               frame_ratio = (((pulse_pos - fr_off) - prev_t->frame()) / (double) ((pulse_pos) - prev_t->frame()));
+                               pulse_ratio = ((start_pulse) / (double) (end_pulse));
+                       }
+                       new_bpm = prev_t->beats_per_minute() * (pulse_ratio * frame_ratio);
                }
 
                prev_t->set_beats_per_minute (new_bpm);