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
This commit is contained in:
Paul Davis 2010-07-16 14:55:11 +00:00
parent e9ab577177
commit c8e3f32533
31 changed files with 345 additions and 194 deletions

View File

@ -33,11 +33,12 @@
#include "pbd/memento_command.h"
#include "pbd/stateful_diff_command.h"
#include <gtkmm2ext/gtk_ui.h>
#include <gtkmm2ext/selector.h>
#include <gtkmm2ext/bindable_button.h>
#include <gtkmm2ext/utils.h>
#include "gtkmm2ext/gtk_ui.h"
#include "gtkmm2ext/selector.h"
#include "gtkmm2ext/bindable_button.h"
#include "gtkmm2ext/utils.h"
#include "ardour/file_source.h"
#include "ardour/midi_playlist.h"
#include "ardour/midi_diskstream.h"
#include "ardour/midi_patch_manager.h"
@ -961,7 +962,6 @@ MidiTimeAxisView::add_region (nframes64_t pos)
boost::shared_ptr<Source> src = _session->create_midi_source_for_session (view()->trackview().track().get(),
view()->trackview().track()->name());
PropertyList plist;
plist.add (ARDOUR::Properties::start, 0);
@ -969,7 +969,7 @@ MidiTimeAxisView::add_region (nframes64_t pos)
plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
playlist()->add_region (region, start);
_session->add_command (new StatefulDiffCommand (playlist()));

View File

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

View File

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

View File

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

View File

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

View File

@ -51,6 +51,17 @@ public:
*/
const PBD::sys::path sound_path () const;
/**
* @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
@ -58,6 +69,13 @@ public:
*/
const PBD::sys::path midi_path () const;
/**
* @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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 ();
mm->sync_to_source ();
_model = mm;
/* data is in the file now, its not removable */
#endif
}
cerr << name() << " @ " << this << " length at save = " << _length_beats << endl;
/* flush model contents to disk
*/
mm->sync_to_source ();
/* reacquire model */
_model = mm;
} else {
flush_midi();
}
}
void

View File

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

View File

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

View File

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

View File

@ -101,12 +101,27 @@ SessionDirectory::sound_path () const
return sources_root() / sound_dir_name;
}
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
{

View File

@ -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,50 +2725,51 @@ 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;
}
while ((dentry = readdir (dead)) != 0) {
/* avoid '.' and '..' */
if ((dentry->d_name[0] == '.' && dentry->d_name[1] == '\0') ||
(dentry->d_name[2] == '\0' && dentry->d_name[0] == '.' && dentry->d_name[1] == '.')) {
continue;
}
string fullpath;
fullpath = dead_sound_dir;
fullpath += '/';
fullpath += dentry->d_name;
if (stat (fullpath.c_str(), &statbuf)) {
continue;
}
if (!S_ISREG (statbuf.st_mode)) {
continue;
}
if (unlink (fullpath.c_str())) {
error << string_compose (_("cannot remove dead sound file %1 (%2)"),
fullpath, strerror (errno))
<< endmsg;
}
rep.paths.push_back (dentry->d_name);
rep.space += statbuf.st_size;
}
closedir (dead);
clear_directory (dead_sound_dir, &rep.space, &rep.paths);
}
return 0;
}
void
Session::cleanup_stubfiles ()
{
vector<space_and_path>::iterator i;
for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
string dir;
string lname = legalize_for_path (_name);
vector<string> v;
/* XXX this is a hack caused by semantic conflicts
between space_and_path and the SessionDirectory concept.
*/
v.push_back ((*i).path);
v.push_back ("interchange");
v.push_back (lname);
v.push_back ("audiofiles");
v.push_back (stub_dir_name);
dir = Glib::build_filename (v);
clear_directory (dir);
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);
dir = Glib::build_filename (v);
clear_directory (dir);
}
}
void
Session::set_dirty ()
{

View File

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

View File

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

View File

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

View File

@ -272,6 +272,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 ()
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -59,6 +59,7 @@ def build(bld):
convert.cc
controllable.cc
controllable_descriptor.cc
clear_dir.cc
crossthread.cc
cpus.cc
debug.cc