Tempo ramps - tempo marks use mvc-style copy drag, don't crash if two successive...
authornick_m <mainsbridge@gmail.com>
Sun, 3 Apr 2016 17:00:40 +0000 (03:00 +1000)
committernick_m <mainsbridge@gmail.com>
Fri, 27 May 2016 13:38:14 +0000 (23:38 +1000)
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_tempodisplay.cc
libs/ardour/ardour/tempo.h
libs/ardour/tempo.cc

index 0dedff5446d01ddb03c3d2233df776d72dab408c..c7e96b27f7c95d059ac9ecf89141763e38a6b351 100644 (file)
@@ -3301,20 +3301,69 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
 
                /* use the new marker for the grab */
                swap_grab (&_marker->the_item(), 0, GDK_CURRENT_TIME);
+               _marker->hide();
 
+               TempoMap& map (_editor->session()->tempo_map());
+               /* get current state */
+               before_state = &map.get_state();
                if (!_copy) {
                        _editor->begin_reversible_command (_("move tempo mark"));
-                       TempoMap& map (_editor->session()->tempo_map());
-                       /* get current state */
-                       before_state = &map.get_state();
+               } else {
+                       _editor->begin_reversible_command (_("copy tempo mark"));
+                       framepos_t frame;
+                       bool use_snap = false;
+
+                       if (!_editor->snap_musical()) {
+                               frame = adjusted_current_frame (event);
+                       } else {
+                               frame = adjusted_current_frame (event, false);
+                               if (ArdourKeyboard::indicates_snap (event->button.state)) {
+                                       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 bbt;
+                       map.bbt_time (frame, bbt);
+
+                       /* add new tempo section to map, ensuring we don't refer to existing tempos for snap */
+
+                       if (_real_section->position_lock_style() == MusicTime) {
+                               if (use_snap && _editor->snap_type() == SnapToBar) {
+                                       map.round_bbt (bbt, -1);
+                               } else if (use_snap) {
+                                       map.round_bbt (bbt, _editor->get_grid_beat_divisions (0));
+                               }
+                               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);
+                               } else if (use_snap) {
+                                       map.round_bbt (bbt, _editor->get_grid_beat_divisions (0));
+                               }
+                               if (use_snap) {
+                                       frame = map.predict_tempo_frame (_real_section, bbt);
+                               }
+                               _real_section = map.add_tempo (_marker->tempo(), frame, _real_section->type());
+                       }
                }
-               _marker->hide();
+
        }
 
        framepos_t pf;
        Tempo const tp = _marker->tempo();
 
