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