Don't strip suffixes twice from peakfile names, otherwise source names like fred...
[ardour.git] / libs / ardour / audioregion.cc
index f1af3b6fabf9c90e6de1667a549f0838b866748e..1461e1a3a4e3888377dfbaf9e9bdf347a8707b18 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>
@@ -67,12 +68,18 @@ namespace ARDOUR {
 void
 AudioRegion::make_property_quarks ()
 {
-       Properties::envelope_active.id = g_quark_from_static_string (X_("envelope-active"));
-       Properties::default_fade_in.id = g_quark_from_static_string (X_("default-fade-in"));
-       Properties::default_fade_out.id = g_quark_from_static_string (X_("default-fade-out"));
-       Properties::fade_in_active.id = g_quark_from_static_string (X_("fade-in-active"));
-       Properties::fade_out_active.id = g_quark_from_static_string (X_("fade-out-active"));
-       Properties::scale_amplitude.id = g_quark_from_static_string (X_("scale-amplitude"));
+       Properties::envelope_active.property_id = g_quark_from_static_string (X_("envelope-active"));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for envelope-active = %1\n",    Properties::envelope_active.property_id));
+       Properties::default_fade_in.property_id = g_quark_from_static_string (X_("default-fade-in"));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for default-fade-in = %1\n",    Properties::default_fade_in.property_id));
+       Properties::default_fade_out.property_id = g_quark_from_static_string (X_("default-fade-out"));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for default-fade-out = %1\n",   Properties::default_fade_out.property_id));
+       Properties::fade_in_active.property_id = g_quark_from_static_string (X_("fade-in-active"));
+        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::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));
 }
 
 void
@@ -89,29 +96,20 @@ AudioRegion::register_properties ()
 }
 
 #define AUDIOREGION_STATE_DEFAULT \
-       _envelope_active (Properties::envelope_active, EnvelopeActiveChanged, false) \
-       , _default_fade_in (Properties::default_fade_in, FadeInChanged, true) \
-       , _default_fade_out (Properties::default_fade_out, FadeOutChanged, true) \
-       , _fade_in_active (Properties::fade_in_active, FadeInActiveChanged, true) \
-       , _fade_out_active (Properties::fade_out_active, FadeOutActiveChanged, true) \
-       , _scale_amplitude (Properties::scale_amplitude, ScaleAmplitudeChanged, 1.0)
-
+       _envelope_active (Properties::envelope_active, false) \
+       , _default_fade_in (Properties::default_fade_in, true) \
+       , _default_fade_out (Properties::default_fade_out, true) \
+       , _fade_in_active (Properties::fade_in_active, true) \
+       , _fade_out_active (Properties::fade_out_active, true) \
+       , _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) 
-
-PropertyChange AudioRegion::FadeInChanged         = PBD::new_change();
-PropertyChange AudioRegion::FadeOutChanged        = PBD::new_change();
-PropertyChange AudioRegion::FadeInActiveChanged   = PBD::new_change();
-PropertyChange AudioRegion::FadeOutActiveChanged  = PBD::new_change();
-PropertyChange AudioRegion::EnvelopeActiveChanged = PBD::new_change();
-PropertyChange AudioRegion::ScaleAmplitudeChanged = PBD::new_change();
-PropertyChange AudioRegion::EnvelopeChanged       = PBD::new_change();
-
+       _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
@@ -119,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 ();
@@ -142,26 +142,7 @@ AudioRegion::AudioRegion (Session& s, framepos_t start, framecnt_t len, std::str
        assert (_sources.size() == _master_sources.size());
 }
 
-/** Basic AudioRegion constructor (one channel) */
-AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src)
-       : Region (boost::static_pointer_cast<Source>(src))
-       , AUDIOREGION_STATE_DEFAULT
-       , _automatable(src->session())
-       , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
-       , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
-       , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
-       , _fade_in_suspended (0)
-       , _fade_out_suspended (0)
-{
-       init ();
-       
-       /* XXX why is this set here ? - set in a property list given to RegionFactory */
-       _external = true;
-
-       assert (_sources.size() == _master_sources.size());
-}
-
-/** Basic AudioRegion constructor (many channels) */
+/** Basic AudioRegion constructor */
 AudioRegion::AudioRegion (const SourceList& srcs)
        : Region (srcs)
        , AUDIOREGION_STATE_DEFAULT
@@ -176,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)
 {
@@ -219,26 +202,8 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const Sour
        assert (_sources.size() == _master_sources.size());
 }
 
-AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& node)
-       : Region (src, node)
-       , AUDIOREGION_STATE_DEFAULT
-       , _automatable(src->session())
-       , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
-       , _fade_out (new AutomationList(Evoral::Parameter(FadeOutAutomation)))
-       , _envelope (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))
-{
-       init ();
-
-       if (set_state (node, Stateful::loading_state_version)) {
-               throw failed_constructor();
-       }
-
-       assert(_type == DataType::AUDIO);
-       assert (_sources.size() == _master_sources.size());
-}
-
-AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
-       : Region (srcs, node)
+AudioRegion::AudioRegion (SourceList& srcs)
+       : Region (srcs)
        , AUDIOREGION_STATE_DEFAULT
        , _automatable(srcs[0]->session())
        , _fade_in (new AutomationList(Evoral::Parameter(FadeInAutomation)))
@@ -249,12 +214,7 @@ AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
 {
        init ();
 
-       if (set_state (node, Stateful::loading_state_version)) {
-               throw failed_constructor();
-       }
-
        assert(_type == DataType::AUDIO);
-       connect_to_analysis_changed ();
        assert (_sources.size() == _master_sources.size());
 }
 
@@ -287,6 +247,9 @@ AudioRegion::post_set ()
                set_default_fade_in ();
                _right_of_split = false;
        }
+
+       /* If _length changed, adjust our gain envelope accordingly */
+       _envelope->truncate_end (_length);
 }
 
 void
@@ -304,6 +267,9 @@ AudioRegion::connect_to_header_position_offset_changed ()
 
        for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
 
+                /* connect only once to HeaderPositionOffsetChanged, even if sources are replicated
+                 */
+
                if (unique_srcs.find (*i) == unique_srcs.end ()) {
                        unique_srcs.insert (*i);
                        boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*i);
@@ -327,7 +293,7 @@ AudioRegion::set_envelope_active (bool yn)
 {
        if (envelope_active() != yn) {
                _envelope_active = yn;
-               send_change (EnvelopeActiveChanged);
+               send_change (PropertyChange (Properties::envelope_active));
        }
 }
 
@@ -358,12 +324,6 @@ AudioRegion::read (Sample* buf, framepos_t timeline_position, framecnt_t cnt, in
        return _read_at (_sources, _length, buf, 0, 0, _position + timeline_position, cnt, channel, 0, 0, ReadOps (0));
 }
 
-framecnt_t
-AudioRegion::read_with_ops (Sample* buf, framepos_t file_position, framecnt_t cnt, int channel, ReadOps rops) const
-{
-       return _read_at (_sources, _length, buf, 0, 0, file_position, cnt, channel, 0, 0, rops);
-}
-
 framecnt_t
 AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
                      framepos_t file_position, framecnt_t cnt, uint32_t chan_n,
@@ -399,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 */
        }
@@ -450,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) {
@@ -546,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.
                 */
@@ -562,64 +541,53 @@ AudioRegion::_read_at (const SourceList& /*srcs*/, framecnt_t limit,
 }
 
 XMLNode&
-AudioRegion::state (bool full)
+AudioRegion::state ()
 {
-       XMLNode& node (Region::state (full));
+       XMLNode& node (Region::state ());
        XMLNode *child;
        char buf[64];
-       char buf2[64];
        LocaleGuard lg (X_("POSIX"));
 
-
-       // XXX these should move into Region
-
-       for (uint32_t n=0; n < _sources.size(); ++n) {
-               snprintf (buf2, sizeof(buf2), "source-%d", n);
-               _sources[n]->id().print (buf, sizeof (buf));
-               node.add_property (buf2, buf);
-       }
-
-       for (uint32_t n=0; n < _master_sources.size(); ++n) {
-               snprintf (buf2, sizeof(buf2), "master-source-%d", n);
-               _master_sources[n]->id().print (buf, sizeof (buf));
-               node.add_property (buf2, buf);
-       }
-
        snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size());
        node.add_property ("channels", buf);
 
-       if (full) {
-               Stateful::add_properties (node);
-       }
+       Stateful::add_properties (node);
 
        child = node.add_child ("Envelope");
 
-       if (full) {
-               bool default_env = false;
-
-               // If there are only two points, the points are in the start of the region and the end of the region
-               // so, if they are both at 1.0f, that means the default region.
-
-               if (_envelope->size() == 2 &&
-                   _envelope->front()->value == 1.0f &&
-                   _envelope->back()->value==1.0f) {
-                       if (_envelope->front()->when == 0 && _envelope->back()->when == _length) {
-                               default_env = true;
-                       }
+       bool default_env = false;
+       
+       // If there are only two points, the points are in the start of the region and the end of the region
+       // so, if they are both at 1.0f, that means the default region.
+       
+       if (_envelope->size() == 2 &&
+           _envelope->front()->value == 1.0f &&
+           _envelope->back()->value==1.0f) {
+               if (_envelope->front()->when == 0 && _envelope->back()->when == _length) {
+                       default_env = true;
                }
+       }
+       
+       if (default_env) {
+               child->add_property ("default", "yes");
+       } else {
+               child->add_child_nocopy (_envelope->get_state ());
+       }
 
-               if (default_env) {
-                       child->add_property ("default", "yes");
-               } else {
-                       child->add_child_nocopy (_envelope->get_state ());
-               }
+       child = node.add_child (X_("FadeIn"));
 
-       } else {
+       if (_default_fade_in) {
                child->add_property ("default", "yes");
+       } else {
+               child->add_child_nocopy (_fade_in->get_state ());
        }
 
-       if (full && _extra_xml) {
-               node.add_child_copy (*_extra_xml);
+       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;
@@ -633,7 +601,7 @@ AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_
        LocaleGuard lg (X_("POSIX"));
        boost::shared_ptr<Playlist> the_playlist (_playlist.lock());    
 
-       freeze ();
+       suspend_property_changes ();
 
        if (the_playlist) {
                the_playlist->freeze ();
@@ -650,14 +618,13 @@ AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_
                float a = atof (prop->value().c_str());
                if (a != _scale_amplitude) {
                        _scale_amplitude = a;
-                       what_changed = PropertyChange (what_changed|ScaleAmplitudeChanged);
-                       cerr << _name << " amp changed\n";
+                       what_changed.add (Properties::scale_amplitude);
                }
        }
 
        /* Now find envelope description and other related child items */
 
-       _envelope->freeze ();
+        _envelope->freeze ();
 
        for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
                XMLNode *child;
@@ -676,8 +643,6 @@ AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_
                        _envelope->set_max_xval (_length);
                        _envelope->truncate_end (_length);
 
-                       cerr << _name << " envelope changd\n";
-               
 
                } else if (child->name() == "FadeIn") {
 
@@ -699,7 +664,6 @@ AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_
                                        set_fade_in_active (false);
                                }
                        }
-                       cerr << _name << " fadein changd\n";
 
                } else if (child->name() == "FadeOut") {
 
@@ -721,16 +685,14 @@ AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_
                                        set_fade_out_active (false);
                                }
                        }
-                       cerr << _name << " fadeout changd\n";
 
                }
        }
 
-       _envelope->thaw ();
-       thaw ();
-
+        _envelope->thaw ();
+       resume_property_changes ();
+        
        if (send) {
-               cerr << _name << ": audio final change: " << hex << what_changed << dec << endl;
                send_change (what_changed);
        }
 
@@ -741,56 +703,6 @@ AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_
        return 0;
 }
 
-PropertyChange
-AudioRegion::set_property (const PropertyBase& prop)
-{
-       PropertyChange c = PropertyChange (0);
-
-       DEBUG_TRACE (DEBUG::Properties,  string_compose ("audio region %1 set property %2\n", _name.val(), prop.property_name()));
-
-       if (prop == Properties::envelope_active.id) {
-               bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
-               if (val != _envelope_active) {
-                       _envelope_active = val;
-                       c = EnvelopeActiveChanged;
-               }
-       } else if (prop == Properties::default_fade_in.id) {
-               bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
-               if (val != _default_fade_in) {
-                       _default_fade_in = val;
-                       c = FadeInChanged;
-               }
-       } else if (prop == Properties::default_fade_out.id) {
-               bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
-               if (val != _default_fade_out) {
-                       _default_fade_out = val;
-                       c = FadeOutChanged;
-               }
-       } else if (prop == Properties::fade_in_active.id) {
-               bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
-               if (val != _fade_in_active) {
-                       _fade_in_active = val;
-                       c = FadeInActiveChanged;
-               }
-       } else if (prop == Properties::fade_out_active.id) {
-               bool val = dynamic_cast<const PropertyTemplate<bool>*>(&prop)->val();
-               if (val != _fade_out_active) {
-                       _fade_out_active = val;
-                       c = FadeOutChanged;
-               }
-       } else if (prop == Properties::scale_amplitude.id) {
-               gain_t val = dynamic_cast<const PropertyTemplate<gain_t>*>(&prop)->val();
-               if (val != _scale_amplitude) {
-                       _scale_amplitude = val;
-                       c = ScaleAmplitudeChanged;
-               }
-       } else {
-               return Region::set_property (prop);
-       }
-
-       return c;
-}
-
 int
 AudioRegion::set_state (const XMLNode& node, int version)
 {
@@ -813,26 +725,26 @@ AudioRegion::set_fade_out_shape (FadeShape shape)
 void
 AudioRegion::set_fade_in (boost::shared_ptr<AutomationList> f)
 {
-       _fade_in->freeze ();
+        _fade_in->freeze ();
        *_fade_in = *f;
-       _fade_in->thaw ();
+        _fade_in->thaw ();
        
-       send_change (FadeInChanged);
+       send_change (PropertyChange (Properties::fade_in));
 }
 
 void
 AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
 {
-       _fade_in->freeze ();
+        _fade_in->freeze ();
        _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);
@@ -842,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);
@@ -853,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);
@@ -863,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);
@@ -874,27 +786,28 @@ AudioRegion::set_fade_in (FadeShape shape, framecnt_t len)
                break;
        }
 
