X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fplaylist.cc;h=47462a3575be3b19274698290d9dbf861f68a3d8;hb=8c5cff60912c7e0a7256f635641399500d8d00d9;hp=bcc203694e687699ede5de682370270b221fd545;hpb=6c0224c9876b1c1c55c6d5f98d82d5d0a870378f;p=ardour.git diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index bcc203694e..47462a3575 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -19,17 +19,12 @@ #include #include -#include #include -#include -#include #include -#include #include #include "pbd/convert.h" -#include "pbd/failed_constructor.h" #include "pbd/stateful_diff_command.h" #include "pbd/xml++.h" @@ -52,9 +47,9 @@ using namespace ARDOUR; using namespace PBD; namespace ARDOUR { -namespace Properties { -PBD::PropertyDescriptor regions; -} + namespace Properties { + PBD::PropertyDescriptor regions; + } } struct ShowMeTheList { @@ -194,7 +189,7 @@ Playlist::Playlist (boost::shared_ptr other, framepos_t start, f , _type(other->_type) , _orig_track_id (other->_orig_track_id) { - RegionLock rlock2 (const_cast (other.get())); + RegionReadLock rlock2 (const_cast (other.get())); framepos_t end = start + cnt - 1; @@ -210,35 +205,35 @@ Playlist::Playlist (boost::shared_ptr other, framepos_t start, f framepos_t position = 0; framecnt_t len = 0; string new_name; - OverlapType overlap; + Evoral::OverlapType overlap; region = *i; overlap = region->coverage (start, end); switch (overlap) { - case OverlapNone: + case Evoral::OverlapNone: continue; - case OverlapInternal: + case Evoral::OverlapInternal: offset = start - region->position(); position = 0; len = cnt; break; - case OverlapStart: + case Evoral::OverlapStart: offset = 0; position = region->position() - start; len = end - region->position(); break; - case OverlapEnd: + case Evoral::OverlapEnd: offset = start - region->position(); position = 0; len = region->length() - offset; break; - case OverlapExternal: + case Evoral::OverlapExternal: offset = 0; position = region->position() - start; len = region->length(); @@ -255,7 +250,7 @@ Playlist::Playlist (boost::shared_ptr other, framepos_t start, f plist.add (Properties::layer, region->layer()); plist.add (Properties::layering_index, region->layering_index()); - new_region = RegionFactory::RegionFactory::create (region, plist); + new_region = RegionFactory::create (region, plist); add_region_internal (new_region, position); } @@ -286,10 +281,10 @@ Playlist::release () void Playlist::copy_regions (RegionList& newlist) const { - RegionLock rlock (const_cast (this)); + RegionReadLock rlock (const_cast (this)); for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { - newlist.push_back (RegionFactory::RegionFactory::create (*i, true)); + newlist.push_back (RegionFactory::create (*i, true)); } } @@ -316,6 +311,7 @@ Playlist::init (bool hide) in_partition = false; subcnt = 0; _frozen = false; + _capture_insertion_underway = false; _combine_ops = 0; _session.history().BeginUndoRedo.connect_same_thread (*this, boost::bind (&Playlist::begin_undo, this)); @@ -329,7 +325,7 @@ Playlist::~Playlist () DEBUG_TRACE (DEBUG::Destruction, string_compose ("Playlist %1 destructor\n", _name)); { - RegionLock rl (this); + RegionReadLock rl (this); for (set >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) { (*i)->set_playlist (boost::shared_ptr()); @@ -561,7 +557,6 @@ Playlist::notify_region_added (boost::shared_ptr r) void Playlist::flush_notifications (bool from_undo) { - set > dependent_checks_needed; set >::iterator s; bool regions_changed = false; @@ -575,6 +570,10 @@ Playlist::flush_notifications (bool from_undo) regions_changed = true; } + /* XXX: it'd be nice if we could use pending_bounds for + RegionsExtended and RegionsMoved. + */ + /* 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" @@ -584,30 +583,28 @@ Playlist::flush_notifications (bool from_undo) // RegionSortByLayer cmp; // pending_bounds.sort (cmp); + list > crossfade_ranges; + for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) { - dependent_checks_needed.insert (*r); + crossfade_ranges.push_back ((*r)->last_range ()); + crossfade_ranges.push_back ((*r)->range ()); } for (s = pending_removes.begin(); s != pending_removes.end(); ++s) { + crossfade_ranges.push_back ((*s)->range ()); remove_dependents (*s); - // cerr << _name << " sends RegionRemoved\n"; RegionRemoved (boost::weak_ptr (*s)); /* EMIT SIGNAL */ } - + for (s = pending_adds.begin(); s != pending_adds.end(); ++s) { - // cerr << _name << " sends RegionAdded\n"; - /* don't emit RegionAdded signal until relayering is done, - so that the region is fully setup by the time - anyone hear's that its been added - */ - dependent_checks_needed.insert (*s); - } + crossfade_ranges.push_back ((*s)->range ()); + /* don't emit RegionAdded signal until relayering is done, + so that the region is fully setup by the time + anyone hears that its been added + */ + } - if ( - ((regions_changed || pending_contents_change) && !in_set_state) || - pending_layering - ) { - + if (((regions_changed || pending_contents_change) && !in_set_state) || pending_layering) { relayer (); } @@ -621,11 +618,12 @@ Playlist::flush_notifications (bool from_undo) RegionAdded (boost::weak_ptr (*s)); /* EMIT SIGNAL */ } - for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) { - check_dependents (*s, false); - } + coalesce_and_check_crossfades (crossfade_ranges); if (!pending_range_moves.empty ()) { + /* We don't need to check crossfades for these as pending_bounds has + already covered it. + */ RangesMoved (pending_range_moves, from_undo); } @@ -657,7 +655,7 @@ Playlist::flush_notifications (bool from_undo) void Playlist::add_region (boost::shared_ptr region, framepos_t position, float times, bool auto_partition) { - RegionLock rlock (this); + RegionWriteLock rlock (this); times = fabs (times); int itimes = (int) floor (times); @@ -714,7 +712,7 @@ Playlist::flush_notifications (bool from_undo) void Playlist::set_region_ownership () { - RegionLock rl (this); + RegionWriteLock rl (this); RegionList::iterator i; boost::weak_ptr pl (shared_from_this()); @@ -753,10 +751,6 @@ Playlist::flush_notifications (bool from_undo) notify_region_added (region); - if (!holding_state ()) { - check_dependents (region, false); - } - region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr (region))); return true; @@ -765,7 +759,7 @@ Playlist::flush_notifications (bool from_undo) void Playlist::replace_region (boost::shared_ptr old, boost::shared_ptr newr, framepos_t pos) { - RegionLock rlock (this); + RegionWriteLock rlock (this); bool old_sp = _splicing; _splicing = true; @@ -782,7 +776,7 @@ Playlist::flush_notifications (bool from_undo) void Playlist::remove_region (boost::shared_ptr region) { - RegionLock rlock (this); + RegionWriteLock rlock (this); remove_region_internal (region); } @@ -827,13 +821,13 @@ Playlist::flush_notifications (bool from_undo) if (Config->get_use_overlap_equivalency()) { for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { if ((*i)->overlap_equivalent (other)) { - results.push_back ((*i)); + results.push_back (*i); } } } else { for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { if ((*i)->equivalent (other)) { - results.push_back ((*i)); + results.push_back (*i); } } } @@ -850,6 +844,17 @@ Playlist::flush_notifications (bool from_undo) } } + void + Playlist::get_source_equivalent_regions (boost::shared_ptr other, vector >& results) + { + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + + if ((*i) && (*i)->any_source_equivalent (other)) { + results.push_back (*i); + } + } + } + void Playlist::partition (framepos_t start, framepos_t end, bool cut) { @@ -873,13 +878,13 @@ Playlist::flush_notifications (bool from_undo) RegionList new_regions; { - RegionLock rlock (this); + RegionWriteLock rlock (this); boost::shared_ptr region; boost::shared_ptr current; string new_name; RegionList::iterator tmp; - OverlapType overlap; + Evoral::OverlapType overlap; framepos_t pos1, pos2, pos3, pos4; in_partition = true; @@ -915,7 +920,7 @@ Playlist::flush_notifications (bool from_undo) continue; } - if ((overlap = current->coverage (start, end)) == OverlapNone) { + if ((overlap = current->coverage (start, end)) == Evoral::OverlapNone) { continue; } @@ -924,7 +929,7 @@ Playlist::flush_notifications (bool from_undo) pos3 = end; pos4 = current->last_frame(); - if (overlap == OverlapInternal) { + if (overlap == Evoral::OverlapInternal) { /* split: we need 3 new regions, the front, middle and end. cut: we need 2 regions, the front and end. */ @@ -986,7 +991,7 @@ Playlist::flush_notifications (bool from_undo) thawlist.push_back (current); current->cut_end (pos2 - 1); - } else if (overlap == OverlapEnd) { + } else if (overlap == Evoral::OverlapEnd) { /* start end @@ -1026,7 +1031,7 @@ Playlist::flush_notifications (bool from_undo) thawlist.push_back (current); current->cut_end (pos2 - 1); - } else if (overlap == OverlapStart) { + } else if (overlap == Evoral::OverlapStart) { /* split: we need 2 regions: the front and the end. cut: just trim current to skip the cut area @@ -1069,7 +1074,7 @@ Playlist::flush_notifications (bool from_undo) current->suspend_property_changes (); thawlist.push_back (current); current->trim_front (pos3); - } else if (overlap == OverlapExternal) { + } else if (overlap == Evoral::OverlapExternal) { /* split: no split required. cut: remove the region. @@ -1097,10 +1102,6 @@ Playlist::flush_notifications (bool from_undo) in_partition = false; } - - for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) { - check_dependents (*i, false); - } } boost::shared_ptr @@ -1195,26 +1196,28 @@ Playlist::flush_notifications (bool from_undo) times = fabs (times); { - RegionLock rl1 (this); - RegionLock rl2 (other.get()); + RegionReadLock rl2 (other.get()); int itimes = (int) floor (times); framepos_t pos = position; framecnt_t const shift = other->_get_extent().second; layer_t top = top_layer (); - while (itimes--) { - for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) { - boost::shared_ptr copy_of_region = RegionFactory::create (*i, true); - - /* put these new regions on top of all existing ones, but preserve - the ordering they had in the original playlist. - */ - - add_region_internal (copy_of_region, (*i)->position() + pos); - set_layer (copy_of_region, copy_of_region->layer() + top); + { + RegionWriteLock rl1 (this); + while (itimes--) { + for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) { + boost::shared_ptr copy_of_region = RegionFactory::create (*i, true); + + /* put these new regions on top of all existing ones, but preserve + the ordering they had in the original playlist. + */ + + add_region_internal (copy_of_region, (*i)->position() + pos); + set_layer (copy_of_region, copy_of_region->layer() + top); + } + pos += shift; } - pos += shift; } } @@ -1227,7 +1230,7 @@ Playlist::flush_notifications (bool from_undo) { times = fabs (times); - RegionLock rl (this); + RegionWriteLock rl (this); int itimes = (int) floor (times); framepos_t pos = position + 1; @@ -1260,7 +1263,7 @@ Playlist::flush_notifications (bool from_undo) void Playlist::shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue) { - RegionLock rlock (this); + RegionWriteLock rlock (this); RegionList copy (regions.rlist()); RegionList fixup; @@ -1299,7 +1302,7 @@ Playlist::flush_notifications (bool from_undo) void Playlist::split (framepos_t at) { - RegionLock rlock (this); + RegionWriteLock rlock (this); RegionList copy (regions.rlist()); /* use a copy since this operation can modify the region list @@ -1313,7 +1316,7 @@ Playlist::flush_notifications (bool from_undo) void Playlist::split_region (boost::shared_ptr region, framepos_t playlist_position) { - RegionLock rl (this); + RegionWriteLock rl (this); _split_region (region, playlist_position); } @@ -1381,9 +1384,6 @@ Playlist::flush_notifications (bool from_undo) add_region_internal (left, region->position()); add_region_internal (right, region->position() + before); - - finalize_split_region (region, left, right); - remove_region_internal (region); _splicing = old_sp; @@ -1419,7 +1419,7 @@ Playlist::flush_notifications (bool from_undo) Playlist::splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr exclude) { { - RegionLock rl (this); + RegionWriteLock rl (this); core_splice (at, distance, exclude); } } @@ -1508,7 +1508,10 @@ Playlist::flush_notifications (bool from_undo) } else { notify_contents_changed (); relayer (); - check_dependents (region, false); + list > xf; + xf.push_back (Evoral::Range (region->last_range())); + xf.push_back (Evoral::Range (region->range())); + coalesce_and_check_crossfades (xf); } } } @@ -1555,10 +1558,6 @@ Playlist::flush_notifications (bool from_undo) save = !(_splicing || _nudging); } - if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) { - check_dependents (region, false); - } - if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) { notify_region_moved (region); } else if (!what_changed.contains (Properties::position) && what_changed.contains (Properties::length)) { @@ -1581,7 +1580,7 @@ Playlist::flush_notifications (bool from_undo) void Playlist::drop_regions () { - RegionLock rl (this); + RegionWriteLock rl (this); regions.clear (); all_regions.clear (); } @@ -1589,7 +1588,7 @@ Playlist::flush_notifications (bool from_undo) void Playlist::sync_all_regions_with_regions () { - RegionLock rl (this); + RegionWriteLock rl (this); all_regions.clear (); @@ -1602,7 +1601,7 @@ Playlist::flush_notifications (bool from_undo) Playlist::clear (bool with_signals) { { - RegionLock rl (this); + RegionWriteLock rl (this); region_state_changed_connections.drop_connections (); @@ -1634,18 +1633,17 @@ Playlist::flush_notifications (bool from_undo) FINDING THINGS **********************************************************************/ - Playlist::RegionList * - Playlist::regions_at (framepos_t frame) - - { - RegionLock rlock (this); - return find_regions_at (frame); - } +boost::shared_ptr +Playlist::regions_at (framepos_t frame) +{ + RegionReadLock rlock (this); + return find_regions_at (frame); +} uint32_t Playlist::count_regions_at (framepos_t frame) const { - RegionLock rlock (const_cast(this)); + RegionReadLock rlock (const_cast(this)); uint32_t cnt = 0; for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { @@ -1661,8 +1659,8 @@ Playlist::flush_notifications (bool from_undo) Playlist::top_region_at (framepos_t frame) { - RegionLock rlock (this); - RegionList *rlist = find_regions_at (frame); + RegionReadLock rlock (this); + boost::shared_ptr rlist = find_regions_at (frame); boost::shared_ptr region; if (rlist->size()) { @@ -1671,7 +1669,6 @@ Playlist::flush_notifications (bool from_undo) region = rlist->back(); } - delete rlist; return region; } @@ -1679,8 +1676,8 @@ Playlist::flush_notifications (bool from_undo) Playlist::top_unmuted_region_at (framepos_t frame) { - RegionLock rlock (this); - RegionList *rlist = find_regions_at (frame); + RegionReadLock rlock (this); + boost::shared_ptr rlist = find_regions_at (frame); for (RegionList::iterator i = rlist->begin(); i != rlist->end(); ) { @@ -1702,301 +1699,204 @@ Playlist::flush_notifications (bool from_undo) region = rlist->back(); } - delete rlist; return region; } - Playlist::RegionList* - Playlist::regions_to_read (framepos_t start, framepos_t end) - { - /* Caller must hold lock */ - - RegionList covering; - set to_check; - set > unique; - - to_check.insert (start); - to_check.insert (end); - - DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n"); - - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - - /* find all/any regions that span start+end */ - - switch ((*i)->coverage (start, end)) { - case OverlapNone: - break; - - case OverlapInternal: - covering.push_back (*i); - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name())); - break; - - case OverlapStart: - to_check.insert ((*i)->position()); - if ((*i)->position() != 0) { - to_check.insert ((*i)->position()-1); - } - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name())); - covering.push_back (*i); - break; - - case OverlapEnd: - to_check.insert ((*i)->last_frame()); - to_check.insert ((*i)->last_frame()+1); - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name())); - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name())); - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name())); - covering.push_back (*i); - break; - - case OverlapExternal: - covering.push_back (*i); - to_check.insert ((*i)->position()); - if ((*i)->position() != 0) { - to_check.insert ((*i)->position()-1); - } - to_check.insert ((*i)->last_frame()); - to_check.insert ((*i)->last_frame()+1); - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name())); - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name())); - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name())); - break; - } - - /* don't go too far */ - - if ((*i)->position() > end) { - break; - } - } - - RegionList* rlist = new RegionList; - - /* find all the regions that cover each position .... */ - - if (covering.size() == 1) { - - rlist->push_back (covering.front()); - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name())); - - } else { - - RegionList here; - for (set::iterator t = to_check.begin(); t != to_check.end(); ++t) { - - here.clear (); - - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t)); - - for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) { - - if ((*x)->covers (*t)) { - here.push_back (*x); - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n", - (*x)->name(), - (*t))); - } else { - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n", - (*x)->name(), - (*t))); - } - - } - - RegionSortByLayer cmp; - here.sort (cmp); - - /* ... and get the top/transparent regions at "here" */ - - for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) { - - unique.insert (*c); - - if ((*c)->opaque()) { - - /* the other regions at this position are hidden by this one */ - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n", - (*c)->name())); - break; - } - } - } - - for (set >::iterator s = unique.begin(); s != unique.end(); ++s) { - rlist->push_back (*s); - } - - if (rlist->size() > 1) { - /* now sort by time order */ - - RegionSortByPosition cmp; - rlist->sort (cmp); - } - } - - DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size())); - - return rlist; - } - - Playlist::RegionList * - Playlist::find_regions_at (framepos_t frame) - { - /* Caller must hold lock */ - - RegionList *rlist = new RegionList; - - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - if ((*i)->covers (frame)) { - rlist->push_back (*i); - } - } - - return rlist; - } - - Playlist::RegionList * - Playlist::regions_touched (framepos_t start, framepos_t end) - { - RegionLock rlock (this); - RegionList *rlist = new RegionList; - - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - if ((*i)->coverage (start, end) != OverlapNone) { - rlist->push_back (*i); - } - } - - return rlist; - } - - framepos_t - Playlist::find_next_transient (framepos_t from, int dir) - { - RegionLock rlock (this); - AnalysisFeatureList points; - AnalysisFeatureList these_points; - - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - if (dir > 0) { - if ((*i)->last_frame() < from) { - continue; - } - } else { - if ((*i)->first_frame() > from) { - continue; - } - } - - (*i)->get_transients (these_points); - - /* add first frame, just, err, because */ - - these_points.push_back ((*i)->first_frame()); - - points.insert (points.end(), these_points.begin(), these_points.end()); - these_points.clear (); - } - - if (points.empty()) { - return -1; - } - - TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0); - bool reached = false; - - if (dir > 0) { - for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) { - if ((*x) >= from) { - reached = true; - } - - if (reached && (*x) > from) { - return *x; - } - } - } else { - for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) { - if ((*x) <= from) { - reached = true; - } - - if (reached && (*x) < from) { - return *x; - } - } - } - - return -1; - } - - boost::shared_ptr - Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir) - { - RegionLock rlock (this); - boost::shared_ptr ret; - framepos_t closest = max_framepos; - - bool end_iter = false; - - for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { +boost::shared_ptr +Playlist::find_regions_at (framepos_t frame) +{ + /* Caller must hold lock */ + + boost::shared_ptr rlist (new RegionList); + + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + if ((*i)->covers (frame)) { + rlist->push_back (*i); + } + } + + return rlist; +} - if(end_iter) break; +boost::shared_ptr +Playlist::regions_with_start_within (Evoral::Range range) +{ + RegionReadLock rlock (this); + boost::shared_ptr rlist (new RegionList); - frameoffset_t distance; - boost::shared_ptr r = (*i); - framepos_t pos = 0; + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + if ((*i)->first_frame() >= range.from && (*i)->first_frame() <= range.to) { + rlist->push_back (*i); + } + } - switch (point) { - case Start: - pos = r->first_frame (); - break; - case End: - pos = r->last_frame (); - break; - case SyncPoint: - pos = r->sync_position (); - break; - } + return rlist; +} - switch (dir) { - case 1: /* forwards */ +boost::shared_ptr +Playlist::regions_with_end_within (Evoral::Range range) +{ + RegionReadLock rlock (this); + boost::shared_ptr rlist (new RegionList); - if (pos > frame) { - if ((distance = pos - frame) < closest) { - closest = distance; - ret = r; - end_iter = true; - } - } + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + if ((*i)->last_frame() >= range.from && (*i)->last_frame() <= range.to) { + rlist->push_back (*i); + } + } - break; + return rlist; +} - default: /* backwards */ +/** @param start Range start. + * @param end Range end. + * @return regions which have some part within this range. + */ +boost::shared_ptr +Playlist::regions_touched (framepos_t start, framepos_t end) +{ + RegionReadLock rlock (this); + return regions_touched_locked (start, end); +} - if (pos < frame) { - if ((distance = frame - pos) < closest) { - closest = distance; - ret = r; - } - } - else { - end_iter = true; - } +boost::shared_ptr +Playlist::regions_touched_locked (framepos_t start, framepos_t end) +{ + boost::shared_ptr rlist (new RegionList); + + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + if ((*i)->coverage (start, end) != Evoral::OverlapNone) { + rlist->push_back (*i); + } + } + + return rlist; +} - break; - } - } +framepos_t +Playlist::find_next_transient (framepos_t from, int dir) +{ + RegionReadLock rlock (this); + AnalysisFeatureList points; + AnalysisFeatureList these_points; + + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + if (dir > 0) { + if ((*i)->last_frame() < from) { + continue; + } + } else { + if ((*i)->first_frame() > from) { + continue; + } + } + + (*i)->get_transients (these_points); + + /* add first frame, just, err, because */ + + these_points.push_back ((*i)->first_frame()); + + points.insert (points.end(), these_points.begin(), these_points.end()); + these_points.clear (); + } + + if (points.empty()) { + return -1; + } + + TransientDetector::cleanup_transients (points, _session.frame_rate(), 3.0); + bool reached = false; + + if (dir > 0) { + for (AnalysisFeatureList::iterator x = points.begin(); x != points.end(); ++x) { + if ((*x) >= from) { + reached = true; + } + + if (reached && (*x) > from) { + return *x; + } + } + } else { + for (AnalysisFeatureList::reverse_iterator x = points.rbegin(); x != points.rend(); ++x) { + if ((*x) <= from) { + reached = true; + } + + if (reached && (*x) < from) { + return *x; + } + } + } + + return -1; +} - return ret; - } +boost::shared_ptr +Playlist::find_next_region (framepos_t frame, RegionPoint point, int dir) +{ + RegionReadLock rlock (this); + boost::shared_ptr ret; + framepos_t closest = max_framepos; + + bool end_iter = false; + + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + + if(end_iter) break; + + frameoffset_t distance; + boost::shared_ptr r = (*i); + framepos_t pos = 0; + + switch (point) { + case Start: + pos = r->first_frame (); + break; + case End: + pos = r->last_frame (); + break; + case SyncPoint: + pos = r->sync_position (); + break; + } + + switch (dir) { + case 1: /* forwards */ + + if (pos > frame) { + if ((distance = pos - frame) < closest) { + closest = distance; + ret = r; + end_iter = true; + } + } + + break; + + default: /* backwards */ + + if (pos < frame) { + if ((distance = frame - pos) < closest) { + closest = distance; + ret = r; + } + } else { + end_iter = true; + } + + break; + } + } + + return ret; +} framepos_t Playlist::find_next_region_boundary (framepos_t frame, int dir) { - RegionLock rlock (this); + RegionReadLock rlock (this); framepos_t closest = max_framepos; framepos_t ret = -1; @@ -2078,14 +1978,14 @@ Playlist::flush_notifications (bool from_undo) void Playlist::rdiff (vector& cmds) const { - RegionLock rlock (const_cast (this)); + RegionReadLock rlock (const_cast (this)); Stateful::rdiff (cmds); } void Playlist::clear_owned_changes () { - RegionLock rlock (this); + RegionReadLock rlock (this); Stateful::clear_owned_changes (); } @@ -2097,11 +1997,11 @@ Playlist::flush_notifications (bool from_undo) freeze (); /* add the added regions */ - for (RegionListProperty::ChangeContainer::iterator i = change.added.begin(); i != change.added.end(); ++i) { + for (RegionListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) { add_region_internal ((*i), (*i)->position()); } /* remove the removed regions */ - for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) { + for (RegionListProperty::ChangeContainer::const_iterator i = change.removed.begin(); i != change.removed.end(); ++i) { remove_region (*i); } @@ -2190,7 +2090,7 @@ Playlist::flush_notifications (bool from_undo) } { - RegionLock rlock (this); + RegionWriteLock rlock (this); add_region_internal (region, region->position()); } @@ -2201,15 +2101,6 @@ Playlist::flush_notifications (bool from_undo) if (seen_region_nodes && regions.empty()) { ret = -1; - } else { - - /* update dependents, which was not done during add_region_internal - due to in_set_state being true - */ - - for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) { - check_dependents (*r, false); - } } thaw (); @@ -2250,7 +2141,7 @@ Playlist::state (bool full_state) node->add_property (X_("frozen"), _frozen ? "yes" : "no"); if (full_state) { - RegionLock rlock (this, false); + RegionReadLock rlock (this); snprintf (buf, sizeof (buf), "%u", _combine_ops); node->add_property ("combine-ops", buf); @@ -2270,21 +2161,31 @@ Playlist::state (bool full_state) bool Playlist::empty() const { - RegionLock rlock (const_cast(this), false); + RegionReadLock rlock (const_cast(this)); return regions.empty(); } uint32_t Playlist::n_regions() const { - RegionLock rlock (const_cast(this), false); + RegionReadLock rlock (const_cast(this)); return regions.size(); } +/** @return true if the all_regions list is empty, ie this playlist + * has never had a region added to it. + */ +bool +Playlist::all_regions_empty() const +{ + RegionReadLock rl (const_cast (this)); + return all_regions.empty(); +} + pair Playlist::get_extent () const { - RegionLock rlock (const_cast(this), false); + RegionReadLock rlock (const_cast(this)); return _get_extent (); } @@ -2327,7 +2228,7 @@ Playlist::bump_name (string name, Session &session) layer_t Playlist::top_layer() const { - RegionLock rlock (const_cast (this)); + RegionReadLock rlock (const_cast (this)); layer_t top = 0; for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { @@ -2376,15 +2277,16 @@ Playlist::set_layer (boost::shared_ptr region, double new_layer) } void -Playlist::setup_layering_indices (RegionList const & regions) const +Playlist::setup_layering_indices (RegionList const & regions) { uint64_t j = 0; + list > xf; + for (RegionList::const_iterator k = regions.begin(); k != regions.end(); ++k) { (*k)->set_layering_index (j++); } } - /** Take the layering indices of each of our regions, compute the layers * that they should be on, and write the layers back to the regions. */ @@ -2500,7 +2402,7 @@ Playlist::relayer () notify_layering_changed (); /* This relayer() may have been called as a result of a region removal, in which - case we need to setup layering indices so account for the one that has just + case we need to setup layering indices to account for the one that has just gone away. */ setup_layering_indices (copy); @@ -2543,7 +2445,7 @@ Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards) _nudging = true; { - RegionLock rlock (const_cast (this)); + RegionWriteLock rlock (const_cast (this)); for (i = regions.begin(); i != regions.end(); ++i) { @@ -2584,9 +2486,9 @@ Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards) bool Playlist::uses_source (boost::shared_ptr src) const { - RegionLock rlock (const_cast (this)); + RegionReadLock rlock (const_cast (this)); - for (set >::iterator r = all_regions.begin(); r != all_regions.end(); ++r) { + for (set >::const_iterator r = all_regions.begin(); r != all_regions.end(); ++r) { if ((*r)->uses_source (src)) { return true; } @@ -2598,7 +2500,7 @@ Playlist::uses_source (boost::shared_ptr src) const boost::shared_ptr Playlist::find_region (const ID& id) const { - RegionLock rlock (const_cast (this)); + RegionReadLock rlock (const_cast (this)); /* searches all regions currently in use by the playlist */ @@ -2614,7 +2516,7 @@ Playlist::find_region (const ID& id) const uint32_t Playlist::region_use_count (boost::shared_ptr r) const { - RegionLock rlock (const_cast (this)); + RegionReadLock rlock (const_cast (this)); uint32_t cnt = 0; for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { @@ -2631,7 +2533,7 @@ Playlist::region_by_id (const ID& id) const { /* searches all regions ever added to this playlist */ - for (set >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) { + for (set >::const_iterator i = all_regions.begin(); i != all_regions.end(); ++i) { if ((*i)->id() == id) { return *i; } @@ -2678,7 +2580,7 @@ Playlist::shuffle (boost::shared_ptr region, int dir) _shuffling = true; { - RegionLock rlock (const_cast (this)); + RegionWriteLock rlock (const_cast (this)); if (dir > 0) { @@ -2775,8 +2677,6 @@ Playlist::shuffle (boost::shared_ptr region, int dir) if (moved) { relayer (); - check_dependents (region, false); - notify_contents_changed(); } @@ -2785,7 +2685,7 @@ Playlist::shuffle (boost::shared_ptr region, int dir) bool Playlist::region_is_shuffle_constrained (boost::shared_ptr) { - RegionLock rlock (const_cast (this)); + RegionReadLock rlock (const_cast (this)); if (regions.size() > 1) { return true; @@ -2797,7 +2697,7 @@ Playlist::region_is_shuffle_constrained (boost::shared_ptr) void Playlist::update_after_tempo_map_change () { - RegionLock rlock (const_cast (this)); + RegionWriteLock rlock (const_cast (this)); RegionList copy (regions.rlist()); freeze (); @@ -2812,7 +2712,7 @@ Playlist::update_after_tempo_map_change () void Playlist::foreach_region (boost::function)> s) { - RegionLock rl (this, false); + RegionWriteLock rl (this, false); for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { s (*i); } @@ -2821,7 +2721,7 @@ Playlist::foreach_region (boost::function)> s) bool Playlist::has_region_at (framepos_t const p) const { - RegionLock (const_cast (this)); + RegionReadLock (const_cast (this)); RegionList::const_iterator i = regions.begin (); while (i != regions.end() && !(*i)->covers (p)) { @@ -2835,7 +2735,7 @@ Playlist::has_region_at (framepos_t const p) const void Playlist::remove_region_by_source (boost::shared_ptr s) { - RegionLock rl (this); + RegionWriteLock rl (this); RegionList::iterator i = regions.begin(); while (i != regions.end()) { @@ -2858,7 +2758,7 @@ Playlist::remove_region_by_source (boost::shared_ptr s) framepos_t Playlist::find_next_top_layer_position (framepos_t t) const { - RegionLock rlock (const_cast (this)); + RegionReadLock rlock (const_cast (this)); layer_t const top = top_layer (); @@ -2925,6 +2825,7 @@ Playlist::combine (const RegionList& r) /* make position relative to zero */ pl->add_region (copied_region, original_region->position() - earliest_position); + copied_region->set_layer (original_region->layer ()); /* use the maximum number of channels for any region */ @@ -2939,10 +2840,6 @@ Playlist::combine (const RegionList& r) pre_combine (copies); - /* add any dependent regions to the new playlist */ - - copy_dependents (old_and_new_regions, pl.get()); - /* now create a new PlaylistSource for each channel in the new playlist */ SourceList sources; @@ -3084,13 +2981,13 @@ Playlist::uncombine (boost::shared_ptr target) modified_region = false; switch (original->coverage (adjusted_start, adjusted_end)) { - case OverlapNone: + case Evoral::OverlapNone: /* original region does not cover any part of the current state of the compound region */ continue; - case OverlapInternal: + case Evoral::OverlapInternal: /* overlap is just a small piece inside the * original so trim both ends */ @@ -3098,13 +2995,13 @@ Playlist::uncombine (boost::shared_ptr target) modified_region = true; break; - case OverlapExternal: + case Evoral::OverlapExternal: /* overlap fully covers original, so leave it as is */ break; - case OverlapEnd: + case Evoral::OverlapEnd: /* overlap starts within but covers end, so trim the front of the region */ @@ -3112,7 +3009,7 @@ Playlist::uncombine (boost::shared_ptr target) modified_region = true; break; - case OverlapStart: + case Evoral::OverlapStart: /* overlap covers start but ends within, so * trim the end of the region. */ @@ -3155,10 +3052,6 @@ Playlist::uncombine (boost::shared_ptr target) add_region ((*i), (*i)->position()); } - /* now move dependent regions back from the compound to this playlist */ - - pl->copy_dependents (old_and_new_regions, this); - in_partition = false; thaw (); } @@ -3166,7 +3059,7 @@ Playlist::uncombine (boost::shared_ptr target) uint32_t Playlist::max_source_level () const { - RegionLock rlock (const_cast (this)); + RegionReadLock rlock (const_cast (this)); uint32_t lvl = 0; for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { @@ -3176,38 +3069,44 @@ Playlist::max_source_level () const return lvl; } - -uint32_t -Playlist::count_joined_regions () const -{ - RegionLock rlock (const_cast (this)); - uint32_t cnt = 0; - - for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { - if ((*i)->max_source_level() > 0) { - cnt++; - } - } - - return cnt; -} - void Playlist::set_orig_track_id (const PBD::ID& id) { _orig_track_id = id; } -uint64_t -Playlist::highest_layering_index () const +/** Take a list of ranges, coalesce any that can be coalesced, then call + * check_crossfades for each one. + */ +void +Playlist::coalesce_and_check_crossfades (list > ranges) { - RegionLock rlock (const_cast (this)); + /* XXX: it's a shame that this coalesce algorithm also exists in + TimeSelection::consolidate(). + */ - uint64_t h = 0; - for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { - h = max (h, (*i)->layering_index ()); - } + /* XXX: xfade: this is implemented in Evoral::RangeList */ - return h; +restart: + for (list >::iterator i = ranges.begin(); i != ranges.end(); ++i) { + for (list >::iterator j = ranges.begin(); j != ranges.end(); ++j) { + + if (i == j) { + continue; + } + + if (Evoral::coverage (i->from, i->to, j->from, j->to) != Evoral::OverlapNone) { + i->from = min (i->from, j->from); + i->to = max (i->to, j->to); + ranges.erase (j); + goto restart; + } + } + } } +void +Playlist::set_capture_insertion_in_progress (bool yn) +{ + _capture_insertion_underway = yn; +}