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