slightly improved fixes for MIDI issues
[ardour.git] / libs / ardour / playlist.cc
index 325ef27a18ad27cb92b7675a90bd83b0438522d6..4af7e2b907febb489496a3199acaf9e9e8cf3c81 100644 (file)
@@ -71,16 +71,17 @@ 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 +94,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 +114,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 +126,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 +187,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 +228,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 +247,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 +273,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 +283,10 @@ Playlist::set_name (string str)
        */
 
        if (_refcnt > 2) {
-               return;
+               return false;
+       } else {
+               return SessionObject::set_name(str);
        }
-
-       _name = str; 
-       NameChanged(); /* EMIT SIGNAL */
 }
 
 /***********************************************************************
@@ -515,10 +518,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 +584,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) {
 
@@ -1181,6 +1189,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)
 {
@@ -1412,7 +1428,7 @@ Playlist::set_state (const XMLNode& node)
        }
 
        in_set_state--;
-
+       first_set_state = false;
        return 0;
 }
 
@@ -1443,12 +1459,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 +1584,66 @@ 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) {
 
-               for (i = copy.begin(); i != copy.end(); ++i) {
-                       (*i)->set_layer (layer++);
+               /* 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++;
+                       }
+
+                       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 +1662,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 +1684,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)
 {