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