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/SMF.hpp"
42 #include "ardour/amp.h"
43 #include "ardour/audio_library.h"
44 #include "ardour/auditioner.h"
45 #include "ardour/audioregion.h"
46 #include "ardour/audiofilesource.h"
47 #include "ardour/smf_source.h"
48 #include "ardour/region_factory.h"
49 #include "ardour/source_factory.h"
50 #include "ardour/session.h"
51 #include "ardour/session_directory.h"
52 #include "ardour/profile.h"
54 #include "ardour_ui.h"
56 #include "gui_thread.h"
61 #include "gain_meter.h"
64 #include "sfdb_freesound_mootcher.h"
69 using namespace ARDOUR;
73 using namespace Gtkmm2ext;
74 using namespace Editing;
78 ustring SoundFileBrowser::persistent_folder;
81 string2importmode (string str)
83 if (str == _("as new tracks")) {
85 } else if (str == _("to selected tracks")) {
87 } else if (str == _("to region list")) {
88 return ImportAsRegion;
89 } else if (str == _("as new tape tracks")) {
90 return ImportAsTapeTrack;
93 warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
99 importmode2string (ImportMode mode)
103 return _("as new tracks");
105 return _("to selected tracks");
107 return _("to region list");
108 case ImportAsTapeTrack:
109 return _("as new tape tracks");
112 return _("as new tracks");
115 SoundFileBox::SoundFileBox (bool persistent)
117 length_clock ("sfboxLengthClock", !persistent, "EditCursorClock", false, false, true, false),
118 timecode_clock ("sfboxTimecodeClock", !persistent, "EditCursorClock", false, false, false, false),
120 autoplay_btn (_("Auto-play"))
123 set_name (X_("SoundFileBox"));
124 set_size_request (300, -1);
126 preview_label.set_markup (_("<b>Sound File Information</b>"));
128 border_frame.set_label_widget (preview_label);
129 border_frame.add (main_box);
131 pack_start (border_frame, true, true);
132 set_border_width (6);
134 main_box.set_border_width (6);
136 length.set_text (_("Length:"));
137 length.set_alignment (1, 0.5);
138 timecode.set_text (_("Timestamp:"));
139 timecode.set_alignment (1, 0.5);
140 format.set_text (_("Format:"));
141 format.set_alignment (1, 0.5);
142 channels.set_text (_("Channels:"));
143 channels.set_alignment (1, 0.5);
144 samplerate.set_text (_("Sample rate:"));
145 samplerate.set_alignment (1, 0.5);
147 format_text.set_max_width_chars (8);
148 format_text.set_ellipsize (Pango::ELLIPSIZE_END);
149 format_text.set_alignment (0, 1);
151 table.set_col_spacings (6);
152 table.set_homogeneous (false);
153 table.set_row_spacings (6);
155 table.attach (channels, 0, 1, 0, 1, FILL, FILL);
156 table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
157 table.attach (format, 0, 1, 2, 4, FILL, FILL);
158 table.attach (length, 0, 1, 4, 5, FILL, FILL);
159 table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
161 table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
162 table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
163 table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
164 table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
165 table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
167 length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock.mode());
168 timecode_clock.set_mode (AudioClock::Timecode);
170 main_box.pack_start (table, false, false);
172 tags_entry.set_editable (true);
173 tags_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
175 Label* label = manage (new Label (_("Tags:")));
176 label->set_alignment (0.0f, 0.5f);
177 main_box.pack_start (*label, false, false);
178 main_box.pack_start (tags_entry, true, true);
180 main_box.pack_start (bottom_box, false, false);
182 play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
183 play_btn.set_label (_("Play"));
185 stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
186 stop_btn.set_label (_("Stop"));
188 bottom_box.set_homogeneous (false);
189 bottom_box.set_spacing (6);
190 bottom_box.pack_start(play_btn, true, true);
191 bottom_box.pack_start(stop_btn, true, true);
192 bottom_box.pack_start(autoplay_btn, false, false);
194 play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
195 stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
197 channels_value.set_alignment (0.0f, 0.5f);
198 samplerate_value.set_alignment (0.0f, 0.5f);
202 SoundFileBox::set_session(Session* s)
204 SessionHandlePtr::set_session (s);
206 length_clock.set_session (s);
207 timecode_clock.set_session (s);
210 play_btn.set_sensitive (false);
211 stop_btn.set_sensitive (false);
216 SoundFileBox::setup_labels (const ustring& filename)
219 // save existing tags
227 if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
229 preview_label.set_markup (_("<b>Sound File Information</b>"));
230 format_text.set_text ("");
231 channels_value.set_text ("");
232 samplerate_value.set_text ("");
233 tags_entry.get_buffer()->set_text ("");
235 length_clock.set (0);
236 timecode_clock.set (0);
238 tags_entry.set_sensitive (false);
239 play_btn.set_sensitive (false);
244 preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
245 std::string n = sf_info.format_name;
246 if (n.substr (0, 8) == X_("Format: ")) {
249 format_text.set_text (n);
250 channels_value.set_text (to_string (sf_info.channels, std::dec));
252 if (_session && sf_info.samplerate != _session->frame_rate()) {
253 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
254 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
255 samplerate_value.set_name ("NewSessionSR1Label");
256 samplerate.set_name ("NewSessionSR1Label");
258 samplerate.set_text (_("Sample rate:"));
259 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
260 samplerate_value.set_name ("NewSessionSR2Label");
261 samplerate.set_name ("NewSessionSR2Label");
264 nframes_t const nfr = _session ? _session->nominal_frame_rate() : 25;
265 double src_coef = (double) nfr / sf_info.samplerate;
267 length_clock.set (sf_info.length * src_coef + 0.5, true);
268 timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
270 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
272 vector<string> tags = Library->get_tags (string ("//") + filename);
274 stringstream tag_string;
275 for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
276 if (i != tags.begin()) {
281 tags_entry.get_buffer()->set_text (tag_string.str());
283 tags_entry.set_sensitive (true);
285 play_btn.set_sensitive (true);
292 SoundFileBox::autoplay() const
294 return autoplay_btn.get_active();
298 SoundFileBox::audition_oneshot()
305 SoundFileBox::audition ()
311 if (SMFSource::safe_midi_file_extension (path)) {
312 error << _("Auditioning of MIDI files is not yet supported") << endmsg;
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> (
335 SourceFactory::createReadable (DataType::AUDIO, *_session,
336 path, n, Source::Flag (0), false));
338 srclist.push_back(afs);
340 } catch (failed_constructor& err) {
341 error << _("Could not access soundfile: ") << path << endmsg;
342 AudioSource::set_build_peakfiles (old_sbp);
347 AudioSource::set_build_peakfiles (old_sbp);
349 if (srclist.empty()) {
353 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
354 string rname = region_name_from_path (afs->path(), false);
358 plist.add (ARDOUR::Properties::start, 0);
359 plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
360 plist.add (ARDOUR::Properties::name, rname);
361 plist.add (ARDOUR::Properties::layer, 0);
363 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
365 _session->audition_region(r);
369 SoundFileBox::stop_audition ()
372 _session->cancel_audition();
377 SoundFileBox::tags_entry_left (GdkEventFocus *)
384 SoundFileBox::tags_changed ()
386 string tag_string = tags_entry.get_buffer()->get_text ();
388 if (tag_string.empty()) {
394 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
395 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
403 SoundFileBox::save_tags (const vector<string>& tags)
405 Library->set_tags (string ("//") + path, tags);
406 Library->save_changes ();
409 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
410 : ArdourDialog (parent, title, false, false),
411 found_list (ListStore::create(found_list_columns)),
412 freesound_list (ListStore::create(freesound_list_columns)),
413 chooser (FILE_CHOOSER_ACTION_OPEN),
414 preview (persistent),
415 found_search_btn (_("Search")),
416 found_list_view (found_list),
417 freesound_search_btn (_("Start Downloading")),
418 freesound_list_view (freesound_list)
420 resetting_ourselves = false;
423 resetting_ourselves = false;
427 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
428 chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
429 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
431 chooser.add_shortcut_folder_uri("file:///Volumes");
434 //add the file chooser
436 chooser.set_border_width (12);
438 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
439 audio_filter.set_name (_("Audio files"));
441 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
442 midi_filter.set_name (_("MIDI files"));
444 matchall_filter.add_pattern ("*.*");
445 matchall_filter.set_name (_("All files"));
447 chooser.add_filter (audio_filter);
448 chooser.add_filter (midi_filter);
449 chooser.add_filter (matchall_filter);
450 chooser.set_select_multiple (true);
451 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
452 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
454 /* some broken redraw behaviour - this is a bandaid */
455 chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
458 if (!persistent_folder.empty()) {
459 chooser.set_current_folder (persistent_folder);
461 notebook.append_page (chooser, _("Browse Files"));
464 hpacker.set_spacing (6);
465 hpacker.pack_start (notebook, true, true);
466 hpacker.pack_start (preview, false, false);
468 get_vbox()->pack_start (hpacker, true, true);
476 hbox = manage(new HBox);
477 hbox->pack_start (found_entry);
478 hbox->pack_start (found_search_btn);
480 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
481 scroll->add(found_list_view);
482 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
484 vbox = manage(new VBox);
485 vbox->pack_start (*hbox, PACK_SHRINK);
486 vbox->pack_start (*scroll);
488 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
490 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
492 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
494 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
495 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
497 notebook.append_page (*vbox, _("Search Tags"));
500 //add freesound search
507 passbox = manage(new HBox);
508 passbox->set_border_width (12);
509 passbox->set_spacing (6);
511 label = manage (new Label);
512 label->set_text (_("User:"));
513 passbox->pack_start (*label, false, false);
514 passbox->pack_start (freesound_name_entry);
515 label = manage (new Label);
516 label->set_text (_("Password:"));
517 passbox->pack_start (*label, false, false);
518 passbox->pack_start (freesound_pass_entry);
519 label = manage (new Label);
520 label->set_text (_("Tags:"));
521 passbox->pack_start (*label, false, false);
522 passbox->pack_start (freesound_entry, false, false);
523 passbox->pack_start (freesound_search_btn, false, false);
525 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
526 scroll->add(freesound_list_view);
527 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
529 vbox = manage(new VBox);
530 vbox->pack_start (*passbox, PACK_SHRINK);
531 vbox->pack_start(*scroll);
533 //vbox->pack_start (freesound_list_view);
535 freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname);
536 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
538 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
539 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
540 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
541 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
542 notebook.append_page (*vbox, _("Search Freesound"));
547 notebook.set_size_request (500, -1);
551 add_button (Stock::CANCEL, RESPONSE_CANCEL);
552 add_button (Stock::APPLY, RESPONSE_APPLY);
553 add_button (Stock::OK, RESPONSE_OK);
557 SoundFileBrowser::~SoundFileBrowser ()
559 persistent_folder = chooser.get_current_folder();
564 SoundFileBrowser::on_show ()
566 ArdourDialog::on_show ();
571 SoundFileBrowser::clear_selection ()
573 chooser.unselect_all ();
574 found_list_view.get_selection()->unselect_all ();
578 SoundFileBrowser::chooser_file_activated ()
584 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
590 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
596 SoundFileBrowser::set_session (Session* s)
598 ArdourDialog::set_session (s);
599 preview.set_session (s);
604 remove_gain_meter ();
609 SoundFileBrowser::add_gain_meter ()
613 gm = new GainMeter (_session, 250);
615 boost::shared_ptr<Route> r = _session->the_auditioner ();
617 gm->set_controls (r, r->shared_peak_meter(), r->amp());
619 meter_packer.set_border_width (12);
620 meter_packer.pack_start (*gm, false, true);
621 hpacker.pack_end (meter_packer, false, false);
622 meter_packer.show_all ();
627 SoundFileBrowser::remove_gain_meter ()
630 meter_packer.remove (*gm);
631 hpacker.remove (meter_packer);
638 SoundFileBrowser::start_metering ()
640 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
644 SoundFileBrowser::stop_metering ()
646 metering_connection.disconnect();
650 SoundFileBrowser::meter ()
652 if (is_mapped () && _session && gm) {
653 gm->update_meters ();
658 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
660 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
664 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
666 return SMFSource::safe_midi_file_extension (filter_info.filename);
670 SoundFileBrowser::update_preview ()
672 if (preview.setup_labels (chooser.get_filename())) {
673 if (preview.autoplay()) {
674 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
680 SoundFileBrowser::found_list_view_selected ()
682 if (!reset_options ()) {
683 set_response_sensitive (RESPONSE_OK, false);
687 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
690 TreeIter iter = found_list->get_iter(*rows.begin());
691 file = (*iter)[found_list_columns.pathname];
692 chooser.set_filename (file);
693 set_response_sensitive (RESPONSE_OK, true);
695 set_response_sensitive (RESPONSE_OK, false);
698 preview.setup_labels (file);
703 SoundFileBrowser::freesound_list_view_selected ()
705 if (!reset_options ()) {
706 set_response_sensitive (RESPONSE_OK, false);
710 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
713 TreeIter iter = freesound_list->get_iter(*rows.begin());
714 file = (*iter)[freesound_list_columns.pathname];
715 chooser.set_filename (file);
716 set_response_sensitive (RESPONSE_OK, true);
718 set_response_sensitive (RESPONSE_OK, false);
721 preview.setup_labels (file);
726 SoundFileBrowser::found_search_clicked ()
728 string tag_string = found_entry.get_text ();
732 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
733 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
737 vector<string> results;
738 Library->search_members_and (results, tags);
741 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
742 TreeModel::iterator new_row = found_list->append();
743 TreeModel::Row row = *new_row;
744 string path = Glib::filename_from_uri (string ("file:") + *i);
745 row[found_list_columns.pathname] = path;
750 freesound_search_thread_entry (void* arg)
752 SessionEvent::create_per_thread_pool ("freesound events", 64);
754 static_cast<SoundFileBrowser*>(arg)->freesound_search_thread ();
759 bool searching = false;
760 bool canceling = false;
763 SoundFileBrowser::freesound_search_clicked ()
765 if (canceling) //already canceling, button does nothing
769 freesound_search_btn.set_label(_("Cancelling.."));
773 freesound_search_btn.set_label(_("Cancel"));
774 pthread_t freesound_thr;
775 pthread_create_and_store ("freesound_search", &freesound_thr, freesound_search_thread_entry, this);
780 SoundFileBrowser::freesound_search_thread()
784 THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD
787 freesound_list->clear();
790 path = Glib::get_home_dir();
791 path += "/Freesound/";
792 Mootcher theMootcher(path.c_str());
794 string name_string = freesound_name_entry.get_text ();
795 string pass_string = freesound_pass_entry.get_text ();
796 string search_string = freesound_entry.get_text ();
798 if ( theMootcher.doLogin( name_string, pass_string ) ) {
800 string theString = theMootcher.searchText(search_string);
803 doc.read_buffer( theString );
804 XMLNode *root = doc.root();
806 if (root==NULL) return;
808 if ( strcmp(root->name().c_str(), "freesound") == 0) {
811 XMLNodeList children = root->children();
812 XMLNodeConstIterator niter;
813 for (niter = children.begin(); niter != children.end() && !canceling; ++niter) {
815 if( strcmp( node->name().c_str(), "sample") == 0 ){
816 XMLProperty *prop=node->property ("id");
817 string filename = theMootcher.getFile( prop->value().c_str() );
818 if ( filename != "" ) {
819 TreeModel::iterator new_row = freesound_list->append();
820 TreeModel::Row row = *new_row;
821 string path = Glib::filename_from_uri (string ("file:") + filename);
822 row[freesound_list_columns.pathname] = path;
831 freesound_search_btn.set_label(_("Start Downloading"));
838 SoundFileBrowser::get_paths ()
840 vector<ustring> results;
842 int n = notebook.get_current_page ();
845 vector<ustring> filenames = chooser.get_filenames();
846 vector<ustring>::iterator i;
848 for (i = filenames.begin(); i != filenames.end(); ++i) {
850 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
851 results.push_back (*i);
857 typedef TreeView::Selection::ListHandle_Path ListPath;
859 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
860 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
861 TreeIter iter = found_list->get_iter(*i);
862 ustring str = (*iter)[found_list_columns.pathname];
864 results.push_back (str);
868 typedef TreeView::Selection::ListHandle_Path ListPath;
870 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
871 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
872 TreeIter iter = freesound_list->get_iter(*i);
873 ustring str = (*iter)[freesound_list_columns.pathname];
875 results.push_back (str);
883 SoundFileOmega::reset_options_noret ()
885 if (!resetting_ourselves) {
886 (void) reset_options ();
891 SoundFileOmega::reset_options ()
893 vector<ustring> paths = get_paths ();
897 channel_combo.set_sensitive (false);
898 action_combo.set_sensitive (false);
899 where_combo.set_sensitive (false);
900 copy_files_btn.set_sensitive (false);
906 channel_combo.set_sensitive (true);
907 action_combo.set_sensitive (true);
908 where_combo.set_sensitive (true);
910 /* if we get through this function successfully, this may be
911 reset at the end, once we know if we can use hard links
915 if (Config->get_only_copy_imported_files()) {
916 copy_files_btn.set_sensitive (false);
918 copy_files_btn.set_sensitive (false);
924 bool selection_includes_multichannel;
925 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
928 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
929 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
933 ustring existing_choice;
934 vector<string> action_strings;
936 if (selected_track_cnt > 0) {
937 if (channel_combo.get_active_text().length()) {
938 ImportDisposition id = get_channel_disposition();
941 case Editing::ImportDistinctFiles:
942 if (selected_track_cnt == paths.size()) {
943 action_strings.push_back (importmode2string (ImportToTrack));
947 case Editing::ImportDistinctChannels:
948 /* XXX it would be nice to allow channel-per-selected track
949 but its too hard we don't want to deal with all the
950 different per-file + per-track channel configurations.
955 action_strings.push_back (importmode2string (ImportToTrack));
961 action_strings.push_back (importmode2string (ImportAsTrack));
962 action_strings.push_back (importmode2string (ImportAsRegion));
963 action_strings.push_back (importmode2string (ImportAsTapeTrack));
965 resetting_ourselves = true;
967 existing_choice = action_combo.get_active_text();
969 set_popdown_strings (action_combo, action_strings);
971 /* preserve any existing choice, if possible */
974 if (existing_choice.length()) {
975 vector<string>::iterator x;
976 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
977 if (*x == existing_choice) {
978 action_combo.set_active_text (existing_choice);
982 if (x == action_strings.end()) {
983 action_combo.set_active_text (action_strings.front());
986 action_combo.set_active_text (action_strings.front());
989 resetting_ourselves = false;
991 if ((mode = get_mode()) == ImportAsRegion) {
992 where_combo.set_sensitive (false);
994 where_combo.set_sensitive (true);
997 vector<string> channel_strings;
999 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1000 channel_strings.push_back (_("one track per file"));
1002 if (selection_includes_multichannel) {
1003 channel_strings.push_back (_("one track per channel"));
1006 if (paths.size() > 1) {
1007 /* tape tracks are a single region per track, so we cannot
1008 sequence multiple files.
1010 if (mode != ImportAsTapeTrack) {
1011 channel_strings.push_back (_("sequence files"));
1014 channel_strings.push_back (_("all files in one track"));
1015 channel_strings.push_back (_("merge files"));
1021 channel_strings.push_back (_("one region per file"));
1023 if (selection_includes_multichannel) {
1024 channel_strings.push_back (_("one region per channel"));
1027 if (paths.size() > 1) {
1029 channel_strings.push_back (_("all files in one region"));
1034 existing_choice = channel_combo.get_active_text();
1036 set_popdown_strings (channel_combo, channel_strings);
1038 /* preserve any existing choice, if possible */
1040 if (existing_choice.length()) {
1041 vector<string>::iterator x;
1042 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1043 if (*x == existing_choice) {
1044 channel_combo.set_active_text (existing_choice);
1048 if (x == channel_strings.end()) {
1049 channel_combo.set_active_text (channel_strings.front());
1052 channel_combo.set_active_text (channel_strings.front());
1056 src_combo.set_sensitive (true);
1058 src_combo.set_sensitive (false);
1061 if (Config->get_only_copy_imported_files()) {
1063 if (selection_can_be_embedded_with_links) {
1064 copy_files_btn.set_sensitive (true);
1066 copy_files_btn.set_sensitive (false);
1071 copy_files_btn.set_sensitive (true);
1079 SoundFileOmega::bad_file_message()
1081 MessageDialog msg (*this,
1082 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1087 resetting_ourselves = true;
1088 chooser.unselect_uri (chooser.get_preview_uri());
1089 resetting_ourselves = false;
1095 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1104 multichannel = false;
1106 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1108 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1109 if (info.channels > 1) {
1110 multichannel = true;
1115 if (sz != info.length) {
1120 if ((nframes_t) info.samplerate != _session->frame_rate()) {
1124 } else if (SMFSource::safe_midi_file_extension (*i)) {
1128 if (reader.num_tracks() > 1) {
1129 multichannel = true; // "channel" == track here...
1132 /* XXX we need err = true handling here in case
1133 we can't check the file
1146 SoundFileOmega::check_link_status (const Session* s, const vector<ustring>& paths)
1148 sys::path path = s->session_directory().sound_path() / "linktest";
1149 string tmpdir = path.to_string();
1152 if (mkdir (tmpdir.c_str(), 0744)) {
1153 if (errno != EEXIST) {
1158 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1160 char tmpc[MAXPATHLEN+1];
1162 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1166 if (link ((*i).c_str(), tmpc)) {
1176 rmdir (tmpdir.c_str());
1180 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1181 : SoundFileBrowser (parent, title, s, false)
1183 chooser.set_select_multiple (false);
1184 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1185 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1189 SoundFileChooser::on_hide ()
1191 ArdourDialog::on_hide();
1195 _session->cancel_audition();
1200 SoundFileChooser::get_filename ()
1202 vector<ustring> paths;
1204 paths = get_paths ();
1206 if (paths.empty()) {
1210 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1214 return paths.front();
1217 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
1218 Editing::ImportMode mode_hint)
1219 : SoundFileBrowser (parent, title, s, persistent),
1220 copy_files_btn ( _("Copy files to session")),
1221 selected_track_cnt (selected_tracks)
1227 set_size_request (-1, 450);
1229 block_two.set_border_width (12);
1230 block_three.set_border_width (12);
1231 block_four.set_border_width (12);
1233 options.set_spacing (12);
1236 str.push_back (_("file timestamp"));
1237 str.push_back (_("edit point"));
1238 str.push_back (_("playhead"));
1239 str.push_back (_("session start"));
1240 set_popdown_strings (where_combo, str);
1241 where_combo.set_active_text (str.front());
1243 Label* l = manage (new Label);
1244 l->set_text (_("Add files:"));
1246 hbox = manage (new HBox);
1247 hbox->set_border_width (12);
1248 hbox->set_spacing (6);
1249 hbox->pack_start (*l, false, false);
1250 hbox->pack_start (action_combo, false, false);
1251 vbox = manage (new VBox);
1252 vbox->pack_start (*hbox, false, false);
1253 options.pack_start (*vbox, false, false);
1255 /* dummy entry for action combo so that it doesn't look odd if we
1256 come up with no tracks selected.
1260 str.push_back (importmode2string (mode_hint));
1261 set_popdown_strings (action_combo, str);
1262 action_combo.set_active_text (str.front());
1263 action_combo.set_sensitive (false);
1265 l = manage (new Label);
1266 l->set_text (_("Insert at:"));
1268 hbox = manage (new HBox);
1269 hbox->set_border_width (12);
1270 hbox->set_spacing (6);
1271 hbox->pack_start (*l, false, false);
1272 hbox->pack_start (where_combo, false, false);
1273 vbox = manage (new VBox);
1274 vbox->pack_start (*hbox, false, false);
1275 options.pack_start (*vbox, false, false);
1278 l = manage (new Label);
1279 l->set_text (_("Mapping:"));
1281 hbox = manage (new HBox);
1282 hbox->set_border_width (12);
1283 hbox->set_spacing (6);
1284 hbox->pack_start (*l, false, false);
1285 hbox->pack_start (channel_combo, false, false);
1286 vbox = manage (new VBox);
1287 vbox->pack_start (*hbox, false, false);
1288 options.pack_start (*vbox, false, false);
1291 str.push_back (_("one track per file"));
1292 set_popdown_strings (channel_combo, str);
1293 channel_combo.set_active_text (str.front());
1294 channel_combo.set_sensitive (false);
1296 l = manage (new Label);
1297 l->set_text (_("Conversion quality:"));
1299 hbox = manage (new HBox);
1300 hbox->set_border_width (12);
1301 hbox->set_spacing (6);
1302 hbox->pack_start (*l, false, false);
1303 hbox->pack_start (src_combo, false, false);
1304 vbox = manage (new VBox);
1305 vbox->pack_start (*hbox, false, false);
1306 options.pack_start (*vbox, false, false);
1309 str.push_back (_("Best"));
1310 str.push_back (_("Good"));
1311 str.push_back (_("Quick"));
1312 str.push_back (_("Fast"));
1313 str.push_back (_("Fastest"));
1315 set_popdown_strings (src_combo, str);
1316 src_combo.set_active_text (str.front());
1317 src_combo.set_sensitive (false);
1321 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1323 copy_files_btn.set_active (true);
1325 block_four.pack_start (copy_files_btn, false, false);
1327 options.pack_start (block_four, false, false);
1329 get_vbox()->pack_start (options, false, false);
1331 /* setup disposition map */
1333 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1334 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1335 disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1336 disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1338 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1339 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1340 disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1341 disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1343 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1345 /* set size requests for a couple of combos to allow them to display the longest text
1346 they will ever be asked to display. This prevents them being resized when the user
1347 selects a file to import, which in turn prevents the size of the dialog from jumping
1351 t.push_back (_("one track per file"));
1352 t.push_back (_("one track per channel"));
1353 t.push_back (_("sequence files"));
1354 t.push_back (_("all files in one region"));
1355 set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
1358 t.push_back (importmode2string (ImportAsTrack));
1359 t.push_back (importmode2string (ImportToTrack));
1360 t.push_back (importmode2string (ImportAsRegion));
1361 t.push_back (importmode2string (ImportAsTapeTrack));
1362 set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
1366 SoundFileOmega::set_mode (ImportMode mode)
1368 action_combo.set_active_text (importmode2string (mode));
1372 SoundFileOmega::get_mode () const
1374 return string2importmode (action_combo.get_active_text());
1378 SoundFileOmega::on_hide ()
1380 ArdourDialog::on_hide();
1382 _session->cancel_audition();
1387 SoundFileOmega::get_position() const
1389 ustring str = where_combo.get_active_text();
1391 if (str == _("file timestamp")) {
1392 return ImportAtTimestamp;
1393 } else if (str == _("edit point")) {
1394 return ImportAtEditPoint;
1395 } else if (str == _("playhead")) {
1396 return ImportAtPlayhead;
1398 return ImportAtStart;
1403 SoundFileOmega::get_src_quality() const
1405 ustring str = where_combo.get_active_text();
1407 if (str == _("Best")) {
1409 } else if (str == _("Good")) {
1411 } else if (str == _("Quick")) {
1413 } else if (str == _("Fast")) {
1421 SoundFileOmega::get_channel_disposition () const
1423 /* we use a map here because the channel combo can contain different strings
1424 depending on the state of the other combos. the map contains all possible strings
1425 and the ImportDisposition enum that corresponds to it.
1428 ustring str = channel_combo.get_active_text();
1429 DispositionMap::const_iterator x = disposition_map.find (str);
1431 if (x == disposition_map.end()) {
1432 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1440 SoundFileOmega::reset (int selected_tracks)
1442 selected_track_cnt = selected_tracks;
1447 SoundFileOmega::file_selection_changed ()
1449 if (resetting_ourselves) {
1453 if (!reset_options ()) {
1454 set_response_sensitive (RESPONSE_OK, false);
1456 if (chooser.get_filenames().size() > 0) {
1457 set_response_sensitive (RESPONSE_OK, true);
1459 set_response_sensitive (RESPONSE_OK, false);