First stage of options rework.
[ardour.git] / libs / ardour / audio_playlist.cc
index dcba0ae31c6e83d4465ad44c79dd942593eb4375..6439c1b91776dec6f96d9ebdcaa5ef5e3eb81a89 100644 (file)
@@ -15,7 +15,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id$
 */
 
 #include <algorithm>
 
 #include <sigc++/bind.h>
 
-#include <ardour/types.h>
-#include <ardour/configuration.h>
-#include <ardour/audioplaylist.h>
-#include <ardour/audioregion.h>
-#include <ardour/crossfade.h>
-#include <ardour/crossfade_compare.h>
-#include <ardour/session.h>
+#include "ardour/types.h"
+#include "ardour/configuration.h"
+#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"
 
 #include "i18n.h"
 
@@ -79,7 +79,7 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, stri
                                        if ((*xfades)->out() == ar2) {
                                                boost::shared_ptr<AudioRegion>in  = boost::dynamic_pointer_cast<AudioRegion>(*in_n);
                                                boost::shared_ptr<AudioRegion>out = boost::dynamic_pointer_cast<AudioRegion>(*out_n);
-                                               boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*(*xfades), in, out));
+                                               boost::shared_ptr<Crossfade> new_fade = boost::shared_ptr<Crossfade> (new Crossfade (*xfades, in, out));
                                                add_crossfade(new_fade);
                                                break;
                                        }
@@ -147,19 +147,27 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf
           its OK to block (for short intervals).
        */
 
-       Glib::Mutex::Lock rm (region_lock);
+       Glib::RecMutex::Lock rm (region_lock);
 
        end =  start + cnt - 1;
-
        read_frames = 0;
        skip_frames = 0;
        _read_data_count = 0;
 
+       _read_data_count = 0;
+
+       RegionList* rlist = regions_to_read (start, start+cnt);
+
+       if (rlist->empty()) {
+               delete rlist;
+               return cnt;
+       }
+
        map<uint32_t,vector<boost::shared_ptr<Region> > > relevant_regions;
        map<uint32_t,vector<boost::shared_ptr<Crossfade> > > relevant_xfades;
        vector<uint32_t> relevant_layers;
 
-       for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+       for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ++i) {
                if ((*i)->coverage (start, end) != OverlapNone) {
                        relevant_regions[(*i)->layer()].push_back (*i);
                        relevant_layers.push_back ((*i)->layer());
@@ -204,6 +212,7 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf
                }
        }
 
+       delete rlist;
        return ret;
 }
 
@@ -276,10 +285,16 @@ AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
 
                if ((*x)->involves (ar)) {
 
-                       if (find (updated.begin(), updated.end(), *x) == updated.end()) {
-                               if ((*x)->refresh ()) {
-                                       /* not invalidated by the refresh */
-                                       updated.insert (*x);
+                       pair<set<boost::shared_ptr<Crossfade> >::iterator, bool> const u = updated.insert (*x);
+                       
+                       if (u.second) {
+                               /* x was successfully inserted into the set, so it has not already been updated */
+                               try {
+                                       (*x)->refresh ();
+                               }
+
+                               catch (Crossfade::NoCrossfadeHere& err) {
+                                       // relax, Invalidated during refresh
                                }
                        }
                }
@@ -304,19 +319,19 @@ AudioPlaylist::finalize_split_region (boost::shared_ptr<Region> o, boost::shared
                
                if ((*x)->_in == orig) {
                        if (! (*x)->covers(right->position())) {
-                               fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, left, (*x)->_out));
+                               fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, left, (*x)->_out));
                        } else {
                                // Overlap, the crossfade is copied on the left side of the right region instead
-                               fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, right, (*x)->_out));
+                               fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, right, (*x)->_out));
                        }
                }
                
                if ((*x)->_out == orig) {
                        if (! (*x)->covers(right->position())) {
-                               fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, right));
+                               fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, right));
                        } else {
                                // Overlap, the crossfade is copied on the right side of the left region instead
-                               fade = boost::shared_ptr<Crossfade> (new Crossfade (**x, (*x)->_in, left));
+                               fade = boost::shared_ptr<Crossfade> (new Crossfade (*x, (*x)->_in, left));
                        }
                }
                
@@ -336,13 +351,12 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
        boost::shared_ptr<AudioRegion> top;
        boost::shared_ptr<AudioRegion> bottom;
        boost::shared_ptr<Crossfade>   xfade;
