Fix for #1179. Crossfades are not lost anymore when regions are split.
[ardour.git] / libs / ardour / audio_playlist.cc
1 /*
2     Copyright (C) 2003 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 <algorithm>
22
23 #include <stdlib.h>
24
25 #include <sigc++/bind.h>
26
27 #include <ardour/types.h>
28 #include <ardour/configuration.h>
29 #include <ardour/audioplaylist.h>
30 #include <ardour/audioregion.h>
31 #include <ardour/crossfade.h>
32 #include <ardour/crossfade_compare.h>
33 #include <ardour/session.h>
34
35 #include "i18n.h"
36
37 using namespace ARDOUR;
38 using namespace sigc;
39 using namespace std;
40
41 AudioPlaylist::State::~State ()
42 {
43 }
44
45 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
46         : Playlist (session, node, hidden)
47 {
48         in_set_state = true;
49         set_state (node);
50         in_set_state = false;
51
52         save_state (_("initial state"));
53
54         if (!hidden) {
55                 PlaylistCreated (this); /* EMIT SIGNAL */
56         }
57 }
58
59 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
60         : Playlist (session, name, hidden)
61 {
62         save_state (_("initial state"));
63
64         if (!hidden) {
65                 PlaylistCreated (this); /* EMIT SIGNAL */
66         }
67
68 }
69
70 AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, string name, bool hidden)
71         : Playlist (other, name, hidden)
72 {
73         save_state (_("initial state"));
74
75         list<Region*>::const_iterator in_o  = other.regions.begin();
76         list<Region*>::iterator in_n = regions.begin();
77
78         while (in_o != other.regions.end()) {
79                 AudioRegion *ar = dynamic_cast<AudioRegion *>( (*in_o) );
80
81                 // We look only for crossfades which begin with the current region, so we don't get doubles
82                 for (list<Crossfade *>::const_iterator xfades = other._crossfades.begin(); xfades != other._crossfades.end(); ++xfades) {
83                         if ( &(*xfades)->in() == ar) {
84                                 // We found one! Now copy it!
85
86                                 list<Region*>::const_iterator out_o = other.regions.begin();
87                                 list<Region*>::const_iterator out_n = regions.begin();
88
89                                 while (out_o != other.regions.end()) {
90                                         
91                                         AudioRegion *ar2 = dynamic_cast<AudioRegion *>( (*out_o) );
92                                         
93                                         if ( &(*xfades)->out() == ar2) {
94                                                 AudioRegion *in  = dynamic_cast<AudioRegion*>( (*in_n) );
95                                                 AudioRegion *out = dynamic_cast<AudioRegion*>( (*out_n) );
96                                                 Crossfade *new_fade = new Crossfade( *(*xfades), in, out);
97                                                 add_crossfade(*new_fade);
98                                                 break;
99                                         }
100                                         
101                                         out_o++;
102                                         out_n++;
103                                 }
104 //                              cerr << "HUH!? second region in the crossfade not found!" << endl;
105                         }
106                 }
107
108                 in_o++;
109                 in_n++;
110         }
111
112         if (!hidden) {
113                 PlaylistCreated (this); /* EMIT SIGNAL */
114         }
115 }
116
117 AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, jack_nframes_t start, jack_nframes_t cnt, string name, bool hidden)
118         : Playlist (other, start, cnt, name, hidden)
119 {
120         save_state (_("initial state"));
121
122         /* this constructor does NOT notify others (session) */
123 }
124
125 AudioPlaylist::~AudioPlaylist ()
126 {
127         set<Crossfade*> all_xfades;
128         set<Region*> all_regions;
129
130         GoingAway (this);
131
132         /* find every region we've ever used, and add it to the set of 
133            all regions. same for xfades;
134         */
135
136         for (RegionList::iterator x = regions.begin(); x != regions.end(); ++x) {
137                 all_regions.insert (*x);
138         }
139
140         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end(); ++x) {
141                 all_xfades.insert (*x);
142         }
143
144         for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
145                 
146                 AudioPlaylist::State* apstate = dynamic_cast<AudioPlaylist::State*> (*i);
147
148                 for (RegionList::iterator r = apstate->regions.begin(); r != apstate->regions.end(); ++r) {
149                         all_regions.insert (*r);
150                 }
151                 for (Crossfades::iterator xf = apstate->crossfades.begin(); xf != apstate->crossfades.end(); ++xf) {
152                         all_xfades.insert (*xf);
153                 }
154
155                 delete apstate;
156         }
157
158         /* delete every region */
159
160         for (set<Region *>::iterator ar = all_regions.begin(); ar != all_regions.end(); ++ar) {
161                 (*ar)->unlock_sources ();
162                 delete *ar;
163         }
164
165         /* delete every crossfade */
166
167         for (set<Crossfade *>::iterator axf = all_xfades.begin(); axf != all_xfades.end(); ++axf) {
168                 delete *axf;
169         }
170 }
171
172 struct RegionSortByLayer {
173     bool operator() (Region *a, Region *b) {
174             return a->layer() < b->layer();
175     }
176 };
177
178 jack_nframes_t
179 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf, jack_nframes_t start,
180                      jack_nframes_t cnt, unsigned chan_n)
181 {
182         jack_nframes_t ret = cnt;
183         jack_nframes_t end;
184         jack_nframes_t read_frames;
185         jack_nframes_t skip_frames;
186
187         /* optimizing this memset() away involves a lot of conditionals
188            that may well cause more of a hit due to cache misses 
189            and related stuff than just doing this here.
190            
191            it would be great if someone could measure this
192            at some point.
193
194            one way or another, parts of the requested area
195            that are not written to by Region::region_at()
196            for all Regions that cover the area need to be
197            zeroed.
198         */
199
200         memset (buf, 0, sizeof (Sample) * cnt);
201
202         /* this function is never called from a realtime thread, so 
203            its OK to block (for short intervals).
204         */
205
206         LockMonitor rm (region_lock, __LINE__, __FILE__);
207
208         end =  start + cnt - 1;
209
210         read_frames = 0;
211         skip_frames = 0;
212         _read_data_count = 0;
213
214         map<uint32_t,vector<Region*> > relevant_regions;
215         map<uint32_t,vector<Crossfade*> > relevant_xfades;
216         vector<uint32_t> relevant_layers;
217
218         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
219                 if ((*i)->coverage (start, end) != OverlapNone) {
220                         
221                         relevant_regions[(*i)->layer()].push_back (*i);
222                         relevant_layers.push_back ((*i)->layer());
223                 }
224         }
225
226         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
227                 if ((*i)->coverage (start, end) != OverlapNone) {
228                         relevant_xfades[(*i)->upper_layer()].push_back (*i);
229                 }
230         }
231
232 //      RegionSortByLayer layer_cmp;
233 //      relevant_regions.sort (layer_cmp);
234
235         /* XXX this whole per-layer approach is a hack that
236            should be removed once Crossfades become
237            CrossfadeRegions and we just grab a list of relevant
238            regions and call read_at() on all of them.
239         */
240
241         sort (relevant_layers.begin(), relevant_layers.end());
242
243         for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
244
245                 vector<Region*>& r (relevant_regions[*l]);
246                 vector<Crossfade*>& x (relevant_xfades[*l]);
247
248                 for (vector<Region*>::iterator i = r.begin(); i != r.end(); ++i) {
249                         (*i)->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n, read_frames, skip_frames);
250                         _read_data_count += (*i)->read_data_count();
251                 }
252                 
253                 for (vector<Crossfade*>::iterator i = x.begin(); i != x.end(); ++i) {
254                         
255                         (*i)->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n);
256
257                         /* don't JACK up _read_data_count, since its the same data as we just
258                            read from the regions, and the OS should handle that for us.
259                         */
260                 }
261         }
262
263         return ret;
264 }
265
266
267 void
268 AudioPlaylist::remove_dependents (Region& region)
269 {
270         Crossfades::iterator i, tmp;
271         AudioRegion* r = dynamic_cast<AudioRegion*> (&region);
272         
273         if (r == 0) {
274                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
275                       << endmsg;
276                 return;
277         }
278
279         for (i = _crossfades.begin(); i != _crossfades.end(); ) {
280                 tmp = i;
281                 tmp++;
282
283                 if ((*i)->involves (*r)) {
284                         /* do not delete crossfades */
285                         _crossfades.erase (i);
286                 }
287                 
288                 i = tmp;
289         }
290 }
291
292
293 void
294 AudioPlaylist::flush_notifications ()
295 {
296         Playlist::flush_notifications();
297
298         if (in_flush) {
299                 return;
300         }
301
302         in_flush = true;
303
304         Crossfades::iterator a;
305         for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
306                 NewCrossfade (*a); /* EMIT SIGNAL */
307         }
308
309         _pending_xfade_adds.clear ();
310         
311         in_flush = false;
312 }
313
314 void
315 AudioPlaylist::refresh_dependents (Region& r)
316 {
317         AudioRegion* ar = dynamic_cast<AudioRegion*>(&r);
318         set<Crossfade*> updated;
319
320         if (ar == 0) {
321                 return;
322         }
323
324         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
325
326                 Crossfades::iterator tmp;
327                 
328                 tmp = x;
329                 ++tmp;
330
331                 /* only update them once */
332
333                 if ((*x)->involves (*ar)) {
334
335                         if (find (updated.begin(), updated.end(), *x) == updated.end()) {
336                                 if ((*x)->refresh ()) {
337                                         /* not invalidated by the refresh */
338                                         updated.insert (*x);
339                                 }
340                         }
341                 }
342
343                 x = tmp;
344         }
345 }
346
347 void
348 AudioPlaylist::finalize_split_region (Region *o, Region *l, Region *r)
349 {
350         AudioRegion *orig  = dynamic_cast<AudioRegion*>(o);
351         AudioRegion *left  = dynamic_cast<AudioRegion*>(l);
352         AudioRegion *right = dynamic_cast<AudioRegion*>(r);
353
354         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end(); ++x) {
355                 Crossfades::iterator tmp;
356
357                 if ((*x)->_in == orig) {
358                         (*x)->_in = left;
359                 }
360
361                 if ((*x)->_out == orig) {
362                         (*x)->_out = right;
363                 }
364                 
365         }
366 }
367
368 void
369 AudioPlaylist::check_dependents (Region& r, bool norefresh)
370 {
371         AudioRegion* other;
372         AudioRegion* region;
373         AudioRegion* top;
374         AudioRegion* bottom;
375         Crossfade*   xfade;
376
377         if (in_set_state || in_partition) {
378                 return;
379         }
380
381         if ((region = dynamic_cast<AudioRegion*> (&r)) == 0) {
382                 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
383                       << endmsg;
384                 return;
385         }
386
387         if (!norefresh) {
388                 refresh_dependents (r);
389         }
390
391         if (!Config->get_auto_xfade()) {
392                 return;
393         }
394
395         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
396
397                 other = dynamic_cast<AudioRegion*> (*i);
398
399                 if (other == region) {
400                         continue;
401                 }
402
403                 if (other->muted() || region->muted()) {
404                         continue;
405                 }
406
407                 if (other->layer() < region->layer()) {
408                         top = region;
409                         bottom = other;
410                 } else {
411                         top = other;
412                         bottom = region;
413                 }
414
415                 try {
416                                 
417                         if (top->coverage (bottom->position(), bottom->last_frame()) != OverlapNone) {
418                                 
419                                 /* check if the upper region is within the lower region */
420                                 
421                                 if (top->first_frame() > bottom->first_frame() &&
422                                     top->last_frame() < bottom->last_frame()) {
423                                         
424                                         
425                                         /*     [ -------- top ------- ]
426                                          * {=========== bottom =============}
427                                          */
428                                         
429                                         /* to avoid discontinuities at the region boundaries of an internal
430                                            overlap (this region is completely within another), we create
431                                            two hidden crossfades at each boundary. this is not dependent
432                                            on the auto-xfade option, because we require it as basic
433                                            audio engineering.
434                                         */
435                                         
436                                         jack_nframes_t xfade_length = min ((jack_nframes_t) 720, top->length());
437                                         
438                                                             /*  in,      out */
439                                         xfade = new Crossfade (*top, *bottom, xfade_length, top->first_frame(), StartOfIn);
440                                         add_crossfade (*xfade);
441                                         xfade = new Crossfade (*bottom, *top, xfade_length, top->last_frame() - xfade_length, EndOfOut);
442                                         add_crossfade (*xfade);
443                                         
444                                 } else {
445                 
446                                         xfade = new Crossfade (*other, *region, _session.get_xfade_model(), _session.get_crossfades_active());
447                                         add_crossfade (*xfade);
448                                 }
449                         } 
450                 }
451                 
452                 catch (failed_constructor& err) {
453                         continue;
454                 }
455                 
456                 catch (Crossfade::NoCrossfadeHere& err) {
457                         continue;
458                 }
459                 
460         }
461 }
462
463 void
464 AudioPlaylist::add_crossfade (Crossfade& xfade)
465 {
466         Crossfades::iterator ci;
467
468         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
469                 if (*(*ci) == xfade) { // Crossfade::operator==()
470                         break;
471                 }
472         }
473         
474         if (ci != _crossfades.end()) {
475                 delete &xfade;
476         } else {
477                 _crossfades.push_back (&xfade);
478
479                 xfade.Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
480                 xfade.StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
481
482                 notify_crossfade_added (&xfade);
483         }
484 }
485         
486 void AudioPlaylist::notify_crossfade_added (Crossfade *x)
487 {
488         if (atomic_read(&block_notifications)) {
489                 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
490         } else {
491                 NewCrossfade (x); /* EMIT SIGNAL */
492         }
493 }
494
495 void
496 AudioPlaylist::crossfade_invalidated (Crossfade* xfade)
497 {
498         Crossfades::iterator i;
499
500         xfade->in().resume_fade_in ();
501         xfade->out().resume_fade_out ();
502
503         if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
504                 _crossfades.erase (i);
505         }
506 }
507
508 int
509 AudioPlaylist::set_state (const XMLNode& node)
510 {
511         XMLNode *child;
512         XMLNodeList nlist;
513         XMLNodeConstIterator niter;
514
515         if (!in_set_state) {
516                 Playlist::set_state (node);
517         }
518
519         nlist = node.children();
520
521         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
522
523                 child = *niter;
524
525                 if (child->name() == "Crossfade") {
526
527                         Crossfade *xfade;
528                         
529                         try {
530                                 xfade = new Crossfade (*((const Playlist *)this), *child);
531                         }
532
533                         catch (failed_constructor& err) {
534                           //    cout << string_compose (_("could not create crossfade object in playlist %1"),
535                           //      _name) 
536                           //    << endl;
537                                 continue;
538                         }
539
540                         Crossfades::iterator ci;
541
542                         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
543                                 if (*(*ci) == *xfade) {
544                                         break;
545                                 }
546                         }
547
548                         if (ci == _crossfades.end()) {
549                                 _crossfades.push_back (xfade);
550                                 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
551                                 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
552                                 /* no need to notify here */
553                         } else {
554                                 delete xfade;
555                         }
556                 }
557
558         }
559
560         return 0;
561 }
562
563 void
564 AudioPlaylist::drop_all_states ()
565 {
566         set<Crossfade*> all_xfades;
567         set<Region*> all_regions;
568
569         /* find every region we've ever used, and add it to the set of 
570            all regions. same for xfades;
571         */
572
573         for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
574                 
575                 AudioPlaylist::State* apstate = dynamic_cast<AudioPlaylist::State*> (*i);
576
577                 for (RegionList::iterator r = apstate->regions.begin(); r != apstate->regions.end(); ++r) {
578                         all_regions.insert (*r);
579                 }
580                 for (Crossfades::iterator xf = apstate->crossfades.begin(); xf != apstate->crossfades.end(); ++xf) {
581                         all_xfades.insert (*xf);
582                 }
583         }
584
585         /* now remove from the "all" lists every region that is in the current list. */
586
587         for (list<Region*>::iterator i = regions.begin(); i != regions.end(); ++i) {
588                 set<Region*>::iterator x = all_regions.find (*i);
589                 if (x != all_regions.end()) {
590                         all_regions.erase (x);
591                 }
592         }
593
594         /* ditto for every crossfade */
595
596         for (list<Crossfade*>::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
597                 set<Crossfade*>::iterator x = all_xfades.find (*i);
598                 if (x != all_xfades.end()) {
599                         all_xfades.erase (x);
600                 }
601         }
602
603         /* delete every region that is left - these are all things that are part of our "history" */
604
605         for (set<Region *>::iterator ar = all_regions.begin(); ar != all_regions.end(); ++ar) {
606                 (*ar)->unlock_sources ();
607                 delete *ar;
608         }
609
610         /* delete every crossfade that is left (ditto as per regions) */
611
612         for (set<Crossfade *>::iterator axf = all_xfades.begin(); axf != all_xfades.end(); ++axf) {
613                 delete *axf;
614         }
615
616         /* Now do the generic thing ... */
617
618         StateManager::drop_all_states ();
619 }
620
621 StateManager::State*
622 AudioPlaylist::state_factory (std::string why) const
623 {
624         State* state = new State (why);
625
626         state->regions = regions;
627         state->region_states.clear ();
628         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
629                 state->region_states.push_back ((*i)->get_memento());
630         }
631
632         state->crossfades = _crossfades;
633         state->crossfade_states.clear ();
634         for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
635                 state->crossfade_states.push_back ((*i)->get_memento());
636         }
637         return state;
638 }
639
640 Change
641 AudioPlaylist::restore_state (StateManager::State& state)
642
643         { 
644                 RegionLock rlock (this);
645                 State* apstate = dynamic_cast<State*> (&state);
646
647                 in_set_state = true;
648
649                 regions = apstate->regions;
650
651                 for (list<UndoAction>::iterator s = apstate->region_states.begin(); s != apstate->region_states.end(); ++s) {
652                         (*s) ();
653                 }
654
655                 _crossfades = apstate->crossfades;
656                 
657                 for (list<UndoAction>::iterator s = apstate->crossfade_states.begin(); s != apstate->crossfade_states.end(); ++s) {
658                         (*s) ();
659                 }
660
661                 in_set_state = false;
662         }
663
664         notify_length_changed ();
665         return Change (~0);
666 }
667
668 UndoAction
669 AudioPlaylist::get_memento () const
670 {
671         return sigc::bind (mem_fun (*(const_cast<AudioPlaylist*> (this)), &StateManager::use_state), _current_state_id);
672 }
673
674 void
675 AudioPlaylist::clear (bool with_delete, bool with_save)
676 {
677         if (with_delete) {
678                 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
679                         delete *i;
680                 }
681         }
682
683         _crossfades.clear ();
684         
685         Playlist::clear (with_delete, with_save);
686 }
687
688 XMLNode&
689 AudioPlaylist::state (bool full_state)
690 {
691         XMLNode& node = Playlist::state (full_state);
692
693         if (full_state) {
694                 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
695                         node.add_child_nocopy ((*i)->get_state());
696                 }
697         }
698         
699         return node;
700 }
701
702 void
703 AudioPlaylist::dump () const
704 {
705         Region *r;
706         Crossfade *x;
707
708         cerr << "Playlist \"" << _name << "\" " << endl
709              << regions.size() << " regions "
710              << _crossfades.size() << " crossfades"
711              << endl;
712
713         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
714                 r = *i;
715                 cerr << "  " << r->name() << " @ " << r << " [" 
716                      << r->start() << "+" << r->length() 
717                      << "] at " 
718                      << r->position()
719                      << " on layer "
720                      << r->layer ()
721                      << endl;
722         }
723
724         for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
725                 x = *i;
726                 cerr << "  xfade [" 
727                      << x->out().name()
728                      << ','
729                      << x->in().name()
730                      << " @ "
731                      << x->position()
732                      << " length = " 
733                      << x->length ()
734                      << " active ? "
735                      << (x->active() ? "yes" : "no")
736                      << endl;
737         }
738 }
739
740 bool
741 AudioPlaylist::destroy_region (Region* region)
742 {
743         AudioRegion* r = dynamic_cast<AudioRegion*> (region);
744         bool changed = false;
745         Crossfades::iterator c, ctmp;
746         set<Crossfade*> unique_xfades;
747
748         if (r == 0) {
749                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
750                       << endmsg;
751                 /*NOTREACHED*/
752                 return false;
753         }
754
755         { 
756                 RegionLock rlock (this);
757                 RegionList::iterator i;
758                 RegionList::iterator tmp;
759
760                 for (i = regions.begin(); i != regions.end(); ) {
761                         
762                         tmp = i;
763                         ++tmp;
764                         
765                         if ((*i) == region) {
766                                 (*i)->unlock_sources ();
767                                 regions.erase (i);
768                                 changed = true;
769                         }
770                         
771                         i = tmp;
772                 }
773         }
774
775         for (c = _crossfades.begin(); c != _crossfades.end(); ) {
776                 ctmp = c;
777                 ++ctmp;
778
779                 if ((*c)->involves (*r)) {
780                         unique_xfades.insert (*c);
781                         _crossfades.erase (c);
782                 }
783                 
784                 c = ctmp;
785         }
786
787         for (StateMap::iterator s = states.begin(); s != states.end(); ) {
788                 StateMap::iterator tmp;
789
790                 tmp = s;
791                 ++tmp;
792
793                 State* astate = dynamic_cast<State*> (*s);
794                 
795                 for (c = astate->crossfades.begin(); c != astate->crossfades.end(); ) {
796
797                         ctmp = c;
798                         ++ctmp;
799
800                         if ((*c)->involves (*r)) {
801                                 unique_xfades.insert (*c);
802                                 _crossfades.erase (c);
803                         }
804
805                         c = ctmp;
806                 }
807
808                 list<UndoAction>::iterator rsi, rsitmp;
809                 RegionList::iterator ri, ritmp;
810
811                 for (ri = astate->regions.begin(), rsi = astate->region_states.begin(); 
812                      ri != astate->regions.end() && rsi != astate->region_states.end();) {
813
814
815                         ritmp = ri;
816                         ++ritmp;
817
818                         rsitmp = rsi; 
819                         ++rsitmp;
820
821                         if (region == (*ri)) {
822                                 astate->regions.erase (ri);
823                                 astate->region_states.erase (rsi);
824                         }
825
826                         ri = ritmp;
827                         rsi = rsitmp;
828                 }
829                 
830                 s = tmp;
831         }
832
833         for (set<Crossfade*>::iterator c = unique_xfades.begin(); c != unique_xfades.end(); ++c) {
834                 delete *c;
835         }
836
837         if (changed) {
838                 /* overload this, it normally means "removed", not destroyed */
839                 notify_region_removed (region);
840         }
841
842         return changed;
843 }
844
845 void
846 AudioPlaylist::crossfade_changed (Change ignored)
847 {
848         if (in_flush || in_set_state) {
849                 return;
850         }
851
852         /* XXX is there a loop here? can an xfade change not happen
853            due to a playlist change? well, sure activation would
854            be an example. maybe we should check the type of change
855            that occured.
856         */
857
858         maybe_save_state (_("xfade change"));
859
860         notify_modified ();
861 }
862
863 void
864 AudioPlaylist::get_equivalent_regions (const AudioRegion& other, vector<AudioRegion*>& results)
865 {
866         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
867
868                 AudioRegion* ar = dynamic_cast<AudioRegion*> (*i);
869
870                 if (ar && ar->equivalent (other)) {
871                         results.push_back (ar);
872                 }
873         }
874 }
875
876 void
877 AudioPlaylist::get_region_list_equivalent_regions (const AudioRegion& other, vector<AudioRegion*>& results)
878 {
879         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
880
881                 AudioRegion* ar = dynamic_cast<AudioRegion*> (*i);
882                 
883                 if (ar && ar->region_list_equivalent (other)) {
884                         results.push_back (ar);
885                 }
886         }
887 }
888
889 bool
890 AudioPlaylist::region_changed (Change what_changed, Region* region)
891 {
892         if (in_flush || in_set_state) {
893                 return false;
894         }
895
896         Change our_interests = Change (AudioRegion::FadeInChanged|
897                                        AudioRegion::FadeOutChanged|
898                                        AudioRegion::FadeInActiveChanged|
899                                        AudioRegion::FadeOutActiveChanged|
900                                        AudioRegion::EnvelopeActiveChanged|
901                                        AudioRegion::ScaleAmplitudeChanged|
902                                        AudioRegion::EnvelopeChanged);
903         bool parent_wants_notify;
904
905         parent_wants_notify = Playlist::region_changed (what_changed, region);
906
907         maybe_save_state (_("region modified"));
908
909         if ((parent_wants_notify || (what_changed & our_interests))) {
910                 notify_modified ();
911         }
912
913         return true; 
914 }
915
916 void
917 AudioPlaylist::crossfades_at (jack_nframes_t frame, Crossfades& clist)
918 {
919         RegionLock rlock (this);
920
921         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
922                 jack_nframes_t start, end;
923
924                 start = (*i)->position();
925                 end = start + (*i)->overlap_length(); // not length(), important difference
926
927                 if (frame >= start && frame <= end) {
928                         clist.push_back (*i);
929                 } 
930         }
931 }