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 _session->cancel_audition();
313 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
314 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
318 boost::shared_ptr<Region> r;
320 boost::shared_ptr<AudioFileSource> afs;
321 bool old_sbp = AudioSource::get_build_peakfiles ();
323 /* don't even think of building peakfiles for these files */
325 AudioSource::set_build_peakfiles (false);
327 for (int n = 0; n < sf_info.channels; ++n) {
329 afs = boost::dynamic_pointer_cast<AudioFileSource> (
330 SourceFactory::createReadable (DataType::AUDIO, *_session,
331 path, n, Source::Flag (0), false));
333 srclist.push_back(afs);
335 } catch (failed_constructor& err) {
336 error << _("Could not access soundfile: ") << path << endmsg;
337 AudioSource::set_build_peakfiles (old_sbp);
342 AudioSource::set_build_peakfiles (old_sbp);
344 if (srclist.empty()) {
348 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
349 string rname = region_name_from_path (afs->path(), false);
350 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0,
351 srclist[0]->length(srclist[0]->timeline_position()),
352 rname, 0, Region::DefaultFlags, false));
354 _session->audition_region(r);
358 SoundFileBox::stop_audition ()
361 _session->cancel_audition();
366 SoundFileBox::tags_entry_left (GdkEventFocus *)
373 SoundFileBox::tags_changed ()
375 string tag_string = tags_entry.get_buffer()->get_text ();
377 if (tag_string.empty()) {
383 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
384 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
392 SoundFileBox::save_tags (const vector<string>& tags)
394 Library->set_tags (string ("//") + path, tags);
395 Library->save_changes ();
398 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
399 : ArdourDialog (parent, title, false, false),
400 found_list (ListStore::create(found_list_columns)),
401 freesound_list (ListStore::create(freesound_list_columns)),
402 chooser (FILE_CHOOSER_ACTION_OPEN),
403 preview (persistent),
404 found_search_btn (_("Search")),
405 found_list_view (found_list),
406 freesound_search_btn (_("Start Downloading")),
407 freesound_list_view (freesound_list)
409 resetting_ourselves = false;
412 resetting_ourselves = false;
415 if (ARDOUR::Profile->get_sae()) {
416 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
417 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
421 //add the file chooser
423 chooser.set_border_width (12);
425 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
426 audio_filter.set_name (_("Audio files"));
428 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
429 midi_filter.set_name (_("MIDI files"));
431 matchall_filter.add_pattern ("*.*");
432 matchall_filter.set_name (_("All files"));
434 chooser.add_filter (audio_filter);
435 chooser.add_filter (midi_filter);
436 chooser.add_filter (matchall_filter);
437 chooser.set_select_multiple (true);
438 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
439 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
441 if (!persistent_folder.empty()) {
442 chooser.set_current_folder (persistent_folder);
444 notebook.append_page (chooser, _("Browse Files"));
447 hpacker.set_spacing (6);
448 hpacker.pack_start (notebook, true, true);
449 hpacker.pack_start (preview, false, false);
451 get_vbox()->pack_start (hpacker, true, true);
459 hbox = manage(new HBox);
460 hbox->pack_start (found_entry);
461 hbox->pack_start (found_search_btn);
463 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
464 scroll->add(found_list_view);
465 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
467 vbox = manage(new VBox);
468 vbox->pack_start (*hbox, PACK_SHRINK);
469 vbox->pack_start (*scroll);
471 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
473 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
475 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
477 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
478 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
480 notebook.append_page (*vbox, _("Search Tags"));
483 //add freesound search
490 passbox = manage(new HBox);
491 passbox->set_border_width (12);
492 passbox->set_spacing (6);
494 label = manage (new Label);
495 label->set_text (_("User:"));
496 passbox->pack_start (*label, false, false);
497 passbox->pack_start (freesound_name_entry);
498 label = manage (new Label);
499 label->set_text (_("Password:"));
500 passbox->pack_start (*label, false, false);
501 passbox->pack_start (freesound_pass_entry);
502 label = manage (new Label);
503 label->set_text (_("Tags:"));
504 passbox->pack_start (*label, false, false);
505 passbox->pack_start (freesound_entry, false, false);
506 passbox->pack_start (freesound_search_btn, false, false);
508 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
509 scroll->add(freesound_list_view);
510 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
512 vbox = manage(new VBox);
513 vbox->pack_start (*passbox, PACK_SHRINK);
514 vbox->pack_start(*scroll);
516 //vbox->pack_start (freesound_list_view);
518 freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname);
519 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
521 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
522 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
523 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
524 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
525 notebook.append_page (*vbox, _("Search Freesound"));
530 notebook.set_size_request (500, -1);
534 add_button (Stock::CANCEL, RESPONSE_CANCEL);
535 add_button (Stock::APPLY, RESPONSE_APPLY);
536 add_button (Stock::OK, RESPONSE_OK);
540 SoundFileBrowser::~SoundFileBrowser ()
542 persistent_folder = chooser.get_current_folder();
547 SoundFileBrowser::on_show ()
549 ArdourDialog::on_show ();
554 SoundFileBrowser::clear_selection ()
556 chooser.unselect_all ();
557 found_list_view.get_selection()->unselect_all ();
561 SoundFileBrowser::chooser_file_activated ()
567 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
573 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
579 SoundFileBrowser::set_session (Session* s)
581 ArdourDialog::set_session (s);
582 preview.set_session (s);
587 remove_gain_meter ();
592 SoundFileBrowser::add_gain_meter ()
596 gm = new GainMeter (_session, 250);
598 boost::shared_ptr<Route> r = _session->the_auditioner ();
600 gm->set_controls (r, r->shared_peak_meter(), r->amp());
602 meter_packer.set_border_width (12);
603 meter_packer.pack_start (*gm, false, true);
604 hpacker.pack_end (meter_packer, false, false);
605 meter_packer.show_all ();
610 SoundFileBrowser::remove_gain_meter ()
613 meter_packer.remove (*gm);
614 hpacker.remove (meter_packer);
621 SoundFileBrowser::start_metering ()
623 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
627 SoundFileBrowser::stop_metering ()
629 metering_connection.disconnect();
633 SoundFileBrowser::meter ()
635 if (is_mapped () && _session && gm) {
636 gm->update_meters ();
641 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
643 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
647 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
649 return SMFSource::safe_midi_file_extension (filter_info.filename);
653 SoundFileBrowser::update_preview ()
655 if (preview.setup_labels (chooser.get_filename())) {
656 if (preview.autoplay()) {
657 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
663 SoundFileBrowser::found_list_view_selected ()
665 if (!reset_options ()) {
666 set_response_sensitive (RESPONSE_OK, false);
670 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
673 TreeIter iter = found_list->get_iter(*rows.begin());
674 file = (*iter)[found_list_columns.pathname];
675 chooser.set_filename (file);
676 set_response_sensitive (RESPONSE_OK, true);
678 set_response_sensitive (RESPONSE_OK, false);
681 preview.setup_labels (file);
686 SoundFileBrowser::freesound_list_view_selected ()
688 if (!reset_options ()) {
689 set_response_sensitive (RESPONSE_OK, false);
693 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
696 TreeIter iter = freesound_list->get_iter(*rows.begin());
697 file = (*iter)[freesound_list_columns.pathname];
698 chooser.set_filename (file);
699 set_response_sensitive (RESPONSE_OK, true);
701 set_response_sensitive (RESPONSE_OK, false);
704 preview.setup_labels (file);
709 SoundFileBrowser::found_search_clicked ()
711 string tag_string = found_entry.get_text ();
715 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
716 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
720 vector<string> results;
721 Library->search_members_and (results, tags);
724 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
725 TreeModel::iterator new_row = found_list->append();
726 TreeModel::Row row = *new_row;
727 string path = Glib::filename_from_uri (string ("file:") + *i);
728 row[found_list_columns.pathname] = path;
733 freesound_search_thread_entry (void* arg)
735 SessionEvent::create_per_thread_pool ("freesound events", 64);
737 static_cast<SoundFileBrowser*>(arg)->freesound_search_thread ();
742 bool searching = false;
743 bool canceling = false;
746 SoundFileBrowser::freesound_search_clicked ()
748 if (canceling) //already canceling, button does nothing
752 freesound_search_btn.set_label(_("Cancelling.."));
756 freesound_search_btn.set_label(_("Cancel"));
757 pthread_t freesound_thr;
758 pthread_create_and_store ("freesound_search", &freesound_thr, freesound_search_thread_entry, this);
763 SoundFileBrowser::freesound_search_thread()
767 THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD
770 freesound_list->clear();
773 path = Glib::get_home_dir();
774 path += "/Freesound/";
775 Mootcher theMootcher(path.c_str());
777 string name_string = freesound_name_entry.get_text ();
778 string pass_string = freesound_pass_entry.get_text ();
779 string search_string = freesound_entry.get_text ();
781 if ( theMootcher.doLogin( name_string, pass_string ) ) {
783 string theString = theMootcher.searchText(search_string);
786 doc.read_buffer( theString );
787 XMLNode *root = doc.root();
789 if (root==NULL) return;
791 if ( strcmp(root->name().c_str(), "freesound") == 0) {
794 XMLNodeList children = root->children();
795 XMLNodeConstIterator niter;
796 for (niter = children.begin(); niter != children.end() && !canceling; ++niter) {
798 if( strcmp( node->name().c_str(), "sample") == 0 ){
799 XMLProperty *prop=node->property ("id");
800 string filename = theMootcher.getFile( prop->value().c_str() );
801 if ( filename != "" ) {
802 TreeModel::iterator new_row = freesound_list->append();
803 TreeModel::Row row = *new_row;
804 string path = Glib::filename_from_uri (string ("file:") + filename);
805 row[freesound_list_columns.pathname] = path;
814 freesound_search_btn.set_label(_("Start Downloading"));
821 SoundFileBrowser::get_paths ()
823 vector<ustring> results;
825 int n = notebook.get_current_page ();
828 vector<ustring> filenames = chooser.get_filenames();
829 vector<ustring>::iterator i;
831 for (i = filenames.begin(); i != filenames.end(); ++i) {
833 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
834 results.push_back (*i);
840 typedef TreeView::Selection::ListHandle_Path ListPath;
842 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
843 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
844 TreeIter iter = found_list->get_iter(*i);
845 ustring str = (*iter)[found_list_columns.pathname];
847 results.push_back (str);
851 typedef TreeView::Selection::ListHandle_Path ListPath;
853 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
854 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
855 TreeIter iter = freesound_list->get_iter(*i);
856 ustring str = (*iter)[freesound_list_columns.pathname];
858 results.push_back (str);
866 SoundFileOmega::reset_options_noret ()
868 if (!resetting_ourselves) {
869 (void) reset_options ();
874 SoundFileOmega::reset_options ()
876 vector<ustring> paths = get_paths ();
880 channel_combo.set_sensitive (false);
881 action_combo.set_sensitive (false);
882 where_combo.set_sensitive (false);
883 copy_files_btn.set_sensitive (false);
889 channel_combo.set_sensitive (true);
890 action_combo.set_sensitive (true);
891 where_combo.set_sensitive (true);
893 /* if we get through this function successfully, this may be
894 reset at the end, once we know if we can use hard links
898 if (Config->get_only_copy_imported_files()) {
899 copy_files_btn.set_sensitive (false);
901 copy_files_btn.set_sensitive (false);
907 bool selection_includes_multichannel;
908 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
911 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
912 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
916 ustring existing_choice;
917 vector<string> action_strings;
919 if (selected_track_cnt > 0) {
920 if (channel_combo.get_active_text().length()) {
921 ImportDisposition id = get_channel_disposition();
924 case Editing::ImportDistinctFiles:
925 if (selected_track_cnt == paths.size()) {
926 action_strings.push_back (importmode2string (ImportToTrack));
930 case Editing::ImportDistinctChannels:
931 /* XXX it would be nice to allow channel-per-selected track
932 but its too hard we don't want to deal with all the
933 different per-file + per-track channel configurations.
938 action_strings.push_back (importmode2string (ImportToTrack));
944 action_strings.push_back (importmode2string (ImportAsTrack));
945 action_strings.push_back (importmode2string (ImportAsRegion));
946 action_strings.push_back (importmode2string (ImportAsTapeTrack));
948 resetting_ourselves = true;
950 existing_choice = action_combo.get_active_text();
952 set_popdown_strings (action_combo, action_strings);
954 /* preserve any existing choice, if possible */
957 if (existing_choice.length()) {
958 vector<string>::iterator x;
959 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
960 if (*x == existing_choice) {
961 action_combo.set_active_text (existing_choice);
965 if (x == action_strings.end()) {
966 action_combo.set_active_text (action_strings.front());
969 action_combo.set_active_text (action_strings.front());
972 resetting_ourselves = false;
974 if ((mode = get_mode()) == ImportAsRegion) {
975 where_combo.set_sensitive (false);
977 where_combo.set_sensitive (true);
980 vector<string> channel_strings;
982 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
983 channel_strings.push_back (_("one track per file"));
985 if (selection_includes_multichannel) {
986 channel_strings.push_back (_("one track per channel"));
989 if (paths.size() > 1) {
990 /* tape tracks are a single region per track, so we cannot
991 sequence multiple files.
993 if (mode != ImportAsTapeTrack) {
994 channel_strings.push_back (_("sequence files"));
997 channel_strings.push_back (_("all files in one region"));
1003 channel_strings.push_back (_("one region per file"));
1005 if (selection_includes_multichannel) {
1006 channel_strings.push_back (_("one region per channel"));
1009 if (paths.size() > 1) {
1011 channel_strings.push_back (_("all files in one region"));
1016 existing_choice = channel_combo.get_active_text();
1018 set_popdown_strings (channel_combo, channel_strings);
1020 /* preserve any existing choice, if possible */
1022 if (existing_choice.length()) {
1023 vector<string>::iterator x;
1024 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1025 if (*x == existing_choice) {
1026 channel_combo.set_active_text (existing_choice);
1030 if (x == channel_strings.end()) {
1031 channel_combo.set_active_text (channel_strings.front());
1034 channel_combo.set_active_text (channel_strings.front());
1038 src_combo.set_sensitive (true);
1040 src_combo.set_sensitive (false);
1043 if (Config->get_only_copy_imported_files()) {
1045 if (selection_can_be_embedded_with_links) {
1046 copy_files_btn.set_sensitive (true);
1048 copy_files_btn.set_sensitive (false);
1053 copy_files_btn.set_sensitive (true);
1061 SoundFileOmega::bad_file_message()
1063 MessageDialog msg (*this,
1064 _("One or more of the selected files\ncannot be used by Ardour"),
1069 resetting_ourselves = true;
1070 chooser.unselect_uri (chooser.get_preview_uri());
1071 resetting_ourselves = false;
1077 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1086 multichannel = false;
1088 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1090 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1091 if (info.channels > 1) {
1092 multichannel = true;
1097 if (sz != info.length) {
1102 if ((nframes_t) info.samplerate != _session->frame_rate()) {
1106 } else if (SMFSource::safe_midi_file_extension (*i)) {
1110 if (reader.num_tracks() > 1) {
1111 multichannel = true; // "channel" == track here...
1114 /* XXX we need err = true handling here in case
1115 we can't check the file
1128 SoundFileOmega::check_link_status (const Session* s, const vector<ustring>& paths)
1130 sys::path path = s->session_directory().sound_path() / "linktest";
1131 string tmpdir = path.to_string();
1134 if (mkdir (tmpdir.c_str(), 0744)) {
1135 if (errno != EEXIST) {
1140 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1142 char tmpc[MAXPATHLEN+1];
1144 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1148 if (link ((*i).c_str(), tmpc)) {
1158 rmdir (tmpdir.c_str());
1162 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1163 : SoundFileBrowser (parent, title, s, false)
1165 chooser.set_select_multiple (false);
1166 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1167 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1171 SoundFileChooser::on_hide ()
1173 ArdourDialog::on_hide();
1177 _session->cancel_audition();
1182 SoundFileChooser::get_filename ()
1184 vector<ustring> paths;
1186 paths = get_paths ();
1188 if (paths.empty()) {
1192 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1196 return paths.front();
1199 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
1200 Editing::ImportMode mode_hint)
1201 : SoundFileBrowser (parent, title, s, persistent),
1202 copy_files_btn ( _("Copy files to session")),
1203 selected_track_cnt (selected_tracks)
1209 set_size_request (-1, 450);
1211 block_two.set_border_width (12);
1212 block_three.set_border_width (12);
1213 block_four.set_border_width (12);
1215 options.set_spacing (12);
1218 str.push_back (_("file timestamp"));
1219 str.push_back (_("edit point"));
1220 str.push_back (_("playhead"));
1221 str.push_back (_("session start"));
1222 set_popdown_strings (where_combo, str);
1223 where_combo.set_active_text (str.front());
1225 Label* l = manage (new Label);
1226 l->set_text (_("Add files:"));
1228 hbox = manage (new HBox);
1229 hbox->set_border_width (12);
1230 hbox->set_spacing (6);
1231 hbox->pack_start (*l, false, false);
1232 hbox->pack_start (action_combo, false, false);
1233 vbox = manage (new VBox);
1234 vbox->pack_start (*hbox, false, false);
1235 options.pack_start (*vbox, false, false);
1237 /* dummy entry for action combo so that it doesn't look odd if we
1238 come up with no tracks selected.
1242 str.push_back (importmode2string (mode_hint));
1243 set_popdown_strings (action_combo, str);
1244 action_combo.set_active_text (str.front());
1245 action_combo.set_sensitive (false);
1247 l = manage (new Label);
1248 l->set_text (_("Insert at:"));
1250 hbox = manage (new HBox);
1251 hbox->set_border_width (12);
1252 hbox->set_spacing (6);
1253 hbox->pack_start (*l, false, false);
1254 hbox->pack_start (where_combo, false, false);
1255 vbox = manage (new VBox);
1256 vbox->pack_start (*hbox, false, false);
1257 options.pack_start (*vbox, false, false);
1260 l = manage (new Label);
1261 l->set_text (_("Mapping:"));
1263 hbox = manage (new HBox);
1264 hbox->set_border_width (12);
1265 hbox->set_spacing (6);
1266 hbox->pack_start (*l, false, false);
1267 hbox->pack_start (channel_combo, false, false);
1268 vbox = manage (new VBox);
1269 vbox->pack_start (*hbox, false, false);
1270 options.pack_start (*vbox, false, false);
1273 str.push_back (_("one track per file"));
1274 set_popdown_strings (channel_combo, str);
1275 channel_combo.set_active_text (str.front());
1276 channel_combo.set_sensitive (false);
1278 l = manage (new Label);
1279 l->set_text (_("Conversion quality:"));
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 (src_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 (_("Best"));
1292 str.push_back (_("Good"));
1293 str.push_back (_("Quick"));
1294 str.push_back (_("Fast"));
1295 str.push_back (_("Fastest"));
1297 set_popdown_strings (src_combo, str);
1298 src_combo.set_active_text (str.front());
1299 src_combo.set_sensitive (false);
1303 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1305 copy_files_btn.set_active (true);
1307 block_four.pack_start (copy_files_btn, false, false);
1309 options.pack_start (block_four, false, false);
1311 get_vbox()->pack_start (options, false, false);
1313 /* setup disposition map */
1315 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1316 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1317 disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1318 disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1320 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1321 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1322 disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1324 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1326 /* set size requests for a couple of combos to allow them to display the longest text
1327 they will ever be asked to display. This prevents them being resized when the user
1328 selects a file to import, which in turn prevents the size of the dialog from jumping
1332 t.push_back (_("one track per file"));
1333 t.push_back (_("one track per channel"));
1334 t.push_back (_("sequence files"));
1335 t.push_back (_("all files in one region"));
1336 set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
1339 t.push_back (importmode2string (ImportAsTrack));
1340 t.push_back (importmode2string (ImportToTrack));
1341 t.push_back (importmode2string (ImportAsRegion));
1342 t.push_back (importmode2string (ImportAsTapeTrack));
1343 set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
1347 SoundFileOmega::set_mode (ImportMode mode)
1349 action_combo.set_active_text (importmode2string (mode));
1353 SoundFileOmega::get_mode () const
1355 return string2importmode (action_combo.get_active_text());
1359 SoundFileOmega::on_hide ()
1361 ArdourDialog::on_hide();
1363 _session->cancel_audition();
1368 SoundFileOmega::get_position() const
1370 ustring str = where_combo.get_active_text();
1372 if (str == _("file timestamp")) {
1373 return ImportAtTimestamp;
1374 } else if (str == _("edit point")) {
1375 return ImportAtEditPoint;
1376 } else if (str == _("playhead")) {
1377 return ImportAtPlayhead;
1379 return ImportAtStart;
1384 SoundFileOmega::get_src_quality() const
1386 ustring str = where_combo.get_active_text();
1388 if (str == _("Best")) {
1390 } else if (str == _("Good")) {
1392 } else if (str == _("Quick")) {
1394 } else if (str == _("Fast")) {
1402 SoundFileOmega::get_channel_disposition () const
1404 /* we use a map here because the channel combo can contain different strings
1405 depending on the state of the other combos. the map contains all possible strings
1406 and the ImportDisposition enum that corresponds to it.
1409 ustring str = channel_combo.get_active_text();
1410 DispositionMap::const_iterator x = disposition_map.find (str);
1412 if (x == disposition_map.end()) {
1413 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1421 SoundFileOmega::reset (int selected_tracks)
1423 selected_track_cnt = selected_tracks;
1428 SoundFileOmega::file_selection_changed ()
1430 if (resetting_ourselves) {
1434 if (!reset_options ()) {
1435 set_response_sensitive (RESPONSE_OK, false);
1437 if (chooser.get_filenames().size() > 0) {
1438 set_response_sensitive (RESPONSE_OK, true);
1440 set_response_sensitive (RESPONSE_OK, false);