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