Merged with trunk R1283.
[ardour.git] / libs / ardour / audioregion.cc
index 959177d0cf611b825ea1a84809c11cabc02db320..8b533deda3922a9e4ff4214de51db53754ea05b9 100644 (file)
@@ -31,6 +31,8 @@
 
 #include <pbd/basename.h>
 #include <pbd/xml++.h>
+#include <pbd/stacktrace.h>
+#include <pbd/enumwriter.h>
 
 #include <ardour/audioregion.h>
 #include <ardour/session.h>
@@ -39,6 +41,7 @@
 #include <ardour/playlist.h>
 #include <ardour/audiofilter.h>
 #include <ardour/audiofilesource.h>
+#include <ardour/destructive_filesource.h>
 
 #include "i18n.h"
 #include <locale.h>
@@ -56,16 +59,8 @@ 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, jack_nframes_t start, jack_nframes_t length)
+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)),
          _fade_in (0.0, 2.0, 1.0, false),
          _fade_out (0.0, 2.0, 1.0, false),
@@ -81,13 +76,11 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t sta
        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) */
-AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
+AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
        : Region (src, start, length, name, DataType::AUDIO, layer, flags)
        , _fade_in (0.0, 2.0, 1.0, false)
        , _fade_out (0.0, 2.0, 1.0, false)
@@ -102,13 +95,12 @@ AudioRegion::AudioRegion (boost::shared_ptr<AudioSource> src, jack_nframes_t sta
 
        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) */
-AudioRegion::AudioRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
+AudioRegion::AudioRegion (SourceList& srcs, nframes_t start, nframes_t length, const string& name, layer_t layer, Flag flags)
        : Region (srcs, start, length, name, DataType::AUDIO, layer, flags)
        , _fade_in (0.0, 2.0, 1.0, false)
        , _fade_out (0.0, 2.0, 1.0, false)
@@ -118,14 +110,13 @@ AudioRegion::AudioRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t
 
        set_default_fades ();
        set_default_envelope ();
-       save_state ("initial state");
 
-       _envelope.StateChanged.connect (mem_fun (*this, &AudioRegion::envelope_changed));
+       listen_to_my_curves ();
 }
 
 
 /** Create a new AudioRegion, that is part of an existing one */
-AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
+AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
        : Region (other, offset, length, name, layer, flags),
          _fade_in (other->_fade_in),
          _fade_out (other->_fade_out),
@@ -158,9 +149,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, jack_nfram
 
        _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);
 }
@@ -177,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);
 }
@@ -201,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);
 }
@@ -221,98 +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 ()
 {
-       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);
-
-       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);
-       }
+       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(source());
 
-       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
@@ -327,26 +283,22 @@ AudioRegion::set_envelope_active (bool yn)
                        snprintf (buf, sizeof (buf), "envelope off");
                        _flags = Flag (_flags & ~EnvelopeActive);
                }
-               if (!_frozen) {
-                       save_state (buf);
-               }
                send_change (EnvelopeActiveChanged);
-
        }
 }
 
-jack_nframes_t
-AudioRegion::read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t offset, jack_nframes_t cnt, uint32_t chan_n, double samples_per_unit) const
+ARDOUR::nframes_t
+AudioRegion::read_peaks (PeakData *buf, nframes_t npeaks, nframes_t offset, nframes_t cnt, uint32_t chan_n, double samples_per_unit) const
 {
        if (chan_n >= _sources.size()) {
                return 0; 
        }
-       
+
        if (audio_source(chan_n)->read_peaks (buf, npeaks, offset, cnt, samples_per_unit)) {
                return 0;
        } else {
                if (_scale_amplitude != 1.0) {
-                       for (jack_nframes_t n = 0; n < npeaks; ++n) {
+                       for (nframes_t n = 0; n < npeaks; ++n) {
                                buf[n].max *= _scale_amplitude;
                                buf[n].min *= _scale_amplitude;
                        }
@@ -355,30 +307,32 @@ AudioRegion::read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t of
        }
 }
 
-jack_nframes_t
-AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t position, 
-                     jack_nframes_t cnt, 
-                     uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
+ARDOUR::nframes_t
+AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position, 
+                     nframes_t cnt, 
+                     uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
 {
        return _read_at (_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames);
 }
 
-jack_nframes_t
-AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t position, 
-                            jack_nframes_t cnt, uint32_t chan_n) const
+ARDOUR::nframes_t
+AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nframes_t position, 
+                            nframes_t cnt, uint32_t chan_n) const
 {
        return _read_at (_master_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0);
 }
 
