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