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::Markup::escape_text (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 (3);
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.append_column(_("Size"), freesound_list_columns.filesize);
570 freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
571 freesound_list_view.get_column(0)->set_alignment(0.5);
572 freesound_list_view.get_column(1)->set_expand(true);
573 freesound_list_view.get_column(2)->set_alignment(0.5);
574 freesound_list_view.get_column(3)->set_alignment(0.5);
575 freesound_list_view.get_column(4)->set_alignment(0.5);
577 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
579 freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
580 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
581 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
582 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
583 freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
584 notebook.append_page (*vbox, _("Search Freesound"));
590 notebook.set_size_request (500, -1);
591 notebook.signal_switch_page().connect (
592 sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options))))
597 add_button (Stock::CANCEL, RESPONSE_CANCEL);
598 add_button (Stock::APPLY, RESPONSE_APPLY);
599 add_button (Stock::OK, RESPONSE_OK);
603 SoundFileBrowser::~SoundFileBrowser ()
605 persistent_folder = chooser.get_current_folder();
610 SoundFileBrowser::on_show ()
612 ArdourDialog::on_show ();
617 SoundFileBrowser::clear_selection ()
619 chooser.unselect_all ();
620 found_list_view.get_selection()->unselect_all ();
624 SoundFileBrowser::chooser_file_activated ()
630 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
636 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
642 SoundFileBrowser::set_session (Session* s)
644 ArdourDialog::set_session (s);
645 preview.set_session (s);
650 remove_gain_meter ();
655 SoundFileBrowser::add_gain_meter ()
659 gm = new GainMeter (_session, 250);
661 boost::shared_ptr<Route> r = _session->the_auditioner ();
663 gm->set_controls (r, r->shared_peak_meter(), r->amp());
665 meter_packer.set_border_width (12);
666 meter_packer.pack_start (*gm, false, true);
667 hpacker.pack_end (meter_packer, false, false);
668 meter_packer.show_all ();
673 SoundFileBrowser::remove_gain_meter ()
676 meter_packer.remove (*gm);
677 hpacker.remove (meter_packer);
684 SoundFileBrowser::start_metering ()
686 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
690 SoundFileBrowser::stop_metering ()
692 metering_connection.disconnect();
696 SoundFileBrowser::meter ()
698 if (is_mapped () && _session && gm) {
699 gm->update_meters ();
704 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
706 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
710 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
712 return SMFSource::safe_midi_file_extension (filter_info.filename);
716 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
718 return on_audio_filter (filter_info) || on_midi_filter (filter_info);
722 SoundFileBrowser::update_preview ()
724 if (preview.setup_labels (chooser.get_preview_filename())) {
725 if (preview.autoplay()) {
726 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
732 SoundFileBrowser::found_list_view_selected ()
734 if (!reset_options ()) {
735 set_response_sensitive (RESPONSE_OK, false);
739 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
742 TreeIter iter = found_list->get_iter(*rows.begin());
743 file = (*iter)[found_list_columns.pathname];
744 chooser.set_filename (file);
745 set_response_sensitive (RESPONSE_OK, true);
747 set_response_sensitive (RESPONSE_OK, false);
750 preview.setup_labels (file);
755 SoundFileBrowser::freesound_list_view_selected ()
757 freesound_download_cancel = false;
760 if (!reset_options ()) {
761 set_response_sensitive (RESPONSE_OK, false);
766 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
769 TreeIter iter = freesound_list->get_iter(*rows.begin());
771 string id = (*iter)[freesound_list_columns.id];
772 string uri = (*iter)[freesound_list_columns.uri];
773 string ofn = (*iter)[freesound_list_columns.filename];
775 // download the sound file
776 GdkCursor *prev_cursor;
777 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
778 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
781 file = mootcher->getAudioFile(ofn, id, uri, this);
783 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
786 chooser.set_filename (file);
787 set_response_sensitive (RESPONSE_OK, true);
790 set_response_sensitive (RESPONSE_OK, false);
793 preview.setup_labels (file);
799 SoundFileBrowser::found_search_clicked ()
801 string tag_string = found_entry.get_text ();
805 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
806 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
810 vector<string> results;
811 Library->search_members_and (results, tags);
814 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
815 TreeModel::iterator new_row = found_list->append();
816 TreeModel::Row row = *new_row;
817 string path = Glib::filename_from_uri (string ("file:") + *i);
818 row[found_list_columns.pathname] = path;
823 SoundFileBrowser::freesound_search_clicked ()
825 freesound_search_cancel = false;
830 SoundFileBrowser::freesound_stop_clicked ()
832 freesound_download_cancel = true;
833 freesound_search_cancel = true;
838 SoundFileBrowser::freesound_search()
841 freesound_list->clear();
843 string search_string = freesound_entry.get_text ();
844 enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
846 GdkCursor *prev_cursor;
847 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
848 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
850 for (int page = 1; page <= 99; page++ ) {
853 prog = string_compose (_("Page %1"), page);
854 freesound_progress_bar.set_text(prog);
855 while (Glib::MainContext::get_default()->iteration (false)) {
859 std::string theString = mootcher->searchText(
863 "", // OSX eats anything incl mp3
865 "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
871 doc.read_buffer( theString );
872 XMLNode *root = doc.root();
875 error << "no root XML node!" << endmsg;
879 if ( strcmp(root->name().c_str(), "response") != 0) {
880 error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
884 XMLNode *sounds_root = root->child("sounds");
887 error << "no child node \"sounds\" found!" << endmsg;
891 XMLNodeList sounds = sounds_root->children();
892 if (sounds.size() == 0) {
897 XMLNodeConstIterator niter;
899 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
901 if( strcmp( node->name().c_str(), "resource") != 0 ){
902 error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
903 freesound_search_cancel = true;
907 // node->dump(cerr, "node:");
909 XMLNode *id_node = node->child ("id");
910 XMLNode *uri_node = node->child ("serve");
911 XMLNode *ofn_node = node->child ("original_filename");
912 XMLNode *dur_node = node->child ("duration");
913 XMLNode *siz_node = node->child ("filesize");
914 XMLNode *srt_node = node->child ("samplerate");
916 if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
918 std::string id = id_node->child("text")->content();
919 std::string uri = uri_node->child("text")->content();
920 std::string ofn = ofn_node->child("text")->content();
921 std::string dur = dur_node->child("text")->content();
922 std::string siz = siz_node->child("text")->content();
923 std::string srt = srt_node->child("text")->content();
926 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
928 double duration_seconds = atof(dur.c_str());
930 char duration_hhmmss[16];
931 if (duration_seconds >= 99 * 60 * 60) {
932 strcpy(duration_hhmmss, ">99h");
934 s = modf(duration_seconds/60, &m) * 60;
935 m = modf(m/60, &h) * 60;
936 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
941 double size_bytes = atof(siz.c_str());
943 if (size_bytes < 1000) {
944 sprintf(bsize, "%.0f %s", size_bytes, _("B"));
945 } else if (size_bytes < 1000000 ) {
946 sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
947 } else if (size_bytes < 10000000) {
948 sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
949 } else if (size_bytes < 1000000000) {
950 sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
952 sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
955 TreeModel::iterator new_row = freesound_list->append();
956 TreeModel::Row row = *new_row;
958 row[freesound_list_columns.id ] = id;
959 row[freesound_list_columns.uri ] = uri;
960 row[freesound_list_columns.filename] = ofn;
961 row[freesound_list_columns.duration] = duration_hhmmss;
962 row[freesound_list_columns.filesize] = bsize;
963 row[freesound_list_columns.smplrate] = srt;
968 if (freesound_search_cancel)
973 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
975 freesound_progress_bar.set_text("");
981 SoundFileBrowser::get_paths ()
983 vector<string> results;
985 int n = notebook.get_current_page ();
988 vector<string> filenames = chooser.get_filenames();
989 vector<string>::iterator i;
991 for (i = filenames.begin(); i != filenames.end(); ++i) {
993 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
994 results.push_back (*i);
1000 typedef TreeView::Selection::ListHandle_Path ListPath;
1002 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1003 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1004 TreeIter iter = found_list->get_iter(*i);
1005 string str = (*iter)[found_list_columns.pathname];
1007 results.push_back (str);
1011 typedef TreeView::Selection::ListHandle_Path ListPath;
1013 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1014 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1015 TreeIter iter = freesound_list->get_iter(*i);
1016 string id = (*iter)[freesound_list_columns.id];
1017 string uri = (*iter)[freesound_list_columns.uri];
1018 string ofn = (*iter)[freesound_list_columns.filename];
1020 GdkCursor *prev_cursor;
1021 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1022 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1025 string str = mootcher->getAudioFile(ofn, id, uri, this);
1027 results.push_back (str);
1030 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1040 SoundFileOmega::reset_options_noret ()
1042 if (!resetting_ourselves) {
1043 (void) reset_options ();
1048 SoundFileOmega::reset_options ()
1050 vector<string> paths = get_paths ();
1052 if (paths.empty()) {
1054 channel_combo.set_sensitive (false);
1055 action_combo.set_sensitive (false);
1056 where_combo.set_sensitive (false);
1057 copy_files_btn.set_active (true);
1058 copy_files_btn.set_sensitive (false);
1064 channel_combo.set_sensitive (true);
1065 action_combo.set_sensitive (true);
1066 where_combo.set_sensitive (true);
1068 /* if we get through this function successfully, this may be
1069 reset at the end, once we know if we can use hard links
1070 to do embedding (or if we are importing a MIDI file).
1073 if (Config->get_only_copy_imported_files()) {
1074 copy_files_btn.set_sensitive (false);
1076 copy_files_btn.set_sensitive (false);
1082 bool selection_includes_multichannel;
1083 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1086 /* See if we are thinking about importing any MIDI files */
1087 vector<string>::iterator i = paths.begin ();
1088 while (i != paths.end() && SMFSource::safe_midi_file_extension (*i) == false) {
1091 bool const have_a_midi_file = (i != paths.end ());
1093 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1094 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1098 string existing_choice;
1099 vector<string> action_strings;
1101 resetting_ourselves = true;
1103 if (chooser.get_filter() == &audio_filter) {
1107 if (selected_audio_track_cnt > 0) {
1108 if (channel_combo.get_active_text().length()) {
1109 ImportDisposition id = get_channel_disposition();
1112 case Editing::ImportDistinctFiles:
1113 if (selected_audio_track_cnt == paths.size()) {
1114 action_strings.push_back (importmode2string (ImportToTrack));
1118 case Editing::ImportDistinctChannels:
1119 /* XXX it would be nice to allow channel-per-selected track
1120 but its too hard we don't want to deal with all the
1121 different per-file + per-track channel configurations.
1126 action_strings.push_back (importmode2string (ImportToTrack));
1136 if (selected_midi_track_cnt > 0) {
1137 action_strings.push_back (importmode2string (ImportToTrack));
1141 action_strings.push_back (importmode2string (ImportAsTrack));
1142 action_strings.push_back (importmode2string (ImportAsRegion));
1143 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1145 existing_choice = action_combo.get_active_text();
1147 set_popdown_strings (action_combo, action_strings);
1149 /* preserve any existing choice, if possible */
1152 if (existing_choice.length()) {
1153 vector<string>::iterator x;
1154 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1155 if (*x == existing_choice) {
1156 action_combo.set_active_text (existing_choice);
1160 if (x == action_strings.end()) {
1161 action_combo.set_active_text (action_strings.front());
1164 action_combo.set_active_text (action_strings.front());
1167 resetting_ourselves = false;
1169 if ((mode = get_mode()) == ImportAsRegion) {
1170 where_combo.set_sensitive (false);
1172 where_combo.set_sensitive (true);
1175 vector<string> channel_strings;
1177 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1178 channel_strings.push_back (_("one track per file"));
1180 if (selection_includes_multichannel) {
1181 channel_strings.push_back (_("one track per channel"));
1184 if (paths.size() > 1) {
1185 /* tape tracks are a single region per track, so we cannot
1186 sequence multiple files.
1188 if (mode != ImportAsTapeTrack) {
1189 channel_strings.push_back (_("sequence files"));
1192 channel_strings.push_back (_("all files in one track"));
1193 channel_strings.push_back (_("merge files"));
1199 channel_strings.push_back (_("one region per file"));
1201 if (selection_includes_multichannel) {
1202 channel_strings.push_back (_("one region per channel"));
1205 if (paths.size() > 1) {
1207 channel_strings.push_back (_("all files in one region"));
1212 resetting_ourselves = true;
1214 existing_choice = channel_combo.get_active_text();
1216 set_popdown_strings (channel_combo, channel_strings);
1218 /* preserve any existing choice, if possible */
1220 if (existing_choice.length()) {
1221 vector<string>::iterator x;
1222 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1223 if (*x == existing_choice) {
1224 channel_combo.set_active_text (existing_choice);
1228 if (x == channel_strings.end()) {
1229 channel_combo.set_active_text (channel_strings.front());
1232 channel_combo.set_active_text (channel_strings.front());
1235 resetting_ourselves = false;
1238 src_combo.set_sensitive (true);
1240 src_combo.set_sensitive (false);
1243 /* We must copy MIDI files or those from Freesound */
1244 bool const must_copy = have_a_midi_file || notebook.get_current_page() == 2;
1246 if (Config->get_only_copy_imported_files()) {
1248 if (selection_can_be_embedded_with_links && !must_copy) {
1249 copy_files_btn.set_sensitive (true);
1252 copy_files_btn.set_active (true);
1254 copy_files_btn.set_sensitive (false);
1260 copy_files_btn.set_active (true);
1262 copy_files_btn.set_sensitive (!must_copy);
1270 SoundFileOmega::bad_file_message()
1272 MessageDialog msg (*this,
1273 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1278 resetting_ourselves = true;
1279 chooser.unselect_uri (chooser.get_preview_uri());
1280 resetting_ourselves = false;
1286 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1295 multichannel = false;
1297 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1299 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1300 if (info.channels > 1) {
1301 multichannel = true;
1306 if (sz != info.length) {
1311 if (info.samplerate != _session->frame_rate()) {
1315 } else if (SMFSource::safe_midi_file_extension (*i)) {
1319 if (reader.num_tracks() > 1) {
1320 multichannel = true; // "channel" == track here...
1323 /* XXX we need err = true handling here in case
1324 we can't check the file
1337 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1339 std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1342 if (mkdir (tmpdir.c_str(), 0744)) {
1343 if (errno != EEXIST) {
1348 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1350 char tmpc[MAXPATHLEN+1];
1352 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1356 if (link ((*i).c_str(), tmpc)) {
1366 rmdir (tmpdir.c_str());
1370 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1371 : SoundFileBrowser (parent, title, s, false)
1373 chooser.set_select_multiple (false);
1374 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1375 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1379 SoundFileChooser::on_hide ()
1381 ArdourDialog::on_hide();
1385 _session->cancel_audition();
1390 SoundFileChooser::get_filename ()
1392 vector<string> paths;
1394 paths = get_paths ();
1396 if (paths.empty()) {
1400 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1404 return paths.front();
1407 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s,
1408 uint32_t selected_audio_tracks,
1409 uint32_t selected_midi_tracks,
1411 Editing::ImportMode mode_hint)
1412 : SoundFileBrowser (parent, title, s, persistent)
1413 , copy_files_btn ( _("Copy files to session"))
1414 , selected_audio_track_cnt (selected_audio_tracks)
1415 , selected_midi_track_cnt (selected_midi_tracks)
1421 set_size_request (-1, 450);
1423 block_two.set_border_width (12);
1424 block_three.set_border_width (12);
1425 block_four.set_border_width (12);
1427 options.set_spacing (12);
1430 str.push_back (_("file timestamp"));
1431 str.push_back (_("edit point"));
1432 str.push_back (_("playhead"));
1433 str.push_back (_("session start"));
1434 set_popdown_strings (where_combo, str);
1435 where_combo.set_active_text (str.front());
1437 Label* l = manage (new Label);
1438 l->set_markup (_("<b>Add files as ...</b>"));
1440 vbox = manage (new VBox);
1441 vbox->set_border_width (12);
1442 vbox->set_spacing (6);
1443 vbox->pack_start (*l, false, false);
1444 vbox->pack_start (action_combo, false, false);
1445 hbox = manage (new HBox);
1446 hbox->pack_start (*vbox, false, false);
1447 options.pack_start (*hbox, false, false);
1449 /* dummy entry for action combo so that it doesn't look odd if we
1450 come up with no tracks selected.
1454 str.push_back (importmode2string (mode_hint));
1455 set_popdown_strings (action_combo, str);
1456 action_combo.set_active_text (str.front());
1457 action_combo.set_sensitive (false);
1459 l = manage (new Label);
1460 l->set_markup (_("<b>Insert at</b>"));
1462 vbox = manage (new VBox);
1463 vbox->set_border_width (12);
1464 vbox->set_spacing (6);
1465 vbox->pack_start (*l, false, false);
1466 vbox->pack_start (where_combo, false, false);
1467 hbox = manage (new HBox);
1468 hbox->pack_start (*vbox, false, false);
1469 options.pack_start (*hbox, false, false);
1472 l = manage (new Label);
1473 l->set_markup (_("<b>Mapping</b>"));
1475 vbox = manage (new VBox);
1476 vbox->set_border_width (12);
1477 vbox->set_spacing (6);
1478 vbox->pack_start (*l, false, false);
1479 vbox->pack_start (channel_combo, false, false);
1480 hbox = manage (new HBox);
1481 hbox->pack_start (*vbox, false, false);
1482 options.pack_start (*hbox, false, false);
1485 str.push_back (_("one track per file"));
1486 set_popdown_strings (channel_combo, str);
1487 channel_combo.set_active_text (str.front());
1488 channel_combo.set_sensitive (false);
1490 l = manage (new Label);
1491 l->set_markup (_("<b>Conversion quality</b>"));
1493 vbox = manage (new VBox);
1494 vbox->set_border_width (12);
1495 vbox->set_spacing (6);
1496 vbox->pack_start (*l, false, false);
1497 vbox->pack_start (src_combo, false, false);
1498 hbox = manage (new HBox);
1499 hbox->pack_start (*vbox, false, false);
1500 options.pack_start (*hbox, false, false);
1503 str.push_back (_("Best"));
1504 str.push_back (_("Good"));
1505 str.push_back (_("Quick"));
1506 str.push_back (_("Fast"));
1507 str.push_back (_("Fastest"));
1509 set_popdown_strings (src_combo, str);
1510 src_combo.set_active_text (str.front());
1511 src_combo.set_sensitive (false);
1515 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1516 channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1518 copy_files_btn.set_active (true);
1520 Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1523 copy_label->set_size_request (175, -1);
1524 copy_label->set_line_wrap (true);
1527 block_four.pack_start (copy_files_btn, false, false);
1529 options.pack_start (block_four, false, false);
1531 get_vbox()->pack_start (options, false, false);
1533 /* setup disposition map */
1535 disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1536 disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1537 disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1538 disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1540 disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1541 disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1542 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1543 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1545 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1547 /* set size requests for a couple of combos to allow them to display the longest text
1548 they will ever be asked to display. This prevents them being resized when the user
1549 selects a file to import, which in turn prevents the size of the dialog from jumping
1553 t.push_back (_("one track per file"));
1554 t.push_back (_("one track per channel"));
1555 t.push_back (_("sequence files"));
1556 t.push_back (_("all files in one region"));
1557 set_popdown_strings (channel_combo, t);
1560 t.push_back (importmode2string (ImportAsTrack));
1561 t.push_back (importmode2string (ImportToTrack));
1562 t.push_back (importmode2string (ImportAsRegion));
1563 t.push_back (importmode2string (ImportAsTapeTrack));
1564 set_popdown_strings (action_combo, t);
1568 SoundFileOmega::set_mode (ImportMode mode)
1570 action_combo.set_active_text (importmode2string (mode));
1574 SoundFileOmega::get_mode () const
1576 return string2importmode (action_combo.get_active_text());
1580 SoundFileOmega::on_hide ()
1582 ArdourDialog::on_hide();
1584 _session->cancel_audition();
1589 SoundFileOmega::get_position() const
1591 string str = where_combo.get_active_text();
1593 if (str == _("file timestamp")) {
1594 return ImportAtTimestamp;
1595 } else if (str == _("edit point")) {
1596 return ImportAtEditPoint;
1597 } else if (str == _("playhead")) {
1598 return ImportAtPlayhead;
1600 return ImportAtStart;
1605 SoundFileOmega::get_src_quality() const
1607 string str = where_combo.get_active_text();
1609 if (str == _("Best")) {
1611 } else if (str == _("Good")) {
1613 } else if (str == _("Quick")) {
1615 } else if (str == _("Fast")) {
1623 SoundFileOmega::get_channel_disposition () const
1625 /* we use a map here because the channel combo can contain different strings
1626 depending on the state of the other combos. the map contains all possible strings
1627 and the ImportDisposition enum that corresponds to it.
1630 string str = channel_combo.get_active_text();
1631 DispositionMap::const_iterator x = disposition_map.find (str);
1633 if (x == disposition_map.end()) {
1634 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1642 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1644 selected_audio_track_cnt = selected_audio_tracks;
1645 selected_midi_track_cnt = selected_midi_tracks;
1647 if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1648 chooser.set_filter (midi_filter);
1649 } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1650 chooser.set_filter (audio_filter);
1652 chooser.set_filter (audio_and_midi_filter);
1659 SoundFileOmega::file_selection_changed ()
1661 if (resetting_ourselves) {
1665 if (!reset_options ()) {
1666 set_response_sensitive (RESPONSE_OK, false);
1668 if (chooser.get_filenames().size() > 0) {
1669 set_response_sensitive (RESPONSE_OK, true);
1671 set_response_sensitive (RESPONSE_OK, false);