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.
21 #include "gtk2ardour-config.h"
30 #include <sys/param.h>
32 #include <gtkmm/box.h>
33 #include <gtkmm/stock.h>
34 #include <glibmm/fileutils.h>
36 #include "pbd/convert.h"
37 #include "pbd/tokenizer.h"
38 #include "pbd/enumwriter.h"
39 #include "pbd/pthread_utils.h"
40 #include "pbd/xml++.h"
42 #include <gtkmm2ext/utils.h>
44 #include "evoral/SMF.hpp"
46 #include "ardour/amp.h"
47 #include "ardour/audio_library.h"
48 #include "ardour/auditioner.h"
49 #include "ardour/audioregion.h"
50 #include "ardour/audiofilesource.h"
51 #include "ardour/smf_source.h"
52 #include "ardour/region_factory.h"
53 #include "ardour/source_factory.h"
54 #include "ardour/session.h"
55 #include "ardour/session_directory.h"
56 #include "ardour/profile.h"
58 #include "ardour_ui.h"
60 #include "gui_thread.h"
65 #include "gain_meter.h"
68 #include "sfdb_freesound_mootcher.h"
73 using namespace ARDOUR;
77 using namespace Gtkmm2ext;
78 using namespace Editing;
82 string SoundFileBrowser::persistent_folder;
85 string2importmode (string str)
87 if (str == _("as new tracks")) {
89 } else if (str == _("to selected tracks")) {
91 } else if (str == _("to region list")) {
92 return ImportAsRegion;
93 } else if (str == _("as new tape tracks")) {
94 return ImportAsTapeTrack;
97 warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
103 importmode2string (ImportMode mode)
107 return _("as new tracks");
109 return _("to selected tracks");
111 return _("to region list");
112 case ImportAsTapeTrack:
113 return _("as new tape tracks");
116 return _("as new tracks");
119 SoundFileBox::SoundFileBox (bool persistent)
121 length_clock ("sfboxLengthClock", !persistent, "EditCursorClock", false, false, true, false),
122 timecode_clock ("sfboxTimecodeClock", !persistent, "EditCursorClock", false, false, false, false),
124 autoplay_btn (_("Auto-play"))
127 set_name (X_("SoundFileBox"));
128 set_size_request (300, -1);
130 preview_label.set_markup (_("<b>Sound File Information</b>"));
132 border_frame.set_label_widget (preview_label);
133 border_frame.add (main_box);
135 pack_start (border_frame, true, true);
136 set_border_width (6);
138 main_box.set_border_width (6);
140 length.set_text (_("Length:"));
141 length.set_alignment (1, 0.5);
142 timecode.set_text (_("Timestamp:"));
143 timecode.set_alignment (1, 0.5);
144 format.set_text (_("Format:"));
145 format.set_alignment (1, 0.5);
146 channels.set_text (_("Channels:"));
147 channels.set_alignment (1, 0.5);
148 samplerate.set_text (_("Sample rate:"));
149 samplerate.set_alignment (1, 0.5);
151 preview_label.set_max_width_chars (50);
152 preview_label.set_ellipsize (Pango::ELLIPSIZE_END);
154 format_text.set_max_width_chars (20);
155 format_text.set_ellipsize (Pango::ELLIPSIZE_END);
156 format_text.set_alignment (0, 1);
158 table.set_col_spacings (6);
159 table.set_homogeneous (false);
160 table.set_row_spacings (6);
162 table.attach (channels, 0, 1, 0, 1, FILL, FILL);
163 table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
164 table.attach (format, 0, 1, 2, 4, FILL, FILL);
165 table.attach (length, 0, 1, 4, 5, FILL, FILL);
166 table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
168 table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
169 table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
170 table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
171 table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
172 table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
174 length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock->mode());
175 timecode_clock.set_mode (AudioClock::Timecode);
177 main_box.pack_start (table, false, false);
179 tags_entry.set_editable (true);
180 tags_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
182 Label* label = manage (new Label (_("Tags:")));
183 label->set_alignment (0.0f, 0.5f);
184 main_box.pack_start (*label, false, false);
185 main_box.pack_start (tags_entry, true, true);
187 main_box.pack_start (bottom_box, false, false);
189 play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
190 play_btn.set_label (_("Play"));
192 stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
193 stop_btn.set_label (_("Stop"));
195 bottom_box.set_homogeneous (false);
196 bottom_box.set_spacing (6);
197 bottom_box.pack_start(play_btn, true, true);
198 bottom_box.pack_start(stop_btn, true, true);
199 bottom_box.pack_start(autoplay_btn, false, false);
201 play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
202 stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
204 channels_value.set_alignment (0.0f, 0.5f);
205 samplerate_value.set_alignment (0.0f, 0.5f);
209 SoundFileBox::set_session(Session* s)
211 SessionHandlePtr::set_session (s);
213 length_clock.set_session (s);
214 timecode_clock.set_session (s);
217 play_btn.set_sensitive (false);
218 stop_btn.set_sensitive (false);
223 SoundFileBox::setup_labels (const string& filename)
226 // save existing tags
234 if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
236 preview_label.set_markup (_("<b>Sound File Information</b>"));
237 format_text.set_text ("");
238 channels_value.set_text ("");
239 samplerate_value.set_text ("");
240 tags_entry.get_buffer()->set_text ("");
242 length_clock.set (0);
243 timecode_clock.set (0);
245 tags_entry.set_sensitive (false);
246 play_btn.set_sensitive (false);
251 preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
252 std::string n = sf_info.format_name;
253 if (n.substr (0, 8) == X_("Format: ")) {
256 format_text.set_text (n);
257 channels_value.set_text (to_string (sf_info.channels, std::dec));
259 if (_session && sf_info.samplerate != _session->frame_rate()) {
260 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
261 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
262 samplerate_value.set_name ("NewSessionSR1Label");
263 samplerate.set_name ("NewSessionSR1Label");
265 samplerate.set_text (_("Sample rate:"));
266 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
267 samplerate_value.set_name ("NewSessionSR2Label");
268 samplerate.set_name ("NewSessionSR2Label");
271 framecnt_t const nfr = _session ? _session->nominal_frame_rate() : 25;
272 double src_coef = (double) nfr / sf_info.samplerate;
274 length_clock.set (sf_info.length * src_coef + 0.5, true);
275 timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
277 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
279 vector<string> tags = Library->get_tags (string ("//") + filename);
281 stringstream tag_string;
282 for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
283 if (i != tags.begin()) {
288 tags_entry.get_buffer()->set_text (tag_string.str());
290 tags_entry.set_sensitive (true);
292 play_btn.set_sensitive (true);
299 SoundFileBox::autoplay() const
301 return autoplay_btn.get_active();
305 SoundFileBox::audition_oneshot()
312 SoundFileBox::audition ()
318 if (SMFSource::safe_midi_file_extension (path)) {
319 error << _("Auditioning of MIDI files is not yet supported") << endmsg;
323 _session->cancel_audition();
325 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
326 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
330 boost::shared_ptr<Region> r;
332 boost::shared_ptr<AudioFileSource> afs;
333 bool old_sbp = AudioSource::get_build_peakfiles ();
335 /* don't even think of building peakfiles for these files */
337 AudioSource::set_build_peakfiles (false);
339 for (int n = 0; n < sf_info.channels; ++n) {
341 afs = boost::dynamic_pointer_cast<AudioFileSource> (
342 SourceFactory::createReadable (DataType::AUDIO, *_session,
343 path, n, Source::Flag (0), false));
345 srclist.push_back(afs);
347 } catch (failed_constructor& err) {
348 error << _("Could not access soundfile: ") << path << endmsg;
349 AudioSource::set_build_peakfiles (old_sbp);
354 AudioSource::set_build_peakfiles (old_sbp);
356 if (srclist.empty()) {
360 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
361 string rname = region_name_from_path (afs->path(), false);
365 plist.add (ARDOUR::Properties::start, 0);
366 plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
367 plist.add (ARDOUR::Properties::name, rname);
368 plist.add (ARDOUR::Properties::layer, 0);
370 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
372 _session->audition_region(r);
376 SoundFileBox::stop_audition ()
379 _session->cancel_audition();
384 SoundFileBox::tags_entry_left (GdkEventFocus *)
391 SoundFileBox::tags_changed ()
393 string tag_string = tags_entry.get_buffer()->get_text ();
395 if (tag_string.empty()) {
401 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
402 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
410 SoundFileBox::save_tags (const vector<string>& tags)
412 Library->set_tags (string ("//") + path, tags);
413 Library->save_changes ();
416 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
417 : ArdourDialog (parent, title, false, false),
418 found_list (ListStore::create(found_list_columns)),
419 freesound_list (ListStore::create(freesound_list_columns)),
420 chooser (FILE_CHOOSER_ACTION_OPEN),
421 preview (persistent),
422 found_search_btn (_("Search")),
423 found_list_view (found_list),
424 freesound_search_btn (_("Search")),
425 freesound_list_view (freesound_list)
427 resetting_ourselves = false;
430 resetting_ourselves = false;
434 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
435 chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
436 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
438 chooser.add_shortcut_folder_uri("file:///Volumes");
441 //add the file chooser
443 chooser.set_border_width (12);
445 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
446 audio_filter.set_name (_("Audio files"));
448 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
449 midi_filter.set_name (_("MIDI files"));
451 matchall_filter.add_pattern ("*.*");
452 matchall_filter.set_name (_("All files"));
454 chooser.add_filter (audio_filter);
455 chooser.add_filter (midi_filter);
456 chooser.add_filter (matchall_filter);
457 chooser.set_select_multiple (true);
458 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
459 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
461 /* some broken redraw behaviour - this is a bandaid */
462 chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
465 if (!persistent_folder.empty()) {
466 chooser.set_current_folder (persistent_folder);
468 notebook.append_page (chooser, _("Browse Files"));
471 hpacker.set_spacing (6);
472 hpacker.pack_start (notebook, true, true);
473 hpacker.pack_start (preview, false, false);
475 get_vbox()->pack_start (hpacker, true, true);
483 hbox = manage(new HBox);
484 hbox->pack_start (found_entry);
485 hbox->pack_start (found_search_btn);
487 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
488 scroll->add(found_list_view);
489 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
491 vbox = manage(new VBox);
492 vbox->pack_start (*hbox, PACK_SHRINK);
493 vbox->pack_start (*scroll);
495 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
497 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
499 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
501 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
502 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
504 notebook.append_page (*vbox, _("Search Tags"));
507 //add freesound search
514 passbox = manage(new HBox);
515 passbox->set_border_width (12);
516 passbox->set_spacing (6);
518 label = manage (new Label);
519 label->set_text (_("Tags:"));
520 passbox->pack_start (*label, false, false);
521 passbox->pack_start (freesound_entry, false, false);
523 label = manage (new Label);
524 label->set_text (_("Sort:"));
525 passbox->pack_start (*label, false, false);
526 passbox->pack_start (freesound_sort, false, false);
527 freesound_sort.clear_items();
529 // Order of the following must correspond with enum sortMethod
530 // in sfdb_freesound_mootcher.h
531 freesound_sort.append_text(_("None"));
532 freesound_sort.append_text(_("Longest"));
533 freesound_sort.append_text(_("Shortest"));
534 freesound_sort.append_text(_("Newest"));
535 freesound_sort.append_text(_("Oldest"));
536 freesound_sort.append_text(_("Most downloaded"));
537 freesound_sort.append_text(_("Least downloaded"));
538 freesound_sort.append_text(_("Highest rated"));
539 freesound_sort.append_text(_("Lowest rated"));
540 freesound_sort.set_active(0);
542 label = manage (new Label);
543 label->set_text (_("Page:"));
544 passbox->pack_start (*label, false, false);
545 passbox->pack_start (freesound_page, false, false);
546 freesound_page.set_range(1, 1000);
547 freesound_page.set_increments(1, 10);
549 passbox->pack_start (freesound_search_btn, false, false);
550 passbox->pack_start (progress_bar);
552 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
553 scroll->add(freesound_list_view);
554 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
556 vbox = manage(new VBox);
557 vbox->pack_start (*passbox, PACK_SHRINK);
558 vbox->pack_start (*scroll);
560 freesound_list_view.append_column(_("ID") , freesound_list_columns.id);
561 freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
562 freesound_list_view.append_column(_("URI") , freesound_list_columns.uri);
563 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
565 freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
566 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
567 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
568 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
569 notebook.append_page (*vbox, _("Search Freesound"));
574 notebook.set_size_request (500, -1);
578 add_button (Stock::CANCEL, RESPONSE_CANCEL);
579 add_button (Stock::APPLY, RESPONSE_APPLY);
580 add_button (Stock::OK, RESPONSE_OK);
584 SoundFileBrowser::~SoundFileBrowser ()
586 persistent_folder = chooser.get_current_folder();
591 SoundFileBrowser::on_show ()
593 ArdourDialog::on_show ();
598 SoundFileBrowser::clear_selection ()
600 chooser.unselect_all ();
601 found_list_view.get_selection()->unselect_all ();
605 SoundFileBrowser::chooser_file_activated ()
611 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
617 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
623 SoundFileBrowser::set_session (Session* s)
625 ArdourDialog::set_session (s);
626 preview.set_session (s);
631 remove_gain_meter ();
636 SoundFileBrowser::add_gain_meter ()
640 gm = new GainMeter (_session, 250);
642 boost::shared_ptr<Route> r = _session->the_auditioner ();
644 gm->set_controls (r, r->shared_peak_meter(), r->amp());
646 meter_packer.set_border_width (12);
647 meter_packer.pack_start (*gm, false, true);
648 hpacker.pack_end (meter_packer, false, false);
649 meter_packer.show_all ();
654 SoundFileBrowser::remove_gain_meter ()
657 meter_packer.remove (*gm);
658 hpacker.remove (meter_packer);
665 SoundFileBrowser::start_metering ()
667 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
671 SoundFileBrowser::stop_metering ()
673 metering_connection.disconnect();
677 SoundFileBrowser::meter ()
679 if (is_mapped () && _session && gm) {
680 gm->update_meters ();
685 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
687 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
691 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
693 return SMFSource::safe_midi_file_extension (filter_info.filename);
697 SoundFileBrowser::update_preview ()
699 if (preview.setup_labels (chooser.get_filename())) {
700 if (preview.autoplay()) {
701 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
707 SoundFileBrowser::found_list_view_selected ()
709 if (!reset_options ()) {
710 set_response_sensitive (RESPONSE_OK, false);
714 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
717 TreeIter iter = found_list->get_iter(*rows.begin());
718 file = (*iter)[found_list_columns.pathname];
719 chooser.set_filename (file);
720 set_response_sensitive (RESPONSE_OK, true);
722 set_response_sensitive (RESPONSE_OK, false);
725 preview.setup_labels (file);
730 SoundFileBrowser::freesound_list_view_selected ()
733 if (!reset_options ()) {
734 set_response_sensitive (RESPONSE_OK, false);
738 path = Glib::get_home_dir();
739 path += "/Freesound/";
740 Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser
744 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
747 TreeIter iter = freesound_list->get_iter(*rows.begin());
749 string id = (*iter)[freesound_list_columns.id];
750 string uri = (*iter)[freesound_list_columns.uri];
751 string ofn = (*iter)[freesound_list_columns.filename];
753 // download the sound file
754 GdkCursor *prev_cursor;
755 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
756 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
759 file = theMootcher.getAudioFile(ofn, id, uri, &progress_bar);
761 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
763 chooser.set_filename (file);
764 set_response_sensitive (RESPONSE_OK, true);
766 set_response_sensitive (RESPONSE_OK, false);
769 preview.setup_labels (file);
775 SoundFileBrowser::found_search_clicked ()
777 string tag_string = found_entry.get_text ();
781 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
782 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
786 vector<string> results;
787 Library->search_members_and (results, tags);
790 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
791 TreeModel::iterator new_row = found_list->append();
792 TreeModel::Row row = *new_row;
793 string path = Glib::filename_from_uri (string ("file:") + *i);
794 row[found_list_columns.pathname] = path;
799 SoundFileBrowser::freesound_search_clicked ()
806 SoundFileBrowser::freesound_search()
809 freesound_list->clear();
812 path = Glib::get_home_dir();
813 path += "/Freesound/";
814 Mootcher theMootcher(path.c_str());
816 string search_string = freesound_entry.get_text ();
817 enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
818 int page = freesound_page.get_value_as_int();
820 GdkCursor *prev_cursor;
821 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
822 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
825 string theString = theMootcher.searchText(
828 "", // filter, could do, e.g. "type:wav"
832 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
835 doc.read_buffer( theString );
836 XMLNode *root = doc.root();
839 cerr << "no root XML node!" << endl;
843 if ( strcmp(root->name().c_str(), "response") != 0) {
844 cerr << "root node name == " << root->name() << ", != \"response\"!" << endl;
848 XMLNode *sounds_root = root->child("sounds");
851 cerr << "no child node \"sounds\" found!" << endl;
855 XMLNodeList sounds = sounds_root->children();
856 XMLNodeConstIterator niter;
858 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
860 if( strcmp( node->name().c_str(), "resource") != 0 ){
861 cerr << "node->name()=" << node->name() << ",!= \"resource\"!" << endl;
865 // node->dump(cerr, "node:");
867 XMLNode *id_node = node->child ("id");
868 XMLNode *uri_node = node->child ("serve");
869 XMLNode *ofn_node = node->child ("original_filename");
871 if (id_node && uri_node && ofn_node) {
873 std::string id = id_node->child("text")->content();
874 std::string uri = uri_node->child("text")->content();
875 std::string ofn = ofn_node->child("text")->content();
878 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << endl;
880 TreeModel::iterator new_row = freesound_list->append();
881 TreeModel::Row row = *new_row;
883 row[freesound_list_columns.id ] = id;
884 row[freesound_list_columns.uri ] = uri;
885 row[freesound_list_columns.filename] = ofn;
893 SoundFileBrowser::get_paths ()
895 vector<string> results;
897 int n = notebook.get_current_page ();
900 vector<string> filenames = chooser.get_filenames();
901 vector<string>::iterator i;
903 for (i = filenames.begin(); i != filenames.end(); ++i) {
905 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
906 results.push_back (*i);
912 typedef TreeView::Selection::ListHandle_Path ListPath;
914 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
915 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
916 TreeIter iter = found_list->get_iter(*i);
917 string str = (*iter)[found_list_columns.pathname];
919 results.push_back (str);
923 typedef TreeView::Selection::ListHandle_Path ListPath;
926 path = Glib::get_home_dir();
927 path += "/Freesound/";
928 Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser
931 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
932 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
933 TreeIter iter = freesound_list->get_iter(*i);
934 string id = (*iter)[freesound_list_columns.id];
935 string uri = (*iter)[freesound_list_columns.uri];
936 string ofn = (*iter)[freesound_list_columns.filename];
938 GdkCursor *prev_cursor;
939 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
940 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
943 string str = theMootcher.getAudioFile(ofn, id, uri, &progress_bar);
944 results.push_back (str);
946 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
956 SoundFileOmega::reset_options_noret ()
958 if (!resetting_ourselves) {
959 (void) reset_options ();
964 SoundFileOmega::reset_options ()
966 vector<string> paths = get_paths ();
970 channel_combo.set_sensitive (false);
971 action_combo.set_sensitive (false);
972 where_combo.set_sensitive (false);
973 copy_files_btn.set_sensitive (false);
979 channel_combo.set_sensitive (true);
980 action_combo.set_sensitive (true);
981 where_combo.set_sensitive (true);
983 /* if we get through this function successfully, this may be
984 reset at the end, once we know if we can use hard links
988 if (Config->get_only_copy_imported_files()) {
989 copy_files_btn.set_sensitive (false);
991 copy_files_btn.set_sensitive (false);
997 bool selection_includes_multichannel;
998 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1001 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1002 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1006 string existing_choice;
1007 vector<string> action_strings;
1009 if (chooser.get_filter() == &audio_filter) {
1013 if (selected_audio_track_cnt > 0) {
1014 if (channel_combo.get_active_text().length()) {
1015 ImportDisposition id = get_channel_disposition();
1018 case Editing::ImportDistinctFiles:
1019 if (selected_audio_track_cnt == paths.size()) {
1020 action_strings.push_back (importmode2string (ImportToTrack));
1024 case Editing::ImportDistinctChannels:
1025 /* XXX it would be nice to allow channel-per-selected track
1026 but its too hard we don't want to deal with all the
1027 different per-file + per-track channel configurations.
1032 action_strings.push_back (importmode2string (ImportToTrack));
1042 if (selected_midi_track_cnt > 0) {
1043 action_strings.push_back (importmode2string (ImportToTrack));
1047 action_strings.push_back (importmode2string (ImportAsTrack));
1048 action_strings.push_back (importmode2string (ImportAsRegion));
1049 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1051 resetting_ourselves = true;
1053 existing_choice = action_combo.get_active_text();
1055 set_popdown_strings (action_combo, action_strings);
1057 /* preserve any existing choice, if possible */
1060 if (existing_choice.length()) {
1061 vector<string>::iterator x;
1062 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1063 if (*x == existing_choice) {
1064 action_combo.set_active_text (existing_choice);
1068 if (x == action_strings.end()) {
1069 action_combo.set_active_text (action_strings.front());
1072 action_combo.set_active_text (action_strings.front());
1075 resetting_ourselves = false;
1077 if ((mode = get_mode()) == ImportAsRegion) {
1078 where_combo.set_sensitive (false);
1080 where_combo.set_sensitive (true);
1083 vector<string> channel_strings;
1085 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1086 channel_strings.push_back (_("one track per file"));
1088 if (selection_includes_multichannel) {
1089 channel_strings.push_back (_("one track per channel"));
1092 if (paths.size() > 1) {
1093 /* tape tracks are a single region per track, so we cannot
1094 sequence multiple files.
1096 if (mode != ImportAsTapeTrack) {
1097 channel_strings.push_back (_("sequence files"));
1100 channel_strings.push_back (_("all files in one track"));
1101 channel_strings.push_back (_("merge files"));
1107 channel_strings.push_back (_("one region per file"));
1109 if (selection_includes_multichannel) {
1110 channel_strings.push_back (_("one region per channel"));
1113 if (paths.size() > 1) {
1115 channel_strings.push_back (_("all files in one region"));
1120 resetting_ourselves = true;
1122 existing_choice = channel_combo.get_active_text();
1124 set_popdown_strings (channel_combo, channel_strings);
1126 /* preserve any existing choice, if possible */
1128 if (existing_choice.length()) {
1129 vector<string>::iterator x;
1130 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1131 if (*x == existing_choice) {
1132 channel_combo.set_active_text (existing_choice);
1136 if (x == channel_strings.end()) {
1137 channel_combo.set_active_text (channel_strings.front());
1140 channel_combo.set_active_text (channel_strings.front());
1143 resetting_ourselves = false;
1146 src_combo.set_sensitive (true);
1148 src_combo.set_sensitive (false);
1151 if (Config->get_only_copy_imported_files()) {
1153 if (selection_can_be_embedded_with_links) {
1154 copy_files_btn.set_sensitive (true);
1156 copy_files_btn.set_sensitive (false);
1161 copy_files_btn.set_sensitive (true);
1169 SoundFileOmega::bad_file_message()
1171 MessageDialog msg (*this,
1172 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1177 resetting_ourselves = true;
1178 chooser.unselect_uri (chooser.get_preview_uri());
1179 resetting_ourselves = false;
1185 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1194 multichannel = false;
1196 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1198 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1199 if (info.channels > 1) {
1200 multichannel = true;
1205 if (sz != info.length) {
1210 if (info.samplerate != _session->frame_rate()) {
1214 } else if (SMFSource::safe_midi_file_extension (*i)) {
1218 if (reader.num_tracks() > 1) {
1219 multichannel = true; // "channel" == track here...
1222 /* XXX we need err = true handling here in case
1223 we can't check the file
1236 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1238 sys::path path = s->session_directory().sound_path() / "linktest";
1239 string tmpdir = path.to_string();
1242 if (mkdir (tmpdir.c_str(), 0744)) {
1243 if (errno != EEXIST) {
1248 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1250 char tmpc[MAXPATHLEN+1];
1252 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1256 if (link ((*i).c_str(), tmpc)) {
1266 rmdir (tmpdir.c_str());
1270 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1271 : SoundFileBrowser (parent, title, s, false)
1273 chooser.set_select_multiple (false);
1274 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1275 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1279 SoundFileChooser::on_hide ()
1281 ArdourDialog::on_hide();
1285 _session->cancel_audition();
1290 SoundFileChooser::get_filename ()
1292 vector<string> paths;
1294 paths = get_paths ();
1296 if (paths.empty()) {
1300 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1304 return paths.front();
1307 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s,
1308 uint32_t selected_audio_tracks,
1309 uint32_t selected_midi_tracks,
1311 Editing::ImportMode mode_hint)
1312 : SoundFileBrowser (parent, title, s, persistent)
1313 , copy_files_btn ( _("Copy files to session"))
1314 , selected_audio_track_cnt (selected_audio_tracks)
1315 , selected_midi_track_cnt (selected_midi_tracks)
1321 set_size_request (-1, 450);
1323 block_two.set_border_width (12);
1324 block_three.set_border_width (12);
1325 block_four.set_border_width (12);
1327 options.set_spacing (12);
1330 str.push_back (_("file timestamp"));
1331 str.push_back (_("edit point"));
1332 str.push_back (_("playhead"));
1333 str.push_back (_("session start"));
1334 set_popdown_strings (where_combo, str);
1335 where_combo.set_active_text (str.front());
1337 Label* l = manage (new Label);
1338 l->set_text (_("Add files:"));
1340 hbox = manage (new HBox);
1341 hbox->set_border_width (12);
1342 hbox->set_spacing (6);
1343 hbox->pack_start (*l, false, false);
1344 hbox->pack_start (action_combo, false, false);
1345 vbox = manage (new VBox);
1346 vbox->pack_start (*hbox, false, false);
1347 options.pack_start (*vbox, false, false);
1349 /* dummy entry for action combo so that it doesn't look odd if we
1350 come up with no tracks selected.
1354 str.push_back (importmode2string (mode_hint));
1355 set_popdown_strings (action_combo, str);
1356 action_combo.set_active_text (str.front());
1357 action_combo.set_sensitive (false);
1359 l = manage (new Label);
1360 l->set_text (_("Insert at:"));
1362 hbox = manage (new HBox);
1363 hbox->set_border_width (12);
1364 hbox->set_spacing (6);
1365 hbox->pack_start (*l, false, false);
1366 hbox->pack_start (where_combo, false, false);
1367 vbox = manage (new VBox);
1368 vbox->pack_start (*hbox, false, false);
1369 options.pack_start (*vbox, false, false);
1372 l = manage (new Label);
1373 l->set_text (_("Mapping:"));
1375 hbox = manage (new HBox);
1376 hbox->set_border_width (12);
1377 hbox->set_spacing (6);
1378 hbox->pack_start (*l, false, false);
1379 hbox->pack_start (channel_combo, false, false);
1380 vbox = manage (new VBox);
1381 vbox->pack_start (*hbox, false, false);
1382 options.pack_start (*vbox, false, false);
1385 str.push_back (_("one track per file"));
1386 set_popdown_strings (channel_combo, str);
1387 channel_combo.set_active_text (str.front());
1388 channel_combo.set_sensitive (false);
1390 l = manage (new Label);
1391 l->set_text (_("Conversion quality:"));
1393 hbox = manage (new HBox);
1394 hbox->set_border_width (12);
1395 hbox->set_spacing (6);
1396 hbox->pack_start (*l, false, false);
1397 hbox->pack_start (src_combo, false, false);
1398 vbox = manage (new VBox);
1399 vbox->pack_start (*hbox, false, false);
1400 options.pack_start (*vbox, false, false);
1403 str.push_back (_("Best"));
1404 str.push_back (_("Good"));
1405 str.push_back (_("Quick"));
1406 str.push_back (_("Fast"));
1407 str.push_back (_("Fastest"));
1409 set_popdown_strings (src_combo, str);
1410 src_combo.set_active_text (str.front());
1411 src_combo.set_sensitive (false);
1415 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1416 channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1418 copy_files_btn.set_active (true);
1420 block_four.pack_start (copy_files_btn, false, false);
1422 options.pack_start (block_four, false, false);
1424 get_vbox()->pack_start (options, false, false);
1426 /* setup disposition map */
1428 disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1429 disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1430 disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1431 disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1433 disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1434 disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1435 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1436 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1438 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1440 /* set size requests for a couple of combos to allow them to display the longest text
1441 they will ever be asked to display. This prevents them being resized when the user
1442 selects a file to import, which in turn prevents the size of the dialog from jumping
1446 t.push_back (_("one track per file"));
1447 t.push_back (_("one track per channel"));
1448 t.push_back (_("sequence files"));
1449 t.push_back (_("all files in one region"));
1450 set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
1453 t.push_back (importmode2string (ImportAsTrack));
1454 t.push_back (importmode2string (ImportToTrack));
1455 t.push_back (importmode2string (ImportAsRegion));
1456 t.push_back (importmode2string (ImportAsTapeTrack));
1457 set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
1461 SoundFileOmega::set_mode (ImportMode mode)
1463 action_combo.set_active_text (importmode2string (mode));
1467 SoundFileOmega::get_mode () const
1469 return string2importmode (action_combo.get_active_text());
1473 SoundFileOmega::on_hide ()
1475 ArdourDialog::on_hide();
1477 _session->cancel_audition();
1482 SoundFileOmega::get_position() const
1484 string str = where_combo.get_active_text();
1486 if (str == _("file timestamp")) {
1487 return ImportAtTimestamp;
1488 } else if (str == _("edit point")) {
1489 return ImportAtEditPoint;
1490 } else if (str == _("playhead")) {
1491 return ImportAtPlayhead;
1493 return ImportAtStart;
1498 SoundFileOmega::get_src_quality() const
1500 string str = where_combo.get_active_text();
1502 if (str == _("Best")) {
1504 } else if (str == _("Good")) {
1506 } else if (str == _("Quick")) {
1508 } else if (str == _("Fast")) {
1516 SoundFileOmega::get_channel_disposition () const
1518 /* we use a map here because the channel combo can contain different strings
1519 depending on the state of the other combos. the map contains all possible strings
1520 and the ImportDisposition enum that corresponds to it.
1523 string str = channel_combo.get_active_text();
1524 DispositionMap::const_iterator x = disposition_map.find (str);
1526 if (x == disposition_map.end()) {
1527 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1535 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1537 selected_audio_track_cnt = selected_audio_tracks;
1538 selected_midi_track_cnt = selected_midi_tracks;
1543 SoundFileOmega::file_selection_changed ()
1545 if (resetting_ourselves) {
1549 if (!reset_options ()) {
1550 set_response_sensitive (RESPONSE_OK, false);
1552 if (chooser.get_filenames().size() > 0) {
1553 set_response_sensitive (RESPONSE_OK, true);
1555 set_response_sensitive (RESPONSE_OK, false);