diff options
-rw-r--r-- | gtk2_ardour/automation_time_axis.cc | 9 | ||||
-rw-r--r-- | gtk2_ardour/automation_time_axis.h | 4 | ||||
-rw-r--r-- | gtk2_ardour/editor.cc | 27 | ||||
-rw-r--r-- | gtk2_ardour/editor.h | 6 | ||||
-rw-r--r-- | gtk2_ardour/editor_ops.cc | 13 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.cc | 24 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/public_editor.h | 1 | ||||
-rw-r--r-- | gtk2_ardour/route_time_axis.cc | 7 | ||||
-rw-r--r-- | gtk2_ardour/route_time_axis.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/time_axis_view.h | 2 |
11 files changed, 80 insertions, 17 deletions
diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index 2c342fb8c9..e0e9b9428f 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -637,7 +637,7 @@ AutomationTimeAxisView::add_automation_event (GdkEvent* event, framepos_t when, * @param nth Index of the AutomationList within the selection to paste from. */ bool -AutomationTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth) +AutomationTimeAxisView::paste (framepos_t pos, unsigned paste_count, float times, Selection& selection, size_t nth) { boost::shared_ptr<AutomationLine> line; @@ -651,11 +651,11 @@ AutomationTimeAxisView::paste (framepos_t pos, float times, Selection& selection return false; } - return paste_one (*line, pos, times, selection, nth); + return paste_one (*line, pos, paste_count, times, selection, nth); } bool -AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float times, Selection& selection, size_t nth) +AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, unsigned paste_count, float times, Selection& selection, size_t nth) { AutomationSelection::iterator p; boost::shared_ptr<AutomationList> alist(line.the_list()); @@ -671,6 +671,9 @@ AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float t return false; } + /* add multi-paste offset if applicable */ + pos += _editor.get_paste_offset(pos, paste_count, (*p)->length()); + double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ()); XMLNode &before = alist->get_state(); diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h index a468c12459..39a211a456 100644 --- a/gtk2_ardour/automation_time_axis.h +++ b/gtk2_ardour/automation_time_axis.h @@ -93,7 +93,7 @@ class AutomationTimeAxisView : public TimeAxisView { /* editing operations */ void cut_copy_clear (Selection&, Editing::CutCopyOp); - bool paste (ARDOUR::framepos_t, float times, Selection&, size_t nth); + bool paste (ARDOUR::framepos_t, unsigned paste_count, float times, Selection&, size_t nth); int set_state (const XMLNode&, int version); @@ -171,7 +171,7 @@ class AutomationTimeAxisView : public TimeAxisView { void build_display_menu (); void cut_copy_clear_one (AutomationLine&, Selection&, Editing::CutCopyOp); - bool paste_one (AutomationLine&, ARDOUR::framepos_t, float times, Selection&, size_t nth); + bool paste_one (AutomationLine&, ARDOUR::framepos_t, unsigned, float times, Selection&, size_t nth); void route_going_away (); void set_automation_state (ARDOUR::AutoState); diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index d5c9aa6fea..a0dcf72db2 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -312,6 +312,8 @@ Editor::Editor () clicked_control_point = 0; last_update_frame = 0; pre_press_cursor = 0; + last_paste_pos = 0; + paste_count = 0; _drags = new DragManager (this); lock_dialog = 0; ruler_dialog = 0; @@ -3856,6 +3858,31 @@ Editor::playlist_selector () const return *_playlist_selector; } +framecnt_t +Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration) +{ + if (paste_count == 0) { + /* don't bother calculating an offset that will be zero anyway */ + return 0; + } + + /* calculate basic unsnapped multi-paste offset */ + framecnt_t offset = paste_count * duration; + + bool success = true; + double snap_beats = get_grid_type_as_beats(success, pos); + if (success) { + /* we're snapped to something musical, round duration up */ + BeatsFramesConverter conv(_session->tempo_map(), pos); + const Evoral::MusicalTime dur_beats = conv.from(duration); + const framecnt_t snap_dur_beats = ceil(dur_beats / snap_beats) * snap_beats; + + offset = paste_count * conv.to(snap_dur_beats); + } + + return offset; +} + Evoral::MusicalTime Editor::get_grid_type_as_beats (bool& success, framepos_t position) { diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 4dc5f80d6f..2831fc894f 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -313,6 +313,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD /* nudge is initiated by transport controls owned by ARDOUR_UI */ framecnt_t get_nudge_distance (framepos_t pos, framecnt_t& next); + framecnt_t get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration); Evoral::MusicalTime get_grid_type_as_beats (bool& success, framepos_t position); void nudge_forward (bool next, bool force_playhead); @@ -1109,6 +1110,11 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD Gtkmm2ext::ActionMap editor_action_map; Gtkmm2ext::Bindings key_bindings; + /* CUT/COPY/PASTE */ + + framepos_t last_paste_pos; + unsigned paste_count; + void cut_copy (Editing::CutCopyOp); bool can_cut_copy () const; void cut_copy_points (Editing::CutCopyOp); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 98235e5861..f6ec077301 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -4364,6 +4364,15 @@ Editor::paste_internal (framepos_t position, float times) DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position)); } + if (position == last_paste_pos) { + /* repeated paste in the same position */ + ++paste_count; + } else { + /* paste in new location, reset repeated paste state */ + paste_count = 0; + last_paste_pos = position; + } + TrackViewList ts; TrackViewList::iterator i; size_t nth; @@ -4401,7 +4410,7 @@ Editor::paste_internal (framepos_t position, float times) cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) { MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r); if (mrv) { - mrv->paste (position, times, **cb); + mrv->paste (position, paste_count, times, **cb); ++cb; } } @@ -4413,7 +4422,7 @@ Editor::paste_internal (framepos_t position, float times) begin_reversible_command (Operations::paste); for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) { - (*i)->paste (position, times, *cut_buffer, nth); + (*i)->paste (position, paste_count, times, *cut_buffer, nth); } commit_reversible_command (); diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index b560367c5c..fc8948e734 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -3321,25 +3321,37 @@ MidiRegionView::selection_as_cut_buffer () const /** This method handles undo */ void -MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb) +MidiRegionView::paste (framepos_t pos, unsigned paste_count, float times, const MidiCutBuffer& mcb) { if (mcb.empty()) { return; } + PublicEditor& editor = trackview.editor (); + trackview.session()->begin_reversible_command (_("paste")); start_note_diff_command (_("paste")); - const Evoral::MusicalTime pos_beats = absolute_frames_to_source_beats (pos); - const Evoral::MusicalTime first_time = (*mcb.notes().begin())->time(); - const Evoral::MusicalTime last_time = (*mcb.notes().rbegin())->end_time(); - Evoral::MusicalTime end_point = 0; + /* get snap duration, default to 1 beat if not snapped to anything musical */ + bool success = true; + double snap_beats = editor.get_grid_type_as_beats(success, pos); + if (!success) { + snap_beats = 1.0; + } + + const Evoral::MusicalTime first_time = (*mcb.notes().begin())->time(); + const Evoral::MusicalTime last_time = (*mcb.notes().rbegin())->end_time(); + const Evoral::MusicalTime duration = last_time - first_time; + const Evoral::MusicalTime snap_duration = ceil(duration / snap_beats) * snap_beats; + const Evoral::MusicalTime paste_offset = paste_count * snap_duration; + const Evoral::MusicalTime pos_beats = absolute_frames_to_source_beats(pos) + paste_offset; + Evoral::MusicalTime end_point = 0; DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste data spans from %1 to %2 (%3) ; paste pos beats = %4 (based on %5 - %6)\n", first_time, last_time, - last_time - first_time, pos, _region->position(), + duration, pos, _region->position(), pos_beats)); clear_selection (); diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index 65ca7df7ab..cda4d5802c 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -112,7 +112,7 @@ public: void resolve_note(uint8_t note_num, double end_time); void cut_copy_clear (Editing::CutCopyOp); - void paste (framepos_t pos, float times, const MidiCutBuffer&); + void paste (framepos_t pos, unsigned paste_count, float times, const MidiCutBuffer&); void add_canvas_patch_change (ARDOUR::MidiModel::PatchChangePtr patch, const std::string& displaytext, bool); diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index bd861ab085..4bf03bc72f 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -299,6 +299,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi virtual void foreach_time_axis_view (sigc::slot<void,TimeAxisView&>) = 0; virtual void add_to_idle_resize (TimeAxisView*, int32_t) = 0; virtual framecnt_t get_nudge_distance (framepos_t pos, framecnt_t& next) = 0; + virtual framecnt_t get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration) = 0; virtual Evoral::MusicalTime get_grid_type_as_beats (bool& success, framepos_t position) = 0; virtual void edit_notes (TimeAxisViewItem&) = 0; diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index c4d49e40b9..b447288566 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -1534,7 +1534,7 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) } bool -RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth) +RouteTimeAxisView::paste (framepos_t pos, unsigned paste_count, float times, Selection& selection, size_t nth) { if (!is_track()) { return false; @@ -1556,6 +1556,11 @@ RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, siz DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos)); } + /* add multi-paste offset if applicable */ + std::pair<framepos_t, framepos_t> extent = (*p)->get_extent(); + const framecnt_t duration = extent.second - extent.first; + pos += _editor.get_paste_offset(pos, paste_count, duration); + pl->clear_changes (); if (Config->get_edit_mode() == Ripple) { std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace(); diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h index 8e0941d591..45b8afd82d 100644 --- a/gtk2_ardour/route_time_axis.h +++ b/gtk2_ardour/route_time_axis.h @@ -99,7 +99,7 @@ public: /* Editing operations */ void cut_copy_clear (Selection&, Editing::CutCopyOp); - bool paste (ARDOUR::framepos_t, float times, Selection&, size_t nth); + bool paste (ARDOUR::framepos_t, unsigned paste_count, float times, Selection&, size_t nth); RegionView* combine_regions (); void uncombine_regions (); void uncombine_region (RegionView*); diff --git a/gtk2_ardour/time_axis_view.h b/gtk2_ardour/time_axis_view.h index cc7f7a0fe0..3dc440b54c 100644 --- a/gtk2_ardour/time_axis_view.h +++ b/gtk2_ardour/time_axis_view.h @@ -165,7 +165,7 @@ class TimeAxisView : public virtual AxisView /* editing operations */ virtual void cut_copy_clear (Selection&, Editing::CutCopyOp) {} - virtual bool paste (ARDOUR::framepos_t, float /*times*/, Selection&, size_t /*nth*/) { return false; } + virtual bool paste (ARDOUR::framepos_t, unsigned /*paste_count*/, float /*times*/, Selection&, size_t /*nth*/) { return false; } virtual void set_selected_regionviews (RegionSelection&) {} virtual void set_selected_points (PointSelection&) {} |