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