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