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