diff options
36 files changed, 309 insertions, 219 deletions
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index bd78648107..b267bcd37b 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -4419,10 +4419,12 @@ Editor::remove_last_capture () if (prompter.run () == 1) { _session->remove_last_capture (); + _regions->redisplay (); } } else { _session->remove_last_capture(); + _regions->redisplay (); } } diff --git a/gtk2_ardour/editor_regions.cc b/gtk2_ardour/editor_regions.cc index dca382415a..ab6ce76567 100644 --- a/gtk2_ardour/editor_regions.cc +++ b/gtk2_ardour/editor_regions.cc @@ -365,7 +365,6 @@ EditorRegions::selection_changed () } else { _change_connection.block (true); - cerr << "\tpush to region selection\n"; _editor->set_selected_regionview_from_region_list (region, Selection::Add); _change_connection.block (false); @@ -392,13 +391,11 @@ EditorRegions::set_selected (RegionSelection& regions) boost::shared_ptr<Region> compared_region = (*i)[_columns.region]; if (r == compared_region) { - cerr << "\tpush into region list\n"; _display.get_selection()->select(*i); break; } if (!(*i).children().empty()) { - cerr << "\tlook for " << r->name() << " among children of " << (compared_region ? compared_region->name() : string ("NO REGION")) << endl; if (set_selected_in_subrow(r, (*i), 2)) { break; } @@ -559,7 +556,6 @@ EditorRegions::update_all_rows () boost::shared_ptr<Region> region = (*i)[_columns.region]; if (!region->automatic()) { - cerr << "level 1 : Updating " << region->name() << "\n"; populate_row(region, (*i)); } @@ -580,7 +576,6 @@ EditorRegions::update_all_subrows (TreeModel::Row const &parent_row, int level) boost::shared_ptr<Region> region = (*i)[_columns.region]; if (!region->automatic()) { - cerr << "level " << level << " : Updating " << region->name() << "\n"; populate_row(region, (*i)); } diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h index c089a39736..d0d2bcbc36 100644 --- a/libs/ardour/ardour/diskstream.h +++ b/libs/ardour/ardour/diskstream.h @@ -45,7 +45,7 @@ namespace ARDOUR { class IO; class Playlist; class Processor; -class Region; +class Source; class Session; class Track; class Location; @@ -134,12 +134,10 @@ class Diskstream : public SessionObject, public PublicDiskstream int set_loop (Location *loc); - std::list<boost::shared_ptr<Region> >& last_capture_regions () { return _last_capture_regions; } + std::list<boost::shared_ptr<Source> >& last_capture_sources () { return _last_capture_sources; } void handle_input_change (IOChange, void *src); - void remove_region_from_last_capture (boost::weak_ptr<Region> wregion); - void move_processor_automation (boost::weak_ptr<Processor>, std::list<Evoral::RangeMove<framepos_t> > const &); @@ -228,7 +226,7 @@ class Diskstream : public SessionObject, public PublicDiskstream virtual bool realtime_set_speed (double, bool global_change); - std::list<boost::shared_ptr<Region> > _last_capture_regions; + std::list<boost::shared_ptr<Source> > _last_capture_sources; virtual int use_pending_capture_data (XMLNode& node) = 0; diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index 4b42fc0bd6..7afc074b4d 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -65,7 +65,8 @@ class RegionListProperty : public PBD::SequenceProperty<std::list<boost::shared_ RegionListProperty (Playlist&); boost::shared_ptr<Region> lookup_id (const PBD::ID& id); - void diff (PBD::PropertyList& undo, PBD::PropertyList& redo) const; + void diff (PBD::PropertyList& undo, PBD::PropertyList& redo, Command*) const; + bool involves (boost::shared_ptr<Region>); private: friend class Playlist; diff --git a/libs/ardour/ardour/public_diskstream.h b/libs/ardour/ardour/public_diskstream.h index c31e88a79b..9e25cb24c6 100755 --- a/libs/ardour/ardour/public_diskstream.h +++ b/libs/ardour/ardour/public_diskstream.h @@ -23,7 +23,7 @@ namespace ARDOUR { class Playlist; -class Region; +class Source; class Location; /** Public interface to a Diskstream */ @@ -34,7 +34,7 @@ public: virtual boost::shared_ptr<Playlist> playlist () = 0; virtual void monitor_input (bool) = 0; virtual bool destructive () const = 0; - virtual std::list<boost::shared_ptr<Region> > & last_capture_regions () = 0; + virtual std::list<boost::shared_ptr<Source> > & last_capture_sources () = 0; virtual void set_capture_offset () = 0; virtual void reset_write_sources (bool, bool force = false) = 0; virtual float playback_buffer_load () const = 0; diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index 2cf9bab97b..a30bb8660c 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -270,6 +270,8 @@ class Region return _pending_explicit_relayer; } + void drop_sources (); + protected: friend class RegionFactory; diff --git a/libs/ardour/ardour/region_factory.h b/libs/ardour/ardour/region_factory.h index c9f387f172..459699d810 100644 --- a/libs/ardour/ardour/region_factory.h +++ b/libs/ardour/ardour/region_factory.h @@ -21,6 +21,7 @@ #define __ardour_region_factory_h__ #include <map> +#include <set> #include <glibmm/thread.h> #include "pbd/id.h" @@ -78,7 +79,10 @@ class RegionFactory { /** create a region with specified sources @param srcs and XML state */ static boost::shared_ptr<Region> create (SourceList& srcs, const XMLNode&); + static void get_regions_using_source (boost::shared_ptr<Source>, std::set<boost::shared_ptr<Region> >& ); + static void map_remove (boost::shared_ptr<Region>); + static void map_remove_with_equivalents (boost::shared_ptr<Region>); static void delete_all_regions (); static const RegionMap& regions() { return region_map; } static uint32_t nregions (); diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index f7692e09cb..bca65c88e4 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -512,8 +512,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi int cleanup_sources (CleanupReport&); int cleanup_trash_sources (CleanupReport&); - int destroy_region (boost::shared_ptr<Region>); - int destroy_regions (std::list<boost::shared_ptr<Region> >); + int destroy_sources (std::list<boost::shared_ptr<Source> >); int remove_last_capture (); diff --git a/libs/ardour/ardour/session_playlists.h b/libs/ardour/ardour/session_playlists.h index d654595d60..1c83a312a5 100644 --- a/libs/ardour/ardour/session_playlists.h +++ b/libs/ardour/ardour/session_playlists.h @@ -53,6 +53,7 @@ public: template<class T> void foreach (T *obj, void (T::*func)(boost::shared_ptr<Playlist>)); void get (std::vector<boost::shared_ptr<Playlist> >&); void unassigned (std::list<boost::shared_ptr<Playlist> > & list); + void destroy_region (boost::shared_ptr<Region>); private: friend class Session; @@ -69,7 +70,7 @@ private: int load (Session &, const XMLNode&); int load_unused (Session &, const XMLNode&); boost::shared_ptr<Playlist> XMLPlaylistFactory (Session &, const XMLNode&); - + mutable Glib::Mutex lock; typedef std::set<boost::shared_ptr<Playlist> > List; List playlists; diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h index bf92e5a6e4..16a762eb94 100644 --- a/libs/ardour/ardour/source.h +++ b/libs/ardour/ardour/source.h @@ -23,6 +23,8 @@ #include <string> #include <set> +#include <glib.h> + #include <boost/utility.hpp> #include "pbd/statefuldestructible.h" @@ -102,6 +104,15 @@ class Source : public SessionObject Glib::Mutex& mutex() { return _lock; } Flag flags() const { return _flags; } + void inc_use_count () { g_atomic_int_inc (&_use_count); } + void dec_use_count () { + gint oldval = g_atomic_int_exchange_and_add (&_use_count, -1); + assert (oldval > 0); + } + + int use_count() const { return g_atomic_int_get (&_use_count); } + bool used() const { return use_count() > 0; } + protected: DataType _type; Flag _flags; @@ -111,6 +122,7 @@ class Source : public SessionObject mutable Glib::Mutex _lock; mutable Glib::Mutex _analysis_lock; Glib::Mutex _playlist_lock; + gint _use_count; /* atomic */ private: void fix_writable_flags (); diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index ac948f12df..d72d29e563 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -29,6 +29,7 @@ namespace ARDOUR { class Session; class Playlist; class RouteGroup; +class Source; class Region; class Diskstream; @@ -100,7 +101,7 @@ class Track : public Route, public PublicDiskstream boost::shared_ptr<Playlist> playlist (); void monitor_input (bool); bool destructive () const; - std::list<boost::shared_ptr<Region> > & last_capture_regions (); + std::list<boost::shared_ptr<Source> > & last_capture_sources (); void set_capture_offset (); void reset_write_sources (bool, bool force = false); float playback_buffer_load () const; diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index b3204c38b6..ae80690b81 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -480,8 +480,8 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can was_recording = true; } - if (can_record && !_last_capture_regions.empty()) { - _last_capture_regions.clear (); + if (can_record && !_last_capture_sources.empty()) { + _last_capture_sources.clear (); } if (rec_nframes) { @@ -1447,7 +1447,6 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo plist.add (Properties::start, c->front()->write_source->last_capture_start_frame()); plist.add (Properties::length, total_capture); plist.add (Properties::name, whole_file_region_name); - boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist)); rx->set_automatic (true); rx->set_whole_file (true); @@ -1462,7 +1461,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo /* XXX what now? */ } - _last_capture_regions.push_back (region); + _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end()); // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n"; @@ -1494,10 +1493,6 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo continue; /* XXX is this OK? */ } - region->DropReferences.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region))); - - _last_capture_regions.push_back (region); - i_am_the_modifier++; _playlist->add_region (region, (*ci)->start, 1, non_layered()); i_am_the_modifier--; @@ -1914,6 +1909,8 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/) boost::shared_ptr<ChannelList> c = channels.reader(); uint32_t n; + cerr << name() << " resetting write sources, recrodable " << recordable() << " chans = " << c->size() << endl; + if (!_session.writable() || !recordable()) { return; } @@ -2356,6 +2353,7 @@ void AudioDiskstream::ChannelInfo::resize_capture (nframes_t capture_bufsize) { delete capture_buf; + capture_buf = new RingBufferNPT<Sample> (capture_bufsize); memset (capture_buf->buffer(), 0, sizeof (Sample) * capture_buf->bufsize()); } diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index bd09af4e1f..6a27541bcd 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -663,17 +663,15 @@ bool AudioPlaylist::destroy_region (boost::shared_ptr<Region> region) { boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region); + + if (!r) { + return false; + } + bool changed = false; Crossfades::iterator c, ctmp; set<boost::shared_ptr<Crossfade> > unique_xfades; - if (r == 0) { - fatal << _("programming error: non-audio Region passed to remove_overlap in audio playlist") - << endmsg; - /*NOTREACHED*/ - return false; - } - { RegionLock rlock (this); diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 0ef79b7018..80f8baef0e 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -263,6 +263,9 @@ AudioRegion::connect_to_header_position_offset_changed () for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) { + /* connect only once to HeaderPositionOffsetChanged, even if sources are replicated + */ + if (unique_srcs.find (*i) == unique_srcs.end ()) { unique_srcs.insert (*i); boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*i); @@ -520,24 +523,8 @@ AudioRegion::state (bool full) XMLNode& node (Region::state (full)); XMLNode *child; char buf[64]; - char buf2[64]; LocaleGuard lg (X_("POSIX")); - - // XXX these should move into Region - - for (uint32_t n=0; n < _sources.size(); ++n) { - snprintf (buf2, sizeof(buf2), "source-%d", n); - _sources[n]->id().print (buf, sizeof (buf)); - node.add_property (buf2, buf); - } - - for (uint32_t n=0; n < _master_sources.size(); ++n) { - snprintf (buf2, sizeof(buf2), "master-source-%d", n); - _master_sources[n]->id().print (buf, sizeof (buf)); - node.add_property (buf2, buf); - } - snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size()); node.add_property ("channels", buf); @@ -571,10 +558,6 @@ AudioRegion::state (bool full) child->add_property ("default", "yes"); } - if (full && _extra_xml) { - node.add_child_copy (*_extra_xml); - } - return node; } diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index 40a2714dc0..5dd9a3b306 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -436,18 +436,6 @@ Diskstream::set_name (const string& str) } void -Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion) -{ - boost::shared_ptr<Region> region (wregion.lock()); - - if (!region) { - return; - } - - _last_capture_regions.remove (region); -} - -void Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<framepos_t> > const & movements_frames) { if (!_track || Config->get_automation_follows_regions () == false) { diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index fa2cdce014..444e4d3788 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -524,8 +524,8 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_ } - if (can_record && !_last_capture_regions.empty()) { - _last_capture_regions.clear (); + if (can_record && !_last_capture_sources.empty()) { + _last_capture_sources.clear (); } if (nominally_recording || rec_nframes) { @@ -975,9 +975,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen /* XXX what now? */ } - _last_capture_regions.push_back (region); - - // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n"; + _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end()); _playlist->clear_history (); _playlist->freeze (); @@ -1007,10 +1005,6 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen continue; /* XXX is this OK? */ } - region->DropReferences.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region))); - - _last_capture_regions.push_back (region); - // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl; i_am_the_modifier++; @@ -1312,6 +1306,8 @@ MidiDiskstream::set_state (const XMLNode& node, int /*version*/) int MidiDiskstream::use_new_write_source (uint32_t n) { + cerr << name() << " use new write source for n = " << n << " recordable ? " << recordable() << endl; + if (!recordable()) { return 1; } diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc index 152735de85..6f5dee979a 100644 --- a/libs/ardour/midi_playlist.cc +++ b/libs/ardour/midi_playlist.cc @@ -359,15 +359,13 @@ bool MidiPlaylist::destroy_region (boost::shared_ptr<Region> region) { boost::shared_ptr<MidiRegion> r = boost::dynamic_pointer_cast<MidiRegion> (region); - bool changed = false; - if (r == 0) { - PBD::fatal << _("programming error: non-midi Region passed to remove_overlap in midi playlist") - << endmsg; - /*NOTREACHED*/ + if (!r) { return false; } + bool changed = false; + { RegionLock rlock (this); RegionList::iterator i; diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index fe03e64f72..abb3191463 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -193,30 +193,7 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, Evoral::EventSink<nframes_t>& XMLNode& MidiRegion::state (bool full) { - XMLNode& node (Region::state (full)); - char buf[64]; - char buf2[64]; - LocaleGuard lg (X_("POSIX")); - - // XXX these should move into Region - - for (uint32_t n=0; n < _sources.size(); ++n) { - snprintf (buf2, sizeof(buf2), "source-%d", n); - _sources[n]->id().print (buf, sizeof(buf)); - node.add_property (buf2, buf); - } - - for (uint32_t n=0; n < _master_sources.size(); ++n) { - snprintf (buf2, sizeof(buf2), "master-source-%d", n); - _master_sources[n]->id().print (buf, sizeof (buf)); - node.add_property (buf2, buf); - } - - if (full && _extra_xml) { - node.add_child_copy (*_extra_xml); - } - - return node; + return Region::state (full); } int diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index 0526d48b11..f07cd645f1 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -134,7 +134,7 @@ RegionListProperty::copy_for_history () const } void -RegionListProperty::diff (PropertyList& undo, PropertyList& redo) const +RegionListProperty::diff (PropertyList& undo, PropertyList& redo, Command* cmd) const { if (changed()) { /* list of the removed/added regions since clear_history() was last called */ @@ -144,6 +144,18 @@ RegionListProperty::diff (PropertyList& undo, PropertyList& redo) const RegionListProperty* b = copy_for_history (); b->invert_changes (); + if (cmd) { + /* whenever one of the regions emits DropReferences, make sure + that the Destructible we've been told to notify hears about + it. the Destructible is likely to be the Command being built + with this diff(). + */ + + for (set<boost::shared_ptr<Region> >::iterator i = a->change().added.begin(); i != a->change().added.end(); ++i) { + (*i)->DropReferences.connect_same_thread (*cmd, boost::bind (&Destructible::drop_references, cmd)); + } + } + undo.add (b); redo.add (a); } diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 2589f94f81..e620319633 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -415,6 +415,7 @@ Region::Region (boost::shared_ptr<const Region> other) Region::~Region () { DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this)); + drop_sources (); } void @@ -1126,10 +1127,12 @@ Region::set_layer (layer_t l) } XMLNode& -Region::state (bool /*full_state*/) +Region::state (bool full) { XMLNode *node = new XMLNode ("Region"); char buf[64]; + char buf2[64]; + LocaleGuard lg (X_("POSIX")); const char* fe = NULL; add_properties (*node); @@ -1164,6 +1167,22 @@ Region::state (bool /*full_state*/) node->add_property ("bbt-position", str.str()); } + for (uint32_t n=0; n < _sources.size(); ++n) { + snprintf (buf2, sizeof(buf2), "source-%d", n); + _sources[n]->id().print (buf, sizeof(buf)); + node->add_property (buf2, buf); + } + + for (uint32_t n=0; n < _master_sources.size(); ++n) { + snprintf (buf2, sizeof(buf2), "master-source-%d", n); + _master_sources[n]->id().print (buf, sizeof (buf)); + node->add_property (buf2, buf); + } + + if (full && _extra_xml) { + node->add_child_copy (*_extra_xml); + } + return *node; } @@ -1237,11 +1256,6 @@ Region::_set_state (const XMLNode& node, int version, PropertyChange& what_chang } if (send) { - cerr << _name << ": final change to be sent: "; - for (PropertyChange::iterator i = what_changed.begin(); i != what_changed.end(); ++i) { - cerr << g_quark_to_string ((GQuark) *i) << ' '; - } - cerr << endl; send_change (what_changed); } @@ -1335,7 +1349,7 @@ Region::region_list_equivalent (boost::shared_ptr<const Region> other) const void Region::source_deleted (boost::weak_ptr<Source>) { - _sources.clear (); + drop_sources (); if (!_session.deletion_in_progress()) { /* this is a very special case: at least one of the region's @@ -1366,8 +1380,16 @@ Region::master_source_names () void Region::set_master_sources (const SourceList& srcs) { + for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + (*i)->dec_use_count (); + } + _master_sources = srcs; assert (_sources.size() == _master_sources.size()); + + for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + (*i)->inc_use_count (); + } } bool @@ -1408,6 +1430,7 @@ Region::uses_source (boost::shared_ptr<const Source> source) const sframes_t Region::source_length(uint32_t n) const { + assert (n < _sources.size()); return _sources[n]->length(_position - _start); } @@ -1420,7 +1443,7 @@ Region::verify_length (framecnt_t len) framecnt_t maxlen = 0; - for (uint32_t n=0; n < _sources.size(); ++n) { + for (uint32_t n = 0; n < _sources.size(); ++n) { maxlen = max (maxlen, source_length(n) - _start); } @@ -1438,7 +1461,7 @@ Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length) framecnt_t maxlen = 0; - for (uint32_t n=0; n < _sources.size(); ++n) { + for (uint32_t n = 0; n < _sources.size(); ++n) { maxlen = max (maxlen, source_length(n) - new_start); } @@ -1454,7 +1477,7 @@ Region::verify_start (framepos_t pos) return true; } - for (uint32_t n=0; n < _sources.size(); ++n) { + for (uint32_t n = 0; n < _sources.size(); ++n) { if (pos > source_length(n) - _length) { return false; } @@ -1469,7 +1492,7 @@ Region::verify_start_mutable (framepos_t& new_start) return true; } - for (uint32_t n=0; n < _sources.size(); ++n) { + for (uint32_t n = 0; n < _sources.size(); ++n) { if (new_start > source_length(n) - _length) { new_start = source_length(n) - _length; } @@ -1508,6 +1531,21 @@ Region::invalidate_transients () _transients.clear (); } +void +Region::drop_sources () +{ + for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) { + (*i)->dec_use_count (); + } + + _sources.clear (); + + for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) { + (*i)->dec_use_count (); + } + + _master_sources.clear (); +} void Region::use_sources (SourceList const & s) @@ -1515,16 +1553,19 @@ 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)->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) { + _sources.push_back (*i); + (*i)->inc_use_count (); _master_sources.push_back (*i); - if (unique_srcs.find (*i) == unique_srcs.end()) { - (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i))); - } + (*i)->inc_use_count (); + + /* connect only once to DropReferences, even if sources are replicated + */ + + if (unique_srcs.find (*i) == unique_srcs.end ()) { + unique_srcs.insert (*i); + (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i))); + } } } diff --git a/libs/ardour/region_factory.cc b/libs/ardour/region_factory.cc index 5a4b129710..65649ad8f7 100644 --- a/libs/ardour/region_factory.cc +++ b/libs/ardour/region_factory.cc @@ -73,6 +73,7 @@ RegionFactory::create (boost::shared_ptr<const Region> region) } if (ret) { + cerr << "Pure copy constructor region " << ret << " named " << ret->name() << endl; map_add (ret); /* pure copy constructor - no property list */ @@ -124,6 +125,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, frameoffset_t offset, b if (ret) { ret->set_properties (plist); + cerr << "Partial copy constructor region\n"; map_add (ret); if (announce) { @@ -163,6 +165,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, const SourceList& srcs, if (ret) { ret->set_properties (plist); + cerr << "New sources copy constructor region\n"; map_add (ret); if (announce) { @@ -208,6 +211,7 @@ RegionFactory::create (const SourceList& srcs, const PropertyList& plist, bool a if (ret) { ret->set_properties (plist); + cerr << "de-novo constructor region " << ret << " named " << ret->name() << endl; map_add (ret); if (announce) { @@ -281,6 +285,8 @@ RegionFactory::map_add (boost::shared_ptr<Region> r) boost::bind (&RegionFactory::region_changed, _1, boost::weak_ptr<Region> (r)) ); + cerr << "Added region with ID = " << r->id() << " named " << r->name() << endl; + update_region_name_map (r); } @@ -292,7 +298,32 @@ RegionFactory::map_remove (boost::shared_ptr<Region> r) if (i != region_map.end()) { region_map.erase (i); + cerr << "Removed region with ID = " << r->id() << " named " << r->name() << endl;; } + +} + +void +RegionFactory::map_remove_with_equivalents (boost::shared_ptr<Region> r) +{ + Glib::Mutex::Lock lm (region_map_lock); + + for (RegionMap::iterator i = region_map.begin(); i != region_map.end(); ) { + RegionMap::iterator tmp = i; + ++tmp; + + if (r->region_list_equivalent (i->second)) { + cerr << "Removed equivalent region " << i->second->name() << '/' << i->first << endl; + region_map.erase (i); + } else if (r == i->second) { + cerr << "Removed actual region " << i->second->name() << '/' << i->first << endl; + region_map.erase (i); + } + + i = tmp; + } + + } boost::shared_ptr<Region> @@ -487,3 +518,15 @@ RegionFactory::new_region_name (string old) error << string_compose (_("cannot create new name for region \"%1\""), old) << endmsg; return old; } + +void +RegionFactory::get_regions_using_source (boost::shared_ptr<Source> s, std::set<boost::shared_ptr<Region> >& r) +{ + Glib::Mutex::Lock lm (region_map_lock); + + for (RegionMap::iterator i = region_map.begin(); i != region_map.end(); ++i) { + if (i->second->uses_source (s)) { + r.insert (i->second); + } + } +} diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 3d5430d259..91b1e2a0f9 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1484,6 +1484,7 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m auto_connect_route (track, existing_inputs, existing_outputs); track->non_realtime_input_change(); + if (route_group) { route_group->add (track); } @@ -2483,46 +2484,58 @@ Session::find_whole_file_parent (boost::shared_ptr<Region const> child) const } int -Session::destroy_region (boost::shared_ptr<Region> region) +Session::destroy_sources (list<boost::shared_ptr<Source> > srcs) { - vector<boost::shared_ptr<Source> > srcs; - - { - if (region->playlist()) { - region->playlist()->destroy_region (region); - } + set<boost::shared_ptr<Region> > relevant_regions; - for (uint32_t n = 0; n < region->n_channels(); ++n) { - srcs.push_back (region->source (n)); - } + for (list<boost::shared_ptr<Source> >::iterator s = srcs.begin(); s != srcs.end(); ++s) { + RegionFactory::get_regions_using_source (*s, relevant_regions); } - region->drop_references (); + cerr << "There are " << relevant_regions.size() << " using " << srcs.size() << " sources" << endl; + + for (set<boost::shared_ptr<Region> >::iterator r = relevant_regions.begin(); r != relevant_regions.end(); ) { + set<boost::shared_ptr<Region> >::iterator tmp; + + tmp = r; + ++tmp; + + cerr << "Cleanup " << (*r)->name() << " UC = " << (*r).use_count() << endl; - for (vector<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) { + playlists->destroy_region (*r); + RegionFactory::map_remove (*r); - (*i)->mark_for_remove (); - (*i)->drop_references (); + (*r)->drop_sources (); + (*r)->drop_references (); + + cerr << "\tdone UC = " << (*r).use_count() << endl; + + relevant_regions.erase (r); + + r = tmp; + } + + for (list<boost::shared_ptr<Source> >::iterator s = srcs.begin(); s != srcs.end(); ) { - cerr << "source was not used by any playlist\n"; - } + { + Glib::Mutex::Lock ls (source_lock); + /* remove from the main source list */ + sources.erase ((*s)->id()); + } - return 0; -} + (*s)->mark_for_remove (); + (*s)->drop_references (); + + s = srcs.erase (s); + } -int -Session::destroy_regions (list<boost::shared_ptr<Region> > regions) -{ - for (list<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) { - destroy_region (*i); - } return 0; } int Session::remove_last_capture () { - list<boost::shared_ptr<Region> > r; + list<boost::shared_ptr<Source> > srcs; boost::shared_ptr<RouteList> rl = routes.reader (); for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { @@ -2531,15 +2544,15 @@ Session::remove_last_capture () continue; } - list<boost::shared_ptr<Region> >& l = tr->last_capture_regions(); + list<boost::shared_ptr<Source> >& l = tr->last_capture_sources(); if (!l.empty()) { - r.insert (r.end(), l.begin(), l.end()); + srcs.insert (srcs.end(), l.begin(), l.end()); l.clear (); } } - destroy_regions (r); + destroy_sources (srcs); save_state (_current_snapshot_name); @@ -2563,16 +2576,19 @@ Session::add_source (boost::shared_ptr<Source> source) } if (result.second) { - set_dirty(); - } - boost::shared_ptr<AudioFileSource> afs; + /* yay, new source */ - if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) { - if (Config->get_auto_analyse_audio()) { - Analyser::queue_source_for_analysis (source, false); - } - } + set_dirty(); + + boost::shared_ptr<AudioFileSource> afs; + + if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) { + if (Config->get_auto_analyse_audio()) { + Analyser::queue_source_for_analysis (source, false); + } + } + } } void diff --git a/libs/ardour/session_playlists.cc b/libs/ardour/session_playlists.cc index 2f8ae9a8f0..38c6744d06 100644 --- a/libs/ardour/session_playlists.cc +++ b/libs/ardour/session_playlists.cc @@ -220,6 +220,21 @@ SessionPlaylists::get (vector<boost::shared_ptr<Playlist> >& s) } void +SessionPlaylists::destroy_region (boost::shared_ptr<Region> r) +{ + Glib::Mutex::Lock lm (lock); + + for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) { + (*i)->destroy_region (r); + } + + for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) { + (*i)->destroy_region (r); + } +} + + +void SessionPlaylists::find_equivalent_playlist_regions (boost::shared_ptr<Region> region, vector<boost::shared_ptr<Region> >& result) { for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) @@ -262,14 +277,12 @@ SessionPlaylists::add_state (XMLNode* node, bool full_state) XMLNode* child = node->add_child ("Playlists"); for (List::iterator i = playlists.begin(); i != playlists.end(); ++i) { if (!(*i)->hidden()) { - if (!(*i)->empty()) { - if (full_state) { - child->add_child_nocopy ((*i)->get_state()); - } else { - child->add_child_nocopy ((*i)->get_template()); - } - } - } + if (full_state) { + child->add_child_nocopy ((*i)->get_state()); + } else { + child->add_child_nocopy ((*i)->get_template()); + } + } } child = node->add_child ("UnusedPlaylists"); diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index a490bb10c9..0f8583a822 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -1040,13 +1040,18 @@ Session::state(bool full_state) for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) { - /* Don't save information about non-destructive file sources that are empty */ - /* FIXME: MIDI breaks if this is made FileSource like it should be... */ + /* Don't save information about non-destructive file sources that are empty + and unused by any regions. + */ - boost::shared_ptr<AudioFileSource> fs; - if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (siter->second)) != 0) { + cerr << "Source " << siter->second->name() << " has UC = " << siter->second->used() + << " length = " << siter->second->length (0) + << endl; + + boost::shared_ptr<FileSource> fs; + if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) { if (!fs->destructive()) { - if (fs->length(fs->timeline_position()) == 0) { + if (fs->length(fs->timeline_position()) == 0 && !fs->used()) { continue; } } diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc index 5ec9631e40..55ce9f8bef 100644 --- a/libs/ardour/source.cc +++ b/libs/ardour/source.cc @@ -52,6 +52,7 @@ Source::Source (Session& s, DataType type, const string& name, Flag flags) , _type(type) , _flags(flags) , _timeline_position(0) + , _use_count (0) { _analysed = false; _timestamp = 0; @@ -63,6 +64,7 @@ Source::Source (Session& s, const XMLNode& node) , _type(DataType::AUDIO) , _flags (Flag (Writable|CanRename)) , _timeline_position(0) + , _use_count (0) { _timestamp = 0; _analysed = false; diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index ad4c765867..b2079e0a2e 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -425,10 +425,10 @@ Track::destructive () const return _diskstream->destructive (); } -list<boost::shared_ptr<Region> > & -Track::last_capture_regions () +list<boost::shared_ptr<Source> > & +Track::last_capture_sources () { - return _diskstream->last_capture_regions (); + return _diskstream->last_capture_sources (); } void diff --git a/libs/evoral/src/SMF.cpp b/libs/evoral/src/SMF.cpp index b8705afbf0..cf838455ce 100644 --- a/libs/evoral/src/SMF.cpp +++ b/libs/evoral/src/SMF.cpp @@ -275,6 +275,16 @@ SMF::begin_write() void SMF::end_write() THROW_FILE_ERROR { +#if 0 + /* don't create empty MIDI files + */ + + smf_rewind (_smf); // smf_save() would have done this anyway + if (smf_peek_next_event (_smf) == 0) { + return; + } +#endif + PBD::StdioFileDescriptor d (_file_path, "w+"); FILE* f = d.allocate (); if (f == 0) { diff --git a/libs/pbd/pbd/command.h b/libs/pbd/pbd/command.h index 5a7290bc89..c6c3c8d3fd 100644 --- a/libs/pbd/pbd/command.h +++ b/libs/pbd/pbd/command.h @@ -22,10 +22,12 @@ #ifndef __lib_pbd_command_h__ #define __lib_pbd_command_h__ +#include <string> + +#include "pbd/signals.h" #include "pbd/statefuldestructible.h" -#include <boost/utility.hpp> -class Command : public PBD::StatefulDestructible, public boost::noncopyable +class Command : public PBD::StatefulDestructible, public PBD::ScopedConnectionList { public: virtual ~Command() { /* NOTE: derived classes must call drop_references() */ } @@ -34,7 +36,7 @@ public: void set_name (const std::string& str) { _name = str; } const std::string& name() const { return _name; } - + virtual void undo() = 0; virtual void redo() { (*this)(); } diff --git a/libs/pbd/pbd/properties.h b/libs/pbd/pbd/properties.h index 784282ee9c..1914344db9 100644 --- a/libs/pbd/pbd/properties.h +++ b/libs/pbd/pbd/properties.h @@ -165,7 +165,7 @@ public: : PropertyTemplate<T> (q, v) {} - void diff (PropertyList& undo, PropertyList& redo) const { + void diff (PropertyList& undo, PropertyList& redo, Command* /*ignored*/) const { if (this->_have_old) { undo.add (new Property<T> (this->property_id(), this->_old)); redo.add (new Property<T> (this->property_id(), this->_current)); @@ -227,7 +227,7 @@ public: : PropertyTemplate<std::string> (q, v) {} - void diff (PropertyList& before, PropertyList& after) const { + void diff (PropertyList& before, PropertyList& after, Command* /*ignored*/) const { if (this->_have_old) { before.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_old)); after.add (new Property<std::string> (PropertyDescriptor<std::string> (this->property_id()), this->_current)); diff --git a/libs/pbd/pbd/property_basics.h b/libs/pbd/pbd/property_basics.h index 5e94abdfc3..2dea20e251 100644 --- a/libs/pbd/pbd/property_basics.h +++ b/libs/pbd/pbd/property_basics.h @@ -25,6 +25,8 @@ #include "pbd/xml++.h" +class Command; + namespace PBD { class PropertyList; @@ -83,7 +85,7 @@ public: {} virtual ~PropertyBase () {} - + /** Forget about any old value for this state */ virtual void clear_history () = 0; @@ -97,7 +99,7 @@ public: * the last call to clear_history, and one that allows redo * of those changes. */ - virtual void diff (PropertyList& undo, PropertyList& redo) const = 0; + virtual void diff (PropertyList& undo, PropertyList& redo, Command*) const = 0; virtual PropertyBase* maybe_clone_self_if_found_in_history_node (const XMLNode&) const { return 0; } diff --git a/libs/pbd/pbd/stateful.h b/libs/pbd/pbd/stateful.h index 4352e88201..1272a735f9 100644 --- a/libs/pbd/pbd/stateful.h +++ b/libs/pbd/pbd/stateful.h @@ -67,7 +67,7 @@ class Stateful { /* history management */ void clear_history (); - void diff (PropertyList&, PropertyList&) const; + void diff (PropertyList&, PropertyList&, Command*) const; bool changed() const; /* create a property list from an XMLNode diff --git a/libs/pbd/pbd/stateful_diff_command.h b/libs/pbd/pbd/stateful_diff_command.h index 21245f029a..25cdfbba12 100644 --- a/libs/pbd/pbd/stateful_diff_command.h +++ b/libs/pbd/pbd/stateful_diff_command.h @@ -27,7 +27,7 @@ namespace PBD { -class Stateful; +class StatefulDestructible; class PropertyList; /** A Command which stores its action as the differences between the before and after @@ -36,13 +36,13 @@ class PropertyList; class StatefulDiffCommand : public Command { public: - StatefulDiffCommand (boost::shared_ptr<Stateful>); - StatefulDiffCommand (boost::shared_ptr<Stateful>, XMLNode const &); + StatefulDiffCommand (boost::shared_ptr<StatefulDestructible>); + StatefulDiffCommand (boost::shared_ptr<StatefulDestructible>, XMLNode const &); ~StatefulDiffCommand (); void operator() (); void undo (); - + XMLNode& get_state (); private: diff --git a/libs/pbd/pbd/undo.h b/libs/pbd/pbd/undo.h index 6eb9e00056..fb5152c293 100644 --- a/libs/pbd/pbd/undo.h +++ b/libs/pbd/pbd/undo.h @@ -27,12 +27,11 @@ #include <sigc++/bind.h> #include <sys/time.h> -#include "pbd/signals.h" #include "pbd/command.h" typedef sigc::slot<void> UndoAction; -class UndoTransaction : public Command, public PBD::ScopedConnectionList +class UndoTransaction : public Command { public: UndoTransaction (); diff --git a/libs/pbd/stateful.cc b/libs/pbd/stateful.cc index b486319c4c..1c3d08b3a9 100644 --- a/libs/pbd/stateful.cc +++ b/libs/pbd/stateful.cc @@ -167,10 +167,10 @@ Stateful::clear_history () } void -Stateful::diff (PropertyList& before, PropertyList& after) const +Stateful::diff (PropertyList& before, PropertyList& after, Command* cmd) const { for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) { - i->second->diff (before, after); + i->second->diff (before, after, cmd); } } diff --git a/libs/pbd/stateful_diff_command.cc b/libs/pbd/stateful_diff_command.cc index 635fe4829a..2c58acee14 100644 --- a/libs/pbd/stateful_diff_command.cc +++ b/libs/pbd/stateful_diff_command.cc @@ -32,15 +32,21 @@ using namespace PBD; * @param s Stateful object. */ -StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<Stateful> s) - : _object (s) +StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible> s) + : _object (s) , _undo (new PropertyList) , _redo (new PropertyList) { - s->diff (*_undo, *_redo); + s->diff (*_undo, *_redo, this); + + /* if the stateful object that this command refers to goes away, + be sure to notify owners of this command. + */ + + s->DropReferences.connect_same_thread (*this, boost::bind (&Destructible::drop_references, this)); } -StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<Stateful> s, XMLNode const & n) +StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible> s, XMLNode const & n) : _object (s) , _undo (0) , _redo (0) @@ -57,10 +63,18 @@ StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<Stateful> s, XMLNode assert (_undo != 0); assert (_redo != 0); + + /* if the stateful object that this command refers to goes away, + be sure to notify owners of this command. + */ + + s->DropReferences.connect_same_thread (*this, boost::bind (&Destructible::drop_references, this)); } StatefulDiffCommand::~StatefulDiffCommand () { + drop_references (); + delete _undo; delete _redo; } diff --git a/libs/pbd/undo.cc b/libs/pbd/undo.cc index a06127926f..120f62c351 100644 --- a/libs/pbd/undo.cc +++ b/libs/pbd/undo.cc @@ -39,7 +39,6 @@ UndoTransaction::UndoTransaction () UndoTransaction::UndoTransaction (const UndoTransaction& rhs) : Command(rhs._name) - , PBD::ScopedConnectionList () , _clearing(false) { clear (); @@ -77,15 +76,15 @@ UndoTransaction::operator= (const UndoTransaction& rhs) } void -UndoTransaction::add_command (Command *const action) +UndoTransaction::add_command (Command *const cmd) { /* catch death of command (e.g. caused by death of object to which it refers. command_death() is a normal static function so there is no need to manage this connection. */ - action->DropReferences.connect_same_thread (*this, boost::bind (&command_death, this, action)); - actions.push_back (action); + cmd->DropReferences.connect_same_thread (*this, boost::bind (&command_death, this, cmd)); + actions.push_back (cmd); } void @@ -250,9 +249,6 @@ UndoHistory::undo (unsigned int n) return; } - struct timeval start, end, diff; - gettimeofday (&start, 0); - { UndoRedoSignaller exception_safe_signaller (*this); @@ -265,16 +261,8 @@ UndoHistory::undo (unsigned int n) ut->undo (); RedoList.push_back (ut); } - gettimeofday (&end, 0); - timersub (&end, &start, &diff); - cerr << "Undo-pre-signals took " << diff.tv_sec << '.' << diff.tv_usec << endl; - } - gettimeofday (&end, 0); - timersub (&end, &start, &diff); - cerr << "Undo took " << diff.tv_sec << '.' << diff.tv_usec << endl; - Changed (); /* EMIT SIGNAL */ } @@ -285,9 +273,6 @@ UndoHistory::redo (unsigned int n) return; } - struct timeval start, end, diff; - gettimeofday (&start, 0); - { UndoRedoSignaller exception_safe_signaller (*this); @@ -300,15 +285,8 @@ UndoHistory::redo (unsigned int n) ut->redo (); UndoList.push_back (ut); } - gettimeofday (&end, 0); - timersub (&end, &start, &diff); - cerr << "Redo-pre-signals took " << diff.tv_sec << '.' << diff.tv_usec << endl; } - gettimeofday (&end, 0); - timersub (&end, &start, &diff); - cerr << "Redo took " << diff.tv_sec << '.' << diff.tv_usec << endl; - Changed (); /* EMIT SIGNAL */ } |