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/audio_library.h"
47 #include "ardour/auditioner.h"
48 #include "ardour/audioregion.h"
49 #include "ardour/audiofilesource.h"
50 #include "ardour/smf_source.h"
51 #include "ardour/region_factory.h"
52 #include "ardour/source_factory.h"
53 #include "ardour/session.h"
54 #include "ardour/session_directory.h"
56 #include "ardour_ui.h"
58 #include "gui_thread.h"
63 #include "gain_meter.h"
64 #include "main_clock.h"
67 #include "sfdb_freesound_mootcher.h"
72 using namespace ARDOUR;
76 using namespace Gtkmm2ext;
77 using namespace Editing;
81 string SoundFileBrowser::persistent_folder;
84 string2importmode (string str)
86 if (str == _("as new tracks")) {
88 } else if (str == _("to selected tracks")) {
90 } else if (str == _("to region list")) {
91 return ImportAsRegion;
92 } else if (str == _("as new tape tracks")) {
93 return ImportAsTapeTrack;
96 warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
102 importmode2string (ImportMode mode)
106 return _("as new tracks");
108 return _("to selected tracks");
110 return _("to region list");
111 case ImportAsTapeTrack:
112 return _("as new tape tracks");
115 return _("as new tracks");
118 SoundFileBox::SoundFileBox (bool persistent)
120 length_clock ("sfboxLengthClock", !persistent, "", false, false, true, false),
121 timecode_clock ("sfboxTimecodeClock", !persistent, "", false, false, false, false),
123 autoplay_btn (_("Auto-play"))
126 set_name (X_("SoundFileBox"));
127 set_size_request (300, -1);
129 preview_label.set_markup (_("<b>Sound File Information</b>"));
131 border_frame.set_label_widget (preview_label);
132 border_frame.add (main_box);
134 pack_start (border_frame, true, true);
135 set_border_width (6);
137 main_box.set_border_width (6);
139 length.set_text (_("Length:"));
140 length.set_alignment (1, 0.5);
141 timecode.set_text (_("Timestamp:"));
142 timecode.set_alignment (1, 0.5);
143 format.set_text (_("Format:"));
144 format.set_alignment (1, 0.5);
145 channels.set_text (_("Channels:"));
146 channels.set_alignment (1, 0.5);
147 samplerate.set_text (_("Sample rate:"));
148 samplerate.set_alignment (1, 0.5);
150 preview_label.set_max_width_chars (50);
151 preview_label.set_ellipsize (Pango::ELLIPSIZE_END);
153 format_text.set_max_width_chars (20);
154 format_text.set_ellipsize (Pango::ELLIPSIZE_END);
155 format_text.set_alignment (0, 1);
157 table.set_col_spacings (6);
158 table.set_homogeneous (false);
159 table.set_row_spacings (6);
161 table.attach (channels, 0, 1, 0, 1, FILL, FILL);
162 table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
163 table.attach (format, 0, 1, 2, 4, FILL, FILL);
164 table.attach (length, 0, 1, 4, 5, FILL, FILL);
165 table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
167 table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
168 table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
169 table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
170 table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
171 table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
173 length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock->mode());
174 timecode_clock.set_mode (AudioClock::Timecode);
176 main_box.pack_start (table, false, false);
178 tags_entry.set_editable (true);
179 tags_entry.set_wrap_mode(Gtk::WRAP_WORD);
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");
442 mootcher = new Mootcher();
445 //add the file chooser
447 chooser.set_border_width (12);
449 audio_and_midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun (*this, &SoundFileBrowser::on_audio_and_midi_filter));
450 audio_and_midi_filter.set_name (_("Audio and MIDI files"));
452 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
453 audio_filter.set_name (_("Audio files"));
455 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
456 midi_filter.set_name (_("MIDI files"));
458 matchall_filter.add_pattern ("*.*");
459 matchall_filter.set_name (_("All files"));
461 chooser.add_filter (audio_and_midi_filter);
462 chooser.add_filter (audio_filter);
463 chooser.add_filter (midi_filter);
464 chooser.add_filter (matchall_filter);
465 chooser.set_select_multiple (true);
466 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
467 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
469 /* some broken redraw behaviour - this is a bandaid */
470 chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
473 if (!persistent_folder.empty()) {
474 chooser.set_current_folder (persistent_folder);
476 notebook.append_page (chooser, _("Browse Files"));
479 hpacker.set_spacing (6);
480 hpacker.pack_start (notebook, true, true);
481 hpacker.pack_start (preview, false, false);
483 get_vbox()->pack_start (hpacker, true, true);
491 hbox = manage(new HBox);
492 hbox->pack_start (found_entry);
493 hbox->pack_start (found_search_btn);
495 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
496 scroll->add(found_list_view);
497 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
499 vbox = manage(new VBox);
500 vbox->pack_start (*hbox, PACK_SHRINK);
501 vbox->pack_start (*scroll);
503 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
505 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
507 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
509 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
510 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
512 freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
514 notebook.append_page (*vbox, _("Search Tags"));
517 //add freesound search
524 passbox = manage(new HBox);
525 passbox->set_border_width (12);
526 passbox->set_spacing (6);
528 label = manage (new Label);
529 label->set_text (_("Tags:"));
530 passbox->pack_start (*label, false, false);
531 passbox->pack_start (freesound_entry, false, false);
533 label = manage (new Label);
534 label->set_text (_("Sort:"));
535 passbox->pack_start (*label, false, false);
536 passbox->pack_start (freesound_sort, false, false);
537 freesound_sort.clear_items();
539 // Order of the following must correspond with enum sortMethod
540 // in sfdb_freesound_mootcher.h
541 freesound_sort.append_text(_("None"));
542 freesound_sort.append_text(_("Longest"));
543 freesound_sort.append_text(_("Shortest"));
544 freesound_sort.append_text(_("Newest"));
545 freesound_sort.append_text(_("Oldest"));
546 freesound_sort.append_text(_("Most downloaded"));
547 freesound_sort.append_text(_("Least downloaded"));
548 freesound_sort.append_text(_("Highest rated"));
549 freesound_sort.append_text(_("Lowest rated"));
550 freesound_sort.set_active(0);
552 passbox->pack_start (freesound_search_btn, false, false);
553 passbox->pack_start (freesound_progress_bar);
554 passbox->pack_end (freesound_stop_btn, false, false);
555 freesound_stop_btn.set_label(_("Stop"));
557 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
558 scroll->add(freesound_list_view);
559 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
561 vbox = manage(new VBox);
562 vbox->pack_start (*passbox, PACK_SHRINK);
563 vbox->pack_start (*scroll);
565 freesound_list_view.append_column(_("ID") , freesound_list_columns.id);
566 freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
567 // freesound_list_view.append_column(_("URI") , freesound_list_columns.uri);
568 freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
569 freesound_list_view.get_column(1)->set_expand(true);
571 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
573 freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
574 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
575 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
576 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
577 freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
578 notebook.append_page (*vbox, _("Search Freesound"));
584 notebook.set_size_request (500, -1);
588 add_button (Stock::CANCEL, RESPONSE_CANCEL);
589 add_button (Stock::APPLY, RESPONSE_APPLY);
590 add_button (Stock::OK, RESPONSE_OK);
594 SoundFileBrowser::~SoundFileBrowser ()
596 persistent_folder = chooser.get_current_folder();
601 SoundFileBrowser::on_show ()
603 ArdourDialog::on_show ();
608 SoundFileBrowser::clear_selection ()
610 chooser.unselect_all ();
611 found_list_view.get_selection()->unselect_all ();
615 SoundFileBrowser::chooser_file_activated ()
621 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
627 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
633 SoundFileBrowser::set_session (Session* s)
635 ArdourDialog::set_session (s);
636 preview.set_session (s);
641 remove_gain_meter ();
646 SoundFileBrowser::add_gain_meter ()
650 gm = new GainMeter (_session, 250);
652 boost::shared_ptr<Route> r = _session->the_auditioner ();
654 gm->set_controls (r, r->shared_peak_meter(), r->amp());
656 meter_packer.set_border_width (12);
657 meter_packer.pack_start (*gm, false, true);
658 hpacker.pack_end (meter_packer, false, false);
659 meter_packer.show_all ();
664 SoundFileBrowser::remove_gain_meter ()
667 meter_packer.remove (*gm);
668 hpacker.remove (meter_packer);
675 SoundFileBrowser::start_metering ()
677 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
681 SoundFileBrowser::stop_metering ()
683 metering_connection.disconnect();
687 SoundFileBrowser::meter ()
689 if (is_mapped () && _session && gm) {
690 gm->update_meters ();
695 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
697 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
701 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
703 return SMFSource::safe_midi_file_extension (filter_info.filename);
707 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
709 return on_audio_filter (filter_info) || on_midi_filter (filter_info);
713 SoundFileBrowser::update_preview ()
715 if (preview.setup_labels (chooser.get_preview_filename())) {
716 if (preview.autoplay()) {
717 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
723 SoundFileBrowser::found_list_view_selected ()
725 if (!reset_options ()) {
726 set_response_sensitive (RESPONSE_OK, false);
730 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
733 TreeIter iter = found_list->get_iter(*rows.begin());
734 file = (*iter)[found_list_columns.pathname];
735 chooser.set_filename (file);
736 set_response_sensitive (RESPONSE_OK, true);
738 set_response_sensitive (RESPONSE_OK, false);
741 preview.setup_labels (file);
746 SoundFileBrowser::freesound_list_view_selected ()
748 freesound_download_cancel = false;
751 if (!reset_options ()) {
752 set_response_sensitive (RESPONSE_OK, false);
757 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
760 TreeIter iter = freesound_list->get_iter(*rows.begin());
762 string id = (*iter)[freesound_list_columns.id];
763 string uri = (*iter)[freesound_list_columns.uri];
764 string ofn = (*iter)[freesound_list_columns.filename];
766 // download the sound file
767 GdkCursor *prev_cursor;
768 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
769 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
772 file = mootcher->getAudioFile(ofn, id, uri, this);
774 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
777 chooser.set_filename (file);
778 set_response_sensitive (RESPONSE_OK, true);
781 set_response_sensitive (RESPONSE_OK, false);
784 preview.setup_labels (file);
790 SoundFileBrowser::found_search_clicked ()
792 string tag_string = found_entry.get_text ();
796 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
797 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
801 vector<string> results;
802 Library->search_members_and (results, tags);
805 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
806 TreeModel::iterator new_row = found_list->append();
807 TreeModel::Row row = *new_row;
808 string path = Glib::filename_from_uri (string ("file:") + *i);
809 row[found_list_columns.pathname] = path;
814 SoundFileBrowser::freesound_search_clicked ()
816 freesound_search_cancel = false;
821 SoundFileBrowser::freesound_stop_clicked ()
823 freesound_download_cancel = true;
824 freesound_search_cancel = true;
829 SoundFileBrowser::freesound_search()
832 freesound_list->clear();
834 string search_string = freesound_entry.get_text ();
835 enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
837 GdkCursor *prev_cursor;
838 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
839 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
841 for (int page = 1; page <= 99; page++ ) {
844 prog = string_compose (_("Page %1, [Stop]->"), page);
845 freesound_progress_bar.set_text(prog);
846 while (Glib::MainContext::get_default()->iteration (false)) {
850 std::string theString = mootcher->searchText(
853 "", // filter, could do, e.g. "type:wav"
858 doc.read_buffer( theString );
859 XMLNode *root = doc.root();
862 cerr << "no root XML node!" << endl;
866 if ( strcmp(root->name().c_str(), "response") != 0) {
867 cerr << "root node name == " << root->name() << ", != \"response\"!" << endl;
871 XMLNode *sounds_root = root->child("sounds");
874 cerr << "no child node \"sounds\" found!" << endl;
878 XMLNodeList sounds = sounds_root->children();
879 XMLNodeConstIterator niter;
881 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
883 if( strcmp( node->name().c_str(), "resource") != 0 ){
884 cerr << "node->name()=" << node->name() << ",!= \"resource\"!" << endl;
885 freesound_search_cancel = true;
889 // node->dump(cerr, "node:");
891 XMLNode *id_node = node->child ("id");
892 XMLNode *uri_node = node->child ("serve");
893 XMLNode *ofn_node = node->child ("original_filename");
894 XMLNode *dur_node = node->child ("duration");
896 if (id_node && uri_node && ofn_node && dur_node) {
898 std::string id = id_node->child("text")->content();
899 std::string uri = uri_node->child("text")->content();
900 std::string ofn = ofn_node->child("text")->content();
901 std::string dur = dur_node->child("text")->content();
904 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
906 double duration_seconds = atof(dur.c_str());
908 char duration_hhmmss[16];
909 if (duration_seconds >= 99 * 60 * 60) {
910 strcpy(duration_hhmmss, ">99h");
912 s = modf(duration_seconds/60, &m) * 60;
913 m = modf(m/60, &h) * 60;
914 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
919 TreeModel::iterator new_row = freesound_list->append();
920 TreeModel::Row row = *new_row;
922 row[freesound_list_columns.id ] = id;
923 row[freesound_list_columns.uri ] = uri;
924 row[freesound_list_columns.filename] = ofn;
925 row[freesound_list_columns.duration] = duration_hhmmss;
930 if (freesound_search_cancel)
935 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
937 freesound_progress_bar.set_text("");
943 SoundFileBrowser::get_paths ()
945 vector<string> results;
947 int n = notebook.get_current_page ();
950 vector<string> filenames = chooser.get_filenames();
951 vector<string>::iterator i;
953 for (i = filenames.begin(); i != filenames.end(); ++i) {
955 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
956 results.push_back (*i);
962 typedef TreeView::Selection::ListHandle_Path ListPath;
964 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
965 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
966 TreeIter iter = found_list->get_iter(*i);
967 string str = (*iter)[found_list_columns.pathname];
969 results.push_back (str);
973 typedef TreeView::Selection::ListHandle_Path ListPath;
975 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
976 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
977 TreeIter iter = freesound_list->get_iter(*i);
978 string id = (*iter)[freesound_list_columns.id];
979 string uri = (*iter)[freesound_list_columns.uri];
980 string ofn = (*iter)[freesound_list_columns.filename];
982 GdkCursor *prev_cursor;
983 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
984 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
987 string str = mootcher->getAudioFile(ofn, id, uri, this);
989 results.push_back (str);
992 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1002 SoundFileOmega::reset_options_noret ()
1004 if (!resetting_ourselves) {
1005 (void) reset_options ();
1010 SoundFileOmega::reset_options ()
1012 vector<string> paths = get_paths ();
1014 if (paths.empty()) {
1016 channel_combo.set_sensitive (false);
1017 action_combo.set_sensitive (false);
1018 where_combo.set_sensitive (false);
1019 copy_files_btn.set_sensitive (false);
1025 channel_combo.set_sensitive (true);
1026 action_combo.set_sensitive (true);
1027 where_combo.set_sensitive (true);
1029 /* if we get through this function successfully, this may be
1030 reset at the end, once we know if we can use hard links
1034 if (Config->get_only_copy_imported_files()) {
1035 copy_files_btn.set_sensitive (false);
1037 copy_files_btn.set_sensitive (false);
1043 bool selection_includes_multichannel;
1044 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1047 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1048 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1052 string existing_choice;
1053 vector<string> action_strings;
1055 resetting_ourselves = true;
1057 if (chooser.get_filter() == &audio_filter) {
1061 if (selected_audio_track_cnt > 0) {
1062 if (channel_combo.get_active_text().length()) {
1063 ImportDisposition id = get_channel_disposition();
1066 case Editing::ImportDistinctFiles:
1067 if (selected_audio_track_cnt == paths.size()) {
1068 action_strings.push_back (importmode2string (ImportToTrack));
1072 case Editing::ImportDistinctChannels:
1073 /* XXX it would be nice to allow channel-per-selected track
1074 but its too hard we don't want to deal with all the
1075 different per-file + per-track channel configurations.
1080 action_strings.push_back (importmode2string (ImportToTrack));
1090 if (selected_midi_track_cnt > 0) {
1091 action_strings.push_back (importmode2string (ImportToTrack));
1095 action_strings.push_back (importmode2string (ImportAsTrack));
1096 action_strings.push_back (importmode2string (ImportAsRegion));
1097 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1099 existing_choice = action_combo.get_active_text();
1101 set_popdown_strings (action_combo, action_strings);
1103 /* preserve any existing choice, if possible */
1106 if (existing_choice.length()) {
1107 vector<string>::iterator x;
1108 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1109 if (*x == existing_choice) {
1110 action_combo.set_active_text (existing_choice);
1114 if (x == action_strings.end()) {
1115 action_combo.set_active_text (action_strings.front());
1118 action_combo.set_active_text (action_strings.front());
1121 resetting_ourselves = false;
1123 if ((mode = get_mode()) == ImportAsRegion) {
1124 where_combo.set_sensitive (false);
1126 where_combo.set_sensitive (true);
1129 vector<string> channel_strings;
1131 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1132 channel_strings.push_back (_("one track per file"));
1134 if (selection_includes_multichannel) {
1135 channel_strings.push_back (_("one track per channel"));
1138 if (paths.size() > 1) {
1139 /* tape tracks are a single region per track, so we cannot
1140 sequence multiple files.
1142 if (mode != ImportAsTapeTrack) {
1143 channel_strings.push_back (_("sequence files"));
1146 channel_strings.push_back (_("all files in one track"));
1147 channel_strings.push_back (_("merge files"));
1153 channel_strings.push_back (_("one region per file"));
1155 if (selection_includes_multichannel) {
1156 channel_strings.push_back (_("one region per channel"));
1159 if (paths.size() > 1) {
1161 channel_strings.push_back (_("all files in one region"));
1166 resetting_ourselves = true;
1168 existing_choice = channel_combo.get_active_text();
1170 set_popdown_strings (channel_combo, channel_strings);
1172 /* preserve any existing choice, if possible */
1174 if (existing_choice.length()) {
1175 vector<string>::iterator x;
1176 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1177 if (*x == existing_choice) {
1178 channel_combo.set_active_text (existing_choice);
1182 if (x == channel_strings.end()) {
1183 channel_combo.set_active_text (channel_strings.front());
1186 channel_combo.set_active_text (channel_strings.front());
1189 resetting_ourselves = false;
1192 src_combo.set_sensitive (true);
1194 src_combo.set_sensitive (false);
1197 if (Config->get_only_copy_imported_files()) {
1199 if (selection_can_be_embedded_with_links) {
1200 copy_files_btn.set_sensitive (true);
1202 copy_files_btn.set_sensitive (false);
1207 copy_files_btn.set_sensitive (true);
1215 SoundFileOmega::bad_file_message()
1217 MessageDialog msg (*this,
1218 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1223 resetting_ourselves = true;
1224 chooser.unselect_uri (chooser.get_preview_uri());
1225 resetting_ourselves = false;
1231 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1240 multichannel = false;
1242 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1244 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1245 if (info.channels > 1) {
1246 multichannel = true;
1251 if (sz != info.length) {
1256 if (info.samplerate != _session->frame_rate()) {
1260 } else if (SMFSource::safe_midi_file_extension (*i)) {
1264 if (reader.num_tracks() > 1) {
1265 multichannel = true; // "channel" == track here...
1268 /* XXX we need err = true handling here in case
1269 we can't check the file
1282 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1284 sys::path path = s->session_directory().sound_path() / "linktest";
1285 string tmpdir = path.to_string();
1288 if (mkdir (tmpdir.c_str(), 0744)) {
1289 if (errno != EEXIST) {
1294 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1296 char tmpc[MAXPATHLEN+1];
1298 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1302 if (link ((*i).c_str(), tmpc)) {
1312 rmdir (tmpdir.c_str());
1316 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1317 : SoundFileBrowser (parent, title, s, false)
1319 chooser.set_select_multiple (false);
1320 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1321 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1325 SoundFileChooser::on_hide ()
1327 ArdourDialog::on_hide();
1331 _session->cancel_audition();
1336 SoundFileChooser::get_filename ()
1338 vector<string> paths;
1340 paths = get_paths ();
1342 if (paths.empty()) {
1346 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1350 return paths.front();
1353 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s,
1354 uint32_t selected_audio_tracks,
1355 uint32_t selected_midi_tracks,
1357 Editing::ImportMode mode_hint)
1358 : SoundFileBrowser (parent, title, s, persistent)
1359 , copy_files_btn ( _("Copy files to session"))
1360 , selected_audio_track_cnt (selected_audio_tracks)
1361 , selected_midi_track_cnt (selected_midi_tracks)
1367 set_size_request (-1, 450);
1369 block_two.set_border_width (12);
1370 block_three.set_border_width (12);
1371 block_four.set_border_width (12);
1373 options.set_spacing (12);
1376 str.push_back (_("file timestamp"));
1377 str.push_back (_("edit point"));
1378 str.push_back (_("playhead"));
1379 str.push_back (_("session start"));
1380 set_popdown_strings (where_combo, str);
1381 where_combo.set_active_text (str.front());
1383 Label* l = manage (new Label);
1384 l->set_text (_("Add files:"));
1386 hbox = manage (new HBox);
1387 hbox->set_border_width (12);
1388 hbox->set_spacing (6);
1389 hbox->pack_start (*l, false, false);
1390 hbox->pack_start (action_combo, false, false);
1391 vbox = manage (new VBox);
1392 vbox->pack_start (*hbox, false, false);
1393 options.pack_start (*vbox, false, false);
1395 /* dummy entry for action combo so that it doesn't look odd if we
1396 come up with no tracks selected.
1400 str.push_back (importmode2string (mode_hint));
1401 set_popdown_strings (action_combo, str);
1402 action_combo.set_active_text (str.front());
1403 action_combo.set_sensitive (false);
1405 l = manage (new Label);
1406 l->set_text (_("Insert at:"));
1408 hbox = manage (new HBox);
1409 hbox->set_border_width (12);
1410 hbox->set_spacing (6);
1411 hbox->pack_start (*l, false, false);
1412 hbox->pack_start (where_combo, false, false);
1413 vbox = manage (new VBox);
1414 vbox->pack_start (*hbox, false, false);
1415 options.pack_start (*vbox, false, false);
1418 l = manage (new Label);
1419 l->set_text (_("Mapping:"));
1421 hbox = manage (new HBox);
1422 hbox->set_border_width (12);
1423 hbox->set_spacing (6);
1424 hbox->pack_start (*l, false, false);
1425 hbox->pack_start (channel_combo, false, false);
1426 vbox = manage (new VBox);
1427 vbox->pack_start (*hbox, false, false);
1428 options.pack_start (*vbox, false, false);
1431 str.push_back (_("one track per file"));
1432 set_popdown_strings (channel_combo, str);
1433 channel_combo.set_active_text (str.front());
1434 channel_combo.set_sensitive (false);
1436 l = manage (new Label);
1437 l->set_text (_("Conversion quality:"));
1439 hbox = manage (new HBox);
1440 hbox->set_border_width (12);
1441 hbox->set_spacing (6);
1442 hbox->pack_start (*l, false, false);
1443 hbox->pack_start (src_combo, false, false);
1444 vbox = manage (new VBox);
1445 vbox->pack_start (*hbox, false, false);
1446 options.pack_start (*vbox, false, false);
1449 str.push_back (_("Best"));
1450 str.push_back (_("Good"));
1451 str.push_back (_("Quick"));
1452 str.push_back (_("Fast"));
1453 str.push_back (_("Fastest"));
1455 set_popdown_strings (src_combo, str);
1456 src_combo.set_active_text (str.front());
1457 src_combo.set_sensitive (false);
1461 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1462 channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1464 copy_files_btn.set_active (true);
1466 block_four.pack_start (copy_files_btn, false, false);
1468 options.pack_start (block_four, false, false);
1470 get_vbox()->pack_start (options, false, false);
1472 /* setup disposition map */
1474 disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1475 disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1476 disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1477 disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1479 disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1480 disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1481 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1482 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1484 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1486 /* set size requests for a couple of combos to allow them to display the longest text
1487 they will ever be asked to display. This prevents them being resized when the user
1488 selects a file to import, which in turn prevents the size of the dialog from jumping
1492 t.push_back (_("one track per file"));
1493 t.push_back (_("one track per channel"));
1494 t.push_back (_("sequence files"));
1495 t.push_back (_("all files in one region"));
1496 set_popdown_strings (channel_combo, t);
1499 t.push_back (importmode2string (ImportAsTrack));
1500 t.push_back (importmode2string (ImportToTrack));
1501 t.push_back (importmode2string (ImportAsRegion));
1502 t.push_back (importmode2string (ImportAsTapeTrack));
1503 set_popdown_strings (action_combo, t);
1507 SoundFileOmega::set_mode (ImportMode mode)
1509 action_combo.set_active_text (importmode2string (mode));
1513 SoundFileOmega::get_mode () const
1515 return string2importmode (action_combo.get_active_text());
1519 SoundFileOmega::on_hide ()
1521 ArdourDialog::on_hide();
1523 _session->cancel_audition();
1528 SoundFileOmega::get_position() const
1530 string str = where_combo.get_active_text();
1532 if (str == _("file timestamp")) {
1533 return ImportAtTimestamp;
1534 } else if (str == _("edit point")) {
1535 return ImportAtEditPoint;
1536 } else if (str == _("playhead")) {
1537 return ImportAtPlayhead;
1539 return ImportAtStart;
1544 SoundFileOmega::get_src_quality() const
1546 string str = where_combo.get_active_text();
1548 if (str == _("Best")) {
1550 } else if (str == _("Good")) {
1552 } else if (str == _("Quick")) {
1554 } else if (str == _("Fast")) {
1562 SoundFileOmega::get_channel_disposition () const
1564 /* we use a map here because the channel combo can contain different strings
1565 depending on the state of the other combos. the map contains all possible strings
1566 and the ImportDisposition enum that corresponds to it.
1569 string str = channel_combo.get_active_text();
1570 DispositionMap::const_iterator x = disposition_map.find (str);
1572 if (x == disposition_map.end()) {
1573 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1581 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1583 selected_audio_track_cnt = selected_audio_tracks;
1584 selected_midi_track_cnt = selected_midi_tracks;
1586 if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1587 chooser.set_filter (midi_filter);
1588 } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1589 chooser.set_filter (audio_filter);
1591 chooser.set_filter (audio_and_midi_filter);
1598 SoundFileOmega::file_selection_changed ()
1600 if (resetting_ourselves) {
1604 if (!reset_options ()) {
1605 set_response_sensitive (RESPONSE_OK, false);
1607 if (chooser.get_filenames().size() > 0) {
1608 set_response_sensitive (RESPONSE_OK, true);
1610 set_response_sensitive (RESPONSE_OK, false);