diff options
author | Carl Hetherington <carl@carlh.net> | 2010-08-05 13:36:38 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2010-08-05 13:36:38 +0000 |
commit | 5e3ca4db5cc356385e520643cfd279f393db4b51 (patch) | |
tree | 2ea31a74d34e37e33bc5b126a5e7f1b58753b4f0 /gtk2_ardour | |
parent | e7a2b99f3d4f7afe73a30ac85e770e228785c1be (diff) |
Support cut / copy / paste of MIDI automation.
git-svn-id: svn://localhost/ardour2/branches/3.0@7545 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour')
-rw-r--r-- | gtk2_ardour/automation_line.cc | 35 | ||||
-rw-r--r-- | gtk2_ardour/automation_line.h | 6 | ||||
-rw-r--r-- | gtk2_ardour/automation_selectable.h | 46 | ||||
-rw-r--r-- | gtk2_ardour/automation_streamview.cc | 50 | ||||
-rw-r--r-- | gtk2_ardour/automation_streamview.h | 3 | ||||
-rw-r--r-- | gtk2_ardour/automation_time_axis.cc | 42 | ||||
-rw-r--r-- | gtk2_ardour/automation_time_axis.h | 4 | ||||
-rw-r--r-- | gtk2_ardour/editor_selection.cc | 6 | ||||
-rw-r--r-- | gtk2_ardour/region_view.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/route_time_axis.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/route_time_axis.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/time_axis_view.h | 2 |
12 files changed, 145 insertions, 55 deletions
diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index dd5f11f042..9ca1c59bb0 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -947,15 +947,25 @@ AutomationLine::remove_point (ControlPoint& cp) trackview.editor().session()->set_dirty (); } +/** Get selectable points within an area. + * @param start Start position in session frames. + * @param end End position in session frames. + * @param botfrac Bottom of area, as a fraction of the line height. + * @param topfrac Bottom of area, as a fraction of the line height. + */ void -AutomationLine::get_selectables (nframes_t start, nframes_t end, - double botfrac, double topfrac, list<Selectable*>& results) +AutomationLine::get_selectables ( + framepos_t start, framepos_t end, double botfrac, double topfrac, list<Selectable*>& results + ) { double top; double bot; - sframes_t nstart; - sframes_t nend; + + /* these two are in AutomationList model coordinates */ + double nstart; + double nend; + bool collecting = false; /* Curse X11 and its inverted coordinate system! */ @@ -963,21 +973,22 @@ AutomationLine::get_selectables (nframes_t start, nframes_t end, bot = (1.0 - topfrac) * _height; top = (1.0 - botfrac) * _height; - nstart = max_frames; + nstart = DBL_MAX; nend = 0; for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { - sframes_t const when = _time_converter.to ((*(*i)->model())->when); + double const model_when = (*(*i)->model())->when; + framepos_t const session_frames_when = _time_converter.to (model_when) + _time_converter.origin_b (); - if (when >= start && when <= end) { + if (session_frames_when >= start && session_frames_when <= end) { if ((*i)->get_y() >= bot && (*i)->get_y() <= top) { (*i)->show(); (*i)->set_visible(true); collecting = true; - nstart = min (nstart, when); - nend = max (nend, when); + nstart = min (nstart, model_when); + nend = max (nend, model_when); } else { @@ -985,7 +996,7 @@ AutomationLine::get_selectables (nframes_t start, nframes_t end, results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, &trackview)); collecting = false; - nstart = max_frames; + nstart = DBL_MAX; nend = 0; } } @@ -1023,8 +1034,8 @@ AutomationLine::point_selection_to_control_points (PointSelection const & s) for (vector<ControlPoint*>::iterator j = control_points.begin(); j != control_points.end(); ++j) { - double const rstart = trackview.editor().frame_to_unit (i->start); - double const rend = trackview.editor().frame_to_unit (i->end); + double const rstart = trackview.editor().frame_to_unit (_time_converter.to (i->start)); + double const rend = trackview.editor().frame_to_unit (_time_converter.to (i->end)); if ((*j)->get_x() >= rstart && (*j)->get_x() <= rend) { if ((*j)->get_y() >= bot && (*j)->get_y() <= top) { diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h index 0222328634..1464170c34 100644 --- a/gtk2_ardour/automation_line.h +++ b/gtk2_ardour/automation_line.h @@ -68,7 +68,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible std::list<ControlPoint*> point_selection_to_control_points (PointSelection const &); void set_selected_points (PointSelection&); - void get_selectables (nframes_t start, nframes_t end, + void get_selectables (ARDOUR::framepos_t start, ARDOUR::framepos_t end, double botfrac, double topfrac, std::list<Selectable*>& results); void get_inverted_selectables (Selection&, std::list<Selectable*>& results); @@ -136,6 +136,10 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible virtual MementoCommandBinder<ARDOUR::AutomationList>* memento_command_binder (); + const Evoral::TimeConverter<double, ARDOUR::sframes_t>& time_converter () const { + return _time_converter; + } + protected: std::string _name; diff --git a/gtk2_ardour/automation_selectable.h b/gtk2_ardour/automation_selectable.h index 7104f6adf4..8c897816ba 100644 --- a/gtk2_ardour/automation_selectable.h +++ b/gtk2_ardour/automation_selectable.h @@ -20,35 +20,37 @@ #ifndef __ardour_gtk_automation_selectable_h__ #define __ardour_gtk_automation_selectable_h__ -#include "ardour/types.h" #include "selectable.h" class TimeAxisView; -/** A selected automation point, expressed as a rectangle on a track (so that x coordinates - * are frames and y coordinates are a fraction of track height). This representation falls - * between the visible GUI control points and the back-end "actual" automation points, - * some of which may not be visible; it is not trivial to convert from one of these to the other, - * so the AutomationSelectable is a kind of "best and worst of both worlds". +/** A selected automation point, expressed as a rectangle. + * x coordinates start/end are in AutomationList model coordinates. + * y coordinates are a expressed as a fraction of track height. + * This representation falls between the visible GUI control points and + * the back-end "actual" automation points, some of which may not be + * visible; it is not trivial to convert from one of these to the + * other, so the AutomationSelectable is a kind of "best and worst of + * both worlds". */ struct AutomationSelectable : public Selectable { - nframes_t start; - nframes_t end; - double low_fract; - double high_fract; - TimeAxisView* track; // ref would be better, but ARDOUR::SessionHandlePtr is non-assignable - - AutomationSelectable (nframes_t s, nframes_t e, double l, double h, TimeAxisView* atv) - : start (s), end (e), low_fract (l), high_fract (h), track (atv) {} - - bool operator== (const AutomationSelectable& other) { - return start == other.start && - end == other.end && - low_fract == other.low_fract && - high_fract == other.high_fract && - track == other.track; - } + double start; + double end; + double low_fract; + double high_fract; + TimeAxisView* track; // ref would be better, but ARDOUR::SessionHandlePtr is non-assignable + + AutomationSelectable (double s, double e, double l, double h, TimeAxisView* atv) + : start (s), end (e), low_fract (l), high_fract (h), track (atv) {} + + bool operator== (const AutomationSelectable& other) { + return start == other.start && + end == other.end && + low_fract == other.low_fract && + high_fract == other.high_fract && + track == other.track; + } }; #endif /* __ardour_gtk_automation_selectable_h__ */ diff --git a/gtk2_ardour/automation_streamview.cc b/gtk2_ardour/automation_streamview.cc index 6beb439b11..90e1b991fd 100644 --- a/gtk2_ardour/automation_streamview.cc +++ b/gtk2_ardour/automation_streamview.cc @@ -274,13 +274,16 @@ AutomationStreamView::clear () } } +/** @param start Start position in session frames. + * @param end End position in session frames. + */ void -AutomationStreamView::get_selectables (nframes_t start, nframes_t end, double botfrac, double topfrac, list<Selectable*>& results) +AutomationStreamView::get_selectables (framepos_t start, framepos_t end, double botfrac, double topfrac, list<Selectable*>& results) { for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) { AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*i); assert (arv); - arv->line()->get_selectables (start - (*i)->region()->position(), end - (*i)->region()->position(), botfrac, topfrac, results); + arv->line()->get_selectables (start, end, botfrac, topfrac, results); } } @@ -307,3 +310,46 @@ AutomationStreamView::get_lines () const return lines; } + +struct RegionPositionSorter { + bool operator() (RegionView* a, RegionView* b) { + return a->region()->position() < b->region()->position(); + } +}; + + +/** @param pos Position, in session frames. + * @return AutomationLine to paste to for that position, or 0 if there is none appropriate. + */ +boost::shared_ptr<AutomationLine> +AutomationStreamView::paste_line (framepos_t pos) +{ + /* XXX: not sure how best to pick this; for now, just use the last region which starts before pos */ + + if (region_views.empty()) { + return boost::shared_ptr<AutomationLine> (); + } + + region_views.sort (RegionPositionSorter ()); + + list<RegionView*>::const_iterator prev = region_views.begin (); + + for (list<RegionView*>::const_iterator i = region_views.begin(); i != region_views.end(); ++i) { + if ((*i)->region()->position() > pos) { + break; + } + prev = i; + } + + boost::shared_ptr<Region> r = (*prev)->region (); + + /* If *prev doesn't cover pos, it's no good */ + if (r->position() > pos || ((r->position() + r->length()) < pos)) { + return boost::shared_ptr<AutomationLine> (); + } + + AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*prev); + assert (arv); + + return arv->line (); +} diff --git a/gtk2_ardour/automation_streamview.h b/gtk2_ardour/automation_streamview.h index 8afacd79cf..257908c9ea 100644 --- a/gtk2_ardour/automation_streamview.h +++ b/gtk2_ardour/automation_streamview.h @@ -61,10 +61,11 @@ class AutomationStreamView : public StreamView void clear (); - void get_selectables (nframes_t, nframes_t, double, double, std::list<Selectable*> &); + void get_selectables (ARDOUR::framepos_t, ARDOUR::framepos_t, double, double, std::list<Selectable*> &); void set_selected_points (PointSelection &); std::list<boost::shared_ptr<AutomationLine> > get_lines () const; + boost::shared_ptr<AutomationLine> paste_line (ARDOUR::framepos_t); private: void setup_rec_box (); diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index 448cf4e501..cb0c85ae61 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -634,21 +634,27 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel XMLNode &before = alist->get_state(); + /* convert time selection to automation list model coordinates */ + const Evoral::TimeConverter<double, ARDOUR::sframes_t>& tc = line.time_converter (); + double const start = tc.from (selection.time.front().start - tc.origin_b ()); + double const end = tc.from (selection.time.front().end - tc.origin_b ()); + switch (op) { case Cut: - if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) { + + if ((what_we_got = alist->cut (start, end)) != 0) { _editor.get_cut_buffer().add (what_we_got); _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state())); } break; case Copy: - if ((what_we_got = alist->copy (selection.time.front().start, selection.time.front().end)) != 0) { + if ((what_we_got = alist->copy (start, end)) != 0) { _editor.get_cut_buffer().add (what_we_got); } break; case Clear: - if ((what_we_got = alist->cut (selection.time.front().start, selection.time.front().end)) != 0) { + if ((what_we_got = alist->cut (start, end)) != 0) { _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state())); } break; @@ -740,8 +746,6 @@ AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointS delete &before; - cout << "CCC objects " << what_we_got->size() << "\n"; - if (what_we_got) { for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) { double when = (*x)->when; @@ -753,14 +757,32 @@ AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointS } } +/** Paste a selection. + * @param pos Position to paste to (session frames). + * @param times Number of times to paste. + * @param selection Selection to paste. + * @param nth Index of the AutomationList within the selection to paste from. + */ bool -AutomationTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth) +AutomationTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth) { - return paste_one (*_line, pos, times, selection, nth); + boost::shared_ptr<AutomationLine> line; + + if (_line) { + line = _line; + } else if (_view) { + line = _view->paste_line (pos); + } + + if (!line) { + return false; + } + + return paste_one (*line, pos, times, selection, nth); } bool -AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float times, Selection& selection, size_t nth) +AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float times, Selection& selection, size_t nth) { AutomationSelection::iterator p; boost::shared_ptr<AutomationList> alist(line.the_list()); @@ -786,8 +808,10 @@ AutomationTimeAxisView::paste_one (AutomationLine& line, nframes_t pos, float ti (*x)->value = val; } + double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ()); + XMLNode &before = alist->get_state(); - alist->paste (copy, pos, times); + alist->paste (copy, model_pos, times); _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state())); return true; diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h index 0da6c69acd..85ad6ad7d9 100644 --- a/gtk2_ardour/automation_time_axis.h +++ b/gtk2_ardour/automation_time_axis.h @@ -88,7 +88,7 @@ class AutomationTimeAxisView : public TimeAxisView { void cut_copy_clear (Selection&, Editing::CutCopyOp); void cut_copy_clear_objects (PointSelection&, Editing::CutCopyOp); - bool paste (nframes_t, float times, Selection&, size_t nth); + bool paste (ARDOUR::framepos_t, float times, Selection&, size_t nth); void reset_objects (PointSelection&); int set_state (const XMLNode&, int version); @@ -148,7 +148,7 @@ class AutomationTimeAxisView : public TimeAxisView { void cut_copy_clear_one (AutomationLine&, Selection&, Editing::CutCopyOp); void cut_copy_clear_objects_one (AutomationLine&, PointSelection&, Editing::CutCopyOp); - bool paste_one (AutomationLine&, nframes_t, float times, Selection&, size_t nth); + bool paste_one (AutomationLine&, ARDOUR::framepos_t, float times, Selection&, size_t nth); void reset_objects_one (AutomationLine&, PointSelection&); void set_automation_state (ARDOUR::AutoState); diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index 6b15f40599..75b4f30d61 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -977,11 +977,13 @@ Editor::invert_selection () selection->set (touched); } -/** @param top Top (lower) y limit in trackview coordinates. +/** @param start Start time in session frames. + * @param end End time in session frames. + * @param top Top (lower) y limit in trackview coordinates. * @param bottom Bottom (higher) y limit in trackview coordinates. */ bool -Editor::select_all_within (nframes64_t start, nframes64_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op) +Editor::select_all_within (framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op) { list<Selectable*> found; diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc index 8a9767bb02..890c16def6 100644 --- a/gtk2_ardour/region_view.cc +++ b/gtk2_ardour/region_view.cc @@ -269,7 +269,7 @@ RegionView::region_resized (const PropertyChange& what_changed) if (what_changed.contains (ARDOUR::Properties::position)) { set_position (_region->position(), 0); - _time_converter.set_origin(_region->position()); + _time_converter.set_origin_b (_region->position()); } PropertyChange s_and_l; diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 9e50b67fac..b4f56f2ffe 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -1363,7 +1363,7 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) } bool -RouteTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth) +RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth) { if (!is_track()) { return false; diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h index 6d832c8077..baef76ee61 100644 --- a/gtk2_ardour/route_time_axis.h +++ b/gtk2_ardour/route_time_axis.h @@ -93,7 +93,7 @@ public: /* Editing operations */ void cut_copy_clear (Selection&, Editing::CutCopyOp); - bool paste (nframes_t, float times, Selection&, size_t nth); + bool paste (ARDOUR::framepos_t, float times, Selection&, size_t nth); TimeAxisView::Children get_child_list(); diff --git a/gtk2_ardour/time_axis_view.h b/gtk2_ardour/time_axis_view.h index dfdff2954e..d84075977f 100644 --- a/gtk2_ardour/time_axis_view.h +++ b/gtk2_ardour/time_axis_view.h @@ -178,7 +178,7 @@ class TimeAxisView : public virtual AxisView, public PBD::Stateful /* editing operations */ virtual void cut_copy_clear (Selection&, Editing::CutCopyOp) {} - virtual bool paste (nframes_t, float /*times*/, Selection&, size_t /*nth*/) { return false; } + virtual bool paste (ARDOUR::framepos_t, float /*times*/, Selection&, size_t /*nth*/) { return false; } virtual void set_selected_regionviews (RegionSelection&) {} virtual void set_selected_points (PointSelection&) {} |