X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fplaylist.cc;h=649d549b8658d9ec13a7f31949ecfc09a47396f1;hb=8f59346592b8232e910ce0bbdc247cf8cecde4dd;hp=6169df8f030b93451626985ca9259b5f8fdba01f;hpb=a5ab2e99e19d5f5d4c1f91f38cd774fefdf257dc;p=ardour.git diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index 6169df8f03..649d549b86 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -25,10 +25,11 @@ #include #include +#include + #include "pbd/failed_constructor.h" -#include "pbd/stl_delete.h" +#include "pbd/stateful_diff_command.h" #include "pbd/xml++.h" -#include "pbd/stacktrace.h" #include "ardour/debug.h" #include "ardour/playlist.h" @@ -113,13 +114,10 @@ RegionListProperty::lookup_id (const ID& id) { boost::shared_ptr ret = _playlist.region_by_id (id); - if (!ret) { - ret = _playlist.session().region_by_id (id); - } - if (!ret) { ret = RegionFactory::region_by_id (id); } + return ret; } @@ -133,22 +131,18 @@ RegionListProperty::copy_for_history () const } void -RegionListProperty::diff (PropertyList& before, PropertyList& after) const +RegionListProperty::diff (PropertyList& undo, PropertyList& redo) const { - if (_have_old) { + if (changed()) { + /* list of the removed/added regions since clear_history() was last called */ RegionListProperty* a = copy_for_history (); - RegionListProperty* b = copy_for_history (); + /* the same list, but with removed/added lists swapped (for undo purposes) */ + RegionListProperty* b = copy_for_history (); b->invert_changes (); - before.add (b); - after.add (a); - - cerr << "pdiff on " << _playlist.name() << " before contains " - << b->change().added.size() << " adds and " << b->change().removed.size() << " removes\n"; - cerr << "pdiff on " << _playlist.name() << " after contains " - << a->change().added.size() << " adds and " << a->change().removed.size() << " removes\n"; - + undo.add (b); + redo.add (a); } } @@ -160,6 +154,7 @@ Playlist::Playlist (Session& sess, string nom, DataType type, bool hide) init (hide); first_set_state = false; _name = nom; + _set_sort_id (); } @@ -174,6 +169,7 @@ Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide init (hide); _name = "unnamed"; /* reset by set_state */ + _set_sort_id (); /* set state called by derived class */ } @@ -182,7 +178,7 @@ Playlist::Playlist (boost::shared_ptr other, string namestr, boo : SessionObject(other->_session, namestr) , regions (*this) , _type(other->_type) - , _orig_diskstream_id(other->_orig_diskstream_id) + , _orig_diskstream_id (other->_orig_diskstream_id) { init (hide); @@ -217,7 +213,7 @@ Playlist::Playlist (boost::shared_ptr other, framepos_t start, f : SessionObject(other->_session, str) , regions (*this) , _type(other->_type) - , _orig_diskstream_id(other->_orig_diskstream_id) + , _orig_diskstream_id (other->_orig_diskstream_id) { RegionLock rlock2 (const_cast (other.get())); @@ -270,11 +266,11 @@ Playlist::Playlist (boost::shared_ptr other, framepos_t start, f break; } - _session.region_name (new_name, region->name(), false); + RegionFactory::region_name (new_name, region->name(), false); PropertyList plist; - plist.add (Properties::start, offset); + plist.add (Properties::start, region->start() + offset); plist.add (Properties::length, len); plist.add (Properties::name, new_name); plist.add (Properties::layer, region->layer()); @@ -337,6 +333,7 @@ Playlist::init (bool hide) _shuffling = false; _nudging = false; in_set_state = 0; + in_update = false; _edit_mode = Config->get_edit_mode(); in_flush = false; in_partition = false; @@ -368,6 +365,32 @@ Playlist::~Playlist () /* GoingAway must be emitted by derived classes */ } +void +Playlist::_set_sort_id () +{ + /* + Playlists are given names like . + or .. where id + is an integer. We extract the id and sort by that. + */ + + size_t dot_position = _name.val().find_last_of("."); + + if (dot_position == string::npos) { + _sort_id = 0; + } else { + string t = _name.val().substr(dot_position + 1); + + try { + _sort_id = boost::lexical_cast(t); + } + + catch (boost::bad_lexical_cast e) { + _sort_id = 0; + } + } +} + bool Playlist::set_name (const string& str) { @@ -379,9 +402,13 @@ Playlist::set_name (const string& str) if (_refcnt > 2) { return false; - } else { - return SessionObject::set_name(str); - } + } + + bool ret = SessionObject::set_name(str); + if (ret) { + _set_sort_id (); + } + return ret; } /*********************************************************************** @@ -395,6 +422,7 @@ Playlist::set_name (const string& str) void Playlist::begin_undo () { + in_update = true; freeze (); } @@ -402,6 +430,7 @@ void Playlist::end_undo () { thaw (); + in_update = false; } void @@ -432,6 +461,7 @@ Playlist::release_notifications () if (g_atomic_int_dec_and_test (&block_notifications)) { flush_notifications (); } + } void @@ -499,7 +529,7 @@ Playlist::notify_region_added (boost::shared_ptr r) /* the length change might not be true, but we have to act as though it could be. */ - + if (holding_state()) { pending_adds.insert (r); pending_contents_change = true; @@ -665,12 +695,12 @@ Playlist::add_region (boost::shared_ptr region, framepos_t position, flo if (floor (times) != times) { length = (framecnt_t) floor (region->length() * (times - floor (times))); string name; - _session.region_name (name, region->name(), false); + RegionFactory::region_name (name, region->name(), false); { PropertyList plist; - plist.add (Properties::start, 0); + plist.add (Properties::start, region->start()); plist.add (Properties::length, length); plist.add (Properties::name, name); plist.add (Properties::layer, region->layer()); @@ -724,8 +754,8 @@ Playlist::add_region_internal (boost::shared_ptr region, framepos_t posi possibly_splice_unlocked (position, region->length(), region); - if (!holding_state () && !in_set_state) { - /* layers get assigned from XML state */ + if (!holding_state ()) { + /* layers get assigned from XML state, and are not reset during undo/redo */ relayer (); } @@ -799,7 +829,7 @@ Playlist::remove_region_internal (boost::shared_ptr region) possibly_splice_unlocked (pos, -distance); if (!holding_state ()) { - relayer (); + relayer (); remove_dependents (region); if (old_length != _get_maximum_extent()) { @@ -855,7 +885,7 @@ Playlist::partition (framepos_t start, framepos_t end, bool cut) partition_internal (start, end, cut, thawlist); for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) { - (*i)->thaw (); + (*i)->resume_property_changes (); } } @@ -935,11 +965,11 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re if (!cutting) { /* "middle" ++++++ */ - _session.region_name (new_name, current->name(), false); + RegionFactory::region_name (new_name, current->name(), false); PropertyList plist; - plist.add (Properties::start, pos2 - pos1); + plist.add (Properties::start, current->start() + (pos2 - pos1)); plist.add (Properties::length, pos3 - pos2); plist.add (Properties::name, new_name); plist.add (Properties::layer, regions.size()); @@ -954,11 +984,11 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re /* "end" ====== */ - _session.region_name (new_name, current->name(), false); + RegionFactory::region_name (new_name, current->name(), false); PropertyList plist; - plist.add (Properties::start, pos3 - pos1); + plist.add (Properties::start, current->start() + (pos3 - pos1)); plist.add (Properties::length, pos4 - pos3); plist.add (Properties::name, new_name); plist.add (Properties::layer, regions.size()); @@ -972,9 +1002,9 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re /* "front" ***** */ - current->freeze (); + current->suspend_property_changes (); thawlist.push_back (current); - current->trim_end (pos2, this); + current->cut_end (pos2 - 1, this); } else if (overlap == OverlapEnd) { @@ -992,11 +1022,11 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re /* end +++++ */ - _session.region_name (new_name, current->name(), false); + RegionFactory::region_name (new_name, current->name(), false); PropertyList plist; - plist.add (Properties::start, pos2 - pos1); + plist.add (Properties::start, current->start() + (pos2 - pos1)); plist.add (Properties::length, pos4 - pos2); plist.add (Properties::name, new_name); plist.add (Properties::layer, regions.size()); @@ -1011,9 +1041,9 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re /* front ****** */ - current->freeze (); + current->suspend_property_changes (); thawlist.push_back (current); - current->trim_end (pos2, this); + current->cut_end (pos2 - 1, this); } else if (overlap == OverlapStart) { @@ -1035,11 +1065,11 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re if (!cutting) { /* front **** */ - _session.region_name (new_name, current->name(), false); + RegionFactory::region_name (new_name, current->name(), false); PropertyList plist; - plist.add (Properties::start, 0); + plist.add (Properties::start, current->start()); plist.add (Properties::length, pos3 - pos1); plist.add (Properties::name, new_name); plist.add (Properties::layer, regions.size()); @@ -1054,7 +1084,7 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re /* end */ - current->freeze (); + current->suspend_property_changes (); thawlist.push_back (current); current->trim_front (pos3, this); } else if (overlap == OverlapExternal) { @@ -1157,7 +1187,7 @@ Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden) partition_internal (start, start+cnt-1, true, thawlist); for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) { - (*i)->thaw (); + (*i)->resume_property_changes(); } return the_copy; @@ -1239,12 +1269,12 @@ Playlist::duplicate (boost::shared_ptr region, framepos_t position, floa if (floor (times) != times) { framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times))); string name; - _session.region_name (name, region->name(), false); + RegionFactory::region_name (name, region->name(), false); { PropertyList plist; - plist.add (Properties::start, 0); + plist.add (Properties::start, region->start()); plist.add (Properties::length, length); plist.add (Properties::name, name); @@ -1340,12 +1370,12 @@ Playlist::_split_region (boost::shared_ptr region, framepos_t playlist_p before = playlist_position - region->position(); after = region->length() - before; - _session.region_name (before_name, region->name(), false); + RegionFactory::region_name (before_name, region->name(), false); { PropertyList plist; - plist.add (Properties::start, 0); + plist.add (Properties::start, region->start()); plist.add (Properties::length, before); plist.add (Properties::name, before_name); plist.add (Properties::left_of_split, true); @@ -1353,12 +1383,12 @@ Playlist::_split_region (boost::shared_ptr region, framepos_t playlist_p left = RegionFactory::create (region, plist); } - _session.region_name (after_name, region->name(), false); + RegionFactory::region_name (after_name, region->name(), false); { PropertyList plist; - plist.add (Properties::start, before); + plist.add (Properties::start, region->start() + before); plist.add (Properties::length, after); plist.add (Properties::name, after_name); plist.add (Properties::right_of_split, true); @@ -1600,9 +1630,19 @@ Playlist::clear (bool with_signals) } regions.clear (); + + for (set >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) { + remove_dependents (*s); + } } if (with_signals) { + + for (set >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) { + RegionRemoved (boost::weak_ptr (*s)); /* EMIT SIGNAL */ + } + + pending_removes.clear (); pending_length = false; LengthChanged (); pending_contents_change = false; @@ -2020,6 +2060,29 @@ Playlist::set_property (const PropertyBase& prop) return false; } +void +Playlist::rdiff (vector& cmds) const +{ + RegionLock rlock (const_cast (this)); + + for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { + if ((*i)->changed ()) { + StatefulDiffCommand* sdc = new StatefulDiffCommand (*i); + cmds.push_back (sdc); + } + } +} + +void +Playlist::clear_owned_history () +{ + RegionLock rlock (this); + + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + (*i)->clear_history (); + } +} + void Playlist::update (const RegionListProperty::ChangeRecord& change) { @@ -2035,6 +2098,7 @@ Playlist::update (const RegionListProperty::ChangeRecord& change) for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) { remove_region (*i); } + thaw (); } @@ -2046,8 +2110,6 @@ Playlist::property_factory (const XMLNode& history_node) const for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { - /* XXX property name needs capitalizing */ - if ((*i)->name() == capitalize (regions.property_name())) { RegionListProperty* rlp = new RegionListProperty (*const_cast (this)); @@ -2095,6 +2157,7 @@ Playlist::set_state (const XMLNode& node, int version) if (prop->name() == X_("name")) { _name = prop->value(); + _set_sort_id (); } else if (prop->name() == X_("id")) { _id = prop->value(); } else if (prop->name() == X_("orig_diskstream_id")) { @@ -2104,7 +2167,7 @@ Playlist::set_state (const XMLNode& node, int version) } } - clear (false); + clear (true); nlist = node.children(); @@ -2123,25 +2186,25 @@ Playlist::set_state (const XMLNode& node, int version) if ((region = region_by_id (id))) { - region->freeze (); + region->suspend_property_changes (); if (region->set_state (*child, version)) { - region->thaw (); + region->resume_property_changes (); continue; } } else if ((region = RegionFactory::create (_session, *child, true)) != 0) { - region->freeze (); + region->suspend_property_changes (); } else { error << _("Playlist: cannot create region from XML") << endmsg; continue; } - + add_region (region, region->position(), 1.0); // So that layer_op ordering doesn't get screwed up region->set_last_layer_op( region->layer()); - region->thaw (); + region->resume_property_changes (); } } @@ -2153,7 +2216,6 @@ Playlist::set_state (const XMLNode& node, int version) check_dependents (*r, false); } - clear_pending (); // this makes thaw() do nothing thaw (); notify_contents_changed (); @@ -2279,6 +2341,12 @@ Playlist::set_edit_mode (EditMode mode) void Playlist::relayer () { + /* never compute layers when changing state for undo/redo or setting from XML */ + + if (in_update || in_set_state) { + return; + } + bool changed = false; /* Build up a new list of regions on each layer, stored in a set of lists @@ -2422,22 +2490,48 @@ void Playlist::raise_region_to_top (boost::shared_ptr region) { /* does nothing useful if layering mode is later=higher */ - if ((_session.config.get_layer_model() == MoveAddHigher) || - (_session.config.get_layer_model() == AddHigher)) { - timestamp_layer_op (region); - relayer (); + switch (_session.config.get_layer_model()) { + case LaterHigher: + return; + default: + break; } + + layer_t top = regions.size() - 1; + + if (region->layer() >= top) { + /* already on the top */ + return; + } + + move_region_to_layer (top, region, 1); + /* mark the region's last_layer_op as now, so that it remains on top when + doing future relayers (until something else takes over) + */ + timestamp_layer_op (region); } void Playlist::lower_region_to_bottom (boost::shared_ptr region) { /* does nothing useful if layering mode is later=higher */ - if ((_session.config.get_layer_model() == MoveAddHigher) || - (_session.config.get_layer_model() == AddHigher)) { - region->set_last_layer_op (0); - relayer (); + switch (_session.config.get_layer_model()) { + case LaterHigher: + return; + default: + break; } + + if (region->layer() == 0) { + /* already on the bottom */ + return; + } + + move_region_to_layer (0, region, -1); + /* force region's last layer op to zero so that it stays at the bottom + when doing future relayers + */ + region->set_last_layer_op (0); } int @@ -2620,8 +2714,6 @@ Playlist::set_frozen (bool yn) void Playlist::timestamp_layer_op (boost::shared_ptr region) { -// struct timeval tv; -// gettimeofday (&tv, 0); region->set_last_layer_op (++layer_op_counter); }