#include "ardour/region_factory.h"
#include "ardour/runtime_functions.h"
#include "ardour/transient_detector.h"
+#include "ardour/progress.h"
#include "i18n.h"
#include <locale.h>
, _scale_amplitude (Properties::scale_amplitude, 1.0)
#define AUDIOREGION_COPY_STATE(other) \
- _envelope_active (other->_envelope_active) \
- , _default_fade_in (other->_default_fade_in) \
- , _default_fade_out (other->_default_fade_out) \
- , _fade_in_active (other->_fade_in_active) \
- , _fade_out_active (other->_fade_out_active) \
- , _scale_amplitude (other->_scale_amplitude)
+ _envelope_active (Properties::envelope_active, other->_envelope_active) \
+ , _default_fade_in (Properties::default_fade_in, other->_default_fade_in) \
+ , _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) \
+ , _scale_amplitude (Properties::scale_amplitude, other->_scale_amplitude)
/* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */
void
{
register_properties ();
+ suspend_property_changes();
set_default_fades ();
set_default_envelope ();
+ resume_property_changes();
listen_to_my_curves ();
connect_to_analysis_changed ();
assert (_sources.size() == _master_sources.size());
}
-AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes64_t offset, bool offset_relative)
+AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, framecnt_t offset, bool offset_relative)
: Region (other, offset, offset_relative)
, AUDIOREGION_COPY_STATE (other)
, _automatable (other->session())
, _fade_in (new AutomationList (*other->_fade_in))
, _fade_out (new AutomationList (*other->_fade_out))
- /* XXX is this guaranteed to work for all values of offset+offset_relative? */
- , _envelope (new AutomationList (*other->_envelope, _start, _start + _length))
+ /* As far as I can see, the _envelope's times are relative to region position, and have nothing
+ to do with sources (and hence _start). So when we copy the envelope, we just use the supplied offset.
+ */
+ , _envelope (new AutomationList (*other->_envelope, offset, other->_length))
, _fade_in_suspended (0)
, _fade_out_suspended (0)
{
framecnt_t to_read;
bool raw = (rops == ReadOpsNone);
+ if (n_channels() == 0) {
+ return 0;
+ }
+
if (muted() && !raw) {
return 0; /* read nothing */
}
we don't have.
*/
- memset (mixdown_buffer, 0, sizeof (Sample) * cnt);
+ 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 = audio_source (channel);
+
+ if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) {
+ return 0; /* "read nothing" */
+ }
+
+ /* adjust read data count appropriately since this was a duplicate read */
+ src->dec_read_data_count (to_read);
+ } else {
+ memset (mixdown_buffer, 0, sizeof (Sample) * cnt);
+ }
}
if (rops & ReadOpsFades) {
}
}
- if (!opaque()) {
+ if (!opaque() && (buf != mixdown_buffer)) {
/* gack. the things we do for users.
*/
child->add_child_nocopy (_envelope->get_state ());
}
+ child = node.add_child (X_("FadeIn"));
+
+ if (_default_fade_in) {
+ child->add_property ("default", "yes");
+ } else {
+ child->add_child_nocopy (_fade_in->get_state ());
+ }
+
+ child = node.add_child (X_("FadeOut"));
+
+ if (_default_fade_out) {
+ child->add_property ("default", "yes");
+ } else {
+ child->add_child_nocopy (_fade_out->get_state ());
+ }
+
return node;
}
_fade_in->clear ();
switch (shape) {
- case Linear:
+ case FadeLinear:
_fade_in->fast_simple_add (0.0, 0.0);
_fade_in->fast_simple_add (len, 1.0);
break;
- case Fast:
+ case FadeFast:
_fade_in->fast_simple_add (0, 0);
_fade_in->fast_simple_add (len * 0.389401, 0.0333333);
_fade_in->fast_simple_add (len * 0.629032, 0.0861111);
_fade_in->fast_simple_add (len, 1);
break;
- case Slow:
+ case FadeSlow:
_fade_in->fast_simple_add (0, 0);
_fade_in->fast_simple_add (len * 0.0207373, 0.197222);
_fade_in->fast_simple_add (len * 0.0645161, 0.525);
_fade_in->fast_simple_add (len, 1);
break;
- case LogA:
+ case FadeLogA:
_fade_in->fast_simple_add (0, 0);
_fade_in->fast_simple_add (len * 0.0737327, 0.308333);
_fade_in->fast_simple_add (len * 0.246544, 0.658333);
_fade_in->fast_simple_add (len, 1);
break;
- case LogB:
+ case FadeLogB:
_fade_in->fast_simple_add (0, 0);
_fade_in->fast_simple_add (len * 0.304147, 0.0694444);
_fade_in->fast_simple_add (len * 0.529954, 0.152778);
}
_fade_in->thaw ();
+ send_change (PropertyChange (Properties::fade_in));
}
void
_fade_out->clear ();
switch (shape) {
- case Fast:
+ case FadeFast:
_fade_out->fast_simple_add (len * 0, 1);
_fade_out->fast_simple_add (len * 0.023041, 0.697222);
_fade_out->fast_simple_add (len * 0.0553, 0.483333);
_fade_out->fast_simple_add (len * 1, 0);
break;
- case LogA:
+ case FadeLogA:
_fade_out->fast_simple_add (len * 0, 1);
_fade_out->fast_simple_add (len * 0.228111, 0.988889);
_fade_out->fast_simple_add (len * 0.347926, 0.972222);
_fade_out->fast_simple_add (len * 1, 0);
break;
- case Slow:
+ case FadeSlow:
_fade_out->fast_simple_add (len * 0, 1);
_fade_out->fast_simple_add (len * 0.305556, 1);
_fade_out->fast_simple_add (len * 0.548611, 0.991736);
_fade_out->fast_simple_add (len * 1, 0);
break;
- case LogB:
+ case FadeLogB:
_fade_out->fast_simple_add (len * 0, 1);
_fade_out->fast_simple_add (len * 0.080645, 0.730556);
_fade_out->fast_simple_add (len * 0.277778, 0.289256);
_fade_out->fast_simple_add (len * 1, 0);
break;
- case Linear:
+ case FadeLinear:
_fade_out->fast_simple_add (len * 0, 1);
_fade_out->fast_simple_add (len * 1, 0);
break;
}
_fade_out->thaw ();
+ send_change (PropertyChange (Properties::fade_in));
}
void
AudioRegion::set_default_fade_in ()
{
_fade_in_suspended = 0;
- set_fade_in (Linear, 64);
+ set_fade_in (FadeLinear, 64);
}
void
AudioRegion::set_default_fade_out ()
{
_fade_out_suspended = 0;
- set_fade_out (Linear, 64);
+ set_fade_out (FadeLinear, 64);
}
void
_envelope->truncate_end (_length);
_envelope->set_max_xval (_length);
_envelope->thaw ();
+
+ suspend_property_changes();
if (_left_of_split) {
set_default_fade_out ();
_fade_in->extend_to (_length);
send_change (PropertyChange (Properties::fade_in));
}
+
+ resume_property_changes();
}
void
/* as above, but the shift was from the front */
_envelope->truncate_start (_length);
+
+ suspend_property_changes();
if (_right_of_split) {
set_default_fade_in ();
_fade_out->extend_to (_length);
send_change (PropertyChange (Properties::fade_out));
}
+
+ resume_property_changes();
}
int
send_change (PropertyChange (Properties::scale_amplitude));
}
-void
-AudioRegion::normalize_to (float target_dB)
+/** @return the maximum (linear) amplitude of the region */
+double
+AudioRegion::maximum_amplitude (Progress* p) const
{
- const framecnt_t blocksize = 64 * 1024;
- Sample buf[blocksize];
- framepos_t fpos;
- framepos_t fend;
- framecnt_t to_read;
+ framepos_t fpos = _start;
+ framepos_t const fend = _start + _length;
double maxamp = 0;
- gain_t target = dB_to_coefficient (target_dB);
-
- if (target == 1.0f) {
- /* do not normalize to precisely 1.0 (0 dBFS), to avoid making it appear
- that we may have clipped.
- */
- target -= FLT_EPSILON;
- }
-
- fpos = _start;
- fend = _start + _length;
-
- /* first pass: find max amplitude */
+ framecnt_t const blocksize = 64 * 1024;
+ Sample buf[blocksize];
+
while (fpos < fend) {
uint32_t n;
- to_read = min (fend - fpos, blocksize);
+ framecnt_t const to_read = min (fend - fpos, blocksize);
for (n = 0; n < n_channels(); ++n) {
/* read it in */
if (read_raw_internal (buf, fpos, to_read, 0) != to_read) {
- return;
+ return 0;
}
maxamp = compute_peak (buf, to_read, maxamp);
}
fpos += to_read;
- };
+ p->set_progress (float (fpos - _start) / _length);
+ }
+
+ return maxamp;
+}
+
+/** Normalize using a given maximum amplitude and target, so that region
+ * _scale_amplitude becomes target / max_amplitude.
+ */
+void
+AudioRegion::normalize (float max_amplitude, float target_dB)
+{
+ gain_t target = dB_to_coefficient (target_dB);
- if (maxamp == 0.0f) {
+ if (target == 1.0f) {
+ /* do not normalize to precisely 1.0 (0 dBFS), to avoid making it appear
+ that we may have clipped.
+ */
+ target -= FLT_EPSILON;
+ }
+
+ if (max_amplitude == 0.0f) {
/* don't even try */
return;
}
- if (maxamp == target) {
+ if (max_amplitude == target) {
/* we can't do anything useful */
return;
}
- /* compute scale factor */
-
- _scale_amplitude = target/maxamp;
-
- /* tell the diskstream we're in */
-
- boost::shared_ptr<Playlist> pl (playlist());
-
- if (pl) {
- pl->ContentsChanged();
- }
-
- /* tell everybody else */
-
- send_change (PropertyChange (Properties::scale_amplitude));
+ set_scale_amplitude (target / max_amplitude);
}
void
}
int
-AudioRegion::adjust_transients (nframes64_t delta)
+AudioRegion::adjust_transients (frameoffset_t delta)
{
for (AnalysisFeatureList::iterator x = _transients.begin(); x != _transients.end(); ++x) {
(*x) = (*x) + delta;
}
int
-AudioRegion::update_transient (nframes64_t old_position, nframes64_t new_position)
+AudioRegion::update_transient (framepos_t old_position, framepos_t new_position)
{
for (AnalysisFeatureList::iterator x = _transients.begin(); x != _transients.end(); ++x) {
if ((*x) == old_position) {
}
void
-AudioRegion::add_transient (nframes64_t where)
+AudioRegion::add_transient (framepos_t where)
{
_transients.push_back(where);
_valid_transients = true;
}
void
-AudioRegion::remove_transient (nframes64_t where)
+AudioRegion::remove_transient (framepos_t where)
{
_transients.remove(where);
_valid_transients = true;
if (!Config->get_auto_analyse_audio()) {
if (!analyse_dialog_shown) {
pl->session().Dialog (_("\
-You have requested an operation that requires audio analysis.\n\n \
-You currently have \"auto-analyse-audio\" disabled, which means\n\
+You have requested an operation that requires audio analysis.\n\n\
+You currently have \"auto-analyse-audio\" disabled, which means \
that transient data must be generated every time it is required.\n\n\
-If you are doing work that will require transient data on a\n\
-regular basis, you should probably enable \"auto-analyse-audio\"\n\
-+then quit ardour and restart.\n\n\
-+This dialog will not display again. But you may notice a slight delay\n\
-+in this and future transient-detection operations.\n\
-+"));
+If you are doing work that will require transient data on a \
+regular basis, you should probably enable \"auto-analyse-audio\" \
+then quit ardour and restart.\n\n\
+This dialog will not display again. But you may notice a slight delay \
+in this and future transient-detection operations.\n\
+"));
analyse_dialog_shown = true;
}
}