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