not actually working attempt to copy relevant xfades into compound regions; fix compi...
[ardour.git] / libs / ardour / audio_playlist.cc
index 2ac3edff80d755999f9b8fdb19c01bdec5acc3ad..e120ebb5ab15cf097bcffe078965cd9186d3e84d 100644 (file)
@@ -27,7 +27,6 @@
 #include "ardour/audioplaylist.h"
 #include "ardour/audioregion.h"
 #include "ardour/crossfade.h"
-#include "ardour/crossfade_compare.h"
 #include "ardour/session.h"
 #include "pbd/enumwriter.h"
 
@@ -57,6 +56,13 @@ CrossfadeListProperty::CrossfadeListProperty (AudioPlaylist& pl)
        
 }
 
+CrossfadeListProperty::CrossfadeListProperty (CrossfadeListProperty const & p)
+       : PBD::SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (p)
+       , _playlist (p._playlist)
+{
+
+}
+
 
 CrossfadeListProperty *
 CrossfadeListProperty::create () const
@@ -157,12 +163,91 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, stri
        }
 }
 
-AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
+AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, framepos_t start, framecnt_t cnt, string name, bool hidden)
        : Playlist (other, start, cnt, name, hidden)
        , _crossfades (*this)
 {
-       add_property (_crossfades);
+       RegionLock rlock2 (const_cast<AudioPlaylist*> (other.get()));
+       in_set_state++;
        
+       add_property (_crossfades);
+
+       framepos_t const end = start + cnt - 1;
+
+       /* Audio regions that have been created by the Playlist constructor
+          will currently have the same fade in/out as the regions that they
+          were created from.  This is wrong, so reset the fades here.
+       */
+
+       RegionList::iterator ours = regions.begin ();
+
+       for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
+               boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (*i);
+               assert (region);
+
+               framecnt_t fade_in = 64;
+               framecnt_t fade_out = 64;
+               framepos_t position;
+               framecnt_t len;
+               frameoffset_t offset;
+
+               switch (region->coverage (start, end)) {
+               case OverlapNone:
+                       continue;
+
+               case OverlapInternal:
+               {
+                       framecnt_t const offset = start - region->position ();
+                       framecnt_t const trim = region->last_frame() - end;
+                       if (region->fade_in()->back()->when > offset) {
+                               fade_in = region->fade_in()->back()->when - offset;
+                       }
+                       if (region->fade_out()->back()->when > trim) {
+                               fade_out = region->fade_out()->back()->when - trim;
+                       }
+                       break;
+               }
+
+               case OverlapStart: {
+                       position = region->position() - start;
+                       len = end - region->position();
+
+                       if (end > region->position() + region->fade_in()->back()->when)
+                               fade_in = region->fade_in()->back()->when;  //end is after fade-in, preserve the fade-in
+                       if (end > region->last_frame() - region->fade_out()->back()->when)
+                               fade_out = region->fade_out()->back()->when - ( region->last_frame() - end );  //end is inside the fadeout, preserve the fades endpoint
+                       break;
+               }
+               
+               case OverlapEnd: {
+                       position = 0;
+                       offset = start - region->position();
+                       len = region->length() - offset;
+
+                       if (start < region->last_frame() - region->fade_out()->back()->when)  //start is before fade-out, preserve the fadeout
+                               fade_out = region->fade_out()->back()->when;
+                       
+                       if (start < region->position() + region->fade_in()->back()->when)
+                               fade_in = region->fade_in()->back()->when - (start - region->position());  //end is inside the fade-in, preserve the fade-in endpoint
+                       break;
+               }
+               
+               case OverlapExternal:
+                       fade_in = region->fade_in()->back()->when;
+                       fade_out = region->fade_out()->back()->when;
+                       break;
+               }
+
+               boost::shared_ptr<AudioRegion> our_region = boost::dynamic_pointer_cast<AudioRegion> (*ours);
+               assert (our_region);
+
+               our_region->set_fade_in_length (fade_in);
+               our_region->set_fade_out_length (fade_out);
+               ++ours;
+       }
+
+       in_set_state--;
+
        /* this constructor does NOT notify others (session) */
 }
 
@@ -177,14 +262,11 @@ struct RegionSortByLayer {
     }
 };
 
-ARDOUR::nframes_t
-AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t start,
-                    nframes_t cnt, unsigned chan_n)
+ARDOUR::framecnt_t
+AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, framepos_t start,
+                    framecnt_t cnt, unsigned chan_n)
 {
-       nframes_t ret = cnt;
-       nframes_t end;
-       nframes_t read_frames;
-       nframes_t skip_frames;
+       framecnt_t ret = cnt;
 
        /* optimizing this memset() away involves a lot of conditionals
           that may well cause more of a hit due to cache misses
@@ -207,9 +289,9 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf
 
        Glib::RecMutex::Lock rm (region_lock);
 
-       end =  start + cnt - 1;
-       read_frames = 0;
-       skip_frames = 0;
+       framepos_t const end = start + cnt - 1;
+       framecnt_t read_frames = 0;
+       framecnt_t skip_frames = 0;
        _read_data_count = 0;
 
        _read_data_count = 0;
@@ -443,6 +525,10 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
                        continue;
                }
 
+                if (other->position() == r->position() && other->length() == r->length()) {
+                        /* precise overlay of two regions - no xfade */
+                        continue;
+                }
 
                if (other->layer() < region->layer()) {
                        top = region;
@@ -834,15 +920,13 @@ AudioPlaylist::region_changed (const PropertyChange& what_changed, boost::shared
 }
 
 void
-AudioPlaylist::crossfades_at (nframes_t frame, Crossfades& clist)
+AudioPlaylist::crossfades_at (framepos_t frame, Crossfades& clist)
 {
        RegionLock rlock (this);
 
        for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) {
-               nframes_t start, end;
-
-               start = (*i)->position();
-               end = start + (*i)->overlap_length(); // not length(), important difference
+               framepos_t const start = (*i)->position ();
+               framepos_t const end = start + (*i)->overlap_length(); // not length(), important difference
 
                if (frame >= start && frame <= end) {
                        clist.push_back (*i);
@@ -868,3 +952,131 @@ AudioPlaylist::update (const CrossfadeListProperty::ChangeRecord& change)
 
        /* 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, boost::shared_ptr<Playlist> other)
+{
+       boost::shared_ptr<AudioPlaylist> other_audio = boost::dynamic_pointer_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::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 */
+
+               new_xfade->set_position (new_xfade->position() + (ci->second.new_in->position() - ci->second.old_in->position()), this);
+               cerr << "Add new xfade to new playlist @ " << new_xfade->position() << " len " << new_xfade->length()
+                    << " in = " << new_xfade->in()->name() << " out = " << new_xfade->out()->name() << endl;
+               other_audio->add_crossfade (new_xfade);
+       }
+}