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);
353 plist.add (ARDOUR::Properties::start, 0);
354 plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
355 plist.add (ARDOUR::Properties::name, rname);
356 plist.add (ARDOUR::Properties::layer, 0);
358 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
360 _session->audition_region(r);
364 SoundFileBox::stop_audition ()
367 _session->cancel_audition();
372 SoundFileBox::tags_entry_left (GdkEventFocus *)
379 SoundFileBox::tags_changed ()
381 string tag_string = tags_entry.get_buffer()->get_text ();
383 if (tag_string.empty()) {
389 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
390 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
398 SoundFileBox::save_tags (const vector<string>& tags)
400 Library->set_tags (string ("//") + path, tags);
401 Library->save_changes ();
404 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
405 : ArdourDialog (parent, title, false, false),
406 found_list (ListStore::create(found_list_columns)),
407 freesound_list (ListStore::create(freesound_list_columns)),
408 chooser (FILE_CHOOSER_ACTION_OPEN),
409 preview (persistent),
410 found_search_btn (_("Search")),
411 found_list_view (found_list),
412 freesound_search_btn (_("Start Downloading")),
413 freesound_list_view (freesound_list)
415 resetting_ourselves = false;
418 resetting_ourselves = false;
421 if (ARDOUR::Profile->get_sae()) {
422 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
423 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
427 //add the file chooser
429 chooser.set_border_width (12);
431 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
432 audio_filter.set_name (_("Audio files"));
434 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
435 midi_filter.set_name (_("MIDI files"));
437 matchall_filter.add_pattern ("*.*");
438 matchall_filter.set_name (_("All files"));
440 chooser.add_filter (audio_filter);
441 chooser.add_filter (midi_filter);
442 chooser.add_filter (matchall_filter);
443 chooser.set_select_multiple (true);
444 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
445 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
447 if (!persistent_folder.empty()) {
448 chooser.set_current_folder (persistent_folder);
450 notebook.append_page (chooser, _("Browse Files"));
453 hpacker.set_spacing (6);
454 hpacker.pack_start (notebook, true, true);
455 hpacker.pack_start (preview, false, false);
457 get_vbox()->pack_start (hpacker, true, true);
465 hbox = manage(new HBox);
466 hbox->pack_start (found_entry);
467 hbox->pack_start (found_search_btn);
469 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
470 scroll->add(found_list_view);
471 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
473 vbox = manage(new VBox);
474 vbox->pack_start (*hbox, PACK_SHRINK);
475 vbox->pack_start (*scroll);
477 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
479 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
481 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
483 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
484 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
486 notebook.append_page (*vbox, _("Search Tags"));
489 //add freesound search
496 passbox = manage(new HBox);
497 passbox->set_border_width (12);
498 passbox->set_spacing (6);
500 label = manage (new Label);
501 label->set_text (_("User:"));
502 passbox->pack_start (*label, false, false);
503 passbox->pack_start (freesound_name_entry);
504 label = manage (new Label);
505 label->set_text (_("Password:"));
506 passbox->pack_start (*label, false, false);
507 passbox->pack_start (freesound_pass_entry);
508 label = manage (new Label);
509 label->set_text (_("Tags:"));
510 passbox->pack_start (*label, false, false);
511 passbox->pack_start (freesound_entry, false, false);
512 passbox->pack_start (freesound_search_btn, false, false);
514 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
515 scroll->add(freesound_list_view);
516 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
518 vbox = manage(new VBox);
519 vbox->pack_start (*passbox, PACK_SHRINK);
520 vbox->pack_start(*scroll);
522 //vbox->pack_start (freesound_list_view);
524 freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname);
525 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
527 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
528 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
529 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
530 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
531 notebook.append_page (*vbox, _("Search Freesound"));
536 notebook.set_size_request (500, -1);
540 add_button (Stock::CANCEL, RESPONSE_CANCEL);
541 add_button (Stock::APPLY, RESPONSE_APPLY);
542 add_button (Stock::OK, RESPONSE_OK);
546 SoundFileBrowser::~SoundFileBrowser ()
548 persistent_folder = chooser.get_current_folder();
553 SoundFileBrowser::on_show ()
555 ArdourDialog::on_show ();
560 SoundFileBrowser::clear_selection ()
562 chooser.unselect_all ();
563 found_list_view.get_selection()->unselect_all ();
567 SoundFileBrowser::chooser_file_activated ()
573 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
579 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
585 SoundFileBrowser::set_session (Session* s)
587 ArdourDialog::set_session (s);
588 preview.set_session (s);
593 remove_gain_meter ();
598 SoundFileBrowser::add_gain_meter ()
602 gm = new GainMeter (_session, 250);
604 boost::shared_ptr<Route> r = _session->the_auditioner ();
606 gm->set_controls (r, r->shared_peak_meter(), r->amp());
608 meter_packer.set_border_width (12);
609 meter_packer.pack_start (*gm, false, true);
610 hpacker.pack_end (meter_packer, false, false);
611 meter_packer.show_all ();
616 SoundFileBrowser::remove_gain_meter ()
619 meter_packer.remove (*gm);
620 hpacker.remove (meter_packer);
627 SoundFileBrowser::start_metering ()
629 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
633 SoundFileBrowser::stop_metering ()
635 metering_connection.disconnect();
639 SoundFileBrowser::meter ()
641 if (is_mapped () && _session && gm) {
642 gm->update_meters ();
647 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
649 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
653 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
655 return SMFSource::safe_midi_file_extension (filter_info.filename);
659 SoundFileBrowser::update_preview ()
661 if (preview.setup_labels (chooser.get_filename())) {
662 if (preview.autoplay()) {
663 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
669 SoundFileBrowser::found_list_view_selected ()
671 if (!reset_options ()) {
672 set_response_sensitive (RESPONSE_OK, false);
676 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
679 TreeIter iter = found_list->get_iter(*rows.begin());
680 file = (*iter)[found_list_columns.pathname];
681 chooser.set_filename (file);
682 set_response_sensitive (RESPONSE_OK, true);
684 set_response_sensitive (RESPONSE_OK, false);
687 preview.setup_labels (file);
692 SoundFileBrowser::freesound_list_view_selected ()
694 if (!reset_options ()) {
695 set_response_sensitive (RESPONSE_OK, false);
699 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
702 TreeIter iter = freesound_list->get_iter(*rows.begin());
703 file = (*iter)[freesound_list_columns.pathname];
704 chooser.set_filename (file);
705 set_response_sensitive (RESPONSE_OK, true);
707 set_response_sensitive (RESPONSE_OK, false);
710 preview.setup_labels (file);
715 SoundFileBrowser::found_search_clicked ()
717 string tag_string = found_entry.get_text ();
721 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
722 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
726 vector<string> results;
727 Library->search_members_and (results, tags);
730 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
731 TreeModel::iterator new_row = found_list->append();
732 TreeModel::Row row = *new_row;
733 string path = Glib::filename_from_uri (string ("file:") + *i);
734 row[found_list_columns.pathname] = path;
739 freesound_search_thread_entry (void* arg)
741 SessionEvent::create_per_thread_pool ("freesound events", 64);
743 static_cast<SoundFileBrowser*>(arg)->freesound_search_thread ();
748 bool searching = false;
749 bool canceling = false;
752 SoundFileBrowser::freesound_search_clicked ()
754 if (canceling) //already canceling, button does nothing
758 freesound_search_btn.set_label(_("Cancelling.."));
762 freesound_search_btn.set_label(_("Cancel"));
763 pthread_t freesound_thr;
764 pthread_create_and_store ("freesound_search", &freesound_thr, freesound_search_thread_entry, this);
769 SoundFileBrowser::freesound_search_thread()
773 THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD
776 freesound_list->clear();
779 path = Glib::get_home_dir();
780 path += "/Freesound/";
781 Mootcher theMootcher(path.c_str());
783 string name_string = freesound_name_entry.get_text ();
784 string pass_string = freesound_pass_entry.get_text ();
785 string search_string = freesound_entry.get_text ();
787 if ( theMootcher.doLogin( name_string, pass_string ) ) {
789 string theString = theMootcher.searchText(search_string);
792 doc.read_buffer( theString );
793 XMLNode *root = doc.root();
795 if (root==NULL) return;
797 if ( strcmp(root->name().c_str(), "freesound") == 0) {
800 XMLNodeList children = root->children();
801 XMLNodeConstIterator niter;
802 for (niter = children.begin(); niter != children.end() && !canceling; ++niter) {
804 if( strcmp( node->name().c_str(), "sample") == 0 ){
805 XMLProperty *prop=node->property ("id");
806 string filename = theMootcher.getFile( prop->value().c_str() );
807 if ( filename != "" ) {
808 TreeModel::iterator new_row = freesound_list->append();
809 TreeModel::Row row = *new_row;
810 string path = Glib::filename_from_uri (string ("file:") + filename);
811 row[freesound_list_columns.pathname] = path;
820 freesound_search_btn.set_label(_("Start Downloading"));
827 SoundFileBrowser::get_paths ()
829 vector<ustring> results;
831 int n = notebook.get_current_page ();
834 vector<ustring> filenames = chooser.get_filenames();
835 vector<ustring>::iterator i;
837 for (i = filenames.begin(); i != filenames.end(); ++i) {
839 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
840 results.push_back (*i);
846 typedef TreeView::Selection::ListHandle_Path ListPath;
848 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
849 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
850 TreeIter iter = found_list->get_iter(*i);
851 ustring str = (*iter)[found_list_columns.pathname];
853 results.push_back (str);
857 typedef TreeView::Selection::ListHandle_Path ListPath;
859 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
860 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
861 TreeIter iter = freesound_list->get_iter(*i);
862 ustring str = (*iter)[freesound_list_columns.pathname];
864 results.push_back (str);
872 SoundFileOmega::reset_options_noret ()
874 if (!resetting_ourselves) {
875 (void) reset_options ();
880 SoundFileOmega::reset_options ()
882 vector<ustring> paths = get_paths ();
886 channel_combo.set_sensitive (false);
887 action_combo.set_sensitive (false);
888 where_combo.set_sensitive (false);
889 copy_files_btn.set_sensitive (false);
895 channel_combo.set_sensitive (true);
896 action_combo.set_sensitive (true);
897 where_combo.set_sensitive (true);
899 /* if we get through this function successfully, this may be
900 reset at the end, once we know if we can use hard links
904 if (Config->get_only_copy_imported_files()) {
905 copy_files_btn.set_sensitive (false);
907 copy_files_btn.set_sensitive (false);
913 bool selection_includes_multichannel;
914 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
917 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
918 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
922 ustring existing_choice;
923 vector<string> action_strings;
925 if (selected_track_cnt > 0) {
926 if (channel_combo.get_active_text().length()) {
927 ImportDisposition id = get_channel_disposition();
930 case Editing::ImportDistinctFiles:
931 if (selected_track_cnt == paths.size()) {
932 action_strings.push_back (importmode2string (ImportToTrack));
936 case Editing::ImportDistinctChannels:
937 /* XXX it would be nice to allow channel-per-selected track
938 but its too hard we don't want to deal with all the
939 different per-file + per-track channel configurations.
944 action_strings.push_back (importmode2string (ImportToTrack));
950 action_strings.push_back (importmode2string (ImportAsTrack));
951 action_strings.push_back (importmode2string (ImportAsRegion));
952 action_strings.push_back (importmode2string (ImportAsTapeTrack));
954 resetting_ourselves = true;
956 existing_choice = action_combo.get_active_text();
958 set_popdown_strings (action_combo, action_strings);
960 /* preserve any existing choice, if possible */
963 if (existing_choice.length()) {
964 vector<string>::iterator x;
965 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
966 if (*x == existing_choice) {
967 action_combo.set_active_text (existing_choice);
971 if (x == action_strings.end()) {
972 action_combo.set_active_text (action_strings.front());
975 action_combo.set_active_text (action_strings.front());
978 resetting_ourselves = false;
980 if ((mode = get_mode()) == ImportAsRegion) {
981 where_combo.set_sensitive (false);
983 where_combo.set_sensitive (true);
986 vector<string> channel_strings;
988 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
989 channel_strings.push_back (_("one track per file"));
991 if (selection_includes_multichannel) {
992 channel_strings.push_back (_("one track per channel"));
995 if (paths.size() > 1) {
996 /* tape tracks are a single region per track, so we cannot
997 sequence multiple files.
999 if (mode != ImportAsTapeTrack) {
1000 channel_strings.push_back (_("sequence files"));
1003 channel_strings.push_back (_("all files in one region"));
1009 channel_strings.push_back (_("one region per file"));
1011 if (selection_includes_multichannel) {
1012 channel_strings.push_back (_("one region per channel"));
1015 if (paths.size() > 1) {
1017 channel_strings.push_back (_("all files in one region"));
1022 existing_choice = channel_combo.get_active_text();
1024 set_popdown_strings (channel_combo, channel_strings);
1026 /* preserve any existing choice, if possible */
1028 if (existing_choice.length()) {
1029 vector<string>::iterator x;
1030 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1031 if (*x == existing_choice) {
1032 channel_combo.set_active_text (existing_choice);
1036 if (x == channel_strings.end()) {
1037 channel_combo.set_active_text (channel_strings.front());
1040 channel_combo.set_active_text (channel_strings.front());
1044 src_combo.set_sensitive (true);
1046 src_combo.set_sensitive (false);
1049 if (Config->get_only_copy_imported_files()) {
1051 if (selection_can_be_embedded_with_links) {
1052 copy_files_btn.set_sensitive (true);
1054 copy_files_btn.set_sensitive (false);
1059 copy_files_btn.set_sensitive (true);
1067 SoundFileOmega::bad_file_message()
1069 MessageDialog msg (*this,
1070 _("One or more of the selected files\ncannot be used by Ardour"),
1075 resetting_ourselves = true;
1076 chooser.unselect_uri (chooser.get_preview_uri());
1077 resetting_ourselves = false;
1083 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1092 multichannel = false;
1094 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1096 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1097 if (info.channels > 1) {
1098 multichannel = true;
1103 if (sz != info.length) {
1108 if ((nframes_t) info.samplerate != _session->frame_rate()) {
1112 } else if (SMFSource::safe_midi_file_extension (*i)) {
1116 if (reader.num_tracks() > 1) {
1117 multichannel = true; // "channel" == track here...
1120 /* XXX we need err = true handling here in case
1121 we can't check the file
1134 SoundFileOmega::check_link_status (const Session* s, const vector<ustring>& paths)
1136 sys::path path = s->session_directory().sound_path() / "linktest";
1137 string tmpdir = path.to_string();
1140 if (mkdir (tmpdir.c_str(), 0744)) {
1141 if (errno != EEXIST) {
1146 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1148 char tmpc[MAXPATHLEN+1];
1150 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1154 if (link ((*i).c_str(), tmpc)) {
1164 rmdir (tmpdir.c_str());
1168 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1169 : SoundFileBrowser (parent, title, s, false)
1171 chooser.set_select_multiple (false);
1172 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1173 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1177 SoundFileChooser::on_hide ()
1179 ArdourDialog::on_hide();
1183 _session->cancel_audition();
1188 SoundFileChooser::get_filename ()
1190 vector<ustring> paths;
1192 paths = get_paths ();
1194 if (paths.empty()) {
1198 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1202 return paths.front();
1205 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
1206 Editing::ImportMode mode_hint)
1207 : SoundFileBrowser (parent, title, s, persistent),
1208 copy_files_btn ( _("Copy files to session")),
1209 selected_track_cnt (selected_tracks)
1215 set_size_request (-1, 450);
1217 block_two.set_border_width (12);
1218 block_three.set_border_width (12);
1219 block_four.set_border_width (12);
1221 options.set_spacing (12);
1224 str.push_back (_("file timestamp"));
1225 str.push_back (_("edit point"));
1226 str.push_back (_("playhead"));
1227 str.push_back (_("session start"));
1228 set_popdown_strings (where_combo, str);
1229 where_combo.set_active_text (str.front());
1231 Label* l = manage (new Label);
1232 l->set_text (_("Add files:"));
1234 hbox = manage (new HBox);
1235 hbox->set_border_width (12);
1236 hbox->set_spacing (6);
1237 hbox->pack_start (*l, false, false);
1238 hbox->pack_start (action_combo, false, false);
1239 vbox = manage (new VBox);
1240 vbox->pack_start (*hbox, false, false);
1241 options.pack_start (*vbox, false, false);
1243 /* dummy entry for action combo so that it doesn't look odd if we
1244 come up with no tracks selected.
1248 str.push_back (importmode2string (mode_hint));
1249 set_popdown_strings (action_combo, str);
1250 action_combo.set_active_text (str.front());
1251 action_combo.set_sensitive (false);
1253 l = manage (new Label);
1254 l->set_text (_("Insert at:"));
1256 hbox = manage (new HBox);
1257 hbox->set_border_width (12);
1258 hbox->set_spacing (6);
1259 hbox->pack_start (*l, false, false);
1260 hbox->pack_start (where_combo, false, false);
1261 vbox = manage (new VBox);
1262 vbox->pack_start (*hbox, false, false);
1263 options.pack_start (*vbox, false, false);
1266 l = manage (new Label);
1267 l->set_text (_("Mapping:"));
1269 hbox = manage (new HBox);
1270 hbox->set_border_width (12);
1271 hbox->set_spacing (6);
1272 hbox->pack_start (*l, false, false);
1273 hbox->pack_start (channel_combo, false, false);
1274 vbox = manage (new VBox);
1275 vbox->pack_start (*hbox, false, false);
1276 options.pack_start (*vbox, false, false);
1279 str.push_back (_("one track per file"));
1280 set_popdown_strings (channel_combo, str);
1281 channel_combo.set_active_text (str.front());
1282 channel_combo.set_sensitive (false);
1284 l = manage (new Label);
1285 l->set_text (_("Conversion quality:"));
1287 hbox = manage (new HBox);
1288 hbox->set_border_width (12);
1289 hbox->set_spacing (6);
1290 hbox->pack_start (*l, false, false);
1291 hbox->pack_start (src_combo, false, false);
1292 vbox = manage (new VBox);
1293 vbox->pack_start (*hbox, false, false);
1294 options.pack_start (*vbox, false, false);
1297 str.push_back (_("Best"));
1298 str.push_back (_("Good"));
1299 str.push_back (_("Quick"));
1300 str.push_back (_("Fast"));
1301 str.push_back (_("Fastest"));
1303 set_popdown_strings (src_combo, str);
1304 src_combo.set_active_text (str.front());
1305 src_combo.set_sensitive (false);
1309 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1311 copy_files_btn.set_active (true);
1313 block_four.pack_start (copy_files_btn, false, false);
1315 options.pack_start (block_four, false, false);
1317 get_vbox()->pack_start (options, false, false);
1319 /* setup disposition map */
1321 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1322 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1323 disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1324 disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1326 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1327 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1328 disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1330 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1332 /* set size requests for a couple of combos to allow them to display the longest text
1333 they will ever be asked to display. This prevents them being resized when the user
1334 selects a file to import, which in turn prevents the size of the dialog from jumping
1338 t.push_back (_("one track per file"));
1339 t.push_back (_("one track per channel"));
1340 t.push_back (_("sequence files"));
1341 t.push_back (_("all files in one region"));
1342 set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
1345 t.push_back (importmode2string (ImportAsTrack));
1346 t.push_back (importmode2string (ImportToTrack));
1347 t.push_back (importmode2string (ImportAsRegion));
1348 t.push_back (importmode2string (ImportAsTapeTrack));
1349 set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
1353 SoundFileOmega::set_mode (ImportMode mode)
1355 action_combo.set_active_text (importmode2string (mode));
1359 SoundFileOmega::get_mode () const
1361 return string2importmode (action_combo.get_active_text());
1365 SoundFileOmega::on_hide ()
1367 ArdourDialog::on_hide();
1369 _session->cancel_audition();
1374 SoundFileOmega::get_position() const
1376 ustring str = where_combo.get_active_text();
1378 if (str == _("file timestamp")) {
1379 return ImportAtTimestamp;
1380 } else if (str == _("edit point")) {
1381 return ImportAtEditPoint;
1382 } else if (str == _("playhead")) {
1383 return ImportAtPlayhead;
1385 return ImportAtStart;
1390 SoundFileOmega::get_src_quality() const
1392 ustring str = where_combo.get_active_text();
1394 if (str == _("Best")) {
1396 } else if (str == _("Good")) {
1398 } else if (str == _("Quick")) {
1400 } else if (str == _("Fast")) {
1408 SoundFileOmega::get_channel_disposition () const
1410 /* we use a map here because the channel combo can contain different strings
1411 depending on the state of the other combos. the map contains all possible strings
1412 and the ImportDisposition enum that corresponds to it.
1415 ustring str = channel_combo.get_active_text();
1416 DispositionMap::const_iterator x = disposition_map.find (str);
1418 if (x == disposition_map.end()) {
1419 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1427 SoundFileOmega::reset (int selected_tracks)
1429 selected_track_cnt = selected_tracks;
1434 SoundFileOmega::file_selection_changed ()
1436 if (resetting_ourselves) {
1440 if (!reset_options ()) {
1441 set_response_sensitive (RESPONSE_OK, false);
1443 if (chooser.get_filenames().size() > 0) {
1444 set_response_sensitive (RESPONSE_OK, true);
1446 set_response_sensitive (RESPONSE_OK, false);