more MTC debugging
[ardour.git] / libs / ardour / region.cc
index 19f26966a70e95bbe39f7caecc058be501a37f80..1f4d6f0f912221d78d3fc4739ea8840a82d13af4 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2000-2003 Paul Davis 
+    Copyright (C) 2000-2003 Paul Davis
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #include <algorithm>
 #include <sstream>
 
-#include <sigc++/bind.h>
-#include <sigc++/class_slot.h>
 
 #include <glibmm/thread.h>
 #include "pbd/xml++.h"
 #include "pbd/stacktrace.h"
 #include "pbd/enumwriter.h"
 
+#include "ardour/debug.h"
 #include "ardour/region.h"
 #include "ardour/playlist.h"
 #include "ardour/session.h"
@@ -55,17 +54,17 @@ Change Region::LockChanged       = ARDOUR::new_change ();
 Change Region::LayerChanged      = ARDOUR::new_change ();
 Change Region::HiddenChanged     = ARDOUR::new_change ();
 
-sigc::signal<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChanged;
+PBD::Signal1<void,boost::shared_ptr<ARDOUR::Region> > Region::RegionPropertyChanged;
 
 /* derived-from-derived constructor (no sources in constructor) */
 Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
        : SessionObject(s, name)
        , _type(type)
-       , _flags(flags)
-       , _start(start) 
-       , _length(length) 
-       , _position(0) 
-       , _last_position(0) 
+       , _flags(Flag (flags|DoNotSendPropertyChanges))
+       , _start(start)
+       , _length(length)
+       , _position(0)
+       , _last_position(0)
        , _positional_lock_style(AudioTime)
        , _sync_position(_start)
        , _layer(layer)
@@ -78,6 +77,7 @@ Region::Region (Session& s, nframes_t start, nframes_t length, const string& nam
        , _read_data_count(0)
        , _pending_changed(Change (0))
        , _last_layer_op(0)
+       , _pending_explicit_relayer (false)
 {
        /* no sources at this point */
 }
@@ -86,11 +86,11 @@ Region::Region (Session& s, nframes_t start, nframes_t length, const string& nam
 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
        : SessionObject(src->session(), name)
        , _type(type)
-       , _flags(flags)
-       , _start(start) 
-       , _length(length) 
-       , _position(0) 
-       , _last_position(0) 
+       , _flags(Flag (flags|DoNotSendPropertyChanges))
+       , _start(start)
+       , _length(length)
+       , _position(0)
+       , _last_position(0)
        , _positional_lock_style(AudioTime)
        , _sync_position(_start)
        , _layer(layer)
@@ -104,12 +104,12 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
        , _read_data_count(0)
        , _pending_changed(Change (0))
        , _last_layer_op(0)
-
+       , _pending_explicit_relayer (false)
 {
        _sources.push_back (src);
        _master_sources.push_back (src);
 
-       src->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), src));
+       src->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(src)));
 
        assert(_sources.size() > 0);
        _positional_lock_style = AudioTime;
@@ -119,11 +119,11 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
 Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
        : SessionObject(srcs.front()->session(), name)
        , _type(type)
-       , _flags(flags)
-       , _start(start) 
-       , _length(length) 
-       , _position(0) 
-       , _last_position(0) 
+       , _flags(Flag (flags|DoNotSendPropertyChanges))
+       , _start(start)
+       , _length(length)
+       , _position(0)
+       , _last_position(0)
        , _positional_lock_style(AudioTime)
        , _sync_position(_start)
        , _layer(layer)
@@ -136,6 +136,7 @@ Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const
        , _read_data_count(0)
        , _pending_changed(Change (0))
        , _last_layer_op(0)
