Fix some workflow problems wrt automation.
[ardour.git] / libs / evoral / src / ControlList.cpp
1 /* This file is part of Evoral.
2  * Copyright (C) 2008 David Robillard <http://drobilla.net>
3  * Copyright (C) 2000-2008 Paul Davis
4  *
5  * Evoral is free software; you can redistribute it and/or modify it under the
6  * terms of the GNU General Public License as published by the Free Software
7  * Foundation; either version 2 of the License, or (at your option) any later
8  * version.
9  *
10  * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include <cmath>
20
21 #ifdef COMPILER_MSVC
22 #include <float.h>
23
24 // 'std::isnan()' is not available in MSVC.
25 #define isnan_local(val) (bool)_isnan((double)val)
26 #else
27 #define isnan_local std::isnan
28 #endif
29
30 #include <cassert>
31 #include <cmath>
32 #include <iostream>
33 #include <utility>
34
35 #include "evoral/ControlList.hpp"
36 #include "evoral/Curve.hpp"
37 #include "evoral/ParameterDescriptor.hpp"
38 #include "evoral/TypeMap.hpp"
39
40 #include "pbd/compose.h"
41 #include "pbd/debug.h"
42
43 using namespace std;
44 using namespace PBD;
45
46 namespace Evoral {
47
48 inline bool event_time_less_than (ControlEvent* a, ControlEvent* b)
49 {
50         return a->when < b->when;
51 }
52
53 ControlList::ControlList (const Parameter& id, const ParameterDescriptor& desc)
54         : _parameter(id)
55         , _desc(desc)
56         , _curve(0)
57 {
58         _interpolation = desc.toggled ? Discrete : Linear;
59         _frozen = 0;
60         _changed_when_thawed = false;
61         _min_yval = desc.lower;
62         _max_yval = desc.upper;
63         _default_value = desc.normal;
64         _lookup_cache.left = -1;
65         _lookup_cache.range.first = _events.end();
66         _lookup_cache.range.second = _events.end();
67         _search_cache.left = -1;
68         _search_cache.first = _events.end();
69         _sort_pending = false;
70         new_write_pass = true;
71         _in_write_pass = false;
72         did_write_during_pass = false;
73         insert_position = -1;
74         most_recent_insert_iterator = _events.end();
75 }
76
77 ControlList::ControlList (const ControlList& other)
78         : _parameter(other._parameter)
79         , _desc(other._desc)
80         , _interpolation(other._interpolation)
81         , _curve(0)
82 {
83         _frozen = 0;
84         _changed_when_thawed = false;
85         _min_yval = other._min_yval;
86         _max_yval = other._max_yval;
87         _default_value = other._default_value;
88         _lookup_cache.range.first = _events.end();
89         _lookup_cache.range.second = _events.end();
90         _search_cache.first = _events.end();
91         _sort_pending = false;
92         new_write_pass = true;
93         _in_write_pass = false;
94         did_write_during_pass = false;
95         insert_position = -1;
96         most_recent_insert_iterator = _events.end();
97
98         copy_events (other);
99
100         mark_dirty ();
101 }
102
103 ControlList::ControlList (const ControlList& other, double start, double end)
104         : _parameter(other._parameter)
105         , _desc(other._desc)
106         , _interpolation(other._interpolation)
107         , _curve(0)
108 {
109         _frozen = 0;
110         _changed_when_thawed = false;
111         _min_yval = other._min_yval;
112         _max_yval = other._max_yval;
113         _default_value = other._default_value;
114         _lookup_cache.range.first = _events.end();
115         _lookup_cache.range.second = _events.end();
116         _search_cache.first = _events.end();
117         _sort_pending = false;
118
119         /* now grab the relevant points, and shift them back if necessary */
120
121         boost::shared_ptr<ControlList> section = const_cast<ControlList*>(&other)->copy (start, end);
122
123         if (!section->empty()) {
124                 copy_events (*(section.get()));
125         }
126
127         new_write_pass = false;
128         _in_write_pass = false;
129         did_write_during_pass = false;
130         insert_position = -1;
131         most_recent_insert_iterator = _events.end();
132
133         mark_dirty ();
134 }
135
136 ControlList::~ControlList()
137 {
138         for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
139                 delete (*x);
140         }
141
142         delete _curve;
143 }
144
145 boost::shared_ptr<ControlList>
146 ControlList::create(const Parameter& id, const ParameterDescriptor& desc)
147 {
148         return boost::shared_ptr<ControlList>(new ControlList(id, desc));
149 }
150
151 bool
152 ControlList::operator== (const ControlList& other)
153 {
154         return _events == other._events;
155 }
156
157 ControlList&
158 ControlList::operator= (const ControlList& other)
159 {
160         if (this != &other) {
161
162                 _min_yval = other._min_yval;
163                 _max_yval = other._max_yval;
164
165
166                 _interpolation = other._interpolation;
167                 _default_value = other._default_value;
168                 
169                 copy_events (other);
170         }
171
172         return *this;
173 }
174
175 void
176 ControlList::copy_events (const ControlList& other)
177 {
178         {
179                 Glib::Threads::RWLock::WriterLock lm (_lock);
180                 _events.clear ();
181                 for (const_iterator i = other.begin(); i != other.end(); ++i) {
182                         _events.push_back (new ControlEvent ((*i)->when, (*i)->value));
183                 }
184                 unlocked_invalidate_insert_iterator ();
185                 mark_dirty ();
186         }
187         maybe_signal_changed ();
188 }
189
190 void
191 ControlList::create_curve()
192 {
193         _curve = new Curve(*this);
194 }
195
196 void
197 ControlList::destroy_curve()
198 {
199         delete _curve;
200         _curve = NULL;
201 }
202
203 void
204 ControlList::maybe_signal_changed ()
205 {
206         mark_dirty ();
207
208         if (_frozen) {
209                 _changed_when_thawed = true;
210         }
211 }
212
213 void
214 ControlList::clear ()
215 {
216         {
217                 Glib::Threads::RWLock::WriterLock lm (_lock);
218                 _events.clear ();
219                 unlocked_invalidate_insert_iterator ();
220                 mark_dirty ();
221         }
222
223         maybe_signal_changed ();
224 }
225
226 void
227 ControlList::x_scale (double factor)
228 {
229         Glib::Threads::RWLock::WriterLock lm (_lock);
230         _x_scale (factor);
231 }
232
233 bool
234 ControlList::extend_to (double when)
235 {
236         Glib::Threads::RWLock::WriterLock lm (_lock);
237         if (_events.empty() || _events.back()->when == when) {
238                 return false;
239         }
240         double factor = when / _events.back()->when;
241         _x_scale (factor);
242         return true;
243 }
244
245 void
246 ControlList::_x_scale (double factor)
247 {
248         for (iterator i = _events.begin(); i != _events.end(); ++i) {
249                 (*i)->when *= factor;
250         }
251
252         mark_dirty ();
253 }
254
255 struct ControlEventTimeComparator {
256         bool operator() (ControlEvent* a, ControlEvent* b) {
257                 return a->when < b->when;
258         }
259 };
260
261 void
262 ControlList::thin (double thinning_factor)
263 {
264         if (thinning_factor == 0.0 || _desc.toggled) {
265                 return;
266         }
267
268         bool changed = false;
269
270         {
271                 Glib::Threads::RWLock::WriterLock lm (_lock);
272                 
273                 ControlEvent* prevprev = 0;
274                 ControlEvent* cur = 0;
275                 ControlEvent* prev = 0;
276                 iterator pprev;
277                 int counter = 0;
278                 
279                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 thin from %2 events\n", this, _events.size()));
280                 
281                 for (iterator i = _events.begin(); i != _events.end(); ++i) {
282                         
283                         cur = *i;
284                         counter++;
285                         
286                         if (counter > 2) {
287                                 
288                                 /* compute the area of the triangle formed by 3 points
289                                  */
290                                 
291                                 double area = fabs ((prevprev->when * (prev->value - cur->value)) + 
292                                                     (prev->when * (cur->value - prevprev->value)) + 
293                                                     (cur->when * (prevprev->value - prev->value)));
294                                 
295                                 if (area < thinning_factor) {
296                                         iterator tmp = pprev;
297                                         
298                                         /* pprev will change to current
299                                            i is incremented to the next event
300                                            as we loop.
301                                         */
302                                         
303                                         pprev = i;
304                                         _events.erase (tmp);
305                                         changed = true;
306                                         continue;
307                                 }
308                         }
309                         
310                         prevprev = prev;
311                         prev = cur;
312                         pprev = i;
313                 }
314                 
315                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 thin => %2 events\n", this, _events.size()));
316
317                 if (changed) {
318                         unlocked_invalidate_insert_iterator ();
319                         mark_dirty ();
320                 }
321         }
322
323         if (changed) {
324                 maybe_signal_changed ();
325         }
326 }
327
328 void
329 ControlList::fast_simple_add (double when, double value)
330 {
331         Glib::Threads::RWLock::WriterLock lm (_lock);
332         /* to be used only for loading pre-sorted data from saved state */
333         _events.insert (_events.end(), new ControlEvent (when, value));
334
335         mark_dirty ();
336 }
337
338 void
339 ControlList::invalidate_insert_iterator ()
340 {
341         Glib::Threads::RWLock::WriterLock lm (_lock);
342         unlocked_invalidate_insert_iterator ();
343 }
344
345 void
346 ControlList::unlocked_invalidate_insert_iterator ()
347 {
348         most_recent_insert_iterator = _events.end();
349 }
350
351 void
352 ControlList::start_write_pass (double when)
353 {
354         Glib::Threads::RWLock::WriterLock lm (_lock);
355
356         DEBUG_TRACE (DEBUG::ControlList, string_compose ("%1: setup write pass @ %2\n", this, when));
357
358         new_write_pass = true;
359         did_write_during_pass = false;
360         insert_position = when;
361         
362         /* leave the insert iterator invalid, so that we will do the lookup
363            of where it should be in a "lazy" way - deferring it until
364            we actually add the first point (which may never happen).
365         */
366         
367         unlocked_invalidate_insert_iterator ();
368 }
369
370 void
371 ControlList::write_pass_finished (double /*when*/, double thinning_factor)
372 {
373         DEBUG_TRACE (DEBUG::ControlList, "write pass finished\n");
374
375         if (did_write_during_pass) {
376                 thin (thinning_factor);
377                 did_write_during_pass = false;
378         }
379         new_write_pass = true;
380         _in_write_pass = false;
381 }
382
383 void
384 ControlList::set_in_write_pass (bool yn, bool add_point, double when)
385 {       
386         DEBUG_TRACE (DEBUG::ControlList, string_compose ("now in write pass @ %1, add point ? %2\n", when, add_point));
387         
388         _in_write_pass = yn;
389
390         if (yn && add_point) {
391                 add_guard_point (when);
392         }
393 }
394
395 void
396 ControlList::add_guard_point (double when)
397 {
398         ControlEvent cp (when, 0.0);
399         most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
400
401         double eval_value = unlocked_eval (insert_position);
402
403         if (most_recent_insert_iterator == _events.end()) {
404                 
405                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert iterator at end, adding eval-value there %2\n", this, eval_value));
406                 _events.push_back (new ControlEvent (when, eval_value));
407                 /* leave insert iterator at the end */
408                 
409         } else if ((*most_recent_insert_iterator)->when == when) {
410
411                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert iterator at existing point, setting eval-value there %2\n", this, eval_value));
412                 
413                 /* most_recent_insert_iterator points to a control event
414                    already at the insert position, so there is
415                    nothing to do.
416                    
417                    ... except ... 
418
419                    advance most_recent_insert_iterator so that the "real"
420                    insert occurs in the right place, since it 
421                    points to the control event just inserted.
422                 */
423
424                 ++most_recent_insert_iterator;
425         } else {
426
427                 /* insert a new control event at the right spot
428                  */
429                 
430                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert eval-value %2 just before iterator @ %3\n", 
431                                                                  this, eval_value, (*most_recent_insert_iterator)->when));
432                 
433                 most_recent_insert_iterator = _events.insert (most_recent_insert_iterator, new ControlEvent (when, eval_value));
434
435                 /* advance most_recent_insert_iterator so that the "real"
436                  * insert occurs in the right place, since it 
437                  * points to the control event just inserted.
438                  */
439                 
440                 ++most_recent_insert_iterator;
441         }
442         
443         /* don't do this again till the next write pass */
444         
445         new_write_pass = false;
446 }
447
448 bool
449 ControlList::in_write_pass () const
450 {
451         return _in_write_pass;
452 }
453
454 void
455 ControlList::editor_add (double when, double value)
456 {
457         /* this is for making changes from a graphical line editor
458         */
459
460         if (_events.empty()) {
461                 
462                 /* as long as the point we're adding is not at zero,
463                  * add an "anchor" point there.
464                  */
465
466                 if (when >= 1) {
467                         _events.insert (_events.end(), new ControlEvent (0, _default_value));
468                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
469                 }
470         }
471
472         ControlEvent cp (when, 0.0f);
473         iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
474         DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value));
475         _events.insert (i, new ControlEvent (when, value));
476
477         mark_dirty ();
478
479         maybe_signal_changed ();
480
481 }
482
483 void
484 ControlList::maybe_add_insert_guard (double when)
485 {
486         if (most_recent_insert_iterator != _events.end()) {
487                 if ((*most_recent_insert_iterator)->when - when > 64) {
488                         /* Next control point is some distance from where our new point is
489                            going to go, so add a new point to avoid changing the shape of
490                            the line too much.  The insert iterator needs to point to the
491                            new control point so that our insert will happen correctly. */
492                         most_recent_insert_iterator = _events.insert (
493                                 most_recent_insert_iterator,
494                                 new ControlEvent (when + 1, (*most_recent_insert_iterator)->value));
495                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
496                                                                          this, when+1,
497                                                                          (*most_recent_insert_iterator)->value));
498                 }
499         }
500 }
501
502 /** If we would just be adding to a straight line, move the previous point instead. */
503 bool
504 ControlList::maybe_insert_straight_line (double when, double value)
505 {
506         if (_events.empty()) {
507                 return false;
508         }
509
510         if (_events.back()->value == value) {
511                 // Point b at the final point, which we know exists
512                 EventList::iterator b = _events.end();
513                 --b;
514                 if (b == _events.begin()) {
515                         return false;  // No previous point
516                 }
517
518                 // Check the previous point's value
519                 --b;
520                 if ((*b)->value == value) {
521                         /* At least two points with the exact same value (straight
522                            line), just move the final point to the new time. */
523                         _events.back()->when = when;
524                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
525                         return true;
526                 }
527         }
528         return false;
529 }
530
531 ControlList::iterator
532 ControlList::erase_from_iterator_to (iterator iter, double when)
533 {
534         while (iter != _events.end()) {
535                 if ((*iter)->when < when) {
536                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
537                         delete *iter;
538                         iter = _events.erase (iter);
539                         continue;
540                 } else if ((*iter)->when >= when) {
541                         break;
542                 }
543                 ++iter;
544         }
545         return iter;
546 }
547
548 void
549 ControlList::add (double when, double value, bool with_guards, bool with_initial)
550 {
551         /* this is for making changes from some kind of user interface or
552            control surface (GUI, MIDI, OSC etc)
553         */
554
555         DEBUG_TRACE (DEBUG::ControlList,
556                      string_compose ("@%1 add %2 at %3 guards = %4 write pass = %5 (new? %6) at end? %7\n",
557                                      this, value, when, with_guards, _in_write_pass, new_write_pass,
558                                      (most_recent_insert_iterator == _events.end())));
559         {
560                 Glib::Threads::RWLock::WriterLock lm (_lock);
561                 ControlEvent cp (when, 0.0f);
562                 iterator insertion_point;
563
564                 if (_events.empty() && with_initial) {
565                         
566                         /* empty: add an "anchor" point if the point we're adding past time 0 */
567
568                         if (when >= 1) {
569                                 _events.insert (_events.end(), new ControlEvent (0, value));
570                                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
571                         }
572                 }
573
574                 if (_in_write_pass && new_write_pass) {
575
576                         /* first write in a write pass: add guard point if requested */
577
578                         if (with_guards) {
579                                 add_guard_point (insert_position);
580                                 did_write_during_pass = true;
581                         } else {
582                                 /* not adding a guard, but we need to set iterator appropriately */
583                                 const ControlEvent cp (when, 0.0);
584                                 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
585                         }
586                         new_write_pass = false;
587
588                 } else if (_in_write_pass &&
589                            (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when)) {
590
591                         /* in write pass: erase from most recent insert to now */
592
593                         if (most_recent_insert_iterator != _events.end()) {
594                                 /* advance to avoid deleting the last inserted point itself. */
595                                 ++most_recent_insert_iterator;
596                         }
597
598                         most_recent_insert_iterator = erase_from_iterator_to(most_recent_insert_iterator, when);
599                         if (with_guards) {
600                                 maybe_add_insert_guard (when);
601                         }
602
603                 } else if (!_in_write_pass) {
604                                 
605                         /* not in a write pass: figure out the iterator we should insert in front of */
606
607                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("compute(b) MRI for position %1\n", when));
608                         ControlEvent cp (when, 0.0f);
609                         most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
610                 }
611
612                 /* OK, now we're really ready to add a new point */
613
614                 if (most_recent_insert_iterator == _events.end()) {
615                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 appending new point at end\n", this));
616                         
617                         const bool done = maybe_insert_straight_line (when, value);
618                         if (!done) {
619                                 _events.push_back (new ControlEvent (when, value));
620                                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("\tactually appended, size now %1\n", _events.size()));
621                         }
622
623                         most_recent_insert_iterator = _events.end();
624                         --most_recent_insert_iterator;
625
626                 } else if ((*most_recent_insert_iterator)->when == when) {
627
628                         if ((*most_recent_insert_iterator)->value != value) {
629                                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
630
631                                 /* only one point allowed per time point, so add a guard point
632                                  * before it if needed then reset the value of the point.
633                                  */
634
635                                 if ((when > 0) && most_recent_insert_iterator != _events.begin ()) {
636                                         --most_recent_insert_iterator;
637                                         double last_when =  (*most_recent_insert_iterator)->when;
638                                         ++most_recent_insert_iterator;
639                                         if (when - last_when > 64) {
640                                                 add_guard_point (when - 64);
641                                         }
642                                 }
643
644                                 (*most_recent_insert_iterator)->value = value;
645
646                                 /* if we modified the final value, then its as
647                                  * if we inserted a new point as far as the
648                                  * next addition, so make sure we know that.
649                                  */
650
651                                 if (_events.back()->when == when) {
652                                         most_recent_insert_iterator = _events.end();
653                                 }
654
655                         } else {
656                                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 same time %2, same value value %3\n", this, when, value));
657                         }
658
659                 } else {
660                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
661                         
662                         const bool done = maybe_insert_straight_line (when, value);
663                         if (with_guards) {
664                                 maybe_add_insert_guard(when);
665                         }
666
667                         if (!done) {
668                                 EventList::iterator x = _events.insert (most_recent_insert_iterator, new ControlEvent (when, value));
669                                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 inserted new value before MRI, size now %2\n", this, _events.size()));
670                                 most_recent_insert_iterator = x;
671                         }
672                 }
673
674                 mark_dirty ();
675         }
676
677         maybe_signal_changed ();
678 }
679
680 void
681 ControlList::erase (iterator i)
682 {
683         {
684                 Glib::Threads::RWLock::WriterLock lm (_lock);
685                 if (most_recent_insert_iterator == i) {
686                         unlocked_invalidate_insert_iterator ();
687                 }
688                 _events.erase (i);
689                 mark_dirty ();
690         }
691         maybe_signal_changed ();
692 }
693
694 void
695 ControlList::erase (iterator start, iterator end)
696 {
697         {
698                 Glib::Threads::RWLock::WriterLock lm (_lock);
699                 _events.erase (start, end);
700                 unlocked_invalidate_insert_iterator ();
701                 mark_dirty ();
702         }
703         maybe_signal_changed ();
704 }
705
706 /** Erase the first event which matches the given time and value */
707 void
708 ControlList::erase (double when, double value)
709 {
710         {
711                 Glib::Threads::RWLock::WriterLock lm (_lock);
712
713                 iterator i = begin ();
714                 while (i != end() && ((*i)->when != when || (*i)->value != value)) {
715                         ++i;
716                 }
717
718                 if (i != end ()) {
719                         _events.erase (i);
720                         if (most_recent_insert_iterator == i) {
721                                 unlocked_invalidate_insert_iterator ();
722                         }
723                 }
724
725                 mark_dirty ();
726         }
727
728         maybe_signal_changed ();
729 }
730
731 void
732 ControlList::erase_range (double start, double endt)
733 {
734         bool erased = false;
735
736         {
737                 Glib::Threads::RWLock::WriterLock lm (_lock);
738                 erased = erase_range_internal (start, endt, _events);
739
740                 if (erased) {
741                         mark_dirty ();
742                 }
743
744         }
745
746         if (erased) {
747                 maybe_signal_changed ();
748         }
749 }
750
751 bool
752 ControlList::erase_range_internal (double start, double endt, EventList & events)
753 {
754         bool erased = false;
755         ControlEvent cp (start, 0.0f);
756         iterator s;
757         iterator e;
758
759         if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
760                 cp.when = endt;
761                 e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
762                 events.erase (s, e);
763                 if (s != e) {
764                         unlocked_invalidate_insert_iterator ();
765                         erased = true;
766                 }
767         }
768
769         return erased;
770 }
771
772 void
773 ControlList::slide (iterator before, double distance)
774 {
775         {
776                 Glib::Threads::RWLock::WriterLock lm (_lock);
777
778                 if (before == _events.end()) {
779                         return;
780                 }
781
782                 while (before != _events.end()) {
783                         (*before)->when += distance;
784                         ++before;
785                 }
786
787                 mark_dirty ();
788         }
789
790         maybe_signal_changed ();
791 }
792
793 void
794 ControlList::shift (double pos, double frames)
795 {
796         {
797                 Glib::Threads::RWLock::WriterLock lm (_lock);
798
799                 for (iterator i = _events.begin(); i != _events.end(); ++i) {
800                         if ((*i)->when >= pos) {
801                                 (*i)->when += frames;
802                         }
803                 }
804
805                 mark_dirty ();
806         }
807
808         maybe_signal_changed ();
809 }
810
811 void
812 ControlList::modify (iterator iter, double when, double val)
813 {
814         /* note: we assume higher level logic is in place to avoid this
815            reordering the time-order of control events in the list. ie. all
816            points after *iter are later than when.
817         */
818
819         {
820                 Glib::Threads::RWLock::WriterLock lm (_lock);
821
822                 (*iter)->when = when;
823                 (*iter)->value = val;
824                 if (isnan_local (val)) {
825                         abort ();
826                 }
827
828                 if (!_frozen) {
829                         _events.sort (event_time_less_than);
830                         unlocked_invalidate_insert_iterator ();
831                 } else {
832                         _sort_pending = true;
833                 }
834
835                 mark_dirty ();
836         }
837
838         maybe_signal_changed ();
839 }
840
841 std::pair<ControlList::iterator,ControlList::iterator>
842 ControlList::control_points_adjacent (double xval)
843 {
844         Glib::Threads::RWLock::ReaderLock lm (_lock);
845         iterator i;
846         ControlEvent cp (xval, 0.0f);
847         std::pair<iterator,iterator> ret;
848
849         ret.first = _events.end();
850         ret.second = _events.end();
851
852         for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
853
854                 if (ret.first == _events.end()) {
855                         if ((*i)->when >= xval) {
856                                 if (i != _events.begin()) {
857                                         ret.first = i;
858                                         --ret.first;
859                                 } else {
860                                         return ret;
861                                 }
862                         }
863                 }
864
865                 if ((*i)->when > xval) {
866                         ret.second = i;
867                         break;
868                 }
869         }
870
871         return ret;
872 }
873
874 void
875 ControlList::freeze ()
876 {
877         _frozen++;
878 }
879
880 void
881 ControlList::thaw ()
882 {
883         assert(_frozen > 0);
884
885         if (--_frozen > 0) {
886                 return;
887         }
888
889         {
890                 Glib::Threads::RWLock::WriterLock lm (_lock);
891
892                 if (_sort_pending) {
893                         _events.sort (event_time_less_than);
894                         unlocked_invalidate_insert_iterator ();
895                         _sort_pending = false;
896                 }
897         }
898 }
899
900 void
901 ControlList::mark_dirty () const
902 {
903         _lookup_cache.left = -1;
904         _lookup_cache.range.first = _events.end();
905         _lookup_cache.range.second = _events.end();
906         _search_cache.left = -1;
907         _search_cache.first = _events.end();
908
909         if (_curve) {
910                 _curve->mark_dirty();
911         }
912
913         Dirty (); /* EMIT SIGNAL */
914 }
915
916 void
917 ControlList::truncate_end (double last_coordinate)
918 {
919         {
920                 Glib::Threads::RWLock::WriterLock lm (_lock);
921                 ControlEvent cp (last_coordinate, 0);
922                 ControlList::reverse_iterator i;
923                 double last_val;
924
925                 if (_events.empty()) {
926                         return;
927                 }
928
929                 if (last_coordinate == _events.back()->when) {
930                         return;
931                 }
932
933                 if (last_coordinate > _events.back()->when) {
934
935                         /* extending end:
936                          */
937
938                         iterator foo = _events.begin();
939                         bool lessthantwo;
940
941                         if (foo == _events.end()) {
942                                 lessthantwo = true;
943                         } else if (++foo == _events.end()) {
944                                 lessthantwo = true;
945                         } else {
946                                 lessthantwo = false;
947                         }
948
949                         if (lessthantwo) {
950                                 /* less than 2 points: add a new point */
951                                 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
952                         } else {
953
954                                 /* more than 2 points: check to see if the last 2 values
955                                    are equal. if so, just move the position of the
956                                    last point. otherwise, add a new point.
957                                 */
958
959                                 iterator penultimate = _events.end();
960                                 --penultimate; /* points at last point */
961                                 --penultimate; /* points at the penultimate point */
962
963                                 if (_events.back()->value == (*penultimate)->value) {
964                                         _events.back()->when = last_coordinate;
965                                 } else {
966                                         _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
967                                 }
968                         }
969
970                 } else {
971
972                         /* shortening end */
973
974                         last_val = unlocked_eval (last_coordinate);
975                         last_val = max ((double) _min_yval, last_val);
976                         last_val = min ((double) _max_yval, last_val);
977
978                         i = _events.rbegin();
979
980                         /* make i point to the last control point */
981
982                         ++i;
983
984                         /* now go backwards, removing control points that are
985                            beyond the new last coordinate.
986                         */
987
988                         // FIXME: SLOW! (size() == O(n))
989
990                         uint32_t sz = _events.size();
991
992                         while (i != _events.rend() && sz > 2) {
993                                 ControlList::reverse_iterator tmp;
994
995                                 tmp = i;
996                                 ++tmp;
997
998                                 if ((*i)->when < last_coordinate) {
999                                         break;
1000                                 }
1001
1002                                 _events.erase (i.base());
1003                                 --sz;
1004
1005                                 i = tmp;
1006                         }
1007
1008                         _events.back()->when = last_coordinate;
1009                         _events.back()->value = last_val;
1010                 }
1011                 
1012                 unlocked_invalidate_insert_iterator ();
1013                 mark_dirty();
1014         }
1015
1016         maybe_signal_changed ();
1017 }
1018
1019 void
1020 ControlList::truncate_start (double overall_length)
1021 {
1022         {
1023                 Glib::Threads::RWLock::WriterLock lm (_lock);
1024                 iterator i;
1025                 double first_legal_value;
1026                 double first_legal_coordinate;
1027
1028                 if (_events.empty()) {
1029                         /* nothing to truncate */
1030                         return;
1031                 } else if (overall_length == _events.back()->when) {
1032                         /* no change in overall length */
1033                         return;
1034                 }
1035
1036                 if (overall_length > _events.back()->when) {
1037
1038                         /* growing at front: duplicate first point. shift all others */
1039
1040                         double shift = overall_length - _events.back()->when;
1041                         uint32_t np;
1042
1043                         for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
1044                                 (*i)->when += shift;
1045                         }
1046
1047                         if (np < 2) {
1048
1049                                 /* less than 2 points: add a new point */
1050                                 _events.push_front (new ControlEvent (0, _events.front()->value));
1051
1052                         } else {
1053
1054                                 /* more than 2 points: check to see if the first 2 values
1055                                    are equal. if so, just move the position of the
1056                                    first point. otherwise, add a new point.
1057                                 */
1058
1059                                 iterator second = _events.begin();
1060                                 ++second; /* points at the second point */
1061
1062                                 if (_events.front()->value == (*second)->value) {
1063                                         /* first segment is flat, just move start point back to zero */
1064                                         _events.front()->when = 0;
1065                                 } else {
1066                                         /* leave non-flat segment in place, add a new leading point. */
1067                                         _events.push_front (new ControlEvent (0, _events.front()->value));
1068                                 }
1069                         }
1070
1071                 } else {
1072
1073                         /* shrinking at front */
1074
1075                         first_legal_coordinate = _events.back()->when - overall_length;
1076                         first_legal_value = unlocked_eval (first_legal_coordinate);
1077                         first_legal_value = max (_min_yval, first_legal_value);
1078                         first_legal_value = min (_max_yval, first_legal_value);
1079
1080                         /* remove all events earlier than the new "front" */
1081
1082                         i = _events.begin();
1083
1084                         while (i != _events.end() && !_events.empty()) {
1085                                 ControlList::iterator tmp;
1086
1087                                 tmp = i;
1088                                 ++tmp;
1089
1090                                 if ((*i)->when > first_legal_coordinate) {
1091                                         break;
1092                                 }
1093
1094                                 _events.erase (i);
1095
1096                                 i = tmp;
1097                         }
1098
1099
1100                         /* shift all remaining points left to keep their same
1101                            relative position
1102                         */
1103
1104                         for (i = _events.begin(); i != _events.end(); ++i) {
1105                                 (*i)->when -= first_legal_coordinate;
1106                         }
1107
1108                         /* add a new point for the interpolated new value */
1109
1110                         _events.push_front (new ControlEvent (0, first_legal_value));
1111                 }
1112
1113                 unlocked_invalidate_insert_iterator ();
1114                 mark_dirty();
1115         }
1116
1117         maybe_signal_changed ();
1118 }
1119
1120 double
1121 ControlList::unlocked_eval (double x) const
1122 {
1123         pair<EventList::iterator,EventList::iterator> range;
1124         int32_t npoints;
1125         double lpos, upos;
1126         double lval, uval;
1127         double fraction;
1128
1129         const_iterator length_check_iter = _events.begin();
1130         for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
1131                 if (length_check_iter == _events.end()) {
1132                         break;
1133                 }
1134         }
1135
1136         switch (npoints) {
1137         case 0:
1138                 return _default_value;
1139
1140         case 1:
1141                 return _events.front()->value;
1142
1143         case 2:
1144                 if (x >= _events.back()->when) {
1145                         return _events.back()->value;
1146                 } else if (x <= _events.front()->when) {
1147                         return _events.front()->value;
1148                 }
1149
1150                 lpos = _events.front()->when;
1151                 lval = _events.front()->value;
1152                 upos = _events.back()->when;
1153                 uval = _events.back()->value;
1154
1155                 if (_interpolation == Discrete) {
1156                         return lval;
1157                 }
1158
1159                 /* linear interpolation betweeen the two points */
1160                 fraction = (double) (x - lpos) / (double) (upos - lpos);
1161                 return lval + (fraction * (uval - lval));
1162
1163         default:
1164                 if (x >= _events.back()->when) {
1165                         return _events.back()->value;
1166                 } else if (x <= _events.front()->when) {
1167                         return _events.front()->value;
1168                 }
1169
1170                 return multipoint_eval (x);
1171         }
1172
1173         abort(); /*NOTREACHED*/ /* stupid gcc */
1174         return _default_value;
1175 }
1176
1177 double
1178 ControlList::multipoint_eval (double x) const
1179 {
1180         double upos, lpos;
1181         double uval, lval;
1182         double fraction;
1183
1184         /* "Stepped" lookup (no interpolation) */
1185         /* FIXME: no cache.  significant? */
1186         if (_interpolation == Discrete) {
1187                 const ControlEvent cp (x, 0);
1188                 EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
1189
1190                 // shouldn't have made it to multipoint_eval
1191                 assert(i != _events.end());
1192
1193                 if (i == _events.begin() || (*i)->when == x)
1194                         return (*i)->value;
1195                 else
1196                         return (*(--i))->value;
1197         }
1198
1199         /* Only do the range lookup if x is in a different range than last time
1200          * this was called (or if the lookup cache has been marked "dirty" (left<0) */
1201         if ((_lookup_cache.left < 0) ||
1202             ((_lookup_cache.left > x) ||
1203              (_lookup_cache.range.first == _events.end()) ||
1204              ((*_lookup_cache.range.second)->when < x))) {
1205
1206                 const ControlEvent cp (x, 0);
1207
1208                 _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
1209         }
1210
1211         pair<const_iterator,const_iterator> range = _lookup_cache.range;
1212
1213         if (range.first == range.second) {
1214
1215                 /* x does not exist within the list as a control point */
1216
1217                 _lookup_cache.left = x;
1218
1219                 if (range.first != _events.begin()) {
1220                         --range.first;
1221                         lpos = (*range.first)->when;
1222                         lval = (*range.first)->value;
1223                 }  else {
1224                         /* we're before the first point */
1225                         // return _default_value;
1226                         return _events.front()->value;
1227                 }
1228
1229                 if (range.second == _events.end()) {
1230                         /* we're after the last point */
1231                         return _events.back()->value;
1232                 }
1233
1234                 upos = (*range.second)->when;
1235                 uval = (*range.second)->value;
1236
1237                 /* linear interpolation betweeen the two points
1238                    on either side of x
1239                 */
1240
1241                 fraction = (double) (x - lpos) / (double) (upos - lpos);
1242                 return lval + (fraction * (uval - lval));
1243
1244         }
1245
1246         /* x is a control point in the data */
1247         _lookup_cache.left = -1;
1248         return (*range.first)->value;
1249 }
1250
1251 void
1252 ControlList::build_search_cache_if_necessary (double start) const
1253 {
1254         if (_events.empty()) {
1255                 /* Empty, nothing to cache, move to end. */
1256                 _search_cache.first = _events.end();
1257                 _search_cache.left = 0;
1258                 return;
1259         } else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
1260                 /* Marked dirty (left < 0), or we're too far forward, re-search. */
1261
1262                 const ControlEvent start_point (start, 0);
1263
1264                 _search_cache.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
1265                 _search_cache.left = start;
1266         }
1267
1268         /* We now have a search cache that is not too far right, but it may be too
1269            far left and need to be advanced. */
1270
1271         while (_search_cache.first != end() && (*_search_cache.first)->when < start) {
1272                 ++_search_cache.first;
1273         }
1274         _search_cache.left = start;
1275 }
1276
1277 /** Get the earliest event after \a start using the current interpolation style.
1278  *
1279  * If an event is found, \a x and \a y are set to its coordinates.
1280  *
1281  * \param inclusive Include events with timestamp exactly equal to \a start
1282  * \return true if event is found (and \a x and \a y are valid).
1283  */
1284 bool
1285 ControlList::rt_safe_earliest_event (double start, double& x, double& y, bool inclusive) const
1286 {
1287         // FIXME: It would be nice if this was unnecessary..
1288         Glib::Threads::RWLock::ReaderLock lm(_lock, Glib::Threads::TRY_LOCK);
1289         if (!lm.locked()) {
1290                 return false;
1291         }
1292
1293         return rt_safe_earliest_event_unlocked (start, x, y, inclusive);
1294 }
1295
1296
1297 /** Get the earliest event after \a start using the current interpolation style.
1298  *
1299  * If an event is found, \a x and \a y are set to its coordinates.
1300  *
1301  * \param inclusive Include events with timestamp exactly equal to \a start
1302  * \return true if event is found (and \a x and \a y are valid).
1303  */
1304 bool
1305 ControlList::rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool inclusive) const
1306 {
1307         if (_interpolation == Discrete) {
1308                 return rt_safe_earliest_event_discrete_unlocked(start, x, y, inclusive);
1309         } else {
1310                 return rt_safe_earliest_event_linear_unlocked(start, x, y, inclusive);
1311         }
1312 }
1313
1314
1315 /** Get the earliest event after \a start without interpolation.
1316  *
1317  * If an event is found, \a x and \a y are set to its coordinates.
1318  *
1319  * \param inclusive Include events with timestamp exactly equal to \a start
1320  * \return true if event is found (and \a x and \a y are valid).
1321  */
1322 bool
1323 ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const
1324 {
1325         build_search_cache_if_necessary (start);
1326
1327         if (_search_cache.first != _events.end()) {
1328                 const ControlEvent* const first = *_search_cache.first;
1329
1330                 const bool past_start = (inclusive ? first->when >= start : first->when > start);
1331
1332                 /* Earliest points is in range, return it */
1333                 if (past_start) {
1334
1335                         x = first->when;
1336                         y = first->value;
1337
1338                         /* Move left of cache to this point
1339                          * (Optimize for immediate call this cycle within range) */
1340                         _search_cache.left = x;
1341                         ++_search_cache.first;
1342
1343                         assert(x >= start);
1344                         return true;
1345
1346                 } else {
1347                         return false;
1348                 }
1349
1350                 /* No points in range */
1351         } else {
1352                 return false;
1353         }
1354 }
1355
1356 /** Get the earliest time the line crosses an integer (Linear interpolation).
1357  *
1358  * If an event is found, \a x and \a y are set to its coordinates.
1359  *
1360  * \param inclusive Include events with timestamp exactly equal to \a start
1361  * \return true if event is found (and \a x and \a y are valid).
1362  */
1363 bool
1364 ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const
1365 {
1366         // cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive <<  ")" << endl;
1367
1368         const_iterator length_check_iter = _events.begin();
1369         if (_events.empty()) { // 0 events
1370                 return false;
1371         } else if (_events.end() == ++length_check_iter) { // 1 event
1372                 return rt_safe_earliest_event_discrete_unlocked (start, x, y, inclusive);
1373         }
1374
1375         // Hack to avoid infinitely repeating the same event
1376         build_search_cache_if_necessary (start);
1377
1378         if (_search_cache.first != _events.end()) {
1379
1380                 const ControlEvent* first = NULL;
1381                 const ControlEvent* next = NULL;
1382
1383                 if (_search_cache.first == _events.begin() || (*_search_cache.first)->when <= start) {
1384                         /* Step is after first */
1385                         first = *_search_cache.first;
1386                         ++_search_cache.first;
1387                         if (_search_cache.first == _events.end()) {
1388                                 return false;
1389                         }
1390                         next = *_search_cache.first;
1391
1392                 } else {
1393                         /* Step is before first */
1394                         const_iterator prev = _search_cache.first;
1395                         --prev;
1396                         first = *prev;
1397                         next = *_search_cache.first;
1398                 }
1399
1400                 if (inclusive && first->when == start) {
1401                         x = first->when;
1402                         y = first->value;
1403                         /* Move left of cache to this point
1404                          * (Optimize for immediate call this cycle within range) */
1405                         _search_cache.left = x;
1406                         return true;
1407                 } else if (next->when < start || (!inclusive && next->when == start)) {
1408                         /* "Next" is before the start, no points left. */
1409                         return false;
1410                 }
1411
1412                 if (fabs(first->value - next->value) <= 1) {
1413                         if (next->when > start) {
1414                                 x = next->when;
1415                                 y = next->value;
1416                                 /* Move left of cache to this point
1417                                  * (Optimize for immediate call this cycle within range) */
1418                                 _search_cache.left = x;
1419                                 return true;
1420                         } else {
1421                                 return false;
1422                         }
1423                 }
1424
1425                 const double slope = (next->value - first->value) / (double)(next->when - first->when);
1426                 //cerr << "start y: " << start_y << endl;
1427
1428                 //y = first->value + (slope * fabs(start - first->when));
1429                 y = first->value;
1430
1431                 if (first->value < next->value) // ramping up
1432                         y = ceil(y);
1433                 else // ramping down
1434                         y = floor(y);
1435
1436                 x = first->when + (y - first->value) / (double)slope;
1437
1438                 while ((inclusive && x < start) || (x <= start && y != next->value)) {
1439
1440                         if (first->value < next->value) // ramping up
1441                                 y += 1.0;
1442                         else // ramping down
1443                                 y -= 1.0;
1444
1445                         x = first->when + (y - first->value) / (double)slope;
1446                 }
1447
1448                 /*cerr << first->value << " @ " << first->when << " ... "
1449                   << next->value << " @ " << next->when
1450                   << " = " << y << " @ " << x << endl;*/
1451
1452                 assert(    (y >= first->value && y <= next->value)
1453                            || (y <= first->value && y >= next->value) );
1454
1455
1456                 const bool past_start = (inclusive ? x >= start : x > start);
1457                 if (past_start) {
1458                         /* Move left of cache to this point
1459                          * (Optimize for immediate call this cycle within range) */
1460                         _search_cache.left = x;
1461                         assert(inclusive ? x >= start : x > start);
1462                         return true;
1463                 } else {
1464                         if (inclusive) {
1465                                 x = next->when;
1466                         } else {
1467                                 x = start;
1468                         }
1469                         _search_cache.left = x;
1470                         return true;
1471                 }
1472
1473         } else {
1474                 /* No points in the future, so no steps (towards them) in the future */
1475                 return false;
1476         }
1477 }
1478
1479
1480 /** @param start Start position in model coordinates.
1481  *  @param end End position in model coordinates.
1482  *  @param op 0 = cut, 1 = copy, 2 = clear.
1483  */
1484 boost::shared_ptr<ControlList>
1485 ControlList::cut_copy_clear (double start, double end, int op)
1486 {
1487         boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
1488         iterator s, e;
1489         ControlEvent cp (start, 0.0);
1490
1491         {
1492                 Glib::Threads::RWLock::WriterLock lm (_lock);
1493
1494                 /* first, determine s & e, two iterators that define the range of points
1495                    affected by this operation
1496                 */
1497
1498                 if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
1499                         return nal;
1500                 }
1501
1502                 /* and the last that is at or after `end' */
1503                 cp.when = end;
1504                 e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1505
1506
1507                 /* if "start" isn't the location of an existing point,
1508                    evaluate the curve to get a value for the start. Add a point to
1509                    both the existing event list, and if its not a "clear" operation,
1510                    to the copy ("nal") as well.
1511
1512                    Note that the time positions of the points in each list are different
1513                    because we want the copy ("nal") to have a zero time reference.
1514                 */
1515
1516
1517                 /* before we begin any cut/clear operations, get the value of the curve
1518                    at "end".
1519                 */
1520
1521                 double end_value = unlocked_eval (end);
1522
1523                 if ((*s)->when != start) {
1524
1525                         double val = unlocked_eval (start);
1526
1527                         if (op == 0) { // cut
1528                                 if (start > _events.front()->when) {
1529                                         _events.insert (s, (new ControlEvent (start, val)));
1530                                 }
1531                         }
1532
1533                         if (op != 2) { // ! clear
1534                                 nal->_events.push_back (new ControlEvent (0, val));
1535                         }
1536                 }
1537
1538                 for (iterator x = s; x != e; ) {
1539
1540                         /* adjust new points to be relative to start, which
1541                            has been set to zero.
1542                         */
1543
1544                         if (op != 2) {
1545                                 nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
1546                         }
1547
1548                         if (op != 1) {
1549                                 x = _events.erase (x);
1550                         } else {
1551                                 ++x;
1552                         }
1553                 }
1554
1555                 if (e == _events.end() || (*e)->when != end) {
1556
1557                         /* only add a boundary point if there is a point after "end"
1558                          */
1559
1560                         if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut
1561                                 _events.insert (e, new ControlEvent (end, end_value));
1562                         }
1563
1564                         if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
1565                                 nal->_events.push_back (new ControlEvent (end - start, end_value));
1566                         }
1567                 }
1568
1569                 unlocked_invalidate_insert_iterator ();
1570                 mark_dirty ();
1571         }
1572
1573         if (op != 1) {
1574                 maybe_signal_changed ();
1575         }
1576
1577         return nal;
1578 }
1579
1580
1581 boost::shared_ptr<ControlList>
1582 ControlList::cut (double start, double end)
1583 {
1584         return cut_copy_clear (start, end, 0);
1585 }
1586
1587 boost::shared_ptr<ControlList>
1588 ControlList::copy (double start, double end)
1589 {
1590         return cut_copy_clear (start, end, 1);
1591 }
1592
1593 void
1594 ControlList::clear (double start, double end)
1595 {
1596         cut_copy_clear (start, end, 2);
1597 }
1598
1599 /** @param pos Position in model coordinates */
1600 bool
1601 ControlList::paste (const ControlList& alist, double pos, float /*times*/)
1602 {
1603         if (alist._events.empty()) {
1604                 return false;
1605         }
1606
1607         {
1608                 Glib::Threads::RWLock::WriterLock lm (_lock);
1609                 iterator where;
1610                 iterator prev;
1611                 double end = 0;
1612                 ControlEvent cp (pos, 0.0);
1613
1614                 where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1615
1616                 for (const_iterator i = alist.begin();i != alist.end(); ++i) {
1617                         double value = (*i)->value;
1618                         if (alist.parameter() != parameter()) {
1619                                 const ParameterDescriptor& src_desc = alist.descriptor();
1620
1621                                 value -= src_desc.lower;  // translate to 0-relative
1622                                 value /= (src_desc.upper - src_desc.lower);  // normalize range
1623                                 value *= (_desc.upper - _desc.lower);  // scale to our range
1624                                 value += _desc.lower;  // translate to our offset
1625                         }
1626                         _events.insert (where, new ControlEvent((*i)->when + pos, value));
1627                         end = (*i)->when + pos;
1628                 }
1629
1630
1631                 /* move all  points after the insertion along the timeline by
1632                    the correct amount.
1633                 */
1634
1635                 while (where != _events.end()) {
1636                         iterator tmp;
1637                         if ((*where)->when <= end) {
1638                                 tmp = where;
1639                                 ++tmp;
1640                                 _events.erase(where);
1641                                 where = tmp;
1642
1643                         } else {
1644                                 break;
1645                         }
1646                 }
1647
1648                 unlocked_invalidate_insert_iterator ();
1649                 mark_dirty ();
1650         }
1651
1652         maybe_signal_changed ();
1653         return true;
1654 }
1655
1656 /** Move automation around according to a list of region movements.
1657  *  @param return true if anything was changed, otherwise false (ie nothing needed changing)
1658  */
1659 bool
1660 ControlList::move_ranges (const list< RangeMove<double> >& movements)
1661 {
1662         typedef list< RangeMove<double> > RangeMoveList;
1663
1664         {
1665                 Glib::Threads::RWLock::WriterLock lm (_lock);
1666
1667                 /* a copy of the events list before we started moving stuff around */
1668                 EventList old_events = _events;
1669
1670                 /* clear the source and destination ranges in the new list */
1671                 bool things_erased = false;
1672                 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1673
1674                         if (erase_range_internal (i->from, i->from + i->length, _events)) {
1675                                 things_erased = true;
1676                         }
1677
1678                         if (erase_range_internal (i->to, i->to + i->length, _events)) {
1679                                 things_erased = true;
1680                         }
1681                 }
1682
1683                 /* if nothing was erased, there is nothing to do */
1684                 if (!things_erased) {
1685                         return false;
1686                 }
1687
1688                 /* copy the events into the new list */
1689                 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1690                         iterator j = old_events.begin ();
1691                         const double limit = i->from + i->length;
1692                         const double dx    = i->to - i->from;
1693                         while (j != old_events.end () && (*j)->when <= limit) {
1694                                 if ((*j)->when >= i->from) {
1695                                         ControlEvent* ev = new ControlEvent (**j);
1696                                         ev->when += dx;
1697                                         _events.push_back (ev);
1698                                 }
1699                                 ++j;
1700                         }
1701                 }
1702
1703                 if (!_frozen) {
1704                         _events.sort (event_time_less_than);
1705                         unlocked_invalidate_insert_iterator ();
1706                 } else {
1707                         _sort_pending = true;
1708                 }
1709
1710                 mark_dirty ();
1711         }
1712
1713         maybe_signal_changed ();
1714         return true;
1715 }
1716
1717 void
1718 ControlList::set_interpolation (InterpolationStyle s)
1719 {
1720         if (_interpolation == s) {
1721                 return;
1722         }
1723
1724         _interpolation = s;
1725         InterpolationChanged (s); /* EMIT SIGNAL */
1726 }
1727
1728 bool
1729 ControlList::operator!= (ControlList const & other) const
1730 {
1731         if (_events.size() != other._events.size()) {
1732                 return true;
1733         }
1734
1735         EventList::const_iterator i = _events.begin ();
1736         EventList::const_iterator j = other._events.begin ();
1737
1738         while (i != _events.end() && (*i)->when == (*j)->when && (*i)->value == (*j)->value) {
1739                 ++i;
1740                 ++j;
1741         }
1742
1743         if (i != _events.end ()) {
1744                 return true;
1745         }
1746         
1747         return (
1748                 _parameter != other._parameter ||
1749                 _interpolation != other._interpolation ||
1750                 _min_yval != other._min_yval ||
1751                 _max_yval != other._max_yval ||
1752                 _default_value != other._default_value
1753                 );
1754 }
1755
1756 void
1757 ControlList::dump (ostream& o)
1758 {
1759         /* NOT LOCKED ... for debugging only */
1760
1761         for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
1762                 o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl;
1763         }
1764 }
1765
1766 } // namespace Evoral
1767