midi note drags are music-based.
authornick_m <mainsbridge@gmail.com>
Sat, 4 Feb 2017 18:02:01 +0000 (05:02 +1100)
committernick_m <mainsbridge@gmail.com>
Sat, 4 Feb 2017 18:02:01 +0000 (05:02 +1100)
- wysiwyg (during drag) when dragging more than one note across
  a tempo change.

- introduces a muscal equivalent of snap_delta (only used for
  note drags atm)

- split earliest note in selection into a separate function

- MRV::copy_selection() returns the equivalent _primary note
     to avoid offset hell.

- RV::snap_frame_to_frame returns a MusicFrame

- prevent note drag moving before region start.

gtk2_ardour/automation_region_view.cc
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_drag.h
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_region_view.h
gtk2_ardour/region_view.cc
gtk2_ardour/region_view.h

index 8354e16b10425683b232c4f9fbb653dda85c3e6a..e3e41b442801028c6eb47aefc01709749e747c52 100644 (file)
@@ -183,7 +183,7 @@ AutomationRegionView::add_automation_event (GdkEvent *, framepos_t when, double
 
        /* snap frame */
 
-       when = snap_frame_to_frame (when - _region->start ()) + _region->start ();
+       when = snap_frame_to_frame (when - _region->start ()).frame + _region->start ();
 
        /* map using line */
 
index 7624546347924e2fa60b79fa9060ab095cbd5629..cf24ddbe9eb36b06959aae7d69b1fd9ac77c8870 100644 (file)
@@ -238,6 +238,7 @@ Drag::Drag (Editor* e, ArdourCanvas::Item* i, bool trackview_only)
        , _grab_frame (0)
        , _last_pointer_frame (0)
        , _snap_delta (0)
+       , _snap_delta_music (0.0)
        , _constraint_pressed (false)
 {
 
@@ -355,6 +356,15 @@ Drag::snap_delta (guint state) const
 
        return 0;
 }
+double
+Drag::snap_delta_music (guint state) const
+{
+       if (ArdourKeyboard::indicates_snap_delta (state)) {
+               return _snap_delta_music;
+       }
+
+       return 0.0;
+}
 
 double
 Drag::current_pointer_x() const
@@ -373,11 +383,18 @@ Drag::current_pointer_y () const
 }
 
 void
-Drag::setup_snap_delta (framepos_t pos)
+Drag::setup_snap_delta (MusicFrame pos)
 {
-       MusicFrame snap (pos, 0);
+       TempoMap& map (_editor->session()->tempo_map());
+       MusicFrame snap (pos);
        _editor->snap_to (snap, ARDOUR::RoundNearest, false, true);
-       _snap_delta = snap.frame - pos;
+       _snap_delta = snap.frame - pos.frame;
+
+       _snap_delta_music = 0.0;
+
+       if (_snap_delta != 0) {
+               _snap_delta_music = map.exact_qn_at_frame (snap.frame, snap.division) - map.exact_qn_at_frame (pos.frame, pos.division);
+       }
 }
 
 bool
