Tempo ramps - music-locked meter drags are now bbt based.
authornick_m <mainsbridge@gmail.com>
Mon, 2 May 2016 17:31:27 +0000 (03:31 +1000)
committernick_m <mainsbridge@gmail.com>
Fri, 27 May 2016 13:38:16 +0000 (23:38 +1000)
gtk2_ardour/editor_drag.cc
libs/ardour/ardour/tempo.h
libs/ardour/tempo.cc

index fe67b71dd258d0d916140752323538ed6e8b6466..080e82d98414c215e4f96a4f90134cc6826621d1 100644 (file)
@@ -3199,17 +3199,15 @@ MeterMarkerDrag::motion (GdkEvent* event, bool first_move)
                Timecode::BBT_Time bbt;
                map.bbt_time (pf, bbt);
                /* round bbt to bars */
-               map.round_bbt (bbt, -1);
-               const MeterSection& prev_m = map.meter_section_at (_real_section->frame() - 1);
+               map.round_bbt (bbt, -1, RoundNearest);
 
                if (Keyboard::modifier_state_contains (event->button.state, ArdourKeyboard::constraint_modifier ())) {
+                       /* adjust previous tempo to match meter frame */
                        _editor->session()->tempo_map().gui_dilate_tempo (_real_section, pf);
-               } else if (bbt.bars > _real_section->bbt().bars) {
-                       const double pulse = _real_section->pulse() + (prev_m.note_divisor() / prev_m.divisions_per_bar());
-                       _editor->session()->tempo_map().gui_move_meter (_real_section, pulse);
-               } else if (bbt.bars < _real_section->bbt().bars) {
-                       const double pulse = _real_section->pulse() - (prev_m.note_divisor() / prev_m.divisions_per_bar());
-                       _editor->session()->tempo_map().gui_move_meter (_real_section, pulse);
+               } else if ((bbt.bars > _real_section->bbt().bars && pf > last_pointer_frame())
+                          || (bbt.bars < _real_section->bbt().bars && pf < last_pointer_frame())) {
+                       /* move meter beat-based */
+                       _editor->session()->tempo_map().gui_move_meter (_real_section, bbt);
                }
        } else {
                /* AudioTime */
@@ -3352,17 +3350,17 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
 
                        if (_real_section->position_lock_style() == MusicTime) {
                                if (use_snap && _editor->snap_type() == SnapToBar) {
-                                       map.round_bbt (bbt, -1);
+                                       map.round_bbt (bbt, -1, (frame > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
                                } else if (use_snap) {
-                                       map.round_bbt (bbt, _editor->get_grid_beat_divisions (0));
+                                       map.round_bbt (bbt, _editor->get_grid_beat_divisions (0), RoundNearest);
                                }
                                double const pulse = map.predict_tempo_pulse (_real_section, map.frame_time (bbt));
                                _real_section = map.add_tempo (_marker->tempo(), pulse, _real_section->type());
                        } else {
                                if (use_snap && _editor->snap_type() == SnapToBar) {
-                                       map.round_bbt (bbt, -1);
+                                       map.round_bbt (bbt, -1, (frame > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
                                } else if (use_snap) {
-                                       map.round_bbt (bbt, _editor->get_grid_beat_divisions (0));
+                                       map.round_bbt (bbt, _editor->get_grid_beat_divisions (0), RoundNearest);
                                }
                                if (use_snap) {
                                        frame = map.predict_tempo_frame (_real_section, bbt);
@@ -3417,17 +3415,17 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
                                const double pulse = map.predict_tempo_pulse (_real_section, pf);
                                when = map.pulse_to_bbt (pulse);
                                if (use_snap && _editor->snap_type() == SnapToBar) {
-                                       map.round_bbt (when, -1);
+                                       map.round_bbt (when, -1, (pf > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
                                } else if (use_snap) {
-                                       map.round_bbt (when, _editor->get_grid_beat_divisions (0));
+                                       map.round_bbt (when, _editor->get_grid_beat_divisions (0), RoundNearest);
                                }
                                const double beat = map.bbt_to_beats (when);
                                map.gui_move_tempo_beat (_real_section, beat);
                        } else {
                                if (use_snap && _editor->snap_type() == SnapToBar) {
-                                       map.round_bbt (when, -1);
+                                       map.round_bbt (when, -1, (pf > _real_section->frame()) ? RoundUpMaybe : RoundDownMaybe);
                                } else if (use_snap) {
-                                       map.round_bbt (when, _editor->get_grid_beat_divisions (0));
+                                       map.round_bbt (when, _editor->get_grid_beat_divisions (0), RoundNearest);
                                }
                                if (use_snap) {
                                        pf = map.predict_tempo_frame (_real_section, when);
index eb6eeb3a50b4d67620dc25596702ad2ae12e4484..87023e0cd8af50d6179541f885cc2d1ec0ab6d2e 100644 (file)
@@ -396,7 +396,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
        void gui_move_tempo_beat (TempoSection*, const double& beat);
        void gui_move_tempo_pulse (TempoSection*, const double& pulse);
        void gui_move_meter (MeterSection*, const framepos_t& frame);
-       void gui_move_meter (MeterSection*, const double& pulse);
+       void gui_move_meter (MeterSection*, const Timecode::BBT_Time& bbt);
        bool gui_change_tempo (TempoSection*, const Tempo& bpm);
        void gui_dilate_tempo (MeterSection*, const framepos_t& frame);
 
@@ -408,7 +408,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
        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 round_bbt (Timecode::BBT_Time& when, const int32_t& snap_divisor);
+       void round_bbt (Timecode::BBT_Time& when, const int32_t& snap_divisor, RoundMode dir);
 
        void set_length (framepos_t frames);
 
@@ -477,7 +477,7 @@ private:
        bool solve_map (Metrics& metrics, TempoSection* section, const framepos_t& frame);
        bool solve_map (Metrics& metrics, TempoSection* section, const double& pulse);
        bool solve_map (Metrics& metrics, MeterSection* section, const framepos_t& frame);
-       bool solve_map (Metrics& metrics, MeterSection* section, const double& pulse);
+       bool solve_map (Metrics& metrics, MeterSection* section, const Timecode::BBT_Time& bbt);
 
        friend class ::BBTTest;
        friend class ::FrameposPlusBeatsTest;
index 7af7545b76a6f50623920adccec85e7864ac990c..a9707c85ef2f44541d6175b1e89870f3824d402f 100644 (file)
@@ -1105,7 +1105,7 @@ TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, boo
        do_insert (new_meter);
 
        if (recompute) {
-               solve_map (_metrics, new_meter, pulse);
+               solve_map (_metrics, new_meter, where);
        }
 
        return new_meter;
@@ -2092,10 +2092,8 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
                TempoSection* t;
                if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
                        if ((t->locked_to_meter() || !t->movable()) && t->frame() == section->frame()) {
-                               if (t->frame() == section->frame()) {
-                                       meter_locked_tempo = t;
-                                       break;
-                               }
+                               meter_locked_tempo = t;
+                               break;
                        }
                }
        }
@@ -2209,7 +2207,6 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
                                        section->set_pulse (0.0);
 
                                }
-                               //section->set_frame (frame);
                                break;
                        }
 
@@ -2232,33 +2229,37 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const framepos_t
 }
 
 bool
-TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const double& pulse)
+TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const BBT_Time& when)
 {
        MeterSection* prev_m = 0;
 
-       section->set_pulse (pulse);
-
        for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
                MeterSection* m;
                if ((m = dynamic_cast<MeterSection*> (*i)) != 0) {
-                       double new_pulse = 0.0;
                        pair<double, BBT_Time> b_bbt;
+                       double new_pulse = 0.0;
 
                        if (prev_m && m == section){
-                               /* the first meter is always audio-locked, so prev_m should exist.
-                                  should we allow setting audio locked meters by pulse?
-                               */
-                               const double beats = floor (((pulse - prev_m->pulse()) * prev_m->note_divisor()) + 0.5);
-                               const int32_t bars = (beats) / prev_m->divisions_per_bar();
-                               pair<double, BBT_Time> b_bbt = make_pair (beats + prev_m->beat(), BBT_Time (bars + prev_m->bbt().bars, 1, 0));
+                               const double beats = (when.bars - prev_m->bbt().bars) * prev_m->divisions_per_bar();
+                               const double pulse = (beats / prev_m->note_divisor()) + prev_m->pulse();
+
+                               b_bbt = make_pair (beats + prev_m->beat(), when);
+
                                section->set_beat (b_bbt);
+                               section->set_pulse (pulse);
                                section->set_frame (frame_at_pulse_locked (imaginary, pulse));
+
                                prev_m = m;
                                continue;
+
+                       } else if (m->bbt().bars == when.bars) {
+                               return false;
                        }
+
                        if (m->position_lock_style() == AudioTime) {
                                if (m->movable()) {
                                        const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
+
                                        if (beats + prev_m->beat() != m->beat()) {
                                                /* tempo/ meter change caused a change in beat (bar). */
                                                b_bbt = make_pair (beats + prev_m->beat()
@@ -2271,12 +2272,23 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const double& pu
                                } else {
                                        b_bbt = make_pair (0.0, BBT_Time (1, 1, 0));
                                }
+
+                               m->set_beat (b_bbt);
+                               m->set_pulse (new_pulse);
+
                        } else {
-                               new_pulse = prev_m->pulse() + ((m->bbt().bars - prev_m->bbt().bars) *  prev_m->divisions_per_bar() / prev_m->note_divisor());
-                               b_bbt = make_pair (((new_pulse - prev_m->pulse()) * prev_m->note_divisor()) + prev_m->beat(), m->bbt());
+                               const double beats = ((m->bbt().bars - prev_m->bbt().bars) * prev_m->divisions_per_bar());
+
+                               b_bbt = make_pair (beats + prev_m->beat()
+                                                  , BBT_Time ((beats / prev_m->divisions_per_bar()) + prev_m->bbt().bars, 1, 0));
+                               new_pulse = prev_m->pulse() + ((m->bbt().bars - prev_m->bbt().bars) *  prev_m->divisions_per_bar()
+                                                              / prev_m->note_divisor());
+
+                               m->set_beat (b_bbt);
+                               m->set_pulse (new_pulse);
+                               m->set_frame (frame_at_pulse_locked (imaginary, new_pulse));
                        }
-                       m->set_beat (b_bbt);
-                       m->set_pulse (new_pulse);
+
                        prev_m = m;
                }
        }
@@ -2521,14 +2533,14 @@ TempoMap::gui_move_meter (MeterSection* ms, const framepos_t&  frame)
 }
 
 void
-TempoMap::gui_move_meter (MeterSection* ms, const double& pulse)
+TempoMap::gui_move_meter (MeterSection* ms, const Timecode::BBT_Time& bbt)
 {
        Metrics future_map;
        {
                Glib::Threads::RWLock::WriterLock lm (lock);
                MeterSection* copy = copy_metrics_and_point (_metrics, future_map, ms);
-               if (solve_map (future_map, copy, pulse)) {
-                       solve_map (_metrics, ms, pulse);
+               if (solve_map (future_map, copy, bbt)) {
+                       solve_map (_metrics, ms, bbt);
                }
        }
 
@@ -2821,16 +2833,27 @@ TempoMap::round_to_beat_subdivision (framepos_t fr, int sub_num, RoundMode dir)
 }
 
 void
-TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num)
+TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num, RoundMode dir)
 {
        if (sub_num == -1) {
-               const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
-               if ((double) when.beats > bpb / 2.0) {
+               if (dir > 0) {
                        ++when.bars;
+                       when.beats = 1;
+                       when.ticks = 0;
+               } else if (dir < 0) {
+                       when.beats = 1;
+                       when.ticks = 0;
+               } else {
+                       const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
+                       if ((double) when.beats > bpb / 2.0) {
+                               ++when.bars;
+                       }
+                       when.beats = 1;
+                       when.ticks = 0;
                }
-               when.beats = 1;
-               when.ticks = 0;
+
                return;
+
        } else if (sub_num == 0) {
                const double bpb = meter_section_at_beat (bbt_to_beats_locked (_metrics, when)).divisions_per_bar();
                if ((double) when.ticks > BBT_Time::ticks_per_beat / 2.0) {
@@ -2841,32 +2864,76 @@ TempoMap::round_bbt (BBT_Time& when, const int32_t& sub_num)
                        }
                }
                when.ticks = 0;
+
                return;
        }
+
        const uint32_t ticks_one_subdivisions_worth = BBT_Time::ticks_per_beat / sub_num;
-       double rem;
-       if ((rem = fmod ((double) when.ticks, (double) ticks_one_subdivisions_worth)) > (ticks_one_subdivisions_worth / 2.0)) {
-               /* closer to the next subdivision, so shift forward */
 
-               when.ticks = when.ticks + (ticks_one_subdivisions_worth - rem);
+       if (dir > 0) {
+               /* round to next (or same iff dir == RoundUpMaybe) */
 
-               if (when.ticks > Timecode::BBT_Time::ticks_per_beat) {
-                       ++when.beats;
-                       when.ticks -= Timecode::BBT_Time::ticks_per_beat;
+               uint32_t mod = when.ticks % ticks_one_subdivisions_worth;
+
+               if (mod == 0 && dir == RoundUpMaybe) {
+                       /* right on the subdivision, which is fine, so do nothing */
+
+               } else if (mod == 0) {
+                       /* right on the subdivision, so the difference is just the subdivision ticks */
+                       when.ticks += ticks_one_subdivisions_worth;
+
+               } else {
+                       /* not on subdivision, compute distance to next subdivision */
+
+                       when.ticks += ticks_one_subdivisions_worth - mod;
                }
 
-       } else if (rem > 0) {
-               /* closer to previous subdivision, so shift backward */
+               if (when.ticks >= BBT_Time::ticks_per_beat) {
+                       when.ticks -= BBT_Time::ticks_per_beat;
+               }
 
-               if (rem > when.ticks) {
-                       if (when.beats == 0) {
-                               /* can't go backwards past zero, so ... */
-                       }
-                       /* step back to previous beat */
-                       --when.beats;
-                       when.ticks = Timecode::BBT_Time::ticks_per_beat - rem;
+       } else if (dir < 0) {
+               /* round to previous (or same iff dir == RoundDownMaybe) */
+
+               uint32_t difference = when.ticks % ticks_one_subdivisions_worth;
+
+               if (difference == 0 && dir == RoundDownAlways) {
+                       /* right on the subdivision, but force-rounding down,
+                          so the difference is just the subdivision ticks */
+                       difference = ticks_one_subdivisions_worth;
+               }
+
+               if (when.ticks < difference) {
+                       when.ticks = BBT_Time::ticks_per_beat - when.ticks;
                } else {
-                       when.ticks = when.ticks - rem;
+                       when.ticks -= difference;
+               }
+
+       } else {
+               /* round to nearest */  double rem;
+               if ((rem = fmod ((double) when.ticks, (double) ticks_one_subdivisions_worth)) > (ticks_one_subdivisions_worth / 2.0)) {
+                       /* closer to the next subdivision, so shift forward */
+
+                       when.ticks = when.ticks + (ticks_one_subdivisions_worth - rem);
+
+                       if (when.ticks > Timecode::BBT_Time::ticks_per_beat) {
+                               ++when.beats;
+                               when.ticks -= Timecode::BBT_Time::ticks_per_beat;
+                       }
+
+               } else if (rem > 0) {
+                       /* closer to previous subdivision, so shift backward */
+
+                       if (rem > when.ticks) {
+                               if (when.beats == 0) {
+                                       /* can't go backwards past zero, so ... */
+                               }
+                               /* step back to previous beat */
+                               --when.beats;
+                               when.ticks = Timecode::BBT_Time::ticks_per_beat - rem;
+                       } else {
+                               when.ticks = when.ticks - rem;
+                       }
                }
        }
 }