diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index fd6c3a8528..013629637d 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -238,6 +238,8 @@ class AudioRegion : public Region bool _fade_in_is_xfade; bool _fade_out_is_xfade; + boost::shared_ptr get_single_other_xfade_region (bool start) const; + protected: /* default constructor for derived (compound) types */ diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index 788a8d90c9..1d7894fac5 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -141,6 +141,15 @@ class Region framepos_t first_frame () const { return _position; } framepos_t last_frame () const { return _position + _length - 1; } + /** Return the earliest possible value of _position given the + * value of _start within the region's sources + */ + framepos_t earliest_possible_position () const; + /** Return the last possible value of _last_frame given the + * value of _startin the regions's sources + */ + framepos_t latest_possible_frame () const; + Evoral::Range last_range () const { return Evoral::Range (_last_position, _last_position + _last_length - 1); } diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 4ba383b37e..36d5cf0a8c 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -1148,6 +1148,20 @@ AudioRegion::set_fade_in_length (framecnt_t len) if (_inverse_fade_in) { _inverse_fade_in->extend_to (len); } + + if (_fade_in_is_xfade) { + + /* trim a single other region below us to the new start + of the fade. + */ + + boost::shared_ptr other = get_single_other_xfade_region (true); + if (other) { + other->trim_end (position() + len); + } + } + + _default_fade_in = false; send_change (PropertyChange (Properties::fade_in)); } @@ -1167,10 +1181,24 @@ AudioRegion::set_fade_out_length (framecnt_t len) bool changed = _fade_out->extend_to (len); if (changed) { + if (_inverse_fade_out) { _inverse_fade_out->extend_to (len); } _default_fade_out = false; + + if (_fade_out_is_xfade) { + + /* trim a single other region below us to the new start + of the fade. + */ + + boost::shared_ptr other = get_single_other_xfade_region (false); + if (other) { + other->trim_front (last_frame() - len); + } + } + send_change (PropertyChange (Properties::fade_out)); } } @@ -1801,8 +1829,8 @@ AudioRegion::set_fade_out_is_xfade (bool yn) _fade_out_is_xfade = yn; } -framecnt_t -AudioRegion::verify_xfade_bounds (framecnt_t len, bool start) +boost::shared_ptr +AudioRegion::get_single_other_xfade_region (bool start) const { boost::shared_ptr pl (playlist()); @@ -1810,11 +1838,10 @@ AudioRegion::verify_xfade_bounds (framecnt_t len, bool start) /* not currently in a playlist - xfade length is unbounded (and irrelevant) */ - return len; + return boost::shared_ptr (); } boost::shared_ptr rl; - framecnt_t maxlen; if (start) { rl = pl->regions_at (position()); @@ -1837,17 +1864,27 @@ AudioRegion::verify_xfade_bounds (framecnt_t len, bool start) if (n != 2) { /* zero or multiple regions stacked here - don't care about xfades */ - return len; + return boost::shared_ptr (); } + return other; +} + +framecnt_t +AudioRegion::verify_xfade_bounds (framecnt_t len, bool start) +{ + boost::shared_ptr other = get_single_other_xfade_region (start); + framecnt_t maxlen; + /* we overlap a single region. clamp the length of an xfade to - the duration of the overlap. + the maximum possible duration of the overlap (if the other + region were trimmed appropriately). */ if (start) { - maxlen = other->last_frame() - position(); + maxlen = other->latest_possible_frame() - position(); } else { - maxlen = last_frame() - other->position(); + maxlen = last_frame() - other->earliest_possible_position(); } return min (maxlen, len); diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index efaa104d35..a4a1584792 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -1654,3 +1654,33 @@ Region::set_start_internal (framecnt_t s) { _start = s; } + +framepos_t +Region::earliest_possible_position () const +{ + if (_start > _position) { + return 0; + } else { + return _position - _start; + } +} + +framecnt_t +Region::latest_possible_frame () const +{ + framecnt_t minlen = max_framecnt; + + for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + /* non-audio regions have a length that may vary based on their + * position, so we have to pass it in the call. + */ + minlen = min (minlen, (*i)->length (_position)); + } + + /* the latest possible last frame is determined by the current + * position, plus the shortest source extent past _start. + */ + + return _position + (minlen - _start) - 1; +} +