@@ -618,7 +635,7 @@ void
 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 {
        Drag::start_grab (event, cursor);
-       setup_snap_delta (_last_position.frame);
+       setup_snap_delta (_last_position);
 
        show_verbose_cursor_time (_last_position.frame);
 
@@ -2862,7 +2879,7 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
        framecnt_t const region_length = (framecnt_t) (_primary->region()->length() / speed);
 
        framepos_t const pf = adjusted_current_frame (event);
-       setup_snap_delta (region_start);
+       setup_snap_delta (MusicFrame(region_start, 0));
 
        if (Keyboard::modifier_state_equals (event->button.state, ArdourKeyboard::trim_contents_modifier ())) {
                /* Move the contents of the region around without changing the region bounds */
@@ -3641,7 +3658,7 @@ void
 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
 {
        Drag::start_grab (event, c);
-       setup_snap_delta (_editor->playhead_cursor->current_frame());
+       setup_snap_delta (MusicFrame (_editor->playhead_cursor->current_frame(), 0));
 
        _grab_zoom = _editor->samples_per_pixel;
 
@@ -3744,7 +3761,7 @@ FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 
        AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
        boost::shared_ptr<AudioRegion> const r = arv->audio_region ();
-       setup_snap_delta (r->position());
+       setup_snap_delta (MusicFrame (r->position(), 0));
 
        show_verbose_cursor_duration (r->position(), r->position() + r->fade_in()->back()->when, 32);
 }
@@ -3870,7 +3887,7 @@ FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 
        AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
        boost::shared_ptr<AudioRegion> r = arv->audio_region ();
-       setup_snap_delta (r->last_frame());
+       setup_snap_delta (MusicFrame (r->last_frame(), 0));
 
        show_verbose_cursor_duration (r->last_frame() - r->fade_out()->back()->when, r->last_frame());
 }
@@ -4031,7 +4048,7 @@ MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
        } else {
                show_verbose_cursor_time (location->end());
        }
-       setup_snap_delta (is_start ? location->start() : location->end());
+       setup_snap_delta (MusicFrame (is_start ? location->start() : location->end(), 0));
 
        Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
 
@@ -4418,7 +4435,7 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
        _fixed_grab_x = _point->get_x() + _editor->sample_to_pixel_unrounded (_point->line().offset());
        _fixed_grab_y = _point->get_y();
 
-       setup_snap_delta (_editor->pixel_to_sample (_fixed_grab_x));
+       setup_snap_delta (MusicFrame (_editor->pixel_to_sample (_fixed_grab_x), 0));
 
        float const fraction = 1 - (_point->get_y() / _point->line().height());
        show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction));
@@ -4916,10 +4933,10 @@ TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
 
        _editor->get_selection().add (_primary);
 
-       framepos_t where = _primary->region()->position();
+       MusicFrame where (_primary->region()->position(), 0);
        setup_snap_delta (where);
 
-       show_verbose_cursor_duration (where, adjusted_current_frame (event), 0);
+       show_verbose_cursor_duration (where.frame, adjusted_current_frame (event), 0);
 }
 
 void
@@ -5627,6 +5644,7 @@ NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
        : Drag (e, i)
        , _cumulative_dx (0)
        , _cumulative_dy (0)
+       , _earliest (0.0)
        , _was_selected (false)
        , _copy (false)
 {
@@ -5638,6 +5656,13 @@ NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
        _note_height = _region->midi_stream_view()->note_height ();
 }
 
+void
+NoteDrag::setup_pointer_frame_offset ()
+{
+       _pointer_frame_offset = raw_grab_frame()
+               - _editor->session()->tempo_map().frame_at_quarter_note (_region->session_relative_qn (_primary->note()->time().to_double()));
+}
+
 void
 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
 {
@@ -5649,7 +5674,7 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
                _copy = false;
        }
 
-       setup_snap_delta (_region->source_beats_to_absolute_frames (_primary->note()->time ()));
+       setup_snap_delta (MusicFrame (_region->source_beats_to_absolute_frames (_primary->note()->time ()), 0));
 
        if (!(_was_selected = _primary->selected())) {
 
@@ -5673,55 +5698,38 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
        }
 }
 
