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)
118 length_clock ("sfboxLengthClock", !persistent, "EditCursorClock", false, false, true, false),
119 timecode_clock ("sfboxTimecodeClock", !persistent, "EditCursorClock", false, false, false, false),
121 autoplay_btn (_("Auto-play"))
124 set_name (X_("SoundFileBox"));
125 set_size_request (300, -1);
127 preview_label.set_markup (_("<b>Sound File Information</b>"));
129 border_frame.set_label_widget (preview_label);
130 border_frame.add (main_box);
132 pack_start (border_frame, true, true);
133 set_border_width (6);
135 main_box.set_border_width (6);
137 length.set_text (_("Length:"));
138 length.set_alignment (1, 0.5);
139 timecode.set_text (_("Timestamp:"));
140 timecode.set_alignment (1, 0.5);
141 format.set_text (_("Format:"));
142 format.set_alignment (1, 0.5);
143 channels.set_text (_("Channels:"));
144 channels.set_alignment (1, 0.5);
145 samplerate.set_text (_("Sample rate:"));
146 samplerate.set_alignment (1, 0.5);
148 format_text.set_max_width_chars (8);
149 format_text.set_ellipsize (Pango::ELLIPSIZE_END);
150 format_text.set_alignment (0, 1);
152 table.set_col_spacings (6);
153 table.set_homogeneous (false);
154 table.set_row_spacings (6);
156 table.attach (channels, 0, 1, 0, 1, FILL, FILL);
157 table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
158 table.attach (format, 0, 1, 2, 4, FILL, FILL);
159 table.attach (length, 0, 1, 4, 5, FILL, FILL);
160 table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
162 table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
163 table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
164 table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
165 table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
166 table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
168 length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock.mode());
169 timecode_clock.set_mode (AudioClock::Timecode);
171 main_box.pack_start (table, false, false);
173 tags_entry.set_editable (true);
174 tags_entry.signal_focus_out_event().connect (mem_fun (*this, &SoundFileBox::tags_entry_left));
176 Label* label = manage (new Label (_("Tags:")));
177 label->set_alignment (0.0f, 0.5f);
178 main_box.pack_start (*label, false, false);
179 main_box.pack_start (tags_entry, true, true);
181 main_box.pack_start (bottom_box, false, false);
183 play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
184 play_btn.set_label (_("Play"));
186 stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
187 stop_btn.set_label (_("Stop"));
189 bottom_box.set_homogeneous (false);
190 bottom_box.set_spacing (6);
191 bottom_box.pack_start(play_btn, true, true);
192 bottom_box.pack_start(stop_btn, true, true);
193 bottom_box.pack_start(autoplay_btn, false, false);
195 play_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::audition));
196 stop_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::stop_audition));
198 channels_value.set_alignment (0.0f, 0.5f);
199 samplerate_value.set_alignment (0.0f, 0.5f);
203 SoundFileBox::set_session(Session* s)
208 play_btn.set_sensitive (false);
209 stop_btn.set_sensitive (false);
213 length_clock.set_session (s);
214 timecode_clock.set_session (s);
218 SoundFileBox::setup_labels (const ustring& filename)
221 // save existing tags
229 if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
231 preview_label.set_markup (_("<b>Sound File Information</b>"));
232 format_text.set_text ("");
233 channels_value.set_text ("");
234 samplerate_value.set_text ("");
235 tags_entry.get_buffer()->set_text ("");
237 length_clock.set (0);
238 timecode_clock.set (0);
240 tags_entry.set_sensitive (false);
241 play_btn.set_sensitive (false);
246 preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
247 std::string n = sf_info.format_name;
248 if (n.substr (0, 8) == X_("Format: ")) {
251 format_text.set_text (n);
252 channels_value.set_text (to_string (sf_info.channels, std::dec));
254 if (_session && sf_info.samplerate != _session->frame_rate()) {
255 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
256 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
257 samplerate_value.set_name ("NewSessionSR1Label");
258 samplerate.set_name ("NewSessionSR1Label");
260 samplerate.set_text (_("Sample rate:"));
261 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
262 samplerate_value.set_name ("NewSessionSR2Label");
263 samplerate.set_name ("NewSessionSR2Label");
266 nframes_t const nfr = _session ? _session->nominal_frame_rate() : 25;
267 double src_coef = (double) nfr / sf_info.samplerate;
269 length_clock.set (sf_info.length * src_coef + 0.5, true);
270 timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
272 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
274 vector<string> tags = Library->get_tags (string ("//") + filename);
276 stringstream tag_string;
277 for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
278 if (i != tags.begin()) {
283 tags_entry.get_buffer()->set_text (tag_string.str());
285 tags_entry.set_sensitive (true);
287 play_btn.set_sensitive (true);
294 SoundFileBox::autoplay() const
296 return autoplay_btn.get_active();
300 SoundFileBox::audition_oneshot()
307 SoundFileBox::audition ()
313 _session->cancel_audition();
315 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
316 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
320 boost::shared_ptr<Region> r;
322 boost::shared_ptr<AudioFileSource> afs;
323 bool old_sbp = AudioSource::get_build_peakfiles ();
325 /* don't even think of building peakfiles for these files */
327 AudioSource::set_build_peakfiles (false);
329 for (int n = 0; n < sf_info.channels; ++n) {
331 afs = boost::dynamic_pointer_cast<AudioFileSource> (
332 SourceFactory::createReadable (DataType::AUDIO, *_session,
333 path, n, Source::Flag (0), false));
335 srclist.push_back(afs);
337 } catch (failed_constructor& err) {
338 error << _("Could not access soundfile: ") << path << endmsg;
339 AudioSource::set_build_peakfiles (old_sbp);
344 AudioSource::set_build_peakfiles (old_sbp);
346 if (srclist.empty()) {
350 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
351 string rname = region_name_from_path (afs->path(), false);
352 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0,
353 srclist[0]->length(srclist[0]->timeline_position()),
354 rname, 0, Region::DefaultFlags, false));
356 _session->audition_region(r);
360 SoundFileBox::stop_audition ()
363 _session->cancel_audition();
368 SoundFileBox::tags_entry_left (GdkEventFocus *)
375 SoundFileBox::tags_changed ()
377 string tag_string = tags_entry.get_buffer()->get_text ();
379 if (tag_string.empty()) {
385 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
386 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
394 SoundFileBox::save_tags (const vector<string>& tags)
396 Library->set_tags (string ("//") + path, tags);
397 Library->save_changes ();
400 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
401 : ArdourDialog (parent, title, false, false),
402 found_list (ListStore::create(found_list_columns)),
403 freesound_list (ListStore::create(freesound_list_columns)),
404 chooser (FILE_CHOOSER_ACTION_OPEN),
405 preview (persistent),
406 found_search_btn (_("Search")),
407 found_list_view (found_list),
408 freesound_search_btn (_("Start Downloading")),
409 freesound_list_view (freesound_list)
411 resetting_ourselves = false;
414 resetting_ourselves = false;
417 if (ARDOUR::Profile->get_sae()) {
418 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
419 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
423 //add the file chooser
425 chooser.set_border_width (12);
427 audio_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_audio_filter));
428 audio_filter.set_name (_("Audio files"));
430 midi_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_midi_filter));
431 midi_filter.set_name (_("MIDI files"));
433 matchall_filter.add_pattern ("*.*");
434 matchall_filter.set_name (_("All files"));
436 chooser.add_filter (audio_filter);
437 chooser.add_filter (midi_filter);
438 chooser.add_filter (matchall_filter);
439 chooser.set_select_multiple (true);
440 chooser.signal_update_preview().connect(mem_fun(*this, &SoundFileBrowser::update_preview));
441 chooser.signal_file_activated().connect (mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
443 if (!persistent_folder.empty()) {
444 chooser.set_current_folder (persistent_folder);
446 notebook.append_page (chooser, _("Browse Files"));
449 hpacker.set_spacing (6);
450 hpacker.pack_start (notebook, true, true);
451 hpacker.pack_start (preview, false, false);
453 get_vbox()->pack_start (hpacker, true, true);
461 hbox = manage(new HBox);
462 hbox->pack_start (found_entry);
463 hbox->pack_start (found_search_btn);
465 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
466 scroll->add(found_list_view);
467 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
469 vbox = manage(new VBox);
470 vbox->pack_start (*hbox, PACK_SHRINK);
471 vbox->pack_start (*scroll);
473 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
475 found_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
477 found_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
479 found_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
480 found_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
482 notebook.append_page (*vbox, _("Search Tags"));
485 //add freesound search
492 passbox = manage(new HBox);
493 passbox->set_border_width (12);
494 passbox->set_spacing (6);
496 label = manage (new Label);
497 label->set_text (_("User:"));
498 passbox->pack_start (*label, false, false);
499 passbox->pack_start (freesound_name_entry);
500 label = manage (new Label);
501 label->set_text (_("Password:"));
502 passbox->pack_start (*label, false, false);
503 passbox->pack_start (freesound_pass_entry);
504 label = manage (new Label);
505 label->set_text (_("Tags:"));
506 passbox->pack_start (*label, false, false);
507 passbox->pack_start (freesound_entry, false, false);
508 passbox->pack_start (freesound_search_btn, false, false);
510 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
511 scroll->add(freesound_list_view);
512 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
514 vbox = manage(new VBox);
515 vbox->pack_start (*passbox, PACK_SHRINK);
516 vbox->pack_start(*scroll);
518 //vbox->pack_start (freesound_list_view);
520 freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname);
521 freesound_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
523 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
524 freesound_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
525 freesound_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
526 freesound_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
527 notebook.append_page (*vbox, _("Search Freesound"));
532 notebook.set_size_request (500, -1);
536 add_button (Stock::CANCEL, RESPONSE_CANCEL);
537 add_button (Stock::APPLY, RESPONSE_APPLY);
538 add_button (Stock::OK, RESPONSE_OK);
542 SoundFileBrowser::~SoundFileBrowser ()
544 persistent_folder = chooser.get_current_folder();
549 SoundFileBrowser::on_show ()
551 ArdourDialog::on_show ();
556 SoundFileBrowser::clear_selection ()
558 chooser.unselect_all ();
559 found_list_view.get_selection()->unselect_all ();
563 SoundFileBrowser::chooser_file_activated ()
569 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
575 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
581 SoundFileBrowser::set_session (Session* s)
583 ArdourDialog::set_session (s);
584 preview.set_session (s);
588 remove_gain_meter ();
593 SoundFileBrowser::add_gain_meter ()
597 gm = new GainMeter (*session, 250);
599 boost::shared_ptr<Route> r = session->the_auditioner ();
601 gm->set_controls (r, r->shared_peak_meter(), r->amp());
603 meter_packer.set_border_width (12);
604 meter_packer.pack_start (*gm, false, true);
605 hpacker.pack_end (meter_packer, false, false);
606 meter_packer.show_all ();
611 SoundFileBrowser::remove_gain_meter ()
614 meter_packer.remove (*gm);
615 hpacker.remove (meter_packer);
622 SoundFileBrowser::start_metering ()
624 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun(*this, &SoundFileBrowser::meter));
628 SoundFileBrowser::stop_metering ()
630 metering_connection.disconnect();
634 SoundFileBrowser::meter ()
636 if (is_mapped () && session && gm) {
637 gm->update_meters ();
642 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
644 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
648 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
650 return SMFSource::safe_midi_file_extension (filter_info.filename);
654 SoundFileBrowser::update_preview ()
656 if (preview.setup_labels (chooser.get_filename())) {
657 if (preview.autoplay()) {
658 Glib::signal_idle().connect (mem_fun (preview, &SoundFileBox::audition_oneshot));
664 SoundFileBrowser::found_list_view_selected ()
666 if (!reset_options ()) {
667 set_response_sensitive (RESPONSE_OK, false);
671 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
674 TreeIter iter = found_list->get_iter(*rows.begin());
675 file = (*iter)[found_list_columns.pathname];
676 chooser.set_filename (file);
677 set_response_sensitive (RESPONSE_OK, true);
679 set_response_sensitive (RESPONSE_OK, false);
682 preview.setup_labels (file);
687 SoundFileBrowser::freesound_list_view_selected ()
689 if (!reset_options ()) {
690 set_response_sensitive (RESPONSE_OK, false);
694 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
697 TreeIter iter = freesound_list->get_iter(*rows.begin());
698 file = (*iter)[freesound_list_columns.pathname];
699 chooser.set_filename (file);
700 set_response_sensitive (RESPONSE_OK, true);
702 set_response_sensitive (RESPONSE_OK, false);
705 preview.setup_labels (file);
710 SoundFileBrowser::found_search_clicked ()
712 string tag_string = found_entry.get_text ();
716 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
717 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
721 vector<string> results;
722 Library->search_members_and (results, tags);
725 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
726 TreeModel::iterator new_row = found_list->append();
727 TreeModel::Row row = *new_row;
728 string path = Glib::filename_from_uri (string ("file:") + *i);
729 row[found_list_columns.pathname] = path;
734 freesound_search_thread_entry (void* arg)
736 SessionEvent::create_per_thread_pool ("freesound events", 64);
738 static_cast<SoundFileBrowser*>(arg)->freesound_search_thread ();
743 bool searching = false;
744 bool canceling = false;
747 SoundFileBrowser::freesound_search_clicked ()
749 if (canceling) //already canceling, button does nothing
753 freesound_search_btn.set_label(_("Cancelling.."));
757 freesound_search_btn.set_label(_("Cancel"));
758 pthread_t freesound_thr;
759 pthread_create_and_store ("freesound_search", &freesound_thr, freesound_search_thread_entry, this);
764 SoundFileBrowser::freesound_search_thread()
768 THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD
771 freesound_list->clear();
774 path = Glib::get_home_dir();
775 path += "/Freesound/";
776 Mootcher theMootcher(path.c_str());
778 string name_string = freesound_name_entry.get_text ();
779 string pass_string = freesound_pass_entry.get_text ();
780 string search_string = freesound_entry.get_text ();
782 if ( theMootcher.doLogin( name_string, pass_string ) ) {
784 string theString = theMootcher.searchText(search_string);
787 doc.read_buffer( theString );
788 XMLNode *root = doc.root();
790 if (root==NULL) return;
792 if ( strcmp(root->name().c_str(), "freesound") == 0) {
795 XMLNodeList children = root->children();
796 XMLNodeConstIterator niter;
797 for (niter = children.begin(); niter != children.end() && !canceling; ++niter) {
799 if( strcmp( node->name().c_str(), "sample") == 0 ){
800 XMLProperty *prop=node->property ("id");
801 string filename = theMootcher.getFile( prop->value().c_str() );
802 if ( filename != "" ) {
803 TreeModel::iterator new_row = freesound_list->append();
804 TreeModel::Row row = *new_row;
805 string path = Glib::filename_from_uri (string ("file:") + filename);
806 row[freesound_list_columns.pathname] = path;
815 freesound_search_btn.set_label(_("Start Downloading"));
822 SoundFileBrowser::get_paths ()
824 vector<ustring> results;
826 int n = notebook.get_current_page ();
829 vector<ustring> filenames = chooser.get_filenames();
830 vector<ustring>::iterator i;
832 for (i = filenames.begin(); i != filenames.end(); ++i) {
834 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
835 results.push_back (*i);
841 typedef TreeView::Selection::ListHandle_Path ListPath;
843 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
844 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
845 TreeIter iter = found_list->get_iter(*i);
846 ustring str = (*iter)[found_list_columns.pathname];
848 results.push_back (str);
852 typedef TreeView::Selection::ListHandle_Path ListPath;
854 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
855 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
856 TreeIter iter = freesound_list->get_iter(*i);
857 ustring str = (*iter)[freesound_list_columns.pathname];
859 results.push_back (str);
867 SoundFileOmega::reset_options_noret ()
869 if (!resetting_ourselves) {
870 (void) reset_options ();
875 SoundFileOmega::reset_options ()
877 vector<ustring> paths = get_paths ();
881 channel_combo.set_sensitive (false);
882 action_combo.set_sensitive (false);
883 where_combo.set_sensitive (false);
884 copy_files_btn.set_sensitive (false);
890 channel_combo.set_sensitive (true);
891 action_combo.set_sensitive (true);
892 where_combo.set_sensitive (true);
894 /* if we get through this function successfully, this may be
895 reset at the end, once we know if we can use hard links
899 if (Config->get_only_copy_imported_files()) {
900 copy_files_btn.set_sensitive (false);
902 copy_files_btn.set_sensitive (false);
908 bool selection_includes_multichannel;
909 bool selection_can_be_embedded_with_links = check_link_status (*session, paths);
912 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
913 Glib::signal_idle().connect (mem_fun (*this, &SoundFileOmega::bad_file_message));
917 ustring existing_choice;
918 vector<string> action_strings;
920 if (selected_track_cnt > 0) {
921 if (channel_combo.get_active_text().length()) {
922 ImportDisposition id = get_channel_disposition();
925 case Editing::ImportDistinctFiles:
926 if (selected_track_cnt == paths.size()) {
927 action_strings.push_back (importmode2string (ImportToTrack));
931 case Editing::ImportDistinctChannels:
932 /* XXX it would be nice to allow channel-per-selected track
933 but its too hard we don't want to deal with all the
934 different per-file + per-track channel configurations.
939 action_strings.push_back (importmode2string (ImportToTrack));
945 action_strings.push_back (importmode2string (ImportAsTrack));
946 action_strings.push_back (importmode2string (ImportAsRegion));
947 action_strings.push_back (importmode2string (ImportAsTapeTrack));
949 resetting_ourselves = true;
951 existing_choice = action_combo.get_active_text();
953 set_popdown_strings (action_combo, action_strings);
955 /* preserve any existing choice, if possible */
958 if (existing_choice.length()) {
959 vector<string>::iterator x;
960 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
961 if (*x == existing_choice) {
962 action_combo.set_active_text (existing_choice);
966 if (x == action_strings.end()) {
967 action_combo.set_active_text (action_strings.front());
970 action_combo.set_active_text (action_strings.front());
973 resetting_ourselves = false;
975 if ((mode = get_mode()) == ImportAsRegion) {
976 where_combo.set_sensitive (false);
978 where_combo.set_sensitive (true);
981 vector<string> channel_strings;
983 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
984 channel_strings.push_back (_("one track per file"));
986 if (selection_includes_multichannel) {
987 channel_strings.push_back (_("one track per channel"));
990 if (paths.size() > 1) {
991 /* tape tracks are a single region per track, so we cannot
992 sequence multiple files.
994 if (mode != ImportAsTapeTrack) {
995 channel_strings.push_back (_("sequence files"));
998 channel_strings.push_back (_("all files in one region"));
1004 channel_strings.push_back (_("one region per file"));
1006 if (selection_includes_multichannel) {
1007 channel_strings.push_back (_("one region per channel"));
1010 if (paths.size() > 1) {
1012 channel_strings.push_back (_("all files in one region"));
1017 existing_choice = channel_combo.get_active_text();
1019 set_popdown_strings (channel_combo, channel_strings);
1021 /* preserve any existing choice, if possible */
1023 if (existing_choice.length()) {
1024 vector<string>::iterator x;
1025 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1026 if (*x == existing_choice) {
1027 channel_combo.set_active_text (existing_choice);
1031 if (x == channel_strings.end()) {
1032 channel_combo.set_active_text (channel_strings.front());
1035 channel_combo.set_active_text (channel_strings.front());
1039 src_combo.set_sensitive (true);
1041 src_combo.set_sensitive (false);
1044 if (Config->get_only_copy_imported_files()) {
1046 if (selection_can_be_embedded_with_links) {
1047 copy_files_btn.set_sensitive (true);
1049 copy_files_btn.set_sensitive (false);
1054 copy_files_btn.set_sensitive (true);
1062 SoundFileOmega::bad_file_message()
1064 MessageDialog msg (*this,
1065 _("One or more of the selected files\ncannot be used by Ardour"),
1070 resetting_ourselves = true;
1071 chooser.unselect_uri (chooser.get_preview_uri());
1072 resetting_ourselves = false;
1078 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1087 multichannel = false;
1089 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1091 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1092 if (info.channels > 1) {
1093 multichannel = true;
1098 if (sz != info.length) {
1103 if ((nframes_t) info.samplerate != session->frame_rate()) {
1107 } else if (SMFSource::safe_midi_file_extension (*i)) {
1111 if (reader.num_tracks() > 1) {
1112 multichannel = true; // "channel" == track here...
1115 /* XXX we need err = true handling here in case
1116 we can't check the file
1129 SoundFileOmega::check_link_status (const Session& s, const vector<ustring>& paths)
1131 sys::path path = s.session_directory().sound_path() / "linktest";
1132 string tmpdir = path.to_string();
1135 if (mkdir (tmpdir.c_str(), 0744)) {
1136 if (errno != EEXIST) {
1141 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1143 char tmpc[MAXPATHLEN+1];
1145 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1149 if (link ((*i).c_str(), tmpc)) {
1159 rmdir (tmpdir.c_str());
1163 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1164 : SoundFileBrowser (parent, title, s, false)
1166 chooser.set_select_multiple (false);
1167 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1168 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1172 SoundFileChooser::on_hide ()
1174 ArdourDialog::on_hide();
1178 session->cancel_audition();
1183 SoundFileChooser::get_filename ()
1185 vector<ustring> paths;
1187 paths = get_paths ();
1189 if (paths.empty()) {
1193 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1197 return paths.front();
1200 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
1201 Editing::ImportMode mode_hint)
1202 : SoundFileBrowser (parent, title, s, persistent),
1203 copy_files_btn ( _("Copy files to session")),
1204 selected_track_cnt (selected_tracks)
1210 set_size_request (-1, 450);
1212 block_two.set_border_width (12);
1213 block_three.set_border_width (12);
1214 block_four.set_border_width (12);
1216 options.set_spacing (12);
1219 str.push_back (_("file timestamp"));
1220 str.push_back (_("edit point"));
1221 str.push_back (_("playhead"));
1222 str.push_back (_("session start"));
1223 set_popdown_strings (where_combo, str);
1224 where_combo.set_active_text (str.front());
1226 Label* l = manage (new Label);
1227 l->set_text (_("Add files:"));
1229 hbox = manage (new HBox);
1230 hbox->set_border_width (12);
1231 hbox->set_spacing (6);
1232 hbox->pack_start (*l, false, false);
1233 hbox->pack_start (action_combo, false, false);
1234 vbox = manage (new VBox);
1235 vbox->pack_start (*hbox, false, false);
1236 options.pack_start (*vbox, false, false);
1238 /* dummy entry for action combo so that it doesn't look odd if we
1239 come up with no tracks selected.
1243 str.push_back (importmode2string (mode_hint));
1244 set_popdown_strings (action_combo, str);
1245 action_combo.set_active_text (str.front());
1246 action_combo.set_sensitive (false);
1248 l = manage (new Label);
1249 l->set_text (_("Insert at:"));
1251 hbox = manage (new HBox);
1252 hbox->set_border_width (12);
1253 hbox->set_spacing (6);
1254 hbox->pack_start (*l, false, false);
1255 hbox->pack_start (where_combo, false, false);
1256 vbox = manage (new VBox);
1257 vbox->pack_start (*hbox, false, false);
1258 options.pack_start (*vbox, false, false);
1261 l = manage (new Label);
1262 l->set_text (_("Mapping:"));
1264 hbox = manage (new HBox);
1265 hbox->set_border_width (12);
1266 hbox->set_spacing (6);
1267 hbox->pack_start (*l, false, false);
1268 hbox->pack_start (channel_combo, false, false);
1269 vbox = manage (new VBox);
1270 vbox->pack_start (*hbox, false, false);
1271 options.pack_start (*vbox, false, false);
1274 str.push_back (_("one track per file"));
1275 set_popdown_strings (channel_combo, str);
1276 channel_combo.set_active_text (str.front());
1277 channel_combo.set_sensitive (false);
1279 l = manage (new Label);
1280 l->set_text (_("Conversion quality:"));
1282 hbox = manage (new HBox);
1283 hbox->set_border_width (12);
1284 hbox->set_spacing (6);
1285 hbox->pack_start (*l, false, false);
1286 hbox->pack_start (src_combo, false, false);
1287 vbox = manage (new VBox);
1288 vbox->pack_start (*hbox, false, false);
1289 options.pack_start (*vbox, false, false);
1292 str.push_back (_("Best"));
1293 str.push_back (_("Good"));
1294 str.push_back (_("Quick"));
1295 str.push_back (_("Fast"));
1296 str.push_back (_("Fastest"));
1298 set_popdown_strings (src_combo, str);
1299 src_combo.set_active_text (str.front());
1300 src_combo.set_sensitive (false);
1304 action_combo.signal_changed().connect (mem_fun (*this, &SoundFileOmega::reset_options_noret));
1306 copy_files_btn.set_active (true);
1308 block_four.pack_start (copy_files_btn, false, false);
1310 options.pack_start (block_four, false, false);
1312 get_vbox()->pack_start (options, false, false);
1314 /* setup disposition map */
1316 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1317 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1318 disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1319 disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1321 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1322 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1323 disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1325 chooser.signal_selection_changed().connect (mem_fun (*this, &SoundFileOmega::file_selection_changed));
1327 /* set size requests for a couple of combos to allow them to display the longest text
1328 they will ever be asked to display. This prevents them being resized when the user
1329 selects a file to import, which in turn prevents the size of the dialog from jumping
1333 t.push_back (_("one track per file"));
1334 t.push_back (_("one track per channel"));
1335 t.push_back (_("sequence files"));
1336 t.push_back (_("all files in one region"));
1337 set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
1340 t.push_back (importmode2string (ImportAsTrack));
1341 t.push_back (importmode2string (ImportToTrack));
1342 t.push_back (importmode2string (ImportAsRegion));
1343 t.push_back (importmode2string (ImportAsTapeTrack));
1344 set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
1348 SoundFileOmega::set_mode (ImportMode mode)
1350 action_combo.set_active_text (importmode2string (mode));
1354 SoundFileOmega::get_mode () const
1356 return string2importmode (action_combo.get_active_text());
1360 SoundFileOmega::on_hide ()
1362 ArdourDialog::on_hide();
1364 session->cancel_audition();
1369 SoundFileOmega::get_position() const
1371 ustring str = where_combo.get_active_text();
1373 if (str == _("file timestamp")) {
1374 return ImportAtTimestamp;
1375 } else if (str == _("edit point")) {
1376 return ImportAtEditPoint;
1377 } else if (str == _("playhead")) {
1378 return ImportAtPlayhead;
1380 return ImportAtStart;
1385 SoundFileOmega::get_src_quality() const
1387 ustring str = where_combo.get_active_text();
1389 if (str == _("Best")) {
1391 } else if (str == _("Good")) {
1393 } else if (str == _("Quick")) {
1395 } else if (str == _("Fast")) {
1403 SoundFileOmega::get_channel_disposition () const
1405 /* we use a map here because the channel combo can contain different strings
1406 depending on the state of the other combos. the map contains all possible strings
1407 and the ImportDisposition enum that corresponds to it.
1410 ustring str = channel_combo.get_active_text();
1411 DispositionMap::const_iterator x = disposition_map.find (str);
1413 if (x == disposition_map.end()) {
1414 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1422 SoundFileOmega::reset (int selected_tracks)
1424 selected_track_cnt = selected_tracks;
1429 SoundFileOmega::file_selection_changed ()
1431 if (resetting_ourselves) {
1435 if (!reset_options ()) {
1436 set_response_sensitive (RESPONSE_OK, false);
1438 if (chooser.get_filenames().size() > 0) {
1439 set_response_sensitive (RESPONSE_OK, true);
1441 set_response_sensitive (RESPONSE_OK, false);