Use sys::basename instead of PBD::basename_nosuffix in Session::import_audiofile
[ardour.git] / libs / ardour / playlist.cc
index 325ef27a18ad27cb92b7675a90bd83b0438522d6..8d20d8539d75417cb5bc6313f6629f76b6a9738b 100644 (file)
@@ -70,17 +70,19 @@ struct RegionSortByLastLayerOp {
     }
 };
 
+
 Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
-       : _session (sess)
+       : SessionObject(sess, nom)
        , _type(type)
 {
        init (hide);
+       first_set_state = false;
        _name = nom;
        
 }
 
 Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
-       : _session (sess)
+       : SessionObject(sess, "unnamed playlist")
        , _type(type)
 {
        const XMLProperty* prop = node.property("type");
@@ -93,7 +95,7 @@ Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide
 }
 
 Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
-       : _name (namestr), _session (other->_session), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
+       : SessionObject(other->_session, namestr), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
 {
        init (hide);
 
@@ -113,6 +115,7 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, boo
        _edit_mode = other->_edit_mode;
 
        in_set_state = 0;
+       first_set_state = false;
        in_flush = false;
        in_partition = false;
        subcnt = 0;
@@ -124,7 +127,7 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, boo
 }
 
 Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
-       : _name (str), _session (other->_session), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
+       : SessionObject(other->_session, str), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
 {
        RegionLock rlock2 (const_cast<Playlist*> (other.get()));
 
@@ -185,6 +188,7 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nf
        }
        
        in_set_state--;
+       first_set_state = false;
 
        /* this constructor does NOT notify others (session) */
 }
@@ -225,6 +229,7 @@ Playlist::init (bool hide)
        g_atomic_int_set (&ignore_state_changes, 0);
        pending_modified = false;
        pending_length = false;
+       first_set_state = true;
        _refcnt = 0;
        _hidden = hide;
        _splicing = false;
@@ -243,14 +248,14 @@ Playlist::init (bool hide)
 }
 
 Playlist::Playlist (const Playlist& pl)
-       : _session (pl._session)
+       : SessionObject(pl._session, pl._name)
        , _type(pl.data_type())
 {
        fatal << _("playlist const copy constructor called") << endmsg;
 }
 
 Playlist::Playlist (Playlist& pl)
-       : _session (pl._session)
+       : SessionObject(pl._session, pl._name)
        , _type(pl.data_type())
 {
        fatal << _("playlist non-const copy constructor called") << endmsg;
@@ -269,8 +274,8 @@ Playlist::~Playlist ()
        /* GoingAway must be emitted by derived classes */
 }
 
-void
-Playlist::set_name (string str)
+bool
+Playlist::set_name (const string& str)
 {
        /* in a typical situation, a playlist is being used
           by one diskstream and also is referenced by the
@@ -279,11 +284,10 @@ Playlist::set_name (string str)
        */
 
        if (_refcnt > 2) {
-               return;
+               return false;
+       } else {
+               return SessionObject::set_name(str);
        }
-
-       _name = str; 
-       NameChanged(); /* EMIT SIGNAL */
 }
 
 /***********************************************************************
@@ -347,7 +351,9 @@ Playlist::notify_region_removed (boost::shared_ptr<Region> r)
                /* this might not be true, but we have to act
                   as though it could be.
                */
+               pending_length = false;
                LengthChanged (); /* EMIT SIGNAL */
+               pending_modified = false;
                Modified (); /* EMIT SIGNAL */
        }
 }
@@ -364,7 +370,9 @@ Playlist::notify_region_added (boost::shared_ptr<Region> r)
                pending_modified = true;
                pending_length = true;
        } else {
+               pending_length = false;
                LengthChanged (); /* EMIT SIGNAL */
+               pending_modified = false;
                Modified (); /* EMIT SIGNAL */
        }
 }
@@ -375,7 +383,9 @@ Playlist::notify_length_changed ()
        if (holding_state ()) {
                pending_length = true;
        } else {
+               pending_length = false;
                LengthChanged(); /* EMIT SIGNAL */
+               pending_modified = false;
                Modified (); /* EMIT SIGNAL */
        }
 }
@@ -434,6 +444,7 @@ Playlist::flush_notifications ()
                }
                pending_modified = false;
                Modified (); /* EMIT SIGNAL */
+               
        }
 
        for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
@@ -455,7 +466,7 @@ void
 Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, float times) 
 { 
        RegionLock rlock (this);
-       
+       delay_notifications();
        times = fabs (times);
        
        int itimes = (int) floor (times);
@@ -491,6 +502,8 @@ Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, floa
                boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
                add_region_internal (sub, pos);
        }
+
+       release_notifications ();
 }
 
 void
@@ -515,10 +528,10 @@ Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t posit
                 old_length = _get_maximum_extent();
        }
 
-       if (!in_set_state) {
+       if (!first_set_state) {
                boost::shared_ptr<Playlist> foo (shared_from_this());
                region->set_playlist (boost::weak_ptr<Playlist>(foo));
-       }
+       } 
 
        region->set_position (position, this);
 