-       _fade_in->thaw ();
+        _fade_in->thaw ();
+       send_change (PropertyChange (Properties::fade_in));
 }
 
 void
 AudioRegion::set_fade_out (boost::shared_ptr<AutomationList> f)
 {
-       _fade_out->freeze ();
+        _fade_out->freeze ();
        *_fade_out = *f;
-       _fade_out->thaw ();
+        _fade_out->thaw ();
 
-       send_change (FadeInChanged);
+       send_change (PropertyChange (Properties::fade_in));
 }
 
 void
 AudioRegion::set_fade_out (FadeShape shape, framecnt_t len)
 {
-       _fade_out->freeze ();
+        _fade_out->freeze ();
        _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);
@@ -904,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);
@@ -914,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);
@@ -924,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);
@@ -933,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 ();
+        _fade_out->thaw ();
+       send_change (PropertyChange (Properties::fade_in));
 }
 
 void
@@ -953,7 +867,7 @@ AudioRegion::set_fade_in_length (framecnt_t len)
 
        if (changed) {
                _default_fade_in = false;
-               send_change (FadeInChanged);
+               send_change (PropertyChange (Properties::fade_in));
        }
 }
 
@@ -968,7 +882,7 @@ AudioRegion::set_fade_out_length (framecnt_t len)
 
        if (changed) {
                _default_fade_out = false;
-               send_change (FadeOutChanged);
+               send_change (PropertyChange (Properties::fade_out));
        }
 }
 
@@ -980,7 +894,7 @@ AudioRegion::set_fade_in_active (bool yn)
        }
 
        _fade_in_active = yn;
-       send_change (FadeInActiveChanged);
+       send_change (PropertyChange (Properties::fade_in_active));
 }
 
 void
@@ -990,7 +904,7 @@ AudioRegion::set_fade_out_active (bool yn)
                return;
        }
        _fade_out_active = yn;
-       send_change (FadeOutActiveChanged);
+       send_change (PropertyChange (Properties::fade_out_active));
 }
 
 bool
@@ -1009,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
@@ -1029,11 +943,11 @@ AudioRegion::set_default_fades ()
 void
 AudioRegion::set_default_envelope ()
 {
-       _envelope->freeze ();
+        _envelope->freeze ();
        _envelope->clear ();
        _envelope->fast_simple_add (0, 1.0f);
        _envelope->fast_simple_add (_length, 1.0f);
-       _envelope->thaw ();
+        _envelope->thaw ();
 }
 
 void
@@ -1043,20 +957,27 @@ AudioRegion::recompute_at_end ()
           based on the the existing curve.
        */
 
-       _envelope->freeze ();
+        _envelope->freeze ();
        _envelope->truncate_end (_length);
        _envelope->set_max_xval (_length);
-       _envelope->thaw ();
-
+        _envelope->thaw ();
+       
+       suspend_property_changes();
+
+        if (_left_of_split) {
+                set_default_fade_out ();
+                _left_of_split = false;
+        } else if (_fade_out->back()->when > _length) {
+                _fade_out->extend_to (_length);
+                send_change (PropertyChange (Properties::fade_out));
+        }
+        
        if (_fade_in->back()->when > _length) {
                _fade_in->extend_to (_length);
-               send_change (FadeInChanged);
-       }
-
-       if (_fade_out->back()->when > _length) {
-               _fade_out->extend_to (_length);
-               send_change (FadeOutChanged);
+               send_change (PropertyChange (Properties::fade_in));
        }
+       
+       resume_property_changes();
 }
 
 void
@@ -1065,16 +986,23 @@ AudioRegion::recompute_at_start ()
        /* as above, but the shift was from the front */
 
        _envelope->truncate_start (_length);
+       
+       suspend_property_changes();
 
