significant overhaul of automation region/lines to update during tempo map drags etc
This commit is contained in:
parent
e2c5a0777b
commit
a928e35efb
|
@ -91,6 +91,14 @@ AutomationLine::AutomationLine (const string& name,
|
|||
const ParameterDescriptor& desc)
|
||||
: trackview (tv)
|
||||
, _name (name)
|
||||
, _height (0)
|
||||
, _visible (Line)
|
||||
, terminal_points_can_slide (true)
|
||||
, update_pending (false)
|
||||
, have_reset_timeout (false)
|
||||
, have_redisplay_timeout (false)
|
||||
, no_draw (false)
|
||||
, _is_boolean (false)
|
||||
, alist (al)
|
||||
, _parent_group (parent)
|
||||
, _offset (0)
|
||||
|
@ -98,15 +106,6 @@ AutomationLine::AutomationLine (const string& name,
|
|||
, _fill (false)
|
||||
, _desc (desc)
|
||||
{
|
||||
_visible = Line;
|
||||
|
||||
update_pending = false;
|
||||
have_timeout = false;
|
||||
no_draw = false;
|
||||
_is_boolean = false;
|
||||
terminal_points_can_slide = true;
|
||||
_height = 0;
|
||||
|
||||
group = new ArdourCanvas::Container (&parent, ArdourCanvas::Duple(0, 1.5));
|
||||
CANVAS_DEBUG_NAME (group, "region gain envelope group");
|
||||
|
||||
|
@ -258,7 +257,7 @@ AutomationLine::set_height (guint32 h)
|
|||
} else {
|
||||
line->set_fill_y1 (0);
|
||||
}
|
||||
reset ();
|
||||
redisplay (true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,8 +410,7 @@ AutomationLine::string_to_fraction (string const & s) const
|
|||
default:
|
||||
break;
|
||||
}
|
||||
model_to_view_coord_y (v);
|
||||
return v;
|
||||
return model_to_view_coord_y (v);
|
||||
}
|
||||
|
||||
/** Start dragging a single point, possibly adding others if the supplied point is selected and there
|
||||
|
@ -554,7 +552,7 @@ AutomationLine::ContiguousControlPoints::move (double dx, double dvalue)
|
|||
double view_y = 1.0 - (*i)->get_y() / line.height();
|
||||
line.view_to_model_coord_y (view_y);
|
||||
line.apply_delta (view_y, dvalue);
|
||||
line.model_to_view_coord_y (view_y);
|
||||
view_y = line.model_to_view_coord_y (view_y);
|
||||
view_y = (1.0 - view_y) * line.height();
|
||||
|
||||
(*i)->move_to ((*i)->get_x() + dx, view_y, ControlPoint::Full);
|
||||
|
@ -782,7 +780,7 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp)
|
|||
/* convert to absolute time on timeline */
|
||||
const timepos_t absolute_time = model_time + get_origin();
|
||||
|
||||
/* now convert it back to match the view_x (RegioView pixel pos) */
|
||||
/* now convert it back to match the view_x (RegionView pixel pos) */
|
||||
const double model_x = trackview.editor().time_to_pixel_unrounded (absolute_time.earlier (_offset).earlier (get_origin ()));
|
||||
|
||||
if (view_x != model_x) {
|
||||
|
@ -811,7 +809,7 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp)
|
|||
alist->modify (cp.model(), model_time, view_y);
|
||||
|
||||
/* convert back from model to view y for clamping position (for integer/boolean/etc) */
|
||||
model_to_view_coord_y (view_y);
|
||||
view_y = model_to_view_coord_y (view_y);
|
||||
const double point_y = _height - (view_y * _height);
|
||||
if (point_y != cp.get_y()) {
|
||||
cp.move_to (cp.get_x(), point_y, ControlPoint::Full);
|
||||
|
@ -968,6 +966,105 @@ AutomationLine::list_changed ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::tempo_map_changed ()
|
||||
{
|
||||
if (alist->time_domain() != Temporal::BeatTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
redisplay (true, false);
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::redisplay (bool view_only, bool with_y)
|
||||
{
|
||||
have_redisplay_timeout = false;
|
||||
|
||||
if (view_only) {
|
||||
|
||||
|
||||
for (std::vector<ControlPoint *>::iterator i = control_points.begin(); i != control_points.end(); i++) {
|
||||
|
||||
AutomationList::iterator ai ((*i)->model());
|
||||
|
||||
/* drop points outside our range */
|
||||
|
||||
if (((*ai)->when < _offset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*ai)->when >= _maximum_time) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* we do not need to recompute the y coordinate here */
|
||||
|
||||
double ty;
|
||||
timecnt_t tx;
|
||||
|
||||
if (!with_y) {
|
||||
|
||||
/* re-use existing y-coordinate */
|
||||
|
||||
ty = (*i)->get_y();
|
||||
|
||||
} else {
|
||||
|
||||
/* convert to absolute position */
|
||||
|
||||
ty = model_to_view_coord_y ((*ai)->value);
|
||||
|
||||
if (isnan_local (ty)) {
|
||||
warning << string_compose (_("Ignoring illegal points on AutomationLine \"%1\""),
|
||||
_name) << endmsg;
|
||||
continue;
|
||||
}
|
||||
|
||||
ty = _height - (ty * _height);
|
||||
}
|
||||
|
||||
/* tx is currently the distance of this point from
|
||||
* _offset, which may be either:
|
||||
*
|
||||
* a) zero, for an automation line not connected to a
|
||||
* region
|
||||
*
|
||||
* b) some non-zero value, corresponding to the start
|
||||
* of the region within its source(s). Remember that
|
||||
* this start is an offset within the source, not a
|
||||
* position on the timeline.
|
||||
*
|
||||
* We need to convert tx to a global position, and to
|
||||
* do that we need to measure the distance from the
|
||||
* result of get_origin(), which tells ut the timeline
|
||||
* position of _offset
|
||||
*/
|
||||
|
||||
tx = model_to_view_coord_x ((*ai)->when);
|
||||
|
||||
/* convert x-coordinate to a canvas unit coordinate (this takes
|
||||
* zoom and scroll into account).
|
||||
*/
|
||||
|
||||
double px = trackview.editor().duration_to_pixels_unrounded (tx);
|
||||
|
||||
(*i)->move_to (px, ty);
|
||||
|
||||
reset_line_coords (**i);
|
||||
|
||||
}
|
||||
|
||||
if (line_points.size() > 1) {
|
||||
line->set_steps (line_points, is_stepped());
|
||||
}
|
||||
|
||||
} else {
|
||||
reset ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::reset_callback (const Evoral::ControlList& events)
|
||||
{
|
||||
|
@ -997,11 +1094,17 @@ AutomationLine::reset_callback (const Evoral::ControlList& events)
|
|||
|
||||
for (AutomationList::iterator ai = e.begin(); ai != e.end(); ++ai, ++pi) {
|
||||
|
||||
double ty = (*ai)->value;
|
||||
/* drop points outside our range */
|
||||
|
||||
/* convert from model coordinates to canonical view coordinates */
|
||||
if (((*ai)->when < _offset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
timepos_t tx = model_to_view_coord (**ai, ty);
|
||||
if ((*ai)->when >= _maximum_time) {
|
||||
break;
|
||||
}
|
||||
|
||||
double ty = model_to_view_coord_y ((*ai)->value);
|
||||
|
||||
if (isnan_local (ty)) {
|
||||
warning << string_compose (_("Ignoring illegal points on AutomationLine \"%1\""),
|
||||
|
@ -1009,21 +1112,22 @@ AutomationLine::reset_callback (const Evoral::ControlList& events)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (tx >= timepos_t::max (tx.time_domain()) || tx.is_negative () || tx >= _maximum_time) {
|
||||
continue;
|
||||
}
|
||||
ty = _height - (ty * _height);
|
||||
|
||||
/* convert from model coordinates to canonical view coordinates */
|
||||
|
||||
timecnt_t tx = model_to_view_coord_x ((*ai)->when);
|
||||
|
||||
/* convert x-coordinate to a canvas unit coordinate (this takes
|
||||
* zoom and scroll into account).
|
||||
*/
|
||||
|
||||
double px = trackview.editor().time_to_pixel_unrounded (tx);
|
||||
double px = trackview.editor().duration_to_pixels_unrounded (tx);
|
||||
|
||||
/* convert from canonical view height (0..1.0) to actual
|
||||
* height coordinates (using X11's top-left rooted system)
|
||||
*/
|
||||
|
||||
ty = _height - (ty * _height);
|
||||
|
||||
add_visible_control_point (vp, pi, px, ty, ai, np);
|
||||
|
||||
|
@ -1072,7 +1176,7 @@ AutomationLine::reset ()
|
|||
{
|
||||
DEBUG_TRACE (DEBUG::Automation, "\t\tLINE RESET\n");
|
||||
update_pending = false;
|
||||
have_timeout = false;
|
||||
have_reset_timeout = false;
|
||||
|
||||
if (no_draw) {
|
||||
return;
|
||||
|
@ -1097,10 +1201,10 @@ AutomationLine::queue_reset ()
|
|||
if (trackview.editor().session()->transport_rolling() && alist->automation_write()) {
|
||||
/* automation write pass ... defer to a timeout */
|
||||
/* redraw in 1/4 second */
|
||||
if (!have_timeout) {
|
||||
if (!have_reset_timeout) {
|
||||
DEBUG_TRACE (DEBUG::Automation, "\tqueue timeout\n");
|
||||
Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (*this, &AutomationLine::reset), false), 250);
|
||||
have_timeout = true;
|
||||
have_reset_timeout = true;
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::Automation, "\ttimeout already queued, change ignored\n");
|
||||
}
|
||||
|
@ -1109,6 +1213,26 @@ AutomationLine::queue_reset ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::queue_redisplay (bool for_height)
|
||||
{
|
||||
/* this must be called from the GUI thread */
|
||||
|
||||
if (trackview.editor().session()->transport_rolling() && alist->automation_write()) {
|
||||
/* automation write pass ... defer to a timeout */
|
||||
/* redraw in 1/4 second */
|
||||
if (!have_redisplay_timeout) {
|
||||
DEBUG_TRACE (DEBUG::Automation, "\tqueue timeout\n");
|
||||
Glib::signal_timeout().connect (sigc::bind_return (sigc::bind (sigc::mem_fun (*this, &AutomationLine::redisplay), true, for_height), true), 250);
|
||||
have_redisplay_timeout = true;
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::Automation, "\ttimeout already queued, change ignored\n");
|
||||
}
|
||||
} else {
|
||||
redisplay (true, for_height);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::clear ()
|
||||
{
|
||||
|
@ -1229,8 +1353,8 @@ AutomationLine::apply_delta (double& val, double delta) const
|
|||
val = _desc.apply_delta (val, delta);
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::model_to_view_coord_y (double& y) const
|
||||
double
|
||||
AutomationLine::model_to_view_coord_y (double y) const
|
||||
{
|
||||
if (alist->default_interpolation () != alist->interpolation()) {
|
||||
switch (alist->interpolation()) {
|
||||
|
@ -1239,8 +1363,7 @@ AutomationLine::model_to_view_coord_y (double& y) const
|
|||
assert (alist->default_interpolation () == AutomationList::Linear);
|
||||
break;
|
||||
case AutomationList::Linear:
|
||||
y = (y - _desc.lower) / (_desc.upper - _desc.lower);
|
||||
return;
|
||||
return (y - _desc.lower) / (_desc.upper - _desc.lower);
|
||||
default:
|
||||
/* types that default to linear, can't be use
|
||||
* Logarithmic or Exponential interpolation.
|
||||
|
@ -1250,15 +1373,22 @@ AutomationLine::model_to_view_coord_y (double& y) const
|
|||
break;
|
||||
}
|
||||
}
|
||||
y = _desc.to_interface (y);
|
||||
return _desc.to_interface (y);
|
||||
}
|
||||
|
||||
timepos_t
|
||||
AutomationLine::model_to_view_coord (Evoral::ControlEvent const & ev, double& y) const
|
||||
timecnt_t
|
||||
AutomationLine::model_to_view_coord_x (timepos_t const & when) const
|
||||
{
|
||||
Temporal::timepos_t w (ev.when);
|
||||
model_to_view_coord_y (y);
|
||||
return (w).earlier (_offset);
|
||||
/* @param when is a distance (with implicit origin) from the start of the
|
||||
* source. So we subtract the offset (from the region if this is
|
||||
* related to a region; zero otherwise) to get the distance (again,
|
||||
* implicit origin) from the start of the line.
|
||||
*
|
||||
* Then we construct a timecnt_t from this duration, and the origin of
|
||||
* the line on the timeline.
|
||||
*/
|
||||
|
||||
return timecnt_t (when.earlier (_offset), get_origin());
|
||||
}
|
||||
|
||||
/** Called when our list has announced that its interpolation style has changed */
|
||||
|
@ -1374,10 +1504,6 @@ AutomationLine::session_position (timepos_t const & when) const
|
|||
void
|
||||
AutomationLine::set_offset (timepos_t const & off)
|
||||
{
|
||||
if (_offset == off) {
|
||||
return;
|
||||
}
|
||||
|
||||
_offset = off;
|
||||
reset ();
|
||||
}
|
||||
|
|
|
@ -76,7 +76,9 @@ public:
|
|||
|
||||
virtual Temporal::timepos_t get_origin () const;
|
||||
|
||||
void redisplay (bool view_only, bool with_y);
|
||||
void queue_reset ();
|
||||
void queue_redisplay (bool for_height);
|
||||
void reset ();
|
||||
void clear ();
|
||||
void set_fill (bool f) { _fill = f; } // owner needs to call set_height
|
||||
|
@ -114,6 +116,7 @@ public:
|
|||
void set_height (guint32);
|
||||
|
||||
bool get_uses_gain_mapping () const;
|
||||
void tempo_map_changed ();
|
||||
|
||||
TimeAxisView& trackview;
|
||||
|
||||
|
@ -126,9 +129,11 @@ public:
|
|||
std::string fraction_to_string (double) const;
|
||||
std::string delta_to_string (double) const;
|
||||
double string_to_fraction (std::string const &) const;
|
||||
|
||||
void view_to_model_coord_y (double &) const;
|
||||
Temporal::timepos_t model_to_view_coord (Evoral::ControlEvent const &, double& y) const;
|
||||
void model_to_view_coord_y (double &) const;
|
||||
|
||||
double model_to_view_coord_y (double) const;
|
||||
Temporal::timecnt_t model_to_view_coord_x (Temporal::timepos_t const &) const;
|
||||
|
||||
double compute_delta (double from, double to) const;
|
||||
void apply_delta (double& val, double delta) const;
|
||||
|
@ -175,7 +180,8 @@ protected:
|
|||
|
||||
bool terminal_points_can_slide;
|
||||
bool update_pending;
|
||||
bool have_timeout;
|
||||
bool have_reset_timeout;
|
||||
bool have_redisplay_timeout;
|
||||
bool no_draw;
|
||||
bool _is_boolean;
|
||||
/** true if we did a push at any point during the current drag */
|
||||
|
|
|
@ -103,6 +103,7 @@ AutomationRegionView::create_line (boost::shared_ptr<ARDOUR::AutomationList> lis
|
|||
_line->set_height ((uint32_t)rint(trackview.current_height() - 2.5 - NAME_HIGHLIGHT_SIZE));
|
||||
_line->set_visibility (AutomationLine::VisibleAspects (AutomationLine::Line|AutomationLine::ControlPoints));
|
||||
_line->set_maximum_time (timepos_t (_region->length()));
|
||||
std::cerr << "Set line offset to " << _region->start() << std::endl;
|
||||
_line->set_offset (_region->start ());
|
||||
}
|
||||
|
||||
|
@ -291,11 +292,10 @@ AutomationRegionView::reset_width_dependent_items (double pixel_width)
|
|||
RegionView::reset_width_dependent_items(pixel_width);
|
||||
|
||||
if (_line) {
|
||||
_line->reset();
|
||||
_line->reset ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AutomationRegionView::region_resized (const PBD::PropertyChange& what_changed)
|
||||
{
|
||||
|
@ -314,6 +314,16 @@ AutomationRegionView::region_resized (const PBD::PropertyChange& what_changed)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutomationRegionView::tempo_map_changed ()
|
||||
{
|
||||
if (_line) {
|
||||
_line->tempo_map_changed ();
|
||||
}
|
||||
|
||||
set_position (_region->position(), 0, 0);
|
||||
set_duration (_region->length(), 0);
|
||||
}
|
||||
|
||||
void
|
||||
AutomationRegionView::entered ()
|
||||
|
|
|
@ -68,6 +68,8 @@ public:
|
|||
void set_height (double);
|
||||
void reset_width_dependent_items(double pixel_width);
|
||||
|
||||
void tempo_map_changed ();
|
||||
|
||||
protected:
|
||||
void create_line(boost::shared_ptr<ARDOUR::AutomationList> list);
|
||||
bool set_position(Temporal::timepos_t const & pos, void* src, double* ignored);
|
||||
|
|
|
@ -1176,7 +1176,7 @@ AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& sel
|
|||
for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
|
||||
timepos_t when = (*x)->when;
|
||||
double val = (*x)->value;
|
||||
line.model_to_view_coord (**x, val);
|
||||
line.model_to_view_coord_y (val);
|
||||
(*x)->when = when;
|
||||
(*x)->value = val;
|
||||
}
|
||||
|
|
|
@ -97,6 +97,8 @@ public:
|
|||
/** @return All AutomationLines associated with this view */
|
||||
std::list<boost::shared_ptr<AutomationLine> > lines () const;
|
||||
|
||||
AutomationStreamView* automation_view() const { return _view; }
|
||||
|
||||
void set_selected_points (PointSelection&);
|
||||
void get_selectables (Temporal::timepos_t const &, Temporal::timepos_t const &, double top, double bot, std::list<Selectable *>&, bool within = false);
|
||||
void get_inverted_selectables (Selection&, std::list<Selectable*>& results);
|
||||
|
|
|
@ -133,7 +133,13 @@ void
|
|||
ControlPoint::set_size (double sz)
|
||||
{
|
||||
_size = sz;
|
||||
move_to (_x, _y, _shape);
|
||||
move_to (_x, _y);
|
||||
}
|
||||
|
||||
void
|
||||
ControlPoint::move_to (double x, double y)
|
||||
{
|
||||
move_to (x, y, _shape);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
End
|
||||
};
|
||||
|
||||
void move_to (double x, double y);
|
||||
void move_to (double x, double y, ShapeType);
|
||||
void reset (double x, double y, ARDOUR::AutomationList::iterator, uint32_t, ShapeType);
|
||||
double get_x() const { return _x; }
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "canvas/item.h"
|
||||
#include "canvas/line_set.h"
|
||||
|
||||
#include "automation_streamview.h"
|
||||
#include "bbt_marker_dialog.h"
|
||||
#include "editor.h"
|
||||
#include "marker.h"
|
||||
|
@ -899,21 +900,32 @@ Editor::mid_tempo_per_track_update (TimeAxisView& tav)
|
|||
{
|
||||
MidiTimeAxisView* mtav = dynamic_cast<MidiTimeAxisView*> (&tav);
|
||||
|
||||
if (!mtav) {
|
||||
return;
|
||||
if (mtav) {
|
||||
MidiStreamView* msv = mtav->midi_view();
|
||||
|
||||
if (msv) {
|
||||
msv->foreach_regionview (sigc::mem_fun (*this, &Editor::mid_tempo_per_region_update));
|
||||
}
|
||||
|
||||
TimeAxisView::Children kids (tav.get_child_list());
|
||||
|
||||
for (TimeAxisView::Children::iterator ct = kids.begin(); ct != kids.end(); ++ct) {
|
||||
|
||||
boost::shared_ptr<AutomationTimeAxisView> atav = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*ct);
|
||||
|
||||
if (atav) {
|
||||
AutomationStreamView* asv = atav->automation_view ();
|
||||
|
||||
if (asv) {
|
||||
asv->foreach_regionview (sigc::mem_fun (*this, &Editor::mid_tempo_per_region_update));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MidiStreamView* msv = mtav->midi_view();
|
||||
|
||||
if (!msv) {
|
||||
return;
|
||||
}
|
||||
|
||||
msv->foreach_regionview (sigc::mem_fun (*this, &Editor::mid_tempo_per_region_update));
|
||||
}
|
||||
|
||||
void
|
||||
Editor::mid_tempo_per_region_update (RegionView* rv)
|
||||
{
|
||||
rv->redisplay (true);
|
||||
rv->tempo_map_changed ();
|
||||
}
|
||||
|
|
|
@ -106,6 +106,10 @@ public:
|
|||
_redisplay (view_only);
|
||||
}
|
||||
|
||||
virtual void tempo_map_changed () {
|
||||
_redisplay (true);
|
||||
}
|
||||
|
||||
struct DisplaySuspender {
|
||||
DisplaySuspender (RegionView& rv, bool just_view = false) : region_view (rv), view_only (just_view) {
|
||||
region_view.disable_display ();
|
||||
|
|
Loading…
Reference in New Issue