forward port automation handling changes from 2.x, upto and including about rev 6981 (will need full testing in the 3.X context). as on 2.x, this removes real-time visual updates to automation curves during write/touch automation recording

git-svn-id: svn://localhost/ardour2/branches/3.0@7653 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis
2010-08-19 21:09:40 +00:00
parent b6642d14ca
commit 7b6b75f38f
37 changed files with 429 additions and 281 deletions

View File

@@ -45,7 +45,6 @@ ControlList::ControlList (const Parameter& id)
_max_yval = id.max();
_max_xval = 0; // means "no limit"
_default_value = 0;
_rt_insertion_point = _events.end();
_lookup_cache.left = -1;
_lookup_cache.range.first = _events.end();
_search_cache.left = -1;
@@ -64,7 +63,6 @@ ControlList::ControlList (const ControlList& other)
_max_yval = other._max_yval;
_max_xval = other._max_xval;
_default_value = other._default_value;
_rt_insertion_point = _events.end();
_lookup_cache.range.first = _events.end();
_search_cache.first = _events.end();
_sort_pending = false;
@@ -87,7 +85,6 @@ ControlList::ControlList (const ControlList& other, double start, double end)
_max_yval = other._max_yval;
_max_xval = other._max_xval;
_default_value = other._default_value;
_rt_insertion_point = _events.end();
_lookup_cache.range.first = _events.end();
_search_cache.first = _events.end();
_sort_pending = false;
@@ -110,6 +107,13 @@ ControlList::~ControlList()
for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
delete (*x);
}
for (list<NascentInfo*>::iterator n = nascent.begin(); n != nascent.end(); ++n) {
for (EventList::iterator x = (*n)->events.begin(); x != (*n)->events.end(); ++x) {
delete *x;
}
delete (*n);
}
delete _curve;
}
@@ -203,7 +207,8 @@ ControlList::extend_to (double when)
return true;
}
void ControlList::_x_scale (double factor)
void
ControlList::_x_scale (double factor)
{
for (iterator i = _events.begin(); i != _events.end(); ++i) {
(*i)->when = floor ((*i)->when * factor);
@@ -213,90 +218,165 @@ void ControlList::_x_scale (double factor)
}
void
ControlList::reposition_for_rt_add (double /*when*/)
ControlList::write_pass_finished (double when)
{
_rt_insertion_point = _events.end();
merge_nascent (when);
}
void
ControlList::merge_nascent (double when)
{
{
Glib::Mutex::Lock lm (_lock);
if (nascent.empty()) {
return;
}
for (list<NascentInfo*>::iterator n = nascent.begin(); n != nascent.end(); ++n) {
NascentInfo* ninfo = *n;
EventList& nascent_events (ninfo->events);
bool need_adjacent_start_clamp;
bool need_adjacent_end_clamp;
if (nascent_events.empty()) {
delete ninfo;
continue;
}
if (ninfo->start_time < 0.0) {
ninfo->start_time = nascent_events.front()->when;
}
if (ninfo->end_time < 0.0) {
ninfo->end_time = when;
}
bool preexisting = !_events.empty();
if (!preexisting) {
_events = nascent_events;
} else if (ninfo->end_time < _events.front()->when) {
/* all points in nascent are before the first existing point */
_events.insert (_events.begin(), nascent_events.begin(), nascent_events.end());
} else if (ninfo->start_time > _events.back()->when) {
/* all points in nascent are after the last existing point */
_events.insert (_events.end(), nascent_events.begin(), nascent_events.end());
} else {
/* find the range that overaps with nascent events,
and insert the contents of nascent events.
*/
iterator i;
iterator range_begin = _events.end();
iterator range_end = _events.end();
double end_value = unlocked_eval (ninfo->end_time);
double start_value = unlocked_eval (ninfo->start_time - 1);
need_adjacent_end_clamp = true;
need_adjacent_start_clamp = true;
for (i = _events.begin(); i != _events.end(); ++i) {
if ((*i)->when == ninfo->start_time) {
/* existing point at same time, remove it
and the consider the next point instead.
*/
i = _events.erase (i);
if (i == _events.end()) {
break;
}
if (range_begin == _events.end()) {
range_begin = i;
need_adjacent_start_clamp = false;
} else {
need_adjacent_end_clamp = false;
}
if ((*i)->when > ninfo->end_time) {
range_end = i;
break;
}
} else if ((*i)->when > ninfo->start_time) {
if (range_begin == _events.end()) {
range_begin = i;
}
if ((*i)->when > ninfo->end_time) {
range_end = i;
break;
}
}
}
assert (range_begin != _events.end());
if (range_begin != _events.begin()) {
/* clamp point before */
if (need_adjacent_start_clamp) {
_events.insert (range_begin, new ControlEvent (ninfo->start_time, start_value));
}
}
_events.insert (range_begin, nascent_events.begin(), nascent_events.end());
if (range_end != _events.end()) {
/* clamp point after */
if (need_adjacent_end_clamp) {
_events.insert (range_begin, new ControlEvent (ninfo->end_time, end_value));
}
}
_events.erase (range_begin, range_end);
}
delete ninfo;
}
nascent.clear ();
if (writing()) {
nascent.push_back (new NascentInfo (false));
}
}
maybe_signal_changed ();
}
void
ControlList::rt_add (double when, double value)
{
// this is for automation recording
if (touch_enabled() && !touching()) {
return;
}
//cerr << "RT: alist " << this << " add " << value << " @ " << when << endl;
{
Glib::Mutex::Lock lm (_lock);
Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK);
iterator where;
ControlEvent cp (when, 0.0);
bool done = false;
if ((_rt_insertion_point != _events.end()) && ((*_rt_insertion_point)->when < when) ) {
/* we have a previous insertion point, so we should delete
everything between it and the position where we are going
to insert this point.
*/
iterator after = _rt_insertion_point;
if (++after != _events.end()) {
iterator far = after;
while (far != _events.end()) {
if ((*far)->when > when) {
break;
}
++far;
}
if (_new_value) {
where = far;
_rt_insertion_point = where;
if ((*where)->when == when) {
(*where)->value = value;
done = true;
}
} else {
where = _events.erase (after, far);
}
} else {
where = after;
}
iterator previous = _rt_insertion_point;
--previous;
if (_rt_insertion_point != _events.begin() && (*_rt_insertion_point)->value == value && (*previous)->value == value) {
(*_rt_insertion_point)->when = when;
done = true;
}
} else {
where = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
if (where != _events.end()) {
if ((*where)->when == when) {
(*where)->value = value;
done = true;
}
}
}
if (!done) {
_rt_insertion_point = _events.insert (where, new ControlEvent (when, value));
}
_new_value = false;
mark_dirty ();
}
maybe_signal_changed ();
if (lm.locked()) {
assert (!nascent.empty());
if (!nascent.back()->events.empty()) {
assert (when > nascent.back()->events.back()->when);
}
nascent.back()->events.push_back (new ControlEvent (when, value));
}
}
void
@@ -336,7 +416,6 @@ ControlList::add (double when, double value)
if (insert) {
_events.insert (insertion_point, new ControlEvent (when, value));
reposition_for_rt_add (0);
}
@@ -352,7 +431,6 @@ ControlList::erase (iterator i)
{
Glib::Mutex::Lock lm (_lock);
_events.erase (i);
reposition_for_rt_add (0);
mark_dirty ();
}
maybe_signal_changed ();
@@ -364,7 +442,6 @@ ControlList::erase (iterator start, iterator end)
{
Glib::Mutex::Lock lm (_lock);
_events.erase (start, end);
reposition_for_rt_add (0);
mark_dirty ();
}
maybe_signal_changed ();
@@ -411,7 +488,6 @@ ControlList::erase_range (double start, double endt)
erased = erase_range_internal (start, endt, _events);
if (erased) {
reposition_for_rt_add (0);
mark_dirty ();
}
@@ -662,7 +738,6 @@ ControlList::truncate_end (double last_coordinate)
_events.back()->value = last_val;
}
reposition_for_rt_add (0);
mark_dirty();
}
@@ -762,8 +837,6 @@ ControlList::truncate_start (double overall_length)
_events.push_front (new ControlEvent (0, first_legal_value));
}
reposition_for_rt_add (0);
mark_dirty();
}
@@ -1115,35 +1188,6 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do
}
}
boost::shared_ptr<ControlList>
ControlList::cut (iterator start, iterator end)
{
boost::shared_ptr<ControlList> nal = create (_parameter);
{
Glib::Mutex::Lock lm (_lock);
for (iterator x = start; x != end; ) {
iterator tmp;
tmp = x;
++tmp;
nal->_events.push_back (new ControlEvent (**x));
_events.erase (x);
reposition_for_rt_add (0);
x = tmp;
}
mark_dirty ();
}
maybe_signal_changed ();
return nal;
}
/** @param start Start position in model coordinates.
* @param end End position in model coordinates.
@@ -1153,15 +1197,16 @@ boost::shared_ptr<ControlList>
ControlList::cut_copy_clear (double start, double end, int op)
{
boost::shared_ptr<ControlList> nal = create (_parameter);
iterator s, e;
bool changed = false;
ControlEvent cp (start, 0.0);
{
Glib::Mutex::Lock lm (_lock);
Glib::Mutex::Lock lm (_lock);
/* first, determine s & e, two iterators that define the range of points
affected by this operation
*/
/* find the first event in our list that is at or before `start' in time */
ControlEvent cp (start, 0.0);
if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
return nal;
}
@@ -1170,71 +1215,80 @@ ControlList::cut_copy_clear (double start, double end, int op)
cp.when = end;
e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
if (op != 2 && (*s)->when != start) {
nal->_events.push_back (new ControlEvent (0, unlocked_eval (start)));
}
/* if "start" isn't the location of an existing point,
evaluate the curve to get a value for the start. Add a point to
both the existing event list, and if its not a "clear" operation,
to the copy ("nal") as well.
Note that the time positions of the points in each list are different
because we want the copy ("nal") to have a zero time reference.
*/
/* before we begin any cut/clear operations, get the value of the curve
at "end".
*/
double end_value = unlocked_eval (end);
if ((*s)->when != start) {
double val = unlocked_eval (start);
if (op == 0) { // cut
if (start > _events.front()->when) {
_events.insert (s, (new ControlEvent (start, val)));
}
}
if (op != 2) { // ! clear
nal->_events.push_back (new ControlEvent (0, val));
}
}
for (iterator x = s; x != e; ) {
iterator tmp = x;
++tmp;
changed = true;
/* adjust new points to be relative to start, which
has been set to zero.
*/
if (op != 2) {
nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
}
if (op != 1) {
_events.erase (x);
}
x = _events.erase (x);
} else {
++x;
}
}
if (e == _events.end() || (*e)->when != end) {
x = tmp;
/* only add a boundary point if there is a point after "end"
*/
if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut
_events.insert (e, new ControlEvent (end, end_value));
}
if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
nal->_events.push_back (new ControlEvent (end - start, end_value));
}
}
if (op != 2 && nal->_events.back()->when != end - start) {
nal->_events.push_back (new ControlEvent (end - start, unlocked_eval (end)));
}
if (changed) {
reposition_for_rt_add (0);
}
mark_dirty ();
mark_dirty ();
}
maybe_signal_changed ();
return nal;
}
boost::shared_ptr<ControlList>
ControlList::copy (iterator start, iterator end)
{
boost::shared_ptr<ControlList> nal = create (_parameter);
{
Glib::Mutex::Lock lm (_lock);
for (iterator x = start; x != end; ) {
iterator tmp;
tmp = x;
++tmp;
nal->_events.push_back (new ControlEvent (**x));
x = tmp;
}
}
if (op != 1) {
maybe_signal_changed ();
}
return nal;
}
boost::shared_ptr<ControlList>
ControlList::cut (double start, double end)
{
@@ -1293,7 +1347,6 @@ ControlList::paste (ControlList& alist, double pos, float /*times*/)
}
}
reposition_for_rt_add (0);
mark_dirty ();
}
@@ -1342,7 +1395,6 @@ ControlList::move_ranges (const list< RangeMove<double> >& movements)
_sort_pending = true;
}
reposition_for_rt_add (0);
mark_dirty ();
}