mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-09 00:04:56 +01:00
Support cut / copy / paste of MIDI automation.
git-svn-id: svn://localhost/ardour2/branches/3.0@7545 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
e7a2b99f3d
commit
5e3ca4db5c
16 changed files with 169 additions and 67 deletions
|
|
@ -947,15 +947,25 @@ AutomationLine::remove_point (ControlPoint& cp)
|
||||||
trackview.editor().session()->set_dirty ();
|
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
|
void
|
||||||
AutomationLine::get_selectables (nframes_t start, nframes_t end,
|
AutomationLine::get_selectables (
|
||||||
double botfrac, double topfrac, list<Selectable*>& results)
|
framepos_t start, framepos_t end, double botfrac, double topfrac, list<Selectable*>& results
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
double top;
|
double top;
|
||||||
double bot;
|
double bot;
|
||||||
sframes_t nstart;
|
|
||||||
sframes_t nend;
|
/* these two are in AutomationList model coordinates */
|
||||||
|
double nstart;
|
||||||
|
double nend;
|
||||||
|
|
||||||
bool collecting = false;
|
bool collecting = false;
|
||||||
|
|
||||||
/* Curse X11 and its inverted coordinate system! */
|
/* 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;
|
bot = (1.0 - topfrac) * _height;
|
||||||
top = (1.0 - botfrac) * _height;
|
top = (1.0 - botfrac) * _height;
|
||||||
|
|
||||||
nstart = max_frames;
|
nstart = DBL_MAX;
|
||||||
nend = 0;
|
nend = 0;
|
||||||
|
|
||||||
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
|
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) {
|
if ((*i)->get_y() >= bot && (*i)->get_y() <= top) {
|
||||||
|
|
||||||
(*i)->show();
|
(*i)->show();
|
||||||
(*i)->set_visible(true);
|
(*i)->set_visible(true);
|
||||||
collecting = true;
|
collecting = true;
|
||||||
nstart = min (nstart, when);
|
nstart = min (nstart, model_when);
|
||||||
nend = max (nend, when);
|
nend = max (nend, model_when);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
@ -985,7 +996,7 @@ AutomationLine::get_selectables (nframes_t start, nframes_t end,
|
||||||
|
|
||||||
results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, &trackview));
|
results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, &trackview));
|
||||||
collecting = false;
|
collecting = false;
|
||||||
nstart = max_frames;
|
nstart = DBL_MAX;
|
||||||
nend = 0;
|
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) {
|
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 rstart = trackview.editor().frame_to_unit (_time_converter.to (i->start));
|
||||||
double const rend = trackview.editor().frame_to_unit (i->end);
|
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_x() >= rstart && (*j)->get_x() <= rend) {
|
||||||
if ((*j)->get_y() >= bot && (*j)->get_y() <= top) {
|
if ((*j)->get_y() >= bot && (*j)->get_y() <= top) {
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
|
||||||
|
|
||||||
std::list<ControlPoint*> point_selection_to_control_points (PointSelection const &);
|
std::list<ControlPoint*> point_selection_to_control_points (PointSelection const &);
|
||||||
void set_selected_points (PointSelection&);
|
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,
|
double botfrac, double topfrac,
|
||||||
std::list<Selectable*>& results);
|
std::list<Selectable*>& results);
|
||||||
void get_inverted_selectables (Selection&, 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 ();
|
virtual MementoCommandBinder<ARDOUR::AutomationList>* memento_command_binder ();
|
||||||
|
|
||||||
|
const Evoral::TimeConverter<double, ARDOUR::sframes_t>& time_converter () const {
|
||||||
|
return _time_converter;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
std::string _name;
|
std::string _name;
|
||||||
|
|
|
||||||
|
|
@ -20,26 +20,28 @@
|
||||||
#ifndef __ardour_gtk_automation_selectable_h__
|
#ifndef __ardour_gtk_automation_selectable_h__
|
||||||
#define __ardour_gtk_automation_selectable_h__
|
#define __ardour_gtk_automation_selectable_h__
|
||||||
|
|
||||||
#include "ardour/types.h"
|
|
||||||
#include "selectable.h"
|
#include "selectable.h"
|
||||||
|
|
||||||
class TimeAxisView;
|
class TimeAxisView;
|
||||||
|
|
||||||
/** A selected automation point, expressed as a rectangle on a track (so that x coordinates
|
/** A selected automation point, expressed as a rectangle.
|
||||||
* are frames and y coordinates are a fraction of track height). This representation falls
|
* x coordinates start/end are in AutomationList model coordinates.
|
||||||
* between the visible GUI control points and the back-end "actual" automation points,
|
* y coordinates are a expressed as a fraction of track height.
|
||||||
* some of which may not be visible; it is not trivial to convert from one of these to the other,
|
* This representation falls between the visible GUI control points and
|
||||||
* so the AutomationSelectable is a kind of "best and worst of both worlds".
|
* 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
|
struct AutomationSelectable : public Selectable
|
||||||
{
|
{
|
||||||
nframes_t start;
|
double start;
|
||||||
nframes_t end;
|
double end;
|
||||||
double low_fract;
|
double low_fract;
|
||||||
double high_fract;
|
double high_fract;
|
||||||
TimeAxisView* track; // ref would be better, but ARDOUR::SessionHandlePtr is non-assignable
|
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)
|
AutomationSelectable (double s, double e, double l, double h, TimeAxisView* atv)
|
||||||
: start (s), end (e), low_fract (l), high_fract (h), track (atv) {}
|
: start (s), end (e), low_fract (l), high_fract (h), track (atv) {}
|
||||||
|
|
||||||
bool operator== (const AutomationSelectable& other) {
|
bool operator== (const AutomationSelectable& other) {
|
||||||
|
|
|
||||||
|
|
@ -274,13 +274,16 @@ AutomationStreamView::clear ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param start Start position in session frames.
|
||||||
|
* @param end End position in session frames.
|
||||||
|
*/
|
||||||
void
|
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) {
|
for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
|
||||||
AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*i);
|
AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*i);
|
||||||
assert (arv);
|
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;
|
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 ();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,10 +61,11 @@ class AutomationStreamView : public StreamView
|
||||||
|
|
||||||
void clear ();
|
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 &);
|
void set_selected_points (PointSelection &);
|
||||||
|
|
||||||
std::list<boost::shared_ptr<AutomationLine> > get_lines () const;
|
std::list<boost::shared_ptr<AutomationLine> > get_lines () const;
|
||||||
|
boost::shared_ptr<AutomationLine> paste_line (ARDOUR::framepos_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setup_rec_box ();
|
void setup_rec_box ();
|
||||||
|
|
|
||||||
|
|
@ -634,21 +634,27 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel
|
||||||
|
|
||||||
XMLNode &before = alist->get_state();
|
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) {
|
switch (op) {
|
||||||
case Cut:
|
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);
|
_editor.get_cut_buffer().add (what_we_got);
|
||||||
_session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
|
_session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Copy:
|
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);
|
_editor.get_cut_buffer().add (what_we_got);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Clear:
|
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()));
|
_session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -740,8 +746,6 @@ AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointS
|
||||||
|
|
||||||
delete &before;
|
delete &before;
|
||||||
|
|
||||||
cout << "CCC objects " << what_we_got->size() << "\n";
|
|
||||||
|
|
||||||
if (what_we_got) {
|
if (what_we_got) {
|
||||||
for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
|
for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
|
||||||
double when = (*x)->when;
|
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
|
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
|
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;
|
AutomationSelection::iterator p;
|
||||||
boost::shared_ptr<AutomationList> alist(line.the_list());
|
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;
|
(*x)->value = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ());
|
||||||
|
|
||||||
XMLNode &before = alist->get_state();
|
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()));
|
_session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ class AutomationTimeAxisView : public TimeAxisView {
|
||||||
|
|
||||||
void cut_copy_clear (Selection&, Editing::CutCopyOp);
|
void cut_copy_clear (Selection&, Editing::CutCopyOp);
|
||||||
void cut_copy_clear_objects (PointSelection&, 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&);
|
void reset_objects (PointSelection&);
|
||||||
|
|
||||||
int set_state (const XMLNode&, int version);
|
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_one (AutomationLine&, Selection&, Editing::CutCopyOp);
|
||||||
void cut_copy_clear_objects_one (AutomationLine&, PointSelection&, 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 reset_objects_one (AutomationLine&, PointSelection&);
|
||||||
|
|
||||||
void set_automation_state (ARDOUR::AutoState);
|
void set_automation_state (ARDOUR::AutoState);
|
||||||
|
|
|
||||||
|
|
@ -977,11 +977,13 @@ Editor::invert_selection ()
|
||||||
selection->set (touched);
|
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.
|
* @param bottom Bottom (higher) y limit in trackview coordinates.
|
||||||
*/
|
*/
|
||||||
bool
|
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;
|
list<Selectable*> found;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ RegionView::region_resized (const PropertyChange& what_changed)
|
||||||
|
|
||||||
if (what_changed.contains (ARDOUR::Properties::position)) {
|
if (what_changed.contains (ARDOUR::Properties::position)) {
|
||||||
set_position (_region->position(), 0);
|
set_position (_region->position(), 0);
|
||||||
_time_converter.set_origin(_region->position());
|
_time_converter.set_origin_b (_region->position());
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyChange s_and_l;
|
PropertyChange s_and_l;
|
||||||
|
|
|
||||||
|
|
@ -1363,7 +1363,7 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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()) {
|
if (!is_track()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ public:
|
||||||
|
|
||||||
/* Editing operations */
|
/* Editing operations */
|
||||||
void cut_copy_clear (Selection&, Editing::CutCopyOp);
|
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();
|
TimeAxisView::Children get_child_list();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ class TimeAxisView : public virtual AxisView, public PBD::Stateful
|
||||||
/* editing operations */
|
/* editing operations */
|
||||||
|
|
||||||
virtual void cut_copy_clear (Selection&, Editing::CutCopyOp) {}
|
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_regionviews (RegionSelection&) {}
|
||||||
virtual void set_selected_points (PointSelection&) {}
|
virtual void set_selected_points (PointSelection&) {}
|
||||||
|
|
|
||||||
|
|
@ -32,19 +32,15 @@ class TempoMap;
|
||||||
class BeatsFramesConverter : public Evoral::TimeConverter<double,sframes_t> {
|
class BeatsFramesConverter : public Evoral::TimeConverter<double,sframes_t> {
|
||||||
public:
|
public:
|
||||||
BeatsFramesConverter(const TempoMap& tempo_map, sframes_t origin)
|
BeatsFramesConverter(const TempoMap& tempo_map, sframes_t origin)
|
||||||
: _tempo_map(tempo_map)
|
: Evoral::TimeConverter<double, sframes_t> (origin)
|
||||||
, _origin(origin)
|
, _tempo_map(tempo_map)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
sframes_t to(double beats) const;
|
sframes_t to(double beats) const;
|
||||||
double from(sframes_t frames) const;
|
double from(sframes_t frames) const;
|
||||||
|
|
||||||
sframes_t origin() const { return _origin; }
|
|
||||||
void set_origin(sframes_t origin) { _origin = origin; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const TempoMap& _tempo_map;
|
const TempoMap& _tempo_map;
|
||||||
sframes_t _origin;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace ARDOUR */
|
} /* namespace ARDOUR */
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,10 @@ sframes_t
|
||||||
BeatsFramesConverter::to(double beats) const
|
BeatsFramesConverter::to(double beats) const
|
||||||
{
|
{
|
||||||
// FIXME: assumes tempo never changes after origin
|
// FIXME: assumes tempo never changes after origin
|
||||||
const Tempo& tempo = _tempo_map.tempo_at(_origin);
|
const Tempo& tempo = _tempo_map.tempo_at (_origin_b);
|
||||||
const double frames_per_beat = tempo.frames_per_beat(
|
const double frames_per_beat = tempo.frames_per_beat(
|
||||||
_tempo_map.frame_rate(),
|
_tempo_map.frame_rate(),
|
||||||
_tempo_map.meter_at(_origin));
|
_tempo_map.meter_at (_origin_b));
|
||||||
|
|
||||||
return lrint(beats * frames_per_beat);
|
return lrint(beats * frames_per_beat);
|
||||||
}
|
}
|
||||||
|
|
@ -40,10 +40,10 @@ double
|
||||||
BeatsFramesConverter::from(sframes_t frames) const
|
BeatsFramesConverter::from(sframes_t frames) const
|
||||||
{
|
{
|
||||||
// FIXME: assumes tempo never changes after origin
|
// FIXME: assumes tempo never changes after origin
|
||||||
const Tempo& tempo = _tempo_map.tempo_at(_origin);
|
const Tempo& tempo = _tempo_map.tempo_at (_origin_b);
|
||||||
const double frames_per_beat = tempo.frames_per_beat(
|
const double frames_per_beat = tempo.frames_per_beat(
|
||||||
_tempo_map.frame_rate(),
|
_tempo_map.frame_rate(),
|
||||||
_tempo_map.meter_at(_origin));
|
_tempo_map.meter_at (_origin_b));
|
||||||
|
|
||||||
return frames / frames_per_beat;
|
return frames / frames_per_beat;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ namespace Evoral {
|
||||||
template<typename A, typename B>
|
template<typename A, typename B>
|
||||||
class TimeConverter {
|
class TimeConverter {
|
||||||
public:
|
public:
|
||||||
|
TimeConverter (B ob = 0) : _origin_b (ob) {}
|
||||||
virtual ~TimeConverter() {}
|
virtual ~TimeConverter() {}
|
||||||
|
|
||||||
/** Convert A time to B time (A to B) */
|
/** Convert A time to B time (A to B) */
|
||||||
|
|
@ -36,6 +37,17 @@ public:
|
||||||
|
|
||||||
/** Convert B time to A time (A from B) */
|
/** Convert B time to A time (A from B) */
|
||||||
virtual A from(B b) const = 0;
|
virtual A from(B b) const = 0;
|
||||||
|
|
||||||
|
B origin_b () const {
|
||||||
|
return _origin_b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_origin_b (B o) {
|
||||||
|
_origin_b = o;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
B _origin_b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1145,7 +1145,10 @@ ControlList::cut (iterator start, iterator end)
|
||||||
return nal;
|
return nal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param op 0 = cut, 1 = copy, 2 = clear */
|
/** @param start Start position in model coordinates.
|
||||||
|
* @param end End position in model coordinates.
|
||||||
|
* @param op 0 = cut, 1 = copy, 2 = clear.
|
||||||
|
*/
|
||||||
boost::shared_ptr<ControlList>
|
boost::shared_ptr<ControlList>
|
||||||
ControlList::cut_copy_clear (double start, double end, int op)
|
ControlList::cut_copy_clear (double start, double end, int op)
|
||||||
{
|
{
|
||||||
|
|
@ -1247,9 +1250,10 @@ ControlList::copy (double start, double end)
|
||||||
void
|
void
|
||||||
ControlList::clear (double start, double end)
|
ControlList::clear (double start, double end)
|
||||||
{
|
{
|
||||||
(void) cut_copy_clear (start, end, 2);
|
cut_copy_clear (start, end, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param pos Position in model coordinates */
|
||||||
bool
|
bool
|
||||||
ControlList::paste (ControlList& alist, double pos, float /*times*/)
|
ControlList::paste (ControlList& alist, double pos, float /*times*/)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue