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