diff options
author | Carl Hetherington <carl@carlh.net> | 2012-04-16 16:32:22 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2012-04-16 16:32:22 +0000 |
commit | a2897ecef6da6a458aa1de8c2d9973a1e809dca2 (patch) | |
tree | 189e34b829823fc73d11fba249f283e00336d44d /libs/ardour/audioregion.cc | |
parent | 02c498a8fa1c2e47988a256321bdcf5e9e869de1 (diff) |
Fairly major change to the way in which crossfades are handled;
they are now done with region fades, rather than separate objects.
After this commit, Ardour will try to convert your session files
to the new crossfade format, but will make a backup in your
session folder first.
If you have works in progress using Ardour 3 it is
***STRONGLY RECOMMENDED*** that you back up session files before
updating to this commit.
git-svn-id: svn://localhost/ardour2/branches/3.0@11986 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour/audioregion.cc')
-rw-r--r-- | libs/ardour/audioregion.cc | 192 |
1 files changed, 91 insertions, 101 deletions
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 2c63f1d40c..617678d634 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -345,16 +345,17 @@ framecnt_t AudioRegion::read (Sample* buf, framepos_t timeline_position, framecnt_t cnt, int channel) const { /* raw read, no fades, no gain, nada */ + /* XXX: xfade: passes no mixbuf... */ return _read_at (_sources, _length, buf, 0, 0, _position + timeline_position, cnt, channel, ReadOps (0)); } framecnt_t AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, - framepos_t file_position, framecnt_t cnt, uint32_t chan_n) const + framepos_t position, framecnt_t cnt, uint32_t chan_n) const { /* regular diskstream/butler read complete with fades etc */ return _read_at (_sources, _length, buf, mixdown_buffer, gain_buffer, - file_position, cnt, chan_n, ReadOps (~0)); + position, cnt, chan_n, ReadOps (~0)); } framecnt_t @@ -369,7 +370,9 @@ AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_bu buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, ReadOps (0)); } -/** @param position Position within the session */ +/** @param position Position within the session to read from. + * @param cnt Number of frames to read. + */ framecnt_t AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit, Sample *buf, Sample *mixdown_buffer, float *gain_buffer, @@ -378,44 +381,27 @@ AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit, uint32_t chan_n, ReadOps rops) const { + /* We are reading data from this region into buf (possibly via mixdown_buffer). + The caller has verified that we cover the desired section. + */ + assert (cnt >= 0); - frameoffset_t internal_offset; - frameoffset_t buf_offset; - framecnt_t to_read; - bool raw = (rops == ReadOpsNone); - if (n_channels() == 0) { return 0; } - if (muted() && !raw) { + if (muted() && rops != ReadOpsNone) { return 0; /* read nothing */ } - /* precondition: caller has verified that we cover the desired section */ + + /* WORK OUT WHERE TO GET DATA FROM */ - if (position < _position) { - internal_offset = 0; - buf_offset = _position - position; - /* if this fails then the requested section is entirely - before the position of this region. An error in xfade - construction that was fixed in oct 2011 (rev 10259) - led to this being the case. We don't want to crash - when this error is encountered, so just settle - on displaying an error. - */ - if (cnt < buf_offset) { - error << "trying to read region " << name() << " @ " << position << " which is outside region bounds " - << _position << " .. " << last_frame() << " (len = " << length() << ')' - << endmsg; - return 0; // read nothing - } - cnt -= buf_offset; - } else { - internal_offset = position - _position; - buf_offset = 0; - } + framecnt_t to_read; + + assert (position >= _position); + frameoffset_t const internal_offset = position - _position; if (internal_offset >= limit) { return 0; /* read nothing */ @@ -425,46 +411,26 @@ AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit, return 0; /* read nothing */ } - if (opaque() || raw) { - /* overwrite whatever is there */ - mixdown_buffer = buf + buf_offset; - } else { - mixdown_buffer += buf_offset; - } - - if (chan_n < n_channels()) { - - boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[chan_n]); - if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) { - return 0; /* "read nothing" */ - } - - } else { - /* track is N-channel, this region has less channels; silence the ones - we don't have. - */ + /* COMPUTE DETAILS OF ANY FADES INVOLVED IN THIS READ */ - if (Config->get_replicate_missing_region_channels()) { - /* track is N-channel, this region has less channels, so use a relevant channel - */ + /* Amount of fade in that we are dealing with in this read */ + framecnt_t fade_in_limit = 0; - uint32_t channel = n_channels() % chan_n; - boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[channel]); - - if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) { - return 0; /* "read nothing" */ - } + /* Offset from buf / mixdown_buffer of the start + of any fade out that we are dealing with + */ + frameoffset_t fade_out_offset = 0; + + /* Amount of fade in that we are dealing with in this read */ + framecnt_t fade_out_limit = 0; - } else { - memset (mixdown_buffer, 0, sizeof (Sample) * cnt); - } - } + framecnt_t fade_interval_start = 0; if (rops & ReadOpsFades) { - /* fade in */ - + /* Fade in */ + if (_fade_in_active && _session.config.get_use_region_fades()) { framecnt_t fade_in_length = (framecnt_t) _fade_in->back()->when; @@ -472,20 +438,11 @@ AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit, /* see if this read is within the fade in */ if (internal_offset < fade_in_length) { - - framecnt_t fi_limit; - - fi_limit = min (to_read, fade_in_length - internal_offset); - - _fade_in->curve().get_vector (internal_offset, internal_offset+fi_limit, gain_buffer, fi_limit); - - for (framecnt_t n = 0; n < fi_limit; ++n) { - mixdown_buffer[n] *= gain_buffer[n]; - } + fade_in_limit = min (to_read, fade_in_length - internal_offset); } } - /* fade out */ + /* Fade out */ if (_fade_out_active && _session.config.get_use_region_fades()) { @@ -508,28 +465,50 @@ AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit, */ - framecnt_t fade_out_length = (framecnt_t) _fade_out->back()->when; - framecnt_t fade_interval_start = max(internal_offset, limit-fade_out_length); + fade_interval_start = max (internal_offset, limit - framecnt_t (_fade_out->back()->when)); framecnt_t fade_interval_end = min(internal_offset + to_read, limit); if (fade_interval_end > fade_interval_start) { - /* (part of the) the fade out is in this buffer */ + /* (part of the) the fade out is in this buffer */ + fade_out_limit = fade_interval_end - fade_interval_start; + fade_out_offset = fade_interval_start - internal_offset; + } + } + } - framecnt_t fo_limit = fade_interval_end - fade_interval_start; - framecnt_t curve_offset = fade_interval_start - (limit-fade_out_length); - framecnt_t fade_offset = fade_interval_start - internal_offset; + /* READ DATA FROM THE SOURCE INTO mixdown_buffer. + We can never read directly into buf, since it may contain data + from a transparent region `above' this one in the stack; we + must always mix. + */ - _fade_out->curve().get_vector (curve_offset, curve_offset+fo_limit, gain_buffer, fo_limit); + if (chan_n < n_channels()) { - for (framecnt_t n = 0, m = fade_offset; n < fo_limit; ++n, ++m) { - mixdown_buffer[m] *= gain_buffer[n]; - } - } + boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[chan_n]); + if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) { + return 0; /* "read nothing" */ + } + + } else { + + /* track is N-channel, this region has fewer channels; silence the ones + we don't have. + */ + + if (Config->get_replicate_missing_region_channels()) { + /* track is N-channel, this region has less channels, so use a relevant channel + */ + + uint32_t channel = n_channels() % chan_n; + boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[channel]); + if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) { + return 0; /* "read nothing" */ + } } } - /* Regular gain curves and scaling */ + /* APPLY REGULAR GAIN CURVES AND SCALING TO mixdown_buffer */ if ((rops & ReadOpsOwnAutomation) && envelope_active()) { _envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read); @@ -544,27 +523,34 @@ AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit, } } } else if ((rops & ReadOpsOwnScaling) && _scale_amplitude != 1.0f) { - - // XXX this should be using what in 2.0 would have been: - // Session::apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude); - - for (framecnt_t n = 0; n < to_read; ++n) { - mixdown_buffer[n] *= _scale_amplitude; - } + apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude); } - if (!opaque() && (buf != mixdown_buffer)) { - /* gack. the things we do for users. - */ + /* APPLY FADES TO THE DATA IN mixdown_buffer AND MIX THE RESULTS INTO buf */ - buf += buf_offset; + if (fade_in_limit != 0) { + _fade_in->curve().get_vector (internal_offset, internal_offset + fade_in_limit, gain_buffer, fade_in_limit); - for (framecnt_t n = 0; n < to_read; ++n) { - buf[n] += mixdown_buffer[n]; + for (framecnt_t n = 0; n < fade_in_limit; ++n) { + buf[n] += mixdown_buffer[n] * gain_buffer[n]; } } + if (fade_out_limit != 0) { + framecnt_t const curve_offset = fade_interval_start - (limit - _fade_out->back()->when); + _fade_out->curve().get_vector (curve_offset, curve_offset + fade_out_limit, gain_buffer, fade_out_limit); + + for (framecnt_t n = 0, m = fade_out_offset; n < fade_out_limit; ++n, ++m) { + buf[m] += mixdown_buffer[m] * gain_buffer[n]; + } + } + + + /* MIX THE REGION BODY FROM mixdown_buffer INTO buf */ + + mix_buffers_no_gain (buf + fade_in_limit, mixdown_buffer + fade_in_limit, to_read - fade_in_limit - fade_out_limit); + return to_read; } @@ -1519,7 +1505,11 @@ AudioRegion::find_silence (Sample threshold, framecnt_t min_length, InterThreadI return silent_periods; } - +Evoral::Range<framepos_t> +AudioRegion::body_range () const +{ + return Evoral::Range<framepos_t> (first_frame() + _fade_in->back()->when, last_frame() - _fade_out->back()->when); +} extern "C" { |