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