X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fplaylist.cc;h=8862c633ab62fbe6578b5d5b3ed36605a174101a;hb=6349570fb24b03694e814dfff344faea92659054;hp=47462a3575be3b19274698290d9dbf861f68a3d8;hpb=5cf1f7f3b28abd36f9390014016def94f4e1468d;p=ardour.git diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index 47462a3575..8862c633ab 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -172,6 +172,7 @@ Playlist::Playlist (boost::shared_ptr other, string namestr, boo in_set_state--; _splicing = other->_splicing; + _rippling = other->_rippling; _nudging = other->_nudging; _edit_mode = other->_edit_mode; @@ -255,6 +256,10 @@ Playlist::Playlist (boost::shared_ptr other, framepos_t start, f add_region_internal (new_region, position); } + //keep track of any dead space at end (for pasting into Ripple or Splice mode) + //at the end of construction, any length of cnt beyond the extents of the regions is end_space + _end_space = cnt - (get_extent().second - get_extent().first); + in_set_state--; first_set_state = false; } @@ -302,6 +307,7 @@ Playlist::init (bool hide) _refcnt = 0; _hidden = hide; _splicing = false; + _rippling = false; _shuffling = false; _nudging = false; in_set_state = 0; @@ -313,6 +319,7 @@ Playlist::init (bool hide) _frozen = false; _capture_insertion_underway = false; _combine_ops = 0; + _end_space = 0; _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)); @@ -550,6 +557,7 @@ Playlist::notify_region_added (boost::shared_ptr r) pending_contents_change = false; RegionAdded (boost::weak_ptr (r)); /* EMIT SIGNAL */ ContentsChanged (); /* EMIT SIGNAL */ + } } @@ -604,37 +612,41 @@ Playlist::flush_notifications (bool from_undo) */ } - if (((regions_changed || pending_contents_change) && !in_set_state) || pending_layering) { + /* notify about contents/region changes first so that layering changes + * in a UI will take place on the new contents. + */ + + if (regions_changed || pending_contents_change) { + pending_layering = true; + ContentsChanged (); /* EMIT SIGNAL */ + } + + for (s = pending_adds.begin(); s != pending_adds.end(); ++s) { + (*s)->clear_changes (); + RegionAdded (boost::weak_ptr (*s)); /* EMIT SIGNAL */ + } + + if ((regions_changed && !in_set_state) || pending_layering) { relayer (); } + + 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); + } + + if (!pending_region_extensions.empty ()) { + RegionsExtended (pending_region_extensions); + } - if (regions_changed || pending_contents_change) { - pending_contents_change = false; - ContentsChanged (); /* EMIT SIGNAL */ - } - - for (s = pending_adds.begin(); s != pending_adds.end(); ++s) { - (*s)->clear_changes (); - RegionAdded (boost::weak_ptr (*s)); /* EMIT SIGNAL */ - } - - 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); - } - - if (!pending_region_extensions.empty ()) { - RegionsExtended (pending_region_extensions); - } - - clear_pending (); + clear_pending (); - in_flush = false; - } + in_flush = false; +} void Playlist::clear_pending () @@ -706,7 +718,7 @@ Playlist::flush_notifications (bool from_undo) } } - possibly_splice_unlocked (position, (pos + length) - position, boost::shared_ptr()); + possibly_splice_unlocked (position, (pos + length) - position, region); } void @@ -1102,6 +1114,10 @@ Playlist::flush_notifications (bool from_undo) in_partition = false; } + + //keep track of any dead space at end (for pasting into Ripple or Splice mode) + framepos_t wanted_length = end-start; + _end_space = wanted_length - get_extent().second-get_extent().first; } boost::shared_ptr @@ -1186,7 +1202,8 @@ Playlist::flush_notifications (bool from_undo) new_name += '.'; new_name += buf; - cnt = min (_get_extent().second - start, cnt); + // cnt = min (_get_extent().second - start, cnt); (We need the full range length when copy/pasting in Ripple. Why was this limit here? It's not in CUT... ) + return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden); } @@ -1399,7 +1416,7 @@ Playlist::flush_notifications (bool from_undo) if (_edit_mode == Splice) { splice_locked (at, distance, exclude); - } + } } void @@ -1456,12 +1473,63 @@ Playlist::flush_notifications (bool from_undo) _splicing = false; notify_contents_changed (); - } +} - void - Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr region) - { - if (in_set_state || _splicing || _nudging || _shuffling) { +void +Playlist::ripple_locked (framepos_t at, framecnt_t distance, RegionList *exclude) +{ + { + RegionWriteLock rl (this); + core_ripple (at, distance, exclude); + } +} + +void +Playlist::ripple_unlocked (framepos_t at, framecnt_t distance, RegionList *exclude) +{ + core_ripple (at, distance, exclude); +} + +void +Playlist::core_ripple (framepos_t at, framecnt_t distance, RegionList *exclude) +{ + if (distance == 0) { + return; + } + + _rippling = true; + RegionListProperty copy = regions; + for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) { + assert (i != copy.end()); + + if (exclude) { + if (std::find(exclude->begin(), exclude->end(), (*i)) != exclude->end()) { + continue; + } + } + + if ((*i)->position() >= at) { + framepos_t new_pos = (*i)->position() + distance; + framepos_t limit = max_framepos - (*i)->length(); + if (new_pos < 0) { + new_pos = 0; + } else if (new_pos >= limit ) { + new_pos = limit; + } + + (*i)->set_position (new_pos); + } + } + + _rippling = false; + notify_contents_changed (); +} + + +void +Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shared_ptr region) +{ + if (in_set_state || _splicing || _rippling || _nudging || _shuffling) { return; } @@ -1574,6 +1642,8 @@ Playlist::flush_notifications (bool from_undo) save = true; } + mark_session_dirty (); + return save; } @@ -2189,6 +2259,14 @@ Playlist::get_extent () const return _get_extent (); } +pair +Playlist::get_extent_with_endspace () const +{ + pair l = get_extent(); + l.second += _end_space; + return l; +} + pair Playlist::_get_extent () const { @@ -2257,7 +2335,10 @@ struct RelayerSort { void Playlist::set_layer (boost::shared_ptr region, double new_layer) { - /* Remove the layer we are setting from our region list, and sort it */ + /* Remove the layer we are setting from our region list, and sort it + * using the layer indeces. + */ + RegionList copy = regions.rlist(); copy.remove (region); copy.sort (RelayerSort ()); @@ -2280,13 +2361,18 @@ void 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++); } } +struct LaterHigherSort { + bool operator () (boost::shared_ptr a, boost::shared_ptr b) { + return a->position() < b->position(); + } +}; + /** 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. */ @@ -2321,9 +2407,16 @@ Playlist::relayer () vector > layers; layers.push_back (vector (divisions)); - /* Sort our regions into layering index order */ + /* Sort our regions into layering index order (for manual layering) or position order (for later is higher)*/ RegionList copy = regions.rlist(); - copy.sort (RelayerSort ()); + switch (Config->get_layer_model()) { + case LaterHigher: + copy.sort (LaterHigherSort ()); + break; + case Manual: + copy.sort (RelayerSort ()); + break; + } DEBUG_TRACE (DEBUG::Layering, "relayer() using:\n"); for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) { @@ -2525,6 +2618,29 @@ Playlist::region_use_count (boost::shared_ptr r) const } } + RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations()); + for (RegionFactory::CompoundAssociations::iterator it = cassocs.begin(); it != cassocs.end(); ++it) { + /* check if region is used in a compound */ + if (it->second == r) { + /* region is referenced as 'original' of a compound */ + ++cnt; + break; + } + if (r->whole_file() && r->max_source_level() > 0) { + /* region itself ia a compound. + * the compound regions are not referenced -> check regions inside compound + */ + const SourceList& sl = r->sources(); + for (SourceList::const_iterator s = sl.begin(); s != sl.end(); ++s) { + boost::shared_ptr ps = boost::dynamic_pointer_cast(*s); + if (!ps) continue; + if (ps->playlist()->region_use_count(it->first)) { + // break out of both loops + return ++cnt; + } + } + } + } return cnt; } @@ -2694,6 +2810,12 @@ Playlist::region_is_shuffle_constrained (boost::shared_ptr) return false; } +void +Playlist::ripple (framepos_t at, framecnt_t distance, RegionList *exclude) +{ + ripple_locked (at, distance, exclude); +} + void Playlist::update_after_tempo_map_change () { @@ -2809,7 +2931,14 @@ Playlist::combine (const RegionList& r) pl->in_partition = true; - for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) { + /* sort by position then layer. + * route_time_axis passes 'selected_regions' - which is not sorted. + * here we need the top-most first, then every layer's region sorted by position. + */ + RegionList sorted(r); + sorted.sort(RegionSortByLayerAndPosition()); + + for (RegionList::const_iterator i = sorted.begin(); i != sorted.end(); ++i) { /* copy the region */ @@ -2954,6 +3083,7 @@ Playlist::uncombine (boost::shared_ptr target) } boost::shared_ptr original (ca->second); + cassocs.erase(ca); bool modified_region; if (i == rl.begin()) { @@ -3050,12 +3180,26 @@ Playlist::uncombine (boost::shared_ptr target) for (vector >::iterator i = originals.begin(); i != originals.end(); ++i) { add_region ((*i), (*i)->position()); + set_layer((*i), (*i)->layer()); + if (!RegionFactory::region_by_id((*i)->id())) { + RegionFactory::map_add(*i); + } } in_partition = false; thaw (); } +void +Playlist::fade_range (list& ranges) +{ + for (list::iterator r = ranges.begin(); r != ranges.end(); ++r) { + for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { + (*i)->fade_range ((*r).start, (*r).end); + } + } +} + uint32_t Playlist::max_source_level () const { @@ -3095,6 +3239,7 @@ restart: continue; } + // XXX i->from can be > i->to - is this right? coverage() will return OverlapNone in this case 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);