2 Copyright (C) 2005-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sys/param.h>
28 #include <gtkmm/box.h>
29 #include <gtkmm/stock.h>
30 #include <glibmm/fileutils.h>
32 #include <pbd/convert.h>
33 #include <pbd/tokenizer.h>
34 #include <pbd/enumwriter.h>
35 #include <pbd/pthread_utils.h>
36 #include <pbd/xml++.h>
38 #include <gtkmm2ext/utils.h>
40 #include <evoral/SMFReader.hpp>
42 #include <ardour/audio_library.h>
43 #include <ardour/auditioner.h>
44 #include <ardour/audioregion.h>
45 #include <ardour/audiofilesource.h>
46 #include <ardour/smf_source.h>
47 #include <ardour/region_factory.h>
48 #include <ardour/source_factory.h>
49 #include <ardour/session.h>
50 #include <ardour/session_directory.h>
51 #include <ardour/profile.h>
53 #include "ardour_ui.h"
55 #include "gui_thread.h"
60 #include "gain_meter.h"
63 #include "sfdb_freesound_mootcher.h"
68 using namespace ARDOUR;
72 using namespace Gtkmm2ext;
73 using namespace Editing;
77 ustring SoundFileBrowser::persistent_folder;
80 string2importmode (string str)
82 if (str == _("as new tracks")) {
84 } else if (str == _("to selected tracks")) {
86 } else if (str == _("to region list")) {
87 return ImportAsRegion;
88 } else if (str == _("as new tape tracks")) {
89 return ImportAsTapeTrack;
92 warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
98 importmode2string (ImportMode mode)
102 return _("as new tracks");
104 return _("to selected tracks");
106 return _("to region list");
107 case ImportAsTapeTrack:
108 return _("as new tape tracks");
111 return _("as new tracks");
114 SoundFileBox::SoundFileBox (bool persistent)
117 length_clock ("sfboxLengthClock", !persistent, "EditCursorClock", false, true, false),
118 timecode_clock ("sfboxTimecodeClock", !persistent, "EditCursorClock", false, false, false),
120 autoplay_btn (_("Auto-play"))
126 set_name (X_("SoundFileBox"));
127 set_size_request (300, -1);
129 preview_label.set_markup (_("<b>Soundfile Info</b>"));
131 border_frame.set_label_widget (preview_label);
132 border_frame.add (main_box);
134 pack_start (border_frame, true, true);
135 set_border_width (6);
137 main_box.set_border_width (6);
138 main_box.set_spacing (12);
140 length.set_text (_("Length:"));
141 timecode.set_text (_("Timestamp:"));
142 format.set_text (_("Format:"));
143 channels.set_text (_("Channels:"));
144 samplerate.set_text (_("Sample rate:"));
146 table.set_col_spacings (6);
147 table.set_homogeneous (false);
148 table.set_row_spacings (6);
150 table.attach (channels, 0, 1, 0, 1, FILL|EXPAND, (AttachOptions) 0);
151 table.attach (samplerate, 0, 1, 1, 2, FILL|EXPAND, (AttachOptions) 0);
152 table.attach (format, 0, 1, 2, 4, FILL|EXPAND, (AttachOptions) 0);
153 table.attach (length, 0, 1, 4, 5, FILL|EXPAND, (AttachOptions) 0);
154 table.attach (timecode, 0, 1, 5, 6, FILL|EXPAND, (AttachOptions) 0);
156 table.attach (channels_value, 1, 2, 0, 1, FILL, (AttachOptions) 0);
157 table.attach (samplerate_value, 1, 2, 1, 2, FILL, (AttachOptions) 0);
158 table.attach (format_text, 1, 2, 2, 4, FILL, AttachOptions (0));
159 table.attach (length_clock, 1, 2, 4, 5, FILL, (AttachOptions) 0);
160 table.attach (timecode_clock, 1, 2, 5, 6, FILL, (AttachOptions) 0);
162 length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock.mode());
163 timecode_clock.set_mode (AudioClock::SMPTE);
165 hbox = manage (new HBox);
166 hbox->pack_start (table, false, false);
167 main_box.pack_start (*hbox, false, false);
169 tags_entry.set_editable (true);
170 tags_entry.signal_focus_out_event().connect (mem_fun (*this, &SoundFileBox::tags_entry_left));
171 hbox = manage (new HBox);
172 hbox->pack_start (tags_entry, true, true);
174 vbox = manage (new VBox);
176 Label* label = manage (new Label (_("Tags:")));
177 label->set_alignment (0.0f, 0.5f);
178 vbox->set_spacing (6);
179 vbox->pack_start(*label, false, false);
180 vbox->pack_start(*hbox, true, true);
182 main_box.pack_start(*vbox, true, true);
183 main_box.pack_start(bottom_box, false, false);
185 play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
186 play_btn.set_label (_("Play (double click)"));
188 stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
189 stop_btn.set_label (_("Stop"));
191 bottom_box.set_homogeneous (false);
192 bottom_box.set_spacing (6);
193 bottom_box.pack_start(play_btn, true, true);
194 bottom_box.pack_start(stop_btn, true, true);
195 bottom_box.pack_start(autoplay_btn, false, false);
197 play_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::audition));
198 stop_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::stop_audition));
200 length.set_alignment (0.0f, 0.5f);
201 format.set_alignment (0.0f, 0.5f);
202 channels.set_alignment (0.0f, 0.5f);
203 samplerate.set_alignment (0.0f, 0.5f);
204 timecode.set_alignment (0.0f, 0.5f);
206 channels_value.set_alignment (0.0f, 0.5f);
207 samplerate_value.set_alignment (0.0f, 0.5f);
211 SoundFileBox::set_session(Session* s)
216 play_btn.set_sensitive (false);
217 stop_btn.set_sensitive (false);
221 length_clock.set_session (s);
222 timecode_clock.set_session (s);
226 SoundFileBox::setup_labels (const ustring& filename)
229 // save existing tags
237 if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
239 preview_label.set_markup (_("<b>Soundfile Info</b>"));
240 format_text.set_text (_("n/a"));
241 channels_value.set_text (_("n/a"));
242 samplerate_value.set_text (_("n/a"));
243 tags_entry.get_buffer()->set_text ("");
245 length_clock.set (0);
246 timecode_clock.set (0);
248 tags_entry.set_sensitive (false);
249 play_btn.set_sensitive (false);
254 preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
255 format_text.set_text (sf_info.format_name);
256 channels_value.set_text (to_string (sf_info.channels, std::dec));
258 if (_session && sf_info.samplerate != _session->frame_rate()) {
259 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
260 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
261 samplerate_value.set_name ("NewSessionSR1Label");
262 samplerate.set_name ("NewSessionSR1Label");
264 samplerate.set_text (_("Sample rate:"));
265 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
266 samplerate_value.set_name ("NewSessionSR2Label");
267 samplerate.set_name ("NewSessionSR2Label");
270 double src_coef = (double) _session->nominal_frame_rate() / sf_info.samplerate;
272 length_clock.set (sf_info.length * src_coef + 0.5, true);
273 timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
275 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
277 vector<string> tags = Library->get_tags (string ("//") + filename);
279 stringstream tag_string;
280 for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
281 if (i != tags.begin()) {
286 tags_entry.get_buffer()->set_text (tag_string.str());
288 tags_entry.set_sensitive (true);
290 play_btn.set_sensitive (true);
297 SoundFileBox::autoplay() const
299 return autoplay_btn.get_active();
303 SoundFileBox::audition_oneshot()
310 SoundFileBox::audition ()
316 _session->cancel_audition();
318 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
319 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
323 boost::shared_ptr<Region> r;
325 boost::shared_ptr<AudioFileSource> afs;
326 bool old_sbp = AudioSource::get_build_peakfiles ();
328 /* don't even think of building peakfiles for these files */
330 AudioSource::set_build_peakfiles (false);
332 for (int n = 0; n < sf_info.channels; ++n) {
334 afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, *_session, path,
335 n, AudioFileSource::Flag (0), false));
337 srclist.push_back(afs);
339 } catch (failed_constructor& err) {
340 error << _("Could not access soundfile: ") << path << endmsg;
341 AudioSource::set_build_peakfiles (old_sbp);
346 AudioSource::set_build_peakfiles (old_sbp);
348 if (srclist.empty()) {
352 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
353 string rname = region_name_from_path (afs->path(), false);
354 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0, srclist[0]->length(), rname, 0, Region::DefaultFlags, false));
356 _session->audition_region(r);
360 SoundFileBox::stop_audition ()
363 _session->cancel_audition();
368 SoundFileBox::tags_entry_left (GdkEventFocus *ev)
375 SoundFileBox::tags_changed ()
377 string tag_string = tags_entry.get_buffer()->get_text ();
379 if (tag_string.empty()) {
385 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
386 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
394 SoundFileBox::save_tags (const vector<string>& tags)
396 Library->set_tags (string ("//") + path, tags);
397 Library->save_changes ();
400 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
401 : ArdourDialog (parent, title, false, false),
402 found_list (ListStore::create(found_list_columns)),
403 freesound_list (ListStore::create(freesound_list_columns)),
404 chooser (FILE_CHOOSER_ACTION_OPEN),
405 preview (persistent),
406 found_search_btn (_("Search")),
407 found_list_view (found_list),
408 freesound_search_btn (_("Start Downloading")),
409 freesound_list_view (freesound_list)
411 resetting_ourselves = false;
414 resetting_ourselves = false;
417 if (ARDOUR::Profile->get_sae()) {
418 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
419 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
423 //add the file chooser
425 chooser.set_border_width (12);
427 audio_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_audio_filter));
428 audio_filter.set_name (_("Audio files"));
430 midi_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_midi_filter));
431 midi_filter.set_name (_("MIDI files"));
433 matchall_filter.add_pattern ("*.*");
434 matchall_filter.set_name (_("All files"));
436 chooser.add_filter (audio_filter);
437 chooser.add_filter (midi_filter);
438 chooser.add_filter (matchall_filter);
439 chooser.set_select_multiple (true);
440 chooser.signal_update_preview().connect(mem_fun(*this, &SoundFileBrowser::update_preview));
441 chooser.signal_file_activated().connect (mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
443 if (!persistent_folder.empty()) {
444 chooser.set_current_folder (persistent_folder);
446 notebook.append_page (chooser, _("Browse Files"));
449 hpacker.set_spacing (6);
450 hpacker.pack_start (notebook, true, true);
451 hpacker.pack_start (preview, false, false);
453 get_vbox()->pack_start (hpacker, true, true);
461 hbox = manage(new HBox);
462 hbox->pack_start (found_entry);
463 hbox->pack_start (found_search_btn);
465 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
466 scroll->add(found_list_view);
467 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
469 vbox = manage(new VBox);
470 vbox->pack_start (*hbox, PACK_SHRINK);
471 vbox->pack_start (*scroll);
473 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
475 found_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
477 found_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
479 found_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
480 found_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
482 notebook.append_page (*vbox, _("Search Tags"));
485 //add freesound search
492 passbox = manage(new HBox);
493 passbox->set_border_width (12);
494 passbox->set_spacing (6);
496 label = manage (new Label);
497 label->set_text (_("User:"));
498 passbox->pack_start (*label, false, false);
499 passbox->pack_start (freesound_name_entry);
500 label = manage (new Label);
501 label->set_text (_("Password:"));
502 passbox->pack_start (*label, false, false);
503 passbox->pack_start (freesound_pass_entry);
504 label = manage (new Label);
505 label->set_text (_("Tags:"));
506 passbox->pack_start (*label, false, false);
507 passbox->pack_start (freesound_entry, false, false);
508 passbox->pack_start (freesound_search_btn, false, false);
510 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
511 scroll->add(freesound_list_view);
512 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
514 vbox = manage(new VBox);
515 vbox->pack_start (*passbox, PACK_SHRINK);
516 vbox->pack_start(*scroll);
518 //vbox->pack_start (freesound_list_view);
520 freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname);
521 freesound_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
523 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
524 freesound_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
525 freesound_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
526 freesound_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
527 notebook.append_page (*vbox, _("Search Freesound"));
532 notebook.set_size_request (500, -1);
536 add_button (Stock::CANCEL, RESPONSE_CANCEL);
537 add_button (Stock::APPLY, RESPONSE_APPLY);
538 add_button (Stock::OK, RESPONSE_OK);
542 SoundFileBrowser::~SoundFileBrowser ()
544 persistent_folder = chooser.get_current_folder();
549 SoundFileBrowser::on_show ()
551 ArdourDialog::on_show ();
556 SoundFileBrowser::clear_selection ()
558 chooser.unselect_all ();
559 found_list_view.get_selection()->unselect_all ();
563 SoundFileBrowser::chooser_file_activated ()
569 SoundFileBrowser::found_list_view_activated (const TreeModel::Path& path, TreeViewColumn* col)
575 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path& path, TreeViewColumn* col)
581 SoundFileBrowser::set_session (Session* s)
583 ArdourDialog::set_session (s);
584 preview.set_session (s);
588 remove_gain_meter ();
593 SoundFileBrowser::add_gain_meter ()
599 gm = new GainMeter (session->the_auditioner(), *session);
601 meter_packer.set_border_width (12);
602 meter_packer.pack_start (*gm, false, true);
603 hpacker.pack_end (meter_packer, false, false);
604 meter_packer.show_all ();
609 SoundFileBrowser::remove_gain_meter ()
612 meter_packer.remove (*gm);
613 hpacker.remove (meter_packer);
620 SoundFileBrowser::start_metering ()
622 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun(*this, &SoundFileBrowser::meter));
626 SoundFileBrowser::stop_metering ()
628 metering_connection.disconnect();
632 SoundFileBrowser::meter ()
634 if (is_mapped () && session && gm) {
635 gm->update_meters ();
640 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
642 return AudioFileSource::safe_file_extension (filter_info.filename);
646 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
648 return SMFSource::safe_file_extension (filter_info.filename);
652 SoundFileBrowser::update_preview ()
654 if (preview.setup_labels (chooser.get_filename())) {
655 if (preview.autoplay()) {
656 Glib::signal_idle().connect (mem_fun (preview, &SoundFileBox::audition_oneshot));
662 SoundFileBrowser::found_list_view_selected ()
664 if (!reset_options ()) {
665 set_response_sensitive (RESPONSE_OK, false);
669 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
672 TreeIter iter = found_list->get_iter(*rows.begin());
673 file = (*iter)[found_list_columns.pathname];
674 chooser.set_filename (file);
675 set_response_sensitive (RESPONSE_OK, true);
677 set_response_sensitive (RESPONSE_OK, false);
680 preview.setup_labels (file);
685 SoundFileBrowser::freesound_list_view_selected ()
687 if (!reset_options ()) {
688 set_response_sensitive (RESPONSE_OK, false);
692 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
695 TreeIter iter = freesound_list->get_iter(*rows.begin());
696 file = (*iter)[freesound_list_columns.pathname];
697 chooser.set_filename (file);
698 set_response_sensitive (RESPONSE_OK, true);
700 set_response_sensitive (RESPONSE_OK, false);
703 preview.setup_labels (file);
708 SoundFileBrowser::found_search_clicked ()
710 string tag_string = found_entry.get_text ();
714 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
715 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
719 vector<string> results;
720 Library->search_members_and (results, tags);
723 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
724 TreeModel::iterator new_row = found_list->append();
725 TreeModel::Row row = *new_row;
726 string path = Glib::filename_from_uri (string ("file:") + *i);
727 row[found_list_columns.pathname] = path;
732 freesound_search_thread_entry (void* arg)
734 PBD::ThreadCreated (pthread_self(), X_("Freesound Search"));
736 static_cast<SoundFileBrowser*>(arg)->freesound_search_thread ();
741 bool searching = false;
742 bool canceling = false;
745 SoundFileBrowser::freesound_search_clicked ()
747 if (canceling) //already canceling, button does nothing
751 freesound_search_btn.set_label(_("Cancelling.."));
755 freesound_search_btn.set_label(_("Cancel"));
756 pthread_t freesound_thr;
757 pthread_create_and_store ("freesound_search", &freesound_thr, 0, freesound_search_thread_entry, this);
762 SoundFileBrowser::freesound_search_thread()
765 freesound_list->clear();
768 path = Glib::get_home_dir();
769 path += "/Freesound/";
770 Mootcher theMootcher(path.c_str());
772 string name_string = freesound_name_entry.get_text ();
773 string pass_string = freesound_pass_entry.get_text ();
774 string search_string = freesound_entry.get_text ();
776 if ( theMootcher.doLogin( name_string, pass_string ) ) {
778 string theString = theMootcher.searchText(search_string);
781 doc.read_buffer( theString );
782 XMLNode *root = doc.root();
784 if (root==NULL) return;
786 if ( strcmp(root->name().c_str(), "freesound") == 0) {
789 XMLNodeList children = root->children();
790 XMLNodeConstIterator niter;
791 for (niter = children.begin(); niter != children.end() && !canceling; ++niter) {
793 if( strcmp( node->name().c_str(), "sample") == 0 ){
794 XMLProperty *prop=node->property ("id");
795 string filename = theMootcher.getFile( prop->value().c_str() );
796 if ( filename != "" ) {
797 TreeModel::iterator new_row = freesound_list->append();
798 TreeModel::Row row = *new_row;
799 string path = Glib::filename_from_uri (string ("file:") + filename);
800 row[freesound_list_columns.pathname] = path;
809 freesound_search_btn.set_label(_("Start Downloading"));
814 SoundFileBrowser::get_paths ()
816 vector<ustring> results;
818 int n = notebook.get_current_page ();
821 vector<ustring> filenames = chooser.get_filenames();
822 vector<ustring>::iterator i;
824 for (i = filenames.begin(); i != filenames.end(); ++i) {
826 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
827 results.push_back (*i);
833 typedef TreeView::Selection::ListHandle_Path ListPath;
835 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
836 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
837 TreeIter iter = found_list->get_iter(*i);
838 ustring str = (*iter)[found_list_columns.pathname];
840 results.push_back (str);
844 typedef TreeView::Selection::ListHandle_Path ListPath;
846 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
847 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
848 TreeIter iter = freesound_list->get_iter(*i);
849 ustring str = (*iter)[freesound_list_columns.pathname];
851 results.push_back (str);
859 SoundFileOmega::reset_options_noret ()
861 if (!resetting_ourselves) {
862 (void) reset_options ();
867 SoundFileOmega::reset_options ()
869 vector<ustring> paths = get_paths ();
873 channel_combo.set_sensitive (false);
874 action_combo.set_sensitive (false);
875 where_combo.set_sensitive (false);
876 copy_files_btn.set_sensitive (false);
882 channel_combo.set_sensitive (true);
883 action_combo.set_sensitive (true);
884 where_combo.set_sensitive (true);
886 /* if we get through this function successfully, this may be
887 reset at the end, once we know if we can use hard links
891 if (Config->get_only_copy_imported_files()) {
892 copy_files_btn.set_sensitive (false);
894 copy_files_btn.set_sensitive (false);
900 bool selection_includes_multichannel;
901 bool selection_can_be_embedded_with_links = check_link_status (*session, paths);
904 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
905 Glib::signal_idle().connect (mem_fun (*this, &SoundFileOmega::bad_file_message));
909 ustring existing_choice;
910 vector<string> action_strings;
912 if (selected_track_cnt > 0) {
913 if (channel_combo.get_active_text().length()) {
914 ImportDisposition id = get_channel_disposition();
917 case Editing::ImportDistinctFiles:
918 if (selected_track_cnt == paths.size()) {
919 action_strings.push_back (importmode2string (ImportToTrack));
923 case Editing::ImportDistinctChannels:
924 /* XXX it would be nice to allow channel-per-selected track
925 but its too hard we don't want to deal with all the
926 different per-file + per-track channel configurations.
931 action_strings.push_back (importmode2string (ImportToTrack));
937 action_strings.push_back (importmode2string (ImportAsTrack));
938 action_strings.push_back (importmode2string (ImportAsRegion));
939 action_strings.push_back (importmode2string (ImportAsTapeTrack));
941 resetting_ourselves = true;
943 existing_choice = action_combo.get_active_text();
945 set_popdown_strings (action_combo, action_strings);
947 /* preserve any existing choice, if possible */
950 if (existing_choice.length()) {
951 vector<string>::iterator x;
952 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
953 if (*x == existing_choice) {
954 action_combo.set_active_text (existing_choice);
958 if (x == action_strings.end()) {
959 action_combo.set_active_text (action_strings.front());
962 action_combo.set_active_text (action_strings.front());
965 resetting_ourselves = false;
967 if ((mode = get_mode()) == ImportAsRegion) {
968 where_combo.set_sensitive (false);
970 where_combo.set_sensitive (true);
973 vector<string> channel_strings;
975 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
976 channel_strings.push_back (_("one track per file"));
978 if (selection_includes_multichannel) {
979 channel_strings.push_back (_("one track per channel"));
982 if (paths.size() > 1) {
983 /* tape tracks are a single region per track, so we cannot
984 sequence multiple files.
986 if (mode != ImportAsTapeTrack) {
987 channel_strings.push_back (_("sequence files"));
990 channel_strings.push_back (_("all files in one region"));
996 channel_strings.push_back (_("one region per file"));
998 if (selection_includes_multichannel) {
999 channel_strings.push_back (_("one region per channel"));
1002 if (paths.size() > 1) {
1004 channel_strings.push_back (_("all files in one region"));
1009 existing_choice = channel_combo.get_active_text();
1011 set_popdown_strings (channel_combo, channel_strings);
1013 /* preserve any existing choice, if possible */
1015 if (existing_choice.length()) {
1016 vector<string>::iterator x;
1017 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1018 if (*x == existing_choice) {
1019 channel_combo.set_active_text (existing_choice);
1023 if (x == channel_strings.end()) {
1024 channel_combo.set_active_text (channel_strings.front());
1027 channel_combo.set_active_text (channel_strings.front());
1031 src_combo.set_sensitive (true);
1033 src_combo.set_sensitive (false);
1036 if (Config->get_only_copy_imported_files()) {
1038 if (selection_can_be_embedded_with_links) {
1039 copy_files_btn.set_sensitive (true);
1041 copy_files_btn.set_sensitive (false);
1046 copy_files_btn.set_sensitive (true);
1054 SoundFileOmega::bad_file_message()
1056 MessageDialog msg (*this,
1057 _("One or more of the selected files\ncannot be used by Ardour"),
1062 resetting_ourselves = true;
1063 chooser.unselect_uri (chooser.get_preview_uri());
1064 resetting_ourselves = false;
1070 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1079 multichannel = false;
1081 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1083 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1084 if (info.channels > 1) {
1085 multichannel = true;
1090 if (sz != info.length) {
1095 if ((nframes_t) info.samplerate != session->frame_rate()) {
1099 } else if (SMFSource::safe_file_extension (*i)) {
1101 Evoral::SMFReader reader(*i);
1102 if (reader.num_tracks() > 1) {
1103 multichannel = true; // "channel" == track here...
1106 /* XXX we need err = true handling here in case
1107 we can't check the file
1120 SoundFileOmega::check_link_status (const Session& s, const vector<ustring>& paths)
1122 sys::path path = s.session_directory().sound_path() / "linktest";
1123 string tmpdir = path.to_string();
1126 if (mkdir (tmpdir.c_str(), 0744)) {
1127 if (errno != EEXIST) {
1132 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1134 char tmpc[MAXPATHLEN+1];
1136 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1140 if (link ((*i).c_str(), tmpc)) {
1150 rmdir (tmpdir.c_str());
1154 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1155 : SoundFileBrowser (parent, title, s, false)
1157 chooser.set_select_multiple (false);
1158 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1159 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1163 SoundFileChooser::on_hide ()
1165 ArdourDialog::on_hide();
1169 session->cancel_audition();
1174 SoundFileChooser::get_filename ()
1176 vector<ustring> paths;
1178 paths = get_paths ();
1180 if (paths.empty()) {
1184 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1188 return paths.front();
1191 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
1192 Editing::ImportMode mode_hint)
1193 : SoundFileBrowser (parent, title, s, persistent),
1194 copy_files_btn ( _("Copy files to session")),
1195 selected_track_cnt (selected_tracks)
1201 set_size_request (-1, 450);
1203 block_two.set_border_width (12);
1204 block_three.set_border_width (12);
1205 block_four.set_border_width (12);
1207 options.set_spacing (12);
1210 str.push_back (_("use file timestamp"));
1211 str.push_back (_("at edit point"));
1212 str.push_back (_("at playhead"));
1213 str.push_back (_("at session start"));
1214 set_popdown_strings (where_combo, str);
1215 where_combo.set_active_text (str.front());
1217 Label* l = manage (new Label);
1218 l->set_text (_("Add files:"));
1220 hbox = manage (new HBox);
1221 hbox->set_border_width (12);
1222 hbox->set_spacing (6);
1223 hbox->pack_start (*l, false, false);
1224 hbox->pack_start (action_combo, false, false);
1225 vbox = manage (new VBox);
1226 vbox->pack_start (*hbox, false, false);
1227 options.pack_start (*vbox, false, false);
1229 /* dummy entry for action combo so that it doesn't look odd if we
1230 come up with no tracks selected.
1234 str.push_back (importmode2string (mode_hint));
1235 set_popdown_strings (action_combo, str);
1236 action_combo.set_active_text (str.front());
1237 action_combo.set_sensitive (false);
1239 l = manage (new Label);
1240 l->set_text (_("Insert:"));
1242 hbox = manage (new HBox);
1243 hbox->set_border_width (12);
1244 hbox->set_spacing (6);
1245 hbox->pack_start (*l, false, false);
1246 hbox->pack_start (where_combo, false, false);
1247 vbox = manage (new VBox);
1248 vbox->pack_start (*hbox, false, false);
1249 options.pack_start (*vbox, false, false);
1252 l = manage (new Label);
1253 l->set_text (_("Mapping:"));
1255 hbox = manage (new HBox);
1256 hbox->set_border_width (12);
1257 hbox->set_spacing (6);
1258 hbox->pack_start (*l, false, false);
1259 hbox->pack_start (channel_combo, false, false);
1260 vbox = manage (new VBox);
1261 vbox->pack_start (*hbox, false, false);
1262 options.pack_start (*vbox, false, false);
1265 str.push_back (_("one track per file"));
1266 set_popdown_strings (channel_combo, str);
1267 channel_combo.set_active_text (str.front());
1268 channel_combo.set_sensitive (false);
1270 l = manage (new Label);
1271 l->set_text (_("Conversion Quality:"));
1273 hbox = manage (new HBox);
1274 hbox->set_border_width (12);
1275 hbox->set_spacing (6);
1276 hbox->pack_start (*l, false, false);
1277 hbox->pack_start (src_combo, false, false);
1278 vbox = manage (new VBox);
1279 vbox->pack_start (*hbox, false, false);
1280 options.pack_start (*vbox, false, false);
1283 str.push_back (_("Best"));
1284 str.push_back (_("Good"));
1285 str.push_back (_("Quick"));
1286 str.push_back (_("Fast"));
1287 str.push_back (_("Fastest"));
1289 set_popdown_strings (src_combo, str);
1290 src_combo.set_active_text (str.front());
1291 src_combo.set_sensitive (false);
1295 action_combo.signal_changed().connect (mem_fun (*this, &SoundFileOmega::reset_options_noret));
1297 copy_files_btn.set_active (true);
1299 block_four.pack_start (copy_files_btn, false, false);
1301 options.pack_start (block_four, false, false);
1303 get_vbox()->pack_start (options, false, false);
1305 /* setup disposition map */
1307 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1308 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1309 disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1310 disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1312 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1313 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1314 disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1316 chooser.signal_selection_changed().connect (mem_fun (*this, &SoundFileOmega::file_selection_changed));
1320 SoundFileOmega::set_mode (ImportMode mode)
1322 action_combo.set_active_text (importmode2string (mode));
1326 SoundFileOmega::get_mode () const
1328 return string2importmode (action_combo.get_active_text());
1332 SoundFileOmega::on_hide ()
1334 ArdourDialog::on_hide();
1336 session->cancel_audition();
1341 SoundFileOmega::get_position() const
1343 ustring str = where_combo.get_active_text();
1345 if (str == _("use file timestamp")) {
1346 return ImportAtTimestamp;
1347 } else if (str == _("at edit point")) {
1348 return ImportAtEditPoint;
1349 } else if (str == _("at playhead")) {
1350 return ImportAtPlayhead;
1352 return ImportAtStart;
1357 SoundFileOmega::get_src_quality() const
1359 ustring str = where_combo.get_active_text();
1361 if (str == _("Best")) {
1363 } else if (str == _("Good")) {
1365 } else if (str == _("Quick")) {
1367 } else if (str == _("Fast")) {
1375 SoundFileOmega::get_channel_disposition () const
1377 /* we use a map here because the channel combo can contain different strings
1378 depending on the state of the other combos. the map contains all possible strings
1379 and the ImportDisposition enum that corresponds to it.
1382 ustring str = channel_combo.get_active_text();
1383 DispositionMap::const_iterator x = disposition_map.find (str);
1385 if (x == disposition_map.end()) {
1386 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1394 SoundFileOmega::reset (int selected_tracks)
1396 selected_track_cnt = selected_tracks;
1401 SoundFileOmega::file_selection_changed ()
1403 if (resetting_ourselves) {
1407 if (!reset_options ()) {
1408 set_response_sensitive (RESPONSE_OK, false);
1410 if (chooser.get_filenames().size() > 0) {
1411 set_response_sensitive (RESPONSE_OK, true);
1413 set_response_sensitive (RESPONSE_OK, false);