mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-20 21:56:30 +01:00
initial implementation of "bring all media into session folder". Incomplete but basically functional for audio files
This commit is contained in:
parent
f5ac8d22fc
commit
3b0ce4038e
13 changed files with 339 additions and 72 deletions
|
|
@ -25,10 +25,11 @@
|
||||||
<menuitem action='CloseVideo'/>
|
<menuitem action='CloseVideo'/>
|
||||||
|
|
||||||
<menu name='Export' action='Export'>
|
<menu name='Export' action='Export'>
|
||||||
<menuitem action='ExportAudio'/>
|
<menuitem action='ExportAudio'/>
|
||||||
<menuitem action='StemExport'/>
|
<menuitem action='StemExport'/>
|
||||||
<menuitem action='ExportVideo'/>
|
<menuitem action='ExportVideo'/>
|
||||||
</menu>
|
</menu>
|
||||||
|
<menuitem action='bring-into-session'/>
|
||||||
<menu name='Cleanup' action='Cleanup'>
|
<menu name='Cleanup' action='Cleanup'>
|
||||||
<menuitem action='CleanupUnused'/>
|
<menuitem action='CleanupUnused'/>
|
||||||
<menuitem action='FlushWastebasket'/>
|
<menuitem action='FlushWastebasket'/>
|
||||||
|
|
|
||||||
|
|
@ -2141,6 +2141,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
||||||
TimeAxisView* _stepping_axis_view;
|
TimeAxisView* _stepping_axis_view;
|
||||||
void zoom_vertical_modifier_released();
|
void zoom_vertical_modifier_released();
|
||||||
|
|
||||||
|
void bring_in_callback (Gtk::Label*, uint32_t n, uint32_t total, std::string name);
|
||||||
|
void update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, std::string name);
|
||||||
|
void bring_all_sources_into_session ();
|
||||||
|
|
||||||
friend class Drag;
|
friend class Drag;
|
||||||
friend class RegionDrag;
|
friend class RegionDrag;
|
||||||
friend class RegionMoveDrag;
|
friend class RegionMoveDrag;
|
||||||
|
|
|
||||||
|
|
@ -692,6 +692,10 @@ Editor::register_actions ()
|
||||||
act = ActionManager::register_action (editor_actions, X_("importFromSession"), _("Import From Session"), sigc::mem_fun(*this, &Editor::session_import_dialog));
|
act = ActionManager::register_action (editor_actions, X_("importFromSession"), _("Import From Session"), sigc::mem_fun(*this, &Editor::session_import_dialog));
|
||||||
ActionManager::write_sensitive_actions.push_back (act);
|
ActionManager::write_sensitive_actions.push_back (act);
|
||||||
|
|
||||||
|
|
||||||
|
act = ActionManager::register_action (editor_actions, X_("bring-into-session"), _("Bring all media into session folder"), sigc::mem_fun(*this, &Editor::bring_all_sources_into_session));
|
||||||
|
ActionManager::write_sensitive_actions.push_back (act);
|
||||||
|
|
||||||
ActionManager::register_toggle_action (editor_actions, X_("ToggleSummary"), _("Show Summary"), sigc::mem_fun (*this, &Editor::set_summary));
|
ActionManager::register_toggle_action (editor_actions, X_("ToggleSummary"), _("Show Summary"), sigc::mem_fun (*this, &Editor::set_summary));
|
||||||
|
|
||||||
ActionManager::register_toggle_action (editor_actions, X_("ToggleGroupTabs"), _("Show Group Tabs"), sigc::mem_fun (*this, &Editor::set_group_tabs));
|
ActionManager::register_toggle_action (editor_actions, X_("ToggleGroupTabs"), _("Show Group Tabs"), sigc::mem_fun (*this, &Editor::set_group_tabs));
|
||||||
|
|
|
||||||
|
|
@ -7062,3 +7062,39 @@ Editor::lock ()
|
||||||
|
|
||||||
start_lock_event_timing ();
|
start_lock_event_timing ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
|
||||||
|
{
|
||||||
|
Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
|
||||||
|
{
|
||||||
|
label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
|
||||||
|
Gtkmm2ext::UI::instance()->flush_pending ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Editor::bring_all_sources_into_session ()
|
||||||
|
{
|
||||||
|
if (!_session) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk::Label msg;
|
||||||
|
ArdourDialog w (_("Moving embedded files into session folder"));
|
||||||
|
w.get_vbox()->pack_start (msg);
|
||||||
|
w.present ();
|
||||||
|
|
||||||
|
/* flush all pending GUI events because we're about to start copying
|
||||||
|
* files
|
||||||
|
*/
|
||||||
|
|
||||||
|
Gtkmm2ext::UI::instance()->flush_pending ();
|
||||||
|
|
||||||
|
cerr << " Do it\n";
|
||||||
|
|
||||||
|
_session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,8 @@ public:
|
||||||
*/
|
*/
|
||||||
int rename (const std::string& name);
|
int rename (const std::string& name);
|
||||||
|
|
||||||
|
virtual void release_descriptor () {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FileSource (Session& session, DataType type,
|
FileSource (Session& session, DataType type,
|
||||||
const std::string& path,
|
const std::string& path,
|
||||||
|
|
|
||||||
|
|
@ -200,11 +200,16 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
||||||
std::string peak_path (std::string) const;
|
std::string peak_path (std::string) const;
|
||||||
|
|
||||||
std::string peak_path_from_audio_path (std::string) const;
|
std::string peak_path_from_audio_path (std::string) const;
|
||||||
|
bool audio_source_name_is_unique (const std::string& name, uint32_t chan);
|
||||||
|
std::string format_audio_source_name (const std::string& legalized_base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required, uint32_t cnt, bool related_exists);
|
||||||
|
std::string new_audio_source_path_for_embedded (const std::string& existing_path);
|
||||||
std::string new_audio_source_path (const std::string&, uint32_t nchans, uint32_t chan, bool destructive, bool take_required);
|
std::string new_audio_source_path (const std::string&, uint32_t nchans, uint32_t chan, bool destructive, bool take_required);
|
||||||
std::string new_midi_source_path (const std::string&);
|
std::string new_midi_source_path (const std::string&);
|
||||||
RouteList new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name);
|
RouteList new_route_from_template (uint32_t how_many, const std::string& template_path, const std::string& name);
|
||||||
std::vector<std::string> get_paths_for_new_sources (bool allow_replacing, const std::string& import_file_path, uint32_t channels);
|
std::vector<std::string> get_paths_for_new_sources (bool allow_replacing, const std::string& import_file_path, uint32_t channels);
|
||||||
|
|
||||||
|
int bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,std::string)> callback);
|
||||||
|
|
||||||
void process (pframes_t nframes);
|
void process (pframes_t nframes);
|
||||||
|
|
||||||
BufferSet& get_silent_buffers (ChanCount count = ChanCount::ZERO);
|
BufferSet& get_silent_buffers (ChanCount count = ChanCount::ZERO);
|
||||||
|
|
@ -871,6 +876,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
||||||
|
|
||||||
std::vector<std::string> source_search_path(DataType) const;
|
std::vector<std::string> source_search_path(DataType) const;
|
||||||
void ensure_search_path_includes (const std::string& path, DataType type);
|
void ensure_search_path_includes (const std::string& path, DataType type);
|
||||||
|
void remove_dir_from_search_path (const std::string& path, DataType type);
|
||||||
|
|
||||||
std::list<std::string> unknown_processors () const;
|
std::list<std::string> unknown_processors () const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,8 @@ class LIBARDOUR_API SndFileSource : public AudioFileSource {
|
||||||
|
|
||||||
static int get_soundfile_info (const std::string& path, SoundFileInfo& _info, std::string& error_msg);
|
static int get_soundfile_info (const std::string& path, SoundFileInfo& _info, std::string& error_msg);
|
||||||
|
|
||||||
|
void release_descriptor ();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void set_path (const std::string& p);
|
void set_path (const std::string& p);
|
||||||
void set_header_timeline_position ();
|
void set_header_timeline_position ();
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include "pbd/convert.h"
|
#include "pbd/convert.h"
|
||||||
#include "pbd/basename.h"
|
#include "pbd/basename.h"
|
||||||
|
#include "pbd/file_utils.h"
|
||||||
#include "pbd/mountpoint.h"
|
#include "pbd/mountpoint.h"
|
||||||
#include "pbd/stl_delete.h"
|
#include "pbd/stl_delete.h"
|
||||||
#include "pbd/strsplit.h"
|
#include "pbd/strsplit.h"
|
||||||
|
|
@ -413,3 +414,4 @@ AudioFileSource::get_interleave_buffer (framecnt_t size)
|
||||||
|
|
||||||
return ssb->buf;
|
return ssb->buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -546,6 +546,12 @@ void
|
||||||
FileSource::set_path (const std::string& newpath)
|
FileSource::set_path (const std::string& newpath)
|
||||||
{
|
{
|
||||||
_path = newpath;
|
_path = newpath;
|
||||||
|
set_within_session_from_path (newpath);
|
||||||
|
if (_within_session) {
|
||||||
|
_origin = Glib::path_get_basename (newpath);
|
||||||
|
} else {
|
||||||
|
_origin = newpath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -597,3 +603,5 @@ FileSource::rename (const string& newpath)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
#include "pbd/stacktrace.h"
|
#include "pbd/stacktrace.h"
|
||||||
#include "pbd/file_utils.h"
|
#include "pbd/file_utils.h"
|
||||||
#include "pbd/convert.h"
|
#include "pbd/convert.h"
|
||||||
|
#include "pbd/md5.h"
|
||||||
#include "pbd/unwind.h"
|
#include "pbd/unwind.h"
|
||||||
#include "pbd/search_path.h"
|
#include "pbd/search_path.h"
|
||||||
|
|
||||||
|
|
@ -3847,6 +3848,146 @@ Session::peak_path (string base) const
|
||||||
return Glib::build_filename (_session_dir->peak_path(), base + peakfile_suffix);
|
return Glib::build_filename (_session_dir->peak_path(), base + peakfile_suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
Session::new_audio_source_path_for_embedded (const std::string& path)
|
||||||
|
{
|
||||||
|
/* embedded source:
|
||||||
|
*
|
||||||
|
* we know that the filename is already unique because it exists
|
||||||
|
* out in the filesystem.
|
||||||
|
*
|
||||||
|
* However, when we bring it into the session, we could get a
|
||||||
|
* collision.
|
||||||
|
*
|
||||||
|
* Eg. two embedded files:
|
||||||
|
*
|
||||||
|
* /foo/bar/baz.wav
|
||||||
|
* /frob/nic/baz.wav
|
||||||
|
*
|
||||||
|
* When merged into session, these collide.
|
||||||
|
*
|
||||||
|
* There will not be a conflict with in-memory sources
|
||||||
|
* because when the source was created we already picked
|
||||||
|
* a unique name for it.
|
||||||
|
*
|
||||||
|
* This collision is not likely to be common, but we have to guard
|
||||||
|
* against it. So, if there is a collision, take the md5 hash of the
|
||||||
|
* the path, and use that as the filename instead.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SessionDirectory sdir (get_best_session_directory_for_new_audio());
|
||||||
|
string base = Glib::path_get_basename (path);
|
||||||
|
string newpath = Glib::build_filename (sdir.sound_path(), base);
|
||||||
|
|
||||||
|
if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
|
||||||
|
|
||||||
|
MD5 md5;
|
||||||
|
|
||||||
|
md5.digestString (path.c_str());
|
||||||
|
md5.writeToString ();
|
||||||
|
base = md5.digestChars;
|
||||||
|
|
||||||
|
/* XXX base needs suffix from path */
|
||||||
|
|
||||||
|
newpath = Glib::build_filename (sdir.sound_path(), base);
|
||||||
|
|
||||||
|
/* if this collides, we're screwed */
|
||||||
|
|
||||||
|
if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
|
||||||
|
error << string_compose (_("Merging embedded file %1: name collision AND md5 hash collision!"), path) << endmsg;
|
||||||
|
return string();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return newpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Session::audio_source_name_is_unique (const string& name, uint32_t chan)
|
||||||
|
{
|
||||||
|
std::vector<string> sdirs = source_search_path (DataType::AUDIO);
|
||||||
|
vector<space_and_path>::iterator i;
|
||||||
|
uint32_t existing = 0;
|
||||||
|
string basename = PBD::basename_nosuffix (name);
|
||||||
|
|
||||||
|
for (vector<string>::const_iterator i = sdirs.begin(); i != sdirs.end(); ++i) {
|
||||||
|
|
||||||
|
/* note that we search *without* the extension so that
|
||||||
|
we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf"
|
||||||
|
in the event that this new name is required for
|
||||||
|
a file format change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const string spath = *i;
|
||||||
|
|
||||||
|
if (matching_unsuffixed_filename_exists_in (spath, basename)) {
|
||||||
|
existing++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* it is possible that we have the path already
|
||||||
|
* assigned to a source that has not yet been written
|
||||||
|
* (ie. the write source for a diskstream). we have to
|
||||||
|
* check this in order to make sure that our candidate
|
||||||
|
* path isn't used again, because that can lead to
|
||||||
|
* two Sources point to the same file with different
|
||||||
|
* notions of their removability.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
string possible_path = Glib::build_filename (spath, name);
|
||||||
|
|
||||||
|
if (audio_source_by_path_and_channel (possible_path, chan)) {
|
||||||
|
existing++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (existing == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
Session::format_audio_source_name (const string& legalized_base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required, uint32_t cnt, bool related_exists)
|
||||||
|
{
|
||||||
|
ostringstream sstr;
|
||||||
|
const string ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
|
||||||
|
|
||||||
|
if (destructive) {
|
||||||
|
sstr << 'T';
|
||||||
|
sstr << setfill ('0') << setw (4) << cnt;
|
||||||
|
sstr << legalized_base;
|
||||||
|
} else {
|
||||||
|
sstr << legalized_base;
|
||||||
|
|
||||||
|
if (take_required || related_exists) {
|
||||||
|
sstr << '-';
|
||||||
|
sstr << cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nchan == 2) {
|
||||||
|
if (chan == 0) {
|
||||||
|
sstr << "%L";
|
||||||
|
} else {
|
||||||
|
sstr << "%R";
|
||||||
|
}
|
||||||
|
} else if (nchan > 2) {
|
||||||
|
if (nchan < 26) {
|
||||||
|
sstr << '%';
|
||||||
|
sstr << 'a' + chan;
|
||||||
|
} else {
|
||||||
|
/* XXX what? more than 26 channels! */
|
||||||
|
sstr << '%';
|
||||||
|
sstr << chan+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sstr << ext;
|
||||||
|
|
||||||
|
return sstr.str();
|
||||||
|
}
|
||||||
|
|
||||||
/** Return a unique name based on \a base for a new internal audio source */
|
/** Return a unique name based on \a base for a new internal audio source */
|
||||||
string
|
string
|
||||||
Session::new_audio_source_path (const string& base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required)
|
Session::new_audio_source_path (const string& base, uint32_t nchan, uint32_t chan, bool destructive, bool take_required)
|
||||||
|
|
@ -3855,86 +3996,20 @@ Session::new_audio_source_path (const string& base, uint32_t nchan, uint32_t cha
|
||||||
string possible_name;
|
string possible_name;
|
||||||
const uint32_t limit = 9999; // arbitrary limit on number of files with the same basic name
|
const uint32_t limit = 9999; // arbitrary limit on number of files with the same basic name
|
||||||
string legalized;
|
string legalized;
|
||||||
string ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
|
|
||||||
bool some_related_source_name_exists = false;
|
bool some_related_source_name_exists = false;
|
||||||
|
|
||||||
possible_name[0] = '\0';
|
|
||||||
legalized = legalize_for_path (base);
|
legalized = legalize_for_path (base);
|
||||||
|
|
||||||
std::vector<string> sdirs = source_search_path(DataType::AUDIO);
|
|
||||||
|
|
||||||
// Find a "version" of the base name that doesn't exist in any of the possible directories.
|
// Find a "version" of the base name that doesn't exist in any of the possible directories.
|
||||||
|
|
||||||
for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) {
|
for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) {
|
||||||
|
|
||||||
vector<space_and_path>::iterator i;
|
possible_name = format_audio_source_name (legalized, nchan, chan, destructive, take_required, cnt, some_related_source_name_exists);
|
||||||
uint32_t existing = 0;
|
|
||||||
|
if (audio_source_name_is_unique (possible_name, chan)) {
|
||||||
for (vector<string>::const_iterator i = sdirs.begin(); i != sdirs.end(); ++i) {
|
|
||||||
|
|
||||||
ostringstream sstr;
|
|
||||||
|
|
||||||
if (destructive) {
|
|
||||||
sstr << 'T';
|
|
||||||
sstr << setfill ('0') << setw (4) << cnt;
|
|
||||||
sstr << legalized;
|
|
||||||
} else {
|
|
||||||
sstr << legalized;
|
|
||||||
|
|
||||||
if (take_required || some_related_source_name_exists) {
|
|
||||||
sstr << '-';
|
|
||||||
sstr << cnt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nchan == 2) {
|
|
||||||
if (chan == 0) {
|
|
||||||
sstr << "%L";
|
|
||||||
} else {
|
|
||||||
sstr << "%R";
|
|
||||||
}
|
|
||||||
} else if (nchan > 2 && nchan < 26) {
|
|
||||||
sstr << '%';
|
|
||||||
sstr << 'a' + chan;
|
|
||||||
}
|
|
||||||
|
|
||||||
sstr << ext;
|
|
||||||
|
|
||||||
possible_name = sstr.str();
|
|
||||||
const string spath = (*i);
|
|
||||||
|
|
||||||
/* note that we search *without* the extension so that
|
|
||||||
we don't end up both "Audio 1-1.wav" and "Audio 1-1.caf"
|
|
||||||
in the event that this new name is required for
|
|
||||||
a file format change.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (matching_unsuffixed_filename_exists_in (spath, possible_name)) {
|
|
||||||
existing++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* it is possible that we have the path already
|
|
||||||
* assigned to a source that has not yet been written
|
|
||||||
* (ie. the write source for a diskstream). we have to
|
|
||||||
* check this in order to make sure that our candidate
|
|
||||||
* path isn't used again, because that can lead to
|
|
||||||
* two Sources point to the same file with different
|
|
||||||
* notions of their removability.
|
|
||||||
*/
|
|
||||||
|
|
||||||
string possible_path = Glib::build_filename (spath, possible_name);
|
|
||||||
|
|
||||||
if (audio_source_by_path_and_channel (possible_path, chan)) {
|
|
||||||
existing++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existing == 0) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
some_related_source_name_exists = true;
|
some_related_source_name_exists = true;
|
||||||
|
|
||||||
if (cnt > limit) {
|
if (cnt > limit) {
|
||||||
|
|
@ -5198,6 +5273,33 @@ Session::ensure_search_path_includes (const string& path, DataType type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Session::remove_dir_from_search_path (const string& dir, DataType type)
|
||||||
|
{
|
||||||
|
Searchpath sp;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case DataType::AUDIO:
|
||||||
|
sp = Searchpath(config.get_audio_search_path ());
|
||||||
|
break;
|
||||||
|
case DataType::MIDI:
|
||||||
|
sp = Searchpath (config.get_midi_search_path ());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp -= dir;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case DataType::AUDIO:
|
||||||
|
config.set_audio_search_path (sp.to_string());
|
||||||
|
break;
|
||||||
|
case DataType::MIDI:
|
||||||
|
config.set_midi_search_path (sp.to_string());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
boost::shared_ptr<Speakers>
|
boost::shared_ptr<Speakers>
|
||||||
Session::get_speakers()
|
Session::get_speakers()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3797,3 +3797,92 @@ Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFo
|
||||||
|
|
||||||
return !(found_sr && found_data_format); // zero if they are both found
|
return !(found_sr && found_data_format); // zero if they are both found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
|
||||||
|
typedef std::map<std::string,SeveralFileSources> SourcePathMap;
|
||||||
|
|
||||||
|
int
|
||||||
|
Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
|
||||||
|
{
|
||||||
|
uint32_t total = 0;
|
||||||
|
uint32_t n = 0;
|
||||||
|
SourcePathMap source_path_map;
|
||||||
|
string new_path;
|
||||||
|
boost::shared_ptr<AudioFileSource> afs;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
Glib::Threads::Mutex::Lock lm (source_lock);
|
||||||
|
|
||||||
|
cerr << " total sources = " << sources.size();
|
||||||
|
|
||||||
|
for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
|
||||||
|
boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
|
||||||
|
|
||||||
|
if (!fs) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs->within_session()) {
|
||||||
|
cerr << "skip " << fs->name() << endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source_path_map.find (fs->path()) != source_path_map.end()) {
|
||||||
|
source_path_map[fs->path()].push_back (fs);
|
||||||
|
} else {
|
||||||
|
SeveralFileSources v;
|
||||||
|
v.push_back (fs);
|
||||||
|
source_path_map.insert (make_pair (fs->path(), v));
|
||||||
|
}
|
||||||
|
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
|
||||||
|
cerr << " fsources = " << total << endl;
|
||||||
|
|
||||||
|
for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
|
||||||
|
|
||||||
|
/* tell caller where we are */
|
||||||
|
|
||||||
|
string old_path = i->first;
|
||||||
|
|
||||||
|
callback (n, total, old_path);
|
||||||
|
|
||||||
|
cerr << old_path << endl;
|
||||||
|
|
||||||
|
new_path.clear ();
|
||||||
|
|
||||||
|
switch (i->second.front()->type()) {
|
||||||
|
case DataType::AUDIO:
|
||||||
|
new_path = new_audio_source_path_for_embedded (old_path);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DataType::MIDI:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cerr << "Move " << old_path << " => " << new_path << endl;
|
||||||
|
|
||||||
|
if (!copy_file (old_path, new_path)) {
|
||||||
|
cerr << "failed !\n";
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure we stop looking in the external
|
||||||
|
dir/folder. Remember, this is an all-or-nothing
|
||||||
|
operations, it doesn't merge just some files.
|
||||||
|
*/
|
||||||
|
remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
|
||||||
|
|
||||||
|
for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
|
||||||
|
(*f)->set_path (new_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
save_state ("", false, false);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
|
||||||
|
#include "pbd/file_utils.h"
|
||||||
#include "pbd/stl_delete.h"
|
#include "pbd/stl_delete.h"
|
||||||
#include "pbd/strsplit.h"
|
#include "pbd/strsplit.h"
|
||||||
|
|
||||||
|
|
@ -717,4 +718,5 @@ SMFSource::prevent_deletion ()
|
||||||
|
|
||||||
_flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));
|
_flags = Flag (_flags & ~(Removable|RemovableIfEmpty|RemoveAtDestroy));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1016,3 +1016,12 @@ SndFileSource::set_path (const string& p)
|
||||||
_descriptor->set_path (_path);
|
_descriptor->set_path (_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SndFileSource::release_descriptor ()
|
||||||
|
{
|
||||||
|
if (_descriptor) {
|
||||||
|
_descriptor->release ();
|
||||||
|
_descriptor = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue