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