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