+ bool same_size;
+ bool src_needed;
+ bool selection_includes_multichannel;
+ bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
+ ImportMode mode;
+
+ if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
+ Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
+ return false;
+ }
+
+ string existing_choice;
+ vector<string> action_strings;
+
+ if (selected_track_cnt > 0) {
+ if (channel_combo.get_active_text().length()) {
+ ImportDisposition id = get_channel_disposition();
+
+ switch (id) {
+ case Editing::ImportDistinctFiles:
+ if (selected_track_cnt == paths.size()) {
+ action_strings.push_back (importmode2string (ImportToTrack));
+ }
+ break;
+
+ case Editing::ImportDistinctChannels:
+ /* XXX it would be nice to allow channel-per-selected track
+ but its too hard we don't want to deal with all the
+ different per-file + per-track channel configurations.
+ */
+ break;
+
+ default:
+ action_strings.push_back (importmode2string (ImportToTrack));
+ break;
+ }
+ }
+ }
+
+ action_strings.push_back (importmode2string (ImportAsTrack));
+ action_strings.push_back (importmode2string (ImportAsRegion));
+ action_strings.push_back (importmode2string (ImportAsTapeTrack));
+
+ resetting_ourselves = true;
+
+ existing_choice = action_combo.get_active_text();
+
+ set_popdown_strings (action_combo, action_strings);
+
+ /* preserve any existing choice, if possible */
+
+
+ if (existing_choice.length()) {
+ vector<string>::iterator x;
+ for (x = action_strings.begin(); x != action_strings.end(); ++x) {
+ if (*x == existing_choice) {
+ action_combo.set_active_text (existing_choice);
+ break;
+ }
+ }
+ if (x == action_strings.end()) {
+ action_combo.set_active_text (action_strings.front());
+ }
+ } else {
+ action_combo.set_active_text (action_strings.front());
+ }
+
+ resetting_ourselves = false;
+
+ if ((mode = get_mode()) == ImportAsRegion) {
+ where_combo.set_sensitive (false);
+ } else {
+ where_combo.set_sensitive (true);
+ }
+
+ vector<string> channel_strings;
+
+ if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
+ channel_strings.push_back (_("one track per file"));
+
+ if (selection_includes_multichannel) {
+ channel_strings.push_back (_("one track per channel"));
+ }
+
+ if (paths.size() > 1) {
+ /* tape tracks are a single region per track, so we cannot
+ sequence multiple files.
+ */
+ if (mode != ImportAsTapeTrack) {
+ channel_strings.push_back (_("sequence files"));
+ }
+ if (same_size) {
+ channel_strings.push_back (_("all files in one track"));
+ channel_strings.push_back (_("merge files"));
+ }
+
+ }
+
+ } else {
+ channel_strings.push_back (_("one region per file"));
+
+ if (selection_includes_multichannel) {
+ channel_strings.push_back (_("one region per channel"));
+ }
+
+ if (paths.size() > 1) {
+ if (same_size) {
+ channel_strings.push_back (_("all files in one region"));
+ }
+ }
+ }
+
+ resetting_ourselves = true;
+
+ existing_choice = channel_combo.get_active_text();
+
+ set_popdown_strings (channel_combo, channel_strings);
+
+ /* preserve any existing choice, if possible */
+
+ if (existing_choice.length()) {
+ vector<string>::iterator x;
+ for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
+ if (*x == existing_choice) {
+ channel_combo.set_active_text (existing_choice);
+ break;
+ }
+ }
+ if (x == channel_strings.end()) {
+ channel_combo.set_active_text (channel_strings.front());
+ }
+ } else {
+ channel_combo.set_active_text (channel_strings.front());
+ }
+
+ resetting_ourselves = false;
+
+ if (src_needed) {
+ src_combo.set_sensitive (true);
+ } else {
+ src_combo.set_sensitive (false);
+ }
+
+ if (Config->get_only_copy_imported_files()) {
+
+ if (selection_can_be_embedded_with_links) {
+ copy_files_btn.set_sensitive (true);
+ } else {
+ copy_files_btn.set_sensitive (false);
+ }
+
+ } else {
+
+ copy_files_btn.set_sensitive (true);
+ }
+
+ return true;
+}
+
+
+bool
+SoundFileOmega::bad_file_message()
+{
+ MessageDialog msg (*this,
+ string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
+ true,
+ Gtk::MESSAGE_INFO,
+ Gtk::BUTTONS_OK);
+ msg.run ();
+ resetting_ourselves = true;
+ chooser.unselect_uri (chooser.get_preview_uri());
+ resetting_ourselves = false;
+
+ return false;
+}
+
+bool
+SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
+{
+ SoundFileInfo info;
+ framepos_t sz = 0;
+ bool err = false;
+ string errmsg;
+
+ same_size = true;
+ src_needed = false;
+ multichannel = false;
+
+ for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
+
+ if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
+ if (info.channels > 1) {
+ multichannel = true;
+ }
+ if (sz == 0) {
+ sz = info.length;
+ } else {
+ if (sz != info.length) {
+ same_size = false;
+ }
+ }
+
+ if (info.samplerate != _session->frame_rate()) {
+ src_needed = true;
+ }
+
+ } else if (SMFSource::safe_midi_file_extension (*i)) {
+
+ Evoral::SMF reader;
+ reader.open(*i);
+ if (reader.num_tracks() > 1) {
+ multichannel = true; // "channel" == track here...
+ }
+
+ /* XXX we need err = true handling here in case
+ we can't check the file
+ */
+
+ } else {
+ err = true;
+ }
+ }
+
+ return err;
+}
+
+
+bool
+SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
+{
+ sys::path path = s->session_directory().sound_path() / "linktest";
+ string tmpdir = path.to_string();
+ bool ret = false;
+
+ if (mkdir (tmpdir.c_str(), 0744)) {
+ if (errno != EEXIST) {
+ return false;
+ }
+ }
+
+ for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
+
+ char tmpc[MAXPATHLEN+1];
+
+ snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
+
+ /* can we link ? */
+
+ if (link ((*i).c_str(), tmpc)) {
+ goto out;
+ }
+
+ unlink (tmpc);
+ }
+
+ ret = true;
+
+ out:
+ rmdir (tmpdir.c_str());
+ return ret;
+}
+
+SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
+ : SoundFileBrowser (parent, title, s, false)
+{
+ chooser.set_select_multiple (false);
+ found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
+ freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
+}
+
+void
+SoundFileChooser::on_hide ()
+{
+ ArdourDialog::on_hide();
+ stop_metering ();
+
+ if (_session) {
+ _session->cancel_audition();
+ }
+}
+
+string
+SoundFileChooser::get_filename ()
+{
+ vector<string> paths;
+
+ paths = get_paths ();
+
+ if (paths.empty()) {
+ return string ();
+ }
+
+ if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
+ return string();
+ }
+
+ return paths.front();
+}
+
+SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
+ Editing::ImportMode mode_hint)
+ : SoundFileBrowser (parent, title, s, persistent),
+ copy_files_btn ( _("Copy files to session")),
+ selected_track_cnt (selected_tracks)
+{
+ VBox* vbox;
+ HBox* hbox;
+ vector<string> str;
+
+ set_size_request (-1, 450);
+
+ block_two.set_border_width (12);
+ block_three.set_border_width (12);
+ block_four.set_border_width (12);
+
+ options.set_spacing (12);
+
+ str.clear ();
+ str.push_back (_("file timestamp"));
+ str.push_back (_("edit point"));
+ str.push_back (_("playhead"));
+ str.push_back (_("session start"));
+ set_popdown_strings (where_combo, str);
+ where_combo.set_active_text (str.front());
+
+ Label* l = manage (new Label);
+ l->set_text (_("Add files:"));
+
+ hbox = manage (new HBox);
+ hbox->set_border_width (12);
+ hbox->set_spacing (6);
+ hbox->pack_start (*l, false, false);
+ hbox->pack_start (action_combo, false, false);
+ vbox = manage (new VBox);
+ vbox->pack_start (*hbox, false, false);
+ options.pack_start (*vbox, false, false);
+
+ /* dummy entry for action combo so that it doesn't look odd if we
+ come up with no tracks selected.
+ */
+
+ str.clear ();
+ str.push_back (importmode2string (mode_hint));
+ set_popdown_strings (action_combo, str);
+ action_combo.set_active_text (str.front());
+ action_combo.set_sensitive (false);
+
+ l = manage (new Label);
+ l->set_text (_("Insert at:"));
+
+ hbox = manage (new HBox);
+ hbox->set_border_width (12);
+ hbox->set_spacing (6);
+ hbox->pack_start (*l, false, false);
+ hbox->pack_start (where_combo, false, false);
+ vbox = manage (new VBox);
+ vbox->pack_start (*hbox, false, false);
+ options.pack_start (*vbox, false, false);
+
+
+ l = manage (new Label);
+ l->set_text (_("Mapping:"));
+
+ hbox = manage (new HBox);
+ hbox->set_border_width (12);
+ hbox->set_spacing (6);
+ hbox->pack_start (*l, false, false);
+ hbox->pack_start (channel_combo, false, false);
+ vbox = manage (new VBox);
+ vbox->pack_start (*hbox, false, false);
+ options.pack_start (*vbox, false, false);
+
+ str.clear ();
+ str.push_back (_("one track per file"));
+ set_popdown_strings (channel_combo, str);
+ channel_combo.set_active_text (str.front());
+ channel_combo.set_sensitive (false);
+
+ l = manage (new Label);
+ l->set_text (_("Conversion quality:"));
+
+ hbox = manage (new HBox);
+ hbox->set_border_width (12);
+ hbox->set_spacing (6);
+ hbox->pack_start (*l, false, false);
+ hbox->pack_start (src_combo, false, false);
+ vbox = manage (new VBox);
+ vbox->pack_start (*hbox, false, false);
+ options.pack_start (*vbox, false, false);
+
+ str.clear ();
+ str.push_back (_("Best"));
+ str.push_back (_("Good"));
+ str.push_back (_("Quick"));
+ str.push_back (_("Fast"));
+ str.push_back (_("Fastest"));
+
+ set_popdown_strings (src_combo, str);
+ src_combo.set_active_text (str.front());
+ src_combo.set_sensitive (false);
+
+ reset_options ();
+
+ action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
+ channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
+
+ copy_files_btn.set_active (true);
+
+ block_four.pack_start (copy_files_btn, false, false);
+
+ options.pack_start (block_four, false, false);
+
+ get_vbox()->pack_start (options, false, false);
+
+ /* setup disposition map */
+
+ disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
+ disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
+ disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
+ disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
+
+ disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
+ disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
+ disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
+ disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
+
+ chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
+
+ /* set size requests for a couple of combos to allow them to display the longest text
+ they will ever be asked to display. This prevents them being resized when the user
+ selects a file to import, which in turn prevents the size of the dialog from jumping
+ around. */
+
+ vector<string> t;
+ t.push_back (_("one track per file"));
+ t.push_back (_("one track per channel"));
+ t.push_back (_("sequence files"));
+ t.push_back (_("all files in one region"));
+ set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
+
+ t.clear ();
+ t.push_back (importmode2string (ImportAsTrack));
+ t.push_back (importmode2string (ImportToTrack));
+ t.push_back (importmode2string (ImportAsRegion));
+ t.push_back (importmode2string (ImportAsTapeTrack));
+ set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
+}
+
+void
+SoundFileOmega::set_mode (ImportMode mode)
+{
+ action_combo.set_active_text (importmode2string (mode));
+}
+
+ImportMode
+SoundFileOmega::get_mode () const
+{
+ return string2importmode (action_combo.get_active_text());
+}
+
+void
+SoundFileOmega::on_hide ()
+{
+ ArdourDialog::on_hide();
+ if (_session) {
+ _session->cancel_audition();
+ }
+}
+
+ImportPosition
+SoundFileOmega::get_position() const
+{
+ string str = where_combo.get_active_text();
+
+ if (str == _("file timestamp")) {
+ return ImportAtTimestamp;
+ } else if (str == _("edit point")) {
+ return ImportAtEditPoint;
+ } else if (str == _("playhead")) {
+ return ImportAtPlayhead;
+ } else {
+ return ImportAtStart;
+ }
+}
+
+SrcQuality
+SoundFileOmega::get_src_quality() const
+{
+ string str = where_combo.get_active_text();
+
+ if (str == _("Best")) {
+ return SrcBest;
+ } else if (str == _("Good")) {
+ return SrcGood;
+ } else if (str == _("Quick")) {
+ return SrcQuick;
+ } else if (str == _("Fast")) {
+ return SrcFast;
+ } else {
+ return SrcFastest;
+ }
+}
+
+ImportDisposition
+SoundFileOmega::get_channel_disposition () const
+{
+ /* we use a map here because the channel combo can contain different strings
+ depending on the state of the other combos. the map contains all possible strings
+ and the ImportDisposition enum that corresponds to it.
+ */
+
+ string str = channel_combo.get_active_text();
+ DispositionMap::const_iterator x = disposition_map.find (str);
+
+ if (x == disposition_map.end()) {
+ fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;