63492b375b7f93b2d5586209183cfd17010446e5
[ardour.git] / libs / ardour / automation_event.cc
1 /*
2     Copyright (C) 2002 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <set>
22 #include <climits>
23 #include <float.h>
24 #include <cmath>
25 #include <algorithm>
26 #include <sigc++/bind.h>
27 #include <ardour/automation_event.h>
28
29 #include "i18n.h"
30
31 using namespace std;
32 using namespace ARDOUR;
33 using namespace sigc;
34 using namespace PBD;
35
36 #if 0
37 static void dumpit (const AutomationList& al, string prefix = "")
38 {
39         cerr << prefix << &al << endl;
40         for (AutomationList::const_iterator i = al.const_begin(); i != al.const_end(); ++i) {
41                 cerr << prefix << '\t' << (*i)->when << ',' << (*i)->value << endl;
42         }
43         cerr << "\n";
44 }
45 #endif
46
47 AutomationList::AutomationList (double defval, bool with_state)
48 {
49         _frozen = false;
50         changed_when_thawed = false;
51         _state = Off;
52         _style = Absolute;
53         _touching = false;
54         no_state = with_state;
55         min_yval = FLT_MIN;
56         max_yval = FLT_MAX;
57         max_xval = 0; // means "no limit" 
58         default_value = defval;
59         _dirty = false;
60         rt_insertion_point = events.end();
61         lookup_cache.left = -1;
62         lookup_cache.range.first = events.end();
63
64         if (!no_state) {
65                 save_state (_("initial"));
66         }
67 }
68
69 AutomationList::AutomationList (const AutomationList& other)
70 {
71         _frozen = false;
72         changed_when_thawed = false;
73         _style = other._style;
74         min_yval = other.min_yval;
75         max_yval = other.max_yval;
76         max_xval = other.max_xval;
77         default_value = other.default_value;
78         _state = other._state;
79         _touching = other._touching;
80         _dirty = false;
81         rt_insertion_point = events.end();
82         no_state = other.no_state;
83         lookup_cache.left = -1;
84         lookup_cache.range.first = events.end();
85
86         for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
87                 /* we have to use other point_factory() because
88                    its virtual and we're in a constructor.
89                 */
90                 events.push_back (other.point_factory (**i));
91         }
92
93         mark_dirty ();
94 }
95
96 AutomationList::AutomationList (const AutomationList& other, double start, double end)
97 {
98         _frozen = false;
99         changed_when_thawed = false;
100         _style = other._style;
101         min_yval = other.min_yval;
102         max_yval = other.max_yval;
103         max_xval = other.max_xval;
104         default_value = other.default_value;
105         _state = other._state;
106         _touching = other._touching;
107         _dirty = false;
108         rt_insertion_point = events.end();
109         no_state = other.no_state;
110         lookup_cache.left = -1;
111         lookup_cache.range.first = events.end();
112
113         /* now grab the relevant points, and shift them back if necessary */
114
115         AutomationList* section = const_cast<AutomationList*>(&other)->copy (start, end);
116
117         if (!section->empty()) {
118                 for (AutomationList::iterator i = section->begin(); i != section->end(); ++i) {
119                         events.push_back (other.point_factory ((*i)->when, (*i)->value));
120                 }
121         }
122
123         delete section;
124
125         mark_dirty ();
126 }
127
128 AutomationList::~AutomationList()
129 {
130         std::set<ControlEvent*> all_events;
131         AutomationList::State* asp;
132
133         for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) {
134                 all_events.insert (*x);
135         }
136
137         for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
138
139                 if ((asp = dynamic_cast<AutomationList::State*> (*i)) != 0) {
140                         
141                         for (AutomationEventList::iterator x = asp->events.begin(); x != asp->events.end(); ++x) {
142                                 all_events.insert (*x);
143                         }
144                 }
145         }
146
147         for (std::set<ControlEvent*>::iterator i = all_events.begin(); i != all_events.end(); ++i) {
148                 delete (*i);
149         }
150 }
151
152 bool
153 AutomationList::operator== (const AutomationList& other)
154 {
155         return events == other.events;
156 }
157
158 AutomationList&
159 AutomationList::operator= (const AutomationList& other)
160 {
161         if (this != &other) {
162                 
163                 events.clear ();
164                 
165                 for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
166                         events.push_back (point_factory (**i));
167                 }
168                 
169                 min_yval = other.min_yval;
170                 max_yval = other.max_yval;
171                 max_xval = other.max_xval;
172                 default_value = other.default_value;
173                 
174                 mark_dirty ();
175                 maybe_signal_changed ();
176         }
177
178         return *this;
179 }
180
181 void
182 AutomationList::maybe_signal_changed ()
183 {
184         mark_dirty ();
185
186         if (_frozen) {
187                 changed_when_thawed = true;
188         } else {
189                 StateChanged (Change (0));
190         }
191 }
192
193 void
194 AutomationList::set_automation_state (AutoState s)
195 {
196         if (s != _state) {
197                 _state = s;
198                 automation_state_changed (); /* EMIT SIGNAL */
199         }
200 }
201
202 void
203 AutomationList::set_automation_style (AutoStyle s)
204 {
205         if (s != _style) {
206                 _style = s;
207                 automation_style_changed (); /* EMIT SIGNAL */
208         }
209 }
210
211 void
212 AutomationList::start_touch ()
213 {
214         _touching = true;
215         _new_touch = true;
216 }
217
218 void
219 AutomationList::stop_touch ()
220 {
221         _touching = false;
222         _new_touch = false;
223 }
224
225 void
226 AutomationList::clear ()
227 {
228         {
229                 Glib::Mutex::Lock lm (lock);
230                 events.clear ();
231                 if (!no_state) {
232                         save_state (_("cleared"));
233                 }
234                 mark_dirty ();
235         }
236
237         maybe_signal_changed ();
238 }
239
240 void
241 AutomationList::x_scale (double factor)
242 {
243         Glib::Mutex::Lock lm (lock);
244         _x_scale (factor);
245 }
246
247 bool
248 AutomationList::extend_to (double when)
249 {
250         Glib::Mutex::Lock lm (lock);
251         if (events.empty() || events.back()->when == when) {
252                 return false;
253         }
254         double factor = when / events.back()->when;
255         _x_scale (factor);
256         return true;
257 }
258
259 void AutomationList::_x_scale (double factor)
260 {
261         for (AutomationList::iterator i = events.begin(); i != events.end(); ++i) {
262                 (*i)->when = floor ((*i)->when * factor);
263         }
264
265         save_state ("x-scaled");
266         mark_dirty ();
267 }
268
269 void
270 AutomationList::reposition_for_rt_add (double when)
271 {
272         rt_insertion_point = events.end();
273 }
274
275 #define last_rt_insertion_point rt_insertion_point
276
277 void
278 AutomationList::rt_add (double when, double value)
279 {
280         /* this is for automation recording */
281
282         if ((_state & Touch) && !_touching) {
283                 return;
284         }
285
286         // cerr << "RT: alist @ " << this << " add " << value << " @ " << when << endl;
287
288         {
289                 Glib::Mutex::Lock lm (lock);
290
291                 iterator where;
292                 TimeComparator cmp;
293                 ControlEvent cp (when, 0.0);
294                 bool done = false;
295
296                 if ((last_rt_insertion_point != events.end()) && ((*last_rt_insertion_point)->when < when) ) {
297
298                         /* we have a previous insertion point, so we should delete
299                            everything between it and the position where we are going
300                            to insert this point.
301                         */
302
303                         iterator after = last_rt_insertion_point;
304
305                         if (++after != events.end()) {
306                                 iterator far = after;
307
308                                 while (far != events.end()) {
309                                         if ((*far)->when > when) {
310                                                 break;
311                                         }
312                                         ++far;
313                                 }
314
315                                 if(_new_touch) {
316                                         where = far;
317                                         last_rt_insertion_point = where;
318                                                                                              
319                                         if((*where)->when == when) {
320                                                 (*where)->value = value;
321                                                 done = true;
322                                         }
323                                 } else {
324                                         where = events.erase (after, far);
325                                 }
326
327                         } else {
328
329                                 where = after;
330
331                         }
332                         
333                         iterator previous = last_rt_insertion_point;
334                         --previous;
335                         
336                         if (last_rt_insertion_point != events.begin() && (*last_rt_insertion_point)->value == value && (*previous)->value == value) {
337                                 (*last_rt_insertion_point)->when = when;
338                                 done = true;
339                                 
340                         }
341                         
342                 } else {
343
344                         where = lower_bound (events.begin(), events.end(), &cp, cmp);
345
346                         if (where != events.end()) {
347                                 if ((*where)->when == when) {
348                                         (*where)->value = value;
349                                         done = true;
350                                 }
351                         }
352                 }
353                 
354                 if (!done) {
355                         last_rt_insertion_point = events.insert (where, point_factory (when, value));
356                 }
357                 
358                 _new_touch = false;
359                 mark_dirty ();
360         }
361
362         maybe_signal_changed ();
363 }
364
365 #undef last_rt_insertion_point
366
367 void
368 AutomationList::add (double when, double value, bool for_loading)
369 {
370         /* this is for graphical editing and loading data from storage */
371
372         {
373                 Glib::Mutex::Lock lm (lock);
374                 TimeComparator cmp;
375                 ControlEvent cp (when, 0.0f);
376                 bool insert = true;
377                 iterator insertion_point;
378
379                 for (insertion_point = lower_bound (events.begin(), events.end(), &cp, cmp); insertion_point != events.end(); ++insertion_point) {
380
381                         /* only one point allowed per time point */
382
383                         if ((*insertion_point)->when == when) {
384                                 (*insertion_point)->value = value;
385                                 insert = false;
386                                 break;
387                         } 
388
389                         if ((*insertion_point)->when >= when) {
390                                 break;
391                         }
392                 }
393
394                 if (insert) {
395
396                         events.insert (insertion_point, point_factory (when, value));
397                         reposition_for_rt_add (0);
398
399                 } 
400
401                 mark_dirty ();
402
403                 if (!no_state && !for_loading) {
404                         save_state (_("added event"));
405                 }
406         }
407
408         if (!for_loading) {
409                 maybe_signal_changed ();
410         }
411 }
412
413 void
414 AutomationList::erase (AutomationList::iterator i)
415 {
416         {
417                 Glib::Mutex::Lock lm (lock);
418                 events.erase (i);
419                 reposition_for_rt_add (0);
420                 if (!no_state) {
421                         save_state (_("removed event"));
422                 }
423                 mark_dirty ();
424         }
425         maybe_signal_changed ();
426 }
427
428 void
429 AutomationList::erase (AutomationList::iterator start, AutomationList::iterator end)
430 {
431         {
432                 Glib::Mutex::Lock lm (lock);
433                 events.erase (start, end);
434                 reposition_for_rt_add (0);
435                 if (!no_state) {
436                         save_state (_("removed multiple events"));
437                 }
438                 mark_dirty ();
439         }
440         maybe_signal_changed ();
441 }       
442
443 void
444 AutomationList::reset_range (double start, double endt)
445 {
446         bool reset = false;
447
448         {
449         Glib::Mutex::Lock lm (lock);
450                 TimeComparator cmp;
451                 ControlEvent cp (start, 0.0f);
452                 iterator s;
453                 iterator e;
454                 
455                 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) != events.end()) {
456
457                         cp.when = endt;
458                         e = upper_bound (events.begin(), events.end(), &cp, cmp);
459
460                         for (iterator i = s; i != e; ++i) {
461                                 (*i)->value = default_value;
462                         }
463                         
464                         reset = true;
465
466                         if (!no_state) {
467                                 save_state (_("removed range"));
468                         }
469
470                         mark_dirty ();
471                 }
472         }
473
474         if (reset) {
475                 maybe_signal_changed ();
476         }
477 }
478
479 void
480 AutomationList::erase_range (double start, double endt)
481 {
482         bool erased = false;
483
484         {
485                 Glib::Mutex::Lock lm (lock);
486                 TimeComparator cmp;
487                 ControlEvent cp (start, 0.0f);
488                 iterator s;
489                 iterator e;
490
491                 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) != events.end()) {
492                         cp.when = endt;
493                         e = upper_bound (events.begin(), events.end(), &cp, cmp);
494                         events.erase (s, e);
495                         reposition_for_rt_add (0);
496                         erased = true;
497                         if (!no_state) {
498                                 save_state (_("removed range"));
499                         }
500                         mark_dirty ();
501                 }
502                 
503         }
504
505         if (erased) {
506                 maybe_signal_changed ();
507         }
508 }
509
510 void
511 AutomationList::move_range (iterator start, iterator end, double xdelta, double ydelta)
512 {
513         /* note: we assume higher level logic is in place to avoid this
514            reordering the time-order of control events in the list. ie. all
515            points after end are later than (end)->when.
516         */
517
518         {
519                 Glib::Mutex::Lock lm (lock);
520
521                 while (start != end) {
522                         (*start)->when += xdelta;
523                         (*start)->value += ydelta;
524                         ++start;
525                 }
526
527                 if (!no_state) {
528                         save_state (_("event range adjusted"));
529                 }
530
531                 mark_dirty ();
532         }
533
534         maybe_signal_changed ();
535 }
536
537 void
538 AutomationList::modify (iterator iter, double when, double val)
539 {
540         /* note: we assume higher level logic is in place to avoid this
541            reordering the time-order of control events in the list. ie. all
542            points after *iter are later than when.
543         */
544
545         {
546                 Glib::Mutex::Lock lm (lock);
547                 (*iter)->when = when;
548                 (*iter)->value = val;
549                 if (!no_state) {
550                         save_state (_("event adjusted"));
551                 }
552
553                 mark_dirty ();
554         }
555         
556         maybe_signal_changed ();
557 }
558
559 std::pair<AutomationList::iterator,AutomationList::iterator>
560 AutomationList::control_points_adjacent (double xval)
561 {
562         Glib::Mutex::Lock lm (lock);
563         iterator i;
564         TimeComparator cmp;
565         ControlEvent cp (xval, 0.0f);
566         std::pair<iterator,iterator> ret;
567
568         ret.first = events.end();
569         ret.second = events.end();
570
571         for (i = lower_bound (events.begin(), events.end(), &cp, cmp); i != events.end(); ++i) {
572                 
573                 if (ret.first == events.end()) {
574                         if ((*i)->when >= xval) {
575                                 if (i != events.begin()) {
576                                         ret.first = i;
577                                         --ret.first;
578                                 } else {
579                                         return ret;
580                                 }
581                         }
582                 } 
583                 
584                 if ((*i)->when > xval) {
585                         ret.second = i;
586                         break;
587                 }
588         }
589
590         return ret;
591 }
592
593 void
594 AutomationList::freeze ()
595 {
596         _frozen = true;
597 }
598
599 void
600 AutomationList::thaw ()
601 {
602         _frozen = false;
603         if (changed_when_thawed) {
604                  StateChanged(Change(0)); /* EMIT SIGNAL */
605         }
606 }
607
608 StateManager::State*
609 AutomationList::state_factory (std::string why) const
610 {
611         State* state = new State (why);
612
613         for (AutomationEventList::const_iterator x = events.begin(); x != events.end(); ++x) {
614                 state->events.push_back (point_factory (**x));
615         }
616
617         return state;
618 }
619
620 Change
621 AutomationList::restore_state (StateManager::State& state) 
622 {
623         {
624                 Glib::Mutex::Lock lm (lock);
625                 State* lstate = dynamic_cast<State*> (&state);
626
627                 events.clear ();
628                 for (AutomationEventList::const_iterator x = lstate->events.begin(); x != lstate->events.end(); ++x) {
629                         events.push_back (point_factory (**x));
630                 }
631         }
632
633         return Change (0);
634 }
635
636 UndoAction
637 AutomationList::get_memento () const
638 {
639   return sigc::bind (mem_fun (*(const_cast<AutomationList*> (this)), &StateManager::use_state), _current_state_id);
640 }
641
642 void
643 AutomationList::set_max_xval (double x)
644 {
645         max_xval = x;
646 }
647
648 void 
649 AutomationList::mark_dirty ()
650 {
651         lookup_cache.left = -1;
652         _dirty = true;
653 }
654
655 void
656 AutomationList::truncate_end (double last_coordinate)
657 {
658         {
659                 Glib::Mutex::Lock lm (lock);
660                 ControlEvent cp (last_coordinate, 0);
661                 list<ControlEvent*>::reverse_iterator i;
662                 double last_val;
663
664                 if (events.empty()) {
665                         fatal << _("programming error:")
666                               << "AutomationList::truncate_end() called on an empty list"
667                               << endmsg;
668                         /*NOTREACHED*/
669                         return;
670                 }
671
672                 if (last_coordinate == events.back()->when) {
673                         return;
674                 }
675
676                 if (last_coordinate > events.back()->when) {
677                         
678                         /* extending end:
679                         */
680
681                         iterator foo = events.begin();
682                         bool lessthantwo;
683
684                         if (foo == events.end()) {
685                                 lessthantwo = true;
686                         } else if (++foo == events.end()) {
687                                 lessthantwo = true;
688                         } else {
689                                 lessthantwo = false;
690                         }
691
692                         if (lessthantwo) {
693                                 /* less than 2 points: add a new point */
694                                 events.push_back (point_factory (last_coordinate, events.back()->value));
695                         } else {
696
697                                 /* more than 2 points: check to see if the last 2 values
698                                    are equal. if so, just move the position of the
699                                    last point. otherwise, add a new point.
700                                 */
701
702                                 iterator penultimate = events.end();
703                                 --penultimate; /* points at last point */
704                                 --penultimate; /* points at the penultimate point */
705                                 
706                                 if (events.back()->value == (*penultimate)->value) {
707                                         events.back()->when = last_coordinate;
708                                 } else {
709                                         events.push_back (point_factory (last_coordinate, events.back()->value));
710                                 }
711                         }
712
713                 } else {
714
715                         /* shortening end */
716
717                         last_val = unlocked_eval (last_coordinate);
718                         last_val = max ((double) min_yval, last_val);
719                         last_val = min ((double) max_yval, last_val);
720                         
721                         i = events.rbegin();
722                         
723                         /* make i point to the last control point */
724                         
725                         ++i;
726                         
727                         /* now go backwards, removing control points that are
728                            beyond the new last coordinate.
729                         */
730
731                         uint32_t sz = events.size();
732                         
733                         while (i != events.rend() && sz > 2) {
734                                 list<ControlEvent*>::reverse_iterator tmp;
735                                 
736                                 tmp = i;
737                                 ++tmp;
738                                 
739                                 if ((*i)->when < last_coordinate) {
740                                         break;
741                                 }
742                                 
743                                 events.erase (i.base());
744                                 --sz;
745
746                                 i = tmp;
747                         }
748                         
749                         events.back()->when = last_coordinate;
750                         events.back()->value = last_val;
751                 }
752
753                 reposition_for_rt_add (0);
754                 mark_dirty();
755         }
756
757         maybe_signal_changed ();
758 }
759
760 void
761 AutomationList::truncate_start (double overall_length)
762 {
763         {
764                 Glib::Mutex::Lock lm (lock);
765                 AutomationList::iterator i;
766                 double first_legal_value;
767                 double first_legal_coordinate;
768
769                 if (events.empty()) {
770                         fatal << _("programming error:")
771                               << "AutomationList::truncate_start() called on an empty list"
772                               << endmsg;
773                         /*NOTREACHED*/
774                         return;
775                 }
776                 
777                 if (overall_length == events.back()->when) {
778                         /* no change in overall length */
779                         return;
780                 }
781                 
782                 if (overall_length > events.back()->when) {
783                         
784                         /* growing at front: duplicate first point. shift all others */
785
786                         double shift = overall_length - events.back()->when;
787                         uint32_t np;
788
789                         for (np = 0, i = events.begin(); i != events.end(); ++i, ++np) {
790                                 (*i)->when += shift;
791                         }
792
793                         if (np < 2) {
794
795                                 /* less than 2 points: add a new point */
796                                 events.push_front (point_factory (0, events.front()->value));
797
798                         } else {
799
800                                 /* more than 2 points: check to see if the first 2 values
801                                    are equal. if so, just move the position of the
802                                    first point. otherwise, add a new point.
803                                 */
804
805                                 iterator second = events.begin();
806                                 ++second; /* points at the second point */
807                                 
808                                 if (events.front()->value == (*second)->value) {
809                                         /* first segment is flat, just move start point back to zero */
810                                         events.front()->when = 0;
811                                 } else {
812                                         /* leave non-flat segment in place, add a new leading point. */
813                                         events.push_front (point_factory (0, events.front()->value));
814                                 }
815                         }
816
817                 } else {
818
819                         /* shrinking at front */
820                         
821                         first_legal_coordinate = events.back()->when - overall_length;
822                         first_legal_value = unlocked_eval (first_legal_coordinate);
823                         first_legal_value = max (min_yval, first_legal_value);
824                         first_legal_value = min (max_yval, first_legal_value);
825
826                         /* remove all events earlier than the new "front" */
827
828                         i = events.begin();
829                         
830                         while (i != events.end() && !events.empty()) {
831                                 list<ControlEvent*>::iterator tmp;
832                                 
833                                 tmp = i;
834                                 ++tmp;
835                                 
836                                 if ((*i)->when > first_legal_coordinate) {
837                                         break;
838                                 }
839                                 
840                                 events.erase (i);
841                                 
842                                 i = tmp;
843                         }
844                         
845
846                         /* shift all remaining points left to keep their same
847                            relative position
848                         */
849                         
850                         for (i = events.begin(); i != events.end(); ++i) {
851                                 (*i)->when -= first_legal_coordinate;
852                         }
853
854                         /* add a new point for the interpolated new value */
855                         
856                         events.push_front (point_factory (0, first_legal_value));
857                 }           
858
859                 reposition_for_rt_add (0);
860
861                 mark_dirty();
862         }
863
864         maybe_signal_changed ();
865 }
866
867 double
868 AutomationList::unlocked_eval (double x)
869 {
870         return shared_eval (x);
871 }
872
873 double
874 AutomationList::shared_eval (double x) 
875 {
876         pair<AutomationEventList::iterator,AutomationEventList::iterator> range;
877         int32_t npoints;
878         double lpos, upos;
879         double lval, uval;
880         double fraction;
881
882         npoints = events.size();
883
884         switch (npoints) {
885         case 0:
886                 return default_value;
887
888         case 1:
889                 if (x >= events.front()->when) {
890                         return events.front()->value;
891                 } else {
892                         // return default_value;
893                         return events.front()->value;
894                 } 
895                 
896         case 2:
897                 if (x >= events.back()->when) {
898                         return events.back()->value;
899                 } else if (x == events.front()->when) {
900                         return events.front()->value;
901                 } else if (x < events.front()->when) {
902                         // return default_value;
903                         return events.front()->value;
904                 }
905
906                 lpos = events.front()->when;
907                 lval = events.front()->value;
908                 upos = events.back()->when;
909                 uval = events.back()->value;
910                 
911                 /* linear interpolation betweeen the two points
912                 */
913
914                 fraction = (double) (x - lpos) / (double) (upos - lpos);
915                 return lval + (fraction * (uval - lval));
916
917         default:
918
919                 if (x >= events.back()->when) {
920                         return events.back()->value;
921                 } else if (x == events.front()->when) {
922                         return events.front()->value;
923                 } else if (x < events.front()->when) {
924                         // return default_value;
925                         return events.front()->value;
926                 }
927
928                 return multipoint_eval (x);
929                 break;
930         }
931 }
932
933 double
934 AutomationList::multipoint_eval (double x) 
935 {
936         pair<AutomationList::iterator,AutomationList::iterator> range;
937         double upos, lpos;
938         double uval, lval;
939         double fraction;
940
941         /* only do the range lookup if x is in a different range than last time
942            this was called (or if the lookup cache has been marked "dirty" (left<0)
943         */
944
945         if ((lookup_cache.left < 0) ||
946             ((lookup_cache.left > x) || 
947              (lookup_cache.range.first == events.end()) || 
948              ((*lookup_cache.range.second)->when < x))) {
949
950                 ControlEvent cp (x, 0);
951                 TimeComparator cmp;
952                 
953                 lookup_cache.range = equal_range (events.begin(), events.end(), &cp, cmp);
954         }
955         
956         range = lookup_cache.range;
957
958         if (range.first == range.second) {
959
960                 /* x does not exist within the list as a control point */
961
962                 lookup_cache.left = x;
963
964                 if (range.first != events.begin()) {
965                         --range.first;
966                         lpos = (*range.first)->when;
967                         lval = (*range.first)->value;
968                 }  else {
969                         /* we're before the first point */
970                         // return default_value;
971                         return events.front()->value;
972                 }
973                 
974                 if (range.second == events.end()) {
975                         /* we're after the last point */
976                         return events.back()->value;
977                 }
978
979                 upos = (*range.second)->when;
980                 uval = (*range.second)->value;
981                 
982                 /* linear interpolation betweeen the two points
983                    on either side of x
984                 */
985
986                 fraction = (double) (x - lpos) / (double) (upos - lpos);
987                 return lval + (fraction * (uval - lval));
988
989         } 
990
991         /* x is a control point in the data */
992         lookup_cache.left = -1;
993         return (*range.first)->value;
994 }
995
996 AutomationList*
997 AutomationList::cut (iterator start, iterator end)
998 {
999         AutomationList* nal = new AutomationList (default_value);
1000
1001         {
1002                 Glib::Mutex::Lock lm (lock);
1003
1004                 for (iterator x = start; x != end; ) {
1005                         iterator tmp;
1006                         
1007                         tmp = x;
1008                         ++tmp;
1009                         
1010                         nal->events.push_back (point_factory (**x));
1011                         events.erase (x);
1012                         
1013                         reposition_for_rt_add (0);
1014
1015                         x = tmp;
1016                 }
1017
1018                 mark_dirty ();
1019         }
1020
1021         maybe_signal_changed ();
1022
1023         return nal;
1024 }
1025
1026 AutomationList*
1027 AutomationList::cut_copy_clear (double start, double end, int op)
1028 {
1029         AutomationList* nal = new AutomationList (default_value);
1030         iterator s, e;
1031         ControlEvent cp (start, 0.0);
1032         TimeComparator cmp;
1033         bool changed = false;
1034         
1035         {
1036                 Glib::Mutex::Lock lm (lock);
1037
1038                 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) == events.end()) {
1039                         return nal;
1040                 }
1041
1042                 cp.when = end;
1043                 e = upper_bound (events.begin(), events.end(), &cp, cmp);
1044
1045                 if (op != 2 && (*s)->when != start) {
1046                         nal->events.push_back (point_factory (0, unlocked_eval (start)));
1047                 }
1048
1049                 for (iterator x = s; x != e; ) {
1050                         iterator tmp;
1051                         
1052                         tmp = x;
1053                         ++tmp;
1054
1055                         changed = true;
1056                         
1057                         /* adjust new points to be relative to start, which
1058                            has been set to zero.
1059                         */
1060                         
1061                         if (op != 2) {
1062                                 nal->events.push_back (point_factory ((*x)->when - start, (*x)->value));
1063                         }
1064
1065                         if (op != 1) {
1066                                 events.erase (x);
1067                         }
1068                         
1069                         x = tmp;
1070                 }
1071
1072                 if (op != 2 && nal->events.back()->when != end - start) {
1073                         nal->events.push_back (point_factory (end - start, unlocked_eval (end)));
1074                 }
1075
1076                 if (changed) {
1077                         reposition_for_rt_add (0);
1078                         if (!no_state) {
1079                                 save_state (_("cut/copy/clear"));
1080                         }
1081                 }
1082
1083                 mark_dirty ();
1084         }
1085
1086         maybe_signal_changed ();
1087
1088         return nal;
1089
1090 }
1091
1092 AutomationList*
1093 AutomationList::copy (iterator start, iterator end)
1094 {
1095         AutomationList* nal = new AutomationList (default_value);
1096
1097         {
1098                 Glib::Mutex::Lock lm (lock);
1099                 
1100                 for (iterator x = start; x != end; ) {
1101                         iterator tmp;
1102                         
1103                         tmp = x;
1104                         ++tmp;
1105                         
1106                         nal->events.push_back (point_factory (**x));
1107                         
1108                         x = tmp;
1109                 }
1110
1111                 if (!no_state) {
1112                         save_state (_("copy"));
1113                 }
1114         }
1115
1116         return nal;
1117 }
1118
1119 AutomationList*
1120 AutomationList::cut (double start, double end)
1121 {
1122         return cut_copy_clear (start, end, 0);
1123 }
1124
1125 AutomationList*
1126 AutomationList::copy (double start, double end)
1127 {
1128         return cut_copy_clear (start, end, 1);
1129 }
1130
1131 void
1132 AutomationList::clear (double start, double end)
1133 {
1134         (void) cut_copy_clear (start, end, 2);
1135 }
1136
1137 bool
1138 AutomationList::paste (AutomationList& alist, double pos, float times)
1139 {
1140         if (alist.events.empty()) {
1141                 return false;
1142         }
1143
1144         {
1145                 Glib::Mutex::Lock lm (lock);
1146                 iterator where;
1147                 iterator prev;
1148                 double end = 0;
1149                 ControlEvent cp (pos, 0.0);
1150                 TimeComparator cmp;
1151
1152                 where = upper_bound (events.begin(), events.end(), &cp, cmp);
1153
1154                 for (iterator i = alist.begin();i != alist.end(); ++i) {
1155                         events.insert (where, point_factory( (*i)->when+pos,( *i)->value));
1156                         end = (*i)->when + pos;
1157                 }
1158         
1159         
1160                 /* move all  points after the insertion along the timeline by 
1161                    the correct amount.
1162                 */
1163
1164                 while (where != events.end()) {
1165                         iterator tmp;
1166                         if ((*where)->when <= end) {
1167                                 tmp = where;
1168                                 ++tmp;
1169                                 events.erase(where);
1170                                 where = tmp;
1171
1172                         } else {
1173                                 break;
1174                         }
1175                 }
1176
1177                 reposition_for_rt_add (0);
1178
1179                 if (!no_state) {
1180                         save_state (_("paste"));
1181                 }
1182
1183                 mark_dirty ();
1184         }
1185
1186         maybe_signal_changed ();
1187         return true;
1188 }
1189
1190 ControlEvent*
1191 AutomationList::point_factory (double when, double val) const
1192 {
1193         return new ControlEvent (when, val);
1194 }
1195
1196 ControlEvent*
1197 AutomationList::point_factory (const ControlEvent& other) const
1198 {
1199         return new ControlEvent (other);
1200 }
1201
1202 void
1203 AutomationList::store_state (XMLNode& node) const
1204 {
1205         LocaleGuard lg (X_("POSIX"));
1206
1207         for (const_iterator i = const_begin(); i != const_end(); ++i) {
1208                 char buf[64];
1209                 
1210                 XMLNode *pointnode = new XMLNode ("point");
1211                 
1212                 snprintf (buf, sizeof (buf), "%" PRIu32, (jack_nframes_t) floor ((*i)->when));
1213                 pointnode->add_property ("x", buf);
1214                 snprintf (buf, sizeof (buf), "%.12g", (*i)->value);
1215                 pointnode->add_property ("y", buf);
1216
1217                 node.add_child_nocopy (*pointnode);
1218         }
1219 }
1220
1221 void
1222 AutomationList::load_state (const XMLNode& node)
1223 {
1224         const XMLNodeList& elist = node.children();
1225         XMLNodeConstIterator i;
1226         XMLProperty* prop;
1227         jack_nframes_t x;
1228         double y;
1229
1230         clear ();
1231         
1232         for (i = elist.begin(); i != elist.end(); ++i) {
1233                 
1234                 if ((prop = (*i)->property ("x")) == 0) {
1235                         error << _("automation list: no x-coordinate stored for control point (point ignored)") << endmsg;
1236                         continue;
1237                 }
1238                 x = atoi (prop->value().c_str());
1239                 
1240                 if ((prop = (*i)->property ("y")) == 0) {
1241                         error << _("automation list: no y-coordinate stored for control point (point ignored)") << endmsg;
1242                         continue;
1243                 }
1244                 y = atof (prop->value().c_str());
1245                 
1246                 add (x, y);
1247         }
1248 }