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