-       if (Keyboard::modifier_state_equals (event->button.state, ArdourKeyboard::constraint_modifier ())) {
+       if (ArdourKeyboard::indicates_snap (event->button.state)) {
                double new_bpm = _real_section->beats_per_minute() + ((last_pointer_y() - current_pointer_y()) / 5.0);
                _editor->session()->tempo_map().gui_change_tempo (_real_section, Tempo (new_bpm, _real_section->note_type()));
                stringstream strs;
@@ -3322,8 +3371,14 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
                show_verbose_cursor_text (strs.str());
        } else if (_movable) {
                if (!_editor->snap_musical()) {
+                       /* snap normally (this is not self-referential).*/
                        pf = adjusted_current_frame (event);
                } else {
+                       /* but this is.
+                          we can't use the map for anything related to tempo,
+                          so we round bbt using meters, which have no dependency
+                          on pulse for this kind of thing.
+                       */
                        bool use_snap;
                        TempoMap& map (_editor->session()->tempo_map());
 
@@ -3387,38 +3442,11 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
                return;
        }
 
-
        TempoMap& map (_editor->session()->tempo_map());
 
-       if (_copy == true) {
-               _editor->begin_reversible_command (_("copy tempo mark"));
-               XMLNode &before = map.get_state();
-
-               if (_marker->tempo().position_lock_style() == MusicTime) {
-                       double const pulse = map.predict_tempo_pulse (_real_section, _real_section->frame());
-                       map.add_tempo (_marker->tempo(), pulse, _marker->tempo().type());
-               } else {
-                       map.add_tempo (_marker->tempo(), _real_section->frame(), _marker->tempo().type());
-               }
-
-               XMLNode &after = map.get_state();
-               _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
-               _editor->commit_reversible_command ();
-
-       } else {
-               if (_marker->tempo().position_lock_style() == MusicTime) {
-                       double const pulse = map.predict_tempo_pulse (_real_section, _real_section->frame());
-                       map.replace_tempo (*_real_section, Tempo (_real_section->beats_per_minute(), _real_section->note_type())
-                                          , pulse, _marker->tempo().type());
-               } else {
-                       map.replace_tempo (*_real_section, Tempo (_real_section->beats_per_minute(), _real_section->note_type())
-                                          , _real_section->frame(), _marker->tempo().type());
-               }
-
-               XMLNode &after = map.get_state();
-               _editor->session()->add_command (new MementoCommand<TempoMap>(map, before_state, &after));
-               _editor->commit_reversible_command ();
-       }
+       XMLNode &after = map.get_state();
+       _editor->session()->add_command (new MementoCommand<TempoMap>(map, before_state, &after));
+       _editor->commit_reversible_command ();
 
        // delete the dummy marker we used for visual representation while moving.
        // a new visual marker will show up automatically.
@@ -3431,12 +3459,7 @@ TempoMarkerDrag::aborted (bool moved)
        _marker->set_position (_marker->tempo().frame());
        if (moved) {
                TempoMap& map (_editor->session()->tempo_map());
-               /* we removed it before, so add it back now */
-               if (_marker->tempo().position_lock_style() == MusicTime) {
-                       map.add_tempo (_marker->tempo(), _marker->tempo().pulse(), _marker->tempo().type());
-               } else {
-                       map.add_tempo (_marker->tempo(), _marker->tempo().frame(), _marker->tempo().type());
-               }
+               map.set_state (*before_state, Stateful::current_state_version);
                // delete the dummy marker we used for visual representation while moving.
                // a new visual marker will show up automatically.
                delete _marker;
index 3931e0bf0991f8ec454ce2d6488df814f0e58ddb..fecdeb0ecb206e081289210541939dd9e8eff6a5 100644 (file)
@@ -368,7 +368,7 @@ Editor::edit_tempo_section (TempoSection* section)
        double nt = tempo_dialog.get_note_type ();
        Timecode::BBT_Time when;
 
-       tempo_dialog.get_bbt_time(when);
+       tempo_dialog.get_bbt_time (when);
        double const beat = _session->tempo_map().bbt_to_beats (when);
 
        bpm = max (0.01, bpm);
index 98c6e82c16560a7cdb4dcff3cc5955018a2d3a94..1a37ecffe50d41c163d7d44a3f152bf3705aaa1d 100644 (file)
@@ -373,8 +373,8 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
        const MeterSection& meter_section_at (framepos_t frame) const;
        const MeterSection& meter_section_at (const double& beat) const;
 
-       void add_tempo (const Tempo&, const double& pulse, TempoSection::Type type);
-       void add_tempo (const Tempo&, const framepos_t& frame, TempoSection::Type type);
+       TempoSection* add_tempo (const Tempo&, const double& pulse, TempoSection::Type type);
+       TempoSection* add_tempo (const Tempo&, const framepos_t& frame, TempoSection::Type type);
 
        MeterSection* add_meter (const Meter&, const double& beat, const Timecode::BBT_Time& where);
        MeterSection* add_meter (const Meter&, const framepos_t& frame, const double& beat, const Timecode::BBT_Time& where);
@@ -489,8 +489,8 @@ private:
 
        void do_insert (MetricSection* section);
 
-       void add_tempo_locked (const Tempo&, double pulse, bool recompute, TempoSection::Type type);
-       void add_tempo_locked (const Tempo&, framepos_t frame, bool recompute, TempoSection::Type type);
+       TempoSection* add_tempo_locked (const Tempo&, double pulse, bool recompute, TempoSection::Type type);
+       TempoSection* add_tempo_locked (const Tempo&, framepos_t frame, bool recompute, TempoSection::Type type);
 
        MeterSection* add_meter_locked (const Meter&, double beat, Timecode::BBT_Time where, bool recompute);
        MeterSection* add_meter_locked (const Meter&, framepos_t frame, double beat, Timecode::BBT_Time where, bool recompute);
index 88199a0d6464bcedce82f53366d504ee3e3ee383..d4c0a1d6393ecda3735be56d36dbb1a3b538f19d 100644 (file)
@@ -198,7 +198,7 @@ double
 TempoSection::tempo_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const
 {
 
-       if (_type == Constant) {
+       if (_type == Constant || _c_func == 0.0) {
                return pulses_per_minute();
        }
 
@@ -213,7 +213,7 @@ TempoSection::tempo_at_frame (const framepos_t& f, const framecnt_t& frame_rate)
 framepos_t
 TempoSection::frame_at_tempo (const double& ppm, const double& b, const framecnt_t& frame_rate) const
 {
-       if (_type == Constant) {
+       if (_type == Constant || _c_func == 0.0) {
                return ((b - pulse())  * frames_per_pulse (frame_rate))  + frame();
        }
 
@@ -225,7 +225,7 @@ double
 TempoSection::tempo_at_pulse (const double& p) const
 {
 
-       if (_type == Constant) {
+       if (_type == Constant || _c_func == 0.0) {
                return pulses_per_minute();
        }
        double const ppm = pulse_tempo_at_pulse (p - pulse());
@@ -239,7 +239,7 @@ TempoSection::tempo_at_pulse (const double& p) const
 double
 TempoSection::pulse_at_tempo (const double& ppm, const framepos_t& f, const framecnt_t& frame_rate) const
 {
-       if (_type == Constant) {
+       if (_type == Constant || _c_func == 0.0) {
                double const pulses = ((f - frame()) / frames_per_pulse (frame_rate)) + pulse();
                return  pulses;
        }
@@ -253,7 +253,7 @@ TempoSection::pulse_at_tempo (const double& ppm, const framepos_t& f, const fram
 double
 TempoSection::pulse_at_frame (const framepos_t& f, const framecnt_t& frame_rate) const
 {
-       if (_type == Constant) {
+       if (_type == Constant || _c_func == 0.0) {
                return ((f - frame()) / frames_per_pulse (frame_rate)) + pulse();
        }
 
@@ -268,7 +268,7 @@ TempoSection::pulse_at_frame (const framepos_t& f, const framecnt_t& frame_rate)
 framepos_t
 TempoSection::frame_at_pulse (const double& p, const framecnt_t& frame_rate) const
 {
-       if (_type == Constant) {
+       if (_type == Constant || _c_func == 0.0) {
                return (framepos_t) floor ((p - pulse()) * frames_per_pulse (frame_rate)) + frame();
        }
 
@@ -885,51 +885,61 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const frame
        PropertyChanged (PropertyChange ());
 }
 
-void
+TempoSection*
 TempoMap::add_tempo (const Tempo& tempo, const double& pulse, ARDOUR::TempoSection::Type type)
 {
+       TempoSection* ts = 0;
        {
                Glib::Threads::RWLock::WriterLock lm (lock);
-               add_tempo_locked (tempo, pulse, true, type);
+               ts = add_tempo_locked (tempo, pulse, true, type);
        }
 
        PropertyChanged (PropertyChange ());
+
+       return ts;
 }
 
-void
+TempoSection*
 TempoMap::add_tempo (const Tempo& tempo, const framepos_t& frame, ARDOUR::TempoSection::Type type)
 {
+       TempoSection* ts = 0;
        {
                Glib::Threads::RWLock::WriterLock lm (lock);
-               add_tempo_locked (tempo, frame, true, type);
+               ts = add_tempo_locked (tempo, frame, true, type);
        }
 
 
        PropertyChanged (PropertyChange ());
+
+       return ts;
 }
 
-void
+TempoSection*
 TempoMap::add_tempo_locked (const Tempo& tempo, double pulse, bool recompute, ARDOUR::TempoSection::Type type)
 {
-       TempoSection* ts = new TempoSection (pulse, tempo.beats_per_minute(), tempo.note_type(), type);
+       TempoSection* t = new TempoSection (pulse, tempo.beats_per_minute(), tempo.note_type(), type);
 
-       do_insert (ts);
+       do_insert (t);
 
        if (recompute) {
-               solve_map (_metrics, ts, ts->pulse());
+               solve_map (_metrics, t, t->pulse());
        }
+
+       return t;
 }
 
-void
+TempoSection*
 TempoMap::add_tempo_locked (const Tempo& tempo, framepos_t frame, bool recompute, ARDOUR::TempoSection::Type type)
 {
-       TempoSection* ts = new TempoSection (frame, tempo.beats_per_minute(), tempo.note_type(), type);
+       TempoSection* t = new TempoSection (frame, tempo.beats_per_minute(), tempo.note_type(), type);
 
-       do_insert (ts);
+       do_insert (t);
 
        if (recompute) {
-               solve_map (_metrics, ts, ts->frame());
+               solve_map (_metrics, t, t->frame());
        }
+
+       return t;
 }
 
 void
@@ -1058,7 +1068,6 @@ TempoMap::add_meter_locked (const Meter& meter, double beat, BBT_Time where, boo
 MeterSection*
 TempoMap::add_meter_locked (const Meter& meter, framepos_t frame, double beat, Timecode::BBT_Time where, bool recompute)
 {
-
        MeterSection* new_meter = new MeterSection (frame, beat, where, meter.divisions_per_bar(), meter.note_divisor());
 
        double pulse = pulse_at_frame_locked (_metrics, frame);
@@ -1236,6 +1245,11 @@ TempoMap::recompute_tempos (Metrics& metrics)
                        if (!t->active()) {
                                continue;
                        }
+                       if (!t->movable()) {
+                               t->set_pulse (0.0);
+                               prev_t = t;
+                               continue;
+                       }
                        if (prev_t) {
                                if (t->position_lock_style() == AudioTime) {
                                        prev_t->set_c_func (prev_t->compute_c_func_frame (t->pulses_per_minute(), t->frame(), _frame_rate));
@@ -1729,8 +1743,8 @@ TempoMap::check_solved (Metrics& metrics, bool by_frame)
                                        return false;
                                }
 
-                               /* precision check ensures pulses and frames align independent of lock style.*/
-                               if (by_frame && t->frame() != prev_t->frame_at_pulse (t->pulse(), _frame_rate)) {
+                               /* precision check ensures pulses and frames align.*/
+                               if (t->frame() != prev_t->frame_at_pulse (t->pulse(), _frame_rate)) {
                                        return false;
                                }
                        }
@@ -1782,9 +1796,9 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const framepos_t
        }
        if (section->movable() && frame <= first_m_frame) {
                return false;
-       } else {
-               section->set_active (true);
        }
+
+       section->set_active (true);
        section->set_frame (frame);
 
        for (Metrics::iterator i = imaginary.begin(); i != imaginary.end(); ++i) {
@@ -1840,11 +1854,12 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const framepos_t
        } else {
                recompute_tempos (imaginary);
        }
+
        if (check_solved (imaginary, true)) {
                recompute_meters (imaginary);
                return true;
        }
-
+#if (0)
        MetricSectionSorter cmp;
        imaginary.sort (cmp);
        if (section->position_lock_style() == MusicTime) {
@@ -1855,10 +1870,12 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const framepos_t
        } else {
                recompute_tempos (imaginary);
        }
+
        if (check_solved (imaginary, true)) {
                recompute_meters (imaginary);
                return true;
        }
+#endif
        //dump (imaginary, std::cerr);
 
        return false;
@@ -1878,6 +1895,11 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const double& pu
                        if (!t->active()) {
                                continue;
                        }
+                       if (!t->movable()) {
+                               t->set_pulse (0.0);
+                               prev_t = t;
+                               continue;
+                       }
                        if (prev_t) {
                                if (t == section) {
                                        section_prev = prev_t;
@@ -1907,6 +1929,7 @@ TempoMap::solve_map (Metrics& imaginary, TempoSection* section, const double& pu
        } else {
                recompute_tempos (imaginary);
        }
+
        if (check_solved (imaginary, false)) {
                recompute_meters (imaginary);
                return true;
@@ -2121,22 +2144,24 @@ TempoMap::solve_map (Metrics& imaginary, MeterSection* section, const double& pu
 }
 
 /** places a copy of _metrics into copy and returns a pointer
- *  to section's equivalent.
+ *  to section's equivalent in copy.
  */
 TempoSection*
 TempoMap::copy_metrics_and_point (Metrics& copy, TempoSection* section)
 {
        TempoSection* t;
-       TempoSection* ret = 0;
        MeterSection* m;
+       TempoSection* ret = 0;
 
        for (Metrics::iterator i = _metrics.begin(); i != _metrics.end(); ++i) {
                if ((t = dynamic_cast<TempoSection*> (*i)) != 0) {
                        if (t == section) {
                                if (t->position_lock_style() == MusicTime) {
                                        ret = new TempoSection (t->pulse(), t->beats_per_minute(), t->note_type(), t->type());
+                                       ret->set_frame (t->frame());
                                } else {
                                        ret = new TempoSection (t->frame(), t->beats_per_minute(), t->note_type(), t->type());
+                                       ret->set_pulse (t->pulse());
                                }
                                ret->set_active (t->active());
                                ret->set_movable (t->movable());
@@ -2146,8 +2171,10 @@ TempoMap::copy_metrics_and_point (Metrics& copy, TempoSection* section)
                        TempoSection* cp = 0;
                        if (t->position_lock_style() == MusicTime) {
                                cp = new TempoSection (t->pulse(), t->beats_per_minute(), t->note_type(), t->type());
+                               cp->set_frame (t->frame());
                        } else {
                                cp = new TempoSection (t->frame(), t->beats_per_minute(), t->note_type(), t->type());
+                               cp->set_pulse (t->pulse());
                        }
                        cp->set_active (t->active());
                        cp->set_movable (t->movable());
@@ -2166,7 +2193,7 @@ TempoMap::copy_metrics_and_point (Metrics& copy, TempoSection* section)
                        copy.push_back (cp);
                }
        }
-       //recompute_map (copy);
+
        return ret;
 }
 
@@ -2210,6 +2237,7 @@ TempoMap::predict_tempo_frame (TempoSection* section, const BBT_Time& bbt)
        TempoSection* new_section = copy_metrics_and_point (future_map, section);
 
        const double beat = bbt_to_beats_locked (future_map, bbt);
+
        if (solve_map (future_map, new_section, pulse_at_beat_locked (future_map, beat))) {
                ret = new_section->frame();
        } else {
@@ -2347,10 +2375,8 @@ TempoMap::bbt_duration_at (framepos_t pos, const BBT_Time& bbt, int dir)
        const double tick_at_time = beat_at_frame_locked (_metrics, pos) * BBT_Time::ticks_per_beat;
        const double bbt_ticks = bbt.ticks + (bbt.beats * BBT_Time::ticks_per_beat);
        const double total_beats = (tick_at_time + bbt_ticks) / BBT_Time::ticks_per_beat;
-       const framecnt_t time_at_bbt = frame_at_beat_locked (_metrics, total_beats);
-       const framecnt_t ret = time_at_bbt;
 
-       return ret;
+       return frame_at_beat_locked (_metrics, total_beats);
 }
 
 framepos_t
@@ -2679,8 +2705,8 @@ TempoMap::tempo_at_locked (const framepos_t& frame) const
                        }
                        if ((prev_t) && t->frame() > frame) {
                                /* t is the section past frame */
-                               const double ret = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
-                               const Tempo ret_tempo (ret, prev_t->note_type());
+                               const double ret_bpm = prev_t->tempo_at_frame (frame, _frame_rate) * prev_t->note_type();
+                               const Tempo ret_tempo (ret_bpm, prev_t->note_type());
                                return ret_tempo;
                        }
                        prev_t = t;
@@ -2703,7 +2729,6 @@ TempoMap::meter_section_at (framepos_t frame) const
 const MeterSection&
 TempoMap::meter_section_at_locked (framepos_t frame) const
 {
-       //framepos_t const frame_off = frame + frame_offset_at (_metrics, frame);
        Metrics::const_iterator i;
        MeterSection* prev = 0;