+       , _pending_explicit_relayer (false)
 {
        use_sources (srcs);
        assert(_sources.size() > 0);
@@ -145,11 +146,14 @@ Region::Region (const SourceList& srcs, nframes_t start, nframes_t length, const
 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
        : SessionObject(other->session(), name)
        , _type (other->data_type())
+       , _pending_explicit_relayer (false)
 
 {
        _start = other->_start + offset;
        copy_stuff (other, offset, length, name, layer, flags);
 
+       _flags = Flag (_flags | DoNotSendPropertyChanges);
+
        /* if the other region had a distinct sync point
           set, then continue to use it as best we can.
           otherwise, reset sync point back to start.
@@ -182,23 +186,26 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
 Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const string& name, layer_t layer, Flag flags)
        : SessionObject(other->session(), name)
        , _type (other->data_type())
+       , _pending_explicit_relayer (false)
 {
        /* create a new Region exactly like another but starting at 0 in its sources */
 
        _start = 0;
        copy_stuff (other, 0, length, name, layer, flags);
 
+       _flags = Flag (_flags | DoNotSendPropertyChanges);
+
        /* sync pos is relative to start of file. our start-in-file is now zero,
           so set our sync position to whatever the the difference between
-          _start and _sync_pos was in the other region. 
+          _start and _sync_pos was in the other region.
 
-          result is that our new sync pos points to the same point in our source(s) 
+          result is that our new sync pos points to the same point in our source(s)
           as the sync in the other region did in its source(s).
 
           since we start at zero in our source(s), it is not possible to use a sync point that
           is before the start. reset it to _start if that was true in the other region.
        */
-       
+
        if (other->flags() & SyncMarked) {
                if (other->_start < other->_sync_position) {
                        /* sync pos was after the start point of the other region */
@@ -212,7 +219,7 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t length, const s
                _flags = Flag (_flags & ~SyncMarked);
                _sync_position = _start;
        }
-               
+
        if (Profile->get_sae()) {
                /* reset sync point to start if its ended up
                   outside region bounds.
@@ -235,10 +242,10 @@ Region::Region (boost::shared_ptr<const Region> other)
        : SessionObject(other->session(), other->name())
        , _type(other->data_type())
        , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
-       , _start(other->_start) 
-       , _length(other->_length) 
-       , _position(other->_position) 
-       , _last_position(other->_last_position) 
+       , _start(other->_start)
+       , _length(other->_length)
+       , _position(other->_position)
+       , _last_position(other->_last_position)
        , _positional_lock_style(other->_positional_lock_style)
        , _sync_position(other->_sync_position)
        , _layer(other->_layer)
@@ -252,7 +259,10 @@ Region::Region (boost::shared_ptr<const Region> other)
        , _read_data_count(0)
        , _pending_changed(Change(0))
        , _last_layer_op(other->_last_layer_op)
+       , _pending_explicit_relayer (false)
 {
+       _flags = Flag (_flags | DoNotSendPropertyChanges);
+
        other->_first_edit = EditChangesName;
 
        if (other->_extra_xml) {
@@ -268,11 +278,11 @@ Region::Region (boost::shared_ptr<const Region> other)
 Region::Region (const SourceList& srcs, const XMLNode& node)
        : SessionObject(srcs.front()->session(), X_("error: XML did not reset this"))
        , _type(DataType::NIL) // to be loaded from XML
-       , _flags(Flag(0))
-       , _start(0) 
-       , _length(0) 
-       , _position(0) 
-       , _last_position(0) 
+       , _flags(DoNotSendPropertyChanges)
+       , _start(0)
+       , _length(0)
+       , _position(0)
+       , _last_position(0)
        , _positional_lock_style(AudioTime)
        , _sync_position(_start)
        , _layer(0)
@@ -283,23 +293,11 @@ Region::Region (const SourceList& srcs, const XMLNode& node)
        , _read_data_count(0)
        , _pending_changed(Change(0))
        , _last_layer_op(0)
+       , _pending_explicit_relayer (false)
 {
-       set<boost::shared_ptr<Source> > unique_srcs;
-
-       for (SourceList::const_iterator i=srcs.begin(); i != srcs.end(); ++i) {
-               _sources.push_back (*i);
-               (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
-               unique_srcs.insert (*i);
-       }
-
-       for (SourceList::const_iterator i = srcs.begin(); i != srcs.end(); ++i) {
-               _master_sources.push_back (*i);
-               if (unique_srcs.find (*i) == unique_srcs.end()) {
-                       (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), (*i)));
-               }
-       }
+       use_sources (srcs);
 
-       if (set_state (node)) {
+       if (set_state (node, Stateful::loading_state_version)) {
                throw failed_constructor();
        }
 
@@ -310,11 +308,11 @@ Region::Region (const SourceList& srcs, const XMLNode& node)
 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
        : SessionObject(src->session(), X_("error: XML did not reset this"))
        , _type(DataType::NIL)
-       , _flags(Flag(0))
-       , _start(0) 
-       , _length(0) 
-       , _position(0) 
-       , _last_position(0) 
+       , _flags(DoNotSendPropertyChanges)
+       , _start(0)
+       , _length(0)
+       , _position(0)
+       , _last_position(0)
        , _positional_lock_style(AudioTime)
        , _sync_position(_start)
        , _layer(0)
@@ -325,53 +323,42 @@ Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
        , _read_data_count(0)
        , _pending_changed(Change(0))
        , _last_layer_op(0)
+       , _pending_explicit_relayer (false)
 {
        _sources.push_back (src);
 
-       if (set_state (node)) {
+       if (set_state (node, Stateful::loading_state_version)) {
                throw failed_constructor();
        }
-       
+
        assert(_type != DataType::NIL);
        assert(_sources.size() > 0);
 }
 
 Region::~Region ()
 {
-       boost::shared_ptr<Playlist> pl (playlist());
-
-       if (pl) {
-               for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
-                       (*i)->remove_playlist (pl);
-               }
-               for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
-                       (*i)->remove_playlist (pl);
-               }
-       }
-       
-       notify_callbacks ();
-       GoingAway (); /* EMIT SIGNAL */
+       DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
 }
 
 void
-Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
+Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t /*offset*/, nframes_t length, const string& name, layer_t layer, Flag flags)
 {
        _frozen = 0;
        _pending_changed = Change (0);
        _read_data_count = 0;
        _valid_transients = false;
 
-       _length = length; 
-       _last_length = length; 
+       _length = length;
+       _last_length = length;
        _sync_position = other->_sync_position;
        _ancestral_start = other->_ancestral_start;
-       _ancestral_length = other->_ancestral_length; 
+       _ancestral_length = other->_ancestral_length;
        _stretch = other->_stretch;
        _shift = other->_shift;
        _name = name;
-       _last_position = 0; 
-       _position = 0; 
-       _layer = layer; 
+       _last_position = 0;
+       _position = 0;
+       _layer = layer;
        _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
        _first_edit = EditChangesNothing;
        _last_layer_op = 0;
@@ -383,44 +370,7 @@ Region::copy_stuff (boost::shared_ptr<const Region> other, nframes_t offset, nfr
 void
 Region::set_playlist (boost::weak_ptr<Playlist> wpl)
 {
-       boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
-
-       boost::shared_ptr<Playlist> pl (wpl.lock());
-
-       if (old_playlist == pl) {
-               return;
-       }
-
-       _playlist = pl;
-
-       if (pl) {
-               if (old_playlist) {
-                       for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
-                               (*i)->remove_playlist (_playlist);      
-                               (*i)->add_playlist (pl);
-                       }
-                       for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
-                               (*i)->remove_playlist (_playlist);      
-                               (*i)->add_playlist (pl);
-                       }
-               } else {
-                       for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
-                               (*i)->add_playlist (pl);
-                       }
-                       for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
-                               (*i)->add_playlist (pl);
-                       }
-               }
-       } else {
-               if (old_playlist) {
-                       for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
-                               (*i)->remove_playlist (old_playlist);
-                       }
-                       for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
-                               (*i)->remove_playlist (old_playlist);
-                       }
-               }
-       }
+       _playlist = wpl.lock();
 }
 
 bool