-jack_nframes_t
+ARDOUR::nframes_t
 AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
-                      jack_nframes_t position, jack_nframes_t cnt, 
-                      uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
+                      nframes_t position, nframes_t cnt, 
+                      uint32_t chan_n, nframes_t read_frames, nframes_t skip_frames) const
 {
-       jack_nframes_t internal_offset;
-       jack_nframes_t buf_offset;
-       jack_nframes_t to_read;
-       
+       //cerr << _name << "._read_at(" << position << ") - " << _position << endl;
+
+       nframes_t internal_offset;
+       nframes_t buf_offset;
+       nframes_t to_read;
+
        /* precondition: caller has verified that we cover the desired section */
 
        if (chan_n >= _sources.size()) {
@@ -397,7 +351,6 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
        if (internal_offset >= _length) {
                return 0; /* read nothing */
        }
-       
 
        if ((to_read = min (cnt, _length - internal_offset)) == 0) {
                return 0; /* read nothing */
@@ -427,19 +380,19 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
 
        if (_flags & FadeIn) {
 
-               jack_nframes_t fade_in_length = (jack_nframes_t) _fade_in.back()->when;
+               nframes_t fade_in_length = (nframes_t) _fade_in.back()->when;
                
                /* see if this read is within the fade in */
 
                if (internal_offset < fade_in_length) {
                        
-                       jack_nframes_t limit;
+                       nframes_t limit;
 
                        limit = min (to_read, fade_in_length - internal_offset);
 
                        _fade_in.get_vector (internal_offset, internal_offset+limit, gain_buffer, limit);
 
-                       for (jack_nframes_t n = 0; n < limit; ++n) {
+                       for (nframes_t n = 0; n < limit; ++n) {
                                mixdown_buffer[n] *= gain_buffer[n];
                        }
                }
@@ -449,9 +402,6 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
 
        if (_flags & FadeOut) {
        
-
-
-       
                /* see if some part of this read is within the fade out */
 
                /* .................        >|            REGION
@@ -471,20 +421,20 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
                */
 
        
-               jack_nframes_t fade_out_length = (jack_nframes_t) _fade_out.back()->when;
-               jack_nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
-               jack_nframes_t fade_interval_end   = min(internal_offset + to_read, _length);
+               nframes_t fade_out_length = (nframes_t) _fade_out.back()->when;
+               nframes_t fade_interval_start = max(internal_offset, _length-fade_out_length);
+               nframes_t fade_interval_end   = min(internal_offset + to_read, _length);
 
                if (fade_interval_end > fade_interval_start) {
                        /* (part of the) the fade out is  in this buffer */
                        
-                       jack_nframes_t limit = fade_interval_end - fade_interval_start;
-                       jack_nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
-                       jack_nframes_t fade_offset = fade_interval_start - internal_offset;
+                       nframes_t limit = fade_interval_end - fade_interval_start;
+                       nframes_t curve_offset = fade_interval_start - (_length-fade_out_length);
+                       nframes_t fade_offset = fade_interval_start - internal_offset;
                                                                       
                        _fade_out.get_vector (curve_offset,curve_offset+limit, gain_buffer, limit);
 
-                       for (jack_nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
+                       for (nframes_t n = 0, m = fade_offset; n < limit; ++n, ++m) {
                                mixdown_buffer[m] *= gain_buffer[n];
                        }
                } 
@@ -497,11 +447,11 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
                _envelope.get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
                
                if (_scale_amplitude != 1.0f) {
-                       for (jack_nframes_t n = 0; n < to_read; ++n) {
+                       for (nframes_t n = 0; n < to_read; ++n) {
                                mixdown_buffer[n] *= gain_buffer[n] * _scale_amplitude;
                        }
                } else {
-                       for (jack_nframes_t n = 0; n < to_read; ++n) {
+                       for (nframes_t n = 0; n < to_read; ++n) {
                                mixdown_buffer[n] *= gain_buffer[n];
                        }
                }
@@ -516,7 +466,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
 
                buf += buf_offset;
 
-               for (jack_nframes_t n = 0; n < to_read; ++n) {
+               for (nframes_t n = 0; n < to_read; ++n) {
                        buf[n] += mixdown_buffer[n];
                }
        } 
@@ -533,14 +483,14 @@ 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);
 
        for (uint32_t n=0; n < _sources.size(); ++n) {
                snprintf (buf2, sizeof(buf2), "source-%d", n);
-               _sources[n]->id().print (buf);
+               _sources[n]->id().print (buf, sizeof (buf));
                node.add_property (buf2, buf);
        }
 
@@ -554,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");
@@ -573,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) {
@@ -584,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");
        }
@@ -598,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 {
@@ -632,210 +602,197 @@ 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)
 {
-       set_fade_in (shape, (jack_nframes_t) _fade_in.back()->when);
+       set_fade_in (shape, (nframes_t) _fade_in.back()->when);
 }
 
 void
 AudioRegion::set_fade_out_shape (FadeShape shape)
 {
-       set_fade_out (shape, (jack_nframes_t) _fade_out.back()->when);
+       set_fade_out (shape, (nframes_t) _fade_out.back()->when);
 }
 
 void
-AudioRegion::set_fade_in (FadeShape shape, jack_nframes_t len)
+AudioRegion::set_fade_in (FadeShape shape, nframes_t len)
 {
        _fade_in.freeze ();
        _fade_in.clear ();
 
        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);
 }
 
 void
-AudioRegion::set_fade_out (FadeShape shape, jack_nframes_t len)
+AudioRegion::set_fade_out (FadeShape shape, nframes_t len)
 {
        _fade_out.freeze ();
        _fade_out.clear ();
 
        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);
 }
 
 void
-AudioRegion::set_fade_in_length (jack_nframes_t len)
+AudioRegion::set_fade_in_length (nframes_t len)
 {
        bool changed = _fade_in.extend_to (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);
        }
 }
 
 void
-AudioRegion::set_fade_out_length (jack_nframes_t len)
+AudioRegion::set_fade_out_length (nframes_t len)
 {
        bool changed =  _fade_out.extend_to (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);
@@ -897,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 ();
 }
 
@@ -971,14 +928,15 @@ 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
 AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
 {
-       const jack_nframes_t blocksize = 4096;
-       jack_nframes_t to_read;
+       const nframes_t blocksize = 4096;
+       nframes_t to_read;
        int status = -1;
 
        spec.channels = _sources.size();
@@ -1013,7 +971,7 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
                                        goto out;
                                }
                                
-                               for (jack_nframes_t x = 0; x < to_read; ++x) {
+                               for (nframes_t x = 0; x < to_read; ++x) {
                                        spec.dataF[chan+(x*spec.channels)] = buf[x];
                                }
                        }
@@ -1041,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 */
@@ -1057,11 +1017,11 @@ AudioRegion::set_scale_amplitude (gain_t g)
 void
 AudioRegion::normalize_to (float target_dB)
 {
-       const jack_nframes_t blocksize = 64 * 1024;
+       const nframes_t blocksize = 64 * 1024;
        Sample buf[blocksize];
-       jack_nframes_t fpos;
-       jack_nframes_t fend;
-       jack_nframes_t to_read;
+       nframes_t fpos;
+       nframes_t fend;
+       nframes_t to_read;
        double maxamp = 0;
        gain_t target = dB_to_coefficient (target_dB);
 
@@ -1111,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 */
@@ -1129,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);
 }
 
@@ -1183,7 +1150,12 @@ AudioRegion::speed_mismatch (float sr) const
 void
 AudioRegion::source_offset_changed ()
 {
-       set_position (source()->natural_position() + start(), 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);
+       } 
 }
 
 boost::shared_ptr<AudioSource>
@@ -1197,7 +1169,7 @@ extern "C" {
 
        int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t cnt, intptr_t data, uint32_t n_chan, double samples_per_unit) 
 {
-       return ((AudioRegion *) arg)->read_peaks ((PeakData *) data, (jack_nframes_t) npeaks, (jack_nframes_t) start, (jack_nframes_t) cnt, n_chan,samples_per_unit);
+       return ((AudioRegion *) arg)->read_peaks ((PeakData *) data, (nframes_t) npeaks, (nframes_t) start, (nframes_t) cnt, n_chan,samples_per_unit);
 }
 
 uint32_t region_length_from_c (void *arg)