-/** @return Current total drag x change in frames */
-frameoffset_t
-NoteDrag::total_dx (const guint state) const
+/** @return Current total drag x change in quarter notes */
+double
+NoteDrag::total_dx (GdkEvent * event) const
 {
        if (_x_constrained) {
                return 0;
        }
+
        TempoMap& map (_editor->session()->tempo_map());
 
        /* dx in frames */
        frameoffset_t const dx = _editor->pixel_to_sample (_drags->current_pointer_x() - grab_x());
 
        /* primary note time */
-       double const quarter_note_start = _region->region()->quarter_note() - _region->midi_region()->start_beats();
-       frameoffset_t const n = map.frame_at_quarter_note (quarter_note_start + _primary->note()->time().to_double());
-
-       /* new time of the primary note in session frames */
-       frameoffset_t st = n + dx + snap_delta (state);
-
-       framepos_t const rp = _region->region()->position ();
+       frameoffset_t const n = map.frame_at_quarter_note (_region->session_relative_qn (_primary->note()->time().to_double()));
 
-       /* prevent the note being dragged earlier than the region's position */
-       st = max (st, rp);
+       /* primary note time in quarter notes */
+       double const n_qn = _region->session_relative_qn (_primary->note()->time().to_double());
 
-       /* possibly snap and return corresponding delta */
+       /* new time of the primary note in session frames */
+       frameoffset_t st = n + dx + snap_delta (event->button.state);
 
-       bool snap = true;
+       /* possibly snap and return corresponding delta in quarter notes */
+       MusicFrame snap (st, 0);
+       _editor->snap_to_with_modifier (snap, event);
+       double ret = map.exact_qn_at_frame (snap.frame, snap.division) - n_qn - snap_delta_music (event->button.state);
 
-       if (ArdourKeyboard::indicates_snap (state)) {
-               if (_editor->snap_mode () != SnapOff) {
-                       snap = false;
-               }
-       } else {
-               if (_editor->snap_mode () == SnapOff) {
-                       snap = false;
-                       /* inverted logic here - we;re in snapoff but we've pressed the snap delta modifier */
-                       if (ArdourKeyboard::indicates_snap_delta (state)) {
-                               snap = true;
-                       }
-               }
+       /* prevent the earliest note being dragged earlier than the region's start position */
+       if (_earliest + ret < _region->midi_region()->start_beats()) {
+               ret -= (_earliest + ret) - _region->midi_region()->start_beats();
        }
 
-       frameoffset_t ret;
-       if (snap) {
-               bool const ensure_snap = _editor->snap_mode () != SnapMagnetic;
-               ret =  _region->snap_frame_to_frame (st - rp, ensure_snap) + rp - n - snap_delta (state);
-       } else {
-               ret = st - n - snap_delta (state);
-       }
        return ret;
 }
 
@@ -5747,30 +5755,33 @@ NoteDrag::total_dy () const
 void
 NoteDrag::motion (GdkEvent * event, bool first_move)
 {
-       if (_copy && first_move) {
-               /* make copies of all the selected notes */
-               _primary = _region->copy_selection ();
+       if (first_move) {
+               _earliest = _region->earliest_in_selection().to_double();
+               if (_copy) {
+                       /* make copies of all the selected notes */
+                       _primary = _region->copy_selection (_primary);
+               }
        }
 
        /* Total change in x and y since the start of the drag */
-       frameoffset_t const dx = total_dx (event->button.state);
+       double const dx_qn = total_dx (event);
        int8_t const dy = total_dy ();
 
        /* Now work out what we have to do to the note canvas items to set this new drag delta */
-       double const tdx = _x_constrained ? 0 : _editor->sample_to_pixel (dx) - _cumulative_dx;
+       double const tdx = _x_constrained ? 0 : dx_qn - _cumulative_dx;
        double const tdy = _y_constrained ? 0 : -dy * _note_height - _cumulative_dy;
 
        if (tdx || tdy) {
-               _cumulative_dx += tdx;
+               _cumulative_dx = dx_qn;
                _cumulative_dy += tdy;
 
                int8_t note_delta = total_dy();
 
                if (tdx || tdy) {
                        if (_copy) {
-                               _region->move_copies (tdx, tdy, note_delta);
+                               _region->move_copies (dx_qn, tdy, note_delta);
                        } else {
-                               _region->move_selection (tdx, tdy, note_delta);
+                               _region->move_selection (dx_qn, tdy, note_delta);
                        }
 
                        /* the new note value may be the same as the old one, but we
@@ -5831,7 +5842,7 @@ NoteDrag::finished (GdkEvent* ev, bool moved)
                        }
                }
        } else {
-               _region->note_dropped (_primary, total_dx (ev->button.state), total_dy(), _copy);
+               _region->note_dropped (_primary, total_dx (ev), total_dy(), _copy);
        }
 }
 
index 95eaf1409b0faee9e4ef529c70cb89b02d27f041..711b5095c73a6e2163aed30854e7d98d39cab03d 100644 (file)
@@ -242,12 +242,13 @@ protected:
        }
 
        ARDOUR::frameoffset_t snap_delta (guint const) const;
+       double  snap_delta_music (guint const) const;
 
        double current_pointer_x () const;
        double current_pointer_y () const;
 
        /* sets snap delta from unsnapped pos */
-       void setup_snap_delta (framepos_t pos);
+       void setup_snap_delta (ARDOUR::MusicFrame pos);
 
        boost::shared_ptr<ARDOUR::Region> add_midi_region (MidiTimeAxisView*, bool commit);
 
@@ -282,6 +283,7 @@ private:
         *  framepos. used for relative snap.
         */
        framepos_t _snap_delta;
+       double     _snap_delta_music;
        CursorContext::Handle _cursor_ctx; ///< cursor change context
        bool _constraint_pressed; ///< if the keyboard indicated constraint modifier was pressed on start_grab()
 };
@@ -557,15 +559,17 @@ class NoteDrag : public Drag
        void finished (GdkEvent *, bool);
        void aborted (bool);
 
+       void setup_pointer_frame_offset ();
   private:
 
-       ARDOUR::frameoffset_t total_dx (const guint) const;
+       double total_dx (GdkEvent * event) const; // total movement in quarter notes
        int8_t total_dy () const;
 
        MidiRegionView* _region;
        NoteBase* _primary;
        double _cumulative_dx;
        double _cumulative_dy;
+       double _earliest; // earliest quarter note in note selection
        bool   _was_selected;
        double _note_height;
        bool   _copy;
index da7f1a54b5644663bf1841208ea6439129658525..f9c088448ede5fc11560edcb477aac0fa2171555 100644 (file)
@@ -2549,11 +2549,9 @@ MidiRegionView::add_to_selection (NoteBase* ev)
        }
 }
 
-void
-MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
+Evoral::Beats
+MidiRegionView::earliest_in_selection ()
 {
-       typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
-       PossibleChord to_play;
        Evoral::Beats earliest = Evoral::MaxBeats;
 
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
@@ -2562,10 +2560,27 @@ MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
                }
        }
 
+       return earliest;
+}
+
+void
+MidiRegionView::move_selection(double dx_qn, double dy, double cumulative_dy)
+{
+       typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
+       Editor* editor = dynamic_cast<Editor*> (&trackview.editor());
+       TempoMap& tmap (editor->session()->tempo_map());
+       PossibleChord to_play;
+       Evoral::Beats earliest = earliest_in_selection();
+
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
-               if ((*i)->note()->time() == earliest) {
-                       to_play.push_back ((*i)->note());
+               NoteBase* n = *i;
+               if (n->note()->time() == earliest) {
+                       to_play.push_back (n->note());
                }
+               double const note_time_qn = session_relative_qn (n->note()->time().to_double());
+               double const dx = editor->sample_to_pixel_unrounded (tmap.frame_at_quarter_note (note_time_qn + dx_qn))
+                       - n->item()->item_to_canvas (ArdourCanvas::Duple (n->x0(), 0)).x;
+
                (*i)->move_event(dx, dy);
        }
 
@@ -2593,15 +2608,17 @@ MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
 }
 
 NoteBase*
