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;
extern const char* const panner_dir_name;
};
const std::string& path() const { return _path; }
- int unstubify ();
- void stubify ();
- bool is_stub () const;
-
- static bool is_stub_path (const std::string& path);
-
virtual bool safe_file_extension (const std::string& path) const = 0;
int move_to_trash (const std::string& trash_dir_name);
uint16_t _channel;
bool _within_session;
std::string _origin;
-
+ bool _open;
+
void prevent_deletion ();
};
virtual framecnt_t length (framepos_t pos) const;
virtual void update_length (framepos_t pos, framecnt_t cnt);
- virtual void mark_streaming_midi_write_started (NoteMode mode, framepos_t start_time);
+ virtual void mark_streaming_midi_write_started (NoteMode mode);
virtual void mark_streaming_write_started ();
virtual void mark_streaming_write_completed ();
void mark_write_starting_now ();
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&, bool as_stub = false);
+ std::string new_source_path_from_name (DataType type, const std::string&);
RouteList new_route_from_template (uint32_t how_many, const std::string& template_path);
void process (pframes_t nframes);
static PBD::Signal0<int> AskAboutPendingState;
boost::shared_ptr<AudioFileSource> create_audio_source_for_session (
- size_t, std::string const &, uint32_t, bool destructive, bool as_stub = false);
+ size_t, std::string const &, uint32_t, bool destructive);
boost::shared_ptr<MidiSource> create_midi_source_for_session (
- Track*, std::string const &, bool as_stub = false);
+ Track*, std::string const &);
boost::shared_ptr<Source> source_by_id (const PBD::ID&);
boost::shared_ptr<Source> source_by_path_and_channel (const std::string&, uint16_t);
void add_session_range_location (framepos_t, framepos_t);
void setup_midi_machine_control ();
- void cleanup_stubfiles ();
void route_order_key_changed ();
*/
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
*/
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
void append_event_unlocked_beats (const Evoral::Event<Evoral::MusicalTime>& ev);
void append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, framepos_t source_start);
- void mark_streaming_midi_write_started (NoteMode mode, framepos_t start_time);
+ void mark_streaming_midi_write_started (NoteMode mode);
void mark_streaming_write_completed ();
XMLNode& get_state ();
void set_path (const std::string& newpath);
private:
+ int open_for_write ();
+
framecnt_t read_unlocked (Evoral::EventSink<framepos_t>& dst,
framepos_t position,
framepos_t start,
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 ();
ChannelInfo* chan = (*c)[n];
try {
- /* 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) {
+ name(), n, destructive())) == 0) {
throw failed_constructor();
}
}
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");
const char* const panner_dir_name = X_("panners");
}
, _file_is_new(true)
, _channel (0)
, _origin (origin)
+ , _open (false)
{
set_within_session_from_path (path);
bool
FileSource::removable () const
{
- bool r = (_path.find (stub_dir_name) != string::npos) ||
- ((_flags & Removable)
- && ((_flags & RemoveAtDestroy) ||
- ((_flags & RemovableIfEmpty) && empty() == 0)));
-
+ bool r = ((_flags & Removable)
+ && ((_flags & RemoveAtDestroy) ||
+ ((_flags & RemovableIfEmpty) && empty() == 0)));
+
return r;
}
_within_session = _session.path_is_within_session (path);
}
-bool
-FileSource::is_stub_path (const std::string& path)
-{
- return path.find (stub_dir_name) != string::npos;
-}
-
-bool
-FileSource::is_stub () const
-{
- return is_stub_path (_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)
{
const double total_capture_beats = converter.from(total_capture);
_write_source->set_length_beats(total_capture_beats);
- /* 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
_write_source.reset();
try {
- /* 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));
+ _session.create_midi_source_for_session (0, name ()));
if (!_write_source) {
throw failed_constructor();
return -1;
}
- _write_source->mark_streaming_midi_write_started (_note_mode, _session.transport_frame());
-
return 0;
}
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 ();
assert (ms);
source->drop_model();
- source->mark_streaming_midi_write_started (note_mode(), ms->timeline_position ());
+ source->mark_streaming_midi_write_started (note_mode());
for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
source->append_event_unlocked_beats(*i);
boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
assert (ms);
- ms->mark_streaming_midi_write_started (note_mode(), ms->timeline_position());
+ ms->mark_streaming_midi_write_started (note_mode());
for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
ms->append_event_unlocked_beats(*i);
assert (ms);
source->drop_model();
- source->mark_streaming_midi_write_started (note_mode(), ms->timeline_position());
+ source->mark_streaming_midi_write_started (note_mode());
for (Evoral::Sequence<TimeType>::const_iterator i = begin(0, true); i != end(); ++i) {
const Evoral::Event<Evoral::MusicalTime>& ev (*i);
}
void
-MidiSource::mark_streaming_midi_write_started (NoteMode mode, framepos_t start_frame)
+MidiSource::mark_streaming_midi_write_started (NoteMode mode)
{
if (_model) {
- _model->set_note_mode(mode);
- _model->start_write();
+ _model->set_note_mode (mode);
+ _model->start_write ();
}
_writing = true;
MidiSource::mark_streaming_write_started ()
{
NoteMode note_mode = _model ? _model->note_mode() : Sustained;
- mark_streaming_midi_write_started(note_mode, _session.transport_frame());
+ mark_streaming_midi_write_started (note_mode);
}
void
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;
* (e.g. as returned by new_*_source_name)
*/
string
-Session::new_source_path_from_name (DataType type, const string& name, bool as_stub)
+Session::new_source_path_from_name (DataType type, const string& name)
{
assert(name.find("/") == string::npos);
sys::path p;
if (type == DataType::AUDIO) {
- p = (as_stub ? sdir.sound_stub_path() : sdir.sound_path());
+ p = sdir.sound_path();
} else if (type == DataType::MIDI) {
- p = (as_stub ? sdir.midi_stub_path() : sdir.midi_path());
+ p = sdir.midi_path();
} else {
error << "Unknown source type, unable to create file path" << endmsg;
return "";
SessionDirectory sdir((*i).path);
string spath = sdir.sound_path().to_string();
- string spath_stubs = sdir.sound_stub_path().to_string();
/* note that we search *without* the extension so that
we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf"
a file format change.
*/
- if (matching_unsuffixed_filename_exists_in (spath, buf) ||
- matching_unsuffixed_filename_exists_in (spath_stubs, buf)) {
+ if (matching_unsuffixed_filename_exists_in (spath, buf)) {
existing++;
break;
}
/** 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, bool as_stub)
+Session::create_audio_source_for_session (size_t n_chans, string const & n, uint32_t chan, bool destructive)
{
const string name = new_audio_source_name (n, n_chans, chan, destructive);
- const string path = new_source_path_from_name(DataType::AUDIO, name, as_stub);
+ const string path = new_source_path_from_name(DataType::AUDIO, name);
return boost::dynamic_pointer_cast<AudioFileSource> (
SourceFactory::createWritable (DataType::AUDIO, *this, path, string(), destructive, frame_rate()));
/** Create a new within-session MIDI source */
boost::shared_ptr<MidiSource>
-Session::create_midi_source_for_session (Track* track, string const & n, bool as_stub)
+Session::create_midi_source_for_session (Track* track, string const & n)
{
/* try to use the existing write source for the track, to keep numbering sane
*/
}
const string name = new_midi_source_name (n);
- const string path = new_source_path_from_name (DataType::MIDI, name, as_stub);
+ const string path = new_source_path_from_name (DataType::MIDI, name);
return boost::dynamic_pointer_cast<SMFSource> (
SourceFactory::createWritable (
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
{
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) {
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_path().to_string();
if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
setup_raid_path(_session_dir->root_path().to_string());
- cleanup_stubfiles ();
-
if ((prop = node.property (X_("id-counter"))) != 0) {
uint64_t x;
sscanf (prop->value().c_str(), "%" PRIu64, &x);
}
static bool
-accept_all_non_stub_audio_files (const string& path, void */*arg*/)
+accept_all_audio_files (const string& path, void */*arg*/)
{
if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
return false;
}
- if (FileSource::is_stub_path (path)) {
- return false;
- }
-
if (!AudioFileSource::safe_audio_file_extension (path)) {
return false;
}
}
static bool
-accept_all_non_stub_midi_files (const string& path, void */*arg*/)
+accept_all_midi_files (const string& path, void */*arg*/)
{
if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
return false;
}
- if (FileSource::is_stub_path (path)) {
- return false;
- }
-
return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
(path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
(path.length() > 5 && path.find (".midi") != (path.length() - 5)));
i = nexti;
}
- candidates = scanner (audio_path, accept_all_non_stub_audio_files, (void *) 0, true, true);
- candidates2 = scanner (midi_path, accept_all_non_stub_midi_files, (void *) 0, true, true);
+ candidates = scanner (audio_path, accept_all_audio_files, (void *) 0, true, true);
+ candidates2 = scanner (midi_path, accept_all_midi_files, (void *) 0, true, true);
/* merge them */
++tmp;
if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
- if (!fs->is_stub()) {
- if (playlists->source_use_count (fs) != 0) {
- all_sources.insert (fs->path());
- } else {
-
- /* we might not remove this source from disk, because it may be used
- by other snapshots, but its not being used in this version
- so lets get rid of it now, along with any representative regions
- in the region list.
- */
-
- cerr << "Source " << i->second->name() << "ID " << i->second->id() << " not used, remove from source list and also all regions\n";
-
- RegionFactory::remove_regions_using_source (i->second);
- sources.erase (i);
- }
+ if (playlists->source_use_count (fs) != 0) {
+ all_sources.insert (fs->path());
+ } else {
+
+ /* we might not remove this source from disk, because it may be used
+ by other snapshots, but its not being used in this version
+ so lets get rid of it now, along with any representative regions
+ in the region list.
+ */
+
+ RegionFactory::remove_regions_using_source (i->second);
+ sources.erase (i);
}
}
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 ()
{
if (init(_path, false)) {
throw failed_constructor ();
}
-
- if (create(path)) {
- throw failed_constructor ();
- }
+
+ /* file is not opened until write */
}
/** Constructor used for existing internal-to-session files. */
if (open(_path)) {
throw failed_constructor ();
}
+
+ _open = true;
}
SMFSource::~SMFSource ()
}
}
+int
+SMFSource::open_for_write ()
+{
+ if (create (_path)) {
+ return -1;
+ }
+ _open = true;
+ return 0;
+}
+
/** All stamps in audio frames */
framecnt_t
SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination, framepos_t const source_start,
int ret = 0;
uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
+ if (writable() && !_open) {
+ /* nothing to read since nothing has ben written */
+ return duration;
+ }
+
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start %1 duration %2\n", start, duration));
_read_data_count = 0;
framecnt_t
SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source, framepos_t position, framecnt_t duration)
{
+ if (!_open && open_for_write()) {
+ error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
+ return 0;
+ }
+
+ if (!_writing) {
+ mark_streaming_write_started ();
+ }
+
_write_data_count = 0;
framepos_t time;
}
void
-SMFSource::mark_streaming_midi_write_started (NoteMode mode, framepos_t start_frame)
+SMFSource::mark_streaming_midi_write_started (NoteMode mode)
{
- Glib::Mutex::Lock lm (_lock);
- MidiSource::mark_streaming_midi_write_started (mode, start_frame);
+ /* CALLER MUST HOLD LOCK */
+
+ MidiSource::mark_streaming_midi_write_started (mode);
Evoral::SMF::begin_write ();
_last_ev_time_beats = 0.0;
_last_ev_time_frames = 0;
_model->clear();
}
+ if (writable() && !_open) {
+ return;
+ }
+
_model->start_write();
Evoral::SMF::seek_to_start();
void
SMFSource::flush_midi ()
{
- if (!writable()) {
+ if (!writable() || (writable() && !_open)) {
return;
}
{
int fmt = 0;
- init_sndfile ();
+ init_sndfile ();
_file_is_new = true;
_info.channels = 1;
_info.samplerate = rate;
_info.format = fmt;
-
- if (open()) {
- throw failed_constructor();
- }
-
- if (writable() && (_flags & Broadcast)) {
-
- SNDFILE* sf = _descriptor->allocate ();
- if (sf == 0) {
- error << string_compose (_("could not allocate file %1"), _path) << endmsg;
- throw failed_constructor ();
- }
-
- if (!_broadcast_info) {
- _broadcast_info = new BroadcastInfo;
- }
-
- _broadcast_info->set_from_session (s, header_position_offset);
- _broadcast_info->set_description (string_compose ("BWF %1", _name));
-
- if (!_broadcast_info->write_to_file (sf)) {
- error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
- _path, _broadcast_info->get_error())
- << endmsg;
- _flags = Flag (_flags & ~Broadcast);
- delete _broadcast_info;
- _broadcast_info = 0;
- }
-
- _descriptor->release ();
- }
+
+ /* do not open the file here - do that in write_unlocked() as needed
+ */
}
void
{
string file;
+ _descriptor = 0;
+
// lets try to keep the object initalizations here at the top
xfade_buf = 0;
_broadcast_info = 0;
if (writable()) {
sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
- }
+
+ if (_flags & Broadcast) {
+
+ if (!_broadcast_info) {
+ _broadcast_info = new BroadcastInfo;
+ }
+
+ _broadcast_info->set_from_session (_session, header_position_offset);
+ _broadcast_info->set_description (string_compose ("BWF %1", _name));
+
+ if (!_broadcast_info->write_to_file (sf)) {
+ error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
+ _path, _broadcast_info->get_error())
+ << endmsg;
+ _flags = Flag (_flags & ~Broadcast);
+ delete _broadcast_info;
+ _broadcast_info = 0;
+ }
+ }
+ }
- _descriptor->release ();
+ _descriptor->release ();
+ _open = true;
return 0;
}
uint32_t real_cnt;
framepos_t file_cnt;
+ if (writable() && !_open) {
+ /* file has not been opened yet - nothing written to it */
+ memset (dst, 0, sizeof (Sample) * cnt);
+ return cnt;
+ }
+
SNDFILE* sf = _descriptor->allocate ();
+
if (sf == 0) {
error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
return 0;
framecnt_t
SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
{
+ if (!_open && open()) {
+ return 0; // failure
+ }
+
if (destructive()) {
return destructive_write_unlocked (data, cnt);
} else {
return -1;
}
+ if (!_open) {
+ warning << string_compose (_("attempt to flush an un-opened audio file source (%1)"), _path) << endmsg;
+ return -1;
+ }
+
SNDFILE* sf = _descriptor->allocate ();
if (sf == 0) {
error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
return -1;
}
+ if (!_open) {
+ warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
+ return -1;
+ }
+
if (!(_flags & Broadcast)) {
return 0;
}