- Fixed a buffer size bug when ~/.ardour2 doesn't exist (can't load configuration...
[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, 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                 // FIXME: Should be vector<AudioRegion*>
247                 vector<Region*>& r (relevant_regions[*l]);
248                 vector<Crossfade*>& x (relevant_xfades[*l]);
249
250                 for (vector<Region*>::iterator i = r.begin(); i != r.end(); ++i) {
251                         AudioRegion* const ar = dynamic_cast<AudioRegion*>(*i);
252                         assert(ar);
253                         ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
254                         _read_data_count += ar->read_data_count();
255                 }
256                 
257                 for (vector<Crossfade*>::iterator i = x.begin(); i != x.end(); ++i) {
258                         (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
259
260                         /* don't JACK up _read_data_count, since its the same data as we just
261                            read from the regions, and the OS should handle that for us.
262                         */
263                 }
264         }
265
266         return ret;
267 }
268
269
270 void
271 AudioPlaylist::remove_dependents (Region& region)
272 {
273         Crossfades::iterator i, tmp;
274         AudioRegion* r = dynamic_cast<AudioRegion*> (&region);
275         
276         if (r == 0) {
277                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
278                       << endmsg;
279                 return;
280         }
281
282         for (i = _crossfades.begin(); i != _crossfades.end(); ) {
283                 tmp = i;
284                 tmp++;
285
286                 if ((*i)->involves (*r)) {
287                         /* do not delete crossfades */
288                         _crossfades.erase (i);
289                 }
290                 
291                 i = tmp;
292         }
293 }
294
295
296 void
297 AudioPlaylist::flush_notifications ()
298 {
299         Playlist::flush_notifications();
300
301         if (in_flush) {
302                 return;
303         }
304
305         in_flush = true;
306
307         Crossfades::iterator a;
308         for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
309                 NewCrossfade (*a); /* EMIT SIGNAL */
310         }
311
312         _pending_xfade_adds.clear ();
313         
314         in_flush = false;
315 }
316
317 void
318 AudioPlaylist::refresh_dependents (Region& r)
319 {
320         AudioRegion* ar = dynamic_cast<AudioRegion*>(&r);
321         set<Crossfade*> updated;
322
323         if (ar == 0) {
324                 return;
325         }
326
327         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
328
329                 Crossfades::iterator tmp;
330                 
331                 tmp = x;
332                 ++tmp;
333
334                 /* only update them once */
335
336                 if ((*x)->involves (*ar)) {
337
338                         if (find (updated.begin(), updated.end(), *x) == updated.end()) {
339                                 if ((*x)->refresh ()) {
340                                         /* not invalidated by the refresh */
341                                         updated.insert (*x);
342                                 }
343                         }
344                 }
345
346                 x = tmp;
347         }
348 }
349
350 void
351 AudioPlaylist::finalize_split_region (Region *o, Region *l, Region *r)
352 {
353         AudioRegion *orig  = dynamic_cast<AudioRegion*>(o);
354         AudioRegion *left  = dynamic_cast<AudioRegion*>(l);
355         AudioRegion *right = dynamic_cast<AudioRegion*>(r);
356
357         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
358                 Crossfades::iterator tmp;
359                 tmp = x;
360                 ++tmp;
361
362                 Crossfade *fade = 0;
363                 
364                 if ((*x)->_in == orig) {
365                         if (! (*x)->covers(right->position())) {
366                                 fade = new Crossfade( *(*x), left, (*x)->_out);
367                         } else {
368                                 // Overlap, the crossfade is copied on the left side of the right region instead
369                                 fade = new Crossfade( *(*x), right, (*x)->_out);
370                         }
371                 }
372                 
373                 if ((*x)->_out == orig) {
374                         if (! (*x)->covers(right->position())) {
375                                 fade = new Crossfade( *(*x), (*x)->_in, right);
376                         } else {
377                                 // Overlap, the crossfade is copied on the right side of the left region instead
378                                 fade = new Crossfade( *(*x), (*x)->_in, left);
379                         }
380                 }
381                 
382                 if (fade) {
383                         _crossfades.remove( (*x) );
384                         add_crossfade (*fade);
385                 }
386                 x = tmp;
387         }
388 }
389
390 void
391 AudioPlaylist::check_dependents (Region& r, bool norefresh)
392 {
393         AudioRegion* other;
394         AudioRegion* region;
395         AudioRegion* top;
396         AudioRegion* bottom;
397         Crossfade*   xfade;
398
399         if (in_set_state || in_partition) {
400                 return;
401         }
402
403         if ((region = dynamic_cast<AudioRegion*> (&r)) == 0) {
404                 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
405                       << endmsg;
406                 return;
407         }
408
409         if (!norefresh) {
410                 refresh_dependents (r);
411         }
412
413         if (!Config->get_auto_xfade()) {
414                 return;
415         }
416
417         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
418
419                 other = dynamic_cast<AudioRegion*> (*i);
420
421                 if (other == region) {
422                         continue;
423                 }
424
425                 if (other->muted() || region->muted()) {
426                         continue;
427                 }
428
429                 if (other->layer() < region->layer()) {
430                         top = region;
431                         bottom = other;
432                 } else {
433                         top = other;
434                         bottom = region;
435                 }
436
437                 try {
438                                 
439                         if (top->coverage (bottom->position(), bottom->last_frame()) != OverlapNone) {
440                                 
441                                 /* check if the upper region is within the lower region */
442                                 
443                                 if (top->first_frame() > bottom->first_frame() &&
444                                     top->last_frame() < bottom->last_frame()) {
445                                         
446                                         
447                                         /*     [ -------- top ------- ]
448                                          * {=========== bottom =============}
449                                          */
450                                         
451                                         /* to avoid discontinuities at the region boundaries of an internal
452                                            overlap (this region is completely within another), we create
453                                            two hidden crossfades at each boundary. this is not dependent
454                                            on the auto-xfade option, because we require it as basic
455                                            audio engineering.
456                                         */
457                                         
458                                         jack_nframes_t xfade_length = min ((jack_nframes_t) 720, top->length());
459                                         
460                                                             /*  in,      out */
461                                         xfade = new Crossfade (*top, *bottom, xfade_length, top->first_frame(), StartOfIn);
462                                         add_crossfade (*xfade);
463                                         xfade = new Crossfade (*bottom, *top, xfade_length, top->last_frame() - xfade_length, EndOfOut);
464                                         add_crossfade (*xfade);
465                                         
466                                 } else {
467                 
468                                         xfade = new Crossfade (*other, *region, _session.get_xfade_model(), _session.get_crossfades_active());
469                                         add_crossfade (*xfade);
470                                 }
471                         } 
472                 }
473                 
474                 catch (failed_constructor& err) {
475                         continue;
476                 }
477                 
478                 catch (Crossfade::NoCrossfadeHere& err) {
479                         continue;
480                 }
481                 
482         }
483 }
484
485 void
486 AudioPlaylist::add_crossfade (Crossfade& xfade)
487 {
488         Crossfades::iterator ci;
489
490         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
491                 if (*(*ci) == xfade) { // Crossfade::operator==()
492                         break;
493                 }
494         }
495         
496         if (ci != _crossfades.end()) {
497                 delete &xfade;
498         } else {
499                 _crossfades.push_back (&xfade);
500
501                 xfade.Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
502                 xfade.StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
503
504                 notify_crossfade_added (&xfade);
505         }
506 }
507         
508 void AudioPlaylist::notify_crossfade_added (Crossfade *x)
509 {
510         if (g_atomic_int_get(&block_notifications)) {
511                 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
512         } else {
513                 NewCrossfade (x); /* EMIT SIGNAL */
514         }
515 }
516
517 void
518 AudioPlaylist::crossfade_invalidated (Crossfade* xfade)
519 {
520         Crossfades::iterator i;
521
522         xfade->in().resume_fade_in ();
523         xfade->out().resume_fade_out ();
524
525         if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
526                 _crossfades.erase (i);
527         }
528 }
529
530 int
531 AudioPlaylist::set_state (const XMLNode& node)
532 {
533         XMLNode *child;
534         XMLNodeList nlist;
535         XMLNodeConstIterator niter;
536
537         if (!in_set_state) {
538                 Playlist::set_state (node);
539         }
540
541         nlist = node.children();
542
543         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
544
545                 child = *niter;
546
547                 if (child->name() == "Crossfade") {
548
549                         Crossfade *xfade;
550                         
551                         try {
552                                 xfade = new Crossfade (*((const Playlist *)this), *child);
553                         }
554
555                         catch (failed_constructor& err) {
556                           //    cout << string_compose (_("could not create crossfade object in playlist %1"),
557                           //      _name) 
558                           //    << endl;
559                                 continue;
560                         }
561
562                         Crossfades::iterator ci;
563
564                         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
565                                 if (*(*ci) == *xfade) {
566                                         break;
567                                 }
568                         }
569
570                         if (ci == _crossfades.end()) {
571                                 _crossfades.push_back (xfade);
572                                 xfade->Invalidated.connect (mem_fun (*this, &AudioPlaylist::crossfade_invalidated));
573                                 xfade->StateChanged.connect (mem_fun (*this, &AudioPlaylist::crossfade_changed));
574                                 /* no need to notify here */
575                         } else {
576                                 delete xfade;
577                         }
578                 }
579
580         }
581
582         return 0;
583 }
584
585 void
586 AudioPlaylist::drop_all_states ()
587 {
588         set<Crossfade*> all_xfades;
589         set<Region*> all_regions;
590
591         /* find every region we've ever used, and add it to the set of 
592            all regions. same for xfades;
593         */
594
595         for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
596                 
597                 AudioPlaylist::State* apstate = dynamic_cast<AudioPlaylist::State*> (*i);
598
599                 for (RegionList::iterator r = apstate->regions.begin(); r != apstate->regions.end(); ++r) {
600                         all_regions.insert (*r);
601                 }
602                 for (Crossfades::iterator xf = apstate->crossfades.begin(); xf != apstate->crossfades.end(); ++xf) {
603                         all_xfades.insert (*xf);
604                 }
605         }
606
607         /* now remove from the "all" lists every region that is in the current list. */
608
609         for (list<Region*>::iterator i = regions.begin(); i != regions.end(); ++i) {
610                 set<Region*>::iterator x = all_regions.find (*i);
611                 if (x != all_regions.end()) {
612                         all_regions.erase (x);
613                 }
614         }
615
616         /* ditto for every crossfade */
617
618         for (list<Crossfade*>::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
619                 set<Crossfade*>::iterator x = all_xfades.find (*i);
620                 if (x != all_xfades.end()) {
621                         all_xfades.erase (x);
622                 }
623         }
624
625         /* delete every region that is left - these are all things that are part of our "history" */
626
627         for (set<Region *>::iterator ar = all_regions.begin(); ar != all_regions.end(); ++ar) {
628                 (*ar)->unlock_sources ();
629                 delete *ar;
630         }
631
632         /* delete every crossfade that is left (ditto as per regions) */
633
634         for (set<Crossfade *>::iterator axf = all_xfades.begin(); axf != all_xfades.end(); ++axf) {
635                 delete *axf;
636         }
637
638         /* Now do the generic thing ... */
639
640         StateManager::drop_all_states ();
641 }
642
643 StateManager::State*
644 AudioPlaylist::state_factory (std::string why) const
645 {
646         State* state = new State (why);
647
648         state->regions = regions;
649         state->region_states.clear ();
650         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
651                 state->region_states.push_back ((*i)->get_memento());
652         }
653
654         state->crossfades = _crossfades;
655         state->crossfade_states.clear ();
656         for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
657                 state->crossfade_states.push_back ((*i)->get_memento());
658         }
659         return state;
660 }
661
662 Change
663 AudioPlaylist::restore_state (StateManager::State& state)
664
665         { 
666                 RegionLock rlock (this);
667                 State* apstate = dynamic_cast<State*> (&state);
668
669                 in_set_state = true;
670
671                 regions = apstate->regions;
672
673                 for (list<UndoAction>::iterator s = apstate->region_states.begin(); s != apstate->region_states.end(); ++s) {
674                         (*s) ();
675                 }
676
677                 _crossfades = apstate->crossfades;
678                 
679                 for (list<UndoAction>::iterator s = apstate->crossfade_states.begin(); s != apstate->crossfade_states.end(); ++s) {
680                         (*s) ();
681                 }
682
683                 in_set_state = false;
684         }
685
686         notify_length_changed ();
687         return Change (~0);
688 }
689
690 UndoAction
691 AudioPlaylist::get_memento () const
692 {
693         return sigc::bind (mem_fun (*(const_cast<AudioPlaylist*> (this)), &StateManager::use_state), _current_state_id);
694 }
695
696 void
697 AudioPlaylist::clear (bool with_delete, bool with_save)
698 {
699         if (with_delete) {
700                 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
701                         delete *i;
702                 }
703         }
704
705         _crossfades.clear ();
706         
707         Playlist::clear (with_delete, with_save);
708 }
709
710 XMLNode&
711 AudioPlaylist::state (bool full_state)
712 {
713         XMLNode& node = Playlist::state (full_state);
714
715         if (full_state) {
716                 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
717                         node.add_child_nocopy ((*i)->get_state());
718                 }
719         }
720         
721         return node;
722 }
723
724 void
725 AudioPlaylist::dump () const
726 {
727         Region *r;
728         Crossfade *x;
729
730         cerr << "Playlist \"" << _name << "\" " << endl
731              << regions.size() << " regions "
732              << _crossfades.size() << " crossfades"
733              << endl;
734
735         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
736                 r = *i;
737                 cerr << "  " << r->name() << " @ " << r << " [" 
738                      << r->start() << "+" << r->length() 
739                      << "] at " 
740                      << r->position()
741                      << " on layer "
742                      << r->layer ()
743                      << endl;
744         }
745
746         for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
747                 x = *i;
748                 cerr << "  xfade [" 
749                      << x->out().name()
750                      << ','
751                      << x->in().name()
752                      << " @ "
753                      << x->position()
754                      << " length = " 
755                      << x->length ()
756                      << " active ? "
757                      << (x->active() ? "yes" : "no")
758                      << endl;
759         }
760 }
761
762 bool
763 AudioPlaylist::destroy_region (Region* region)
764 {
765         AudioRegion* r = dynamic_cast<AudioRegion*> (region);
766         bool changed = false;
767         Crossfades::iterator c, ctmp;
768         set<Crossfade*> unique_xfades;
769
770         if (r == 0) {
771                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
772                       << endmsg;
773                 /*NOTREACHED*/
774                 return false;
775         }
776
777         { 
778                 RegionLock rlock (this);
779                 RegionList::iterator i;
780                 RegionList::iterator tmp;
781
782                 for (i = regions.begin(); i != regions.end(); ) {
783                         
784                         tmp = i;
785                         ++tmp;
786                         
787                         if ((*i) == region) {
788                                 (*i)->unlock_sources ();
789                                 regions.erase (i);
790                                 changed = true;
791                         }
792                         
793                         i = tmp;
794                 }
795         }
796
797         for (c = _crossfades.begin(); c != _crossfades.end(); ) {
798                 ctmp = c;
799                 ++ctmp;
800
801                 if ((*c)->involves (*r)) {
802                         unique_xfades.insert (*c);
803                         _crossfades.erase (c);
804                 }
805                 
806                 c = ctmp;
807         }
808
809         for (StateMap::iterator s = states.begin(); s != states.end(); ) {
810                 StateMap::iterator tmp;
811
812                 tmp = s;
813                 ++tmp;
814
815                 State* astate = dynamic_cast<State*> (*s);
816                 
817                 for (c = astate->crossfades.begin(); c != astate->crossfades.end(); ) {
818
819                         ctmp = c;
820                         ++ctmp;
821
822                         if ((*c)->involves (*r)) {
823                                 unique_xfades.insert (*c);
824                                 _crossfades.erase (c);
825                         }
826
827                         c = ctmp;
828                 }
829
830                 list<UndoAction>::iterator rsi, rsitmp;
831                 RegionList::iterator ri, ritmp;
832
833                 for (ri = astate->regions.begin(), rsi = astate->region_states.begin(); 
834                      ri != astate->regions.end() && rsi != astate->region_states.end();) {
835
836
837                         ritmp = ri;
838                         ++ritmp;
839
840                         rsitmp = rsi; 
841                         ++rsitmp;
842
843                         if (region == (*ri)) {
844                                 astate->regions.erase (ri);
845                                 astate->region_states.erase (rsi);
846                         }
847
848                         ri = ritmp;
849                         rsi = rsitmp;
850                 }
851                 
852                 s = tmp;
853         }
854
855         for (set<Crossfade*>::iterator c = unique_xfades.begin(); c != unique_xfades.end(); ++c) {
856                 delete *c;
857         }
858
859         if (changed) {
860                 /* overload this, it normally means "removed", not destroyed */
861                 notify_region_removed (region);
862         }
863
864         return changed;
865 }
866
867 void
868 AudioPlaylist::crossfade_changed (Change ignored)
869 {
870         if (in_flush || in_set_state) {
871                 return;
872         }
873
874         /* XXX is there a loop here? can an xfade change not happen
875            due to a playlist change? well, sure activation would
876            be an example. maybe we should check the type of change
877            that occured.
878         */
879
880         maybe_save_state (_("xfade change"));
881
882         notify_modified ();
883 }
884
885 bool
886 AudioPlaylist::region_changed (Change what_changed, Region* region)
887 {
888         if (in_flush || in_set_state) {
889                 return false;
890         }
891
892         Change our_interests = Change (AudioRegion::FadeInChanged|
893                                        AudioRegion::FadeOutChanged|
894                                        AudioRegion::FadeInActiveChanged|
895                                        AudioRegion::FadeOutActiveChanged|
896                                        AudioRegion::EnvelopeActiveChanged|
897                                        AudioRegion::ScaleAmplitudeChanged|
898                                        AudioRegion::EnvelopeChanged);
899         bool parent_wants_notify;
900
901         parent_wants_notify = Playlist::region_changed (what_changed, region);
902
903         maybe_save_state (_("region modified"));
904
905         if ((parent_wants_notify || (what_changed & our_interests))) {
906                 notify_modified ();
907         }
908
909         return true; 
910 }
911
912 void
913 AudioPlaylist::crossfades_at (jack_nframes_t frame, Crossfades& clist)
914 {
915         RegionLock rlock (this);
916
917         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
918                 jack_nframes_t start, end;
919
920                 start = (*i)->position();
921                 end = start + (*i)->overlap_length(); // not length(), important difference
922
923                 if (frame >= start && frame <= end) {
924                         clist.push_back (*i);
925                 } 
926         }
927 }