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