Set up layering_index immediately on an explicit layer, so that undo
[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 */
19
20 #include <algorithm>
21
22 #include <cstdlib>
23
24 #include "ardour/types.h"
25 #include "ardour/debug.h"
26 #include "ardour/configuration.h"
27 #include "ardour/audioplaylist.h"
28 #include "ardour/audioregion.h"
29 #include "ardour/crossfade.h"
30 #include "ardour/region_sorters.h"
31 #include "ardour/session.h"
32 #include "pbd/enumwriter.h"
33
34 #include "i18n.h"
35
36 using namespace ARDOUR;
37 using namespace std;
38 using namespace PBD;
39
40 namespace ARDOUR {
41         namespace Properties {
42                 PBD::PropertyDescriptor<bool> crossfades;
43         }
44 }
45
46 void
47 AudioPlaylist::make_property_quarks ()
48 {
49         Properties::crossfades.property_id = g_quark_from_static_string (X_("crossfades"));
50         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for crossfades = %1\n", Properties::crossfades.property_id));
51 }
52
53 CrossfadeListProperty::CrossfadeListProperty (AudioPlaylist& pl)
54         : SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (Properties::crossfades.property_id, boost::bind (&AudioPlaylist::update, &pl, _1))
55         , _playlist (pl)
56 {
57
58 }
59
60 CrossfadeListProperty::CrossfadeListProperty (CrossfadeListProperty const & p)
61         : PBD::SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (p)
62         , _playlist (p._playlist)
63 {
64
65 }
66
67
68 CrossfadeListProperty *
69 CrossfadeListProperty::create () const
70 {
71         return new CrossfadeListProperty (_playlist);
72 }
73
74 CrossfadeListProperty *
75 CrossfadeListProperty::clone () const
76 {
77         return new CrossfadeListProperty (*this);
78 }
79
80 void
81 CrossfadeListProperty::get_content_as_xml (boost::shared_ptr<Crossfade> xfade, XMLNode & node) const
82 {
83         /* Crossfades are not written to any state when they are no
84            longer in use, so we must write their state here.
85         */
86
87         XMLNode& c = xfade->get_state ();
88         node.add_child_nocopy (c);
89 }
90
91 boost::shared_ptr<Crossfade>
92 CrossfadeListProperty::get_content_from_xml (XMLNode const & node) const
93 {
94         XMLNodeList const c = node.children ();
95         assert (c.size() == 1);
96         return boost::shared_ptr<Crossfade> (new Crossfade (_playlist, *c.front()));
97 }
98
99
100 AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
101         : Playlist (session, node, DataType::AUDIO, hidden)
102         , _crossfades (*this)
103 {
104 #ifndef NDEBUG
105         const XMLProperty* prop = node.property("type");
106         assert(!prop || DataType(prop->value()) == DataType::AUDIO);
107 #endif
108
109         add_property (_crossfades);
110
111         in_set_state++;
112         if (set_state (node, Stateful::loading_state_version)) {
113                 throw failed_constructor();
114         }
115         in_set_state--;
116
117         relayer ();
118 }
119
120 AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
121         : Playlist (session, name, DataType::AUDIO, hidden)
122         , _crossfades (*this)
123 {
124         add_property (_crossfades);
125 }
126
127 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
128         : Playlist (other, name, hidden)
129         , _crossfades (*this)
130 {
131         add_property (_crossfades);
132
133         RegionList::const_iterator in_o  = other->regions.begin();
134         RegionList::iterator in_n = regions.begin();
135
136         while (in_o != other->regions.end()) {
137                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
138
139                 // We look only for crossfades which begin with the current region, so we don't get doubles
140                 for (Crossfades::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
141                         if ((*xfades)->in() == ar) {
142                                 // We found one! Now copy it!
143
144                                 RegionList::const_iterator out_o = other->regions.begin();
145                                 RegionList::const_iterator out_n = regions.begin();
146
147                                 while (out_o != other->regions.end()) {
148
149                                         boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
150
151                                         if ((*xfades)->out() == ar2) {
152                                                 boost::shared_ptr<AudioRegion>in  = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
153                                                 boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
154                                                 boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
155                                                 add_crossfade(new_fade);
156                                                 break;
157                                         }
158
159                                         out_o++;
160                                         out_n++;
161                                 }
162 //                              cerr << "HUH!? second region in the crossfade not found!" << endl;
163                         }
164                 }
165
166                 in_o++;
167                 in_n++;
168         }
169 }
170
171 AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, framepos_t start, framecnt_t cnt, string name, bool hidden)
172         : Playlist (other, start, cnt, name, hidden)
173         , _crossfades (*this)
174 {
175         RegionLock rlock2 (const_cast<AudioPlaylist*> (other.get()));
176         in_set_state++;
177
178         add_property (_crossfades);
179
180         framepos_t const end = start + cnt - 1;
181
182         /* Audio regions that have been created by the Playlist constructor
183            will currently have the same fade in/out as the regions that they
184            were created from.  This is wrong, so reset the fades here.
185         */
186
187         RegionList::iterator ours = regions.begin ();
188
189         for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
190                 boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (*i);
191                 assert (region);
192
193                 framecnt_t fade_in = 64;
194                 framecnt_t fade_out = 64;
195
196                 switch (region->coverage (start, end)) {
197                 case OverlapNone:
198                         continue;
199
200                 case OverlapInternal:
201                 {
202                         framecnt_t const offset = start - region->position ();
203                         framecnt_t const trim = region->last_frame() - end;
204                         if (region->fade_in()->back()->when > offset) {
205                                 fade_in = region->fade_in()->back()->when - offset;
206                         }
207                         if (region->fade_out()->back()->when > trim) {
208                                 fade_out = region->fade_out()->back()->when - trim;
209                         }
210                         break;
211                 }
212
213                 case OverlapStart: {
214                         if (end > region->position() + region->fade_in()->back()->when)
215                                 fade_in = region->fade_in()->back()->when;  //end is after fade-in, preserve the fade-in
216                         if (end > region->last_frame() - region->fade_out()->back()->when)
217                                 fade_out = region->fade_out()->back()->when - ( region->last_frame() - end );  //end is inside the fadeout, preserve the fades endpoint
218                         break;
219                 }
220
221                 case OverlapEnd: {
222                         if (start < region->last_frame() - region->fade_out()->back()->when)  //start is before fade-out, preserve the fadeout
223                                 fade_out = region->fade_out()->back()->when;
224
225                         if (start < region->position() + region->fade_in()->back()->when)
226                                 fade_in = region->fade_in()->back()->when - (start - region->position());  //end is inside the fade-in, preserve the fade-in endpoint
227                         break;
228                 }
229
230                 case OverlapExternal:
231                         fade_in = region->fade_in()->back()->when;
232                         fade_out = region->fade_out()->back()->when;
233                         break;
234                 }
235
236                 boost::shared_ptr<AudioRegion> our_region = boost::dynamic_pointer_cast<AudioRegion> (*ours);
237                 assert (our_region);
238
239                 our_region->set_fade_in_length (fade_in);
240                 our_region->set_fade_out_length (fade_out);
241                 ++ours;
242         }
243
244         in_set_state--;
245
246         /* this constructor does NOT notify others (session) */
247 }
248
249 AudioPlaylist::~AudioPlaylist ()
250 {
251         _crossfades.clear ();
252 }
253
254 struct RegionSortByLayer {
255     bool operator() (boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
256             return a->layer() < b->layer();
257     }
258 };
259
260 ARDOUR::framecnt_t
261 AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, framepos_t start,
262                      framecnt_t cnt, unsigned chan_n)
263 {
264         framecnt_t ret = cnt;
265
266         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Playlist %1 read @ %2 for %3, channel %4, regions %5 xfades %6\n",
267                                                            name(), start, cnt, chan_n, regions.size(), _crossfades.size()));
268
269         /* optimizing this memset() away involves a lot of conditionals
270            that may well cause more of a hit due to cache misses
271            and related stuff than just doing this here.
272
273            it would be great if someone could measure this
274            at some point.
275
276            one way or another, parts of the requested area
277            that are not written to by Region::region_at()
278            for all Regions that cover the area need to be
279            zeroed.
280         */
281
282         memset (buf, 0, sizeof (Sample) * cnt);
283
284         /* this function is never called from a realtime thread, so
285            its OK to block (for short intervals).
286         */
287
288         Glib::RecMutex::Lock rm (region_lock);
289
290         framepos_t const end = start + cnt - 1;
291
292         RegionList* rlist = regions_to_read (start, start+cnt);
293
294         if (rlist->empty()) {
295                 delete rlist;
296                 return cnt;
297         }
298
299         map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
300         map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
301         vector<uint32_t> relevant_layers;
302
303         for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
304                 if ((*i)->coverage (start, end) != OverlapNone) {
305                         relevant_regions[(*i)->layer()].push_back (*i);
306                         relevant_layers.push_back ((*i)->layer());
307                 }
308         }
309
310         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Checking %1 xfades\n", _crossfades.size()));
311
312         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
313                 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 check xfade between %2 and %3 ... [ %4 ... %5 | %6 ... %7]\n",
314                                                                    name(), (*i)->out()->name(), (*i)->in()->name(), 
315                                                                    (*i)->first_frame(), (*i)->last_frame(),
316                                                                    start, end));
317                 if ((*i)->coverage (start, end) != OverlapNone) {
318                         relevant_xfades[(*i)->upper_layer()].push_back (*i);
319                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\t\txfade is relevant (coverage = %2), place on layer %1\n",
320                                                                            (*i)->upper_layer(), enum_2_string ((*i)->coverage (start, end))));
321                 }
322         }
323
324 //      RegionSortByLayer layer_cmp;
325 //      relevant_regions.sort (layer_cmp);
326
327         /* XXX this whole per-layer approach is a hack that
328            should be removed once Crossfades become
329            CrossfadeRegions and we just grab a list of relevant
330            regions and call read_at() on all of them.
331         */
332
333         sort (relevant_layers.begin(), relevant_layers.end());
334
335         for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
336
337                 DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read for layer %1\n", *l));
338
339                 vector<boost::shared_ptr<Region> > r (relevant_regions[*l]);
340                 vector<boost::shared_ptr<Crossfade> >& x (relevant_xfades[*l]);
341
342
343                 for (vector<boost::shared_ptr<Region> >::iterator i = r.begin(); i != r.end(); ++i) {
344                         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*i);
345                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name()));
346                         assert(ar);
347                         ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
348                 }
349
350                 for (vector<boost::shared_ptr<Crossfade> >::iterator i = x.begin(); i != x.end(); ++i) {
351                         DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from xfade between %1 & %2\n", (*i)->out()->name(), (*i)->in()->name()));
352                         (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
353                 }
354         }
355
356         delete rlist;
357         return ret;
358 }
359
360
361 void
362 AudioPlaylist::remove_dependents (boost::shared_ptr<Region> region)
363 {
364         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
365
366         if (in_set_state) {
367                 return;
368         }
369
370         if (r == 0) {
371                 fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist")
372                       << endmsg;
373                 return;
374         }
375
376         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ) {
377
378                 if ((*i)->involves (r)) {
379                         i = _crossfades.erase (i);
380                 } else {
381                         ++i;
382                 }
383         }
384 }
385
386
387 void
388 AudioPlaylist::flush_notifications (bool from_undo)
389 {
390         Playlist::flush_notifications (from_undo);
391
392         if (in_flush) {
393                 return;
394         }
395
396         in_flush = true;
397
398         Crossfades::iterator a;
399         for (a = _pending_xfade_adds.begin(); a != _pending_xfade_adds.end(); ++a) {
400                 NewCrossfade (*a); /* EMIT SIGNAL */
401         }
402
403         _pending_xfade_adds.clear ();
404
405         in_flush = false;
406 }
407
408 void
409 AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
410 {
411         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
412         set<boost::shared_ptr<Crossfade> > updated;
413
414         if (ar == 0) {
415                 return;
416         }
417
418         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
419
420                 Crossfades::iterator tmp;
421
422                 tmp = x;
423                 ++tmp;
424
425                 /* only update them once */
426
427                 if ((*x)->involves (ar)) {
428
429                         pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
430
431                         if (u.second) {
432                                 /* x was successfully inserted into the set, so it has not already been updated */
433                                 try {
434                                         (*x)->refresh ();
435                                 }
436
437                                 catch (Crossfade::NoCrossfadeHere& err) {
438                                         // relax, Invalidated during refresh
439                                 }
440                         }
441                 }
442
443                 x = tmp;
444         }
445 }
446
447 void
448 AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared_ptr<Region> l, boost::shared_ptr<Region> r)
449 {
450         boost::shared_ptr<AudioRegion> orig  = boost::dynamic_pointer_cast<AudioRegion>(o);
451         boost::shared_ptr<AudioRegion> left  = boost::dynamic_pointer_cast<AudioRegion>(l);
452         boost::shared_ptr<AudioRegion> right = boost::dynamic_pointer_cast<AudioRegion>(r);
453
454         for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
455                 Crossfades::iterator tmp;
456                 tmp = x;
457                 ++tmp;
458
459                 boost::shared_ptr<Crossfade> fade;
460
461                 if ((*x)->_in == orig) {
462                         if (! (*x)->covers(right->position())) {
463                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
464                         } else {
465                                 // Overlap, the crossfade is copied on the left side of the right region instead
466                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
467                         }
468                 }
469
470                 if ((*x)->_out == orig) {
471                         if (! (*x)->covers(right->position())) {
472                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
473                         } else {
474                                 // Overlap, the crossfade is copied on the right side of the left region instead
475                                 fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
476                         }
477                 }
478
479                 if (fade) {
480                         _crossfades.remove (*x);
481                         add_crossfade (fade);
482                 }
483                 x = tmp;
484         }
485 }
486
487 void
488 AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
489 {
490         boost::shared_ptr<AudioRegion> other;
491         boost::shared_ptr<AudioRegion> region;
492         boost::shared_ptr<AudioRegion> top;
493         boost::shared_ptr<AudioRegion> bottom;
494         boost::shared_ptr<Crossfade>   xfade;
495         RegionList*  touched_regions = 0;
496
497         if (in_set_state || in_partition) {
498                 return;
499         }
500
501         if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
502                 fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
503                       << endmsg;
504                 return;
505         }
506
507         if (!norefresh) {
508                 refresh_dependents (r);
509         }
510
511
512         if (!_session.config.get_auto_xfade()) {
513                 return;
514         }
515
516         for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
517                 other = boost::dynamic_pointer_cast<AudioRegion> (*i);
518
519                 if (other == region) {
520                         continue;
521                 }
522
523                 if (other->muted() || region->muted()) {
524                         continue;
525                 }
526
527                 if (other->position() == r->position() && other->length() == r->length()) {
528                         /* precise overlay of two regions - no xfade */
529                         continue;
530                 }
531
532                 if (other->layer() < region->layer()) {
533                         top = region;
534                         bottom = other;
535                 } else {
536                         top = other;
537                         bottom = region;
538                 }
539
540                 if (!top->opaque()) {
541                         continue;
542                 }
543
544                 OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
545
546                 delete touched_regions;
547                 touched_regions = 0;
548
549                 try {
550                         framecnt_t xfade_length;
551                         switch (c) {
552                         case OverlapNone:
553                                 break;
554
555                         case OverlapInternal:
556                                  /* {=============== top  =============}
557                                   *     [ ----- bottom  ------- ]
558                                   */
559                                 break;
560
561                         case OverlapExternal:
562
563                                 /*     [ -------- top ------- ]
564                                  * {=========== bottom =============}
565                                  */
566
567                                 /* to avoid discontinuities at the region boundaries of an internal
568                                    overlap (this region is completely within another), we create
569                                    two hidden crossfades at each boundary. this is not dependent
570                                    on the auto-xfade option, because we require it as basic
571                                    audio engineering.
572                                 */
573
574                                 xfade_length = min ((framecnt_t) 720, top->length());
575
576                                 if (top_region_at (top->first_frame()) == top) {
577
578                                         xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, StartOfIn));
579                                         xfade->set_position (top->first_frame());
580                                         add_crossfade (xfade);
581                                 }
582
583                                 if (top_region_at (top->last_frame() - 1) == top) {
584
585                                         /*
586                                            only add a fade out if there is no region on top of the end of 'top' (which
587                                            would cover it).
588                                         */
589
590                                         xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, EndOfOut));
591                                         xfade->set_position (top->last_frame() - xfade_length);
592                                         add_crossfade (xfade);
593                                 }
594                                 break;
595                         case OverlapStart:
596
597                                 /*                   { ==== top ============ }
598                                  *   [---- bottom -------------------]
599                                  */
600
601                                 if (_session.config.get_xfade_model() == FullCrossfade) {
602                                         touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
603                                         if (touched_regions->size() <= 2) {
604                                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
605                                                 add_crossfade (xfade);
606                                         }
607                                 } else {
608
609                                         touched_regions = regions_touched (top->first_frame(),
610                                                                            top->first_frame() + min ((framecnt_t) _session.config.get_short_xfade_seconds() * _session.frame_rate(),
611                                                                                                      top->length()));
612                                         if (touched_regions->size() <= 2) {
613                                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
614                                                 add_crossfade (xfade);
615                                         }
616                                 }
617                                 break;
618                         case OverlapEnd:
619
620
621                                 /* [---- top ------------------------]
622                                  *                { ==== bottom ============ }
623                                  */
624
625                                 if (_session.config.get_xfade_model() == FullCrossfade) {
626
627                                         touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
628                                         if (touched_regions->size() <= 2) {
629                                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
630                                                                                                      _session.config.get_xfade_model(), _session.config.get_xfades_active()));
631                                                 add_crossfade (xfade);
632                                         }
633
634                                 } else {
635                                         touched_regions = regions_touched (bottom->first_frame(),
636                                                                            bottom->first_frame() + min ((framecnt_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(),
637                                                                                                         bottom->length()));
638                                         if (touched_regions->size() <= 2) {
639                                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
640                                                 add_crossfade (xfade);
641                                         }
642                                 }
643                                 break;
644                         default:
645                                 xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other,
646                                                                                      _session.config.get_xfade_model(), _session.config.get_xfades_active()));
647                                 add_crossfade (xfade);
648                         }
649                 }
650
651                 catch (failed_constructor& err) {
652                         continue;
653                 }
654
655                 catch (Crossfade::NoCrossfadeHere& err) {
656                         continue;
657                 }
658
659         }
660
661         delete touched_regions;
662 }
663
664 void
665 AudioPlaylist::add_crossfade (boost::shared_ptr<Crossfade> xfade)
666 {
667         Crossfades::iterator ci;
668
669         for (ci = _crossfades.begin(); ci != _crossfades.end(); ++ci) {
670                 if (*(*ci) == *xfade) { // Crossfade::operator==()
671                         break;
672                 }
673         }
674
675         if (ci != _crossfades.end()) {
676                 // it will just go away
677         } else {
678                 _crossfades.push_back (xfade);
679
680                 xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
681                 xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
682
683                 notify_crossfade_added (xfade);
684         }
685 }
686
687 void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
688 {
689         if (g_atomic_int_get(&block_notifications)) {
690                 _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
691         } else {
692                 NewCrossfade (x); /* EMIT SIGNAL */
693         }
694 }
695
696 void
697 AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
698 {
699         Crossfades::iterator i;
700         boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
701
702         xfade->in()->resume_fade_in ();
703         xfade->out()->resume_fade_out ();
704
705         if ((i = find (_crossfades.begin(), _crossfades.end(), xfade)) != _crossfades.end()) {
706                 _crossfades.erase (i);
707         }
708 }
709
710 int
711 AudioPlaylist::set_state (const XMLNode& node, int version)
712 {
713         XMLNode *child;
714         XMLNodeList nlist;
715         XMLNodeConstIterator niter;
716
717         in_set_state++;
718
719         if (Playlist::set_state (node, version)) {
720                 return -1;
721         }
722
723         freeze ();
724
725         nlist = node.children();
726
727         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
728
729                 child = *niter;
730
731                 if (child->name() != "Crossfade") {
732                         continue;
733                 }
734
735                 try {
736                         boost::shared_ptr<Crossfade> xfade = boost::shared_ptr<Crossfade> (new Crossfade (*((const Playlist *)this), *child));
737                         _crossfades.push_back (xfade);
738                         xfade->Invalidated.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_invalidated, this, _1));
739                         xfade->PropertyChanged.connect_same_thread (*this, boost::bind (&AudioPlaylist::crossfade_changed, this, _1));
740                         NewCrossfade(xfade);
741                 }
742
743                 catch (failed_constructor& err) {
744                         //      cout << string_compose (_("could not create crossfade object in playlist %1"),
745                         //        _name)
746                         //    << endl;
747                         continue;
748                 }
749         }
750
751         thaw ();
752         in_set_state--;
753
754         return 0;
755 }
756
757 void
758 AudioPlaylist::clear (bool with_signals)
759 {
760         _crossfades.clear ();
761         Playlist::clear (with_signals);
762 }
763
764 XMLNode&
765 AudioPlaylist::state (bool full_state)
766 {
767         XMLNode& node = Playlist::state (full_state);
768
769         if (full_state) {
770                 for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
771                         node.add_child_nocopy ((*i)->get_state());
772                 }
773         }
774
775         return node;
776 }
777
778 void
779 AudioPlaylist::dump () const
780 {
781         boost::shared_ptr<Region>r;
782         boost::shared_ptr<Crossfade> x;
783
784         cerr << "Playlist \"" << _name << "\" " << endl
785              << regions.size() << " regions "
786              << _crossfades.size() << " crossfades"
787              << endl;
788
789         for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
790                 r = *i;
791                 cerr << "  " << r->name() << " @ " << r << " ["
792                      << r->start() << "+" << r->length()
793                      << "] at "
794                      << r->position()
795                      << " on layer "
796                      << r->layer ()
797                      << endl;
798         }
799
800         for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
801                 x = *i;
802                 cerr << "  xfade ["
803                      << x->out()->name()
804                      << ','
805                      << x->in()->name()
806                      << " @ "
807                      << x->position()
808                      << " length = "
809                      << x->length ()
810                      << " active ? "
811                      << (x->active() ? "yes" : "no")
812                      << endl;
813         }
814 }
815
816 bool
817 AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
818 {
819         boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
820
821         if (!r) {
822                 return false;
823         }
824
825         bool changed = false;
826         Crossfades::iterator c, ctmp;
827         set<boost::shared_ptr<Crossfade> > unique_xfades;
828
829         {
830                 RegionLock rlock (this);
831
832                 for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
833
834                         RegionList::iterator tmp = i;
835                         ++tmp;
836
837                         if ((*i) == region) {
838                                 regions.erase (i);
839                                 changed = true;
840                         }
841
842                         i = tmp;
843                 }
844
845                 for (set<boost::shared_ptr<Region> >::iterator x = all_regions.begin(); x != all_regions.end(); ) {
846
847                         set<boost::shared_ptr<Region> >::iterator xtmp = x;
848                         ++xtmp;
849
850                         if ((*x) == region) {
851                                 all_regions.erase (x);
852                                 changed = true;
853                         }
854
855                         x = xtmp;
856                 }
857
858                 region->set_playlist (boost::shared_ptr<Playlist>());
859         }
860
861         for (c = _crossfades.begin(); c != _crossfades.end(); ) {
862                 ctmp = c;
863                 ++ctmp;
864
865                 if ((*c)->involves (r)) {
866                         unique_xfades.insert (*c);
867                         _crossfades.erase (c);
868                 }
869
870                 c = ctmp;
871         }
872
873         if (changed) {
874                 /* overload this, it normally means "removed", not destroyed */
875                 notify_region_removed (region);
876         }
877
878         return changed;
879 }
880
881 void
882 AudioPlaylist::crossfade_changed (const PropertyChange&)
883 {
884         if (in_flush || in_set_state) {
885                 return;
886         }
887
888         /* XXX is there a loop here? can an xfade change not happen
889            due to a playlist change? well, sure activation would
890            be an example. maybe we should check the type of change
891            that occured.
892         */
893
894         notify_contents_changed ();
895 }
896
897 bool
898 AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared_ptr<Region> region)
899 {
900         if (in_flush || in_set_state) {
901                 return false;
902         }
903
904         PropertyChange our_interests;
905
906         our_interests.add (Properties::fade_in_active);
907         our_interests.add (Properties::fade_out_active);
908         our_interests.add (Properties::scale_amplitude);
909         our_interests.add (Properties::envelope_active);
910         our_interests.add (Properties::envelope);
911         our_interests.add (Properties::fade_in);
912         our_interests.add (Properties::fade_out);
913
914         bool parent_wants_notify;
915
916         parent_wants_notify = Playlist::region_changed (what_changed, region);
917
918         if (parent_wants_notify || (what_changed.contains (our_interests))) {
919                 notify_contents_changed ();
920         }
921
922         return true;
923 }
924
925 void
926 AudioPlaylist::crossfades_at (framepos_t frame, Crossfades& clist)
927 {
928         RegionLock rlock (this);
929
930         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
931                 framepos_t const start = (*i)->position ();
932                 framepos_t const end = start + (*i)->overlap_length(); // not length(), important difference
933
934                 if (frame >= start && frame <= end) {
935                         clist.push_back (*i);
936                 }
937         }
938 }
939
940 void
941 AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)> s)
942 {
943         RegionLock rl (this, false);
944         for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
945                 s (*i);
946         }
947 }
948
949 void
950 AudioPlaylist::update (const CrossfadeListProperty::ChangeRecord& change)
951 {
952         for (CrossfadeListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
953                 add_crossfade (*i);
954         }
955
956         /* don't remove crossfades here; they will be dealt with by the dependency code */
957 }
958
959 boost::shared_ptr<Crossfade>
960 AudioPlaylist::find_crossfade (const PBD::ID& id) const
961 {
962         Crossfades::const_iterator i = _crossfades.begin ();
963         while (i != _crossfades.end() && (*i)->id() != id) {
964                 ++i;
965         }
966
967         if (i == _crossfades.end()) {
968                 return boost::shared_ptr<Crossfade> ();
969         }
970
971         return *i;
972 }
973
974 struct crossfade_triple {
975     boost::shared_ptr<Region> old_in;
976     boost::shared_ptr<Region> new_in;
977     boost::shared_ptr<Region> new_out;
978 };
979
980 void
981 AudioPlaylist::copy_dependents (const vector<TwoRegions>& old_and_new, Playlist* other) const
982 {
983         AudioPlaylist* other_audio = dynamic_cast<AudioPlaylist*>(other);
984
985         if (!other_audio) {
986                 return;
987         }
988
989         /* our argument is a vector of old and new regions. Each old region
990            might be participant in a crossfade that is already present. Each new
991            region is a copy of the old region, present in the other playlist.
992
993            our task is to find all the relevant xfades in our playlist (involving
994            the "old" regions) and place copies of them in the other playlist.
995         */
996
997         typedef map<boost::shared_ptr<Crossfade>,crossfade_triple> CrossfadeInfo;
998         CrossfadeInfo crossfade_info;
999
1000         /* build up a record that links crossfades, old regions and new regions
1001          */
1002
1003         for (vector<TwoRegions>::const_iterator on = old_and_new.begin(); on != old_and_new.end(); ++on) {
1004
1005                 for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
1006
1007                         if ((*i)->in() == on->first) {
1008
1009                                 CrossfadeInfo::iterator cf;
1010
1011                                 if ((cf = crossfade_info.find (*i)) != crossfade_info.end()) {
1012
1013                                         /* already have a record for the old fade-in region,
1014                                            so note the new fade-in region
1015                                         */
1016
1017                                         cf->second.new_in = on->second;
1018
1019                                 } else {
1020
1021                                         /* add a record of this crossfade, keeping an association
1022                                            with the new fade-in region
1023                                         */
1024
1025                                         crossfade_triple ct;
1026
1027                                         ct.old_in = on->first;
1028                                         ct.new_in = on->second;
1029
1030                                         crossfade_info[*i] = ct;
1031                                 }
1032
1033                         } else if ((*i)->out() == on->first) {
1034
1035                                 /* this old region is the fade-out region of this crossfade */
1036
1037                                 CrossfadeInfo::iterator cf;
1038
1039                                 if ((cf = crossfade_info.find (*i)) != crossfade_info.end()) {
1040
1041                                         /* already have a record for this crossfade, so just keep
1042                                            an association for the new fade out region
1043                                         */
1044
1045                                         cf->second.new_out = on->second;
1046
1047                                 } else {
1048
1049                                         /* add a record of this crossfade, keeping an association
1050                                            with the new fade-in region
1051                                         */
1052
1053                                         crossfade_triple ct;
1054
1055                                         ct.old_in = on->first;
1056                                         ct.new_out = on->second;
1057
1058                                         crossfade_info[*i] = ct;
1059                                 }
1060                         }
1061                 }
1062         }
1063
1064         for (CrossfadeInfo::iterator ci = crossfade_info.begin(); ci != crossfade_info.end(); ++ci) {
1065
1066                 /* for each crossfade that involves at least two of the old regions,
1067                    create a new identical crossfade with the new regions
1068                 */
1069
1070                 if (!ci->second.new_in || !ci->second.new_out) {
1071                         continue;
1072                 }
1073
1074                 boost::shared_ptr<Crossfade> new_xfade (new Crossfade (ci->first,
1075                                                                        boost::dynamic_pointer_cast<AudioRegion>(ci->second.new_in),
1076                                                                        boost::dynamic_pointer_cast<AudioRegion>(ci->second.new_out)));
1077
1078                 /* add it at the right position - which must be at the start
1079                  * of the fade-in region
1080                  */
1081
1082                 new_xfade->set_position (ci->second.new_in->position());
1083                 other_audio->add_crossfade (new_xfade);
1084         }
1085 }
1086
1087 void
1088 AudioPlaylist::pre_combine (vector<boost::shared_ptr<Region> >& copies)
1089 {
1090         RegionSortByPosition cmp;
1091         boost::shared_ptr<AudioRegion> ar;
1092
1093         sort (copies.begin(), copies.end(), cmp);
1094
1095         ar = boost::dynamic_pointer_cast<AudioRegion> (copies.front());
1096
1097         /* disable fade in of the first region */
1098
1099         if (ar) {
1100                 ar->set_fade_in_active (false);
1101         }
1102
1103         ar = boost::dynamic_pointer_cast<AudioRegion> (copies.back());
1104
1105         /* disable fade out of the last region */
1106
1107         if (ar) {
1108                 ar->set_fade_out_active (false);
1109         }
1110 }
1111
1112 void
1113 AudioPlaylist::post_combine (vector<boost::shared_ptr<Region> >& originals, boost::shared_ptr<Region> compound_region)
1114 {
1115         RegionSortByPosition cmp;
1116         boost::shared_ptr<AudioRegion> ar;
1117         boost::shared_ptr<AudioRegion> cr;
1118
1119         if ((cr = boost::dynamic_pointer_cast<AudioRegion> (compound_region)) == 0) {
1120                 return;
1121         }
1122
1123         sort (originals.begin(), originals.end(), cmp);
1124
1125         ar = boost::dynamic_pointer_cast<AudioRegion> (originals.front());
1126
1127         /* copy the fade in of the first into the compound region */
1128
1129         if (ar) {
1130                 cr->set_fade_in (ar->fade_in());
1131         }
1132
1133         ar = boost::dynamic_pointer_cast<AudioRegion> (originals.back());
1134
1135         if (ar) {
1136                 /* copy the fade out of the last into the compound region */
1137                 cr->set_fade_out (ar->fade_out());
1138         }
1139 }
1140
1141 void
1142 AudioPlaylist::pre_uncombine (vector<boost::shared_ptr<Region> >& originals, boost::shared_ptr<Region> compound_region)
1143 {
1144         RegionSortByPosition cmp;
1145         boost::shared_ptr<AudioRegion> ar;
1146         boost::shared_ptr<AudioRegion> cr = boost::dynamic_pointer_cast<AudioRegion>(compound_region);
1147
1148         if (!cr) {
1149                 return;
1150         }
1151
1152         sort (originals.begin(), originals.end(), cmp);
1153
1154         /* no need to call clear_changes() on the originals because that is
1155          * done within Playlist::uncombine ()
1156          */
1157
1158         for (vector<boost::shared_ptr<Region> >::iterator i = originals.begin(); i != originals.end(); ++i) {
1159
1160                 if ((ar = boost::dynamic_pointer_cast<AudioRegion> (*i)) == 0) {
1161                         continue;
1162                 }
1163
1164                 /* scale the uncombined regions by any gain setting for the
1165                  * compound one.
1166                  */
1167
1168                 ar->set_scale_amplitude (ar->scale_amplitude() * cr->scale_amplitude());
1169
1170                 if (i == originals.begin()) {
1171
1172                         /* copy the compound region's fade in back into the first
1173                            original region.
1174                         */
1175
1176                         if (cr->fade_in()->back()->when <= ar->length()) {
1177                                 /* don't do this if the fade is longer than the
1178                                  * region
1179                                  */
1180                                 ar->set_fade_in (cr->fade_in());
1181                         }
1182
1183
1184                 } else if (*i == originals.back()) {
1185
1186                         /* copy the compound region's fade out back into the last
1187                            original region.
1188                         */
1189
1190                         if (cr->fade_out()->back()->when <= ar->length()) {
1191                                 /* don't do this if the fade is longer than the
1192                                  * region
1193                                  */
1194                                 ar->set_fade_out (cr->fade_out());
1195                         }
1196
1197                 }
1198
1199                 _session.add_command (new StatefulDiffCommand (*i));
1200         }
1201 }