summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/automation_time_axis.cc9
-rw-r--r--gtk2_ardour/automation_time_axis.h4
-rw-r--r--gtk2_ardour/editor.cc27
-rw-r--r--gtk2_ardour/editor.h6
-rw-r--r--gtk2_ardour/editor_ops.cc13
-rw-r--r--gtk2_ardour/midi_region_view.cc24
-rw-r--r--gtk2_ardour/midi_region_view.h2
-rw-r--r--gtk2_ardour/public_editor.h1
-rw-r--r--gtk2_ardour/route_time_axis.cc7
-rw-r--r--gtk2_ardour/route_time_axis.h2
-rw-r--r--gtk2_ardour/time_axis_view.h2
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&) {}