0755bd27d229bc26520af40de60439c330a1df53
[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, bool with_guard)
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, value));
468                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added value %2 at zero\n", this, value));
469                 }
470         }
471
472         insert_position = when;
473         if (with_guard) {
474                 if (when > 64) {
475                         add_guard_point (when - 64);
476                 }
477                 maybe_add_insert_guard (when);
478         }
479
480         ControlEvent cp (when, 0.0f);
481         iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
482         DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value));
483         _events.insert (i, new ControlEvent (when, value));
484
485         mark_dirty ();
486
487         maybe_signal_changed ();
488
489 }
490
491 void
492 ControlList::maybe_add_insert_guard (double when)
493 {
494         if (most_recent_insert_iterator != _events.end()) {
495                 if ((*most_recent_insert_iterator)->when - when > 64) {
496                         /* Next control point is some distance from where our new point is
497                            going to go, so add a new point to avoid changing the shape of
498                            the line too much.  The insert iterator needs to point to the
499                            new control point so that our insert will happen correctly. */
500                         most_recent_insert_iterator = _events.insert (
501                                 most_recent_insert_iterator,
502                                 new ControlEvent (when + 64, (*most_recent_insert_iterator)->value));
503                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
504                                                                          this, when + 64,
505                                                                          (*most_recent_insert_iterator)->value));
506                 }
507         }
508 }
509
510 /** If we would just be adding to a straight line, move the previous point instead. */
511 bool
512 ControlList::maybe_insert_straight_line (double when, double value)
513 {
514         if (_events.empty()) {
515                 return false;
516         }
517
518         if (_events.back()->value == value) {
519                 // Point b at the final point, which we know exists
520                 EventList::iterator b = _events.end();
521                 --b;
522                 if (b == _events.begin()) {
523                         return false;  // No previous point
524                 }
525
526                 // Check the previous point's value
527                 --b;
528                 if ((*b)->value == value) {
529                         /* At least two points with the exact same value (straight
530                            line), just move the final point to the new time. */
531                         _events.back()->when = when;
532                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
533                         return true;
534                 }
535         }
536         return false;
537 }
538
539 ControlList::iterator
540 ControlList::erase_from_iterator_to (iterator iter, double when)
541 {
542         while (iter != _events.end()) {
543                 if ((*iter)->when < when) {
544                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
545                         delete *iter;
546                         iter = _events.erase (iter);
547                         continue;
548                 } else if ((*iter)->when >= when) {
549                         break;
550                 }
551                 ++iter;
552         }
553         return iter;
554 }
555
556 void
557 ControlList::add (double when, double value, bool with_guards, bool with_initial)
558 {
559         /* this is for making changes from some kind of user interface or
560            control surface (GUI, MIDI, OSC etc)
561         */
562
563         DEBUG_TRACE (DEBUG::ControlList,
564                      string_compose ("@%1 add %2 at %3 guards = %4 write pass = %5 (new? %6) at end? %7\n",
565                                      this, value, when, with_guards, _in_write_pass, new_write_pass,
566                                      (most_recent_insert_iterator == _events.end())));
567         {
568                 Glib::Threads::RWLock::WriterLock lm (_lock);
569                 ControlEvent cp (when, 0.0f);
570                 iterator insertion_point;
571
572                 if (_events.empty() && with_initial) {
573                         
574                         /* empty: add an "anchor" point if the point we're adding past time 0 */
575
576                         if (when >= 1) {
577                                 _events.insert (_events.end(), new ControlEvent (0, value));
578                                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
579                         }
580                 }
581
582                 if (_in_write_pass && new_write_pass) {
583
584                         /* first write in a write pass: add guard point if requested */
585
586                         if (with_guards) {
587                                 add_guard_point (insert_position);
588                                 did_write_during_pass = true;
589                         } else {
590                                 /* not adding a guard, but we need to set iterator appropriately */
591                                 const ControlEvent cp (when, 0.0);
592                                 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
593                         }
594                         new_write_pass = false;
595
596                 } else if (_in_write_pass &&
597                            (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when)) {
598
599                         /* in write pass: erase from most recent insert to now */
600
601                         if (most_recent_insert_iterator != _events.end()) {
602                                 /* advance to avoid deleting the last inserted point itself. */
603                                 ++most_recent_insert_iterator;
604                         }
605
606                         most_recent_insert_iterator = erase_from_iterator_to(most_recent_insert_iterator, when);
607                         if (with_guards) {
608                                 maybe_add_insert_guard (when);
609                         }
610
611                 } else if (!_in_write_pass) {
612                                 
613                         /* not in a write pass: figure out the iterator we should insert in front of */
614
615                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("compute(b) MRI for position %1\n", when));
616                         ControlEvent cp (when, 0.0f);
617                         most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
618                 }
619
620                 /* OK, now we're really ready to add a new point */
621
622                 if (most_recent_insert_iterator == _events.end()) {
623                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 appending new point at end\n", this));
624                         
625                         const bool done = maybe_insert_straight_line (when, value);
626                         if (!done) {
627                                 _events.push_back (new ControlEvent (when, value));
628                                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("\tactually appended, size now %1\n", _events.size()));
629                         }
630
631                         most_recent_insert_iterator = _events.end();
632                         --most_recent_insert_iterator;
633
634                 } else if ((*most_recent_insert_iterator)->when == when) {
635
636                         if ((*most_recent_insert_iterator)->value != value) {
637                                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
638
639                                 /* only one point allowed per time point, so add a guard point
640                                  * before it if needed then reset the value of the point.
641                                  */
642
643                                 (*most_recent_insert_iterator)->value = value;
644
645                                 /* if we modified the final value, then its as
646                                  * if we inserted a new point as far as the
647                                  * next addition, so make sure we know that.
648                                  */
649
650                                 if (_events.back()->when == when) {
651                                         most_recent_insert_iterator = _events.end();
652                                 }
653
654                         } else {
655                                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 same time %2, same value value %3\n", this, when, value));
656                         }
657
658                 } else {
659                         DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
660                         bool done = false;
661                         /* check for possible straight line here until maybe_insert_straight_line () handles the insert iterator properly*/
662                         if (most_recent_insert_iterator != _events.begin ()) {
663                                 bool have_point2 = false;
664                                 --most_recent_insert_iterator;
665                                 const bool have_point1 = (*most_recent_insert_iterator)->value == value;
666
667                                 if (most_recent_insert_iterator != _events.begin ()) {
668                                         --most_recent_insert_iterator;
669                                         have_point2 = (*most_recent_insert_iterator)->value == value;
670                                         ++most_recent_insert_iterator;
671                                 }
672
673                                 if (have_point1 && have_point2) {
674                                         (*most_recent_insert_iterator)->when = when;
675                                         done = true;
676                                 } else {
677                                         ++most_recent_insert_iterator;
678                                 }
679                         }
680                         //done = maybe_insert_straight_line (when, value) || done;
681                         /* if the transport is stopped, add guard points (?) */
682                         if (!done && !_in_write_pass && when > 64) {
683                                 add_guard_point (when - 64);
684                                 maybe_add_insert_guard (when);
685                         }
686
687                         if (with_guards) {
688                                 maybe_add_insert_guard (when);
689                         }
690
691                         if (!done) {
692                                 EventList::iterator x = _events.insert (most_recent_insert_iterator, new ControlEvent (when, value));
693                                 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 inserted new value before MRI, size now %2\n", this, _events.size()));
694                                 most_recent_insert_iterator = x;
695                         }
696                 }
697
698                 mark_dirty ();
699         }
700
701         maybe_signal_changed ();
702 }
703
704 void
705 ControlList::erase (iterator i)
706 {
707         {
708                 Glib::Threads::RWLock::WriterLock lm (_lock);
709                 if (most_recent_insert_iterator == i) {
710                         unlocked_invalidate_insert_iterator ();
711                 }
712                 _events.erase (i);
713                 mark_dirty ();
714         }
715         maybe_signal_changed ();
716 }
717
718 void
719 ControlList::erase (iterator start, iterator end)
720 {
721         {
722                 Glib::Threads::RWLock::WriterLock lm (_lock);
723                 _events.erase (start, end);
724                 unlocked_invalidate_insert_iterator ();
725                 mark_dirty ();
726         }
727         maybe_signal_changed ();
728 }
729
730 /** Erase the first event which matches the given time and value */
731 void
732 ControlList::erase (double when, double value)
733 {
734         {
735                 Glib::Threads::RWLock::WriterLock lm (_lock);
736
737                 iterator i = begin ();
738                 while (i != end() && ((*i)->when != when || (*i)->value != value)) {
739                         ++i;
740                 }
741
742                 if (i != end ()) {
743                         _events.erase (i);
744                         if (most_recent_insert_iterator == i) {
745                                 unlocked_invalidate_insert_iterator ();
746                         }
747                 }
748
749                 mark_dirty ();
750         }
751
752         maybe_signal_changed ();
753 }
754
755 void
756 ControlList::erase_range (double start, double endt)
757 {
758         bool erased = false;
759
760         {
761                 Glib::Threads::RWLock::WriterLock lm (_lock);
762                 erased = erase_range_internal (start, endt, _events);
763
764                 if (erased) {
765                         mark_dirty ();
766                 }
767
768         }
769
770         if (erased) {
771                 maybe_signal_changed ();
772         }
773 }
774
775 bool
776 ControlList::erase_range_internal (double start, double endt, EventList & events)
777 {
778         bool erased = false;
779         ControlEvent cp (start, 0.0f);
780         iterator s;
781         iterator e;
782
783         if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
784                 cp.when = endt;
785                 e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
786                 events.erase (s, e);
787                 if (s != e) {
788                         unlocked_invalidate_insert_iterator ();
789                         erased = true;
790                 }
791         }
792
793         return erased;
794 }
795
796 void
797 ControlList::slide (iterator before, double distance)
798 {
799         {
800                 Glib::Threads::RWLock::WriterLock lm (_lock);
801
802                 if (before == _events.end()) {
803                         return;
804                 }
805
806                 while (before != _events.end()) {
807                         (*before)->when += distance;
808                         ++before;
809                 }
810
811                 mark_dirty ();
812         }
813
814         maybe_signal_changed ();
815 }
816
817 void
818 ControlList::shift (double pos, double frames)
819 {
820         {
821                 Glib::Threads::RWLock::WriterLock lm (_lock);
822
823                 for (iterator i = _events.begin(); i != _events.end(); ++i) {
824                         if ((*i)->when >= pos) {
825                                 (*i)->when += frames;
826                         }
827                 }
828
829                 mark_dirty ();
830         }
831
832         maybe_signal_changed ();
833 }
834
835 void
836 ControlList::modify (iterator iter, double when, double val)
837 {
838         /* note: we assume higher level logic is in place to avoid this
839            reordering the time-order of control events in the list. ie. all
840            points after *iter are later than when.
841         */
842
843         {
844                 Glib::Threads::RWLock::WriterLock lm (_lock);
845
846                 (*iter)->when = when;
847                 (*iter)->value = val;
848                 if (isnan_local (val)) {
849                         abort ();
850                 }
851
852                 if (!_frozen) {
853                         _events.sort (event_time_less_than);
854                         unlocked_invalidate_insert_iterator ();
855                 } else {
856                         _sort_pending = true;
857                 }
858
859                 mark_dirty ();
860         }
861
862         maybe_signal_changed ();
863 }
864
865 std::pair<ControlList::iterator,ControlList::iterator>
866 ControlList::control_points_adjacent (double xval)
867 {
868         Glib::Threads::RWLock::ReaderLock lm (_lock);
869         iterator i;
870         ControlEvent cp (xval, 0.0f);
871         std::pair<iterator,iterator> ret;
872
873         ret.first = _events.end();
874         ret.second = _events.end();
875
876         for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
877
878                 if (ret.first == _events.end()) {
879                         if ((*i)->when >= xval) {
880                                 if (i != _events.begin()) {
881                                         ret.first = i;
882                                         --ret.first;
883                                 } else {
884                                         return ret;
885                                 }
886                         }
887                 }
888
889                 if ((*i)->when > xval) {
890                         ret.second = i;
891                         break;
892                 }
893         }
894
895         return ret;
896 }
897
898 void
899 ControlList::freeze ()
900 {
901         _frozen++;
902 }
903
904 void
905 ControlList::thaw ()
906 {
907         assert(_frozen > 0);
908
909         if (--_frozen > 0) {
910                 return;
911         }
912
913         {
914                 Glib::Threads::RWLock::WriterLock lm (_lock);
915
916                 if (_sort_pending) {
917                         _events.sort (event_time_less_than);
918                         unlocked_invalidate_insert_iterator ();
919                         _sort_pending = false;
920                 }
921         }
922 }
923
924 void
925 ControlList::mark_dirty () const
926 {
927         _lookup_cache.left = -1;
928         _lookup_cache.range.first = _events.end();
929         _lookup_cache.range.second = _events.end();
930         _search_cache.left = -1;
931         _search_cache.first = _events.end();
932
933         if (_curve) {
934                 _curve->mark_dirty();
935         }
936
937         Dirty (); /* EMIT SIGNAL */
938 }
939
940 void
941 ControlList::truncate_end (double last_coordinate)
942 {
943         {
944                 Glib::Threads::RWLock::WriterLock lm (_lock);
945                 ControlEvent cp (last_coordinate, 0);
946                 ControlList::reverse_iterator i;
947                 double last_val;
948
949                 if (_events.empty()) {
950                         return;
951                 }
952
953                 if (last_coordinate == _events.back()->when) {
954                         return;
955                 }
956
957                 if (last_coordinate > _events.back()->when) {
958
959                         /* extending end:
960                          */
961
962                         iterator foo = _events.begin();
963                         bool lessthantwo;
964
965                         if (foo == _events.end()) {
966                                 lessthantwo = true;
967                         } else if (++foo == _events.end()) {
968                                 lessthantwo = true;
969                         } else {
970                                 lessthantwo = false;
971                         }
972
973                         if (lessthantwo) {
974                                 /* less than 2 points: add a new point */
975                                 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
976                         } else {
977
978                                 /* more than 2 points: check to see if the last 2 values
979                                    are equal. if so, just move the position of the
980                                    last point. otherwise, add a new point.
981                                 */
982
983                                 iterator penultimate = _events.end();
984                                 --penultimate; /* points at last point */
985                                 --penultimate; /* points at the penultimate point */
986
987                                 if (_events.back()->value == (*penultimate)->value) {
988                                         _events.back()->when = last_coordinate;
989                                 } else {
990                                         _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
991                                 }
992                         }
993
994                 } else {
995
996                         /* shortening end */
997
998                         last_val = unlocked_eval (last_coordinate);
999                         last_val = max ((double) _min_yval, last_val);
1000                         last_val = min ((double) _max_yval, last_val);
1001
1002                         i = _events.rbegin();
1003
1004                         /* make i point to the last control point */
1005
1006                         ++i;
1007
1008                         /* now go backwards, removing control points that are
1009                            beyond the new last coordinate.
1010                         */
1011
1012                         // FIXME: SLOW! (size() == O(n))
1013
1014                         uint32_t sz = _events.size();
1015
1016                         while (i != _events.rend() && sz > 2) {
1017                                 ControlList::reverse_iterator tmp;
1018
1019                                 tmp = i;
1020                                 ++tmp;
1021
1022                                 if ((*i)->when < last_coordinate) {
1023                                         break;
1024                                 }
1025
1026                                 _events.erase (i.base());
1027                                 --sz;
1028
1029                                 i = tmp;
1030                         }
1031
1032                         _events.back()->when = last_coordinate;
1033                         _events.back()->value = last_val;
1034                 }
1035                 
1036                 unlocked_invalidate_insert_iterator ();
1037                 mark_dirty();
1038         }
1039
1040         maybe_signal_changed ();
1041 }
1042
1043 void
1044 ControlList::truncate_start (double overall_length)
1045 {
1046         {
1047                 Glib::Threads::RWLock::WriterLock lm (_lock);
1048                 iterator i;
1049                 double first_legal_value;
1050                 double first_legal_coordinate;
1051
1052                 if (_events.empty()) {
1053                         /* nothing to truncate */
1054                         return;
1055                 } else if (overall_length == _events.back()->when) {
1056                         /* no change in overall length */
1057                         return;
1058                 }
1059
1060                 if (overall_length > _events.back()->when) {
1061
1062                         /* growing at front: duplicate first point. shift all others */
1063
1064                         double shift = overall_length - _events.back()->when;
1065                         uint32_t np;
1066
1067                         for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
1068                                 (*i)->when += shift;
1069                         }
1070
1071                         if (np < 2) {
1072
1073                                 /* less than 2 points: add a new point */
1074                                 _events.push_front (new ControlEvent (0, _events.front()->value));
1075
1076                         } else {
1077
1078                                 /* more than 2 points: check to see if the first 2 values
1079                                    are equal. if so, just move the position of the
1080                                    first point. otherwise, add a new point.
1081                                 */
1082
1083                                 iterator second = _events.begin();
1084                                 ++second; /* points at the second point */
1085
1086                                 if (_events.front()->value == (*second)->value) {
1087                                         /* first segment is flat, just move start point back to zero */
1088                                         _events.front()->when = 0;
1089                                 } else {
1090                                         /* leave non-flat segment in place, add a new leading point. */
1091                                         _events.push_front (new ControlEvent (0, _events.front()->value));
1092                                 }
1093                         }
1094
1095                 } else {
1096
1097                         /* shrinking at front */
1098
1099                         first_legal_coordinate = _events.back()->when - overall_length;
1100                         first_legal_value = unlocked_eval (first_legal_coordinate);
1101                         first_legal_value = max (_min_yval, first_legal_value);
1102                         first_legal_value = min (_max_yval, first_legal_value);
1103
1104                         /* remove all events earlier than the new "front" */
1105
1106                         i = _events.begin();
1107
1108                         while (i != _events.end() && !_events.empty()) {
1109                                 ControlList::iterator tmp;
1110
1111                                 tmp = i;
1112                                 ++tmp;
1113
1114                                 if ((*i)->when > first_legal_coordinate) {
1115                                         break;
1116                                 }
1117
1118                                 _events.erase (i);
1119
1120                                 i = tmp;
1121                         }
1122
1123
1124                         /* shift all remaining points left to keep their same
1125                            relative position
1126                         */
1127
1128                         for (i = _events.begin(); i != _events.end(); ++i) {
1129                                 (*i)->when -= first_legal_coordinate;
1130                         }
1131
1132                         /* add a new point for the interpolated new value */
1133
1134                         _events.push_front (new ControlEvent (0, first_legal_value));
1135                 }
1136
1137                 unlocked_invalidate_insert_iterator ();
1138                 mark_dirty();
1139         }
1140
1141         maybe_signal_changed ();
1142 }
1143
1144 double
1145 ControlList::unlocked_eval (double x) const
1146 {
1147         pair<EventList::iterator,EventList::iterator> range;
1148         int32_t npoints;
1149         double lpos, upos;
1150         double lval, uval;
1151         double fraction;
1152
1153         const_iterator length_check_iter = _events.begin();
1154         for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
1155                 if (length_check_iter == _events.end()) {
1156                         break;
1157                 }
1158         }
1159
1160         switch (npoints) {
1161         case 0:
1162                 return _default_value;
1163
1164         case 1:
1165                 return _events.front()->value;
1166
1167         case 2:
1168                 if (x >= _events.back()->when) {
1169                         return _events.back()->value;
1170                 } else if (x <= _events.front()->when) {
1171                         return _events.front()->value;
1172                 }
1173
1174                 lpos = _events.front()->when;
1175                 lval = _events.front()->value;
1176                 upos = _events.back()->when;
1177                 uval = _events.back()->value;
1178
1179                 if (_interpolation == Discrete) {
1180                         return lval;
1181                 }
1182
1183                 /* linear interpolation betweeen the two points */
1184                 fraction = (double) (x - lpos) / (double) (upos - lpos);
1185                 return lval + (fraction * (uval - lval));
1186
1187         default:
1188                 if (x >= _events.back()->when) {
1189                         return _events.back()->value;
1190                 } else if (x <= _events.front()->when) {
1191                         return _events.front()->value;
1192                 }
1193
1194                 return multipoint_eval (x);
1195         }
1196
1197         abort(); /*NOTREACHED*/ /* stupid gcc */
1198         return _default_value;
1199 }
1200
1201 double
1202 ControlList::multipoint_eval (double x) const
1203 {
1204         double upos, lpos;
1205         double uval, lval;
1206         double fraction;
1207
1208         /* "Stepped" lookup (no interpolation) */
1209         /* FIXME: no cache.  significant? */
1210         if (_interpolation == Discrete) {
1211                 const ControlEvent cp (x, 0);
1212                 EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
1213
1214                 // shouldn't have made it to multipoint_eval
1215                 assert(i != _events.end());
1216
1217                 if (i == _events.begin() || (*i)->when == x)
1218                         return (*i)->value;
1219                 else
1220                         return (*(--i))->value;
1221         }
1222
1223         /* Only do the range lookup if x is in a different range than last time
1224          * this was called (or if the lookup cache has been marked "dirty" (left<0) */
1225         if ((_lookup_cache.left < 0) ||
1226             ((_lookup_cache.left > x) ||
1227              (_lookup_cache.range.first == _events.end()) ||
1228              ((*_lookup_cache.range.second)->when < x))) {
1229
1230                 const ControlEvent cp (x, 0);
1231
1232                 _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
1233         }
1234
1235         pair<const_iterator,const_iterator> range = _lookup_cache.range;
1236
1237         if (range.first == range.second) {
1238
1239                 /* x does not exist within the list as a control point */
1240
1241                 _lookup_cache.left = x;
1242
1243                 if (range.first != _events.begin()) {
1244                         --range.first;
1245                         lpos = (*range.first)->when;
1246                         lval = (*range.first)->value;
1247                 }  else {
1248                         /* we're before the first point */
1249                         // return _default_value;
1250                         return _events.front()->value;
1251                 }
1252
1253                 if (range.second == _events.end()) {
1254                         /* we're after the last point */
1255                         return _events.back()->value;
1256                 }
1257
1258                 upos = (*range.second)->when;
1259                 uval = (*range.second)->value;
1260
1261                 /* linear interpolation betweeen the two points
1262                    on either side of x
1263                 */
1264
1265                 fraction = (double) (x - lpos) / (double) (upos - lpos);
1266                 return lval + (fraction * (uval - lval));
1267
1268         }
1269
1270         /* x is a control point in the data */
1271         _lookup_cache.left = -1;
1272         return (*range.first)->value;
1273 }
1274
1275 void
1276 ControlList::build_search_cache_if_necessary (double start) const
1277 {
1278         if (_events.empty()) {
1279                 /* Empty, nothing to cache, move to end. */
1280                 _search_cache.first = _events.end();
1281                 _search_cache.left = 0;
1282                 return;
1283         } else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
1284                 /* Marked dirty (left < 0), or we're too far forward, re-search. */
1285
1286                 const ControlEvent start_point (start, 0);
1287
1288                 _search_cache.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
1289                 _search_cache.left = start;
1290         }
1291
1292         /* We now have a search cache that is not too far right, but it may be too
1293            far left and need to be advanced. */
1294
1295         while (_search_cache.first != end() && (*_search_cache.first)->when < start) {
1296                 ++_search_cache.first;
1297         }
1298         _search_cache.left = start;
1299 }
1300
1301 /** Get the earliest event after \a start using the current interpolation style.
1302  *
1303  * If an event is found, \a x and \a y are set to its coordinates.
1304  *
1305  * \param inclusive Include events with timestamp exactly equal to \a start
1306  * \return true if event is found (and \a x and \a y are valid).
1307  */
1308 bool
1309 ControlList::rt_safe_earliest_event (double start, double& x, double& y, bool inclusive) const
1310 {
1311         // FIXME: It would be nice if this was unnecessary..
1312         Glib::Threads::RWLock::ReaderLock lm(_lock, Glib::Threads::TRY_LOCK);
1313         if (!lm.locked()) {
1314                 return false;
1315         }
1316
1317         return rt_safe_earliest_event_unlocked (start, x, y, inclusive);
1318 }
1319
1320
1321 /** Get the earliest event after \a start using the current interpolation style.
1322  *
1323  * If an event is found, \a x and \a y are set to its coordinates.
1324  *
1325  * \param inclusive Include events with timestamp exactly equal to \a start
1326  * \return true if event is found (and \a x and \a y are valid).
1327  */
1328 bool
1329 ControlList::rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool inclusive) const
1330 {
1331         if (_interpolation == Discrete) {
1332                 return rt_safe_earliest_event_discrete_unlocked(start, x, y, inclusive);
1333         } else {
1334                 return rt_safe_earliest_event_linear_unlocked(start, x, y, inclusive);
1335         }
1336 }
1337
1338
1339 /** Get the earliest event after \a start without interpolation.
1340  *
1341  * If an event is found, \a x and \a y are set to its coordinates.
1342  *
1343  * \param inclusive Include events with timestamp exactly equal to \a start
1344  * \return true if event is found (and \a x and \a y are valid).
1345  */
1346 bool
1347 ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const
1348 {
1349         build_search_cache_if_necessary (start);
1350
1351         if (_search_cache.first != _events.end()) {
1352                 const ControlEvent* const first = *_search_cache.first;
1353
1354                 const bool past_start = (inclusive ? first->when >= start : first->when > start);
1355
1356                 /* Earliest points is in range, return it */
1357                 if (past_start) {
1358
1359                         x = first->when;
1360                         y = first->value;
1361
1362                         /* Move left of cache to this point
1363                          * (Optimize for immediate call this cycle within range) */
1364                         _search_cache.left = x;
1365                         ++_search_cache.first;
1366
1367                         assert(x >= start);
1368                         return true;
1369
1370                 } else {
1371                         return false;
1372                 }
1373
1374                 /* No points in range */
1375         } else {
1376                 return false;
1377         }
1378 }
1379
1380 /** Get the earliest time the line crosses an integer (Linear interpolation).
1381  *
1382  * If an event is found, \a x and \a y are set to its coordinates.
1383  *
1384  * \param inclusive Include events with timestamp exactly equal to \a start
1385  * \return true if event is found (and \a x and \a y are valid).
1386  */
1387 bool
1388 ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const
1389 {
1390         // cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive <<  ")" << endl;
1391
1392         const_iterator length_check_iter = _events.begin();
1393         if (_events.empty()) { // 0 events
1394                 return false;
1395         } else if (_events.end() == ++length_check_iter) { // 1 event
1396                 return rt_safe_earliest_event_discrete_unlocked (start, x, y, inclusive);
1397         }
1398
1399         // Hack to avoid infinitely repeating the same event
1400         build_search_cache_if_necessary (start);
1401
1402         if (_search_cache.first != _events.end()) {
1403
1404                 const ControlEvent* first = NULL;
1405                 const ControlEvent* next = NULL;
1406
1407                 if (_search_cache.first == _events.begin() || (*_search_cache.first)->when <= start) {
1408                         /* Step is after first */
1409                         first = *_search_cache.first;
1410                         ++_search_cache.first;
1411                         if (_search_cache.first == _events.end()) {
1412                                 return false;
1413                         }
1414                         next = *_search_cache.first;
1415
1416                 } else {
1417                         /* Step is before first */
1418                         const_iterator prev = _search_cache.first;
1419                         --prev;
1420                         first = *prev;
1421                         next = *_search_cache.first;
1422                 }
1423
1424                 if (inclusive && first->when == start) {
1425                         x = first->when;
1426                         y = first->value;
1427                         /* Move left of cache to this point
1428                          * (Optimize for immediate call this cycle within range) */
1429                         _search_cache.left = x;
1430                         return true;
1431                 } else if (next->when < start || (!inclusive && next->when == start)) {
1432                         /* "Next" is before the start, no points left. */
1433                         return false;
1434                 }
1435
1436                 if (fabs(first->value - next->value) <= 1) {
1437                         if (next->when > start) {
1438                                 x = next->when;
1439                                 y = next->value;
1440                                 /* Move left of cache to this point
1441                                  * (Optimize for immediate call this cycle within range) */
1442                                 _search_cache.left = x;
1443                                 return true;
1444                         } else {
1445                                 return false;
1446                         }
1447                 }
1448
1449                 const double slope = (next->value - first->value) / (double)(next->when - first->when);
1450                 //cerr << "start y: " << start_y << endl;
1451
1452                 //y = first->value + (slope * fabs(start - first->when));
1453                 y = first->value;
1454
1455                 if (first->value < next->value) // ramping up
1456                         y = ceil(y);
1457                 else // ramping down
1458                         y = floor(y);
1459
1460                 x = first->when + (y - first->value) / (double)slope;
1461
1462                 while ((inclusive && x < start) || (x <= start && y != next->value)) {
1463
1464                         if (first->value < next->value) // ramping up
1465                                 y += 1.0;
1466                         else // ramping down
1467                                 y -= 1.0;
1468
1469                         x = first->when + (y - first->value) / (double)slope;
1470                 }
1471
1472                 /*cerr << first->value << " @ " << first->when << " ... "
1473                   << next->value << " @ " << next->when
1474                   << " = " << y << " @ " << x << endl;*/
1475
1476                 assert(    (y >= first->value && y <= next->value)
1477                            || (y <= first->value && y >= next->value) );
1478
1479
1480                 const bool past_start = (inclusive ? x >= start : x > start);
1481                 if (past_start) {
1482                         /* Move left of cache to this point
1483                          * (Optimize for immediate call this cycle within range) */
1484                         _search_cache.left = x;
1485                         assert(inclusive ? x >= start : x > start);
1486                         return true;
1487                 } else {
1488                         if (inclusive) {
1489                                 x = next->when;
1490                         } else {
1491                                 x = start;
1492                         }
1493                         _search_cache.left = x;
1494                         return true;
1495                 }
1496
1497         } else {
1498                 /* No points in the future, so no steps (towards them) in the future */
1499                 return false;
1500         }
1501 }
1502
1503
1504 /** @param start Start position in model coordinates.
1505  *  @param end End position in model coordinates.
1506  *  @param op 0 = cut, 1 = copy, 2 = clear.
1507  */
1508 boost::shared_ptr<ControlList>
1509 ControlList::cut_copy_clear (double start, double end, int op)
1510 {
1511         boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
1512         iterator s, e;
1513         ControlEvent cp (start, 0.0);
1514
1515         {
1516                 Glib::Threads::RWLock::WriterLock lm (_lock);
1517
1518                 /* first, determine s & e, two iterators that define the range of points
1519                    affected by this operation
1520                 */
1521
1522                 if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
1523                         return nal;
1524                 }
1525
1526                 /* and the last that is at or after `end' */
1527                 cp.when = end;
1528                 e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1529
1530
1531                 /* if "start" isn't the location of an existing point,
1532                    evaluate the curve to get a value for the start. Add a point to
1533                    both the existing event list, and if its not a "clear" operation,
1534                    to the copy ("nal") as well.
1535
1536                    Note that the time positions of the points in each list are different
1537                    because we want the copy ("nal") to have a zero time reference.
1538                 */
1539
1540
1541                 /* before we begin any cut/clear operations, get the value of the curve
1542                    at "end".
1543                 */
1544
1545                 double end_value = unlocked_eval (end);
1546
1547                 if ((*s)->when != start) {
1548
1549                         double val = unlocked_eval (start);
1550
1551                         if (op == 0) { // cut
1552                                 if (start > _events.front()->when) {
1553                                         _events.insert (s, (new ControlEvent (start, val)));
1554                                 }
1555                         }
1556
1557                         if (op != 2) { // ! clear
1558                                 nal->_events.push_back (new ControlEvent (0, val));
1559                         }
1560                 }
1561
1562                 for (iterator x = s; x != e; ) {
1563
1564                         /* adjust new points to be relative to start, which
1565                            has been set to zero.
1566                         */
1567
1568                         if (op != 2) {
1569                                 nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
1570                         }
1571
1572                         if (op != 1) {
1573                                 x = _events.erase (x);
1574                         } else {
1575                                 ++x;
1576                         }
1577                 }
1578
1579                 if (e == _events.end() || (*e)->when != end) {
1580
1581                         /* only add a boundary point if there is a point after "end"
1582                          */
1583
1584                         if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut
1585                                 _events.insert (e, new ControlEvent (end, end_value));
1586                         }
1587
1588                         if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
1589                                 nal->_events.push_back (new ControlEvent (end - start, end_value));
1590                         }
1591                 }
1592
1593                 unlocked_invalidate_insert_iterator ();
1594                 mark_dirty ();
1595         }
1596
1597         if (op != 1) {
1598                 maybe_signal_changed ();
1599         }
1600
1601         return nal;
1602 }
1603
1604
1605 boost::shared_ptr<ControlList>
1606 ControlList::cut (double start, double end)
1607 {
1608         return cut_copy_clear (start, end, 0);
1609 }
1610
1611 boost::shared_ptr<ControlList>
1612 ControlList::copy (double start, double end)
1613 {
1614         return cut_copy_clear (start, end, 1);
1615 }
1616
1617 void
1618 ControlList::clear (double start, double end)
1619 {
1620         cut_copy_clear (start, end, 2);
1621 }
1622
1623 /** @param pos Position in model coordinates */
1624 bool
1625 ControlList::paste (const ControlList& alist, double pos, float /*times*/)
1626 {
1627         if (alist._events.empty()) {
1628                 return false;
1629         }
1630
1631         {
1632                 Glib::Threads::RWLock::WriterLock lm (_lock);
1633                 iterator where;
1634                 iterator prev;
1635                 double end = 0;
1636                 ControlEvent cp (pos, 0.0);
1637
1638                 where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1639
1640                 for (const_iterator i = alist.begin();i != alist.end(); ++i) {
1641                         double value = (*i)->value;
1642                         if (alist.parameter() != parameter()) {
1643                                 const ParameterDescriptor& src_desc = alist.descriptor();
1644
1645                                 value -= src_desc.lower;  // translate to 0-relative
1646                                 value /= (src_desc.upper - src_desc.lower);  // normalize range
1647                                 value *= (_desc.upper - _desc.lower);  // scale to our range
1648                                 value += _desc.lower;  // translate to our offset
1649                         }
1650                         _events.insert (where, new ControlEvent((*i)->when + pos, value));
1651                         end = (*i)->when + pos;
1652                 }
1653
1654
1655                 /* move all  points after the insertion along the timeline by
1656                    the correct amount.
1657                 */
1658
1659                 while (where != _events.end()) {
1660                         iterator tmp;
1661                         if ((*where)->when <= end) {
1662                                 tmp = where;
1663                                 ++tmp;
1664                                 _events.erase(where);
1665                                 where = tmp;
1666
1667                         } else {
1668                                 break;
1669                         }
1670                 }
1671
1672                 unlocked_invalidate_insert_iterator ();
1673                 mark_dirty ();
1674         }
1675
1676         maybe_signal_changed ();
1677         return true;
1678 }
1679
1680 /** Move automation around according to a list of region movements.
1681  *  @param return true if anything was changed, otherwise false (ie nothing needed changing)
1682  */
1683 bool
1684 ControlList::move_ranges (const list< RangeMove<double> >& movements)
1685 {
1686         typedef list< RangeMove<double> > RangeMoveList;
1687
1688         {
1689                 Glib::Threads::RWLock::WriterLock lm (_lock);
1690
1691                 /* a copy of the events list before we started moving stuff around */
1692                 EventList old_events = _events;
1693
1694                 /* clear the source and destination ranges in the new list */
1695                 bool things_erased = false;
1696                 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1697
1698                         if (erase_range_internal (i->from, i->from + i->length, _events)) {
1699                                 things_erased = true;
1700                         }
1701
1702                         if (erase_range_internal (i->to, i->to + i->length, _events)) {
1703                                 things_erased = true;
1704                         }
1705                 }
1706
1707                 /* if nothing was erased, there is nothing to do */
1708                 if (!things_erased) {
1709                         return false;
1710                 }
1711
1712                 /* copy the events into the new list */
1713                 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1714                         iterator j = old_events.begin ();
1715                         const double limit = i->from + i->length;
1716                         const double dx    = i->to - i->from;
1717                         while (j != old_events.end () && (*j)->when <= limit) {
1718                                 if ((*j)->when >= i->from) {
1719                                         ControlEvent* ev = new ControlEvent (**j);
1720                                         ev->when += dx;
1721                                         _events.push_back (ev);
1722                                 }
1723                                 ++j;
1724                         }
1725                 }
1726
1727                 if (!_frozen) {
1728                         _events.sort (event_time_less_than);
1729                         unlocked_invalidate_insert_iterator ();
1730                 } else {
1731                         _sort_pending = true;
1732                 }
1733
1734                 mark_dirty ();
1735         }
1736
1737         maybe_signal_changed ();
1738         return true;
1739 }
1740
1741 void
1742 ControlList::set_interpolation (InterpolationStyle s)
1743 {
1744         if (_interpolation == s) {
1745                 return;
1746         }
1747
1748         _interpolation = s;
1749         InterpolationChanged (s); /* EMIT SIGNAL */
1750 }
1751
1752 bool
1753 ControlList::operator!= (ControlList const & other) const
1754 {
1755         if (_events.size() != other._events.size()) {
1756                 return true;
1757         }
1758
1759         EventList::const_iterator i = _events.begin ();
1760         EventList::const_iterator j = other._events.begin ();
1761
1762         while (i != _events.end() && (*i)->when == (*j)->when && (*i)->value == (*j)->value) {
1763                 ++i;
1764                 ++j;
1765         }
1766
1767         if (i != _events.end ()) {
1768                 return true;
1769         }
1770         
1771         return (
1772                 _parameter != other._parameter ||
1773                 _interpolation != other._interpolation ||
1774                 _min_yval != other._min_yval ||
1775                 _max_yval != other._max_yval ||
1776                 _default_value != other._default_value
1777                 );
1778 }
1779
1780 void
1781 ControlList::dump (ostream& o)
1782 {
1783         /* NOT LOCKED ... for debugging only */
1784
1785         for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
1786                 o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl;
1787         }
1788 }
1789
1790 } // namespace Evoral
1791