diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2009-08-13 01:57:03 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2009-08-13 01:57:03 +0000 |
commit | 0178875021916feea05a830325c25e9a7db81d34 (patch) | |
tree | da01be83db51399e179d08814e3fb1e0a3bff183 /gtk2_ardour | |
parent | 677bb36f5c012ac6d429a1d1fce0a726616160d4 (diff) |
MIDI cut&paste round two (not done yet); a small region trim fix from lincoln s.
git-svn-id: svn://localhost/ardour2/branches/3.0@5517 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour')
-rw-r--r-- | gtk2_ardour/audio_region_view.cc | 6 | ||||
-rw-r--r-- | gtk2_ardour/editor_ops.cc | 47 | ||||
-rw-r--r-- | gtk2_ardour/midi_cut_buffer.cc | 44 | ||||
-rw-r--r-- | gtk2_ardour/midi_cut_buffer.h | 45 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.cc | 46 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.h | 32 | ||||
-rw-r--r-- | gtk2_ardour/midi_selection.h | 4 | ||||
-rw-r--r-- | gtk2_ardour/route_time_axis.cc | 3 | ||||
-rw-r--r-- | gtk2_ardour/selection.cc | 151 | ||||
-rw-r--r-- | gtk2_ardour/selection.h | 18 | ||||
-rw-r--r-- | gtk2_ardour/wscript | 1 |
11 files changed, 342 insertions, 55 deletions
diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index f5dd4da3d1..d4e846aec5 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -614,6 +614,9 @@ AudioRegionView::reset_fade_in_shape_width (nframes_t width) fade_in_shape->property_points() = *points; delete points; + + /* ensure trim handle stays on top */ + frame_handle_start->raise_to_top(); } void @@ -702,6 +705,9 @@ AudioRegionView::reset_fade_out_shape_width (nframes_t width) fade_out_shape->property_points() = *points; delete points; + + /* ensure trim handle stays on top */ + frame_handle_end->raise_to_top(); } void diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 0a7543b214..72a8d7bdf6 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -4011,9 +4011,9 @@ Editor::cut_copy_points (CutCopyOp op) void Editor::cut_copy_midi (CutCopyOp op) { - cerr << "CCM: there are " << selection->midi.size() << " MRV's to work on\n"; + cerr << "CCM: there are " << selection->midi_regions.size() << " MRV's to work on\n"; - for (MidiSelection::iterator i = selection->midi.begin(); i != selection->midi.end(); ++i) { + for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) { MidiRegionView* mrv = *i; mrv->cut_copy_clear (op); } @@ -4318,8 +4318,14 @@ Editor::paste_internal (nframes64_t position, float times) { bool commit = false; - if (cut_buffer->empty()) { - return; + if (internal_editing()) { + if (cut_buffer->midi_notes.empty()) { + return; + } + } else { + if (cut_buffer->empty()) { + return; + } } if (position == max_frames) { @@ -4341,13 +4347,38 @@ Editor::paste_internal (nframes64_t position, float times) ts.push_back (entered_track); } + + cerr << "Paste into " << ts.size() << " tracks\n"; + for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) { - /* undo/redo is handled by individual tracks */ + /* undo/redo is handled by individual tracks/regions */ - if ((*i)->paste (position, times, *cut_buffer, nth)) { - commit = true; - } + if (internal_editing()) { + + RegionSelection rs; + RegionSelection::iterator r; + MidiNoteSelection::iterator cb; + + get_regions_at (rs, position, ts); + + + cerr << " We have " << cut_buffer->midi_notes.size() << " MIDI cut buffers\n"; + + for (cb = cut_buffer->midi_notes.begin(), r = rs.begin(); cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) { + MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r); + if (mrv) { + mrv->paste (position, **cb); + ++cb; + } + } + + } else { + + if ((*i)->paste (position, times, *cut_buffer, nth)) { + commit = true; + } + } } if (commit) { diff --git a/gtk2_ardour/midi_cut_buffer.cc b/gtk2_ardour/midi_cut_buffer.cc new file mode 100644 index 0000000000..008597bc84 --- /dev/null +++ b/gtk2_ardour/midi_cut_buffer.cc @@ -0,0 +1,44 @@ +/* + Copyright (C) 2009 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "midi_cut_buffer.h" + +using namespace ARDOUR; + +MidiCutBuffer::MidiCutBuffer (Session& s) + : AutomatableSequence<MidiModel::TimeType> (s, 0) + , _origin (0) +{ + +} + +MidiCutBuffer::~MidiCutBuffer () +{ +} + +void +MidiCutBuffer::set_origin (MidiCutBuffer::TimeType when) +{ + _origin = when; +} + +void +MidiCutBuffer::set (const Evoral::Sequence<MidiCutBuffer::TimeType>::Notes& notes) +{ + set_notes (notes); +} diff --git a/gtk2_ardour/midi_cut_buffer.h b/gtk2_ardour/midi_cut_buffer.h new file mode 100644 index 0000000000..279d34d244 --- /dev/null +++ b/gtk2_ardour/midi_cut_buffer.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2009 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __gtk_ardour_midi_cut_buffer_h__ +#define __gtk_ardour_midi_cut_buffer_h__ + +#include "ardour/midi_model.h" + +namespace ARDOUR { + class Session; +} + +class MidiCutBuffer : public ARDOUR::AutomatableSequence<ARDOUR::MidiModel::TimeType> +{ + public: + typedef ARDOUR::MidiModel::TimeType TimeType; + + MidiCutBuffer (ARDOUR::Session&); + ~MidiCutBuffer(); + + TimeType origin() const { return _origin; } + void set_origin (TimeType); + + void set (const Evoral::Sequence<TimeType>::Notes&); + + private: + TimeType _origin; +}; + +#endif /* __gtk_ardour_midi_cut_buffer_h__ */ diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 9b9be486a3..7482981b71 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -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,25 @@ MidiRegionView::cut_copy_clear (Editing::CutCopyOp op) return; } - _cut_buffer.clear (); + PublicEditor& editor (trackview.editor()); + switch (op) { + case Cut: + case Copy: + cerr << "Cut/Copy: get selection as CB\n"; + 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 +1698,33 @@ 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, const MidiCutBuffer& mcb) +{ + MidiModel::DeltaCommand* cmd = _model->new_delta_command("paste"); + for (Evoral::Sequence<MidiModel::TimeType>::Notes::const_iterator i = mcb.notes().begin(); i != mcb.notes().end(); ++i) { + cmd->add (boost::shared_ptr<NoteType> (new NoteType (*((*i).get())))); + } + _model->apply_command(trackview.session(), cmd); + + +} diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index 01d5a305cb..1d234e0d1a 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -57,6 +57,7 @@ class MidiTimeAxisView; class GhostRegion; class AutomationTimeAxisView; class AutomationRegionView; +class MidiCutBuffer; class MidiRegionView : public RegionView { @@ -100,7 +101,8 @@ class MidiRegionView : public RegionView void resolve_note(uint8_t note_num, double end_time); void cut_copy_clear (Editing::CutCopyOp); - + void paste (nframes64_t pos, const MidiCutBuffer&); + struct PCEvent { PCEvent(double a_time, uint8_t a_value, uint8_t a_channel) : time(a_time), value(a_value), channel(a_channel) {} @@ -255,23 +257,26 @@ class MidiRegionView : public RegionView /** Convert a timestamp in frames to beats (both relative to region start) */ double frames_to_beats(nframes64_t beats) const; + + /** Return the current selection as a MidiModel or null if there is no selection */ + ARDOUR::MidiModel* selection_as_model () const; protected: - /** Allows derived types to specify their visibility requirements - * to the TimeAxisViewItem parent class. - */ - MidiRegionView (ArdourCanvas::Group *, + /** Allows derived types to specify their visibility requirements + * to the TimeAxisViewItem parent class. + */ + MidiRegionView (ArdourCanvas::Group *, RouteTimeAxisView&, boost::shared_ptr<ARDOUR::MidiRegion>, double samples_per_unit, Gdk::Color& basic_color, TimeAxisViewItem::Visibility); - - void region_resized (ARDOUR::Change); - - void set_flags (XMLNode *); - void store_flags (); - + + void region_resized (ARDOUR::Change); + + void set_flags (XMLNode *); + void store_flags (); + void reset_width_dependent_items (double pixel_width); private: @@ -333,9 +338,8 @@ class MidiRegionView : public RegionView typedef std::set<ArdourCanvas::CanvasNoteEvent*> Selection; /// Currently selected CanvasNoteEvents Selection _selection; - /// the cut buffer for this region view - typedef std::list<NoteType> CutBuffer; - CutBuffer _cut_buffer; + + MidiCutBuffer* selection_as_cut_buffer () const; /** New notes (created in the current command) which should be selected * when they appear after the command is applied. */ diff --git a/gtk2_ardour/midi_selection.h b/gtk2_ardour/midi_selection.h index 27b8ef7352..bd6851870e 100644 --- a/gtk2_ardour/midi_selection.h +++ b/gtk2_ardour/midi_selection.h @@ -23,7 +23,9 @@ #include <list> class MidiRegionView; +class MidiCutBuffer; -struct MidiSelection : std::list<MidiRegionView*> {}; +struct MidiRegionSelection : std::list<MidiRegionView*> {}; +struct MidiNoteSelection : std::list<MidiCutBuffer*> {}; #endif /* __ardour_gtk_midi_selection_h__ */ diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 87d0d07433..d8cbfbc3ea 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -1462,8 +1462,9 @@ RouteTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size return false; } - if (get_diskstream()->speed() != 1.0f) + if (get_diskstream()->speed() != 1.0f) { pos = session_frame_to_track_frame(pos, get_diskstream()->speed() ); + } XMLNode &before = playlist->get_state(); playlist->paste (*p, pos, times); diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index be7552b0bd..b5454c4a12 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -53,7 +53,8 @@ Selection::operator= (const Selection& other) tracks = other.tracks; time = other.time; lines = other.lines; - midi = other.midi; + midi_regions = other.midi_regions; + midi_notes = other.midi_notes; } return *this; } @@ -68,7 +69,8 @@ operator== (const Selection& a, const Selection& b) a.time == b.time && a.lines == b.lines && a.playlists == b.playlists && - a.midi == b.midi; + a.midi_notes == b.midi_notes && + a.midi_regions == b.midi_regions; } /** Clear everything from the Selection */ @@ -81,7 +83,8 @@ Selection::clear () clear_lines(); clear_time (); clear_playlists (); - clear_midi (); + clear_midi_notes (); + clear_midi_regions (); } void @@ -113,11 +116,20 @@ Selection::clear_tracks () } void -Selection::clear_midi () +Selection::clear_midi_notes () { - if (!midi.empty()) { - midi.clear (); - MidiChanged (); + if (!midi_notes.empty()) { + midi_notes.clear (); + MidiNotesChanged (); + } +} + +void +Selection::clear_midi_regions () +{ + if (!midi_regions.empty()) { + midi_regions.clear (); + MidiRegionsChanged (); } } @@ -185,7 +197,7 @@ void Selection::toggle (const list<TimeAxisView*>& track_list) { for (list<TimeAxisView*>::const_iterator i = track_list.begin(); i != track_list.end(); ++i) { - toggle ( (*i) ); + toggle ((*i)); } } @@ -206,6 +218,29 @@ Selection::toggle (TimeAxisView* track) } void +Selection::toggle (const MidiNoteSelection& midi_note_list) +{ + for (MidiNoteSelection::const_iterator i = midi_note_list.begin(); i != midi_note_list.end(); ++i) { + toggle ((*i)); + } +} + +void +Selection::toggle (MidiCutBuffer* midi) +{ + MidiNoteSelection::iterator i; + + if ((i = find (midi_notes.begin(), midi_notes.end(), midi)) == midi_notes.end()) { + midi_notes.push_back (midi); + } else { + midi_notes.erase (i); + } + + MidiNotesChanged(); +} + + +void Selection::toggle (RegionView* r) { RegionSelection::iterator i; @@ -222,15 +257,15 @@ Selection::toggle (RegionView* r) void Selection::toggle (MidiRegionView* mrv) { - MidiSelection::iterator i; + MidiRegionSelection::iterator i; - if ((i = find (midi.begin(), midi.end(), mrv)) == midi.end()) { + if ((i = find (midi_regions.begin(), midi_regions.end(), mrv)) == midi_regions.end()) { add (mrv); } else { - midi.erase (i); + midi_regions.erase (i); } - MidiChanged (); + MidiRegionsChanged (); } void @@ -320,6 +355,27 @@ Selection::add (TimeAxisView* track) } void +Selection::add (const MidiNoteSelection& midi_list) +{ + const MidiNoteSelection::const_iterator b = midi_list.begin(); + const MidiNoteSelection::const_iterator e = midi_list.end(); + + if (!midi_list.empty()) { + midi_notes.insert (midi_notes.end(), b, e); + MidiNotesChanged (); + } +} + +void +Selection::add (MidiCutBuffer* midi) +{ + if (find (midi_notes.begin(), midi_notes.end(), midi) == midi_notes.end()) { + midi_notes.push_back (midi); + MidiNotesChanged (); + } +} + +void Selection::add (vector<RegionView*>& v) { /* XXX This method or the add (const RegionSelection&) needs to go @@ -378,15 +434,15 @@ Selection::add (RegionView* r) void Selection::add (MidiRegionView* mrv) { - if (find (midi.begin(), midi.end(), mrv) == midi.end()) { - midi.push_back (mrv); + if (find (midi_regions.begin(), midi_regions.end(), mrv) == midi_regions.end()) { + midi_regions.push_back (mrv); /* XXX should we do this? */ #if 0 if (Config->get_link_region_and_track_selection()) { add (&mrv->get_trackview()); } #endif - MidiChanged (); + MidiRegionsChanged (); } } @@ -473,6 +529,37 @@ Selection::remove (const list<TimeAxisView*>& track_list) } void +Selection::remove (const MidiNoteSelection& midi_list) +{ + bool changed = false; + + for (MidiNoteSelection::const_iterator i = midi_list.begin(); i != midi_list.end(); ++i) { + + MidiNoteSelection::iterator x; + + if ((x = find (midi_notes.begin(), midi_notes.end(), (*i))) != midi_notes.end()) { + midi_notes.erase (x); + changed = true; + } + } + + if (changed) { + MidiNotesChanged(); + } +} + +void +Selection::remove (MidiCutBuffer* midi) +{ + MidiNoteSelection::iterator x; + + if ((x = find (midi_notes.begin(), midi_notes.end(), midi)) != midi_notes.end()) { + midi_notes.erase (x); + MidiNotesChanged (); + } +} + +void Selection::remove (boost::shared_ptr<Playlist> track) { list<boost::shared_ptr<Playlist> >::iterator i; @@ -517,11 +604,11 @@ Selection::remove (RegionView* r) void Selection::remove (MidiRegionView* mrv) { - MidiSelection::iterator x; + MidiRegionSelection::iterator x; - if ((x = find (midi.begin(), midi.end(), mrv)) != midi.end()) { - midi.erase (x); - MidiChanged (); + if ((x = find (midi_regions.begin(), midi_regions.end(), mrv)) != midi_regions.end()) { + midi_regions.erase (x); + MidiRegionsChanged (); } #if 0 @@ -580,6 +667,13 @@ Selection::set (const list<TimeAxisView*>& track_list) } void +Selection::set (const MidiNoteSelection& midi_list) +{ + clear_midi_notes (); + add (midi_list); +} + +void Selection::set (boost::shared_ptr<Playlist> playlist) { clear_playlists (); @@ -604,7 +698,7 @@ Selection::set (const RegionSelection& rs) void Selection::set (MidiRegionView* mrv) { - clear_midi (); + clear_midi_regions (); add (mrv); } @@ -690,17 +784,28 @@ Selection::selected (RegionView* rv) } bool -Selection::empty () +Selection::empty (bool internal_selection) { - return regions.empty () && + bool object_level_empty = regions.empty () && tracks.empty () && points.empty () && playlists.empty () && lines.empty () && time.empty () && playlists.empty () && - markers.empty() + markers.empty() && + midi_regions.empty() ; + + if (!internal_selection) { + return object_level_empty; + } + + /* this is intended to really only apply when using a Selection + as a cut buffer. + */ + + return object_level_empty && midi_notes.empty(); } void diff --git a/gtk2_ardour/selection.h b/gtk2_ardour/selection.h index 9278935e31..288c832178 100644 --- a/gtk2_ardour/selection.h +++ b/gtk2_ardour/selection.h @@ -79,7 +79,8 @@ class Selection : public sigc::trackable PlaylistSelection playlists; PointSelection points; MarkerSelection markers; - MidiSelection midi; + MidiRegionSelection midi_regions; + MidiNoteSelection midi_notes; Selection (PublicEditor const * e) : editor (e), next_time_id (0) { clear(); @@ -94,10 +95,11 @@ class Selection : public sigc::trackable sigc::signal<void> PlaylistsChanged; sigc::signal<void> PointsChanged; sigc::signal<void> MarkersChanged; - sigc::signal<void> MidiChanged; + sigc::signal<void> MidiNotesChanged; + sigc::signal<void> MidiRegionsChanged; void clear (); - bool empty(); + bool empty (bool internal_selection = false); void dump_region_layers(); @@ -111,6 +113,7 @@ class Selection : public sigc::trackable void set (TimeAxisView*); void set (const std::list<TimeAxisView*>&); + void set (const MidiNoteSelection&); void set (RegionView*, bool also_clear_tracks = true); void set (MidiRegionView*); void set (std::vector<RegionView*>&); @@ -124,8 +127,10 @@ class Selection : public sigc::trackable void toggle (TimeAxisView*); void toggle (const std::list<TimeAxisView*>&); + void toggle (const MidiNoteSelection&); void toggle (RegionView*); void toggle (MidiRegionView*); + void toggle (MidiCutBuffer*); void toggle (std::vector<RegionView*>&); long toggle (nframes_t, nframes_t); void toggle (ARDOUR::AutomationList*); @@ -136,8 +141,10 @@ class Selection : public sigc::trackable void add (TimeAxisView*); void add (const std::list<TimeAxisView*>&); + void add (const MidiNoteSelection&); void add (RegionView*); void add (MidiRegionView*); + void add (MidiCutBuffer*); void add (std::vector<RegionView*>&); long add (nframes_t, nframes_t); void add (boost::shared_ptr<Evoral::ControlList>); @@ -148,8 +155,10 @@ class Selection : public sigc::trackable void add (const RegionSelection&); void remove (TimeAxisView*); void remove (const std::list<TimeAxisView*>&); + void remove (const MidiNoteSelection&); void remove (RegionView*); void remove (MidiRegionView*); + void remove (MidiCutBuffer*); void remove (uint32_t selection_id); void remove (nframes_t, nframes_t); void remove (boost::shared_ptr<ARDOUR::AutomationList>); @@ -167,7 +176,8 @@ class Selection : public sigc::trackable void clear_playlists (); void clear_points (); void clear_markers (); - void clear_midi (); + void clear_midi_notes (); + void clear_midi_regions (); void foreach_region (void (ARDOUR::Region::*method)(void)); void foreach_regionview (void (RegionView::*method)(void)); diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 592b48efd0..87503ff2d3 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -126,6 +126,7 @@ gtk2_ardour_sources = [ 'main.cc', 'marker.cc', 'midi_channel_selector.cc', + 'midi_cut_buffer.cc', 'midi_port_dialog.cc', 'midi_region_view.cc', 'midi_scroomer.cc', |