diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 60aa58dbb0..a45e243da5 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -2653,6 +2653,16 @@ Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark) snap_to_internal (start, direction, for_mark); } +void +Editor::snap_to_no_magnets (framepos_t& start, RoundMode direction, bool for_mark) +{ + if (!_session || _snap_mode == SnapOff) { + return; + } + + snap_to_internal (start, direction, for_mark, true); +} + void Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/) { @@ -2720,7 +2730,7 @@ Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool } void -Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark) +Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool no_magnets) { const framepos_t one_second = _session->frame_rate(); const framepos_t one_minute = _session->frame_rate() * 60; @@ -2890,6 +2900,10 @@ Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark) case SnapMagnetic: + if (no_magnets) { + return; + } + if (presnap > start) { if (presnap > (start + pixel_to_sample(snap_threshold))) { start = presnap; diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 0e1661aca9..988d20efd2 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -440,6 +440,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD ARDOUR::RoundMode direction = ARDOUR::RoundNearest, bool for_mark = false); + void snap_to_no_magnets (framepos_t& first, + ARDOUR::RoundMode direction = ARDOUR::RoundNearest, + bool for_mark = false); + void snap_to_with_modifier (framepos_t& first, GdkEvent const * ev, ARDOUR::RoundMode direction = ARDOUR::RoundNearest, @@ -2140,7 +2144,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void snap_to_internal (framepos_t& first, ARDOUR::RoundMode direction = ARDOUR::RoundNearest, - bool for_mark = false); + bool for_mark = false, + bool no_magnets = false); void timecode_snap_to_internal (framepos_t& first, ARDOUR::RoundMode direction = ARDOUR::RoundNearest, diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index f7f4cd2873..966ab7002f 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -366,7 +366,7 @@ Drag::setup_snap_delta (framepos_t pos) { if (_editor->snap_delta () == SnapRelative) { framepos_t temp = pos; - _editor->snap_to (temp); + _editor->snap_to_no_magnets (temp); _snap_delta = temp - pos; } } @@ -2358,7 +2358,7 @@ NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/) if (_editor->snap_delta () == SnapRelative) { double temp; - temp = region->snap_to_pixel(cnote->x0 ()); + temp = region->snap_to_pixel_no_magnets (cnote->x0 ()); _snap_delta = temp - cnote->x0 (); } diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index 5fb183671f..a58d95dfa1 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -217,7 +217,7 @@ protected: return _last_pointer_frame; } - framecnt_t snap_delta () const { + ARDOUR::frameoffset_t snap_delta () const { return _snap_delta; } @@ -259,7 +259,7 @@ private: /* difference between some key position's snapped and unsnapped * framepos. used for relative snap. */ - framecnt_t _snap_delta; + ARDOUR::frameoffset_t _snap_delta; CursorContext::Handle _cursor_ctx; ///< cursor change context }; diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 97a71003eb..3ecadc4775 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -2633,6 +2633,16 @@ MidiRegionView::snap_pixel_to_sample(double x) return snap_frame_to_frame (editor.pixel_to_sample (x)); } +/** @param x Pixel relative to the region position explicitly (no magnetic snap) + * @return Snapped frame relative to the region position. + */ +framepos_t +MidiRegionView::snap_pixel_to_sample_no_magnets (double x) +{ + PublicEditor& editor (trackview.editor()); + return snap_frame_to_frame_no_magnets (editor.pixel_to_sample (x)); +} + /** @param x Pixel relative to the region position. * @return Snapped pixel relative to the region position. */ @@ -2642,6 +2652,15 @@ MidiRegionView::snap_to_pixel(double x) return (double) trackview.editor().sample_to_pixel(snap_pixel_to_sample(x)); } +/** @param x Pixel relative to the region position. + * @return Explicitly snapped pixel relative to the region position (no magnetic snap). + */ +double +MidiRegionView::snap_to_pixel_no_magnets (double x) +{ + return (double) trackview.editor().sample_to_pixel(snap_pixel_to_sample_no_magnets(x)); +} + double MidiRegionView::get_position_pixels() { @@ -2691,7 +2710,7 @@ MidiRegionView::region_frames_to_region_beats(framepos_t frames) const } double -MidiRegionView::region_frames_to_region_beats_double(framepos_t frames) const +MidiRegionView::region_frames_to_region_beats_double (framepos_t frames) const { return _region_relative_time_converter_double.from(frames); } @@ -2794,9 +2813,9 @@ MidiRegionView::update_resizing (NoteBase* primary, bool at_front, double delta_ int sign = 1; /* negative beat offsets aren't allowed */ if (delta_samps > 0) { - delta_beats = _region_relative_time_converter_double.from(delta_samps); + delta_beats = region_frames_to_region_beats_double (delta_samps); } else if (delta_samps < 0) { - delta_beats = _region_relative_time_converter_double.from( - delta_samps); + delta_beats = region_frames_to_region_beats_double ( - delta_samps); sign = -1; } @@ -2869,9 +2888,9 @@ MidiRegionView::commit_resizing (NoteBase* primary, bool at_front, double delta_ double delta_beats; int sign = 1; if (delta_samps > 0) { - delta_beats = _region_relative_time_converter_double.from(delta_samps); + delta_beats = region_frames_to_region_beats_double (delta_samps); } else if (delta_samps < 0) { - delta_beats = _region_relative_time_converter_double.from( - delta_samps); + delta_beats = region_frames_to_region_beats_double ( - delta_samps); sign = -1; } diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index cfdb50a99c..7329c6facc 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -254,12 +254,24 @@ public: */ double snap_to_pixel(double x); + /** Snap a region relative pixel coordinate to pixel units explicitly (no magnetic snap). + * @param x a pixel coordinate relative to region start + * @return the explicitly snapped pixel coordinate relative to region start + */ + double snap_to_pixel_no_magnets (double x); + /** Snap a region relative pixel coordinate to frame units. * @param x a pixel coordinate relative to region start * @return the snapped framepos_t coordinate relative to region start */ framepos_t snap_pixel_to_sample(double x); + /** Explicitly snap a region relative pixel coordinate to frame units (no magnetic snap). + * @param x a pixel coordinate relative to region start + * @return the explicitly snapped framepos_t coordinate relative to region start + */ + framepos_t snap_pixel_to_sample_no_magnets (double x); + /** Convert a timestamp in beats into frames (both relative to region position) */ framepos_t region_beats_to_region_frames(Evoral::Beats beats) const; /** Convert a timestamp in beats into absolute frames */ diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index a8ecbb5f40..dc845e6f89 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -148,6 +148,10 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi virtual void snap_to (framepos_t& first, ARDOUR::RoundMode direction = ARDOUR::RoundNearest, bool for_mark = false) = 0; + /** Snap a value according to the current snap setting. */ + virtual void snap_to_no_magnets (framepos_t& first, + ARDOUR::RoundMode direction = ARDOUR::RoundNearest, + bool for_mark = false) = 0; /** Undo some transactions. * @param n Number of transactions to undo. diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc index be96cd4058..cd83154a9f 100644 --- a/gtk2_ardour/region_view.cc +++ b/gtk2_ardour/region_view.cc @@ -962,3 +962,29 @@ RegionView::snap_frame_to_frame (frameoffset_t x) const /* back to region relative */ return frame - _region->position(); } + +/** Snap a frame offset within our region using the current snap settings. + * @param x Frame offset from this region's position. + * @return Snapped frame offset from this region's position. + */ +frameoffset_t +RegionView::snap_frame_to_frame_no_magnets (frameoffset_t x) const +{ + PublicEditor& editor = trackview.editor(); + + /* x is region relative, convert it to global absolute frames */ + framepos_t const session_frame = x + _region->position(); + + /* try a snap in either direction */ + framepos_t frame = session_frame; + editor.snap_to_no_magnets (frame, RoundNearest); + + /* if we went off the beginning of the region, snap forwards */ + if (frame < _region->position ()) { + frame = session_frame; + editor.snap_to_no_magnets (frame, RoundUpAlways); + } + + /* back to region relative */ + return frame - _region->position(); +} diff --git a/gtk2_ardour/region_view.h b/gtk2_ardour/region_view.h index 92006c556c..77abb5e2a9 100644 --- a/gtk2_ardour/region_view.h +++ b/gtk2_ardour/region_view.h @@ -122,6 +122,7 @@ class RegionView : public TimeAxisViewItem }; ARDOUR::frameoffset_t snap_frame_to_frame (ARDOUR::frameoffset_t) const; + ARDOUR::frameoffset_t snap_frame_to_frame_no_magnets (ARDOUR::frameoffset_t) const; protected: