Merged with trunk R1283.
[ardour.git] / libs / ardour / audioregion.cc
index d7724f3a3911298d47912f29a50316ff7c64c83a..8b533deda3922a9e4ff4214de51db53754ea05b9 100644 (file)
@@ -32,6 +32,7 @@
 #include <pbd/basename.h>
 #include <pbd/xml++.h>
 #include <pbd/stacktrace.h>
+#include <pbd/enumwriter.h>
 
 #include <ardour/audioregion.h>
 #include <ardour/session.h>
@@ -58,14 +59,6 @@ Change AudioRegion::EnvelopeActiveChanged = ARDOUR::new_change();
 Change AudioRegion::ScaleAmplitudeChanged = ARDOUR::new_change();
 Change AudioRegion::EnvelopeChanged       = ARDOUR::new_change();
 
-AudioRegionState::AudioRegionState (string why)
-       : RegionState (why)
-       , _fade_in (0.0, 2.0, 1.0, false)
-       , _fade_out (0.0, 2.0, 1.0, false)
-       , _envelope (0.0, 2.0, 1.0, false)
-{
-}
-
 /** Basic AudioRegion constructor (one channel) */
 AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length)
        : Region (src, start, length, PBD::basename_nosuffix(src->name()), DataType::AUDIO, 0,  Region::Flag(Region::DefaultFlags|Region::External)),
@@ -83,9 +76,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
        set_default_fades ();
        set_default_envelope ();
 
-       save_state ("initial state");
-
-       _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+       listen_to_my_curves ();
 }
 
 /* Basic AudioRegion constructor (one channel) */
@@ -104,9 +95,8 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, n
 
        set_default_fades ();
        set_default_envelope ();
-       save_state ("initial state");
 
-       _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+       listen_to_my_curves ();
 }
 
 /* Basic AudioRegion constructor (many channels) */
@@ -120,9 +110,8 @@ AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, c
 
        set_default_fades ();
        set_default_envelope ();
-       save_state ("initial state");
 
-       _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+       listen_to_my_curves ();
 }
 
 
@@ -160,9 +149,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t
 
        _scale_amplitude = other->_scale_amplitude;
 
-       save_state ("initial state");
-
-       _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+       listen_to_my_curves ();
        
        assert(_type == DataType::AUDIO);
 }
@@ -179,9 +166,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
        _fade_in_disabled = 0;
        _fade_out_disabled = 0;
        
-       save_state ("initial state");
-
-       _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+       listen_to_my_curves ();
 
        assert(_type == DataType::AUDIO);
 }
@@ -203,9 +188,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, const XMLNode& nod
                throw failed_constructor();
        }
 
-       save_state ("initial state");
-
-       _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+       listen_to_my_curves ();
 
        assert(_type == DataType::AUDIO);
 }
@@ -223,99 +206,69 @@ AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
                throw failed_constructor();
        }
 
-       save_state ("initial state");
-
-       _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+       listen_to_my_curves ();
 
        assert(_type == DataType::AUDIO);
 }
 
 AudioRegion::~AudioRegion ()
 {
-       notify_callbacks ();
-       GoingAway (); /* EMIT SIGNAL */
 }
 
-StateManager::State*
-AudioRegion::state_factory (std::string why) const
+void
+AudioRegion::listen_to_my_curves ()
 {
-       AudioRegionState* state = new AudioRegionState (why);
-
-       Region::store_state (*state);
-
-       state->_fade_in = _fade_in;
-       state->_fade_out = _fade_out;
-       state->_envelope = _envelope;
-       state->_scale_amplitude = _scale_amplitude;
-       state->_fade_in_disabled = _fade_in_disabled;
-       state->_fade_out_disabled = _fade_out_disabled;
-
-       return state;
-}      
+       _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+       _fade_in.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_in_changed));
+       _fade_out.StateChanged.connect (mem_fun (*this, &AudioRegion::fade_out_changed));
+}
 
-Change
-AudioRegion::restore_state (StateManager::State& sstate) 
+bool
+AudioRegion::verify_length (nframes_t len)
 {
-       AudioRegionState* state = dynamic_cast<AudioRegionState*> (&sstate);
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
 
-       Change what_changed = Region::restore_and_return_flags (*state);
-       
-       if (_flags != Flag (state->_flags)) {
-               
-               uint32_t old_flags = _flags;
-               
-               _flags = Flag (state->_flags);
-               
-               if ((old_flags ^ state->_flags) & EnvelopeActive) {
-                       what_changed = Change (what_changed|EnvelopeActiveChanged);
-               }
-       }
-               
-       if (!(_fade_in == state->_fade_in)) {
-               _fade_in = state->_fade_in;
-               what_changed = Change (what_changed|FadeInChanged);
-       }
-
-       if (!(_fade_out == state->_fade_out)) {
-               _fade_out = state->_fade_out;
-               what_changed = Change (what_changed|FadeOutChanged);
+       if (afs && afs->destructive()) {
+               return true;
+       } else {
+               return Region::verify_length(len);
        }
+}
 
-       if (_scale_amplitude != state->_scale_amplitude) {
-               _scale_amplitude = state->_scale_amplitude;
-               what_changed = Change (what_changed|ScaleAmplitudeChanged);
-       }
+bool
+AudioRegion::verify_start_and_length (nframes_t new_start, nframes_t new_length)
+{
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
 
-       if (_fade_in_disabled != state->_fade_in_disabled) {
-               if (_fade_in_disabled == 0 && state->_fade_in_disabled) {
-                       set_fade_in_active (false);
-               } else if (_fade_in_disabled && state->_fade_in_disabled == 0) {
-                       set_fade_in_active (true);
-               }
-               _fade_in_disabled = state->_fade_in_disabled;
-       }
-               
-       if (_fade_out_disabled != state->_fade_out_disabled) {
-               if (_fade_out_disabled == 0 && state->_fade_out_disabled) {
-                       set_fade_out_active (false);
-               } else if (_fade_out_disabled && state->_fade_out_disabled == 0) {
-                       set_fade_out_active (true);
-               }
-               _fade_out_disabled = state->_fade_out_disabled;
+       if (afs && afs->destructive()) {
+               return true;
+       } else {
+               return verify_start_and_length(new_start, new_length);
        }
+}
 
-       /* XXX need a way to test stored state versus current for envelopes */
-
-       _envelope = state->_envelope;
-       what_changed = Change (what_changed);
+bool
+AudioRegion::verify_start (nframes_t pos)
+{
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
 
-       return what_changed;
+       if (afs && afs->destructive()) {
+               return true;
+       } else {
+               return verify_start(pos);
+       }
 }
 
-UndoAction
-AudioRegion::get_memento() const
+bool
+AudioRegion::verify_start_mutable (nframes_t& new_start)
 {
-       return sigc::bind (mem_fun (*(const_cast<AudioRegion *> (this)), &StateManager::use_state), _current_state_id);
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
+
+       if (afs && afs->destructive()) {
+               return true;
+       } else {
+               return verify_start_mutable(new_start);
+       }
 }
 
 void
@@ -330,11 +283,7 @@ AudioRegion::set_envelope_active (bool yn)
                        snprintf (buf, sizeof (buf), "envelope off");
                        _flags = Flag (_flags & ~EnvelopeActive);
                }
-               if (!_frozen) {
-                       save_state (buf);
-               }
                send_change (EnvelopeActiveChanged);
-
        }
 }
 
@@ -344,7 +293,7 @@ AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nfra
        if (chan_n >= _sources.size()) {
                return 0; 
        }
-       
+
        if (audio_source(chan_n)->read_peaks (buf, npeaks, offset, cnt, samples_per_unit)) {
                return 0;
        } else {
@@ -378,6 +327,8 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
                       nframes_t position, nframes_t cnt, 
                       uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
 {
+       //cerr << _name << "._read_at(" << position << ") - " << _position << endl;
+
        nframes_t internal_offset;
        nframes_t buf_offset;
        nframes_t to_read;
@@ -532,8 +483,8 @@ AudioRegion::state (bool full)
        char buf2[64];
        LocaleGuard lg (X_("POSIX"));
        
-       snprintf (buf, sizeof (buf), "0x%x", (int) _flags);
-       node.add_property ("flags", buf);
+       node.add_property ("flags", enum_2_string (_flags));
+
        snprintf (buf, sizeof(buf), "%.12g", _scale_amplitude);
        node.add_property ("scale-gain", buf);
 
@@ -553,16 +504,20 @@ AudioRegion::state (bool full)
                if ((_flags & DefaultFadeIn)) {
                        child->add_property (X_("default"), X_("yes"));
                } else {
-                       _fade_in.store_state (*child);
+                       child->add_child_nocopy (_fade_in.get_state ());
                }
+
+               child->add_property (X_("active"), _fade_in_disabled ? X_("no") : X_("yes"));
                
                child = node.add_child (X_("FadeOut"));
                
                if ((_flags & DefaultFadeOut)) {
                        child->add_property (X_("default"), X_("yes"));
                } else {
-                       _fade_out.store_state (*child);
+                       child->add_child_nocopy (_fade_out.get_state ());
                }
+               
+               child->add_property (X_("active"), _fade_out_disabled ? X_("no") : X_("yes"));
        }
        
        child = node.add_child ("Envelope");
@@ -572,6 +527,7 @@ AudioRegion::state (bool full)
                
                // 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) {
@@ -583,8 +539,9 @@ AudioRegion::state (bool full)
                if (default_env) {
                        child->add_property ("default", "yes");
                } else {
-                       _envelope.store_state (*child);
+                       child->add_child_nocopy (_envelope.get_state ());
                }
+
        } else {
                child->add_property ("default", "yes");
        }
@@ -597,21 +554,35 @@ AudioRegion::state (bool full)
 }
 
 int
-AudioRegion::set_state (const XMLNode& node)
+AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool send)
 {
        const XMLNodeList& nlist = node.children();
        const XMLProperty *prop;
        LocaleGuard lg (X_("POSIX"));
 
-       Region::set_state (node);
+       Region::set_live_state (node, what_changed, false);
 
+       uint32_t old_flags = _flags;
+               
        if ((prop = node.property ("flags")) != 0) {
-               _flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
+               _flags = Flag (string_2_enum (prop->value(), _flags));
+
+               //_flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
 
                _flags = Flag (_flags & ~Region::LeftOfSplit);
                _flags = Flag (_flags & ~Region::RightOfSplit);
        }
 
+       if ((old_flags ^ _flags) & Muted) {
+               what_changed = Change (what_changed|MuteChanged);
+       }
+       if ((old_flags ^ _flags) & Opaque) {
+               what_changed = Change (what_changed|OpacityChanged);
+       }
+       if ((old_flags ^ _flags) & Locked) {
+               what_changed = Change (what_changed|LockChanged);
+       }
+
        if ((prop = node.property ("scale-gain")) != 0) {
                _scale_amplitude = atof (prop->value().c_str());
        } else {
@@ -631,41 +602,49 @@ AudioRegion::set_state (const XMLNode& node)
                        
                        _envelope.clear ();
 
-                       if ((prop = child->property ("default")) != 0) {
+                       if ((prop = child->property ("default")) != 0 || _envelope.set_state (*child)) {
                                set_default_envelope ();
-                       } else {
-                               _envelope.load_state (*child);
                        }
 
                        _envelope.set_max_xval (_length);
                        _envelope.truncate_end (_length);
-                       
+
                } else if (child->name() == "FadeIn") {
                        
                        _fade_in.clear ();
                        
-                       if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) {
+                       if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_in.set_state (*child)) {
                                set_default_fade_in ();
-                       } else {
-                               
-                               _fade_in.load_state (*child);
-                       }
+                       } 
 
                } else if (child->name() == "FadeOut") {
                        
                        _fade_out.clear ();
 
-                       if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) {
+                       if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0 || _fade_out.set_state (*child)) {
                                set_default_fade_out ();
-                       } else {
-                               _fade_out.load_state (*child);
-                       }
+                       } 
                } 
        }
 
+       if (send) {
+               send_change (what_changed);
+       }
+
        return 0;
 }
 
+int
+AudioRegion::set_state (const XMLNode& node)
+{
+       /* Region::set_state() calls the virtual set_live_state(),
+          which will get us back to AudioRegion::set_live_state()
+          to handle the relevant stuff.
+       */
+
+       return Region::set_state (node);
+}
+
 void
 AudioRegion::set_fade_in_shape (FadeShape shape)
 {
@@ -686,59 +665,55 @@ AudioRegion::set_fade_in (FadeShape shape, nframes_t len)
 
        switch (shape) {
        case Linear:
-               _fade_in.add (0.0, 0.0);
-               _fade_in.add (len, 1.0);
+               _fade_in.fast_simple_add (0.0, 0.0);
+               _fade_in.fast_simple_add (len, 1.0);
                break;
 
        case Fast:
-               _fade_in.add (0, 0);
-               _fade_in.add (len * 0.389401, 0.0333333);
-               _fade_in.add (len * 0.629032, 0.0861111);
-               _fade_in.add (len * 0.829493, 0.233333);
-               _fade_in.add (len * 0.9447, 0.483333);
-               _fade_in.add (len * 0.976959, 0.697222);
-               _fade_in.add (len, 1);
+               _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 * 0.829493, 0.233333);
+               _fade_in.fast_simple_add (len * 0.9447, 0.483333);
+               _fade_in.fast_simple_add (len * 0.976959, 0.697222);
+               _fade_in.fast_simple_add (len, 1);
                break;
 
        case Slow:
-               _fade_in.add (0, 0);
-               _fade_in.add (len * 0.0207373, 0.197222);
-               _fade_in.add (len * 0.0645161, 0.525);
-               _fade_in.add (len * 0.152074, 0.802778);
-               _fade_in.add (len * 0.276498, 0.919444);
-               _fade_in.add (len * 0.481567, 0.980556);
-               _fade_in.add (len * 0.767281, 1);
-               _fade_in.add (len, 1);
+               _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 * 0.152074, 0.802778);
+               _fade_in.fast_simple_add (len * 0.276498, 0.919444);
+               _fade_in.fast_simple_add (len * 0.481567, 0.980556);
+               _fade_in.fast_simple_add (len * 0.767281, 1);
+               _fade_in.fast_simple_add (len, 1);
                break;
 
        case LogA:
-               _fade_in.add (0, 0);
-               _fade_in.add (len * 0.0737327, 0.308333);
-               _fade_in.add (len * 0.246544, 0.658333);
-               _fade_in.add (len * 0.470046, 0.886111);
-               _fade_in.add (len * 0.652074, 0.972222);
-               _fade_in.add (len * 0.771889, 0.988889);
-               _fade_in.add (len, 1);
+               _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 * 0.470046, 0.886111);
+               _fade_in.fast_simple_add (len * 0.652074, 0.972222);
+               _fade_in.fast_simple_add (len * 0.771889, 0.988889);
+               _fade_in.fast_simple_add (len, 1);
                break;
 
        case LogB:
-               _fade_in.add (0, 0);
-               _fade_in.add (len * 0.304147, 0.0694444);
-               _fade_in.add (len * 0.529954, 0.152778);
-               _fade_in.add (len * 0.725806, 0.333333);
-               _fade_in.add (len * 0.847926, 0.558333);
-               _fade_in.add (len * 0.919355, 0.730556);
-               _fade_in.add (len, 1);
+               _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.fast_simple_add (len * 0.725806, 0.333333);
+               _fade_in.fast_simple_add (len * 0.847926, 0.558333);
+               _fade_in.fast_simple_add (len * 0.919355, 0.730556);
+               _fade_in.fast_simple_add (len, 1);
                break;
        }
 
        _fade_in.thaw ();
        _fade_in_shape = shape;
 
-       if (!_frozen) {
-               save_state (_("fade in change"));
-       }
-
        send_change (FadeInChanged);
 }
 
@@ -750,57 +725,53 @@ AudioRegion::set_fade_out (FadeShape shape, nframes_t len)
 
        switch (shape) {
        case Fast:
-               _fade_out.add (len * 0, 1);
-               _fade_out.add (len * 0.023041, 0.697222);
-               _fade_out.add (len * 0.0553,   0.483333);
-               _fade_out.add (len * 0.170507, 0.233333);
-               _fade_out.add (len * 0.370968, 0.0861111);
-               _fade_out.add (len * 0.610599, 0.0333333);
-               _fade_out.add (len * 1, 0);
+               _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 * 0.170507, 0.233333);
+               _fade_out.fast_simple_add (len * 0.370968, 0.0861111);
+               _fade_out.fast_simple_add (len * 0.610599, 0.0333333);
+               _fade_out.fast_simple_add (len * 1, 0);
                break;
 
        case LogA:
-               _fade_out.add (len * 0, 1);
-               _fade_out.add (len * 0.228111, 0.988889);
-               _fade_out.add (len * 0.347926, 0.972222);
-               _fade_out.add (len * 0.529954, 0.886111);
-               _fade_out.add (len * 0.753456, 0.658333);
-               _fade_out.add (len * 0.9262673, 0.308333);
-               _fade_out.add (len * 1, 0);
+               _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 * 0.529954, 0.886111);
+               _fade_out.fast_simple_add (len * 0.753456, 0.658333);
+               _fade_out.fast_simple_add (len * 0.9262673, 0.308333);
+               _fade_out.fast_simple_add (len * 1, 0);
                break;
 
        case Slow:
-               _fade_out.add (len * 0, 1);
-               _fade_out.add (len * 0.305556, 1);
-               _fade_out.add (len * 0.548611, 0.991736);
-               _fade_out.add (len * 0.759259, 0.931129);
-               _fade_out.add (len * 0.918981, 0.68595);
-               _fade_out.add (len * 0.976852, 0.22865);
-               _fade_out.add (len * 1, 0);
+               _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 * 0.759259, 0.931129);
+               _fade_out.fast_simple_add (len * 0.918981, 0.68595);
+               _fade_out.fast_simple_add (len * 0.976852, 0.22865);
+               _fade_out.fast_simple_add (len * 1, 0);
                break;
 
        case LogB:
