midway snapshot of work done on managing Region & Source lifetimes correctly. may fix missing MIDI file bug ; save empty playlists because they may be referred to by the history file ; undo commands auto-delete when objects they refer to die (currently not commands built from XML deserialization); Sources now know how many regions are using them for something, meaning that we know if we can delete the files holding any data for the source

git-svn-id: svn://localhost/ardour2/branches/3.0@7291 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2010-06-23 20:14:07 +00:00
parent cac03dbeb6
commit f4401c5928
36 changed files with 310 additions and 220 deletions

View File

@ -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 ();
}
}

View File

@ -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));
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -270,6 +270,8 @@ class Region
return _pending_explicit_relayer;
}
void drop_sources ();
protected:
friend class RegionFactory;

View File

@ -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 ();

View File

@ -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 ();

View File

@ -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;

View File

@ -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 ();

View File

@ -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;

View File

@ -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());
}

View File

@ -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);

View File

@ -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;
}

View File

@ -435,18 +435,6 @@ Diskstream::set_name (const string& str)
return true;
}
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)
{

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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)));
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
set<boost::shared_ptr<Region> > relevant_regions;
{
if (region->playlist()) {
region->playlist()->destroy_region (region);
}
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 (vector<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) {
for (set<boost::shared_ptr<Region> >::iterator r = relevant_regions.begin(); r != relevant_regions.end(); ) {
set<boost::shared_ptr<Region> >::iterator tmp;
(*i)->mark_for_remove ();
(*i)->drop_references ();
tmp = r;
++tmp;
cerr << "Cleanup " << (*r)->name() << " UC = " << (*r).use_count() << endl;
playlists->destroy_region (*r);
RegionFactory::map_remove (*r);
(*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) {
/* yay, new source */
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);
}
}
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

View File

@ -219,6 +219,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)
{
@ -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");

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -22,10 +22,12 @@
#ifndef __lib_pbd_command_h__
#define __lib_pbd_command_h__
#include "pbd/statefuldestructible.h"
#include <boost/utility.hpp>
#include <string>
class Command : public PBD::StatefulDestructible, public boost::noncopyable
#include "pbd/signals.h"
#include "pbd/statefuldestructible.h"
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)(); }

View File

@ -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));

View File

@ -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; }

View File

@ -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

View File

@ -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:

View File

@ -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 ();

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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 */
}