-       if (_fade_in->back()->when > _length) {
+        if (_right_of_split) {
+                set_default_fade_in ();
+                _right_of_split = false;
+        } else if (_fade_in->back()->when > _length) {
                _fade_in->extend_to (_length);
-               send_change (FadeInChanged);
+               send_change (PropertyChange (Properties::fade_in));
        }
 
        if (_fade_out->back()->when > _length) {
                _fade_out->extend_to (_length);
-               send_change (FadeOutChanged);
+               send_change (PropertyChange (Properties::fade_out));
        }
+       
+       resume_property_changes();
 }
 
 int
@@ -1212,95 +1140,88 @@ AudioRegion::set_scale_amplitude (gain_t g)
 
        /* tell everybody else */
 
-       send_change (ScaleAmplitudeChanged);
+       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;
+}
 
-       if (maxamp == 0.0f) {
+/** 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 (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 (ScaleAmplitudeChanged);
+       set_scale_amplitude (target / max_amplitude);
 }
 
 void
 AudioRegion::fade_in_changed ()
 {
-       send_change (FadeInChanged);
+       send_change (PropertyChange (Properties::fade_in));
 }
 
 void
 AudioRegion::fade_out_changed ()
 {
-       send_change (FadeOutChanged);
+       send_change (PropertyChange (Properties::fade_out));
 }
 
 void
 AudioRegion::envelope_changed ()
 {
-       send_change (EnvelopeChanged);
+       send_change (PropertyChange (Properties::envelope));
 }
 
 void
@@ -1379,6 +1300,63 @@ AudioRegion::audio_source (uint32_t n) const
        return boost::dynamic_pointer_cast<AudioSource>(source(n));
 }
 
+int 
+AudioRegion::adjust_transients (frameoffset_t delta)
+{
+       for (AnalysisFeatureList::iterator x = _transients.begin(); x != _transients.end(); ++x) {
+               (*x) = (*x) + delta;
+       }
+       
+       send_change (PropertyChange (Properties::valid_transients));
+       
+       return 0;  
+} 
+
+int
+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) {
+                       (*x) = new_position;
+                       send_change (PropertyChange (Properties::valid_transients));
+                       
+                       break;
+               }
+       }
+       
+       return 0;
+}
+
+void
+AudioRegion::add_transient (framepos_t where)
+{
+       _transients.push_back(where);
+       _valid_transients = true;
+       
+       send_change (PropertyChange (Properties::valid_transients));
+}
+
+void
+AudioRegion::remove_transient (framepos_t where)
+{
+       _transients.remove(where);
+       _valid_transients = true;
+       
+       send_change (PropertyChange (Properties::valid_transients));
+}
+
+int
+AudioRegion::set_transients (AnalysisFeatureList& results)
+{
+       _transients.clear();
+       _transients = results;
+       _valid_transients = true;
+       
+       send_change (PropertyChange (Properties::valid_transients));
+       
+       return 0;
+}
+
 int
 AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
 {
@@ -1439,14 +1417,22 @@ AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new)
 
        /* no existing/complete transient info */
 
+        static bool analyse_dialog_shown = false; /* global per instance of Ardour */
+
        if (!Config->get_auto_analyse_audio()) {
-               pl->session().Dialog (_("\
+                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 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."));
+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;
+                }
        }
 
        TransientDetector t (pl->session().frame_rate());
@@ -1510,7 +1496,7 @@ then quit ardour and restart."));
  */
 
 std::list<std::pair<frameoffset_t, framecnt_t> >
-AudioRegion::find_silence (Sample threshold, framecnt_t min_length) const
+AudioRegion::find_silence (Sample threshold, framecnt_t min_length, InterThreadInfo& itt) const
 {
        framecnt_t const block_size = 64 * 1024;
        Sample loudest[block_size];
@@ -1525,7 +1511,7 @@ AudioRegion::find_silence (Sample threshold, framecnt_t min_length) const
        frameoffset_t silence_start = 0;
        bool silence;
 
-       while (pos < end) {
+       while (pos < end && !itt.cancel) {
 
                /* fill `loudest' with the loudest absolute sample at each instant, across all channels */
                memset (loudest, 0, sizeof (Sample) * block_size);
@@ -1554,6 +1540,7 @@ AudioRegion::find_silence (Sample threshold, framecnt_t min_length) const
                }
 
                pos += block_size;
+                itt.progress = (end-pos)/(double)_length;
        }
 
        if (in_silence && end - 1 - silence_start >= min_length) {
@@ -1561,6 +1548,8 @@ AudioRegion::find_silence (Sample threshold, framecnt_t min_length) const
                silent_periods.push_back (std::make_pair (silence_start, end));
        }
 
+        itt.done = true;
+
        return silent_periods;
 }