+void
+AudioPlaylist::update (const CrossfadeListProperty::ChangeRecord& change)
+{
+ for (CrossfadeListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
+ add_crossfade (*i);
+ }
+
+ /* don't remove crossfades here; they will be dealt with by the dependency code */
+}
+
+boost::shared_ptr<Crossfade>
+AudioPlaylist::find_crossfade (const PBD::ID& id) const
+{
+ Crossfades::const_iterator i = _crossfades.begin ();
+ while (i != _crossfades.end() && (*i)->id() != id) {
+ ++i;
+ }
+
+ if (i == _crossfades.end()) {
+ return boost::shared_ptr<Crossfade> ();
+ }
+
+ return *i;
+}
+
+struct crossfade_triple {
+ boost::shared_ptr<Region> old_in;
+ boost::shared_ptr<Region> new_in;
+ boost::shared_ptr<Region> new_out;
+};
+
+void
+AudioPlaylist::copy_dependents (const vector<TwoRegions>& old_and_new, Playlist* other) const
+{
+ AudioPlaylist* other_audio = dynamic_cast<AudioPlaylist*>(other);
+
+ if (!other_audio) {
+ return;
+ }
+
+ /* our argument is a vector of old and new regions. Each old region
+ might be participant in a crossfade that is already present. Each new
+ region is a copy of the old region, present in the other playlist.
+
+ our task is to find all the relevant xfades in our playlist (involving
+ the "old" regions) and place copies of them in the other playlist.
+ */
+
+ typedef map<boost::shared_ptr<Crossfade>,crossfade_triple> CrossfadeInfo;
+ CrossfadeInfo crossfade_info;
+
+ /* build up a record that links crossfades, old regions and new regions
+ */
+
+ for (vector<TwoRegions>::const_iterator on = old_and_new.begin(); on != old_and_new.end(); ++on) {
+
+ for (Crossfades::const_iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
+
+ if ((*i)->in() == on->first) {
+
+ CrossfadeInfo::iterator cf;
+
+ if ((cf = crossfade_info.find (*i)) != crossfade_info.end()) {
+
+ /* already have a record for the old fade-in region,
+ so note the new fade-in region
+ */
+
+ cf->second.new_in = on->second;
+
+ } else {
+
+ /* add a record of this crossfade, keeping an association
+ with the new fade-in region
+ */
+
+ crossfade_triple ct;
+
+ ct.old_in = on->first;
+ ct.new_in = on->second;
+
+ crossfade_info[*i] = ct;
+ }
+
+ } else if ((*i)->out() == on->first) {
+
+ /* this old region is the fade-out region of this crossfade */
+
+ CrossfadeInfo::iterator cf;
+
+ if ((cf = crossfade_info.find (*i)) != crossfade_info.end()) {
+
+ /* already have a record for this crossfade, so just keep
+ an association for the new fade out region
+ */
+
+ cf->second.new_out = on->second;
+
+ } else {
+
+ /* add a record of this crossfade, keeping an association
+ with the new fade-in region
+ */
+
+ crossfade_triple ct;
+
+ ct.old_in = on->first;
+ ct.new_out = on->second;
+
+ crossfade_info[*i] = ct;
+ }
+ }
+ }
+ }
+
+ for (CrossfadeInfo::iterator ci = crossfade_info.begin(); ci != crossfade_info.end(); ++ci) {
+
+ /* for each crossfade that involves at least two of the old regions,
+ create a new identical crossfade with the new regions
+ */
+
+ if (!ci->second.new_in || !ci->second.new_out) {
+ continue;
+ }
+
+ boost::shared_ptr<Crossfade> new_xfade (new Crossfade (ci->first,
+ boost::dynamic_pointer_cast<AudioRegion>(ci->second.new_in),
+ boost::dynamic_pointer_cast<AudioRegion>(ci->second.new_out)));
+
+ /* add it at the right position - which must be at the start
+ * of the fade-in region
+ */
+
+ new_xfade->set_position (ci->second.new_in->position());
+ other_audio->add_crossfade (new_xfade);
+ }
+}
+
+void
+AudioPlaylist::pre_combine (vector<boost::shared_ptr<Region> >& copies)
+{
+ RegionSortByPosition cmp;
+ boost::shared_ptr<AudioRegion> ar;
+
+ sort (copies.begin(), copies.end(), cmp);
+
+ ar = boost::dynamic_pointer_cast<AudioRegion> (copies.front());
+
+ /* disable fade in of the first region */
+
+ if (ar) {
+ ar->set_fade_in_active (false);
+ }
+
+ ar = boost::dynamic_pointer_cast<AudioRegion> (copies.back());
+
+ /* disable fade out of the last region */
+
+ if (ar) {
+ ar->set_fade_out_active (false);
+ }
+}
+
+void
+AudioPlaylist::post_combine (vector<boost::shared_ptr<Region> >& originals, boost::shared_ptr<Region> compound_region)
+{
+ RegionSortByPosition cmp;
+ boost::shared_ptr<AudioRegion> ar;
+ boost::shared_ptr<AudioRegion> cr;
+
+ if ((cr = boost::dynamic_pointer_cast<AudioRegion> (compound_region)) == 0) {
+ return;
+ }
+
+ sort (originals.begin(), originals.end(), cmp);
+
+ ar = boost::dynamic_pointer_cast<AudioRegion> (originals.front());
+
+ /* copy the fade in of the first into the compound region */
+
+ if (ar) {
+ cr->set_fade_in (ar->fade_in());
+ }
+
+ ar = boost::dynamic_pointer_cast<AudioRegion> (originals.back());
+
+ if (ar) {
+ /* copy the fade out of the last into the compound region */
+ cr->set_fade_out (ar->fade_out());
+ }
+}
+
+void
+AudioPlaylist::pre_uncombine (vector<boost::shared_ptr<Region> >& originals, boost::shared_ptr<Region> compound_region)
+{
+ RegionSortByPosition cmp;
+ boost::shared_ptr<AudioRegion> ar;
+ boost::shared_ptr<AudioRegion> cr = boost::dynamic_pointer_cast<AudioRegion>(compound_region);
+
+ if (!cr) {
+ return;
+ }
+
+ sort (originals.begin(), originals.end(), cmp);
+
+ /* no need to call clear_changes() on the originals because that is
+ * done within Playlist::uncombine ()
+ */
+
+ for (vector<boost::shared_ptr<Region> >::iterator i = originals.begin(); i != originals.end(); ++i) {
+
+ if ((ar = boost::dynamic_pointer_cast<AudioRegion> (*i)) == 0) {
+ continue;
+ }
+
+ /* scale the uncombined regions by any gain setting for the
+ * compound one.
+ */
+
+ ar->set_scale_amplitude (ar->scale_amplitude() * cr->scale_amplitude());
+
+ if (i == originals.begin()) {
+
+ /* copy the compound region's fade in back into the first
+ original region.
+ */
+
+ if (cr->fade_in()->back()->when <= ar->length()) {
+ /* don't do this if the fade is longer than the
+ * region
+ */
+ ar->set_fade_in (cr->fade_in());
+ }
+
+
+ } else if (*i == originals.back()) {
+
+ /* copy the compound region's fade out back into the last
+ original region.
+ */
+
+ if (cr->fade_out()->back()->when <= ar->length()) {
+ /* don't do this if the fade is longer than the
+ * region
+ */
+ ar->set_fade_out (cr->fade_out());
+ }
+
+ }
+
+ _session.add_command (new StatefulDiffCommand (*i));
+ }
+}