diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 7ae7024f46..6c4764a738 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -106,6 +106,7 @@ session_state.cc session_time.cc session_timefx.cc session_transport.cc +session_utils.cc silentfilesource.cc sndfile_helpers.cc sndfilesource.cc diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index eeb0870792..94c0af07eb 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -1556,10 +1556,7 @@ class Session : public PBD::StatefulDestructible Glib::Mutex space_lock; string old_sound_dir (bool with_path = true) const; - string discover_best_sound_dir (bool destructive = false); - string discover_best_midi_dir (); - int ensure_sound_dir (string, string&); - int ensure_midi_dir (string, string&); + string get_best_session_directory_for_new_source (); void refresh_disk_space (); mutable gint _playback_load; diff --git a/libs/ardour/ardour/session_utils.h b/libs/ardour/ardour/session_utils.h index 8aa4505fe5..8a9f6f584c 100644 --- a/libs/ardour/ardour/session_utils.h +++ b/libs/ardour/ardour/session_utils.h @@ -10,6 +10,17 @@ using std::string; int find_session (string str, string& path, string& snapshot, bool& isnew); +/** + * Create a SessionDirectory at the path specified by + * session_directory_path, this includes all subdirectories. + * + * @return true if the session directory was able to be created + * or if it already existed, false otherwise. + * + * @see SessionDirectory + */ +bool create_session_directory (const string& session_directory_path); + }; #endif diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index 7c0deccca1..bc16cde156 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -147,7 +148,9 @@ Session::import_audiofile (import_status& status) newfiles.push_back (boost::shared_ptr()); } - sounds_dir = discover_best_sound_dir (); + SessionDirectory sdir(get_best_session_directory_for_new_source ()); + sounds_dir = sdir.sound_path().to_string(); + basepath = PBD::basename_nosuffix (status.paths.front()); for (int n = 0; n < info.channels; ++n) { diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 71653a6896..ed2aaff4b5 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -2972,7 +2972,9 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool string foo = buf; - spath = discover_best_sound_dir (); + SessionDirectory sdir(get_best_session_directory_for_new_source ()); + + spath = sdir.sound_path().to_string(); spath += '/'; string::size_type pos = foo.find_last_of ('/'); @@ -3159,7 +3161,9 @@ Session::midi_path_from_name (string name) string foo = buf; - spath = discover_best_midi_dir (); + SessionDirectory sdir(get_best_session_directory_for_new_source ()); + + spath = sdir.sound_path().to_string(); spath += '/'; string::size_type pos = foo.find_last_of ('/'); @@ -3890,12 +3894,13 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le boost::shared_ptr fsource; uint32_t x; char buf[PATH_MAX+1]; - string dir; ChanCount nchans(track.audio_diskstream()->n_channels()); nframes_t position; nframes_t this_chunk; nframes_t to_do; BufferSet buffers; + SessionDirectory sdir(get_best_session_directory_for_new_source ()); + const string sound_dir = sdir.sound_path().to_string(); // any bigger than this seems to cause stack overflows in called functions const nframes_t chunk_size = (128 * 1024)/4; @@ -3913,13 +3918,11 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le if (track.has_external_redirects()) { goto out; } - - dir = discover_best_sound_dir (); for (uint32_t chan_n=0; chan_n < nchans.n_audio(); ++chan_n) { for (x = 0; x < 99999; ++x) { - snprintf (buf, sizeof(buf), "%s/%s-%d-bounce-%" PRIu32 ".wav", dir.c_str(), playlist->name().c_str(), chan_n, x+1); + snprintf (buf, sizeof(buf), "%s/%s-%d-bounce-%" PRIu32 ".wav", sound_dir.c_str(), playlist->name().c_str(), chan_n, x+1); if (access (buf, F_OK) != 0) { break; } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 29df9477b6..24a335a128 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -1504,14 +1505,15 @@ Session::path_from_region_name (string name, string identifier) { char buf[PATH_MAX+1]; uint32_t n; - string dir = discover_best_sound_dir (); + SessionDirectory sdir(get_best_session_directory_for_new_source()); + string sound_dir = sdir.sound_path().to_string(); for (n = 0; n < 999999; ++n) { if (identifier.length()) { - snprintf (buf, sizeof(buf), "%s/%s%s%" PRIu32 ".wav", dir.c_str(), name.c_str(), + snprintf (buf, sizeof(buf), "%s/%s%s%" PRIu32 ".wav", sound_dir.c_str(), name.c_str(), identifier.c_str(), n); } else { - snprintf (buf, sizeof(buf), "%s/%s-%" PRIu32 ".wav", dir.c_str(), name.c_str(), n); + snprintf (buf, sizeof(buf), "%s/%s-%" PRIu32 ".wav", sound_dir.c_str(), name.c_str(), n); } if (!Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) { @@ -1660,102 +1662,16 @@ Session::refresh_disk_space () #endif } -int -Session::ensure_sound_dir (string path, string& result) -{ - string dead; - string peak; - - /* Ensure that the parent directory exists */ - - if (g_mkdir_with_parents (path.c_str(), 0775)) { - error << string_compose(_("cannot create session directory \"%1\"; ignored"), path) << endmsg; - return -1; - } - - /* Ensure that the sounds directory exists */ - - result = path; - result += '/'; - result += sound_dir_name; - - if (g_mkdir_with_parents (result.c_str(), 0775)) { - error << string_compose(_("cannot create sounds directory \"%1\"; ignored"), result) << endmsg; - return -1; - } - - dead = path; - dead += '/'; - dead += dead_sound_dir_name; - - if (g_mkdir_with_parents (dead.c_str(), 0775)) { - error << string_compose(_("cannot create dead sounds directory \"%1\"; ignored"), dead) << endmsg; - return -1; - } - - peak = path; - peak += '/'; - peak += peak_dir_name; - - if (g_mkdir_with_parents (peak.c_str(), 0775)) { - error << string_compose(_("cannot create peak file directory \"%1\"; ignored"), peak) << endmsg; - return -1; - } - - /* callers expect this to be terminated ... */ - - result += '/'; - return 0; -} - -int -Session::ensure_midi_dir (string path, string& result) -{ - string dead; - - /* Ensure that the parent directory exists */ - - if (g_mkdir_with_parents (path.c_str(), 0775)) { - error << string_compose(_("cannot create session directory \"%1\"; ignored"), path) << endmsg; - return -1; - } - - /* Ensure that the sounds directory exists */ - - result = path; - result += '/'; - result += midi_dir_name; - - if (g_mkdir_with_parents (result.c_str(), 0775)) { - error << string_compose(_("cannot create sounds directory \"%1\"; ignored"), result) << endmsg; - return -1; - } - - dead = path; - dead += '/'; - dead += dead_midi_dir_name; - - if (g_mkdir_with_parents (dead.c_str(), 0775)) { - error << string_compose(_("cannot create dead sounds directory \"%1\"; ignored"), dead) << endmsg; - return -1; - } - - /* callers expect this to be terminated ... */ - - result += '/'; - return 0; -} - string -Session::discover_best_sound_dir (bool destructive) +Session::get_best_session_directory_for_new_source () { vector::iterator i; - string result; + string result = _session_dir->root_path().to_string(); /* handle common case without system calls */ if (session_dirs.size() == 1) { - return sound_dir(); + return result; } /* OK, here's the algorithm we're following here: @@ -1797,9 +1713,6 @@ Session::discover_best_sound_dir (bool destructive) } if (free_enough >= 2) { - - bool found_it = false; - /* use RR selection process, ensuring that the one picked works OK. */ @@ -1812,19 +1725,15 @@ Session::discover_best_sound_dir (bool destructive) } if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) { - if (ensure_sound_dir ((*i).path, result) == 0) { + if (create_session_directory ((*i).path)) { + result = (*i).path; last_rr_session_dir = i; - found_it = true; - break; + return result; } } } while (i != last_rr_session_dir); - if (!found_it) { - result = sound_dir(); - } - } else { /* pick FS with the most freespace (and that @@ -1838,125 +1747,12 @@ Session::discover_best_sound_dir (bool destructive) sort (sorted.begin(), sorted.end(), cmp); for (i = sorted.begin(); i != sorted.end(); ++i) { - if (ensure_sound_dir ((*i).path, result) == 0) { + if (create_session_directory ((*i).path)) { + result = (*i).path; last_rr_session_dir = i; - break; + return result; } } - - /* if the above fails, fall back to the most simplistic solution */ - - if (i == sorted.end()) { - return sound_dir(); - } - } - - return result; -} - -string -Session::discover_best_midi_dir () -{ - vector::iterator i; - string result; - - /* handle common case without system calls */ - - if (session_dirs.size() == 1) { - return midi_dir(); - } - - /* OK, here's the algorithm we're following here: - - We want to select which directory to use for - the next file source to be created. Ideally, - we'd like to use a round-robin process so as to - get maximum performance benefits from splitting - the files across multiple disks. - - However, in situations without much diskspace, an - RR approach may end up filling up a filesystem - with new files while others still have space. - Its therefore important to pay some attention to - the freespace in the filesystem holding each - directory as well. However, if we did that by - itself, we'd keep creating new files in the file - system with the most space until it was as full - as all others, thus negating any performance - benefits of this RAID-1 like approach. - - So, we use a user-configurable space threshold. If - there are at least 2 filesystems with more than this - much space available, we use RR selection between them. - If not, then we pick the filesystem with the most space. - - This gets a good balance between the two - approaches. - */ - - refresh_disk_space (); - - int free_enough = 0; - - for (i = session_dirs.begin(); i != session_dirs.end(); ++i) { - if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) { - free_enough++; - } - } - - if (free_enough >= 2) { - - bool found_it = false; - - /* use RR selection process, ensuring that the one - picked works OK. - */ - - i = last_rr_session_dir; - - do { - if (++i == session_dirs.end()) { - i = session_dirs.begin(); - } - - if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) { - if (ensure_midi_dir ((*i).path, result) == 0) { - last_rr_session_dir = i; - found_it = true; - break; - } - } - - } while (i != last_rr_session_dir); - - if (!found_it) { - result = midi_dir(); - } - - } else { - - /* pick FS with the most freespace (and that - seems to actually work ...) - */ - - vector sorted; - space_and_path_ascending_cmp cmp; - - sorted = session_dirs; - sort (sorted.begin(), sorted.end(), cmp); - - for (i = sorted.begin(); i != sorted.end(); ++i) { - if (ensure_midi_dir ((*i).path, result) == 0) { - last_rr_session_dir = i; - break; - } - } - - /* if the above fails, fall back to the most simplistic solution */ - - if (i == sorted.end()) { - return midi_dir(); - } } return result; diff --git a/libs/ardour/session_utils.cc b/libs/ardour/session_utils.cc new file mode 100644 index 0000000000..3b2baad69a --- /dev/null +++ b/libs/ardour/session_utils.cc @@ -0,0 +1,39 @@ + +#include + +#include + +#include "i18n.h" + +namespace ARDOUR { + +using namespace PBD; + +bool +create_session_directory (const string& session_directory_path) +{ + SessionDirectory sdir(session_directory_path); + + try + { + // create all the required session directories + sdir.create(); + } + catch(sys::filesystem_error& ex) + { + // log the exception + warning << string_compose + ( + _("Unable to create session directory at path %1 : %2"), + session_directory_path, + ex.what() + ); + + return false; + } + + // successfully created the session directory + return true; +} + +} // namespace ARDOUR