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