mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-30 00:43:18 +01:00
RegionFX: implement pre/post region-fade FX
This commit is contained in:
parent
8f5d6295b3
commit
4bcf1d31c6
3 changed files with 111 additions and 30 deletions
|
|
@ -50,6 +50,7 @@ namespace Properties {
|
|||
LIBARDOUR_API extern PBD::PropertyDescriptor<bool> default_fade_out;
|
||||
LIBARDOUR_API extern PBD::PropertyDescriptor<bool> fade_in_active;
|
||||
LIBARDOUR_API extern PBD::PropertyDescriptor<bool> fade_out_active;
|
||||
LIBARDOUR_API extern PBD::PropertyDescriptor<bool> fade_before_fx;
|
||||
LIBARDOUR_API extern PBD::PropertyDescriptor<float> scale_amplitude;
|
||||
LIBARDOUR_API extern PBD::PropertyDescriptor<std::shared_ptr<AutomationList> > fade_in;
|
||||
LIBARDOUR_API extern PBD::PropertyDescriptor<std::shared_ptr<AutomationList> > inverse_fade_in;
|
||||
|
|
@ -100,6 +101,7 @@ class LIBARDOUR_API AudioRegion : public Region, public AudioReadable
|
|||
bool envelope_active () const { return _envelope_active; }
|
||||
bool fade_in_active () const { return _fade_in_active; }
|
||||
bool fade_out_active () const { return _fade_out_active; }
|
||||
bool fade_before_fx () const { return _fade_before_fx; }
|
||||
|
||||
std::shared_ptr<AutomationList> fade_in() { return _fade_in.val (); }
|
||||
std::shared_ptr<AutomationList> inverse_fade_in() { return _inverse_fade_in.val (); }
|
||||
|
|
@ -162,6 +164,8 @@ class LIBARDOUR_API AudioRegion : public Region, public AudioReadable
|
|||
void set_envelope_active (bool yn);
|
||||
void set_default_envelope ();
|
||||
|
||||
void set_fade_before_fx (bool yn);
|
||||
|
||||
int separate_by_channel (std::vector<std::shared_ptr<Region> >&) const;
|
||||
|
||||
bool remove_plugin (std::shared_ptr<RegionFxPlugin>);
|
||||
|
|
@ -220,6 +224,7 @@ class LIBARDOUR_API AudioRegion : public Region, public AudioReadable
|
|||
PBD::Property<bool> _default_fade_out;
|
||||
PBD::Property<bool> _fade_in_active;
|
||||
PBD::Property<bool> _fade_out_active;
|
||||
PBD::Property<bool> _fade_before_fx;
|
||||
/** linear gain to apply to the whole region */
|
||||
PBD::Property<gain_t> _scale_amplitude;
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ namespace ARDOUR {
|
|||
PBD::PropertyDescriptor<bool> default_fade_out;
|
||||
PBD::PropertyDescriptor<bool> fade_in_active;
|
||||
PBD::PropertyDescriptor<bool> fade_out_active;
|
||||
PBD::PropertyDescriptor<bool> fade_before_fx;
|
||||
PBD::PropertyDescriptor<float> scale_amplitude;
|
||||
PBD::PropertyDescriptor<std::shared_ptr<AutomationList> > fade_in;
|
||||
PBD::PropertyDescriptor<std::shared_ptr<AutomationList> > inverse_fade_in;
|
||||
|
|
@ -176,6 +177,8 @@ AudioRegion::make_property_quarks ()
|
|||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade-in-active = %1\n", Properties::fade_in_active.property_id));
|
||||
Properties::fade_out_active.property_id = g_quark_from_static_string (X_("fade-out-active"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade-out-active = %1\n", Properties::fade_out_active.property_id));
|
||||
Properties::fade_before_fx.property_id = g_quark_from_static_string (X_("fade-before-fx"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fade-before-fx = %1\n", Properties::fade_before_fx.property_id));
|
||||
Properties::scale_amplitude.property_id = g_quark_from_static_string (X_("scale-amplitude"));
|
||||
DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for scale-amplitude = %1\n", Properties::scale_amplitude.property_id));
|
||||
Properties::fade_in.property_id = g_quark_from_static_string (X_("FadeIn"));
|
||||
|
|
@ -200,6 +203,7 @@ AudioRegion::register_properties ()
|
|||
add_property (_default_fade_out);
|
||||
add_property (_fade_in_active);
|
||||
add_property (_fade_out_active);
|
||||
add_property (_fade_before_fx);
|
||||
add_property (_scale_amplitude);
|
||||
add_property (_fade_in);
|
||||
add_property (_inverse_fade_in);
|
||||
|
|
@ -214,6 +218,7 @@ AudioRegion::register_properties ()
|
|||
, _default_fade_out (Properties::default_fade_out, true) \
|
||||
, _fade_in_active (Properties::fade_in_active, true) \
|
||||
, _fade_out_active (Properties::fade_out_active, true) \
|
||||
, _fade_before_fx (Properties::fade_before_fx, false) \
|
||||
, _scale_amplitude (Properties::scale_amplitude, 1.0) \
|
||||
, _fade_in (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeInAutomation), tdp))) \
|
||||
, _inverse_fade_in (Properties::inverse_fade_in, std::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeInAutomation), tdp))) \
|
||||
|
|
@ -226,6 +231,7 @@ AudioRegion::register_properties ()
|
|||
, _default_fade_out (Properties::default_fade_out, other->_default_fade_out) \
|
||||
, _fade_in_active (Properties::fade_in_active, other->_fade_in_active) \
|
||||
, _fade_out_active (Properties::fade_out_active, other->_fade_out_active) \
|
||||
, _fade_before_fx (Properties::fade_before_fx, other->_fade_before_fx) \
|
||||
, _scale_amplitude (Properties::scale_amplitude, other->_scale_amplitude) \
|
||||
, _fade_in (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_fade_in.val()))) \
|
||||
, _inverse_fade_in (Properties::fade_in, std::shared_ptr<AutomationList> (new AutomationList (*other->_inverse_fade_in.val()))) \
|
||||
|
|
@ -499,6 +505,22 @@ AudioRegion::set_envelope_active (bool yn)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioRegion::set_fade_before_fx (bool yn)
|
||||
{
|
||||
if (fade_before_fx() != yn) {
|
||||
_fade_before_fx = yn;
|
||||
send_change (PropertyChange (Properties::fade_before_fx));
|
||||
if (!has_region_fx ()) {
|
||||
return;
|
||||
}
|
||||
if (!_invalidated.exchange (true)) {
|
||||
send_change (PropertyChange (Properties::region_fx)); // trigger DiskReader overwrite
|
||||
}
|
||||
RegionFxChanged (); /* EMIT SIGNAL */
|
||||
}
|
||||
}
|
||||
|
||||
/** @param buf Buffer to put peak data in.
|
||||
* @param npeaks Number of peaks to read (ie the number of PeakDatas in buf)
|
||||
* @param offset Start position, as an offset from the start of this region's source.
|
||||
|
|
@ -585,6 +607,11 @@ AudioRegion::read_at (Sample* buf,
|
|||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<Playlist> pl (playlist());
|
||||
if (!pl){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* WORK OUT WHERE TO GET DATA FROM */
|
||||
|
||||
samplecnt_t to_read;
|
||||
|
|
@ -605,29 +632,28 @@ AudioRegion::read_at (Sample* buf,
|
|||
return 0; /* read nothing */
|
||||
}
|
||||
|
||||
std::shared_ptr<Playlist> pl (playlist());
|
||||
if (!pl){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* COMPUTE DETAILS OF ANY FADES INVOLVED IN THIS READ */
|
||||
/* COMPUTE DETAILS OF ANY FADES INVOLVED IN THIS READ
|
||||
*
|
||||
* This information is also used for inverse fades to fade out
|
||||
* layered regions below this one.
|
||||
*/
|
||||
bool const use_region_fades = _session.config.get_use_region_fades();
|
||||
|
||||
/* Amount (length) of fade in that we are dealing with in this read */
|
||||
samplecnt_t fade_in_limit = 0;
|
||||
|
||||
/* Offset from buf / mixdown_buffer of the start
|
||||
of any fade out that we are dealing with
|
||||
*/
|
||||
/* Offset from buf / mixdown_buffer of the start of any fade out that we are dealing with */
|
||||
sampleoffset_t fade_out_offset = 0;
|
||||
|
||||
/* Amount (length) of fade out that we are dealing with in this read */
|
||||
samplecnt_t fade_out_limit = 0;
|
||||
|
||||
/* offset for fade-out curve data */
|
||||
samplecnt_t fade_interval_start = 0;
|
||||
|
||||
/* Fade in */
|
||||
|
||||
if (_fade_in_active && _session.config.get_use_region_fades()) {
|
||||
if (_fade_in_active && use_region_fades) {
|
||||
|
||||
samplecnt_t fade_in_length = _fade_in->when(false).samples();
|
||||
|
||||
|
|
@ -639,15 +665,13 @@ AudioRegion::read_at (Sample* buf,
|
|||
}
|
||||
|
||||
/* Fade out */
|
||||
|
||||
if (_fade_out_active && _session.config.get_use_region_fades()) {
|
||||
if (_fade_out_active && use_region_fades) {
|
||||
|
||||
/* see if some part of this read is within the fade out */
|
||||
|
||||
/* ................. >| REGION
|
||||
/* ................. >| REGION
|
||||
* _length
|
||||
*
|
||||
* { } FADE
|
||||
* { } FADE
|
||||
* fade_out_length
|
||||
* ^
|
||||
* _length - fade_out_length
|
||||
|
|
@ -655,18 +679,19 @@ AudioRegion::read_at (Sample* buf,
|
|||
* |--------------|
|
||||
* ^internal_offset
|
||||
* ^internal_offset + to_read
|
||||
*
|
||||
* we need the intersection of [internal_offset,internal_offset+to_read] with
|
||||
* [_length - fade_out_length, _length]
|
||||
*
|
||||
*/
|
||||
/* we need the intersection of
|
||||
* [internal_offset, internal_offset + to_read]
|
||||
* with
|
||||
* [_length - fade_out_length, _length]
|
||||
*/
|
||||
|
||||
fade_interval_start = max (internal_offset, lsamples - _fade_out->when(false).samples());
|
||||
samplecnt_t fade_interval_end = min(internal_offset + to_read, lsamples);
|
||||
fade_interval_start = max (internal_offset, lsamples - _fade_out->when(false).samples());
|
||||
samplecnt_t fade_interval_end = min (internal_offset + to_read, lsamples);
|
||||
|
||||
if (fade_interval_end > fade_interval_start) {
|
||||
/* (part of the) the fade out is in this buffer */
|
||||
fade_out_limit = fade_interval_end - fade_interval_start;
|
||||
fade_out_limit = fade_interval_end - fade_interval_start;
|
||||
fade_out_offset = fade_interval_start - internal_offset;
|
||||
}
|
||||
}
|
||||
|
|
@ -760,6 +785,49 @@ AudioRegion::read_at (Sample* buf,
|
|||
apply_gain_to_buffer (mixdown_buffer, n_read, _scale_amplitude);
|
||||
}
|
||||
|
||||
/* Apply Region Fades before processing. */
|
||||
|
||||
/* Fade in. Precomputed data from above may not apply here.
|
||||
* latent FX may have increasded to_read -> n_read,
|
||||
* or internal_offset.
|
||||
*/
|
||||
if (_fade_before_fx && use_region_fades && _fade_in_active) {
|
||||
samplecnt_t fade_in_length = _fade_in->when(false).samples();
|
||||
if (offset < fade_in_length) {
|
||||
samplecnt_t fade_in_limit = min (n_read, fade_in_length - offset);
|
||||
|
||||
//fade_in_limit = min (fade_in_limit, n_read);
|
||||
assert (fade_in_limit <= n_read);
|
||||
_fade_in->curve().get_vector (timepos_t (offset), timepos_t (offset + fade_in_limit), gain_buffer, fade_in_limit);
|
||||
for (samplecnt_t n = 0; n < fade_in_limit; ++n) {
|
||||
mixdown_buffer[n] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fade out. Precomputed data from above may not apply here.
|
||||
* If there are latent FX: internal_offset != offset
|
||||
*/
|
||||
if (_fade_before_fx && use_region_fades && _fade_out_active) {
|
||||
samplecnt_t fade_interval_start = max (offset, lsamples - _fade_out->when(false).samples());
|
||||
samplecnt_t fade_interval_end = min (offset + n_read, lsamples);
|
||||
|
||||
if (fade_interval_end > fade_interval_start) {
|
||||
/* (part of the) the fade out is in this buffer */
|
||||
samplecnt_t fade_out_limit = fade_interval_end - fade_interval_start;
|
||||
sampleoffset_t fade_out_offset = fade_interval_start - offset;
|
||||
|
||||
assert (fade_out_offset + fade_out_limit <= n_read);
|
||||
|
||||
/* apply fade out */
|
||||
samplecnt_t const curve_offset = fade_interval_start - _fade_out->when(false).distance (len_as_tpos ()).samples();
|
||||
_fade_out->curve().get_vector (timepos_t (curve_offset), timepos_t (curve_offset + fade_out_limit), gain_buffer, fade_out_limit);
|
||||
for (samplecnt_t n = 0, m = fade_out_offset; n < fade_out_limit; ++n, ++m) {
|
||||
mixdown_buffer[m] *= gain_buffer[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* for mono regions no cache is required, unless there are
|
||||
* regionFX, which use the _readcache BufferSet.
|
||||
*/
|
||||
|
|
@ -838,9 +906,13 @@ AudioRegion::read_at (Sample* buf,
|
|||
_fade_in->curve().get_vector (timepos_t (internal_offset), timepos_t (internal_offset + fade_in_limit), gain_buffer, fade_in_limit);
|
||||
}
|
||||
|
||||
/* Mix our newly-read data in, with the fade */
|
||||
for (samplecnt_t n = 0; n < fade_in_limit; ++n) {
|
||||
buf[n] += mixdown_buffer[n] * gain_buffer[n];
|
||||
if (!_fade_before_fx) {
|
||||
/* Mix our newly-read data in, with the fade */
|
||||
for (samplecnt_t n = 0; n < fade_in_limit; ++n) {
|
||||
buf[n] += mixdown_buffer[n] * gain_buffer[n];
|
||||
}
|
||||
} else {
|
||||
fade_in_limit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -879,11 +951,13 @@ AudioRegion::read_at (Sample* buf,
|
|||
_fade_out->curve().get_vector (timepos_t (curve_offset), timepos_t (curve_offset + fade_out_limit), gain_buffer, fade_out_limit);
|
||||
}
|
||||
|
||||
/* Mix our newly-read data with whatever was already there,
|
||||
with the fade out applied to our data.
|
||||
*/
|
||||
for (samplecnt_t n = 0, m = fade_out_offset; n < fade_out_limit; ++n, ++m) {
|
||||
buf[m] += mixdown_buffer[m] * gain_buffer[n];
|
||||
if (!_fade_before_fx) {
|
||||
/* Mix our newly-read data with whatever was already there, with the fade out applied to our data. */
|
||||
for (samplecnt_t n = 0, m = fade_out_offset; n < fade_out_limit; ++n, ++m) {
|
||||
buf[m] += mixdown_buffer[m] * gain_buffer[n];
|
||||
}
|
||||
} else {
|
||||
fade_out_limit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1692,7 +1692,9 @@ LuaBindings::common (lua_State* L)
|
|||
.addFunction ("envelope_active", &AudioRegion::envelope_active)
|
||||
.addFunction ("fade_in_active", &AudioRegion::fade_in_active)
|
||||
.addFunction ("fade_out_active", &AudioRegion::fade_out_active)
|
||||
.addFunction ("fade_before_fx", &AudioRegion::fade_before_fx)
|
||||
.addFunction ("set_envelope_active", &AudioRegion::set_envelope_active)
|
||||
.addFunction ("set_fade_before_fx", &AudioRegion::set_fade_before_fx)
|
||||
.addFunction ("set_fade_in_active", &AudioRegion::set_fade_in_active)
|
||||
.addFunction ("set_fade_in_shape", &AudioRegion::set_fade_in_shape)
|
||||
.addFunction ("set_fade_in_length", &AudioRegion::set_fade_in_length)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue