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