@@ -581,6 +594,11 @@ Playlist::remove_region_internal (boost::shared_ptr<Region>region)
                old_length = _get_maximum_extent();
        }
 
+       if (!in_set_state) {
+               /* unset playlist */
+               region->set_playlist (boost::weak_ptr<Playlist>());
+       }
+
        for (i = regions.begin(); i != regions.end(); ++i) {
                if (*i == region) {
 
@@ -646,7 +664,6 @@ Playlist::partition (nframes_t start, nframes_t end, bool just_top_level)
 void
 Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist)
 {
-       RegionLock rlock (this);
        boost::shared_ptr<Region> region;
        boost::shared_ptr<Region> current;
        string new_name;
@@ -654,14 +671,19 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
        OverlapType overlap;
        nframes_t pos1, pos2, pos3, pos4;
        RegionList new_regions;
+       RegionList copy;
 
        in_partition = true;
 
+       delay_notifications();
+
        /* need to work from a copy, because otherwise the regions we add during the process
           get operated on as well.
        */
-
-       RegionList copy = regions;
+       {
+               RegionLock rlock (this);
+               copy = regions;
+       }
 
        for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) {
                
@@ -669,9 +691,10 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                ++tmp;
 
                current = *i;
-               
+
                if (current->first_frame() == start && current->last_frame() == end) {
                        if (cutting) {
+                               RegionLock rlock (this);
                                remove_region_internal (current);
                        }
                        continue;
@@ -680,14 +703,14 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                if ((overlap = current->coverage (start, end)) == OverlapNone) {
                        continue;
                }
-               
+
                pos1 = current->position();
                pos2 = start;
                pos3 = end;
                pos4 = current->last_frame();
 
                if (overlap == OverlapInternal) {
-                       
+
                        /* split: we need 3 new regions, the front, middle and end.
                           cut:   we need 2 regions, the front and end.
                        */
@@ -707,9 +730,10 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                
                                /* "middle" ++++++ */
                                
-                               _session.region_name (new_name, current->name(), false);
+                               _session.region_name (new_name, current->name(), false); //takes the session-wide region lock
                                region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
                                                       regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
+                               RegionLock rlock (this);
                                add_region_internal (region, start);
                                new_regions.push_back (region);
                        }
@@ -719,10 +743,11 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                        _session.region_name (new_name, current->name(), false);
                        region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name, 
                                               regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
-
-                       add_region_internal (region, end);
-                       new_regions.push_back (region);
-
+                       {
+                               RegionLock rlock (this);
+                               add_region_internal (region, end);
+                               new_regions.push_back (region);
+                       }
                        /* "front" ***** */
                                
                        current->freeze ();
@@ -747,8 +772,9 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                /* end +++++ */
                                
                                _session.region_name (new_name, current->name(), false);
-                               region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
+                               region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, regions.size(),
                                                       Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
+                               RegionLock rlock (this);
                                add_region_internal (region, start);
                                new_regions.push_back (region);
                        }
@@ -783,6 +809,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                                 _session.region_name (new_name, current->name(), false);
                                 region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
                                                        regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
+                                RegionLock rlock (this);
                                 add_region_internal (region, pos1);
                                 new_regions.push_back (region);
                        } 
@@ -812,6 +839,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
                        */
 
                        if (cutting) {
+                               RegionLock rlock (this);
                                remove_region_internal (current);
                        }
                        new_regions.push_back (current);
@@ -823,6 +851,8 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
        for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
                check_dependents (*i, false);
        }
+
+       release_notifications ();
 }
 
 boost::shared_ptr<Playlist>
@@ -1168,8 +1198,8 @@ Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
                        save = !(_splicing || _nudging);
                }
                
-               if ((what_changed & Region::MuteChanged) && 
-                   !(what_changed &  Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
+               if ((what_changed & our_interests) && 
+                   !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
                        check_dependents (region, false);
                }
                
@@ -1181,6 +1211,14 @@ Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
        return save;
 }
 
+void
+Playlist::drop_regions ()
+{
+       RegionLock rl (this);
+       regions.clear ();
+       all_regions.clear ();
+}
+
 void
 Playlist::clear (bool with_signals)
 {
@@ -1193,7 +1231,9 @@ Playlist::clear (bool with_signals)
        }
 
        if (with_signals) {
+               pending_length = false;
                LengthChanged ();
+               pending_modified = false;
                Modified ();
        }
 
@@ -1412,7 +1452,7 @@ Playlist::set_state (const XMLNode& node)
        }
 
        in_set_state--;
-
+       first_set_state = false;
        return 0;
 }
 
@@ -1443,12 +1483,7 @@ Playlist::state (bool full_state)
 
        if (full_state) {
                RegionLock rlock (this, false);
-
-               cerr << _name << " getting region state for " << regions.size() << endl;
-
                for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
-                       cerr << "\t" << " now at " << (*i) << endl;
-                       cerr << "\t\t" << (*i)->name() << endl;
                        node->add_child_nocopy ((*i)->get_state());
                }
        }