-               _fade_out.add (len * 0, 1);
-               _fade_out.add (len * 0.080645, 0.730556);
-               _fade_out.add (len * 0.277778, 0.289256);
-               _fade_out.add (len * 0.470046, 0.152778);
-               _fade_out.add (len * 0.695853, 0.0694444);
-               _fade_out.add (len * 1, 0);
+               _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 * 0.470046, 0.152778);
+               _fade_out.fast_simple_add (len * 0.695853, 0.0694444);
+               _fade_out.fast_simple_add (len * 1, 0);
                break;
 
        case Linear:
-               _fade_out.add (len * 0, 1);
-               _fade_out.add (len * 1, 0);
+               _fade_out.fast_simple_add (len * 0, 1);
+               _fade_out.fast_simple_add (len * 1, 0);
                break;
        }
 
        _fade_out.thaw ();
        _fade_out_shape = shape;
 
-       if (!_frozen) {
-               save_state (_("fade in change"));
-       }
-
        send_change (FadeOutChanged);
 }
 
@@ -811,13 +782,6 @@ AudioRegion::set_fade_in_length (nframes_t len)
 
        if (changed) {
                _flags = Flag (_flags & ~DefaultFadeIn);
-
-               if (!_frozen) {
-                       char buf[64];
-                       snprintf (buf, sizeof (buf), "fade in length changed to %u", len);
-                       save_state (buf);
-               }
-               
                send_change (FadeInChanged);
        }
 }
@@ -829,12 +793,6 @@ AudioRegion::set_fade_out_length (nframes_t len)
 
        if (changed) {
                _flags = Flag (_flags & ~DefaultFadeOut);
-               
-               if (!_frozen) {
-                       char buf[64];
-                       snprintf (buf, sizeof (buf), "fade out length changed to %u", len);
-                       save_state (buf);
-               }
        }
 
        send_change (FadeOutChanged);
@@ -896,8 +854,8 @@ AudioRegion::set_default_envelope ()
 {
        _envelope.freeze ();
        _envelope.clear ();
-       _envelope.add (0, 1.0f);
-       _envelope.add (_length, 1.0f);
+       _envelope.fast_simple_add (0, 1.0f);
+       _envelope.fast_simple_add (_length, 1.0f);
        _envelope.thaw ();
 }
 
@@ -970,7 +928,8 @@ AudioRegion::separate_by_channel (Session& session, vector<AudioRegion*>& v) con
 int
 AudioRegion::apply (AudioFilter& filter)
 {
-       return filter.run (boost::shared_ptr<AudioRegion> (this));
+       boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (shared_from_this());
+       return filter.run (ar);
 }
 
 int
@@ -1040,12 +999,14 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
 void
 AudioRegion::set_scale_amplitude (gain_t g)
 {
+       boost::shared_ptr<Playlist> pl (playlist());
+
        _scale_amplitude = g;
 
        /* tell the diskstream we're in */
-
-       if (_playlist) {
-               _playlist->Modified();
+       
+       if (pl) {
+               pl->Modified();
        }
 
        /* tell everybody else */
@@ -1110,16 +1071,12 @@ AudioRegion::normalize_to (float target_dB)
 
        _scale_amplitude = target/maxamp;
 
-       if (!_frozen) {
-               char buf[64];
-               snprintf (buf, sizeof (buf), _("normalized to %.2fdB"), target_dB);
-               save_state (buf);
-       }
-
        /* tell the diskstream we're in */
 
-       if (_playlist) {
-               _playlist->Modified();
+       boost::shared_ptr<Playlist> pl (playlist());
+
+       if (pl) {
+               pl->Modified();
        }
 
        /* tell everybody else */
@@ -1128,9 +1085,20 @@ AudioRegion::normalize_to (float target_dB)
 }
 
 void
-AudioRegion::envelope_changed (Change ignored)
+AudioRegion::fade_in_changed ()
+{
+       send_change (FadeInChanged);
+}
+
+void
+AudioRegion::fade_out_changed ()
+{
+       send_change (FadeOutChanged);
+}
+
+void
+AudioRegion::envelope_changed ()
 {
-       save_state (_("envelope change"));
        send_change (EnvelopeChanged);
 }
 
@@ -1182,8 +1150,10 @@ AudioRegion::speed_mismatch (float sr) const
 void
 AudioRegion::source_offset_changed ()
 {
-       if (boost::dynamic_pointer_cast<DestructiveFileSource>(_sources.front())) {
-               set_start (source()->natural_position(), this);
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(_sources.front());
+
+       if (afs && afs->destructive()) {
+               // set_start (source()->natural_position(), this);
                set_position (source()->natural_position(), this);
        } 
 }