initial pass at a missing file dialog and "relocatable" source files. lots more to do here
git-svn-id: svn://localhost/ardour2/branches/3.0@7983 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
d29f14bf33
commit
5c6ba165f6
|
@ -102,6 +102,7 @@ typedef uint64_t microseconds_t;
|
|||
#include "window_proxy.h"
|
||||
#include "global_port_matrix.h"
|
||||
#include "location_ui.h"
|
||||
#include "missing_file_dialog.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
|
@ -264,6 +265,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
|
|||
|
||||
ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
|
||||
|
||||
/* handle requests to deal with missing files */
|
||||
|
||||
ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
|
||||
|
||||
/* lets get this party started */
|
||||
|
||||
try {
|
||||
|
@ -3689,3 +3694,26 @@ ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
|
|||
{
|
||||
_window_proxies.remove (p);
|
||||
}
|
||||
|
||||
int
|
||||
ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
|
||||
{
|
||||
MissingFileDialog dialog (s, str, type);
|
||||
|
||||
dialog.show ();
|
||||
dialog.present ();
|
||||
|
||||
int result = dialog.run ();
|
||||
dialog.hide ();
|
||||
|
||||
switch (result) {
|
||||
case RESPONSE_OK:
|
||||
break;
|
||||
default:
|
||||
return 1; // quit entire session load
|
||||
}
|
||||
|
||||
result = dialog.get_action ();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -716,6 +716,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
void queue_finish ();
|
||||
|
||||
std::list<WindowProxyBase*> _window_proxies;
|
||||
|
||||
int missing_file (ARDOUR::Session*s, std::string str, ARDOUR::DataType type);
|
||||
};
|
||||
|
||||
#endif /* __ardour_gui_h__ */
|
||||
|
|
166
gtk2_ardour/missing_file_dialog.cc
Normal file
166
gtk2_ardour/missing_file_dialog.cc
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
Copyright (C) 2010 Paul Davis
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "pbd/compose.h"
|
||||
#include "pbd/replace_all.h"
|
||||
#include "pbd/strsplit.h"
|
||||
|
||||
#include "ardour/session.h"
|
||||
|
||||
#include "missing_file_dialog.h"
|
||||
|
||||
using namespace Gtk;
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
|
||||
MissingFileDialog::MissingFileDialog (Session* s, const std::string& path, DataType type)
|
||||
: ArdourDialog (_("Missing File!"), true, false)
|
||||
, filetype (type)
|
||||
, chooser (FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
||||
, use_chosen (_("Add chosen folder to search path, and try again"))
|
||||
, choice_group (use_chosen.get_group())
|
||||
, use_chosen_and_no_more_questions (choice_group, _("Add chosen folder to search path, try again but don't ask me again"), false)
|
||||
, stop_loading_button (choice_group, _("Stop loading this session"), false)
|
||||
, all_missing_ok (choice_group, _("This and all other missing files are OK"), false)
|
||||
, this_missing_ok (choice_group, _("This missing file is OK"), false)
|
||||
{
|
||||
set_session (s);
|
||||
|
||||
add_button (_("Done"), RESPONSE_OK);
|
||||
|
||||
string typestr;
|
||||
|
||||
switch (type) {
|
||||
case DataType::AUDIO:
|
||||
typestr = _("An audio");
|
||||
break;
|
||||
case DataType::MIDI:
|
||||
typestr = _("A MIDI");
|
||||
break;
|
||||
}
|
||||
|
||||
string dirstr;
|
||||
|
||||
dirstr = s->source_search_path (type);
|
||||
replace_all (dirstr, ":", "\n");
|
||||
|
||||
msg.set_markup (string_compose (_("%1 file (\"%2\") cannot be found.\n\n\
|
||||
Currently, Ardour has searched in the following folders for this file:\n\n\
|
||||
<tt>%3</tt>\n\n\
|
||||
The following options are available:"), typestr, path, dirstr));
|
||||
|
||||
VBox* button_packer_box = manage (new VBox);
|
||||
|
||||
button_packer_box->set_spacing (6);
|
||||
button_packer_box->set_border_width (12);
|
||||
|
||||
button_packer_box->pack_start (use_chosen, false, false);
|
||||
button_packer_box->pack_start (use_chosen_and_no_more_questions, false, false);
|
||||
button_packer_box->pack_start (this_missing_ok, false, false);
|
||||
button_packer_box->pack_start (all_missing_ok, false, false);
|
||||
button_packer_box->pack_start (stop_loading_button, false, false);
|
||||
|
||||
button_packer_box->show_all ();
|
||||
|
||||
get_vbox()->set_spacing (6);
|
||||
get_vbox()->set_border_width (12);
|
||||
get_vbox()->set_homogeneous (false);
|
||||
|
||||
get_vbox()->pack_start (msg, false, false);
|
||||
|
||||
HBox* hbox = manage (new HBox);
|
||||
hbox->pack_start (*button_packer_box, false, true);
|
||||
hbox->show ();
|
||||
|
||||
get_vbox()->pack_start (*hbox, false, false);
|
||||
get_vbox()->pack_start (chooser, true, true);
|
||||
|
||||
msg.show ();
|
||||
chooser.set_size_request (-1, 300);
|
||||
chooser.show ();
|
||||
chooser.set_current_folder (Glib::get_home_dir());
|
||||
chooser.set_create_folders (false);
|
||||
}
|
||||
|
||||
void
|
||||
MissingFileDialog::add_chosen ()
|
||||
{
|
||||
string str;
|
||||
string newdir;
|
||||
vector<string> dirs;
|
||||
|
||||
switch (filetype) {
|
||||
case DataType::AUDIO:
|
||||
str = _session->config.get_audio_search_path();
|
||||
break;
|
||||
case DataType::MIDI:
|
||||
str = _session->config.get_midi_search_path();
|
||||
break;
|
||||
}
|
||||
|
||||
split (str, dirs, ':');
|
||||
|
||||
newdir = chooser.get_filename ();
|
||||
|
||||
for (vector<string>::iterator d = dirs.begin(); d != dirs.end(); d++) {
|
||||
if (*d == newdir) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!str.empty()) {
|
||||
str += ':';
|
||||
}
|
||||
|
||||
str += newdir;
|
||||
|
||||
switch (filetype) {
|
||||
case DataType::AUDIO:
|
||||
_session->config.set_audio_search_path (str);
|
||||
break;
|
||||
case DataType::MIDI:
|
||||
_session->config.set_midi_search_path (str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
MissingFileDialog::get_action ()
|
||||
{
|
||||
|
||||
if (use_chosen.get_active ()) {
|
||||
add_chosen ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (use_chosen_and_no_more_questions.get_active()) {
|
||||
add_chosen ();
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (this_missing_ok.get_active()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (all_missing_ok.get_active ()) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
39
gtk2_ardour/missing_file_dialog.h
Normal file
39
gtk2_ardour/missing_file_dialog.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef __gtk_ardour_missing_file_dialog_h__
|
||||
#define __gtk_ardour_missing_file_dialog_h__
|
||||
|
||||
#include <string>
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/filechooserwidget.h>
|
||||
#include <gtkmm/radiobutton.h>
|
||||
|
||||
#include "ardour/types.h"
|
||||
|
||||
#include "ardour_dialog.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class Session;
|
||||
}
|
||||
|
||||
class MissingFileDialog : public ArdourDialog
|
||||
{
|
||||
public:
|
||||
MissingFileDialog (ARDOUR::Session*, const std::string& path, ARDOUR::DataType type);
|
||||
|
||||
int get_action();
|
||||
|
||||
private:
|
||||
ARDOUR::DataType filetype;
|
||||
|
||||
Gtk::FileChooserWidget chooser;
|
||||
Gtk::RadioButton use_chosen;
|
||||
Gtk::RadioButton::Group choice_group;
|
||||
Gtk::RadioButton use_chosen_and_no_more_questions;
|
||||
Gtk::RadioButton stop_loading_button;
|
||||
Gtk::RadioButton all_missing_ok;
|
||||
Gtk::RadioButton this_missing_ok;
|
||||
Gtk::Label msg;
|
||||
|
||||
void add_chosen ();
|
||||
};
|
||||
|
||||
#endif /* __gtk_ardour_missing_file_dialog_h__ */
|
|
@ -136,7 +136,7 @@ public:
|
|||
return _id;
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
|
||||
std::string _id;
|
||||
std::string _name;
|
||||
|
|
156
gtk2_ardour/search_path_option.cc
Normal file
156
gtk2_ardour/search_path_option.cc
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
Copyright (C) 2010 Paul Davis
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "pbd/strsplit.h"
|
||||
#include "search_path_option.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Gtk;
|
||||
|
||||
SearchPathOption::SearchPathOption (const string& pathname, const string& label,
|
||||
sigc::slot<std::string> get, sigc::slot<bool, std::string> set)
|
||||
: Option (pathname, label)
|
||||
, _get (get)
|
||||
, _set (set)
|
||||
, add_chooser (_("Select folder to search for media"), FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
||||
{
|
||||
add_chooser.signal_file_set().connect (sigc::mem_fun (*this, &SearchPathOption::path_chosen));
|
||||
|
||||
HBox* hbox = manage (new HBox);
|
||||
|
||||
hbox->set_border_width (12);
|
||||
hbox->set_spacing (6);
|
||||
hbox->pack_end (add_chooser, false, false);
|
||||
hbox->pack_end (*manage (new Label ("Click to add a new location")), false, false);
|
||||
hbox->show_all ();
|
||||
|
||||
vbox.pack_start (path_box);
|
||||
vbox.pack_end (*hbox);
|
||||
|
||||
session_label.set_use_markup (true);
|
||||
session_label.set_markup (string_compose ("<i>%1</i>", _("the session folder")));
|
||||
session_label.set_alignment (0.0, 0.5);
|
||||
session_label.show ();
|
||||
}
|
||||
|
||||
SearchPathOption::~SearchPathOption()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
SearchPathOption::path_chosen ()
|
||||
{
|
||||
string path = add_chooser.get_filename ();
|
||||
add_path (path);
|
||||
}
|
||||
|
||||
void
|
||||
SearchPathOption::add_to_page (OptionEditorPage* p)
|
||||
{
|
||||
int const n = p->table.property_n_rows();
|
||||
p->table.resize (n + 2, 3);
|
||||
|
||||
Label* label = manage (new Label);
|
||||
label->set_alignment (0.0, 0.5);
|
||||
label->set_markup (string_compose ("<b>%1</b>", _name));
|
||||
|
||||
p->table.attach (*label, 0, 1, n, n + 1, FILL | EXPAND);
|
||||
p->table.attach (vbox, 0, 3, n + 1, n + 2, FILL | EXPAND);
|
||||
}
|
||||
|
||||
void
|
||||
SearchPathOption::clear ()
|
||||
{
|
||||
path_box.remove (session_label);
|
||||
for (list<PathEntry*>::iterator p = paths.begin(); p != paths.end(); ++p) {
|
||||
path_box.remove ((*p)->box);
|
||||
delete *p;
|
||||
}
|
||||
paths.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
SearchPathOption::set_state_from_config ()
|
||||
{
|
||||
string str = _get ();
|
||||
vector<string> dirs;
|
||||
|
||||
clear ();
|
||||
path_box.pack_start (session_label);
|
||||
|
||||
split (str, dirs, ':');
|
||||
|
||||
for (vector<string>::iterator d = dirs.begin(); d != dirs.end(); ++d) {
|
||||
add_path (*d);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SearchPathOption::changed ()
|
||||
{
|
||||
string str;
|
||||
|
||||
for (list<PathEntry*>::iterator p = paths.begin(); p != paths.end(); ++p) {
|
||||
|
||||
if (p == paths.begin()) {
|
||||
/* skip first entry, its always "the session"
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!str.empty()) {
|
||||
str += ':';
|
||||
}
|
||||
str += (*p)->entry.get_text ();
|
||||
}
|
||||
|
||||
_set (str);
|
||||
}
|
||||
|
||||
void
|
||||
SearchPathOption::add_path (const string& path, bool removable)
|
||||
{
|
||||
PathEntry* pe = new PathEntry (path, removable);
|
||||
paths.push_back (pe);
|
||||
path_box.pack_start (pe->box, false, false);
|
||||
}
|
||||
|
||||
void
|
||||
SearchPathOption::remove_path (const string& path)
|
||||
{
|
||||
}
|
||||
|
||||
SearchPathOption::PathEntry::PathEntry (const std::string& path, bool removable)
|
||||
: remove_button (Stock::REMOVE)
|
||||
{
|
||||
entry.set_text (path);
|
||||
entry.show ();
|
||||
|
||||
box.set_spacing (6);
|
||||
box.set_homogeneous (false);
|
||||
box.pack_start (entry, true, true);
|
||||
|
||||
if (removable) {
|
||||
box.pack_start (remove_button, false, false);
|
||||
remove_button.show ();
|
||||
}
|
||||
|
||||
box.show ();
|
||||
}
|
50
gtk2_ardour/search_path_option.h
Normal file
50
gtk2_ardour/search_path_option.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef __gtk_ardour_search_path_option_h__
|
||||
#define __gtk_ardour_search_path_option_h__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gtkmm/filechooserbutton.h>
|
||||
#include <gtkmm/entry.h>
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/box.h>
|
||||
|
||||
#include "option_editor.h"
|
||||
|
||||
class SearchPathOption : public Option
|
||||
{
|
||||
public:
|
||||
SearchPathOption (const std::string& pathname, const std::string& label,
|
||||
sigc::slot<std::string>, sigc::slot<bool, std::string>);
|
||||
~SearchPathOption ();
|
||||
|
||||
void set_state_from_config ();
|
||||
void add_to_page (OptionEditorPage*);
|
||||
void clear ();
|
||||
|
||||
protected:
|
||||
sigc::slot<std::string> _get; ///< slot to get the configuration variable's value
|
||||
sigc::slot<bool, std::string> _set; ///< slot to set the configuration variable's value
|
||||
|
||||
struct PathEntry {
|
||||
PathEntry (const std::string& path, bool removable=true);
|
||||
|
||||
Gtk::Entry entry;
|
||||
Gtk::Button remove_button;
|
||||
Gtk::HBox box;
|
||||
|
||||
std::string path;
|
||||
};
|
||||
|
||||
std::list<PathEntry*> paths;
|
||||
Gtk::FileChooserButton add_chooser;
|
||||
Gtk::VBox vbox;
|
||||
Gtk::VBox path_box;
|
||||
Gtk::Label session_label;
|
||||
|
||||
void add_path (const std::string& path, bool removable=true);
|
||||
void remove_path (const std::string& path);
|
||||
void changed ();
|
||||
void path_chosen ();
|
||||
};
|
||||
|
||||
#endif /* __gtk_ardour_search_path_option_h__ */
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "gui_thread.h"
|
||||
#include "session_option_editor.h"
|
||||
#include "search_path_option.h"
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -177,9 +178,9 @@ SessionOptionEditor::SessionOptionEditor (Session* s)
|
|||
sigc::mem_fun (*_session_config, &SessionConfiguration::set_show_region_fades)
|
||||
));
|
||||
|
||||
/* MISC */
|
||||
/* Media */
|
||||
|
||||
add_option (_("Misc"), new OptionEditorHeading (_("Audio file format")));
|
||||
add_option (_("Media"), new OptionEditorHeading (_("Audio file format")));
|
||||
|
||||
ComboOption<SampleFormat>* sf = new ComboOption<SampleFormat> (
|
||||
"native-file-data-format",
|
||||
|
@ -192,7 +193,7 @@ SessionOptionEditor::SessionOptionEditor (Session* s)
|
|||
sf->add (FormatInt24, _("24-bit integer"));
|
||||
sf->add (FormatInt16, _("16-bit integer"));
|
||||
|
||||
add_option (_("Misc"), sf);
|
||||
add_option (_("Media"), sf);
|
||||
|
||||
ComboOption<HeaderFormat>* hf = new ComboOption<HeaderFormat> (
|
||||
"native-file-header-format",
|
||||
|
@ -206,13 +207,28 @@ SessionOptionEditor::SessionOptionEditor (Session* s)
|
|||
hf->add (WAVE64, _("WAVE-64"));
|
||||
hf->add (CAF, _("CAF"));
|
||||
|
||||
add_option (_("Misc"), hf);
|
||||
add_option (_("Media"), hf);
|
||||
|
||||
add_option (_("Media"), new OptionEditorHeading (_("Media Locations")));
|
||||
|
||||
add_option (_("Misc"), new OptionEditorHeading (_("Layering")));
|
||||
SearchPathOption* spo = new SearchPathOption ("audio-search-path", _("Search for audio files in:"),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::get_audio_search_path),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::set_audio_search_path));
|
||||
add_option (_("Media"), spo);
|
||||
|
||||
spo = new SearchPathOption ("midi-search-path", _("Search for MIDI files in:"),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::get_midi_search_path),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::set_midi_search_path));
|
||||
|
||||
add_option (_("Media"), spo);
|
||||
|
||||
/* Misc */
|
||||
|
||||
add_option (_("Misc"), new OptionEditorHeading (_("Layering (in overlaid mode)")));
|
||||
|
||||
ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
|
||||
"layer-model",
|
||||
_("Layering model in overlaid mode"),
|
||||
_("Layering model"),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::get_layer_model),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::set_layer_model)
|
||||
);
|
||||
|
@ -227,7 +243,7 @@ SessionOptionEditor::SessionOptionEditor (Session* s)
|
|||
|
||||
ComboOption<InsertMergePolicy>* li = new ComboOption<InsertMergePolicy> (
|
||||
"insert-merge-policy",
|
||||
_("Policy for handling same note and channel overlaps"),
|
||||
_("Policy for handling same note\nand channel overlaps"),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::get_insert_merge_policy),
|
||||
sigc::mem_fun (*_session_config, &SessionConfiguration::set_insert_merge_policy)
|
||||
);
|
||||
|
|
|
@ -141,6 +141,7 @@ gtk2_ardour_sources = [
|
|||
'midi_streamview.cc',
|
||||
'midi_time_axis.cc',
|
||||
'midi_tracer.cc',
|
||||
'missing_file_dialog.cc',
|
||||
'mixer_group_tabs.cc',
|
||||
'mixer_strip.cc',
|
||||
'mixer_ui.cc',
|
||||
|
@ -186,6 +187,7 @@ gtk2_ardour_sources = [
|
|||
'route_processor_selection.cc',
|
||||
'route_time_axis.cc',
|
||||
'route_ui.cc',
|
||||
'search_path_option.cc',
|
||||
'selection.cc',
|
||||
'send_ui.cc',
|
||||
'session_import_dialog.cc',
|
||||
|
|
|
@ -20,15 +20,25 @@
|
|||
#ifndef __ardour_filesource_h__
|
||||
#define __ardour_filesource_h__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <time.h>
|
||||
#include "ardour/source.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class MissingSource : public std::exception {
|
||||
public:
|
||||
class MissingSource : public std::exception
|
||||
{
|
||||
public:
|
||||
MissingSource (const std::string& p, DataType t) throw ()
|
||||
: path (p), type (t) {}
|
||||
~MissingSource() throw() {}
|
||||
|
||||
virtual const char *what() const throw() { return "source file does not exist"; }
|
||||
|
||||
std::string path;
|
||||
DataType type;
|
||||
};
|
||||
|
||||
/** A source associated with a file on disk somewhere */
|
||||
|
@ -54,15 +64,19 @@ public:
|
|||
|
||||
int set_source_name (const std::string& newname, bool destructive);
|
||||
|
||||
static void set_search_path (DataType type, const std::string& path);
|
||||
static bool find (Session&, DataType type, const std::string& path,
|
||||
bool must_exist, bool& is_new, uint16_t& chan,
|
||||
std::string& found_path);
|
||||
|
||||
static bool find (DataType type, const std::string& path,
|
||||
bool must_exist, bool& is_new, uint16_t& chan,
|
||||
std::string& found_path);
|
||||
static bool find_2X (Session&, DataType type, const std::string& path,
|
||||
bool must_exist, bool& is_new, uint16_t& chan,
|
||||
std::string& found_path);
|
||||
|
||||
void inc_use_count ();
|
||||
bool removable () const;
|
||||
|
||||
static PBD::Signal3<int,std::string,std::string,std::vector<std::string> > AmbiguousFileName;
|
||||
|
||||
protected:
|
||||
FileSource (Session& session, DataType type,
|
||||
const std::string& path,
|
||||
|
@ -81,8 +95,6 @@ protected:
|
|||
bool _file_is_new;
|
||||
uint16_t _channel;
|
||||
bool _within_session;
|
||||
|
||||
static std::map<DataType, std::string> search_paths;
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
@ -785,6 +785,19 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
void request_resume_timecode_transmission ();
|
||||
bool timecode_transmission_suspended () const;
|
||||
|
||||
std::string source_search_path(DataType) const;
|
||||
|
||||
/* handlers can return an integer value:
|
||||
0: config.set_audio_search_path() or config.set_midi_search_path() was used
|
||||
to modify the search path and we should try to find it again.
|
||||
1: quit entire session load
|
||||
2: as 0, but don't ask about other missing files
|
||||
3: don't ask about other missing files, and just mark this one missing
|
||||
-1: just mark this one missing
|
||||
any other value: as -1
|
||||
*/
|
||||
static PBD::Signal3<int,Session*,std::string,DataType> MissingFile;
|
||||
|
||||
/** Emitted when the session wants Ardour to quit */
|
||||
static PBD::Signal0<void> Quit;
|
||||
|
||||
|
@ -1310,6 +1323,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
uint32_t _total_free_4k_blocks;
|
||||
Glib::Mutex space_lock;
|
||||
|
||||
bool no_questions_about_missing_files;
|
||||
|
||||
std::string get_best_session_directory_for_new_source ();
|
||||
|
||||
mutable gint _playback_load;
|
||||
|
|
|
@ -35,6 +35,8 @@ CONFIG_VARIABLE (bool, punch_out, "punch-out", false)
|
|||
CONFIG_VARIABLE (uint32_t, subframes_per_frame, "subframes-per-frame", 100)
|
||||
CONFIG_VARIABLE (TimecodeFormat, timecode_format, "timecode-format", timecode_30)
|
||||
CONFIG_VARIABLE_SPECIAL(std::string, raid_path, "raid-path", "", path_expand)
|
||||
CONFIG_VARIABLE_SPECIAL(std::string, audio_search_path, "audio-search-path", "", path_expand)
|
||||
CONFIG_VARIABLE_SPECIAL(std::string, midi_search_path, "midi-search-path", "", path_expand)
|
||||
CONFIG_VARIABLE (std::string, bwf_country_code, "bwf-country-code", "US")
|
||||
CONFIG_VARIABLE (std::string, bwf_organization_code, "bwf-organization-code", "US")
|
||||
CONFIG_VARIABLE (LayerModel, layer_model, "layer-model", MoveAddHigher)
|
||||
|
|
|
@ -52,7 +52,7 @@ using namespace ARDOUR;
|
|||
using namespace PBD;
|
||||
using namespace Glib;
|
||||
|
||||
map<DataType, string> FileSource::search_paths;
|
||||
PBD::Signal3<int,std::string,std::string,std::vector<std::string> > FileSource::AmbiguousFileName;
|
||||
|
||||
FileSource::FileSource (Session& session, DataType type, const string& path, Source::Flag flag)
|
||||
: Source(session, type, path, flag)
|
||||
|
@ -84,8 +84,6 @@ FileSource::removable () const
|
|||
&& ((_flags & RemoveAtDestroy) ||
|
||||
((_flags & RemovableIfEmpty) && empty() == 0)));
|
||||
|
||||
cerr << "is " << _path << " removable ? " << r << endl;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -94,9 +92,15 @@ FileSource::init (const string& pathstr, bool must_exist)
|
|||
{
|
||||
_timeline_position = 0;
|
||||
|
||||
if (!find (_type, pathstr, must_exist, _file_is_new, _channel, _path)) {
|
||||
throw MissingSource ();
|
||||
}
|
||||
if (Stateful::loading_state_version < 3000) {
|
||||
if (!find_2X (_session, _type, pathstr, must_exist, _file_is_new, _channel, _path)) {
|
||||
throw MissingSource (pathstr, _type);
|
||||
}
|
||||
} else {
|
||||
if (!find (_session, _type, pathstr, must_exist, _file_is_new, _channel, _path)) {
|
||||
throw MissingSource (pathstr, _type);
|
||||
}
|
||||
}
|
||||
|
||||
set_within_session_from_path (pathstr);
|
||||
|
||||
|
@ -204,10 +208,100 @@ FileSource::move_to_trash (const string& trash_dir_name)
|
|||
* \return true iff the file was found.
|
||||
*/
|
||||
bool
|
||||
FileSource::find (DataType type, const string& path, bool must_exist,
|
||||
FileSource::find (Session& s, DataType type, const string& path, bool must_exist,
|
||||
bool& isnew, uint16_t& chan, string& found_path)
|
||||
{
|
||||
string search_path = search_paths[type];
|
||||
string search_path = s.source_search_path (type);
|
||||
|
||||
string pathstr = path;
|
||||
bool ret = false;
|
||||
|
||||
cerr << "Searching along " << search_path << endl;
|
||||
|
||||
isnew = false;
|
||||
|
||||
vector<string> dirs;
|
||||
vector<string> hits;
|
||||
int cnt;
|
||||
string fullpath;
|
||||
string keeppath;
|
||||
|
||||
if (search_path.length() == 0) {
|
||||
error << _("FileSource: search path not set") << endmsg;
|
||||
goto out;
|
||||
}
|
||||
|
||||
split (search_path, dirs, ':');
|
||||
|
||||
cnt = 0;
|
||||
hits.clear ();
|
||||
|
||||
for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
|
||||
|
||||
cerr << "Searching in " << *i << " for " << pathstr << endl;
|
||||
|
||||
fullpath = Glib::build_filename (*i, pathstr);
|
||||
|
||||
if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
|
||||
keeppath = fullpath;
|
||||
hits.push_back (fullpath);
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt > 1) {
|
||||
|
||||
int which = FileSource::AmbiguousFileName (pathstr, search_path, hits).get_value_or (-1);
|
||||
|
||||
if (which < 0) {
|
||||
goto out;
|
||||
} else {
|
||||
keeppath = hits[which];
|
||||
}
|
||||
|
||||
} else if (cnt == 0) {
|
||||
|
||||
if (must_exist) {
|
||||
error << string_compose(
|
||||
_("Filesource: cannot find required file (%1): while searching %2"),
|
||||
pathstr, search_path) << endmsg;
|
||||
goto out;
|
||||
} else {
|
||||
isnew = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Current find() is unable to parse relative path names to yet non-existant
|
||||
sources. QuickFix(tm)
|
||||
*/
|
||||
if (keeppath == "") {
|
||||
if (must_exist) {
|
||||
error << "FileSource::find(), keeppath = \"\", but the file must exist" << endl;
|
||||
} else {
|
||||
keeppath = pathstr;
|
||||
}
|
||||
}
|
||||
|
||||
found_path = keeppath;
|
||||
|
||||
ret = true;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Find the actual source file based on \a filename.
|
||||
*
|
||||
* If the source is within the session tree, \a filename should be a simple filename (no slashes).
|
||||
* If the source is external, \a filename should be a full path.
|
||||
* In either case, found_path is set to the complete absolute path of the source file.
|
||||
* \return true iff the file was found.
|
||||
*/
|
||||
bool
|
||||
FileSource::find_2X (Session& s, DataType type, const string& path, bool must_exist,
|
||||
bool& isnew, uint16_t& chan, string& found_path)
|
||||
{
|
||||
string search_path = s.source_search_path (type);
|
||||
|
||||
string pathstr = path;
|
||||
string::size_type pos;
|
||||
|
@ -397,12 +491,6 @@ FileSource::set_source_name (const string& newname, bool destructive)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
FileSource::set_search_path (DataType type, const string& p)
|
||||
{
|
||||
search_paths[type] = p;
|
||||
}
|
||||
|
||||
void
|
||||
FileSource::mark_immutable ()
|
||||
{
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "pbd/stacktrace.h"
|
||||
#include "pbd/file_utils.h"
|
||||
#include "pbd/convert.h"
|
||||
#include "pbd/strsplit.h"
|
||||
|
||||
#include "ardour/amp.h"
|
||||
#include "ardour/analyser.h"
|
||||
|
@ -117,6 +118,7 @@ PBD::Signal1<void,std::string> Session::Dialog;
|
|||
PBD::Signal0<int> Session::AskAboutPendingState;
|
||||
PBD::Signal2<int,nframes_t,nframes_t> Session::AskAboutSampleRateMismatch;
|
||||
PBD::Signal0<void> Session::SendFeedback;
|
||||
PBD::Signal3<int,Session*,std::string,DataType> Session::MissingFile;
|
||||
|
||||
PBD::Signal0<void> Session::TimecodeOffsetChanged;
|
||||
PBD::Signal1<void, framepos_t> Session::StartTimeChanged;
|
||||
|
@ -4060,3 +4062,58 @@ Session::end_time_changed (framepos_t old)
|
|||
l->set_end (s->end(), true);
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
Session::source_search_path (DataType type) const
|
||||
{
|
||||
string search_path;
|
||||
|
||||
if (session_dirs.size() == 1) {
|
||||
switch (type) {
|
||||
case DataType::AUDIO:
|
||||
search_path = _session_dir->sound_path().to_string();
|
||||
break;
|
||||
case DataType::MIDI:
|
||||
search_path = _session_dir->midi_path().to_string();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
|
||||
SessionDirectory sdir (i->path);
|
||||
if (!search_path.empty()) {
|
||||
search_path += ':';
|
||||
}
|
||||
switch (type) {
|
||||
case DataType::AUDIO:
|
||||
search_path += sdir.sound_path().to_string();
|
||||
break;
|
||||
case DataType::MIDI:
|
||||
search_path += sdir.midi_path().to_string();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* now add user-specified locations
|
||||
*/
|
||||
|
||||
vector<string> dirs;
|
||||
|
||||
switch (type) {
|
||||
case DataType::AUDIO:
|
||||
split (config.get_audio_search_path (), dirs, ':');
|
||||
break;
|
||||
case DataType::MIDI:
|
||||
split (config.get_midi_search_path (), dirs, ':');
|
||||
break;
|
||||
}
|
||||
|
||||
for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
|
||||
search_path += ':';
|
||||
search_path += *i;
|
||||
|
||||
}
|
||||
|
||||
return search_path;
|
||||
}
|
||||
|
||||
|
|
|
@ -217,6 +217,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
|
|||
post_export_sync = false;
|
||||
midi_control_ui = 0;
|
||||
_step_editors = 0;
|
||||
no_questions_about_missing_files = false;
|
||||
|
||||
AudioDiskstream::allocate_working_buffers();
|
||||
|
||||
|
@ -423,10 +424,6 @@ Session::setup_raid_path (string path)
|
|||
midi_search_path += sdir.midi_path ();
|
||||
}
|
||||
|
||||
// set the search path for each data type
|
||||
FileSource::set_search_path (DataType::AUDIO, sound_search_path.to_string ());
|
||||
SMFSource::set_search_path (DataType::MIDI, midi_search_path.to_string ());
|
||||
|
||||
// reset the round-robin soundfile path thingie
|
||||
last_rr_session_dir = session_dirs.begin();
|
||||
}
|
||||
|
@ -1871,13 +1868,47 @@ Session::load_sources (const XMLNode& node)
|
|||
set_dirty();
|
||||
|
||||
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
||||
retry:
|
||||
try {
|
||||
if ((source = XMLSourceFactory (**niter)) == 0) {
|
||||
error << _("Session: cannot create Source from XML description.") << endmsg;
|
||||
}
|
||||
|
||||
} catch (MissingSource& err) {
|
||||
warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
|
||||
source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
|
||||
|
||||
int user_choice;
|
||||
|
||||
if (!no_questions_about_missing_files) {
|
||||
user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
|
||||
} else {
|
||||
user_choice = -2;
|
||||
}
|
||||
|
||||
switch (user_choice) {
|
||||
case 0:
|
||||
/* user added a new search location, so try again */
|
||||
goto retry;
|
||||
|
||||
|
||||
case 1:
|
||||
/* user asked to quit the entire session load
|
||||
*/
|
||||
return -1;
|
||||
|
||||
case 2:
|
||||
no_questions_about_missing_files = true;
|
||||
goto retry;
|
||||
|
||||
case 3:
|
||||
no_questions_about_missing_files = true;
|
||||
/* fallthru */
|
||||
|
||||
case -1:
|
||||
default:
|
||||
warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
|
||||
source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2421,7 +2452,7 @@ Session::find_all_sources (string path, set<string>& result)
|
|||
bool is_new;
|
||||
uint16_t chan;
|
||||
|
||||
if (FileSource::find (type, prop->value(), true, is_new, chan, found_path)) {
|
||||
if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
|
||||
result.insert (found_path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,7 +144,6 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
|
|||
if (type == DataType::AUDIO) {
|
||||
|
||||
try {
|
||||
|
||||
Source* src = new SndFileSource (s, node);
|
||||
// boost_debug_shared_ptr_mark_interesting (src, "Source");
|
||||
boost::shared_ptr<Source> ret (src);
|
||||
|
|
Loading…
Reference in New Issue
Block a user