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