-MidiRegionView::copy_selection ()
+MidiRegionView::copy_selection (NoteBase* primary)
 {
-       NoteBase* note;
        _copy_drag_events.clear ();
 
        if (_selection.empty()) {
                return 0;
        }
 
+       NoteBase* note;
+       NoteBase* ret = 0;
+
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
                boost::shared_ptr<NoteType> g (new NoteType (*((*i)->note())));
                if (midi_view()->note_mode() == Sustained) {
@@ -2614,29 +2631,34 @@ MidiRegionView::copy_selection ()
                        note = h;
                }
 
+               if ((*i) == primary) {
+                       ret = note;
+               }
+
                _copy_drag_events.push_back (note);
        }
 
-       return _copy_drag_events.front ();
+       return ret;
 }
 
 void
-MidiRegionView::move_copies (double dx, double dy, double cumulative_dy)
+MidiRegionView::move_copies (double dx_qn, double dy, double cumulative_dy)
 {
        typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
+       Editor* editor = dynamic_cast<Editor*> (&trackview.editor());
+       TempoMap& tmap (editor->session()->tempo_map());
        PossibleChord to_play;
-       Evoral::Beats earliest = Evoral::MaxBeats;
+       Evoral::Beats earliest = earliest_in_selection();
 
        for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end(); ++i) {
-               if ((*i)->note()->time() < earliest) {
-                       earliest = (*i)->note()->time();
+               NoteBase* n = *i;
+               if (n->note()->time() == earliest) {
+                       to_play.push_back (n->note());
                }
-       }
+               double const note_time_qn = session_relative_qn (n->note()->time().to_double());
+               double const dx = editor->sample_to_pixel_unrounded (tmap.frame_at_quarter_note (note_time_qn + dx_qn))
+                       - n->item()->item_to_canvas (ArdourCanvas::Duple (n->x0(), 0)).x;
 
-       for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end(); ++i) {
-               if ((*i)->note()->time() == earliest) {
-                       to_play.push_back ((*i)->note());
-               }
                (*i)->move_event(dx, dy);
        }
 
