summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2010-07-16 14:55:11 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2010-07-16 14:55:11 +0000
commitc8e3f32533cc6f4481222781d93e7bf7c32ffe5f (patch)
tree94f6c8a687459ebeaaa259acc4da1832ff2bd303 /libs
parente9ab577177db3c37719331c00900e48d4dfbf158 (diff)
newly created files for use in recording appear in a .stubs folder, and are moved out of it when recording stops
git-svn-id: svn://localhost/ardour2/branches/3.0@7426 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/coreaudiosource.h2
-rw-r--r--libs/ardour/ardour/directory_names.h1
-rw-r--r--libs/ardour/ardour/file_source.h6
-rw-r--r--libs/ardour/ardour/session.h10
-rw-r--r--libs/ardour/ardour/session_directory.h18
-rw-r--r--libs/ardour/ardour/smf_source.h5
-rw-r--r--libs/ardour/ardour/sndfilesource.h1
-rw-r--r--libs/ardour/ardour/source.h4
-rw-r--r--libs/ardour/ardour/types.h3
-rw-r--r--libs/ardour/audio_diskstream.cc17
-rw-r--r--libs/ardour/coreaudiosource.cc6
-rw-r--r--libs/ardour/directory_names.cc1
-rw-r--r--libs/ardour/file_source.cc68
-rw-r--r--libs/ardour/midi_diskstream.cc37
-rw-r--r--libs/ardour/midi_source.cc28
-rw-r--r--libs/ardour/playlist_factory.cc5
-rw-r--r--libs/ardour/region.cc1
-rw-r--r--libs/ardour/session.cc80
-rw-r--r--libs/ardour/session_directory.cc15
-rw-r--r--libs/ardour/session_state.cc108
-rw-r--r--libs/ardour/session_transport.cc11
-rw-r--r--libs/ardour/smf_source.cc9
-rw-r--r--libs/ardour/sndfilesource.cc10
-rw-r--r--libs/ardour/source.cc6
-rw-r--r--libs/evoral/evoral/SMF.hpp5
-rw-r--r--libs/evoral/src/SMF.cpp19
-rw-r--r--libs/pbd/file_manager.cc21
-rw-r--r--libs/pbd/pbd/file_manager.h5
-rw-r--r--libs/pbd/sndfile_manager.cc2
-rw-r--r--libs/pbd/wscript1
30 files changed, 328 insertions, 177 deletions
diff --git a/libs/ardour/ardour/coreaudiosource.h b/libs/ardour/ardour/coreaudiosource.h
index f25f1b0154..33a493b040 100644
--- a/libs/ardour/ardour/coreaudiosource.h
+++ b/libs/ardour/ardour/coreaudiosource.h
@@ -34,6 +34,8 @@ class CoreAudioSource : public AudioFileSource {
CoreAudioSource (ARDOUR::Session&, const string& path, int chn, Flag);
~CoreAudioSource ();
+ void set_path (const std::string& p);
+
float sample_rate() const;
int update_header (sframes_t when, struct tm&, time_t);
diff --git a/libs/ardour/ardour/directory_names.h b/libs/ardour/ardour/directory_names.h
index cd3217b3b9..9cce077ad0 100644
--- a/libs/ardour/ardour/directory_names.h
+++ b/libs/ardour/ardour/directory_names.h
@@ -20,6 +20,7 @@ extern const char* const templates_dir_name;
extern const char* const route_templates_dir_name;
extern const char* const surfaces_dir_name;
extern const char* const user_config_dir_name;
+extern const char* const stub_dir_name;
};
diff --git a/libs/ardour/ardour/file_source.h b/libs/ardour/ardour/file_source.h
index 38449def26..dfb1b43e58 100644
--- a/libs/ardour/ardour/file_source.h
+++ b/libs/ardour/ardour/file_source.h
@@ -35,6 +35,9 @@ public:
class FileSource : virtual public Source {
public:
const Glib::ustring& path() const { return _path; }
+
+ int unstubify ();
+ void stubify ();
virtual bool safe_file_extension (const Glib::ustring& path) const = 0;
@@ -57,6 +60,8 @@ public:
bool must_exist, bool& is_new, uint16_t& chan,
Glib::ustring& found_path);
+ void inc_use_count ();
+
protected:
FileSource (Session& session, DataType type,
const Glib::ustring& path,
@@ -66,6 +71,7 @@ protected:
virtual int init (const Glib::ustring& idstr, bool must_exist);
+ virtual void set_path (const std::string&);
virtual int move_dependents_to_trash() { return 0; }
void set_within_session_from_path (const std::string&);
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 5255654005..aa75cb17e6 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -185,7 +185,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
std::string peak_path_from_audio_path (std::string) const;
std::string new_audio_source_name (const std::string&, uint32_t nchans, uint32_t chan, bool destructive);
std::string new_midi_source_name (const std::string&);
- std::string new_source_path_from_name (DataType type, const std::string&);
+ std::string new_source_path_from_name (DataType type, const std::string&, bool as_stub = false);
RouteList new_route_from_template (uint32_t how_many, const std::string& template_path);
void process (nframes_t nframes);
@@ -533,9 +533,10 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
*/
static PBD::Signal0<int> AskAboutPendingState;
- boost::shared_ptr<AudioFileSource> create_audio_source_for_session (size_t, std::string const &, uint32_t, bool);
-
- boost::shared_ptr<MidiSource> create_midi_source_for_session (Track*, std::string const &);
+ boost::shared_ptr<AudioFileSource> create_audio_source_for_session (size_t, std::string const &, uint32_t,
+ bool destructive, bool as_stub = false);
+
+ boost::shared_ptr<MidiSource> create_midi_source_for_session (Track*, std::string const &, bool as_stub = false);
boost::shared_ptr<Source> source_by_id (const PBD::ID&);
boost::shared_ptr<Source> source_by_path_and_channel (const Glib::ustring&, uint16_t);
@@ -1415,6 +1416,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void add_session_range_location (nframes_t, nframes_t);
void setup_midi_machine_control ();
+ void cleanup_stubfiles ();
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/session_directory.h b/libs/ardour/ardour/session_directory.h
index ae6aa256cb..bcde4bdf2c 100644
--- a/libs/ardour/ardour/session_directory.h
+++ b/libs/ardour/ardour/session_directory.h
@@ -53,6 +53,17 @@ public:
/**
* @return the absolute path to the directory in which
+ * the session stores STUB audio files.
+ *
+ * If the session is an older session with an existing
+ * "sounds" directory then it will return a path to that
+ * directory otherwise it will return the new location
+ * of root_path()/interchange/session_name/audiofiles/.stubs
+ */
+ const PBD::sys::path sound_stub_path () const;
+
+ /**
+ * @return the absolute path to the directory in which
* the session stores MIDI files, ie
* root_path()/interchange/session_name/midifiles
*/
@@ -60,6 +71,13 @@ public:
/**
* @return the absolute path to the directory in which
+ * the session stores STUB MIDI files, ie
+ * root_path()/interchange/session_name/midifiles/.stubs
+ */
+ const PBD::sys::path midi_stub_path () const;
+
+ /**
+ * @return the absolute path to the directory in which
* the session stores MIDNAM patch files, ie
* root_path()/interchange/session_name/patchfiles
*/
diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h
index 6dcea9dd60..956fb6c75f 100644
--- a/libs/ardour/ardour/smf_source.h
+++ b/libs/ardour/ardour/smf_source.h
@@ -69,7 +69,10 @@ public:
static bool safe_midi_file_extension (const Glib::ustring& path);
-private:
+ protected:
+ void set_path (const std::string& newpath);
+
+ private:
nframes_t read_unlocked (Evoral::EventSink<nframes_t>& dst,
sframes_t position,
sframes_t start,
diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h
index 9a01892ccf..151889dbb5 100644
--- a/libs/ardour/ardour/sndfilesource.h
+++ b/libs/ardour/ardour/sndfilesource.h
@@ -66,6 +66,7 @@ class SndFileSource : public AudioFileSource {
static int get_soundfile_info (const Glib::ustring& path, SoundFileInfo& _info, std::string& error_msg);
protected:
+ void set_path (const std::string& p);
void set_header_timeline_position ();
framecnt_t read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const;
diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h
index 6f750e6fd0..cb46e90085 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -105,8 +105,8 @@ 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 ();
+ virtual void inc_use_count ();
+ virtual void dec_use_count ();
int use_count() const { return g_atomic_int_get (&_use_count); }
bool used() const { return use_count() > 0; }
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index cff8a12fd5..c666545dfa 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -27,6 +27,7 @@
#include <istream>
#include <vector>
#include <boost/shared_ptr.hpp>
+#include <sys/types.h>
#include <inttypes.h>
#include <jack/types.h>
@@ -440,7 +441,7 @@ namespace ARDOUR {
struct CleanupReport {
std::vector<std::string> paths;
- int64_t space;
+ size_t space;
};
enum PositionLockStyle {
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index 6dc29a510b..5a68f78e96 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -1388,6 +1388,7 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
(*chan)->write_source->mark_for_remove ();
(*chan)->write_source->drop_references ();
+ _session.remove_source ((*chan)->write_source);
(*chan)->write_source.reset ();
}
@@ -1409,9 +1410,13 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
if (s) {
srcs.push_back (s);
+ if (s->unstubify ()) {
+ error << string_compose (_("Could not move capture file from %1"), s->path()) << endmsg;
+ }
s->update_header (capture_info.front()->start, when, twhen);
s->set_captured_for (_name.val());
s->mark_immutable ();
+
if (Config->get_auto_analyse_audio()) {
Analyser::queue_source_for_analysis (s, true);
}
@@ -1880,7 +1885,13 @@ AudioDiskstream::use_new_write_source (uint32_t n)
}
try {
- if ((chan->write_source = _session.create_audio_source_for_session (n_channels().n_audio(), name(), n, destructive())) == 0) {
+ /* file starts off as a stub file, it will be converted
+ when we're done with a capture pass.
+ */
+
+ if ((chan->write_source = _session.create_audio_source_for_session (n_channels().n_audio(),
+ name(), n, destructive(),
+ true)) == 0) {
throw failed_constructor();
}
}
@@ -1895,10 +1906,6 @@ AudioDiskstream::use_new_write_source (uint32_t n)
chan->write_source->set_allow_remove_if_empty (!destructive());
- /* until we write, this file is considered removable */
-
- chan->write_source->mark_for_remove ();
-
return 0;
}
diff --git a/libs/ardour/coreaudiosource.cc b/libs/ardour/coreaudiosource.cc
index 1b3a77bc39..6878069398 100644
--- a/libs/ardour/coreaudiosource.cc
+++ b/libs/ardour/coreaudiosource.cc
@@ -368,3 +368,9 @@ CoreAudioSource::get_soundfile_info (string path, SoundFileInfo& _info, string&
return ret;
}
+
+void
+CoreAudioSource::set_path (const string& p)
+{
+ FileSource::set_path (p);
+}
diff --git a/libs/ardour/directory_names.cc b/libs/ardour/directory_names.cc
index a843fff67f..d6e2f94455 100644
--- a/libs/ardour/directory_names.cc
+++ b/libs/ardour/directory_names.cc
@@ -17,5 +17,6 @@ const char* const templates_dir_name = X_("templates");
const char* const route_templates_dir_name = X_("route_templates");
const char* const surfaces_dir_name = X_("surfaces");
const char* const user_config_dir_name = X_("ardour3");
+const char* const stub_dir_name = X_(".stubs");
}
diff --git a/libs/ardour/file_source.cc b/libs/ardour/file_source.cc
index be68c0c405..2fd978e172 100644
--- a/libs/ardour/file_source.cc
+++ b/libs/ardour/file_source.cc
@@ -39,6 +39,7 @@
#include <glibmm/thread.h>
#include "ardour/file_source.h"
+#include "ardour/directory_names.h"
#include "ardour/session.h"
#include "ardour/session_directory.h"
#include "ardour/source_factory.h"
@@ -51,8 +52,6 @@ using namespace ARDOUR;
using namespace PBD;
using namespace Glib;
-static const std::string PATH_SEP = "/"; // I don't do windows
-
map<DataType, ustring> FileSource::search_paths;
FileSource::FileSource (Session& session, DataType type, const ustring& path, Source::Flag flag)
@@ -80,9 +79,14 @@ FileSource::FileSource (Session& session, const XMLNode& node, bool /*must_exist
bool
FileSource::removable () const
{
- return (_flags & Removable)
- && ((_flags & RemoveAtDestroy) ||
- ((_flags & RemovableIfEmpty) && empty() == 0));
+ bool r = (_path.find (stub_dir_name) != string::npos) ||
+ ((_flags & Removable)
+ && ((_flags & RemoveAtDestroy) ||
+ ((_flags & RemovableIfEmpty) && empty() == 0)));
+
+ cerr << "is " << _path << " removable ? " << r << endl;
+
+ return r;
}
int
@@ -140,15 +144,16 @@ FileSource::move_to_trash (const ustring& trash_dir_name)
trash_dir_name directory on whichever filesystem it was already on
*/
- ustring newpath;
- newpath = Glib::path_get_dirname (_path);
- newpath = Glib::path_get_dirname (newpath);
+ vector<string> v;
+ v.push_back (Glib::path_get_dirname (Glib::path_get_dirname (_path)));
+ v.push_back (trash_dir_name);
+ v.push_back (Glib::path_get_basename (_path));
- newpath += string(PATH_SEP) + trash_dir_name + PATH_SEP;
- newpath += Glib::path_get_basename (_path);
+ string newpath = Glib::build_filename (v);
/* the new path already exists, try versioning */
- if (access (newpath.c_str(), F_OK) == 0) {
+
+ if (Glib::file_test (newpath.c_str(), Glib::FILE_TEST_EXISTS)) {
char buf[PATH_MAX+1];
int version = 1;
ustring newpath_v;
@@ -391,7 +396,7 @@ FileSource::set_source_name (const ustring& newname, bool destructive)
return -1;
}
- if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
+ if (::rename (oldpath.c_str(), newpath.c_str()) != 0) {
error << string_compose (_("cannot rename audio file %1 to %2"), _name, newpath) << endmsg;
return -1;
}
@@ -428,3 +433,42 @@ FileSource::set_within_session_from_path (const std::string& path)
{
_within_session = _session.path_is_within_session (path);
}
+
+int
+FileSource::unstubify ()
+{
+ string::size_type pos = _path.find (stub_dir_name);
+
+ if (pos == string::npos || (_flags & Destructive)) {
+ return 0;
+ }
+
+ vector<string> v;
+
+ v.push_back (Glib::path_get_dirname (Glib::path_get_dirname (_path)));
+ v.push_back (Glib::path_get_basename(_path));
+
+ string newpath = Glib::build_filename (v);
+
+ if (::rename (_path.c_str(), newpath.c_str()) != 0) {
+ error << string_compose (_("rename from %1 to %2 failed: %3)"), _path, newpath, strerror (errno)) << endmsg;
+ return -1;
+ }
+
+ set_path (newpath);
+
+ return 0;
+}
+
+void
+FileSource::set_path (const std::string& newpath)
+{
+ _path = newpath;
+}
+
+void
+FileSource::inc_use_count ()
+{
+ Source::inc_use_count ();
+}
+
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index 9c0abe53ef..08b3719301 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -957,14 +957,18 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
_write_source->mark_streaming_write_completed ();
+ /* make it not a stub anymore */
+
+ _write_source->unstubify ();
+
/* we will want to be able to keep (over)writing the source
but we don't want it to be removable. this also differs
from the audio situation, where the source at this point
- must be considered immutable
+ must be considered immutable. luckily, we can rely on
+ MidiSource::mark_streaming_write_completed() to have
+ already done the necessary work for that.
*/
- _write_source->mark_nonremovable ();
-
string whole_file_region_name;
whole_file_region_name = region_name_from_path (_write_source->name(), true);
@@ -1321,7 +1325,14 @@ MidiDiskstream::use_new_write_source (uint32_t n)
_write_source.reset();
try {
- _write_source = boost::dynamic_pointer_cast<SMFSource>(_session.create_midi_source_for_session (0, name ()));
+ /* file starts off as a stub file, it will be converted
+ when we're done with a capture pass, or when "stolen"
+ by the GUI.
+ */
+
+ _write_source = boost::dynamic_pointer_cast<SMFSource>(
+ _session.create_midi_source_for_session (0, name (), true));
+
if (!_write_source) {
throw failed_constructor();
}
@@ -1342,8 +1353,26 @@ list<boost::shared_ptr<Source> >
MidiDiskstream::steal_write_sources()
{
list<boost::shared_ptr<Source> > ret;
+
+ /* put some data on the disk, even if its just a header for an empty file.
+ XXX should we not have a more direct method for doing this? Maybe not
+ since we don't want to mess around with the model/disk relationship
+ that the Source has to pay attention to.
+ */
+
+ boost::dynamic_pointer_cast<MidiSource>(_write_source)->session_saved ();
+
+ /* make it visible/present */
+ _write_source->unstubify ();
+ /* never let it go away */
+ _write_source->mark_nonremovable ();
+
ret.push_back (_write_source);
+
+ /* get a new one */
+
use_new_write_source (0);
+
return ret;
}
diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc
index dbc41c8ab6..3f053eceeb 100644
--- a/libs/ardour/midi_source.cc
+++ b/libs/ardour/midi_source.cc
@@ -321,19 +321,11 @@ MidiSource::session_saved()
XXX do we need to do this every time?
*/
- flush_midi();
-
if (_model && _model->edited()) {
-#if 0 // old style: clone the source if necessary on every session save
- // and switch to the new source
- boost::shared_ptr<MidiSource> newsrc = clone ();
- if (newsrc) {
- _model->set_midi_source (newsrc);
- Switched (newsrc); /* EMIT SIGNAL */
- }
-#else
- // new style: if the model is edited, write its contents into
+
+
+ // if the model is edited, write its contents into
// the current source file (overwiting previous contents.
/* temporarily drop our reference to the model so that
@@ -343,13 +335,19 @@ MidiSource::session_saved()
boost::shared_ptr<MidiModel> mm = _model ;
_model.reset ();
+
+ /* flush model contents to disk
+ */
+
mm->sync_to_source ();
+
+ /* reacquire model */
+
_model = mm;
- /* data is in the file now, its not removable */
-#endif
- }
- cerr << name() << " @ " << this << " length at save = " << _length_beats << endl;
+ } else {
+ flush_midi();
+ }
}
void
diff --git a/libs/ardour/playlist_factory.cc b/libs/ardour/playlist_factory.cc
index 2619d0e0c4..00996a059d 100644
--- a/libs/ardour/playlist_factory.cc
+++ b/libs/ardour/playlist_factory.cc
@@ -40,10 +40,11 @@ PlaylistFactory::create (Session& s, const XMLNode& node, bool hidden, bool unus
boost::shared_ptr<Playlist> pl;
- if ( !type || type->value() == "audio" )
+ if (!type || type->value() == "audio") {
pl = boost::shared_ptr<Playlist> (new AudioPlaylist (s, node, hidden));
- else if ( type->value() == "midi" )
+ } else if (type->value() == "midi") {
pl = boost::shared_ptr<Playlist> (new MidiPlaylist (s, node, hidden));
+ }
pl->set_region_ownership ();
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 9d8e4e8ca0..a4de9fc8b7 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -1388,7 +1388,6 @@ void
Region::set_master_sources (const SourceList& srcs)
{
for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
- cerr << name() << " " << id() << " DEC M SMS\n";
(*i)->dec_use_count ();
}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 4e59a73f5f..9f0bbf7439 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -226,6 +226,10 @@ Session::destroy ()
delete state_tree;
+ /* remove all stubfiles that might still be lurking */
+
+ cleanup_stubfiles ();
+
/* reset dynamic state version back to default */
Stateful::loading_state_version = 0;
@@ -2606,6 +2610,7 @@ Session::remove_source (boost::weak_ptr<Source> src)
Glib::Mutex::Lock lm (source_lock);
if ((i = sources.find (source->id())) != sources.end()) {
+ cerr << "Removing source " << source->name() << endl;
sources.erase (i);
}
}
@@ -2640,7 +2645,6 @@ Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn)
Glib::Mutex::Lock lm (source_lock);
for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
- cerr << "comparing " << path << " with " << i->second->name() << endl;
boost::shared_ptr<AudioFileSource> afs
= boost::dynamic_pointer_cast<AudioFileSource>(i->second);
@@ -2670,18 +2674,12 @@ Session::change_source_path_by_name (string path, string oldname, string newname
the task here is to replace NAME with the new name.
*/
- /* find last slash */
-
string dir;
string prefix;
- string::size_type slash;
string::size_type dash;
- if ((slash = path.find_last_of ('/')) == string::npos) {
- return "";
- }
-
- dir = path.substr (0, slash+1);
+ dir = Glib::path_get_dirname (path);
+ path = Glib::path_get_basename (path);
/* '-' is not a legal character for the NAME part of the path */
@@ -2689,7 +2687,7 @@ Session::change_source_path_by_name (string path, string oldname, string newname
return "";
}
- prefix = path.substr (slash+1, dash-(slash+1));
+ prefix = path.substr (0, dash);
path = dir;
path += prefix;
@@ -2708,17 +2706,11 @@ Session::change_source_path_by_name (string path, string oldname, string newname
string dir;
string suffix;
- string::size_type slash;
string::size_type dash;
string::size_type postfix;
- /* find last slash */
-
- if ((slash = path.find_last_of ('/')) == string::npos) {
- return "";
- }
-
- dir = path.substr (0, slash+1);
+ dir = Glib::path_get_dirname (path);
+ path = Glib::path_get_basename (path);
/* '-' is not a legal character for the NAME part of the path */
@@ -2750,7 +2742,7 @@ Session::change_source_path_by_name (string path, string oldname, string newname
snprintf (buf, sizeof(buf), "%s%s-%u%s", dir.c_str(), newname.c_str(), cnt, suffix.c_str());
- if (access (buf, F_OK) != 0) {
+ if (!Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
path = buf;
break;
}
@@ -2771,7 +2763,7 @@ Session::change_source_path_by_name (string path, string oldname, string newname
* (e.g. as returned by new_*_source_name)
*/
string
-Session::new_source_path_from_name (DataType type, const string& name)
+Session::new_source_path_from_name (DataType type, const string& name, bool as_stub)
{
assert(name.find("/") == string::npos);
@@ -2779,9 +2771,9 @@ Session::new_source_path_from_name (DataType type, const string& name)
sys::path p;
if (type == DataType::AUDIO) {
- p = sdir.sound_path();
+ p = (as_stub ? sdir.sound_stub_path() : sdir.sound_path());
} else if (type == DataType::MIDI) {
- p = sdir.midi_path();
+ p = (as_stub ? sdir.midi_stub_path() : sdir.midi_path());
} else {
error << "Unknown source type, unable to create file path" << endmsg;
return "";
@@ -2889,10 +2881,10 @@ Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t cha
/** Create a new within-session audio source */
boost::shared_ptr<AudioFileSource>
-Session::create_audio_source_for_session (size_t n_chans, string const & n, uint32_t chan, bool destructive)
+Session::create_audio_source_for_session (size_t n_chans, string const & n, uint32_t chan, bool destructive, bool as_stub)
{
const string name = new_audio_source_name (n, n_chans, chan, destructive);
- const string path = new_source_path_from_name(DataType::AUDIO, name);
+ const string path = new_source_path_from_name(DataType::AUDIO, name, as_stub);
return boost::dynamic_pointer_cast<AudioFileSource> (
SourceFactory::createWritable (DataType::AUDIO, *this, path, destructive, frame_rate()));
@@ -2949,7 +2941,7 @@ Session::new_midi_source_name (const string& base)
/** Create a new within-session MIDI source */
boost::shared_ptr<MidiSource>
-Session::create_midi_source_for_session (Track* track, string const & n)
+Session::create_midi_source_for_session (Track* track, string const & n, bool as_stub)
{
/* try to use the existing write source for the track, to keep numbering sane
*/
@@ -2968,7 +2960,7 @@ Session::create_midi_source_for_session (Track* track, string const & n)
}
const string name = new_midi_source_name (n);
- const string path = new_source_path_from_name (DataType::MIDI, name);
+ const string path = new_source_path_from_name (DataType::MIDI, name, as_stub);
return boost::dynamic_pointer_cast<SMFSource> (
SourceFactory::createWritable (
@@ -3067,42 +3059,6 @@ Session::RoutePublicOrderSorter::operator() (boost::shared_ptr<Route> a, boost::
return a->order_key(N_("signal")) < b->order_key(N_("signal"));
}
-void
-Session::remove_empty_sounds ()
-{
- vector<string> audio_filenames;
-
- get_files_in_directory (_session_dir->sound_path(), audio_filenames);
-
- Glib::Mutex::Lock lm (source_lock);
-
- TapeFileMatcher tape_file_matcher;
-
- remove_if (audio_filenames.begin(), audio_filenames.end(),
- boost::bind (&TapeFileMatcher::matches, &tape_file_matcher, _1));
-
- for (vector<string>::iterator i = audio_filenames.begin(); i != audio_filenames.end(); ++i) {
-
- sys::path audio_file_path (_session_dir->sound_path());
-
- audio_file_path /= *i;
-
- if (AudioFileSource::is_empty (*this, audio_file_path.to_string())) {
-
- try
- {
- sys::remove (audio_file_path);
- const string peakfile = peak_path (audio_file_path.to_string());
- sys::remove (peakfile);
- }
- catch (const sys::filesystem_error& err)
- {
- error << err.what() << endmsg;
- }
- }
- }
-}
-
bool
Session::is_auditioning () const
{
diff --git a/libs/ardour/session_directory.cc b/libs/ardour/session_directory.cc
index 09c2154c30..a848ceee4b 100644
--- a/libs/ardour/session_directory.cc
+++ b/libs/ardour/session_directory.cc
@@ -102,12 +102,27 @@ SessionDirectory::sound_path () const
}
const path
+SessionDirectory::sound_stub_path () const
+{
+ if(is_directory (old_sound_path ())) return old_sound_path();
+
+ // the new style sound directory
+ return sources_root() / sound_dir_name / stub_dir_name;
+}
+
+const path
SessionDirectory::midi_path () const
{
return sources_root() / midi_dir_name;
}
const path
+SessionDirectory::midi_stub_path () const
+{
+ return sources_root() / midi_dir_name / stub_dir_name;
+}
+
+const path
SessionDirectory::midi_patch_path () const
{
return sources_root() / midi_patch_dir_name;
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index 7f067ae407..8bb3fa1ff0 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -41,7 +41,6 @@
#include <signal.h>
#include <sys/mman.h>
#include <sys/time.h>
-#include <dirent.h>
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
@@ -66,6 +65,7 @@
#include "pbd/search_path.h"
#include "pbd/stacktrace.h"
#include "pbd/convert.h"
+#include "pbd/clear_dir.h"
#include "ardour/amp.h"
#include "ardour/audio_diskstream.h"
@@ -288,7 +288,7 @@ Session::second_stage_init ()
if (load_state (_current_snapshot_name)) {
return -1;
}
- remove_empty_sounds ();
+ cleanup_stubfiles ();
}
if (_butler->start_thread()) {
@@ -460,6 +460,13 @@ Session::ensure_subdirs ()
return -1;
}
+ dir = session_directory().sound_stub_path().to_string();
+
+ if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session stub sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ return -1;
+ }
+
dir = session_directory().midi_path().to_string();
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
@@ -467,6 +474,13 @@ Session::ensure_subdirs ()
return -1;
}
+ dir = session_directory().midi_stub_path().to_string();
+
+ if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session stub midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
+ return -1;
+ }
+
dir = session_directory().dead_sound_path().to_string();
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
@@ -1595,15 +1609,11 @@ Session::XMLRegionFactory (const XMLNode& node, bool full)
try {
- if ( !type || type->value() == "audio" ) {
-
- return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
-
- } else if (type->value() == "midi") {
-
- return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
-
- }
+ if (!type || type->value() == "audio") {
+ return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
+ } else if (type->value() == "midi") {
+ return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
+ }
} catch (failed_constructor& err) {
return boost::shared_ptr<Region> ();
@@ -1738,24 +1748,16 @@ Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
boost::shared_ptr<Source> source;
boost::shared_ptr<MidiSource> ms;
SourceList sources;
- uint32_t nchans = 1;
if (node.name() != X_("Region")) {
return boost::shared_ptr<MidiRegion>();
}
- if ((prop = node.property (X_("channels"))) != 0) {
- nchans = atoi (prop->value().c_str());
- }
-
if ((prop = node.property ("name")) == 0) {
cerr << "no name for this region\n";
abort ();
}
- // Multiple midi channels? that's just crazy talk
- assert(nchans == 1);
-
if ((prop = node.property (X_("source-0"))) == 0) {
if ((prop = node.property ("source")) == 0) {
error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
@@ -2339,6 +2341,10 @@ Session::commit_reversible_command(Command *cmd)
static bool
accept_all_non_peak_files (const string& path, void */*arg*/)
{
+ if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
+ return false;
+ }
+
return (path.length() > 5 && path.find (peakfile_suffix) != (path.length() - 5));
}
@@ -2710,9 +2716,6 @@ Session::cleanup_trash_sources (CleanupReport& rep)
vector<space_and_path>::iterator i;
string dead_sound_dir;
- struct dirent* dentry;
- struct stat statbuf;
- DIR* dead;
rep.paths.clear ();
rep.space = 0;
@@ -2722,48 +2725,49 @@ Session::cleanup_trash_sources (CleanupReport& rep)
dead_sound_dir = (*i).path;
dead_sound_dir += dead_sound_dir_name;
- if ((dead = opendir (dead_sound_dir.c_str())) == 0) {
- continue;
- }
+ clear_directory (dead_sound_dir, &rep.space, &rep.paths);
+ }
- while ((dentry = readdir (dead)) != 0) {
+ return 0;
+}
- /* avoid '.' and '..' */
+void
+Session::cleanup_stubfiles ()
+{
+ vector<space_and_path>::iterator i;
- if ((dentry->d_name[0] == '.' && dentry->d_name[1] == '\0') ||
- (dentry->d_name[2] == '\0' && dentry->d_name[0] == '.' && dentry->d_name[1] == '.')) {
- continue;
- }
+ for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
- string fullpath;
+ string dir;
+ string lname = legalize_for_path (_name);
- fullpath = dead_sound_dir;
- fullpath += '/';
- fullpath += dentry->d_name;
+ vector<string> v;
- if (stat (fullpath.c_str(), &statbuf)) {
- continue;
- }
+ /* XXX this is a hack caused by semantic conflicts
+ between space_and_path and the SessionDirectory concept.
+ */
- if (!S_ISREG (statbuf.st_mode)) {
- continue;
- }
+ v.push_back ((*i).path);
+ v.push_back ("interchange");
+ v.push_back (lname);
+ v.push_back ("audiofiles");
+ v.push_back (stub_dir_name);
- if (unlink (fullpath.c_str())) {
- error << string_compose (_("cannot remove dead sound file %1 (%2)"),
- fullpath, strerror (errno))
- << endmsg;
- }
+ dir = Glib::build_filename (v);
+
+ clear_directory (dir);
- rep.paths.push_back (dentry->d_name);
- rep.space += statbuf.st_size;
- }
+ v.clear ();
+ v.push_back ((*i).path);
+ v.push_back ("interchange");
+ v.push_back (lname);
+ v.push_back ("midifiles");
+ v.push_back (stub_dir_name);
- closedir (dead);
+ dir = Glib::build_filename (v);
+ clear_directory (dir);
}
-
- return 0;
}
void
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index f737b194c0..2897c5cd8f 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -432,6 +432,13 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
}
DEBUG_TRACE (DEBUG::Transport, X_("Butler PTW: DS stop\n"));
+
+ if (abort && did_record) {
+ /* no reason to save the session file when we remove sources
+ */
+ _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
+ }
+
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
if (tr) {
@@ -439,6 +446,10 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
}
}
+ if (abort && did_record) {
+ _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
+ }
+
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index bbdf958815..f8a2d10e97 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -99,7 +99,6 @@ SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist)
SMFSource::~SMFSource ()
{
if (removable()) {
- cerr << name() << " is removable, empty ? " << empty() << " UC " << use_count() << endl;
unlink (_path.c_str());
}
}
@@ -170,7 +169,7 @@ SMFSource::read_unlocked (Evoral::EventSink<nframes_t>& destination, sframes_t s
assert(time >= start_ticks);
const sframes_t ev_frame_time = converter.to(time / (double)ppqn()) + stamp_offset;
-#if 1
+#if 0
cerr << " frames = " << ev_frame_time
<< " w/offset = " << ev_frame_time - negative_stamp_offset
<< endl;
@@ -494,3 +493,9 @@ SMFSource::flush_midi ()
mark_nonremovable ();
}
+void
+SMFSource::set_path (const string& p)
+{
+ FileSource::set_path (p);
+ SMF::set_path (_path);
+}
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc
index 0b67cd789e..28286dbebf 100644
--- a/libs/ardour/sndfilesource.cc
+++ b/libs/ardour/sndfilesource.cc
@@ -889,3 +889,13 @@ SndFileSource::file_closed ()
touch_peakfile ();
}
+
+void
+SndFileSource::set_path (const string& p)
+{
+ FileSource::set_path (p);
+
+ if (_descriptor) {
+ _descriptor->set_path (_path);
+ }
+}
diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc
index f819e6eb42..6ab907ba16 100644
--- a/libs/ardour/source.cc
+++ b/libs/ardour/source.cc
@@ -273,6 +273,12 @@ Source::set_allow_remove_if_empty (bool yn)
}
void
+Source::inc_use_count ()
+{
+ g_atomic_int_inc (&_use_count);
+}
+
+void
Source::dec_use_count ()
{
#ifndef NDEBUG
diff --git a/libs/evoral/evoral/SMF.hpp b/libs/evoral/evoral/SMF.hpp
index 7b77051238..a99514829d 100644
--- a/libs/evoral/evoral/SMF.hpp
+++ b/libs/evoral/evoral/SMF.hpp
@@ -66,7 +66,10 @@ public:
double round_to_file_precision (double val) const;
-private:
+ protected:
+ void set_path (const std::string& p);
+
+ private:
std::string _file_path;
smf_t* _smf;
smf_track_t* _smf_track;
diff --git a/libs/evoral/src/SMF.cpp b/libs/evoral/src/SMF.cpp
index 332547a13b..ef460c2eef 100644
--- a/libs/evoral/src/SMF.cpp
+++ b/libs/evoral/src/SMF.cpp
@@ -90,14 +90,13 @@ SMF::open(const std::string& path, int track) THROW_FILE_ERROR
return -1;
}
- _smf = smf_load (f);
- if (_smf == NULL) {
+ if ((_smf = smf_load (f)) == 0) {
return -1;
}
- _smf_track = smf_get_track_by_number(_smf, track);
- if (!_smf_track)
+ if ((_smf_track = smf_get_track_by_number(_smf, track)) == 0) {
return -2;
+ }
//cerr << "Track " << track << " # events: " << _smf_track->number_of_events << endl;
if (_smf_track->number_of_events == 0) {
@@ -157,15 +156,22 @@ void
SMF::close() THROW_FILE_ERROR
{
if (_smf) {
+#if 0
+ /* XXX why would we automatically save-on-close?
+ */
+
PBD::StdioFileDescriptor d (_file_path, "w+");
FILE* f = d.allocate ();
if (f == 0) {
throw FileError ();
}
+ cerr << "CLOSE: Save SMF to " << _file_path << endl;
+
if (smf_save(_smf, f) != 0) {
throw FileError();
}
+#endif
smf_delete(_smf);
_smf = 0;
_smf_track = 0;
@@ -294,5 +300,10 @@ SMF::round_to_file_precision (double val) const
return round (val * div) / div;
}
+void
+SMF::set_path (const std::string& p)
+{
+ _file_path = p;
+}
} // namespace Evoral
diff --git a/libs/pbd/file_manager.cc b/libs/pbd/file_manager.cc
index 0f05ecedc4..4d82e3d112 100644
--- a/libs/pbd/file_manager.cc
+++ b/libs/pbd/file_manager.cc
@@ -100,19 +100,19 @@ FileManager::allocate (FileDescriptor* d)
DEBUG::FileManager,
string_compose (
"closed file for %1 to release file handle; now have %2 of %3 open\n",
- (*oldest)->_name, _open, _max_open
+ (*oldest)->_path, _open, _max_open
)
);
}
if (d->open ()) {
- DEBUG_TRACE (DEBUG::FileManager, string_compose ("open of %1 failed.\n", d->_name));
+ DEBUG_TRACE (DEBUG::FileManager, string_compose ("open of %1 failed.\n", d->_path));
return true;
}
_open++;
- DEBUG_TRACE (DEBUG::FileManager, string_compose ("opened file for %1; now have %2 of %3 open.\n", d->_name, _open, _max_open));
+ DEBUG_TRACE (DEBUG::FileManager, string_compose ("opened file for %1; now have %2 of %3 open.\n", d->_path, _open, _max_open));
}
#ifdef __APPLE__
@@ -148,7 +148,7 @@ FileManager::remove (FileDescriptor* d)
close (d);
DEBUG_TRACE (
DEBUG::FileManager,
- string_compose ("closed file for %1; file is being removed; now have %2 of %3 open\n", d->_name, _open, _max_open)
+ string_compose ("closed file for %1; file is being removed; now have %2 of %3 open\n", d->_path, _open, _max_open)
);
}
@@ -168,7 +168,7 @@ FileManager::close (FileDescriptor* d)
FileDescriptor::FileDescriptor (string const & n, bool w)
: _refcount (0)
, _last_used (0)
- , _name (n)
+ , _path (n)
, _writeable (w)
{
@@ -224,7 +224,7 @@ FdFileDescriptor::open ()
{
/* we must have a lock on the FileManager's mutex */
- _fd = ::open (_name.c_str(), _writeable ? (O_RDWR | O_CREAT) : O_RDONLY, _mode);
+ _fd = ::open (_path.c_str(), _writeable ? (O_RDWR | O_CREAT) : O_RDONLY, _mode);
return (_fd == -1);
}
@@ -253,6 +253,13 @@ FdFileDescriptor::allocate ()
}
+void
+FileDescriptor::set_path (const string& p)
+{
+ assert (!is_open());
+ _path = p;
+}
+
/** @param n Filename.
* @param w true to open writeable, otherwise false.
*/
@@ -283,7 +290,7 @@ StdioFileDescriptor::open ()
{
/* we must have a lock on the FileManager's mutex */
- _file = fopen (_name.c_str(), _mode.c_str());
+ _file = fopen (_path.c_str(), _mode.c_str());
return (_file == 0);
}
diff --git a/libs/pbd/pbd/file_manager.h b/libs/pbd/pbd/file_manager.h
index 2d3650c2c5..5d957eaa5a 100644
--- a/libs/pbd/pbd/file_manager.h
+++ b/libs/pbd/pbd/file_manager.h
@@ -51,7 +51,10 @@ public:
FileDescriptor (std::string const &, bool);
virtual ~FileDescriptor () {}
+ const std::string& path() const { return _path; }
+
void release ();
+ virtual void set_path (const std::string&);
/** Emitted when the file is closed */
PBD::Signal0<void> Closed;
@@ -71,7 +74,7 @@ protected:
int _refcount; ///< number of active users of this file
double _last_used; ///< monotonic time that this file was last allocated
- std::string _name; ///< filename
+ std::string _path; ///< file path
bool _writeable; ///< true if it should be opened writeable, otherwise false
FileManager* manager ();
diff --git a/libs/pbd/sndfile_manager.cc b/libs/pbd/sndfile_manager.cc
index 5637de26ee..c6a52416ed 100644
--- a/libs/pbd/sndfile_manager.cc
+++ b/libs/pbd/sndfile_manager.cc
@@ -86,7 +86,7 @@ SndFileDescriptor::open ()
{
/* we must have a lock on the FileManager's mutex */
- _sndfile = sf_open (_name.c_str(), _writeable ? SFM_RDWR : SFM_READ, _info);
+ _sndfile = sf_open (_path.c_str(), _writeable ? SFM_RDWR : SFM_READ, _info);
return (_sndfile == 0);
}
diff --git a/libs/pbd/wscript b/libs/pbd/wscript
index a558a04da2..275db6d70d 100644
--- a/libs/pbd/wscript
+++ b/libs/pbd/wscript
@@ -59,6 +59,7 @@ def build(bld):
convert.cc
controllable.cc
controllable_descriptor.cc
+ clear_dir.cc
crossthread.cc
cpus.cc
debug.cc