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