+       RegionList*  touched_regions;
 
        if (in_set_state || in_partition) {
                return;
        }
 
-       cerr << "Check dependents of " << r->name() << endl;
-
        if ((region = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
                fatal << _("programming error: non-audio Region tested for overlap in audio playlist")
                      << endmsg;
@@ -353,7 +367,8 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
                refresh_dependents (r);
        }
 
-       if (!Config->get_auto_xfade()) {
+
+       if (!_session.config.get_auto_xfade()) {
                return;
        }
 
@@ -380,9 +395,12 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
                        bottom = region;
                }
 
+               if (!top->opaque()) {
+                       continue;
+               }
 
                OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
-               
+
                try {
                        switch (c) {
                        case OverlapNone:
@@ -395,7 +413,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
                                break;
 
                        case OverlapExternal:
-
                                /*     [ -------- top ------- ]
                                 * {=========== bottom =============}
                                 */
@@ -408,11 +426,15 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
                                */
                                
                                xfade_length = min ((nframes_t) 720, top->length());
-                               
-                               xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
-                               add_crossfade (xfade);
-                               
+
+                               if (top_region_at (top->first_frame()) == top) {
+                                       xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
+                                       add_crossfade (xfade);
+                               }
+
                                if (top_region_at (top->last_frame() - 1) == top) {
+
                                        /* 
                                           only add a fade out if there is no region on top of the end of 'top' (which 
                                           would cover it).
@@ -422,9 +444,58 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
                                        add_crossfade (xfade);
                                }
                                break;
-                               
+                       case OverlapStart:
+
+                               /*                   { ==== top ============ } 
+                                *   [---- bottom -------------------] 
+                                */
+
+                               if (_session.config.get_xfade_model() == FullCrossfade) {
+                                       touched_regions = regions_touched (top->first_frame(), bottom->last_frame());
+                                       if (touched_regions->size() <= 2) {
+                                               xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
+                                               add_crossfade (xfade);
+                                       }
+                               } else {
+
+                                       touched_regions = regions_touched (top->first_frame(), 
+                                                                          top->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(), 
+                                                                                                    top->length()));
+                                       if (touched_regions->size() <= 2) {
+                                               xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
+                                               add_crossfade (xfade);
+                                       }
+                               }
+                               break;
+                       case OverlapEnd:
+
+
+                               /* [---- top ------------------------] 
+                                *                { ==== bottom ============ } 
+                                */ 
+
+                               if (_session.config.get_xfade_model() == FullCrossfade) {
+
+                                       touched_regions = regions_touched (bottom->first_frame(), top->last_frame());
+                                       if (touched_regions->size() <= 2) {
+                                               xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, 
+                                                                                                    _session.config.get_xfade_model(), _session.config.get_xfades_active()));
+                                               add_crossfade (xfade);
+                                       }
+
+                               } else {
+                                       touched_regions = regions_touched (bottom->first_frame(), 
+                                                                          bottom->first_frame() + min ((nframes_t)_session.config.get_short_xfade_seconds() * _session.frame_rate(), 
+                                                                                                       bottom->length()));
+                                       if (touched_regions->size() <= 2) {
+                                               xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, _session.config.get_xfade_model(), _session.config.get_xfades_active()));
+                                               add_crossfade (xfade);
+                                       }
+                               }
+                               break;
                        default:
-                               xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active()));
+                               xfade = boost::shared_ptr<Crossfade> (new Crossfade (region, other, 
+                                                                                    _session.config.get_xfade_model(), _session.config.get_xfades_active()));
                                add_crossfade (xfade);
                        }
                }
@@ -468,14 +539,16 @@ void AudioPlaylist::notify_crossfade_added (boost::shared_ptr<Crossfade> x)
        if (g_atomic_int_get(&block_notifications)) {
                _pending_xfade_adds.insert (_pending_xfade_adds.end(), x);
        } else {
+
                NewCrossfade (x); /* EMIT SIGNAL */
        }
 }
 
 void
-AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Crossfade> xfade)
+AudioPlaylist::crossfade_invalidated (boost::shared_ptr<Region> r)
 {
        Crossfades::iterator i;
+       boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
 
        xfade->in()->resume_fade_in ();
        xfade->out()->resume_fade_out ();
@@ -603,7 +676,7 @@ AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
                return false;
        }
 
-       { 
+       {
                RegionLock rlock (this);
 
                for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {