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