@@ -428,7 +378,7 @@ Region::set_name (const std::string& str)
 {
        if (_name != str) {
                SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
-               assert(_name == str); 
+               assert(_name == str);
                send_change (ARDOUR::NameChanged);
        }
 
@@ -436,7 +386,7 @@ Region::set_name (const std::string& str)
 }
 
 void
-Region::set_length (nframes_t len, void *src)
+Region::set_length (nframes_t len, void */*src*/)
 {
        //cerr << "Region::set_length() len = " << len << endl;
        if (_flags & Locked) {
@@ -445,7 +395,7 @@ Region::set_length (nframes_t len, void *src)
 
        if (_length != len && len != 0) {
 
-               /* check that the current _position wouldn't make the new 
+               /* check that the current _position wouldn't make the new
                   length impossible.
                */
 
@@ -456,7 +406,7 @@ Region::set_length (nframes_t len, void *src)
                if (!verify_length (len)) {
                        return;
                }
-               
+
 
                _last_length = _length;
                _length = len;
@@ -487,7 +437,7 @@ Region::first_edit ()
 
        if (_first_edit != EditChangesNothing && pl) {
 
-               _name = pl->session().new_region_name (_name);
+               _name = _session.new_region_name (_name);
                _first_edit = EditChangesNothing;
 
                send_change (ARDOUR::NameChanged);
@@ -503,7 +453,7 @@ Region::at_natural_position () const
        if (!pl) {
                return false;
        }
-       
+
        boost::shared_ptr<Region> whole_file_region = get_parent();
 
        if (whole_file_region) {
@@ -523,18 +473,18 @@ Region::move_to_natural_position (void *src)
        if (!pl) {
                return;
        }
-       
+
        boost::shared_ptr<Region> whole_file_region = get_parent();
 
        if (whole_file_region) {
                set_position (whole_file_region->position() + _start, src);
        }
 }
-       
+
 void
 Region::special_set_position (nframes_t pos)
 {
-       /* this is used when creating a whole file region as 
+       /* this is used when creating a whole file region as
           a way to store its "natural" or "captured" position.
        */
 
@@ -554,27 +504,27 @@ Region::set_position_lock_style (PositionLockStyle ps)
        _positional_lock_style = ps;
 
        if (_positional_lock_style == MusicTime) {
-               pl->session().tempo_map().bbt_time (_position, _bbt_time);
+               _session.tempo_map().bbt_time (_position, _bbt_time);
        }
-       
+
 }
 
 void
 Region::update_position_after_tempo_map_change ()
 {
        boost::shared_ptr<Playlist> pl (playlist());
-       
+
        if (!pl || _positional_lock_style != MusicTime) {
                return;
        }
 
-       TempoMap& map (pl->session().tempo_map());
+       TempoMap& map (_session.tempo_map());
        nframes_t pos = map.frame_time (_bbt_time);
        set_position_internal (pos, false);
 }
 
 void
-Region::set_position (nframes_t pos, void *src)
+Region::set_position (nframes_t pos, void* /*src*/)
 {
        if (!can_move()) {
                return;
@@ -591,7 +541,7 @@ Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
                _position = pos;
 
                /* check that the new _position wouldn't make the current
-                  length impossible - if so, change the length. 
+                  length impossible - if so, change the length.
 
                   XXX is this the right thing to do?
                */
@@ -616,7 +566,7 @@ Region::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
 }
 
 void
-Region::set_position_on_top (nframes_t pos, void *src)
+Region::set_position_on_top (nframes_t pos, void* /*src*/)
 {
        if (_flags & Locked) {
                return;
@@ -636,7 +586,7 @@ Region::set_position_on_top (nframes_t pos, void *src)
        /* do this even if the position is the same. this helps out
           a GUI that has moved its representation already.
        */
-       
+
        send_change (PositionChanged);
 }
 
@@ -644,15 +594,12 @@ void
 Region::recompute_position_from_lock_style ()
 {
        if (_positional_lock_style == MusicTime) {
-               boost::shared_ptr<Playlist> pl (playlist());
-               if (pl) {
-                       pl->session().tempo_map().bbt_time (_position, _bbt_time);
-               }
+               _session.tempo_map().bbt_time (_position, _bbt_time);
        }
 }
-               
+
 void
-Region::nudge_position (nframes64_t n, void *src)
+Region::nudge_position (nframes64_t n, void* /*src*/)
 {
        if (_flags & Locked) {
                return;
@@ -661,7 +608,7 @@ Region::nudge_position (nframes64_t n, void *src)
        if (n == 0) {
                return;
        }
-       
+
        _last_position = _position;
 
        if (n > 0) {
@@ -691,7 +638,7 @@ Region::set_ancestral_data (nframes64_t s, nframes64_t l, float st, float sh)
 }
 
 void
-Region::set_start (nframes_t pos, void *src)
+Region::set_start (nframes_t pos, void* /*src*/)
 {
        if (_flags & (Locked|PositionLocked)) {
                return;
@@ -717,14 +664,14 @@ Region::set_start (nframes_t pos, void *src)
 }
 
 void
-Region::trim_start (nframes_t new_position, void *src)
+Region::trim_start (nframes_t new_position, void */*src*/)
 {
        if (_flags & (Locked|PositionLocked)) {
                return;
        }
        nframes_t new_start;
        int32_t start_shift;
-       
+
        if (new_position > _position) {
                start_shift = new_position - _position;
        } else {
@@ -757,7 +704,7 @@ Region::trim_start (nframes_t new_position, void *src)
        if (new_start == _start) {
                return;
        }
-       
+
        _start = new_start;
        _flags = Region::Flag (_flags & ~WholeFile);
        first_edit ();
@@ -782,20 +729,20 @@ Region::trim_front (nframes_t new_position, void *src)
        }
 
        if (new_position < end) { /* can't trim it zero or negative length */
-               
+
                nframes_t newlen;
 
                /* can't trim it back passed where source position zero is located */
-               
+
                new_position = max (new_position, source_zero);
-               
-               
+
+
                if (new_position > _position) {
                        newlen = _length - (new_position - _position);
                } else {
                        newlen = _length + (_position - new_position);
                }
-               
+
                trim_to_internal (new_position, newlen, src);
                if (!_frozen) {
                        recompute_at_start ();
@@ -803,15 +750,19 @@ Region::trim_front (nframes_t new_position, void *src)
        }
 }
 
+/** @param new_endpoint New region end point, such that, for example,
+ *  a region at 0 of length 10 has an endpoint of 9.
+ */
+
 void
-Region::trim_end (nframes_t new_endpoint, void *src)
+Region::trim_end (nframes_t new_endpoint, void */*src*/)
 {
        if (_flags & Locked) {
                return;
        }
 
        if (new_endpoint > _position) {
-               trim_to_internal (_position, new_endpoint - _position, this);
+               trim_to_internal (_position, new_endpoint - _position + 1, this);
                if (!_frozen) {
                        recompute_at_end ();
                }
@@ -834,7 +785,7 @@ Region::trim_to (nframes_t position, nframes_t length, void *src)
 }
 
 void
-Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
+Region::trim_to_internal (nframes_t position, nframes_t length, void */*src*/)
 {
        int32_t start_shift;
        nframes_t new_start;
@@ -893,17 +844,17 @@ Region::trim_to_internal (nframes_t position, nframes_t length, void *src)
                _position = position;
                what_changed = Change (what_changed|PositionChanged);
        }
-       
+
        _flags = Region::Flag (_flags & ~WholeFile);
 
        if (what_changed & (StartChanged|LengthChanged)) {
                first_edit ();
-       } 
+       }
 
        if (what_changed) {
                send_change (what_changed);
        }
-}      
+}
 
 void
 Region::set_hidden (bool yn)
@@ -977,12 +928,10 @@ Region::set_position_locked (bool yn)
 void
 Region::set_sync_position (nframes_t absolute_pos)
 {
-       nframes_t file_pos;
-
-       file_pos = _start + (absolute_pos - _position);
+       nframes_t const file_pos = _start + (absolute_pos - _position);
 
        if (file_pos != _sync_position) {
-               
+
                _sync_position = file_pos;
                _flags = Flag (_flags|SyncMarked);
 
@@ -1014,7 +963,7 @@ Region::sync_offset (int& dir) const
        if (_flags & SyncMarked) {
                if (_sync_position > _start) {
                        dir = 1;
-                       return _sync_position - _start; 
+                       return _sync_position - _start;
                } else {
                        dir = -1;
                        return _start - _sync_position;
@@ -1025,14 +974,14 @@ Region::sync_offset (int& dir) const
        }
 }
 
-nframes_t 
+nframes_t
 Region::adjust_to_sync (nframes_t pos) const
 {
        int sync_dir;
        nframes_t offset = sync_offset (sync_dir);
 
        // cerr << "adjusting pos = " << pos << " to sync at " << _sync_position << " offset = " << offset << " with dir = " << sync_dir << endl;
-       
+
        if (sync_dir > 0) {
                if (pos > offset) {
                        pos -= offset;
@@ -1052,7 +1001,7 @@ nframes_t
 Region::sync_position() const
 {
        if (_flags & SyncMarked) {
-               return _sync_position; 
+               return _sync_position;
        } else {
                return _start;
        }
@@ -1100,13 +1049,13 @@ Region::set_layer (layer_t l)
 {
        if (_layer != l) {
                _layer = l;
-               
+
                send_change (LayerChanged);
        }
 }
 
 XMLNode&
-Region::state (bool full_state)
+Region::state (bool /*full_state*/)
 {
        XMLNode *node = new XMLNode ("Region");
        char buf[64];
@@ -1130,7 +1079,7 @@ Region::state (bool full_state)
        node->add_property ("stretch", buf);
        snprintf (buf, sizeof (buf), "%.12g", _shift);
        node->add_property ("shift", buf);
-       
+
        switch (_first_edit) {
        case EditChangesNothing:
                fe = X_("nothing");
@@ -1172,13 +1121,13 @@ Region::get_state ()
 }
 
 int
-Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
+Region::set_live_state (const XMLNode& node, int /*version*/, Change& what_changed, bool send)
 {
        const XMLNodeList& nlist = node.children();
        const XMLProperty *prop;
        nframes_t val;
 
-       /* this is responsible for setting those aspects of Region state 
+       /* this is responsible for setting those aspects of Region state
           that are mutable after construction.
        */
 
@@ -1188,7 +1137,7 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
        }
 
        _name = prop->value();
-       
+
        if ((prop = node.property ("type")) == 0) {
                _type = DataType::AUDIO;
        } else {
@@ -1198,7 +1147,8 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
        if ((prop = node.property ("start")) != 0) {
                sscanf (prop->value().c_str(), "%" PRIu32, &val);
                if (val != _start) {
-                       what_changed = Change (what_changed|StartChanged);      
+                       what_changed = Change (what_changed|StartChanged);
+                       cerr << _name << " start changed\n";
                        _start = val;
                }
        } else {
@@ -1209,6 +1159,7 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
                sscanf (prop->value().c_str(), "%" PRIu32, &val);
                if (val != _length) {
                        what_changed = Change (what_changed|LengthChanged);
+                       cerr << _name << " length changed\n";
                        _last_length = _length;
                        _length = val;
                }
@@ -1221,6 +1172,7 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
                sscanf (prop->value().c_str(), "%" PRIu32, &val);
                if (val != _position) {
                        what_changed = Change (what_changed|PositionChanged);
+                       cerr << _name << " position changed\n";
                        _last_position = _position;
                        _position = val;
                }
@@ -1234,6 +1186,7 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
                x = (layer_t) atoi (prop->value().c_str());
                if (x != _layer) {
                        what_changed = Change (what_changed|LayerChanged);
+                       cerr << _name << " layer changed\n";
                        _layer = x;
                }
        } else {
@@ -1244,6 +1197,7 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
                sscanf (prop->value().c_str(), "%" PRIu32, &val);
                if (val != _sync_position) {
                        what_changed = Change (what_changed|SyncOffsetChanged);
+                       cerr << _name << " sync changed\n";
                        _sync_position = val;
                }
        } else {
@@ -1258,7 +1212,7 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
                                /* missing BBT info, revert to audio time locking */
                                _positional_lock_style = AudioTime;
                        } else {
-                               if (sscanf (prop->value().c_str(), "%d|%d|%d", 
+                               if (sscanf (prop->value().c_str(), "%d|%d|%d",
                                            &_bbt_time.bars,
                                            &_bbt_time.beats,
                                            &_bbt_time.ticks) != 3) {
@@ -1266,13 +1220,13 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
                                }
                        }
                }
-                       
+
        } else {
                _positional_lock_style = AudioTime;
        }
 
        /* XXX FIRST EDIT !!! */
-       
+
        /* these 3 properties never change as a result of any editing */
 
        if ((prop = node.property ("ancestral-start")) != 0) {
@@ -1282,7 +1236,7 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
        }
 
        if ((prop = node.property ("ancestral-length")) != 0) {
-               _ancestral_length = atoi (prop->value());
+               _ancestral_length = strtoll (prop->value().c_str(), 0, 10);
        } else {
                _ancestral_length = _length;
        }
@@ -1320,11 +1274,11 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
        _extra_xml = 0;
 
        for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
-               
+
                XMLNode *child;
-               
+
                child = (*niter);
-               
+
                if (child->name () == "Extra") {
                        _extra_xml = new XMLNode (*child);
                        break;
@@ -1332,6 +1286,7 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
        }
 
        if (send) {
+               cerr << _name << ": final change to be sent: " << hex << what_changed << dec << endl;
                send_change (what_changed);
        }
 
@@ -1339,7 +1294,7 @@ Region::set_live_state (const XMLNode& node, Change& what_changed, bool send)
 }
 
 int
-Region::set_state (const XMLNode& node)
+Region::set_state (const XMLNode& node, int version)
 {
        const XMLProperty *prop;
        Change what_changed = Change (0);
@@ -1352,10 +1307,10 @@ Region::set_state (const XMLNode& node)
        }
 
        _id = prop->value();
-       
+
        _first_edit = EditChangesNothing;
-       
-       set_live_state (node, what_changed, true);
+
+       set_live_state (node, version, what_changed, true);
 
        return 0;
 }
@@ -1369,7 +1324,7 @@ Region::freeze ()
 }
 
 void
-Region::thaw (const string& why)
+Region::thaw (const string& /*why*/)
 {
        Change what_changed = Change (0);
 
@@ -1393,40 +1348,45 @@ Region::thaw (const string& why)
        if (what_changed & LengthChanged) {
                if (what_changed & PositionChanged) {
                        recompute_at_start ();
-               } 
+               }
                recompute_at_end ();
        }
-               
-       StateChanged (what_changed);
+
+       send_change (what_changed);
 }
 
 void
 Region::send_change (Change what_changed)
 {
+
        {
                Glib::Mutex::Lock lm (_lock);
                if (_frozen) {
                        _pending_changed = Change (_pending_changed|what_changed);
                        return;
-               } 
+               }
        }
 
+       cerr << _name << " actually sends " << hex << what_changed << dec << " @" << get_microseconds() << endl;
        StateChanged (what_changed);
-       
-       if (!(_flags & DoNotSaveState)) {
-               
+       cerr << _name << " done with " << hex << what_changed << dec << " @" << get_microseconds() << endl;
+
+       if (!(_flags & DoNotSendPropertyChanges)) {
+
                /* Try and send a shared_pointer unless this is part of the constructor.
                   If so, do nothing.
                */
-               
+
                try {
                        boost::shared_ptr<Region> rptr = shared_from_this();
+                       cerr << _name << " actually sends prop change " << hex << what_changed << dec <<  " @ " << get_microseconds() << endl;
                        RegionPropertyChanged (rptr);
+                       cerr << _name << " done with prop change  @ " << get_microseconds() << endl;
                } catch (...) {
                        /* no shared_ptr available, relax; */
                }
        }
-       
+
 }
 
 void
@@ -1463,10 +1423,21 @@ Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
 }
 
 void
-Region::source_deleted (boost::shared_ptr<Source>)
+Region::source_deleted (boost::weak_ptr<Source>)
 {
        _sources.clear ();
-       drop_references ();
+
+       if (!_session.deletion_in_progress()) {
+               /* this is a very special case: at least one of the region's
+                  sources has bee deleted, so invalidate all references to
+                  ourselves. Do NOT do this during session deletion, because
+                  then we run the risk that this will actually result
+                  in this object being deleted (as refcnt goes to zero)
+                  while emitting DropReferences.
+               */
+
+               drop_references ();
+       }
 }
 
 vector<string>
@@ -1486,6 +1457,7 @@ void
 Region::set_master_sources (const SourceList& srcs)
 {
        _master_sources = srcs;
+       assert (_sources.size() == _master_sources.size());
 }
 
 bool
@@ -1512,6 +1484,17 @@ Region::source_equivalent (boost::shared_ptr<const Region> other) const
        return true;
 }
 
+bool
+Region::uses_source (boost::shared_ptr<const Source> source) const
+{
+       for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
+               if (*i == source) {
+                       return true;
+               }
+       }
+       return false;
+}
+
 sframes_t
 Region::source_length(uint32_t n) const
 {
@@ -1530,9 +1513,9 @@ Region::verify_length (nframes_t len)
        for (uint32_t n=0; n < _sources.size(); ++n) {
                maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
        }
-       
+
        len = min (len, maxlen);
-       
+
        return true;
 }
 
@@ -1592,12 +1575,12 @@ Region::get_parent() const
        if (pl) {
                boost::shared_ptr<Region> r;
                boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
-               
-               if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
+
+               if (grrr2 && (r = _session.find_whole_file_parent (grrr2))) {
                        return boost::static_pointer_cast<Region> (r);
                }
        }
-       
+
        return boost::shared_ptr<Region>();
 }
 
@@ -1620,18 +1603,18 @@ void
 Region::use_sources (SourceList const & s)
 {
        set<boost::shared_ptr<Source> > unique_srcs;
-       
+
        for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
                _sources.push_back (*i);
-               (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), *i));
+               (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
                unique_srcs.insert (*i);
        }
 
-       for (SourceList::const_iterator i = s.begin(); i != s.end(); ++i) {
+       for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
                _master_sources.push_back (*i);
                if (unique_srcs.find (*i) == unique_srcs.end()) {
-                       (*i)->GoingAway.connect (bind (mem_fun (*this, &Region::source_deleted), *i));
+                       (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
                }
        }
 }
-       
+