more MIDI paste improvements, plus move region-mute binding to PRIMARY-m and use...
[ardour.git] / gtk2_ardour / midi_region_view.cc
index 9b9be486a3d57fbb18761a0baa7c283451ed3687..215f7c34da5fd6d769eea5d0b7b509b0eeb67053 100644 (file)
@@ -47,6 +47,7 @@
 #include "ghostregion.h"
 #include "gui_thread.h"
 #include "keyboard.h"
+#include "midi_cut_buffer.h"
 #include "midi_region_view.h"
 #include "midi_streamview.h"
 #include "midi_time_axis.h"
@@ -660,7 +661,6 @@ MidiRegionView::~MidiRegionView ()
        }
 
        _selection.clear();
-       _cut_buffer.clear ();
        clear_events();
        delete _note_group;
        delete _delta_command;
@@ -1669,17 +1669,24 @@ MidiRegionView::cut_copy_clear (Editing::CutCopyOp op)
                return;
        }
 
-       _cut_buffer.clear ();
+       PublicEditor& editor (trackview.editor());
 
+       switch (op) {
+       case Cut:
+       case Copy:
+               editor.get_cut_buffer().add (selection_as_cut_buffer());
+               break;
+       default:
+               break;
+       }
+               
        start_delta_command();
 
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
                switch (op) {
                case Copy:
-                       _cut_buffer.push_back (NoteType (*((*i)->note().get())));
                        break;
                case Cut:
-                       _cut_buffer.push_back (NoteType (*(*i)->note().get()));
                        command_remove_note (*i);
                        break;
                case Clear:
@@ -1690,3 +1697,59 @@ MidiRegionView::cut_copy_clear (Editing::CutCopyOp op)
        apply_command();
 }
 
+MidiCutBuffer*
+MidiRegionView::selection_as_cut_buffer () const
+{
+       Evoral::Sequence<MidiModel::TimeType>::Notes notes;
+
+       for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+               notes.push_back (boost::shared_ptr<NoteType> (new NoteType (*((*i)->note().get()))));
+       }
+
+       /* sort them into time order */
+
+       sort (notes.begin(), notes.end(), Evoral::Sequence<MidiModel::TimeType>::note_time_comparator);
+
+       MidiCutBuffer* cb = new MidiCutBuffer (trackview.session());
+       cb->set (notes);
+       
+       return cb;
+}
+
+void
+MidiRegionView::paste (nframes64_t pos, float times, const MidiCutBuffer& mcb)
+{
+       if (mcb.empty()) {
+               return;
+       }
+
+       start_delta_command (_("paste"));
+
+       MidiModel::TimeType beat_delta;
+       MidiModel::TimeType paste_pos_beats;
+       MidiModel::TimeType duration;
+
+       duration = mcb.notes().back()->end_time() - mcb.notes().front()->time();
+       paste_pos_beats = frames_to_beats (pos);
+       beat_delta = mcb.notes().front()->time() - paste_pos_beats;
+       paste_pos_beats = 0;
+
+       _selection.clear ();
+
+       for (int n = 0; n < (int) times; ++n) {
+
+               for (Evoral::Sequence<MidiModel::TimeType>::Notes::const_iterator i = mcb.notes().begin(); i != mcb.notes().end(); ++i) {
+                       
+                       boost::shared_ptr<NoteType> copied_note (new NoteType (*((*i).get())));
+                       copied_note->set_time (paste_pos_beats + copied_note->time() - beat_delta);
+
+                       /* make all newly added notes selected */
+
+                       command_add_note (copied_note, true);
+               }
+
+               paste_pos_beats += duration;
+       }
+       
+       apply_command ();
+}