X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fplaylist.cc;h=6fc7fdc2cffa9d92020485a07aa77d672b850647;hb=d9cebc2edf8accded23c6f2a1caab73eb47a50fd;hp=aa41bf65d167d75f642b9fe2f328d37ac3177c67;hpb=51693a3a5835a7c2deb16242d14d73fbb7881382;p=ardour.git diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index aa41bf65d1..6fc7fdc2cf 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -25,12 +25,11 @@ #include #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" @@ -39,6 +38,7 @@ #include "ardour/region_factory.h" #include "ardour/playlist_factory.h" #include "ardour/transient_detector.h" +#include "ardour/session_playlists.h" #include "i18n.h" @@ -46,6 +46,12 @@ using namespace std; using namespace ARDOUR; using namespace PBD; +namespace ARDOUR { +namespace Properties { +PBD::PropertyDescriptor regions; +} +} + struct ShowMeTheList { ShowMeTheList (boost::shared_ptr pl, const string& n) : playlist (pl), name (n) {} ~ShowMeTheList () { @@ -90,32 +96,89 @@ struct RegionSortByLastLayerOp { } }; +void +Playlist::make_property_quarks () +{ + Properties::regions.property_id = g_quark_from_static_string (X_("regions")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for regions = %1\n", Properties::regions.property_id)); +} + +RegionListProperty::RegionListProperty (Playlist& pl) + : SequenceProperty > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1)) + , _playlist (pl) +{ +} + +boost::shared_ptr +RegionListProperty::lookup_id (const ID& id) +{ + boost::shared_ptr ret = _playlist.region_by_id (id); + + if (!ret) { + ret = RegionFactory::region_by_id (id); + } + + return ret; +} + +RegionListProperty* +RegionListProperty::copy_for_history () const +{ + RegionListProperty* copy = new RegionListProperty (_playlist); + /* this is all we need */ + copy->_change = _change; + return copy; +} + +void +RegionListProperty::diff (PropertyList& undo, PropertyList& redo) const +{ + if (changed()) { + /* list of the removed/added regions since clear_history() was last called */ + RegionListProperty* a = copy_for_history (); + + /* the same list, but with removed/added lists swapped (for undo purposes) */ + RegionListProperty* b = copy_for_history (); + b->invert_changes (); + + undo.add (b); + redo.add (a); + } +} Playlist::Playlist (Session& sess, string nom, DataType type, bool hide) : SessionObject(sess, nom) + , regions (*this) , _type(type) { init (hide); first_set_state = false; _name = nom; + _set_sort_id (); } Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide) : SessionObject(sess, "unnamed playlist") - , _type(type) + , regions (*this) + , _type(type) + { const XMLProperty* prop = node.property("type"); assert(!prop || DataType(prop->value()) == _type); init (hide); _name = "unnamed"; /* reset by set_state */ + _set_sort_id (); /* set state called by derived class */ } Playlist::Playlist (boost::shared_ptr other, string namestr, bool hide) - : SessionObject(other->_session, namestr), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id) + : SessionObject(other->_session, namestr) + , regions (*this) + , _type(other->_type) + , _orig_diskstream_id(other->_orig_diskstream_id) { init (hide); @@ -146,24 +209,27 @@ Playlist::Playlist (boost::shared_ptr other, string namestr, boo freeze_length = other->freeze_length; } -Playlist::Playlist (boost::shared_ptr other, nframes_t start, nframes_t cnt, string str, bool hide) - : SessionObject(other->_session, str), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id) +Playlist::Playlist (boost::shared_ptr other, framepos_t start, framecnt_t cnt, string str, bool hide) + : SessionObject(other->_session, str) + , regions (*this) + , _type(other->_type) + , _orig_diskstream_id(other->_orig_diskstream_id) { RegionLock rlock2 (const_cast (other.get())); - nframes_t end = start + cnt - 1; + framepos_t end = start + cnt - 1; init (hide); in_set_state++; - for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) { + for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); ++i) { boost::shared_ptr region; boost::shared_ptr new_region; - nframes_t offset = 0; - nframes_t position = 0; - nframes_t len = 0; + frameoffset_t offset = 0; + framepos_t position = 0; + framecnt_t len = 0; string new_name; OverlapType overlap; @@ -200,9 +266,16 @@ Playlist::Playlist (boost::shared_ptr other, nframes_t start, nf break; } - _session.region_name (new_name, region->name(), false); + RegionFactory::region_name (new_name, region->name(), false); - new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags()); + PropertyList plist; + + plist.add (Properties::start, region->start() + offset); + plist.add (Properties::length, len); + plist.add (Properties::name, new_name); + plist.add (Properties::layer, region->layer()); + + new_region = RegionFactory::RegionFactory::create (region, plist); add_region_internal (new_region, position); } @@ -245,10 +318,14 @@ Playlist::copy_regions (RegionList& newlist) const void Playlist::init (bool hide) { + add_property (regions); + _xml_node_name = X_("Playlist"); + g_atomic_int_set (&block_notifications, 0); g_atomic_int_set (&ignore_state_changes, 0); - pending_modified = false; + pending_contents_change = false; pending_length = false; + pending_layering = false; first_set_state = true; _refcnt = 0; _hidden = hide; @@ -256,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; @@ -266,12 +344,16 @@ Playlist::init (bool hide) freeze_length = 0; _explicit_relayering = false; - Modified.connect (mem_fun (*this, &Playlist::mark_session_dirty)); + _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this)); + _session.history().EndUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::end_undo, this)); + + ContentsChanged.connect_same_thread (*this, boost::bind (&Playlist::mark_session_dirty, this)); } Playlist::~Playlist () { DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name)); + { RegionLock rl (this); @@ -283,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) { @@ -294,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; } /*********************************************************************** @@ -307,6 +419,20 @@ Playlist::set_name (const string& str) the lock (e.g. to read from the playlist). ***********************************************************************/ +void +Playlist::begin_undo () +{ + in_update = true; + freeze (); +} + +void +Playlist::end_undo () +{ + thaw (); + in_update = false; +} + void Playlist::freeze () { @@ -334,17 +460,29 @@ Playlist::release_notifications () { if (g_atomic_int_dec_and_test (&block_notifications)) { flush_notifications (); + } + +} + +void +Playlist::notify_contents_changed () +{ + if (holding_state ()) { + pending_contents_change = true; + } else { + pending_contents_change = false; + ContentsChanged(); /* EMIT SIGNAL */ } } void -Playlist::notify_modified () +Playlist::notify_layering_changed () { if (holding_state ()) { - pending_modified = true; + pending_layering = true; } else { - pending_modified = false; - Modified(); /* EMIT SIGNAL */ + pending_layering = false; + LayeringChanged(); /* EMIT SIGNAL */ } } @@ -353,7 +491,7 @@ Playlist::notify_region_removed (boost::shared_ptr r) { if (holding_state ()) { pending_removes.insert (r); - pending_modified = true; + pending_contents_change = true; pending_length = true; } else { /* this might not be true, but we have to act @@ -361,16 +499,16 @@ Playlist::notify_region_removed (boost::shared_ptr r) */ pending_length = false; LengthChanged (); /* EMIT SIGNAL */ - pending_modified = false; + pending_contents_change = false; RegionRemoved (boost::weak_ptr (r)); /* EMIT SIGNAL */ - Modified (); /* EMIT SIGNAL */ + ContentsChanged (); /* EMIT SIGNAL */ } } void Playlist::notify_region_moved (boost::shared_ptr r) { - Evoral::RangeMove const move (r->last_position (), r->length (), r->position ()); + Evoral::RangeMove const move (r->last_position (), r->length (), r->position ()); if (holding_state ()) { @@ -378,7 +516,7 @@ Playlist::notify_region_moved (boost::shared_ptr r) } else { - list< Evoral::RangeMove > m; + list< Evoral::RangeMove > m; m.push_back (move); RangesMoved (m); } @@ -391,17 +529,17 @@ 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_modified = true; + pending_contents_change = true; pending_length = true; } else { pending_length = false; LengthChanged (); /* EMIT SIGNAL */ - pending_modified = false; + pending_contents_change = false; RegionAdded (boost::weak_ptr (r)); /* EMIT SIGNAL */ - Modified (); /* EMIT SIGNAL */ + ContentsChanged (); /* EMIT SIGNAL */ } } @@ -413,8 +551,8 @@ Playlist::notify_length_changed () } else { pending_length = false; LengthChanged(); /* EMIT SIGNAL */ - pending_modified = false; - Modified (); /* EMIT SIGNAL */ + pending_contents_change = false; + ContentsChanged (); /* EMIT SIGNAL */ } } @@ -423,7 +561,9 @@ Playlist::flush_notifications () { set > dependent_checks_needed; set >::iterator s; - uint32_t n = 0; + uint32_t regions_changed = false; + bool check_length = false; + framecnt_t old_length = 0; if (in_flush) { return; @@ -431,6 +571,14 @@ Playlist::flush_notifications () in_flush = true; + if (!pending_bounds.empty() || !pending_removes.empty() || !pending_adds.empty()) { + regions_changed = true; + if (!pending_length) { + old_length = _get_maximum_extent (); + check_length = true; + } + } + /* we have no idea what order the regions ended up in pending bounds (it could be based on selection order, for example). so, to preserve layering in the "most recently moved is higher" @@ -444,37 +592,42 @@ Playlist::flush_notifications () if (_session.config.get_layer_model() == MoveAddHigher) { timestamp_layer_op (*r); } - - pending_length = true; dependent_checks_needed.insert (*r); - - n++; } for (s = pending_removes.begin(); s != pending_removes.end(); ++s) { remove_dependents (*s); + // cerr << _name << " sends RegionRemoved\n"; RegionRemoved (boost::weak_ptr (*s)); /* EMIT SIGNAL */ - n++; } for (s = pending_adds.begin(); s != pending_adds.end(); ++s) { + // cerr << _name << " sends RegionAdded\n"; RegionAdded (boost::weak_ptr (*s)); /* EMIT SIGNAL */ dependent_checks_needed.insert (*s); - n++; } - if ((freeze_length != _get_maximum_extent()) || pending_length) { - pending_length = 0; + if (check_length) { + if (old_length != _get_maximum_extent()) { + pending_length = true; + // cerr << _name << " length has changed\n"; + } + } + + if (pending_length || (freeze_length != _get_maximum_extent())) { + pending_length = false; + // cerr << _name << " sends LengthChanged\n"; LengthChanged(); /* EMIT SIGNAL */ - n++; } - if (n || pending_modified) { + if (regions_changed || pending_contents_change) { if (!in_set_state) { relayer (); } - pending_modified = false; - Modified (); /* EMIT SIGNAL */ + pending_contents_change = false; + // cerr << _name << " sends 5 contents change @ " << get_microseconds() << endl; + ContentsChanged (); /* EMIT SIGNAL */ + // cerr << _name << "done contents change @ " << get_microseconds() << endl; } for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) { @@ -482,15 +635,24 @@ Playlist::flush_notifications () } if (!pending_range_moves.empty ()) { + // cerr << _name << " sends RangesMoved\n"; RangesMoved (pending_range_moves); } + + clear_pending (); + + in_flush = false; +} +void +Playlist::clear_pending () +{ pending_adds.clear (); pending_removes.clear (); pending_bounds.clear (); pending_range_moves.clear (); - - in_flush = false; + pending_contents_change = false; + pending_length = false; } /************************************************************* @@ -498,17 +660,17 @@ Playlist::flush_notifications () *************************************************************/ void -Playlist::add_region (boost::shared_ptr region, nframes_t position, float times, bool auto_partition) +Playlist::add_region (boost::shared_ptr region, framepos_t position, float times, bool auto_partition) { RegionLock rlock (this); times = fabs (times); int itimes = (int) floor (times); - nframes_t pos = position; + framepos_t pos = position; if (times == 1 && auto_partition){ - partition(pos, (nframes_t) (pos + region->length()), true); + partition(pos, (pos + region->length()), true); } if (itimes >= 1) { @@ -528,14 +690,24 @@ Playlist::add_region (boost::shared_ptr region, nframes_t position, floa pos += region->length(); } - nframes_t length = 0; + framecnt_t length = 0; if (floor (times) != times) { - length = (nframes_t) floor (region->length() * (times - floor (times))); + length = (framecnt_t) floor (region->length() * (times - floor (times))); string name; - _session.region_name (name, region->name(), false); - boost::shared_ptr sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags()); - add_region_internal (sub, pos); + RegionFactory::region_name (name, region->name(), false); + + { + PropertyList plist; + + plist.add (Properties::start, region->start()); + plist.add (Properties::length, length); + plist.add (Properties::name, name); + plist.add (Properties::layer, region->layer()); + + boost::shared_ptr sub = RegionFactory::create (region, plist); + add_region_internal (sub, pos); + } } possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr()); @@ -554,7 +726,7 @@ Playlist::set_region_ownership () } bool -Playlist::add_region_internal (boost::shared_ptr region, nframes_t position) +Playlist::add_region_internal (boost::shared_ptr region, framepos_t position) { if (region->data_type() != _type){ return false; @@ -562,7 +734,7 @@ Playlist::add_region_internal (boost::shared_ptr region, nframes_t posit RegionSortByPosition cmp; - nframes_t old_length = 0; + framecnt_t old_length = 0; if (!holding_state()) { old_length = _get_maximum_extent(); @@ -582,8 +754,8 @@ Playlist::add_region_internal (boost::shared_ptr region, nframes_t posit 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 (); } @@ -600,16 +772,13 @@ Playlist::add_region_internal (boost::shared_ptr region, nframes_t posit } } - region_state_changed_connections.push_back ( - region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy), - boost::weak_ptr (region))) - ); + region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr (region))); return true; } void -Playlist::replace_region (boost::shared_ptr old, boost::shared_ptr newr, nframes_t pos) +Playlist::replace_region (boost::shared_ptr old, boost::shared_ptr newr, framepos_t pos) { RegionLock rlock (this); @@ -621,7 +790,7 @@ Playlist::replace_region (boost::shared_ptr old, boost::shared_ptrlength() - (nframes64_t) newr->length()); + possibly_splice_unlocked (pos, old->length() - newr->length()); } void @@ -635,7 +804,8 @@ int Playlist::remove_region_internal (boost::shared_ptr region) { RegionList::iterator i; - nframes_t old_length = 0; + framecnt_t old_length = 0; + int ret = -1; if (!holding_state()) { old_length = _get_maximum_extent(); @@ -646,18 +816,20 @@ Playlist::remove_region_internal (boost::shared_ptr region) region->set_playlist (boost::weak_ptr()); } + /* XXX should probably freeze here .... */ + for (i = regions.begin(); i != regions.end(); ++i) { if (*i == region) { - nframes_t pos = (*i)->position(); - nframes64_t distance = (*i)->length(); + framepos_t pos = (*i)->position(); + framecnt_t distance = (*i)->length(); regions.erase (i); possibly_splice_unlocked (pos, -distance); if (!holding_state ()) { - relayer (); + relayer (); remove_dependents (region); if (old_length != _get_maximum_extent()) { @@ -666,13 +838,14 @@ Playlist::remove_region_internal (boost::shared_ptr region) } notify_region_removed (region); - return 0; + ret = 0; + break; } } + /* XXX and thaw ... */ - - return -1; + return ret; } void @@ -705,19 +878,19 @@ Playlist::get_region_list_equivalent_regions (boost::shared_ptr other, v } void -Playlist::partition (nframes_t start, nframes_t end, bool cut) +Playlist::partition (framepos_t start, framepos_t end, bool cut) { RegionList thawlist; partition_internal (start, end, cut, thawlist); for (RegionList::iterator i = thawlist.begin(); i != thawlist.end(); ++i) { - (*i)->thaw ("separation"); + (*i)->resume_property_changes (); } } void -Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist) +Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, RegionList& thawlist) { RegionList new_regions; @@ -729,7 +902,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi string new_name; RegionList::iterator tmp; OverlapType overlap; - nframes_t pos1, pos2, pos3, pos4; + framepos_t pos1, pos2, pos3, pos4; in_partition = true; @@ -737,7 +910,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi get operated on as well. */ - RegionList copy = regions; + RegionList copy = regions.rlist(); for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) { @@ -792,27 +965,46 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi if (!cutting) { /* "middle" ++++++ */ - _session.region_name (new_name, current->name(), false); - region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name, - regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit)); + RegionFactory::region_name (new_name, current->name(), false); + + PropertyList plist; + + 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()); + plist.add (Properties::automatic, true); + plist.add (Properties::left_of_split, true); + plist.add (Properties::right_of_split, true); + + region = RegionFactory::create (current, plist); add_region_internal (region, start); new_regions.push_back (region); } /* "end" ====== */ - _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)); + RegionFactory::region_name (new_name, current->name(), false); + + PropertyList plist; + + 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()); + plist.add (Properties::automatic, true); + plist.add (Properties::right_of_split, true); + + region = RegionFactory::create (current, plist); add_region_internal (region, end); new_regions.push_back (region); /* "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) { @@ -830,9 +1022,18 @@ 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::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit)); + RegionFactory::region_name (new_name, current->name(), false); + + PropertyList plist; + + 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()); + plist.add (Properties::automatic, true); + plist.add (Properties::left_of_split, true); + + region = RegionFactory::create (current, plist); add_region_internal (region, start); new_regions.push_back (region); @@ -840,9 +1041,9 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi /* 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) { @@ -864,9 +1065,18 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi if (!cutting) { /* front **** */ - _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)); + RegionFactory::region_name (new_name, current->name(), false); + + PropertyList plist; + + plist.add (Properties::start, current->start()); + plist.add (Properties::length, pos3 - pos1); + plist.add (Properties::name, new_name); + plist.add (Properties::layer, regions.size()); + plist.add (Properties::automatic, true); + plist.add (Properties::right_of_split, true); + + region = RegionFactory::create (current, plist); add_region_internal (region, pos1); new_regions.push_back (region); @@ -874,7 +1084,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi /* end */ - current->freeze (); + current->suspend_property_changes (); thawlist.push_back (current); current->trim_front (pos3, this); } else if (overlap == OverlapExternal) { @@ -912,11 +1122,11 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi } boost::shared_ptr -Playlist::cut_copy (boost::shared_ptr (Playlist::*pmf)(nframes_t, nframes_t,bool), list& ranges, bool result_is_hidden) +Playlist::cut_copy (boost::shared_ptr (Playlist::*pmf)(framepos_t, framecnt_t,bool), list& ranges, bool result_is_hidden) { boost::shared_ptr ret; boost::shared_ptr pl; - nframes_t start; + framepos_t start; if (ranges.empty()) { return boost::shared_ptr(); @@ -947,19 +1157,19 @@ Playlist::cut_copy (boost::shared_ptr (Playlist::*pmf)(nframes_t, nfra boost::shared_ptr Playlist::cut (list& ranges, bool result_is_hidden) { - boost::shared_ptr (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut; + boost::shared_ptr (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::cut; return cut_copy (pmf, ranges, result_is_hidden); } boost::shared_ptr Playlist::copy (list& ranges, bool result_is_hidden) { - boost::shared_ptr (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy; + boost::shared_ptr (Playlist::*pmf)(framepos_t,framecnt_t,bool) = &Playlist::copy; return cut_copy (pmf, ranges, result_is_hidden); } boost::shared_ptr -Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden) +Playlist::cut (framepos_t start, framecnt_t cnt, bool result_is_hidden) { boost::shared_ptr the_copy; RegionList thawlist; @@ -977,14 +1187,14 @@ Playlist::cut (nframes_t start, nframes_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 ("playlist cut"); + (*i)->resume_property_changes(); } return the_copy; } boost::shared_ptr -Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden) +Playlist::copy (framepos_t start, framecnt_t cnt, bool result_is_hidden) { char buf[32]; @@ -998,20 +1208,19 @@ Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden) } int -Playlist::paste (boost::shared_ptr other, nframes_t position, float times) +Playlist::paste (boost::shared_ptr other, framepos_t position, float times) { times = fabs (times); - nframes_t old_length; { RegionLock rl1 (this); RegionLock rl2 (other.get()); - old_length = _get_maximum_extent(); + framecnt_t old_length = _get_maximum_extent(); int itimes = (int) floor (times); - nframes_t pos = position; - nframes_t shift = other->_get_maximum_extent(); + framepos_t pos = position; + framecnt_t shift = other->_get_maximum_extent(); layer_t top_layer = regions.size(); while (itimes--) { @@ -1043,13 +1252,13 @@ Playlist::paste (boost::shared_ptr other, nframes_t position, float ti void -Playlist::duplicate (boost::shared_ptr region, nframes_t position, float times) +Playlist::duplicate (boost::shared_ptr region, framepos_t position, float times) { times = fabs (times); RegionLock rl (this); int itimes = (int) floor (times); - nframes_t pos = position; + framepos_t pos = position; while (itimes--) { boost::shared_ptr copy = RegionFactory::create (region); @@ -1058,19 +1267,28 @@ Playlist::duplicate (boost::shared_ptr region, nframes_t position, float } if (floor (times) != times) { - nframes_t length = (nframes_t) floor (region->length() * (times - floor (times))); + framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times))); string name; - _session.region_name (name, region->name(), false); - boost::shared_ptr sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags()); - add_region_internal (sub, pos); + RegionFactory::region_name (name, region->name(), false); + + { + PropertyList plist; + + plist.add (Properties::start, region->start()); + plist.add (Properties::length, length); + plist.add (Properties::name, name); + + boost::shared_ptr sub = RegionFactory::create (region, plist); + add_region_internal (sub, pos); + } } } void -Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bool ignore_music_glue) +Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue) { RegionLock rlock (this); - RegionList copy (regions); + RegionList copy (regions.rlist()); RegionList fixup; for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) { @@ -1105,10 +1323,10 @@ Playlist::shift (nframes64_t at, nframes64_t distance, bool move_intersected, bo } void -Playlist::split (nframes64_t at) +Playlist::split (framepos_t at) { RegionLock rlock (this); - RegionList copy (regions); + RegionList copy (regions.rlist()); /* use a copy since this operation can modify the region list */ @@ -1119,14 +1337,14 @@ Playlist::split (nframes64_t at) } void -Playlist::split_region (boost::shared_ptr region, nframes_t playlist_position) +Playlist::split_region (boost::shared_ptr region, framepos_t playlist_position) { RegionLock rl (this); _split_region (region, playlist_position); } void -Playlist::_split_region (boost::shared_ptr region, nframes_t playlist_position) +Playlist::_split_region (boost::shared_ptr region, framepos_t playlist_position) { if (!region->covers (playlist_position)) { return; @@ -1139,8 +1357,8 @@ Playlist::_split_region (boost::shared_ptr region, nframes_t playlist_po boost::shared_ptr left; boost::shared_ptr right; - nframes_t before; - nframes_t after; + frameoffset_t before; + frameoffset_t after; string before_name; string after_name; @@ -1152,11 +1370,31 @@ Playlist::_split_region (boost::shared_ptr region, nframes_t playlist_po before = playlist_position - region->position(); after = region->length() - before; - _session.region_name (before_name, region->name(), false); - left = RegionFactory::create (region, 0, before, before_name, region->layer(), Region::Flag (region->flags()|Region::LeftOfSplit)); + RegionFactory::region_name (before_name, region->name(), false); - _session.region_name (after_name, region->name(), false); - right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit)); + { + PropertyList plist; + + plist.add (Properties::start, region->start()); + plist.add (Properties::length, before); + plist.add (Properties::name, before_name); + plist.add (Properties::left_of_split, true); + + left = RegionFactory::create (region, plist); + } + + RegionFactory::region_name (after_name, region->name(), false); + + { + PropertyList plist; + + 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); + + right = RegionFactory::create (region, plist); + } add_region_internal (left, region->position()); add_region_internal (right, region->position() + before); @@ -1181,7 +1419,7 @@ Playlist::_split_region (boost::shared_ptr region, nframes_t playlist_po } void -Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr exclude) +Playlist::possibly_splice (framepos_t at, framecnt_t distance, boost::shared_ptr exclude) { if (_splicing || in_set_state) { /* don't respond to splicing moves or state setting */ @@ -1194,7 +1432,7 @@ Playlist::possibly_splice (nframes_t at, nframes64_t distance, boost::shared_ptr } void -Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::shared_ptr exclude) +Playlist::possibly_splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr exclude) { if (_splicing || in_set_state) { /* don't respond to splicing moves or state setting */ @@ -1207,7 +1445,7 @@ Playlist::possibly_splice_unlocked (nframes_t at, nframes64_t distance, boost::s } void -Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr exclude) +Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr exclude) { { RegionLock rl (this); @@ -1216,13 +1454,13 @@ Playlist::splice_locked (nframes_t at, nframes64_t distance, boost::shared_ptr exclude) +Playlist::splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr exclude) { core_splice (at, distance, exclude); } void -Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr exclude) +Playlist::core_splice (framepos_t at, framecnt_t distance, boost::shared_ptr exclude) { _splicing = true; @@ -1233,7 +1471,7 @@ Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptrposition() >= at) { - nframes64_t new_pos = (*i)->position() + distance; + framepos_t new_pos = (*i)->position() + distance; if (new_pos < 0) { new_pos = 0; } else if (new_pos >= max_frames - (*i)->length()) { @@ -1250,13 +1488,13 @@ Playlist::core_splice (nframes_t at, nframes64_t distance, boost::shared_ptr region) +Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr region) { if (in_set_state || _splicing || _nudging || _shuffling) { return; } - if (what_changed & ARDOUR::PositionChanged) { + if (what_changed.contains (Properties::position)) { /* remove it from the list then add it back in the right place again. @@ -1267,9 +1505,10 @@ Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr RegionList::iterator i = find (regions.begin(), regions.end(), region); if (i == regions.end()) { - warning << string_compose (_("%1: bounds changed received for region (%2)not in playlist"), - _name, region->name()) - << endmsg; + /* the region bounds are being modified but its not currently + in the region list. we will use its bounds correctly when/if + it is added + */ return; } @@ -1277,16 +1516,16 @@ Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr regions.insert (upper_bound (regions.begin(), regions.end(), region, cmp), region); } - if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) { + if (what_changed.contains (Properties::position) || what_changed.contains (Properties::length)) { - nframes64_t delta = 0; + frameoffset_t delta = 0; - if (what_changed & ARDOUR::PositionChanged) { - delta = (nframes64_t) region->position() - (nframes64_t) region->last_position(); + if (what_changed.contains (Properties::position)) { + delta = region->position() - region->last_position(); } - if (what_changed & ARDOUR::LengthChanged) { - delta += (nframes64_t) region->length() - (nframes64_t) region->last_length(); + if (what_changed.contains (Properties::length)) { + delta += region->length() - region->last_length(); } if (delta) { @@ -1309,7 +1548,7 @@ Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr } void -Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr weak_region) +Playlist::region_changed_proxy (const PropertyChange& what_changed, boost::weak_ptr weak_region) { boost::shared_ptr region (weak_region.lock()); @@ -1317,37 +1556,53 @@ Playlist::region_changed_proxy (Change what_changed, boost::weak_ptr wea return; } - /* this makes a virtual call to the right kind of playlist ... */ region_changed (what_changed, region); } bool -Playlist::region_changed (Change what_changed, boost::shared_ptr region) +Playlist::region_changed (const PropertyChange& what_changed, boost::shared_ptr region) { - Change our_interests = Change (Region::MuteChanged|Region::LayerChanged|Region::OpacityChanged); + PropertyChange our_interests; + PropertyChange bounds; + PropertyChange pos_and_length; bool save = false; if (in_set_state || in_flush) { return false; } - if (what_changed & BoundsChanged) { + our_interests.add (Properties::muted); + our_interests.add (Properties::layer); + our_interests.add (Properties::opaque); + + bounds.add (Properties::start); + bounds.add (Properties::position); + bounds.add (Properties::length); + + pos_and_length.add (Properties::position); + pos_and_length.add (Properties::length); + + if (what_changed.contains (bounds)) { region_bounds_changed (what_changed, region); save = !(_splicing || _nudging); } - if ((what_changed & our_interests) && - !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) { + if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) { check_dependents (region, false); } - if (what_changed & Change (ARDOUR::PositionChanged)) { + if (what_changed.contains (Properties::position)) { notify_region_moved (region); } - if (what_changed & our_interests) { + + /* don't notify about layer changes, since we are the only object that can initiate + them, and we notify in ::relayer() + */ + + if (what_changed.contains (our_interests)) { save = true; } @@ -1368,26 +1623,30 @@ Playlist::clear (bool with_signals) { RegionLock rl (this); - for ( - std::list::iterator i = region_state_changed_connections.begin (); - i != region_state_changed_connections.end (); - ++i - ) { - i->disconnect (); - } + region_state_changed_connections.drop_connections (); for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { pending_removes.insert (*i); } 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_modified = false; - Modified (); + pending_contents_change = false; + ContentsChanged (); } } @@ -1397,7 +1656,7 @@ Playlist::clear (bool with_signals) **********************************************************************/ Playlist::RegionList * -Playlist::regions_at (nframes_t frame) +Playlist::regions_at (framepos_t frame) { RegionLock rlock (this); @@ -1405,7 +1664,7 @@ Playlist::regions_at (nframes_t frame) } boost::shared_ptr -Playlist::top_region_at (nframes_t frame) +Playlist::top_region_at (framepos_t frame) { RegionLock rlock (this); @@ -1423,7 +1682,7 @@ Playlist::top_region_at (nframes_t frame) } boost::shared_ptr -Playlist::top_unmuted_region_at (nframes_t frame) +Playlist::top_unmuted_region_at (framepos_t frame) { RegionLock rlock (this); @@ -1454,14 +1713,13 @@ Playlist::top_unmuted_region_at (nframes_t frame) } Playlist::RegionList* -Playlist::regions_to_read (nframes_t start, nframes_t end) +Playlist::regions_to_read (framepos_t start, framepos_t end) { /* Caller must hold lock */ RegionList covering; - set to_check; + set to_check; set > unique; - RegionList here; to_check.insert (start); to_check.insert (end); @@ -1512,7 +1770,8 @@ Playlist::regions_to_read (nframes_t start, nframes_t end) } else { - for (set::iterator t = to_check.begin(); t != to_check.end(); ++t) { + RegionList here; + for (set::iterator t = to_check.begin(); t != to_check.end(); ++t) { here.clear (); @@ -1557,7 +1816,7 @@ Playlist::regions_to_read (nframes_t start, nframes_t end) } Playlist::RegionList * -Playlist::find_regions_at (nframes_t frame) +Playlist::find_regions_at (framepos_t frame) { /* Caller must hold lock */ @@ -1573,7 +1832,7 @@ Playlist::find_regions_at (nframes_t frame) } Playlist::RegionList * -Playlist::regions_touched (nframes_t start, nframes_t end) +Playlist::regions_touched (framepos_t start, framepos_t end) { RegionLock rlock (this); RegionList *rlist = new RegionList; @@ -1587,8 +1846,8 @@ Playlist::regions_touched (nframes_t start, nframes_t end) return rlist; } -nframes64_t -Playlist::find_next_transient (nframes64_t from, int dir) +framepos_t +Playlist::find_next_transient (framepos_t from, int dir) { RegionLock rlock (this); AnalysisFeatureList points; @@ -1648,11 +1907,11 @@ Playlist::find_next_transient (nframes64_t from, int dir) } boost::shared_ptr -Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir) +Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir) { RegionLock rlock (this); boost::shared_ptr ret; - nframes_t closest = max_frames; + framepos_t closest = max_frames; bool end_iter = false; @@ -1660,9 +1919,9 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir) if(end_iter) break; - nframes_t distance; + frameoffset_t distance; boost::shared_ptr r = (*i); - nframes_t pos = 0; + framepos_t pos = 0; switch (point) { case Start: @@ -1709,20 +1968,20 @@ Playlist::find_next_region (nframes_t frame, RegionPoint point, int dir) return ret; } -nframes64_t -Playlist::find_next_region_boundary (nframes64_t frame, int dir) +framepos_t +Playlist::find_next_region_boundary (framepos_t frame, int dir) { RegionLock rlock (this); - nframes64_t closest = max_frames; - nframes64_t ret = -1; + framepos_t closest = max_frames; + framepos_t ret = -1; if (dir > 0) { for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { boost::shared_ptr r = (*i); - nframes64_t distance; + frameoffset_t distance; if (r->first_frame() > frame) { @@ -1750,7 +2009,7 @@ Playlist::find_next_region_boundary (nframes64_t frame, int dir) for (RegionList::reverse_iterator i = regions.rbegin(); i != regions.rend(); ++i) { boost::shared_ptr r = (*i); - nframes64_t distance; + frameoffset_t distance; if (r->last_frame() < frame) { @@ -1790,6 +2049,85 @@ Playlist::mark_session_dirty () } } +bool +Playlist::set_property (const PropertyBase& prop) +{ + if (prop == Properties::regions.property_id) { + const RegionListProperty::ChangeRecord& change (dynamic_cast(&prop)->change()); + regions.update (change); + return (!change.added.empty() && !change.removed.empty()); + } + 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) +{ + DEBUG_TRACE (DEBUG::Properties, string_compose ("Playlist %1 updates from a change record with %2 adds %3 removes\n", + name(), change.added.size(), change.removed.size())); + + freeze (); + /* add the added regions */ + for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) { + add_region ((*i), (*i)->position()); + } + /* remove the removed regions */ + for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) { + remove_region (*i); + } + + thaw (); +} + +PropertyList* +Playlist::property_factory (const XMLNode& history_node) const +{ + const XMLNodeList& children (history_node.children()); + PropertyList* prop_list = 0; + + for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { + + if ((*i)->name() == capitalize (regions.property_name())) { + + RegionListProperty* rlp = new RegionListProperty (*const_cast (this)); + + if (rlp->load_history_state (**i)) { + if (!prop_list) { + prop_list = new PropertyList(); + } + prop_list->add (rlp); + } else { + delete rlp; + } + } + } + + return prop_list; +} + int Playlist::set_state (const XMLNode& node, int version) { @@ -1819,6 +2157,9 @@ 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")) { _orig_diskstream_id = prop->value (); } else if (prop->name() == X_("frozen")) { @@ -1826,7 +2167,7 @@ Playlist::set_state (const XMLNode& node, int version) } } - clear (false); + clear (true); nlist = node.children(); @@ -1840,35 +2181,33 @@ Playlist::set_state (const XMLNode& node, int version) error << _("region state node has no ID, ignored") << endmsg; continue; } - + ID id = prop->value (); if ((region = region_by_id (id))) { - Change what_changed = Change (0); + region->suspend_property_changes (); - if (region->set_live_state (*child, version, what_changed, true)) { - error << _("Playlist: cannot reset region state from XML") << endmsg; + if (region->set_state (*child, version)) { + region->resume_property_changes (); continue; } - - } else if ((region = RegionFactory::create (_session, *child, true)) == 0) { + + } else if ((region = RegionFactory::create (_session, *child, true)) != 0) { + 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->resume_property_changes (); } } - notify_modified (); - - thaw (); - /* update dependents, which was not done during add_region_internal due to in_set_state being true */ @@ -1877,6 +2216,9 @@ Playlist::set_state (const XMLNode& node, int version) check_dependents (*r, false); } + thaw (); + notify_contents_changed (); + in_set_state--; first_set_state = false; return 0; @@ -1902,6 +2244,7 @@ Playlist::state (bool full_state) XMLNode *node = new XMLNode (X_("Playlist")); char buf[64]; + node->add_property (X_("id"), id().to_s()); node->add_property (X_("name"), _name); node->add_property (X_("type"), _type.to_string()); @@ -1937,19 +2280,19 @@ Playlist::n_regions() const return regions.size(); } -nframes_t +framecnt_t Playlist::get_maximum_extent () const { RegionLock rlock (const_cast(this), false); return _get_maximum_extent (); } -ARDOUR::nframes_t +framecnt_t Playlist::_get_maximum_extent () const { RegionList::const_iterator i; - nframes_t max_extent = 0; - nframes_t end = 0; + framecnt_t max_extent = 0; + framepos_t end = 0; for (i = regions.begin(); i != regions.end(); ++i) { if ((end = (*i)->position() + (*i)->length()) > max_extent) { @@ -1967,7 +2310,7 @@ Playlist::bump_name (string name, Session &session) do { newname = bump_name_once (newname); - } while (session.playlist_by_name (newname)!=NULL); + } while (session.playlists->by_name (newname)!=NULL); return newname; } @@ -1998,11 +2341,13 @@ Playlist::set_edit_mode (EditMode mode) void Playlist::relayer () { - /* don't send multiple Modified notifications - when multiple regions are relayered. - */ + /* never compute layers when changing state for undo/redo or setting from XML */ - freeze (); + 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 each of which represent some period of time on some layer. The idea @@ -2013,8 +2358,8 @@ Playlist::relayer () int const divisions = 512; /* find the start and end positions of the regions on this playlist */ - nframes_t start = UINT_MAX; - nframes_t end = 0; + framepos_t start = UINT_MAX; + framepos_t end = 0; for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { start = min (start, (*i)->position()); end = max (end, (*i)->position() + (*i)->length()); @@ -2030,7 +2375,7 @@ Playlist::relayer () which depends on the layer model */ - RegionList copy = regions; + RegionList copy = regions.rlist(); /* sort according to the model and the layering mode that we're in */ @@ -2044,6 +2389,7 @@ Playlist::relayer () } + for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) { /* reset the pending explicit relayer flag for every region, now that we're relayering */ @@ -2098,21 +2444,17 @@ Playlist::relayer () for (int k = start_division; k <= end_division; ++k) { layers[j][k].push_back (*i); } + + if ((*i)->layer() != j) { + changed = true; + } (*i)->set_layer (j); } - /* sending Modified means that various kinds of layering - models operate correctly at the GUI - level. slightly inefficient, but only slightly. - - We force a Modified signal here in case no layers actually - changed. - */ - - notify_modified (); - - thaw (); + if (changed) { + notify_layering_changed (); + } } /* XXX these layer functions are all deprecated */ @@ -2148,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 @@ -2172,7 +2540,6 @@ Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr RegionList::iterator i; typedef pair,layer_t> LayerInfo; list layerinfo; - layer_t dest; { RegionLock rlock (const_cast (this)); @@ -2183,6 +2550,8 @@ Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr continue; } + layer_t dest; + if (dir > 0) { /* region is moving up, move all regions on intermediate layers @@ -2240,10 +2609,9 @@ Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr } void -Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards) +Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards) { RegionList::iterator i; - nframes_t new_pos; bool moved = false; _nudging = true; @@ -2255,6 +2623,8 @@ Playlist::nudge_after (nframes_t start, nframes_t distance, bool forwards) if ((*i)->position() >= start) { + framepos_t new_pos; + if (forwards) { if ((*i)->last_frame() > max_frames - distance) { @@ -2302,7 +2672,7 @@ Playlist::find_region (const ID& id) const } boost::shared_ptr -Playlist::region_by_id (ID id) +Playlist::region_by_id (const ID& id) { /* searches all regions ever added to this playlist */ @@ -2344,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); } @@ -2354,7 +2722,6 @@ void Playlist::shuffle (boost::shared_ptr region, int dir) { bool moved = false; - nframes_t new_pos; if (region->locked()) { return; @@ -2381,6 +2748,8 @@ Playlist::shuffle (boost::shared_ptr region, int dir) break; } + framepos_t new_pos; + if ((*next)->position() != region->last_frame() + 1) { /* they didn't used to touch, so after shuffle, just have them swap positions. @@ -2422,6 +2791,7 @@ Playlist::shuffle (boost::shared_ptr region, int dir) break; } + framepos_t new_pos; if (region->position() != (*prev)->last_frame() + 1) { /* they didn't used to touch, so after shuffle, just have them swap positions. @@ -2459,7 +2829,7 @@ Playlist::shuffle (boost::shared_ptr region, int dir) relayer (); check_dependents (region, false); - notify_modified(); + notify_contents_changed(); } } @@ -2480,7 +2850,7 @@ void Playlist::update_after_tempo_map_change () { RegionLock rlock (const_cast (this)); - RegionList copy (regions); + RegionList copy (regions.rlist()); freeze (); @@ -2492,7 +2862,7 @@ Playlist::update_after_tempo_map_change () } void -Playlist::foreach_region (sigc::slot > s) +Playlist::foreach_region (boost::function)> s) { RegionLock rl (this, false); for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { @@ -2521,3 +2891,17 @@ Playlist::set_explicit_relayering (bool e) _explicit_relayering = e; } + + +bool +Playlist::has_region_at (framepos_t const p) const +{ + RegionLock (const_cast (this)); + + RegionList::const_iterator i = regions.begin (); + while (i != regions.end() && !(*i)->covers (p)) { + ++i; + } + + return (i != regions.end()); +}