@@ -2664,7 +2686,7 @@ MidiRegionView::move_copies (double dx, double dy, double cumulative_dy)
 }
 
 void
-MidiRegionView::note_dropped(NoteBase *, frameoffset_t dt, int8_t dnote, bool copy)
+MidiRegionView::note_dropped(NoteBase *, double d_qn, int8_t dnote, bool copy)
 {
        uint8_t lowest_note_in_selection  = 127;
        uint8_t highest_note_in_selection = 0;
@@ -2693,15 +2715,13 @@ MidiRegionView::note_dropped(NoteBase *, frameoffset_t dt, int8_t dnote, bool co
                if (highest_note_in_selection + dnote > 127) {
                        highest_note_difference = highest_note_in_selection - 127;
                }
-               TempoMap& map (trackview.session()->tempo_map());
 
                start_note_diff_command (_("move notes"));
 
                for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) {
 
-                       double const start_qn = _region->quarter_note() - midi_region()->start_beats();
-                       framepos_t new_frames = map.frame_at_quarter_note (start_qn + (*i)->note()->time().to_double()) + dt;
-                       Evoral::Beats new_time = Evoral::Beats (map.quarter_note_at_frame (new_frames) - start_qn);
+                       Evoral::Beats new_time = Evoral::Beats (max ((*i)->note()->time().to_double() + d_qn, midi_region()->start_beats()));
+
                        if (new_time < 0) {
                                continue;
                        }
@@ -2734,16 +2754,12 @@ MidiRegionView::note_dropped(NoteBase *, frameoffset_t dt, int8_t dnote, bool co
                        highest_note_difference = highest_note_in_selection - 127;
                }
 
-               TempoMap& map (trackview.session()->tempo_map());
                start_note_diff_command (_("copy notes"));
 
                for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end() ; ++i) {
 
                        /* update time */
-
-                       double const start_qn = _region->quarter_note() - midi_region()->start_beats();
-                       framepos_t new_frames = map.frame_at_quarter_note (start_qn + (*i)->note()->time().to_double()) + dt;
-                       Evoral::Beats new_time = Evoral::Beats (map.quarter_note_at_frame (new_frames) - start_qn);
+                       Evoral::Beats new_time = Evoral::Beats (max ((*i)->note()->time().to_double() + d_qn, midi_region()->start_beats()));
 
                        if (new_time < 0) {
                                continue;
@@ -2790,7 +2806,7 @@ framepos_t
 MidiRegionView::snap_pixel_to_sample(double x, bool ensure_snap)
 {
        PublicEditor& editor (trackview.editor());
-       return snap_frame_to_frame (editor.pixel_to_sample (x), ensure_snap);
+       return snap_frame_to_frame (editor.pixel_to_sample (x), ensure_snap).frame;
 }
 
 /** @param x Pixel relative to the region position.
@@ -4369,3 +4385,9 @@ MidiRegionView::note_to_y(uint8_t note) const
 {
        return contents_height() - (note + 1 - _current_range_min) * note_height() + 1;
 }
+
+double
+MidiRegionView::session_relative_qn (double qn) const
+{
+       return qn + (region()->quarter_note() - midi_region()->start_beats());
+}
index 929b3bd7f9193274164b6b5096ff37d393dd1f95..0d5b82255d75dae87a9fae6d3e4b9926360492cc 100644 (file)
@@ -200,10 +200,11 @@ public:
        void   select_range(framepos_t start, framepos_t end);
        void   invert_selection ();
 
+       Evoral::Beats earliest_in_selection ();
        void move_selection(double dx, double dy, double cumulative_dy);
-       void note_dropped (NoteBase* ev, ARDOUR::frameoffset_t, int8_t d_note, bool copy);
-       NoteBase* copy_selection ();
-       void move_copies(double dx, double dy, double cumulative_dy);
+       void note_dropped (NoteBase* ev, double d_qn, int8_t d_note, bool copy);
+       NoteBase* copy_selection (NoteBase* primary);
+       void move_copies(double dx_qn, double dy, double cumulative_dy);
 
        void select_notes (std::list<Evoral::event_id_t>);
        void select_matching_notes (uint8_t notenum, uint16_t channel_mask, bool add, bool extend);
@@ -297,6 +298,8 @@ public:
                return _region_relative_time_converter_double;
        }
 
+       double session_relative_qn (double qn) const;
+
        void goto_previous_note (bool add_to_selection);
        void goto_next_note (bool add_to_selection);
        void change_note_lengths (bool, bool, Evoral::Beats beats, bool start, bool end);
index 9f6ff645ce855894872ebd5d1f81b9f15e4f340b..c689a15e7d3c05b7539b5c21084b59f8a073d212 100644 (file)
@@ -943,7 +943,7 @@ RegionView::move_contents (frameoffset_t distance)
  *  Used when inverting snap mode logic with key modifiers, or snap distance calculation.
  *  @return Snapped frame offset from this region's position.
  */
-frameoffset_t
+MusicFrame
 RegionView::snap_frame_to_frame (frameoffset_t x, bool ensure_snap) const
 {
        PublicEditor& editor = trackview.editor();
@@ -960,6 +960,6 @@ RegionView::snap_frame_to_frame (frameoffset_t x, bool ensure_snap) const
                editor.snap_to (frame, RoundUpAlways, false, ensure_snap);
        }
 
-       /* back to region relative */
-       return frame.frame - _region->position();
+       /* back to region relative, keeping the relevant divisor */
+       return MusicFrame (frame.frame - _region->position(), frame.division);
 }
index 7fad731dc26cd82e6814af7875c162ade9212f9b..10eb7b5dc6977c366c74a64d632e78397933bb20 100644 (file)
@@ -121,7 +121,7 @@ class RegionView : public TimeAxisViewItem
                }
        };
 
-       ARDOUR::frameoffset_t snap_frame_to_frame (ARDOUR::frameoffset_t, bool ensure_snap = false) const;
+       ARDOUR::MusicFrame snap_frame_to_frame (ARDOUR::frameoffset_t, bool ensure_snap = false) const;
 
   protected: