Tempo ramps - allow live updating of tempo markers.
authornick_m <mainsbridge@gmail.com>
Tue, 22 Dec 2015 18:58:49 +0000 (05:58 +1100)
committernick_m <mainsbridge@gmail.com>
Fri, 27 May 2016 13:38:09 +0000 (23:38 +1000)
- all a bit slow, but should be ok once we can lock
  markers to frames.

gtk2_ardour/editor.cc
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 7353b6ff38a7bc9db6f09db1efcfb5a836fb0d5e..0d7717614c92b6a7df49dab820720306ad328de0 100644 (file)
@@ -1365,6 +1365,7 @@ Editor::set_session (Session *t)
        _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
        _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
        _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
+       _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
        _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
        _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
        _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
index 139e044eae9d23236100a86c4e8cb3d93754f66e..7a2988005dbedcb8b3e46544e681ac5c6a60eed2 100644 (file)
@@ -1697,6 +1697,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
        void compute_current_bbt_points (std::vector<ARDOUR::TempoMap::BBTPoint>& grid, framepos_t left, framepos_t right);
 
        void tempo_map_changed (const PBD::PropertyChange&);
+       void marker_position_changed ();
        void redisplay_tempo (bool immediate_redraw);
 
        uint32_t bbt_beat_subdivision;
index 238a0d8ab00122fb65b8aac87e6945e3f6026c38..dccb6cac51c94ea9c499d817d7b01be4556c62c0 100644 (file)
@@ -515,7 +515,6 @@ Drag::add_midi_region (MidiTimeAxisView* view, bool commit)
        if (_editor->session()) {
                const TempoMap& map (_editor->session()->tempo_map());
                framecnt_t pos = grab_frame();
-               const Meter& m = map.meter_at (pos);
                /* not that the frame rate used here can be affected by pull up/down which
                   might be wrong.
                */
@@ -3255,6 +3254,7 @@ TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
        DEBUG_TRACE (DEBUG::Drags, "New TempoMarkerDrag\n");
 
        _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
+       _real_section = &_marker->tempo();
        assert (_marker);
 }
 
@@ -3310,12 +3310,15 @@ TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
                        /* get current state */
                        before_state = &map.get_state();
                        /* remove the section while we drag it */
-                       map.remove_tempo (section, true);
+                       //map.remove_tempo (section, true);
                }
        }
 
-       framepos_t const pf = adjusted_current_frame (event);
+       framepos_t const pf = adjusted_current_frame (event, false);
+       TempoMap& map (_editor->session()->tempo_map());
        _marker->set_position (pf);
+       map.gui_set_tempo_frame (*_real_section, pf);
+
        show_verbose_cursor_time (pf);
 }
 
@@ -3351,7 +3354,7 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
 
        } else {
                /* we removed it before, so add it back now */
-               map.add_tempo (_marker->tempo(), when, _marker->tempo().type());
+               map.replace_tempo (*_real_section, _marker->tempo().beats_per_minute() , when, _marker->tempo().type());
                XMLNode &after = map.get_state();
                _editor->session()->add_command (new MementoCommand<TempoMap>(map, before_state, &after));
                _editor->commit_reversible_command ();
index cd1b0c2474446934222a3f5cf9b3b41623fb6276..bd2672e23e3c3189b8021d5042343c5bc2d71d49 100644 (file)
@@ -25,6 +25,7 @@
 #include <gdk/gdk.h>
 #include <stdint.h>
 
+#include "ardour/tempo.h"
 #include "ardour/types.h"
 
 #include "canvas/types.h"
@@ -731,6 +732,8 @@ public:
 
 private:
        TempoMarker* _marker;
+       ARDOUR::TempoSection* _real_section;
+
        bool _copy;
        XMLNode* before_state;
 };
index 2d5a3e47d5d94295d47b7265a46b5080f0626d85..2794051265e912bc10c617bd1cd02796a4eb1d2e 100644 (file)
@@ -101,6 +101,7 @@ Editor::draw_metric_marks (const Metrics& metrics)
 
 }
 
+
 void
 Editor::tempo_map_changed (const PropertyChange& /*ignored*/)
 {
@@ -122,6 +123,27 @@ Editor::tempo_map_changed (const PropertyChange& /*ignored*/)
        update_tempo_based_rulers (grid);
 }
 
+void
+Editor::marker_position_changed ()
+{
+// yes its identical...
+       if (!_session) {
+               return;
+       }
+
+       ENSURE_GUI_THREAD (*this, &Editor::tempo_map_changed);
+
+       if (tempo_lines) {
+               tempo_lines->tempo_map_changed();
+       }
+
+       std::vector<TempoMap::BBTPoint> grid;
+       compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
+       _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
+       draw_measures (grid);
+       update_tempo_based_rulers (grid);
+}
+
 void
 Editor::redisplay_tempo (bool immediate_redraw)
 {
index 5f511243723d00baedef171d468c92131e1afb21..403b4c59c92efa4fa06729b8be7a74e8d0ceede9 100644 (file)
@@ -27,6 +27,7 @@
 #include <glibmm/threads.h>
 
 #include "pbd/undo.h"
+
 #include "pbd/stateful.h"
 #include "pbd/statefuldestructible.h"
 
@@ -54,7 +55,8 @@ class LIBARDOUR_API Tempo {
        Tempo (double bpm, double type=4.0) // defaulting to quarter note
                : _beats_per_minute (bpm), _note_type(type) {}
 
-       double beats_per_minute () const { return _beats_per_minute;}
+       double beats_per_minute () const { return _beats_per_minute; }
+
        double ticks_per_minute () const { return _beats_per_minute * Timecode::BBT_Time::ticks_per_beat;}
        double note_type () const { return _note_type;}
        /** audio samples per beat
@@ -125,6 +127,7 @@ class LIBARDOUR_API MetricSection {
        virtual XMLNode& get_state() const = 0;
 
   private:
+
        Timecode::BBT_Time _start;
        framepos_t         _frame;
        bool               _movable;
@@ -350,6 +353,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
        void remove_meter (const MeterSection&, bool send_signal);
 
        void replace_tempo (const TempoSection&, const Tempo&, const Timecode::BBT_Time& where, TempoSection::Type type);
+       void gui_set_tempo_frame (TempoSection&, framepos_t where);
        void replace_meter (const MeterSection&, const Meter&, const Timecode::BBT_Time& where);
 
        framepos_t round_to_bar  (framepos_t frame, RoundMode dir);
@@ -383,7 +387,7 @@ class LIBARDOUR_API TempoMap : public PBD::StatefulDestructible
        int n_meters () const;
 
        framecnt_t frame_rate () const { return _frame_rate; }
-
+       PBD::Signal0<void> MetricPositionChanged;
   private:
 
        friend class ::BBTTest;
index ef7c7d0239ce69d6893cfd1f0efc7d0036ce1288..19b25544dc07c278dcbe6876f2a583071e1c3f1e 100644 (file)
@@ -65,6 +65,7 @@ Meter::frames_per_bar (const Tempo& tempo, framecnt_t sr) const
        return frames_per_grid (tempo, sr) * _divisions_per_bar;
 }
 
+
 /***********************************************************************/
 
 const string TempoSection::xml_state_node_name = "Tempo";
@@ -72,7 +73,7 @@ const string TempoSection::xml_state_node_name = "Tempo";
 TempoSection::TempoSection (const XMLNode& node)
        : MetricSection (BBT_Time()), Tempo (TempoMap::default_tempo())
 {
-       XMLProperty const * prop;
+       const XMLProperty *prop;
        BBT_Time start;
        LocaleGuard lg;
 
@@ -326,7 +327,8 @@ TempoSection::update_bbt_time_from_bar_offset (const Meter& meter)
 
        double ticks = BBT_Time::ticks_per_beat * meter.divisions_per_bar() * _bar_offset;
        new_start.beats = (uint32_t) floor (ticks/BBT_Time::ticks_per_beat);
-       new_start.ticks = 0; /* (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat); */
+       //new_start.ticks = 0; /* (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat); */
+       new_start.ticks = (uint32_t) fmod (ticks, BBT_Time::ticks_per_beat);
 
        /* remember the 1-based counting properties of beats */
        new_start.beats += 1;
@@ -443,6 +445,7 @@ TempoMap::TempoMap (framecnt_t fr)
 
        metrics.push_back (t);
        metrics.push_back (m);
+
 }
 
 TempoMap::~TempoMap ()
@@ -647,9 +650,9 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_T
                        remove_tempo_locked (ts);
                        add_tempo_locked (tempo, where, true, type);
                } else {
+                       first.set_type (type);
                        {
                                /* cannot move the first tempo section */
-                               first.set_type (type);
                                *static_cast<Tempo*>(&first) = tempo;
                                recompute_map (false);
                        }
@@ -659,6 +662,28 @@ TempoMap::replace_tempo (const TempoSection& ts, const Tempo& tempo, const BBT_T
        PropertyChanged (PropertyChange ());
 }
 
+void
+TempoMap::gui_set_tempo_frame (TempoSection& ts, framepos_t frame)
+{
+       {
+               TempoSection& first (first_tempo());
+
+               if (ts.start() != first.start()) {
+                       BBT_Time bbt;
+                       bbt_time (frame, bbt);
+                       {
+                               Glib::Threads::RWLock::WriterLock lm (lock);
+                               ts.set_frame (frame);
+                               ts.set_start (bbt);
+
+                               recompute_map (false);
+                       }
+               }
+       }
+
+       MetricPositionChanged (); // Emit Signal
+}
+
 void
 TempoMap::add_tempo (const Tempo& tempo, BBT_Time where, ARDOUR::TempoSection::Type type)
 {
@@ -933,13 +958,6 @@ TempoMap::recompute_map (bool reassign_tempo_bbt, framepos_t end)
                */
                end = max_framepos;
 
-       } else {
-               /*
-               if (!_map.empty ()) {
-                       /* never allow the map to be shortened /
-                       end = max (end, _map.back().frame);
-               }
-               */
        }
 
        DEBUG_TRACE (DEBUG::TempoMath, string_compose ("recomputing tempo map, zero to %1\n", end));
@@ -1051,15 +1069,11 @@ TempoMap::_extend_map (TempoSection* tempo, MeterSection* meter,
 
                                                        /*tempo section (t) lies in the previous meter */
                                                        double ticks_at_ts = ((((t->start().bars - 1 ) * meter->divisions_per_bar()) + (t->start().beats - 1) )  * BBT_Time::ticks_per_beat) + t->start().ticks;
-
-
                                                        double ticks_at_prev_ts = ((((prev_ts->start().bars - 1) * meter->divisions_per_bar()) + (prev_ts->start().beats - 1))  * BBT_Time::ticks_per_beat) + prev_ts->start().ticks;
-
                                                        double ticks_relative_to_prev_ts = ticks_at_ts - ticks_at_prev_ts;
                                                        /* assume (falsely) that the target tempo is constant */
                                                        double length_estimate = (ticks_relative_to_prev_ts /  BBT_Time::ticks_per_beat) * meter->frames_per_grid (*t, _frame_rate);
                                                        if (prev_ts->type() == TempoSection::Type::Constant) {
-                                                               cerr << "constant type " << endl;
                                                                length_estimate = (ticks_relative_to_prev_ts / BBT_Time::ticks_per_beat) * prev_ts->frames_per_beat (_frame_rate);
                                                        }
                                                        cerr<< "initial length extimate = " << length_estimate << " ticks_relative_to_prev_ts " << ticks_relative_to_prev_ts << endl;
@@ -1378,6 +1392,8 @@ TempoMap::frame_at_tick (double tick) const
        Glib::Threads::RWLock::ReaderLock lm (lock);
 
        double accumulated_ticks = 0.0;
+       double accumulated_ticks_to_prev = 0.0;
+
        const TempoSection* prev_ts =  &first_tempo();
        uint32_t cnt = 0;
 
@@ -1397,12 +1413,13 @@ TempoMap::frame_at_tick (double tick) const
                        if (tick < accumulated_ticks) {
                                /* prev_ts is the one affecting us. */
 
-                               double ticks_in_section = tick - tick_at_frame (prev_ts->frame());
+                               double ticks_in_section = tick - accumulated_ticks_to_prev;
                                framepos_t section_start = prev_ts->frame();
                                framepos_t last_time = t->frame() - prev_ts->frame();
                                double last_beats_per_minute = t->beats_per_minute();
                                return prev_ts->frame_at_tick (ticks_in_section, last_beats_per_minute, last_time, _frame_rate) + section_start;
                        }
+                       accumulated_ticks_to_prev = accumulated_ticks;
 
                        prev_ts = t;
                        ++cnt;