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 chooser.add_shortcut_folder_uri("file:///Volumes");
430 //add the file chooser
432 chooser.set_border_width (12);
434 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
435 audio_filter.set_name (_("Audio files"));
437 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
438 midi_filter.set_name (_("MIDI files"));
440 matchall_filter.add_pattern ("*.*");
441 matchall_filter.set_name (_("All files"));
443 chooser.add_filter (audio_filter);
444 chooser.add_filter (midi_filter);
445 chooser.add_filter (matchall_filter);
446 chooser.set_select_multiple (true);
447 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
448 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
450 /* some broken redraw behaviour - this is a bandaid */
451 chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
454 if (!persistent_folder.empty()) {
455 chooser.set_current_folder (persistent_folder);
457 notebook.append_page (chooser, _("Browse Files"));
460 hpacker.set_spacing (6);
461 hpacker.pack_start (notebook, true, true);
462 hpacker.pack_start (preview, false, false);
464 get_vbox()->pack_start (hpacker, true, true);
472 hbox = manage(new HBox);
473 hbox->pack_start (found_entry);
474 hbox->pack_start (found_search_btn);
476 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
477 scroll->add(found_list_view);
478 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
480 vbox = manage(new VBox);
481 vbox->pack_start (*hbox, PACK_SHRINK);
482 vbox->pack_start (*scroll);
484 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
486 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
488 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
490 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
491 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
493 notebook.append_page (*vbox, _("Search Tags"));
496 //add freesound search
503 passbox = manage(new HBox);
504 passbox->set_border_width (12);
505 passbox->set_spacing (6);
507 label = manage (new Label);
508 label->set_text (_("User:"));
509 passbox->pack_start (*label, false, false);
510 passbox->pack_start (freesound_name_entry);
511 label = manage (new Label);
512 label->set_text (_("Password:"));
513 passbox->pack_start (*label, false, false);
514 passbox->pack_start (freesound_pass_entry);
515 label = manage (new Label);
516 label->set_text (_("Tags:"));
517 passbox->pack_start (*label, false, false);
518 passbox->pack_start (freesound_entry, false, false);
519 passbox->pack_start (freesound_search_btn, false, false);
521 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
522 scroll->add(freesound_list_view);
523 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
525 vbox = manage(new VBox);
526 vbox->pack_start (*passbox, PACK_SHRINK);
527 vbox->pack_start(*scroll);
529 //vbox->pack_start (freesound_list_view);
531 freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname);
532 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
534 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
535 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
536 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
537 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
538 notebook.append_page (*vbox, _("Search Freesound"));
543 notebook.set_size_request (500, -1);
547 add_button (Stock::CANCEL, RESPONSE_CANCEL);
548 add_button (Stock::APPLY, RESPONSE_APPLY);
549 add_button (Stock::OK, RESPONSE_OK);
553 SoundFileBrowser::~SoundFileBrowser ()
555 persistent_folder = chooser.get_current_folder();
560 SoundFileBrowser::on_show ()
562 ArdourDialog::on_show ();
567 SoundFileBrowser::clear_selection ()
569 chooser.unselect_all ();
570 found_list_view.get_selection()->unselect_all ();
574 SoundFileBrowser::chooser_file_activated ()
580 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
586 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
592 SoundFileBrowser::set_session (Session* s)
594 ArdourDialog::set_session (s);
595 preview.set_session (s);
600 remove_gain_meter ();
605 SoundFileBrowser::add_gain_meter ()
609 gm = new GainMeter (_session, 250);
611 boost::shared_ptr<Route> r = _session->the_auditioner ();
613 gm->set_controls (r, r->shared_peak_meter(), r->amp());
615 meter_packer.set_border_width (12);
616 meter_packer.pack_start (*gm, false, true);
617 hpacker.pack_end (meter_packer, false, false);
618 meter_packer.show_all ();
623 SoundFileBrowser::remove_gain_meter ()
626 meter_packer.remove (*gm);
627 hpacker.remove (meter_packer);
634 SoundFileBrowser::start_metering ()
636 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
640 SoundFileBrowser::stop_metering ()
642 metering_connection.disconnect();
646 SoundFileBrowser::meter ()
648 if (is_mapped () && _session && gm) {
649 gm->update_meters ();
654 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
656 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
660 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
662 return SMFSource::safe_midi_file_extension (filter_info.filename);
666 SoundFileBrowser::update_preview ()
668 if (preview.setup_labels (chooser.get_filename())) {
669 if (preview.autoplay()) {
670 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
676 SoundFileBrowser::found_list_view_selected ()
678 if (!reset_options ()) {
679 set_response_sensitive (RESPONSE_OK, false);
683 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
686 TreeIter iter = found_list->get_iter(*rows.begin());
687 file = (*iter)[found_list_columns.pathname];
688 chooser.set_filename (file);
689 set_response_sensitive (RESPONSE_OK, true);
691 set_response_sensitive (RESPONSE_OK, false);
694 preview.setup_labels (file);
699 SoundFileBrowser::freesound_list_view_selected ()
701 if (!reset_options ()) {
702 set_response_sensitive (RESPONSE_OK, false);
706 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
709 TreeIter iter = freesound_list->get_iter(*rows.begin());
710 file = (*iter)[freesound_list_columns.pathname];
711 chooser.set_filename (file);
712 set_response_sensitive (RESPONSE_OK, true);
714 set_response_sensitive (RESPONSE_OK, false);
717 preview.setup_labels (file);
722 SoundFileBrowser::found_search_clicked ()
724 string tag_string = found_entry.get_text ();
728 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
729 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
733 vector<string> results;
734 Library->search_members_and (results, tags);
737 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
738 TreeModel::iterator new_row = found_list->append();
739 TreeModel::Row row = *new_row;
740 string path = Glib::filename_from_uri (string ("file:") + *i);
741 row[found_list_columns.pathname] = path;
746 freesound_search_thread_entry (void* arg)
748 SessionEvent::create_per_thread_pool ("freesound events", 64);
750 static_cast<SoundFileBrowser*>(arg)->freesound_search_thread ();
755 bool searching = false;
756 bool canceling = false;
759 SoundFileBrowser::freesound_search_clicked ()
761 if (canceling) //already canceling, button does nothing
765 freesound_search_btn.set_label(_("Cancelling.."));
769 freesound_search_btn.set_label(_("Cancel"));
770 pthread_t freesound_thr;
771 pthread_create_and_store ("freesound_search", &freesound_thr, freesound_search_thread_entry, this);
776 SoundFileBrowser::freesound_search_thread()
780 THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD
783 freesound_list->clear();
786 path = Glib::get_home_dir();
787 path += "/Freesound/";
788 Mootcher theMootcher(path.c_str());
790 string name_string = freesound_name_entry.get_text ();
791 string pass_string = freesound_pass_entry.get_text ();
792 string search_string = freesound_entry.get_text ();
794 if ( theMootcher.doLogin( name_string, pass_string ) ) {
796 string theString = theMootcher.searchText(search_string);
799 doc.read_buffer( theString );
800 XMLNode *root = doc.root();
802 if (root==NULL) return;
804 if ( strcmp(root->name().c_str(), "freesound") == 0) {
807 XMLNodeList children = root->children();
808 XMLNodeConstIterator niter;
809 for (niter = children.begin(); niter != children.end() && !canceling; ++niter) {
811 if( strcmp( node->name().c_str(), "sample") == 0 ){
812 XMLProperty *prop=node->property ("id");
813 string filename = theMootcher.getFile( prop->value().c_str() );
814 if ( filename != "" ) {
815 TreeModel::iterator new_row = freesound_list->append();
816 TreeModel::Row row = *new_row;
817 string path = Glib::filename_from_uri (string ("file:") + filename);
818 row[freesound_list_columns.pathname] = path;
827 freesound_search_btn.set_label(_("Start Downloading"));
834 SoundFileBrowser::get_paths ()
836 vector<ustring> results;
838 int n = notebook.get_current_page ();
841 vector<ustring> filenames = chooser.get_filenames();
842 vector<ustring>::iterator i;
844 for (i = filenames.begin(); i != filenames.end(); ++i) {
846 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
847 results.push_back (*i);
853 typedef TreeView::Selection::ListHandle_Path ListPath;
855 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
856 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
857 TreeIter iter = found_list->get_iter(*i);
858 ustring str = (*iter)[found_list_columns.pathname];
860 results.push_back (str);
864 typedef TreeView::Selection::ListHandle_Path ListPath;
866 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
867 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
868 TreeIter iter = freesound_list->get_iter(*i);
869 ustring str = (*iter)[freesound_list_columns.pathname];
871 results.push_back (str);
879 SoundFileOmega::reset_options_noret ()
881 if (!resetting_ourselves) {
882 (void) reset_options ();
887 SoundFileOmega::reset_options ()
889 vector<ustring> paths = get_paths ();
893 channel_combo.set_sensitive (false);
894 action_combo.set_sensitive (false);
895 where_combo.set_sensitive (false);
896 copy_files_btn.set_sensitive (false);
902 channel_combo.set_sensitive (true);
903 action_combo.set_sensitive (true);
904 where_combo.set_sensitive (true);
906 /* if we get through this function successfully, this may be
907 reset at the end, once we know if we can use hard links
911 if (Config->get_only_copy_imported_files()) {
912 copy_files_btn.set_sensitive (false);
914 copy_files_btn.set_sensitive (false);
920 bool selection_includes_multichannel;
921 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
924 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
925 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
929 ustring existing_choice;
930 vector<string> action_strings;
932 if (selected_track_cnt > 0) {
933 if (channel_combo.get_active_text().length()) {
934 ImportDisposition id = get_channel_disposition();
937 case Editing::ImportDistinctFiles:
938 if (selected_track_cnt == paths.size()) {
939 action_strings.push_back (importmode2string (ImportToTrack));
943 case Editing::ImportDistinctChannels:
944 /* XXX it would be nice to allow channel-per-selected track
945 but its too hard we don't want to deal with all the
946 different per-file + per-track channel configurations.
951 action_strings.push_back (importmode2string (ImportToTrack));
957 action_strings.push_back (importmode2string (ImportAsTrack));
958 action_strings.push_back (importmode2string (ImportAsRegion));
959 action_strings.push_back (importmode2string (ImportAsTapeTrack));
961 resetting_ourselves = true;
963 existing_choice = action_combo.get_active_text();
965 set_popdown_strings (action_combo, action_strings);
967 /* preserve any existing choice, if possible */
970 if (existing_choice.length()) {
971 vector<string>::iterator x;
972 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
973 if (*x == existing_choice) {
974 action_combo.set_active_text (existing_choice);
978 if (x == action_strings.end()) {
979 action_combo.set_active_text (action_strings.front());
982 action_combo.set_active_text (action_strings.front());
985 resetting_ourselves = false;
987 if ((mode = get_mode()) == ImportAsRegion) {
988 where_combo.set_sensitive (false);
990 where_combo.set_sensitive (true);
993 vector<string> channel_strings;
995 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
996 channel_strings.push_back (_("one track per file"));
998 if (selection_includes_multichannel) {
999 channel_strings.push_back (_("one track per channel"));
1002 if (paths.size() > 1) {
1003 /* tape tracks are a single region per track, so we cannot
1004 sequence multiple files.
1006 if (mode != ImportAsTapeTrack) {
1007 channel_strings.push_back (_("sequence files"));
1010 channel_strings.push_back (_("all files in one track"));
1016 channel_strings.push_back (_("one region per file"));
1018 if (selection_includes_multichannel) {
1019 channel_strings.push_back (_("one region per channel"));
1022 if (paths.size() > 1) {
1024 channel_strings.push_back (_("all files in one region"));
1029 existing_choice = channel_combo.get_active_text();
1031 set_popdown_strings (channel_combo, channel_strings);
1033 /* preserve any existing choice, if possible */
1035 if (existing_choice.length()) {
1036 vector<string>::iterator x;
1037 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1038 if (*x == existing_choice) {
1039 channel_combo.set_active_text (existing_choice);
1043 if (x == channel_strings.end()) {
1044 channel_combo.set_active_text (channel_strings.front());
1047 channel_combo.set_active_text (channel_strings.front());
1051 src_combo.set_sensitive (true);
1053 src_combo.set_sensitive (false);
1056 if (Config->get_only_copy_imported_files()) {
1058 if (selection_can_be_embedded_with_links) {
1059 copy_files_btn.set_sensitive (true);
1061 copy_files_btn.set_sensitive (false);
1066 copy_files_btn.set_sensitive (true);
1074 SoundFileOmega::bad_file_message()
1076 MessageDialog msg (*this,
1077 _("One or more of the selected files\ncannot be used by Ardour"),
1082 resetting_ourselves = true;
1083 chooser.unselect_uri (chooser.get_preview_uri());
1084 resetting_ourselves = false;
1090 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1099 multichannel = false;
1101 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1103 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1104 if (info.channels > 1) {
1105 multichannel = true;
1110 if (sz != info.length) {
1115 if ((nframes_t) info.samplerate != _session->frame_rate()) {
1119 } else if (SMFSource::safe_midi_file_extension (*i)) {
1123 if (reader.num_tracks() > 1) {
1124 multichannel = true; // "channel" == track here...
1127 /* XXX we need err = true handling here in case
1128 we can't check the file
1141 SoundFileOmega::check_link_status (const Session* s, const vector<ustring>& paths)
1143 sys::path path = s->session_directory().sound_path() / "linktest";
1144 string tmpdir = path.to_string();
1147 if (mkdir (tmpdir.c_str(), 0744)) {
1148 if (errno != EEXIST) {
1153 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1155 char tmpc[MAXPATHLEN+1];
1157 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1161 if (link ((*i).c_str(), tmpc)) {
1171 rmdir (tmpdir.c_str());
1175 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1176 : SoundFileBrowser (parent, title, s, false)
1178 chooser.set_select_multiple (false);
1179 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1180 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1184 SoundFileChooser::on_hide ()
1186 ArdourDialog::on_hide();
1190 _session->cancel_audition();
1195 SoundFileChooser::get_filename ()
1197 vector<ustring> paths;
1199 paths = get_paths ();
1201 if (paths.empty()) {
1205 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1209 return paths.front();
1212 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
1213 Editing::ImportMode mode_hint)
1214 : SoundFileBrowser (parent, title, s, persistent),
1215 copy_files_btn ( _("Copy files to session")),
1216 selected_track_cnt (selected_tracks)
1222 set_size_request (-1, 450);
1224 block_two.set_border_width (12);
1225 block_three.set_border_width (12);
1226 block_four.set_border_width (12);
1228 options.set_spacing (12);
1231 str.push_back (_("file timestamp"));
1232 str.push_back (_("edit point"));
1233 str.push_back (_("playhead"));
1234 str.push_back (_("session start"));
1235 set_popdown_strings (where_combo, str);
1236 where_combo.set_active_text (str.front());
1238 Label* l = manage (new Label);
1239 l->set_text (_("Add files:"));
1241 hbox = manage (new HBox);
1242 hbox->set_border_width (12);
1243 hbox->set_spacing (6);
1244 hbox->pack_start (*l, false, false);
1245 hbox->pack_start (action_combo, false, false);
1246 vbox = manage (new VBox);
1247 vbox->pack_start (*hbox, false, false);
1248 options.pack_start (*vbox, false, false);
1250 /* dummy entry for action combo so that it doesn't look odd if we
1251 come up with no tracks selected.
1255 str.push_back (importmode2string (mode_hint));
1256 set_popdown_strings (action_combo, str);
1257 action_combo.set_active_text (str.front());
1258 action_combo.set_sensitive (false);
1260 l = manage (new Label);
1261 l->set_text (_("Insert at:"));
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 (where_combo, false, false);
1268 vbox = manage (new VBox);
1269 vbox->pack_start (*hbox, false, false);
1270 options.pack_start (*vbox, false, false);
1273 l = manage (new Label);
1274 l->set_text (_("Mapping:"));
1276 hbox = manage (new HBox);
1277 hbox->set_border_width (12);
1278 hbox->set_spacing (6);
1279 hbox->pack_start (*l, false, false);
1280 hbox->pack_start (channel_combo, false, false);
1281 vbox = manage (new VBox);
1282 vbox->pack_start (*hbox, false, false);
1283 options.pack_start (*vbox, false, false);
1286 str.push_back (_("one track per file"));
1287 set_popdown_strings (channel_combo, str);
1288 channel_combo.set_active_text (str.front());
1289 channel_combo.set_sensitive (false);
1291 l = manage (new Label);
1292 l->set_text (_("Conversion quality:"));
1294 hbox = manage (new HBox);
1295 hbox->set_border_width (12);
1296 hbox->set_spacing (6);
1297 hbox->pack_start (*l, false, false);
1298 hbox->pack_start (src_combo, false, false);
1299 vbox = manage (new VBox);
1300 vbox->pack_start (*hbox, false, false);
1301 options.pack_start (*vbox, false, false);
1304 str.push_back (_("Best"));
1305 str.push_back (_("Good"));
1306 str.push_back (_("Quick"));
1307 str.push_back (_("Fast"));
1308 str.push_back (_("Fastest"));
1310 set_popdown_strings (src_combo, str);
1311 src_combo.set_active_text (str.front());
1312 src_combo.set_sensitive (false);
1316 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1318 copy_files_btn.set_active (true);
1320 block_four.pack_start (copy_files_btn, false, false);
1322 options.pack_start (block_four, false, false);
1324 get_vbox()->pack_start (options, false, false);
1326 /* setup disposition map */
1328 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1329 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1330 disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1331 disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1333 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1334 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1335 disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1337 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1339 /* set size requests for a couple of combos to allow them to display the longest text
1340 they will ever be asked to display. This prevents them being resized when the user
1341 selects a file to import, which in turn prevents the size of the dialog from jumping
1345 t.push_back (_("one track per file"));
1346 t.push_back (_("one track per channel"));
1347 t.push_back (_("sequence files"));
1348 t.push_back (_("all files in one region"));
1349 set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
1352 t.push_back (importmode2string (ImportAsTrack));
1353 t.push_back (importmode2string (ImportToTrack));
1354 t.push_back (importmode2string (ImportAsRegion));
1355 t.push_back (importmode2string (ImportAsTapeTrack));
1356 set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
1360 SoundFileOmega::set_mode (ImportMode mode)
1362 action_combo.set_active_text (importmode2string (mode));
1366 SoundFileOmega::get_mode () const
1368 return string2importmode (action_combo.get_active_text());
1372 SoundFileOmega::on_hide ()
1374 ArdourDialog::on_hide();
1376 _session->cancel_audition();
1381 SoundFileOmega::get_position() const
1383 ustring str = where_combo.get_active_text();
1385 if (str == _("file timestamp")) {
1386 return ImportAtTimestamp;
1387 } else if (str == _("edit point")) {
1388 return ImportAtEditPoint;
1389 } else if (str == _("playhead")) {
1390 return ImportAtPlayhead;
1392 return ImportAtStart;
1397 SoundFileOmega::get_src_quality() const
1399 ustring str = where_combo.get_active_text();
1401 if (str == _("Best")) {
1403 } else if (str == _("Good")) {
1405 } else if (str == _("Quick")) {
1407 } else if (str == _("Fast")) {
1415 SoundFileOmega::get_channel_disposition () const
1417 /* we use a map here because the channel combo can contain different strings
1418 depending on the state of the other combos. the map contains all possible strings
1419 and the ImportDisposition enum that corresponds to it.
1422 ustring str = channel_combo.get_active_text();
1423 DispositionMap::const_iterator x = disposition_map.find (str);
1425 if (x == disposition_map.end()) {
1426 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1434 SoundFileOmega::reset (int selected_tracks)
1436 selected_track_cnt = selected_tracks;
1441 SoundFileOmega::file_selection_changed ()
1443 if (resetting_ourselves) {
1447 if (!reset_options ()) {
1448 set_response_sensitive (RESPONSE_OK, false);
1450 if (chooser.get_filenames().size() > 0) {
1451 set_response_sensitive (RESPONSE_OK, true);
1453 set_response_sensitive (RESPONSE_OK, false);