Make normalize cancel button work.
[ardour.git] / libs / ardour / audioregion.cc
index 6f349fed05b031a820ac94f52fbb23cee56b2552..be3b80de8717ddbc9aac5b92ddab09cdd0e4a263 100644 (file)
@@ -45,6 +45,7 @@
 #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>
@@ -103,12 +104,12 @@ AudioRegion::register_properties ()
        , _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
@@ -116,8 +117,10 @@ AudioRegion::init ()
 {
        register_properties ();
 
+       suspend_property_changes();
        set_default_fades ();
        set_default_envelope ();
+       resume_property_changes();
 
        listen_to_my_curves ();
        connect_to_analysis_changed ();
@@ -154,14 +157,16 @@ AudioRegion::AudioRegion (const SourceList& srcs)
        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)
 {
@@ -354,6 +359,10 @@ AudioRegion::_read_at (const SourceList& /*srcs*/, framecnt_t limit,
        framecnt_t to_read;
        bool raw = (rops == ReadOpsNone);
 
+        if (n_channels() == 0) {
+                return 0;
+        }
+
        if (muted() && !raw) {
                return 0; /* read nothing */
        }
@@ -405,7 +414,22 @@ AudioRegion::_read_at (const SourceList& /*srcs*/, framecnt_t limit,
                   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) {
@@ -501,7 +525,7 @@ AudioRegion::_read_at (const SourceList& /*srcs*/, framecnt_t limit,
                }
        }
 
-       if (!opaque()) {
+       if (!opaque() && (buf != mixdown_buffer)) {
 
                /* gack. the things we do for users.
                 */
@@ -550,6 +574,22 @@ AudioRegion::state ()
                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;
 }
 
@@ -699,12 +739,12 @@ AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
        _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);
@@ -714,7 +754,7 @@ AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
                _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);
@@ -725,7 +765,7 @@ AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
                _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);
@@ -735,7 +775,7 @@ AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
                _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);
@@ -747,6 +787,7 @@ AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
        }
 
         _fade_in->thaw ();
+       send_change (PropertyChange (Properties::fade_in));
 }
 
 void
@@ -766,7 +807,7 @@ AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
        _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);
@@ -776,7 +817,7 @@ AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
                _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);
@@ -786,7 +827,7 @@ AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
                _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);
@@ -796,7 +837,7 @@ AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
                _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);
@@ -805,13 +846,14 @@ AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
                _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
@@ -881,14 +923,14 @@ 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
@@ -919,6 +961,8 @@ AudioRegion::recompute_at_end ()
        _envelope->truncate_end (_length);
        _envelope->set_max_xval (_length);
         _envelope->thaw ();
+       
+       suspend_property_changes();
 
         if (_left_of_split) {
                 set_default_fade_out ();
@@ -932,6 +976,8 @@ AudioRegion::recompute_at_end ()
                _fade_in->extend_to (_length);
                send_change (PropertyChange (Properties::fade_in));
        }
+       
+       resume_property_changes();
 }
 
 void
@@ -940,6 +986,8 @@ AudioRegion::recompute_at_start ()
        /* as above, but the shift was from the front */
 
        _envelope->truncate_start (_length);
+       
+       suspend_property_changes();
 
         if (_right_of_split) {
                 set_default_fade_in ();
@@ -953,6 +1001,8 @@ AudioRegion::recompute_at_start ()
                _fade_out->extend_to (_length);
                send_change (PropertyChange (Properties::fade_out));
        }
+       
+       resume_property_changes();
 }
 
 int
@@ -1093,74 +1143,72 @@ AudioRegion::set_scale_amplitude (gain_t g)
        send_change (PropertyChange (Properties::scale_amplitude));
 }
 
-void
-AudioRegion::normalize_to (float target_dB)
+/** @return the maximum (linear) amplitude of the region, or a -ve
+ *  number if the Progress object reports that the process was cancelled.
+ */
+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);
+               if (p->cancelled ()) {
+                       return -1;
+               }
+       }
+
+       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 (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 (maxamp == 0.0f) {
+       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
@@ -1258,7 +1306,7 @@ AudioRegion::audio_source (uint32_t n) const
 }
 
 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;
@@ -1270,7 +1318,7 @@ AudioRegion::adjust_transients (nframes64_t 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) {
@@ -1285,7 +1333,7 @@ AudioRegion::update_transient (nframes64_t old_position, nframes64_t new_positio
 }
 
 void
-AudioRegion::add_transient (nframes64_t where)
+AudioRegion::add_transient (framepos_t where)
 {
        _transients.push_back(where);
        _valid_transients = true;
@@ -1294,7 +1342,7 @@ AudioRegion::add_transient (nframes64_t where)
 }
 
 void
-AudioRegion::remove_transient (nframes64_t where)
+AudioRegion::remove_transient (framepos_t where)
 {
        _transients.remove(where);
        _valid_transients = true;
@@ -1379,15 +1427,15 @@ AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
        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;
                 }
        }