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