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