@@ -1573,33 +1608,65 @@ Playlist::set_edit_mode (EditMode mode)
 void
 Playlist::relayer ()
 {
-       RegionList::iterator i;
-       uint32_t layer = 0;
-
        /* don't send multiple Modified notifications
           when multiple regions are relayered.
        */
-
        freeze ();
 
-       if (Config->get_layer_model() == MoveAddHigher || 
-           Config->get_layer_model() == AddHigher) {
+       /* build up a new list of regions on each layer */
 
-               RegionSortByLastLayerOp cmp;
-               RegionList copy = regions;
+       std::vector<RegionList> layers;
+
+       /* we want to go through regions from desired lowest to desired highest layer,
+          which depends on the layer model
+       */
+
+       RegionList copy = regions;
+
+       /* sort according to the model */
 
+       if (Config->get_layer_model() == MoveAddHigher || Config->get_layer_model() == AddHigher) {
+               RegionSortByLastLayerOp cmp;
                copy.sort (cmp);
+       }
+       
+       for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) {
+
+               /* find the lowest layer that this region can go on */
+               size_t j = layers.size();
+               while (j > 0) {
+                       /* try layer j - 1; it can go on if it overlaps no other region
+                          that is already on that layer
+                       */
+                       RegionList::iterator k = layers[j - 1].begin();
+                       while (k != layers[j - 1].end()) {
+                               if ((*k)->overlap_equivalent (*i)) {
+                                       break;
+                               }
+                               k++;
+                       }
 
-               for (i = copy.begin(); i != copy.end(); ++i) {
-                       (*i)->set_layer (layer++);
+                       if (k != layers[j - 1].end()) {
+                               /* no overlap, so we can use this layer */
+                               break;
+                       }
+                                       
+                       j--;
                }
 
-       } else {
-               
-               /* Session::LaterHigher model */
+               if (j == layers.size()) {
+                       /* we need a new layer for this region */
+                       layers.push_back (RegionList ());
+               }
 
-               for (i = regions.begin(); i != regions.end(); ++i) {
-                       (*i)->set_layer (layer++);
+               layers[j].push_back (*i);
+       }
+
+       /* first pass: set up the layer numbers in the regions */
+       for (size_t j = 0; j < layers.size(); ++j) {
+               for (RegionList::iterator i = layers[j].begin(); i != layers[j].end(); ++i) {
+                       (*i)->set_layer (j);
                }
        }
 
@@ -1618,33 +1685,6 @@ Playlist::relayer ()
 
 /* XXX these layer functions are all deprecated */
 
-void
-Playlist::raise_region (boost::shared_ptr<Region> region)
-{
-       uint32_t rsz = regions.size();
-       layer_t target = region->layer() + 1U;
-
-       if (target >= rsz) {
-               /* its already at the effective top */
-               return;
-       }
-
-       move_region_to_layer (target, region, 1);
-}
-
-void
-Playlist::lower_region (boost::shared_ptr<Region> region)
-{
-       if (region->layer() == 0) {
-               /* its already at the bottom */
-               return;
-       }
-
-       layer_t target = region->layer() - 1U;
-
-       move_region_to_layer (target, region, -1);
-}
-
 void
 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
 {
@@ -1667,79 +1707,6 @@ Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
        }
 }
 
-int
-Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region> region, int dir)
-{
-       RegionList::iterator i;
-       typedef pair<boost::shared_ptr<Region>,layer_t> LayerInfo;
-       list<LayerInfo> layerinfo;
-       layer_t dest;
-
-       {
-               RegionLock rlock (const_cast<Playlist *> (this));
-               
-               for (i = regions.begin(); i != regions.end(); ++i) {
-                       
-                       if (region == *i) {
-                               continue;
-                       }
-
-                       if (dir > 0) {
-
-                               /* region is moving up, move all regions on intermediate layers
-                                  down 1
-                               */
-                               
-                               if ((*i)->layer() > region->layer() && (*i)->layer() <= target_layer) {
-                                       dest = (*i)->layer() - 1;
-                               } else {
-                                       /* not affected */
-                                       continue;
-                               }
-                       } else {
-
-                               /* region is moving down, move all regions on intermediate layers
-                                  up 1
-                               */
-
-                               if ((*i)->layer() < region->layer() && (*i)->layer() >= target_layer) {
-                                       dest = (*i)->layer() + 1;
-                               } else {
-                                       /* not affected */
-                                       continue;
-                               }
-                       }
-
-                       LayerInfo newpair;
-                       
-                       newpair.first = *i;
-                       newpair.second = dest;
-                       
-                       layerinfo.push_back (newpair);
-               } 
-       }
-
-       /* now reset the layers without holding the region lock */
-
-       for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
-               x->first->set_layer (x->second);
-       }
-
-       region->set_layer (target_layer);
-
-#if 0
-       /* now check all dependents */
-
-       for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
-               check_dependents (x->first, false);
-       }
-       
-       check_dependents (region, false);
-#endif
-       
-       return 0;
-}
-
 void
 Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards)
 {