many small changes, see ardour-dev for more
[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 ();
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                         if (isnan ((*start)->value)) {
515                                 abort ();
516                         }
517                         ++start;
518                 }
519
520                 mark_dirty ();
521         }
522
523         maybe_signal_changed ();
524 }
525
526 void
527 AutomationList::modify (iterator iter, double when, double val)
528 {
529         /* note: we assume higher level logic is in place to avoid this
530            reordering the time-order of control events in the list. ie. all
531            points after *iter are later than when.
532         */
533
534         {
535                 Glib::Mutex::Lock lm (lock);
536                 (*iter)->when = when;
537                 (*iter)->value = val;
538                 if (isnan (val)) {
539                         abort ();
540                 }
541                 mark_dirty ();
542         }
543         
544         maybe_signal_changed ();
545 }
546
547 std::pair<AutomationList::iterator,AutomationList::iterator>
548 AutomationList::control_points_adjacent (double xval)
549 {
550         Glib::Mutex::Lock lm (lock);
551         iterator i;
552         TimeComparator cmp;
553         ControlEvent cp (xval, 0.0f);
554         std::pair<iterator,iterator> ret;
555
556         ret.first = events.end();
557         ret.second = events.end();
558
559         for (i = lower_bound (events.begin(), events.end(), &cp, cmp); i != events.end(); ++i) {
560                 
561                 if (ret.first == events.end()) {
562                         if ((*i)->when >= xval) {
563                                 if (i != events.begin()) {
564                                         ret.first = i;
565                                         --ret.first;
566                                 } else {
567                                         return ret;
568                                 }
569                         }
570                 } 
571                 
572                 if ((*i)->when > xval) {
573                         ret.second = i;
574                         break;
575                 }
576         }
577
578         return ret;
579 }
580
581 void
582 AutomationList::freeze ()
583 {
584         _frozen = true;
585 }
586
587 void
588 AutomationList::thaw ()
589 {
590         _frozen = false;
591         if (changed_when_thawed) {
592                 StateChanged(); /* EMIT SIGNAL */
593         }
594 }
595
596 void
597 AutomationList::set_max_xval (double x)
598 {
599         max_xval = x;
600 }
601
602 void 
603 AutomationList::mark_dirty ()
604 {
605         lookup_cache.left = -1;
606         _dirty = true;
607 }
608
609 void
610 AutomationList::truncate_end (double last_coordinate)
611 {
612         {
613                 Glib::Mutex::Lock lm (lock);
614                 ControlEvent cp (last_coordinate, 0);
615                 list<ControlEvent*>::reverse_iterator i;
616                 double last_val;
617
618                 if (events.empty()) {
619                         return;
620                 }
621
622                 if (last_coordinate == events.back()->when) {
623                         return;
624                 }
625
626                 if (last_coordinate > events.back()->when) {
627                         
628                         /* extending end:
629                         */
630
631                         iterator foo = events.begin();
632                         bool lessthantwo;
633
634                         if (foo == events.end()) {
635                                 lessthantwo = true;
636                         } else if (++foo == events.end()) {
637                                 lessthantwo = true;
638                         } else {
639                                 lessthantwo = false;
640                         }
641
642                         if (lessthantwo) {
643                                 /* less than 2 points: add a new point */
644                                 events.push_back (point_factory (last_coordinate, events.back()->value));
645                         } else {
646
647                                 /* more than 2 points: check to see if the last 2 values
648                                    are equal. if so, just move the position of the
649                                    last point. otherwise, add a new point.
650                                 */
651
652                                 iterator penultimate = events.end();
653                                 --penultimate; /* points at last point */
654                                 --penultimate; /* points at the penultimate point */
655                                 
656                                 if (events.back()->value == (*penultimate)->value) {
657                                         events.back()->when = last_coordinate;
658                                 } else {
659                                         events.push_back (point_factory (last_coordinate, events.back()->value));
660                                 }
661                         }
662
663                 } else {
664
665                         /* shortening end */
666
667                         last_val = unlocked_eval (last_coordinate);
668                         last_val = max ((double) min_yval, last_val);
669                         last_val = min ((double) max_yval, last_val);
670                         
671                         i = events.rbegin();
672                         
673                         /* make i point to the last control point */
674                         
675                         ++i;
676                         
677                         /* now go backwards, removing control points that are
678                            beyond the new last coordinate.
679                         */
680
681                         uint32_t sz = events.size();
682                         
683                         while (i != events.rend() && sz > 2) {
684                                 list<ControlEvent*>::reverse_iterator tmp;
685                                 
686                                 tmp = i;
687                                 ++tmp;
688                                 
689                                 if ((*i)->when < last_coordinate) {
690                                         break;
691                                 }
692                                 
693                                 events.erase (i.base());
694                                 --sz;
695
696                                 i = tmp;
697                         }
698                         
699                         events.back()->when = last_coordinate;
700                         events.back()->value = last_val;
701                 }
702
703                 reposition_for_rt_add (0);
704                 mark_dirty();
705         }
706
707         maybe_signal_changed ();
708 }
709
710 void
711 AutomationList::truncate_start (double overall_length)
712 {
713         {
714                 Glib::Mutex::Lock lm (lock);
715                 AutomationList::iterator i;
716                 double first_legal_value;
717                 double first_legal_coordinate;
718
719                 if (events.empty()) {
720                         fatal << _("programming error:")
721                               << "AutomationList::truncate_start() called on an empty list"
722                               << endmsg;
723                         /*NOTREACHED*/
724                         return;
725                 }
726                 
727                 if (overall_length == events.back()->when) {
728                         /* no change in overall length */
729                         return;
730                 }
731                 
732                 if (overall_length > events.back()->when) {
733                         
734                         /* growing at front: duplicate first point. shift all others */
735
736                         double shift = overall_length - events.back()->when;
737                         uint32_t np;
738
739                         for (np = 0, i = events.begin(); i != events.end(); ++i, ++np) {
740                                 (*i)->when += shift;
741                         }
742
743                         if (np < 2) {
744
745                                 /* less than 2 points: add a new point */
746                                 events.push_front (point_factory (0, events.front()->value));
747
748                         } else {
749
750                                 /* more than 2 points: check to see if the first 2 values
751                                    are equal. if so, just move the position of the
752                                    first point. otherwise, add a new point.
753                                 */
754
755                                 iterator second = events.begin();
756                                 ++second; /* points at the second point */
757                                 
758                                 if (events.front()->value == (*second)->value) {
759                                         /* first segment is flat, just move start point back to zero */
760                                         events.front()->when = 0;
761                                 } else {
762                                         /* leave non-flat segment in place, add a new leading point. */
763                                         events.push_front (point_factory (0, events.front()->value));
764                                 }
765                         }
766
767                 } else {
768
769                         /* shrinking at front */
770                         
771                         first_legal_coordinate = events.back()->when - overall_length;
772                         first_legal_value = unlocked_eval (first_legal_coordinate);
773                         first_legal_value = max (min_yval, first_legal_value);
774                         first_legal_value = min (max_yval, first_legal_value);
775
776                         /* remove all events earlier than the new "front" */
777
778                         i = events.begin();
779                         
780                         while (i != events.end() && !events.empty()) {
781                                 list<ControlEvent*>::iterator tmp;
782                                 
783                                 tmp = i;
784                                 ++tmp;
785                                 
786                                 if ((*i)->when > first_legal_coordinate) {
787                                         break;
788                                 }
789                                 
790                                 events.erase (i);
791                                 
792                                 i = tmp;
793                         }
794                         
795
796                         /* shift all remaining points left to keep their same
797                            relative position
798                         */
799                         
800                         for (i = events.begin(); i != events.end(); ++i) {
801                                 (*i)->when -= first_legal_coordinate;
802                         }
803
804                         /* add a new point for the interpolated new value */
805                         
806                         events.push_front (point_factory (0, first_legal_value));
807                 }           
808
809                 reposition_for_rt_add (0);
810
811                 mark_dirty();
812         }
813
814         maybe_signal_changed ();
815 }
816
817 double
818 AutomationList::unlocked_eval (double x)
819 {
820         return shared_eval (x);
821 }
822
823 double
824 AutomationList::shared_eval (double x) 
825 {
826         pair<AutomationEventList::iterator,AutomationEventList::iterator> range;
827         int32_t npoints;
828         double lpos, upos;
829         double lval, uval;
830         double fraction;
831
832         npoints = events.size();
833
834         switch (npoints) {
835         case 0:
836                 return default_value;
837
838         case 1:
839                 if (x >= events.front()->when) {
840                         return events.front()->value;
841                 } else {
842                         // return default_value;
843                         return events.front()->value;
844                 } 
845                 
846         case 2:
847                 if (x >= events.back()->when) {
848                         return events.back()->value;
849                 } else if (x == events.front()->when) {
850                         return events.front()->value;
851                 } else if (x < events.front()->when) {
852                         // return default_value;
853                         return events.front()->value;
854                 }
855
856                 lpos = events.front()->when;
857                 lval = events.front()->value;
858                 upos = events.back()->when;
859                 uval = events.back()->value;
860                 
861                 /* linear interpolation betweeen the two points
862                 */
863
864                 fraction = (double) (x - lpos) / (double) (upos - lpos);
865                 return lval + (fraction * (uval - lval));
866
867         default:
868
869                 if (x >= events.back()->when) {
870                         return events.back()->value;
871                 } else if (x == events.front()->when) {
872                         return events.front()->value;
873                 } else if (x < events.front()->when) {
874                         // return default_value;
875                         return events.front()->value;
876                 }
877
878                 return multipoint_eval (x);
879                 break;
880         }
881 }
882
883 double
884 AutomationList::multipoint_eval (double x) 
885 {
886         pair<AutomationList::iterator,AutomationList::iterator> range;
887         double upos, lpos;
888         double uval, lval;
889         double fraction;
890
891         /* only do the range lookup if x is in a different range than last time
892            this was called (or if the lookup cache has been marked "dirty" (left<0)
893         */
894
895         if ((lookup_cache.left < 0) ||
896             ((lookup_cache.left > x) || 
897              (lookup_cache.range.first == events.end()) || 
898              ((*lookup_cache.range.second)->when < x))) {
899
900                 ControlEvent cp (x, 0);
901                 TimeComparator cmp;
902                 
903                 lookup_cache.range = equal_range (events.begin(), events.end(), &cp, cmp);
904         }
905         
906         range = lookup_cache.range;
907
908         if (range.first == range.second) {
909
910                 /* x does not exist within the list as a control point */
911
912                 lookup_cache.left = x;
913
914                 if (range.first != events.begin()) {
915                         --range.first;
916                         lpos = (*range.first)->when;
917                         lval = (*range.first)->value;
918                 }  else {
919                         /* we're before the first point */
920                         // return default_value;
921                         return events.front()->value;
922                 }
923                 
924                 if (range.second == events.end()) {
925                         /* we're after the last point */
926                         return events.back()->value;
927                 }
928
929                 upos = (*range.second)->when;
930                 uval = (*range.second)->value;
931                 
932                 /* linear interpolation betweeen the two points
933                    on either side of x
934                 */
935
936                 fraction = (double) (x - lpos) / (double) (upos - lpos);
937                 return lval + (fraction * (uval - lval));
938
939         } 
940
941         /* x is a control point in the data */
942         lookup_cache.left = -1;
943         return (*range.first)->value;
944 }
945
946 AutomationList*
947 AutomationList::cut (iterator start, iterator end)
948 {
949         AutomationList* nal = new AutomationList (default_value);
950
951         {
952                 Glib::Mutex::Lock lm (lock);
953
954                 for (iterator x = start; x != end; ) {
955                         iterator tmp;
956                         
957                         tmp = x;
958                         ++tmp;
959                         
960                         nal->events.push_back (point_factory (**x));
961                         events.erase (x);
962                         
963                         reposition_for_rt_add (0);
964
965                         x = tmp;
966                 }
967
968                 mark_dirty ();
969         }
970
971         maybe_signal_changed ();
972
973         return nal;
974 }
975
976 AutomationList*
977 AutomationList::cut_copy_clear (double start, double end, int op)
978 {
979         AutomationList* nal = new AutomationList (default_value);
980         iterator s, e;
981         ControlEvent cp (start, 0.0);
982         TimeComparator cmp;
983         bool changed = false;
984         
985         {
986                 Glib::Mutex::Lock lm (lock);
987
988                 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) == events.end()) {
989                         return nal;
990                 }
991
992                 cp.when = end;
993                 e = upper_bound (events.begin(), events.end(), &cp, cmp);
994
995                 if (op != 2 && (*s)->when != start) {
996                         nal->events.push_back (point_factory (0, unlocked_eval (start)));
997                 }
998
999                 for (iterator x = s; x != e; ) {
1000                         iterator tmp;
1001                         
1002                         tmp = x;
1003                         ++tmp;
1004
1005                         changed = true;
1006                         
1007                         /* adjust new points to be relative to start, which
1008                            has been set to zero.
1009                         */
1010                         
1011                         if (op != 2) {
1012                                 nal->events.push_back (point_factory ((*x)->when - start, (*x)->value));
1013                         }
1014
1015                         if (op != 1) {
1016                                 events.erase (x);
1017                         }
1018                         
1019                         x = tmp;
1020                 }
1021
1022                 if (op != 2 && nal->events.back()->when != end - start) {
1023                         nal->events.push_back (point_factory (end - start, unlocked_eval (end)));
1024                 }
1025
1026                 if (changed) {
1027                         reposition_for_rt_add (0);
1028                 }
1029
1030                 mark_dirty ();
1031         }
1032
1033         maybe_signal_changed ();
1034
1035         return nal;
1036
1037 }
1038
1039 AutomationList*
1040 AutomationList::copy (iterator start, iterator end)
1041 {
1042         AutomationList* nal = new AutomationList (default_value);
1043
1044         {
1045                 Glib::Mutex::Lock lm (lock);
1046                 
1047                 for (iterator x = start; x != end; ) {
1048                         iterator tmp;
1049                         
1050                         tmp = x;
1051                         ++tmp;
1052                         
1053                         nal->events.push_back (point_factory (**x));
1054                         
1055                         x = tmp;
1056                 }
1057         }
1058
1059         return nal;
1060 }
1061
1062 AutomationList*
1063 AutomationList::cut (double start, double end)
1064 {
1065         return cut_copy_clear (start, end, 0);
1066 }
1067
1068 AutomationList*
1069 AutomationList::copy (double start, double end)
1070 {
1071         return cut_copy_clear (start, end, 1);
1072 }
1073
1074 void
1075 AutomationList::clear (double start, double end)
1076 {
1077         (void) cut_copy_clear (start, end, 2);
1078 }
1079
1080 bool
1081 AutomationList::paste (AutomationList& alist, double pos, float times)
1082 {
1083         if (alist.events.empty()) {
1084                 return false;
1085         }
1086
1087         {
1088                 Glib::Mutex::Lock lm (lock);
1089                 iterator where;
1090                 iterator prev;
1091                 double end = 0;
1092                 ControlEvent cp (pos, 0.0);
1093                 TimeComparator cmp;
1094
1095                 where = upper_bound (events.begin(), events.end(), &cp, cmp);
1096
1097                 for (iterator i = alist.begin();i != alist.end(); ++i) {
1098                         events.insert (where, point_factory( (*i)->when+pos,( *i)->value));
1099                         end = (*i)->when + pos;
1100                 }
1101         
1102         
1103                 /* move all  points after the insertion along the timeline by 
1104                    the correct amount.
1105                 */
1106
1107                 while (where != events.end()) {
1108                         iterator tmp;
1109                         if ((*where)->when <= end) {
1110                                 tmp = where;
1111                                 ++tmp;
1112                                 events.erase(where);
1113                                 where = tmp;
1114
1115                         } else {
1116                                 break;
1117                         }
1118                 }
1119
1120                 reposition_for_rt_add (0);
1121                 mark_dirty ();
1122         }
1123
1124         maybe_signal_changed ();
1125         return true;
1126 }
1127
1128 ControlEvent*
1129 AutomationList::point_factory (double when, double val) const
1130 {
1131         return new ControlEvent (when, val);
1132 }
1133
1134 ControlEvent*
1135 AutomationList::point_factory (const ControlEvent& other) const
1136 {
1137         return new ControlEvent (other);
1138 }
1139
1140 XMLNode&
1141 AutomationList::get_state ()
1142 {
1143         return state (true);
1144 }
1145
1146 XMLNode&
1147 AutomationList::state (bool full)
1148 {
1149         XMLNode* root = new XMLNode (X_("AutomationList"));
1150         char buf[64];
1151         LocaleGuard lg (X_("POSIX"));
1152
1153         root->add_property ("id", _id.to_s());
1154
1155         snprintf (buf, sizeof (buf), "%.12g", default_value);
1156         root->add_property ("default", buf);
1157         snprintf (buf, sizeof (buf), "%.12g", min_yval);
1158         root->add_property ("min_yval", buf);
1159         snprintf (buf, sizeof (buf), "%.12g", max_yval);
1160         root->add_property ("max_yval", buf);
1161         snprintf (buf, sizeof (buf), "%.12g", max_xval);
1162         root->add_property ("max_xval", buf);
1163
1164         if (full) {
1165                 root->add_property ("state", auto_state_to_string (_state));
1166         } else {
1167                 /* never save anything but Off for automation state to a template */
1168                 root->add_property ("state", auto_state_to_string (Off));
1169         }
1170
1171         root->add_property ("style", auto_style_to_string (_style));
1172
1173         if (!events.empty()) {
1174                 root->add_child_nocopy (serialize_events());
1175         }
1176
1177         return *root;
1178 }
1179
1180 XMLNode&
1181 AutomationList::serialize_events ()
1182 {
1183         XMLNode* node = new XMLNode (X_("events"));
1184         stringstream str;
1185
1186         for (iterator xx = events.begin(); xx != events.end(); ++xx) {
1187                 str << (double) (*xx)->when;
1188                 str << ' ';
1189                 str <<(double) (*xx)->value;
1190                 str << '\n';
1191         }
1192
1193         /* XML is a bit wierd */
1194
1195         XMLNode* content_node = new XMLNode (X_("foo")); /* it gets renamed by libxml when we set content */
1196         content_node->set_content (str.str());
1197
1198         node->add_child_nocopy (*content_node);
1199
1200         return *node;
1201 }
1202
1203 int
1204 AutomationList::deserialize_events (const XMLNode& node)
1205 {
1206         if (node.children().empty()) {
1207                 return -1;
1208         }
1209
1210         XMLNode* content_node = node.children().front();
1211
1212         if (content_node->content().empty()) {
1213                 return -1;
1214         }
1215
1216         freeze ();
1217         clear ();
1218         
1219         stringstream str (content_node->content());
1220         
1221         double x;
1222         double y;
1223         bool ok = true;
1224         
1225         while (str) {
1226                 str >> x;
1227                 if (!str) {
1228                         break;
1229                 }
1230                 str >> y;
1231                 if (!str) {
1232                         ok = false;
1233                         break;
1234                 }
1235                 fast_simple_add (x, y);
1236         }
1237         
1238         if (!ok) {
1239                 clear ();
1240                 error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg;
1241         } else {
1242                 mark_dirty ();
1243                 reposition_for_rt_add (0);
1244                 maybe_signal_changed ();
1245         }
1246
1247         thaw ();
1248
1249         return 0;
1250 }
1251
1252 int
1253 AutomationList::set_state (const XMLNode& node)
1254 {
1255         XMLNodeList nlist = node.children();
1256         XMLNode* nsos;
1257         XMLNodeIterator niter;
1258         const XMLProperty* prop;
1259
1260         if (node.name() == X_("events")) {
1261                 /* partial state setting*/
1262                 return deserialize_events (node);
1263         }
1264         
1265         if (node.name() == X_("Envelope") || node.name() == X_("FadeOut") || node.name() == X_("FadeIn")) {
1266
1267                 if ((nsos = node.child (X_("AutomationList")))) {
1268                         /* new school in old school clothing */
1269                         return set_state (*nsos);
1270                 }
1271
1272                 /* old school */
1273
1274                 const XMLNodeList& elist = node.children();
1275                 XMLNodeConstIterator i;
1276                 XMLProperty* prop;
1277                 jack_nframes_t x;
1278                 double y;
1279                 
1280                 freeze ();
1281                 clear ();
1282                 
1283                 for (i = elist.begin(); i != elist.end(); ++i) {
1284                         
1285                         if ((prop = (*i)->property ("x")) == 0) {
1286                                 error << _("automation list: no x-coordinate stored for control point (point ignored)") << endmsg;
1287                                 continue;
1288                         }
1289                         x = atoi (prop->value().c_str());
1290                         
1291                         if ((prop = (*i)->property ("y")) == 0) {
1292                                 error << _("automation list: no y-coordinate stored for control point (point ignored)") << endmsg;
1293                                 continue;
1294                         }
1295                         y = atof (prop->value().c_str());
1296                         
1297                         fast_simple_add (x, y);
1298                 }
1299                 
1300                 thaw ();
1301
1302                 return 0;
1303         }
1304
1305         if (node.name() != X_("AutomationList") ) {
1306                 error << string_compose (_("AutomationList: passed XML node called %1, not \"AutomationList\" - ignored"), node.name()) << endmsg;
1307                 return -1;
1308         }
1309         
1310         if ((prop = node.property ("id")) != 0) {
1311                 _id = prop->value ();
1312                 /* update session AL list */
1313                 AutomationListCreated(this);
1314         }
1315         
1316         if ((prop = node.property (X_("default"))) != 0){ 
1317                 default_value = atof (prop->value());
1318         } else {
1319                 default_value = 0.0;
1320         }
1321
1322         if ((prop = node.property (X_("style"))) != 0) {
1323                 _style = string_to_auto_style (prop->value());
1324         } else {
1325                 _style = Absolute;
1326         }
1327
1328         if ((prop = node.property (X_("state"))) != 0) {
1329                 _state = string_to_auto_state (prop->value());
1330         } else {
1331                 _state = Off;
1332         }
1333
1334         if ((prop = node.property (X_("min_yval"))) != 0) {
1335                 min_yval = atof (prop->value ());
1336         } else {
1337                 min_yval = FLT_MIN;
1338         }
1339
1340         if ((prop = node.property (X_("max_yval"))) != 0) {
1341                 max_yval = atof (prop->value ());
1342         } else {
1343                 max_yval = FLT_MAX;
1344         }
1345
1346         if ((prop = node.property (X_("max_xval"))) != 0) {
1347                 max_xval = atof (prop->value ());
1348         } else {
1349                 max_xval = 0; // means "no limit ;
1350         }
1351
1352         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1353                 if ((*niter)->name() == X_("events")) {
1354                         deserialize_events (*(*niter));
1355                 }
1356         }
1357         
1358         return 0;
1359 }
1360