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, "", false, false, true, false),
122 timecode_clock ("sfboxTimecodeClock", !persistent, "", 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.set_wrap_mode(Gtk::WRAP_WORD);
181 tags_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
183 Label* label = manage (new Label (_("Tags:")));
184 label->set_alignment (0.0f, 0.5f);
185 main_box.pack_start (*label, false, false);
186 main_box.pack_start (tags_entry, true, true);
188 main_box.pack_start (bottom_box, false, false);
190 play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
191 // play_btn.set_label (_("Play"));
193 stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
194 // stop_btn.set_label (_("Stop"));
196 bottom_box.set_homogeneous (false);
197 bottom_box.set_spacing (6);
198 bottom_box.pack_start(play_btn, true, true);
199 bottom_box.pack_start(stop_btn, true, true);
200 bottom_box.pack_start(autoplay_btn, false, false);
202 play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
203 stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
205 channels_value.set_alignment (0.0f, 0.5f);
206 samplerate_value.set_alignment (0.0f, 0.5f);
210 SoundFileBox::set_session(Session* s)
212 SessionHandlePtr::set_session (s);
214 length_clock.set_session (s);
215 timecode_clock.set_session (s);
218 play_btn.set_sensitive (false);
219 stop_btn.set_sensitive (false);
224 SoundFileBox::setup_labels (const string& filename)
227 // save existing tags
235 if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
237 preview_label.set_markup (_("<b>Sound File Information</b>"));
238 format_text.set_text ("");
239 channels_value.set_text ("");
240 samplerate_value.set_text ("");
241 tags_entry.get_buffer()->set_text ("");
243 length_clock.set (0);
244 timecode_clock.set (0);
246 tags_entry.set_sensitive (false);
247 play_btn.set_sensitive (false);
252 preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
253 std::string n = sf_info.format_name;
254 if (n.substr (0, 8) == X_("Format: ")) {
257 format_text.set_text (n);
258 channels_value.set_text (to_string (sf_info.channels, std::dec));
260 if (_session && sf_info.samplerate != _session->frame_rate()) {
261 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
262 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
263 samplerate_value.set_name ("NewSessionSR1Label");
264 samplerate.set_name ("NewSessionSR1Label");
266 samplerate.set_text (_("Sample rate:"));
267 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
268 samplerate_value.set_name ("NewSessionSR2Label");
269 samplerate.set_name ("NewSessionSR2Label");
272 framecnt_t const nfr = _session ? _session->nominal_frame_rate() : 25;
273 double src_coef = (double) nfr / sf_info.samplerate;
275 length_clock.set (sf_info.length * src_coef + 0.5, true);
276 timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
278 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
280 vector<string> tags = Library->get_tags (string ("//") + filename);
282 stringstream tag_string;
283 for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
284 if (i != tags.begin()) {
289 tags_entry.get_buffer()->set_text (tag_string.str());
291 tags_entry.set_sensitive (true);
293 play_btn.set_sensitive (true);
300 SoundFileBox::autoplay() const
302 return autoplay_btn.get_active();
306 SoundFileBox::audition_oneshot()
313 SoundFileBox::audition ()
319 if (SMFSource::safe_midi_file_extension (path)) {
320 error << _("Auditioning of MIDI files is not yet supported") << endmsg;
324 _session->cancel_audition();
326 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
327 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
331 boost::shared_ptr<Region> r;
333 boost::shared_ptr<AudioFileSource> afs;
334 bool old_sbp = AudioSource::get_build_peakfiles ();
336 /* don't even think of building peakfiles for these files */
338 AudioSource::set_build_peakfiles (false);
340 for (int n = 0; n < sf_info.channels; ++n) {
342 afs = boost::dynamic_pointer_cast<AudioFileSource> (
343 SourceFactory::createReadable (DataType::AUDIO, *_session,
344 path, n, Source::Flag (0), false));
346 srclist.push_back(afs);
348 } catch (failed_constructor& err) {
349 error << _("Could not access soundfile: ") << path << endmsg;
350 AudioSource::set_build_peakfiles (old_sbp);
355 AudioSource::set_build_peakfiles (old_sbp);
357 if (srclist.empty()) {
361 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
362 string rname = region_name_from_path (afs->path(), false);
366 plist.add (ARDOUR::Properties::start, 0);
367 plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
368 plist.add (ARDOUR::Properties::name, rname);
369 plist.add (ARDOUR::Properties::layer, 0);
371 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
373 _session->audition_region(r);
377 SoundFileBox::stop_audition ()
380 _session->cancel_audition();
385 SoundFileBox::tags_entry_left (GdkEventFocus *)
392 SoundFileBox::tags_changed ()
394 string tag_string = tags_entry.get_buffer()->get_text ();
396 if (tag_string.empty()) {
402 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
403 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
411 SoundFileBox::save_tags (const vector<string>& tags)
413 Library->set_tags (string ("//") + path, tags);
414 Library->save_changes ();
417 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
418 : ArdourDialog (parent, title, false, false),
419 found_list (ListStore::create(found_list_columns)),
420 freesound_list (ListStore::create(freesound_list_columns)),
421 chooser (FILE_CHOOSER_ACTION_OPEN),
422 preview (persistent),
423 found_search_btn (_("Search")),
424 found_list_view (found_list),
425 freesound_search_btn (_("Search")),
426 freesound_list_view (freesound_list)
428 resetting_ourselves = false;
431 resetting_ourselves = false;
435 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
436 chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
437 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
439 chooser.add_shortcut_folder_uri("file:///Volumes");
443 mootcher = new Mootcher();
446 //add the file chooser
448 chooser.set_border_width (12);
450 audio_and_midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun (*this, &SoundFileBrowser::on_audio_and_midi_filter));
451 audio_and_midi_filter.set_name (_("Audio and MIDI files"));
453 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
454 audio_filter.set_name (_("Audio files"));
456 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
457 midi_filter.set_name (_("MIDI files"));
459 matchall_filter.add_pattern ("*.*");
460 matchall_filter.set_name (_("All files"));
462 chooser.add_filter (audio_and_midi_filter);
463 chooser.add_filter (audio_filter);
464 chooser.add_filter (midi_filter);
465 chooser.add_filter (matchall_filter);
466 chooser.set_select_multiple (true);
467 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
468 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
470 /* some broken redraw behaviour - this is a bandaid */
471 chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
474 if (!persistent_folder.empty()) {
475 chooser.set_current_folder (persistent_folder);
477 notebook.append_page (chooser, _("Browse Files"));
480 hpacker.set_spacing (6);
481 hpacker.pack_start (notebook, true, true);
482 hpacker.pack_start (preview, false, false);
484 get_vbox()->pack_start (hpacker, true, true);
492 hbox = manage(new HBox);
493 hbox->pack_start (found_entry);
494 hbox->pack_start (found_search_btn);
496 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
497 scroll->add(found_list_view);
498 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
500 vbox = manage(new VBox);
501 vbox->pack_start (*hbox, PACK_SHRINK);
502 vbox->pack_start (*scroll);
504 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
506 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
508 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
510 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
511 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
513 freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
515 notebook.append_page (*vbox, _("Search Tags"));
518 //add freesound search
525 passbox = manage(new HBox);
526 passbox->set_border_width (12);
527 passbox->set_spacing (6);
529 label = manage (new Label);
530 label->set_text (_("Tags:"));
531 passbox->pack_start (*label, false, false);
532 passbox->pack_start (freesound_entry, false, false);
534 label = manage (new Label);
535 label->set_text (_("Sort:"));
536 passbox->pack_start (*label, false, false);
537 passbox->pack_start (freesound_sort, false, false);
538 freesound_sort.clear_items();
540 // Order of the following must correspond with enum sortMethod
541 // in sfdb_freesound_mootcher.h
542 freesound_sort.append_text(_("None"));
543 freesound_sort.append_text(_("Longest"));
544 freesound_sort.append_text(_("Shortest"));
545 freesound_sort.append_text(_("Newest"));
546 freesound_sort.append_text(_("Oldest"));
547 freesound_sort.append_text(_("Most downloaded"));
548 freesound_sort.append_text(_("Least downloaded"));
549 freesound_sort.append_text(_("Highest rated"));
550 freesound_sort.append_text(_("Lowest rated"));
551 freesound_sort.set_active(0);
553 passbox->pack_start (freesound_search_btn, false, false);
554 passbox->pack_start (freesound_progress_bar);
555 passbox->pack_end (freesound_stop_btn, false, false);
556 freesound_stop_btn.set_label(_("Stop"));
558 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
559 scroll->add(freesound_list_view);
560 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
562 vbox = manage(new VBox);
563 vbox->pack_start (*passbox, PACK_SHRINK);
564 vbox->pack_start (*scroll);
566 freesound_list_view.append_column(_("ID") , freesound_list_columns.id);
567 freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
568 // freesound_list_view.append_column(_("URI") , freesound_list_columns.uri);
569 freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
570 freesound_list_view.get_column(1)->set_expand(true);
572 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
574 freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
575 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
576 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
577 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
578 freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
579 notebook.append_page (*vbox, _("Search Freesound"));
585 notebook.set_size_request (500, -1);
589 add_button (Stock::CANCEL, RESPONSE_CANCEL);
590 add_button (Stock::APPLY, RESPONSE_APPLY);
591 add_button (Stock::OK, RESPONSE_OK);
595 SoundFileBrowser::~SoundFileBrowser ()
597 persistent_folder = chooser.get_current_folder();
602 SoundFileBrowser::on_show ()
604 ArdourDialog::on_show ();
609 SoundFileBrowser::clear_selection ()
611 chooser.unselect_all ();
612 found_list_view.get_selection()->unselect_all ();
616 SoundFileBrowser::chooser_file_activated ()
622 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
628 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
634 SoundFileBrowser::set_session (Session* s)
636 ArdourDialog::set_session (s);
637 preview.set_session (s);
642 remove_gain_meter ();
647 SoundFileBrowser::add_gain_meter ()
651 gm = new GainMeter (_session, 250);
653 boost::shared_ptr<Route> r = _session->the_auditioner ();
655 gm->set_controls (r, r->shared_peak_meter(), r->amp());
657 meter_packer.set_border_width (12);
658 meter_packer.pack_start (*gm, false, true);
659 hpacker.pack_end (meter_packer, false, false);
660 meter_packer.show_all ();
665 SoundFileBrowser::remove_gain_meter ()
668 meter_packer.remove (*gm);
669 hpacker.remove (meter_packer);
676 SoundFileBrowser::start_metering ()
678 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
682 SoundFileBrowser::stop_metering ()
684 metering_connection.disconnect();
688 SoundFileBrowser::meter ()
690 if (is_mapped () && _session && gm) {
691 gm->update_meters ();
696 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
698 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
702 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
704 return SMFSource::safe_midi_file_extension (filter_info.filename);
708 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
710 return on_audio_filter (filter_info) || on_midi_filter (filter_info);
714 SoundFileBrowser::update_preview ()
716 if (preview.setup_labels (chooser.get_filename())) {
717 if (preview.autoplay()) {
718 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
724 SoundFileBrowser::found_list_view_selected ()
726 if (!reset_options ()) {
727 set_response_sensitive (RESPONSE_OK, false);
731 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
734 TreeIter iter = found_list->get_iter(*rows.begin());
735 file = (*iter)[found_list_columns.pathname];
736 chooser.set_filename (file);
737 set_response_sensitive (RESPONSE_OK, true);
739 set_response_sensitive (RESPONSE_OK, false);
742 preview.setup_labels (file);
747 SoundFileBrowser::freesound_list_view_selected ()
749 freesound_download_cancel = false;
752 if (!reset_options ()) {
753 set_response_sensitive (RESPONSE_OK, false);
758 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
761 TreeIter iter = freesound_list->get_iter(*rows.begin());
763 string id = (*iter)[freesound_list_columns.id];
764 string uri = (*iter)[freesound_list_columns.uri];
765 string ofn = (*iter)[freesound_list_columns.filename];
767 // download the sound file
768 GdkCursor *prev_cursor;
769 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
770 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
773 file = mootcher->getAudioFile(ofn, id, uri, this);
775 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
778 chooser.set_filename (file);
779 set_response_sensitive (RESPONSE_OK, true);
782 set_response_sensitive (RESPONSE_OK, false);
785 preview.setup_labels (file);
791 SoundFileBrowser::found_search_clicked ()
793 string tag_string = found_entry.get_text ();
797 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
798 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
802 vector<string> results;
803 Library->search_members_and (results, tags);
806 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
807 TreeModel::iterator new_row = found_list->append();
808 TreeModel::Row row = *new_row;
809 string path = Glib::filename_from_uri (string ("file:") + *i);
810 row[found_list_columns.pathname] = path;
815 SoundFileBrowser::freesound_search_clicked ()
817 freesound_search_cancel = false;
822 SoundFileBrowser::freesound_stop_clicked ()
824 freesound_download_cancel = true;
825 freesound_search_cancel = true;
830 SoundFileBrowser::freesound_search()
833 freesound_list->clear();
835 string search_string = freesound_entry.get_text ();
836 enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
838 GdkCursor *prev_cursor;
839 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
840 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
842 for (int page = 1; page <= 99; page++ ) {
845 prog = string_compose (_("Page %1, [Stop]->"), page);
846 freesound_progress_bar.set_text(prog);
847 while (Glib::MainContext::get_default()->iteration (false)) {
851 std::string theString = mootcher->searchText(
854 "", // filter, could do, e.g. "type:wav"
859 doc.read_buffer( theString );
860 XMLNode *root = doc.root();
863 cerr << "no root XML node!" << endl;
867 if ( strcmp(root->name().c_str(), "response") != 0) {
868 cerr << "root node name == " << root->name() << ", != \"response\"!" << endl;
872 XMLNode *sounds_root = root->child("sounds");
875 cerr << "no child node \"sounds\" found!" << endl;
879 XMLNodeList sounds = sounds_root->children();
880 XMLNodeConstIterator niter;
882 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
884 if( strcmp( node->name().c_str(), "resource") != 0 ){
885 cerr << "node->name()=" << node->name() << ",!= \"resource\"!" << endl;
886 freesound_search_cancel = true;
890 // node->dump(cerr, "node:");
892 XMLNode *id_node = node->child ("id");
893 XMLNode *uri_node = node->child ("serve");
894 XMLNode *ofn_node = node->child ("original_filename");
895 XMLNode *dur_node = node->child ("duration");
897 if (id_node && uri_node && ofn_node && dur_node) {
899 std::string id = id_node->child("text")->content();
900 std::string uri = uri_node->child("text")->content();
901 std::string ofn = ofn_node->child("text")->content();
902 std::string dur = dur_node->child("text")->content();
905 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
907 double duration_seconds = atof(dur.c_str());
909 char duration_hhmmss[16];
910 if (duration_seconds >= 99 * 60 * 60) {
911 strcpy(duration_hhmmss, ">99h");
913 s = modf(duration_seconds/60, &m) * 60;
914 m = modf(m/60, &h) * 60;
915 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
920 TreeModel::iterator new_row = freesound_list->append();
921 TreeModel::Row row = *new_row;
923 row[freesound_list_columns.id ] = id;
924 row[freesound_list_columns.uri ] = uri;
925 row[freesound_list_columns.filename] = ofn;
926 row[freesound_list_columns.duration] = duration_hhmmss;
931 if (freesound_search_cancel)
936 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
938 freesound_progress_bar.set_text("");
944 SoundFileBrowser::get_paths ()
946 vector<string> results;
948 int n = notebook.get_current_page ();
951 vector<string> filenames = chooser.get_filenames();
952 vector<string>::iterator i;
954 for (i = filenames.begin(); i != filenames.end(); ++i) {
956 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
957 results.push_back (*i);
963 typedef TreeView::Selection::ListHandle_Path ListPath;
965 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
966 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
967 TreeIter iter = found_list->get_iter(*i);
968 string str = (*iter)[found_list_columns.pathname];
970 results.push_back (str);
974 typedef TreeView::Selection::ListHandle_Path ListPath;
976 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
977 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
978 TreeIter iter = freesound_list->get_iter(*i);
979 string id = (*iter)[freesound_list_columns.id];
980 string uri = (*iter)[freesound_list_columns.uri];
981 string ofn = (*iter)[freesound_list_columns.filename];
983 GdkCursor *prev_cursor;
984 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
985 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
988 string str = mootcher->getAudioFile(ofn, id, uri, this);
990 results.push_back (str);
993 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1003 SoundFileOmega::reset_options_noret ()
1005 if (!resetting_ourselves) {
1006 (void) reset_options ();
1011 SoundFileOmega::reset_options ()
1013 vector<string> paths = get_paths ();
1015 if (paths.empty()) {
1017 channel_combo.set_sensitive (false);
1018 action_combo.set_sensitive (false);
1019 where_combo.set_sensitive (false);
1020 copy_files_btn.set_sensitive (false);
1026 channel_combo.set_sensitive (true);
1027 action_combo.set_sensitive (true);
1028 where_combo.set_sensitive (true);
1030 /* if we get through this function successfully, this may be
1031 reset at the end, once we know if we can use hard links
1035 if (Config->get_only_copy_imported_files()) {
1036 copy_files_btn.set_sensitive (false);
1038 copy_files_btn.set_sensitive (false);
1044 bool selection_includes_multichannel;
1045 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1048 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1049 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1053 string existing_choice;
1054 vector<string> action_strings;
1056 if (chooser.get_filter() == &audio_filter) {
1060 if (selected_audio_track_cnt > 0) {
1061 if (channel_combo.get_active_text().length()) {
1062 ImportDisposition id = get_channel_disposition();
1065 case Editing::ImportDistinctFiles:
1066 if (selected_audio_track_cnt == paths.size()) {
1067 action_strings.push_back (importmode2string (ImportToTrack));
1071 case Editing::ImportDistinctChannels:
1072 /* XXX it would be nice to allow channel-per-selected track
1073 but its too hard we don't want to deal with all the
1074 different per-file + per-track channel configurations.
1079 action_strings.push_back (importmode2string (ImportToTrack));
1089 if (selected_midi_track_cnt > 0) {
1090 action_strings.push_back (importmode2string (ImportToTrack));
1094 action_strings.push_back (importmode2string (ImportAsTrack));
1095 action_strings.push_back (importmode2string (ImportAsRegion));
1096 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1098 resetting_ourselves = true;
1100 existing_choice = action_combo.get_active_text();
1102 set_popdown_strings (action_combo, action_strings);
1104 /* preserve any existing choice, if possible */
1107 if (existing_choice.length()) {
1108 vector<string>::iterator x;
1109 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1110 if (*x == existing_choice) {
1111 action_combo.set_active_text (existing_choice);
1115 if (x == action_strings.end()) {
1116 action_combo.set_active_text (action_strings.front());
1119 action_combo.set_active_text (action_strings.front());
1122 resetting_ourselves = false;
1124 if ((mode = get_mode()) == ImportAsRegion) {
1125 where_combo.set_sensitive (false);
1127 where_combo.set_sensitive (true);
1130 vector<string> channel_strings;
1132 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1133 channel_strings.push_back (_("one track per file"));
1135 if (selection_includes_multichannel) {
1136 channel_strings.push_back (_("one track per channel"));
1139 if (paths.size() > 1) {
1140 /* tape tracks are a single region per track, so we cannot
1141 sequence multiple files.
1143 if (mode != ImportAsTapeTrack) {
1144 channel_strings.push_back (_("sequence files"));
1147 channel_strings.push_back (_("all files in one track"));
1148 channel_strings.push_back (_("merge files"));
1154 channel_strings.push_back (_("one region per file"));
1156 if (selection_includes_multichannel) {
1157 channel_strings.push_back (_("one region per channel"));
1160 if (paths.size() > 1) {
1162 channel_strings.push_back (_("all files in one region"));
1167 resetting_ourselves = true;
1169 existing_choice = channel_combo.get_active_text();
1171 set_popdown_strings (channel_combo, channel_strings);
1173 /* preserve any existing choice, if possible */
1175 if (existing_choice.length()) {
1176 vector<string>::iterator x;
1177 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1178 if (*x == existing_choice) {
1179 channel_combo.set_active_text (existing_choice);
1183 if (x == channel_strings.end()) {
1184 channel_combo.set_active_text (channel_strings.front());
1187 channel_combo.set_active_text (channel_strings.front());
1190 resetting_ourselves = false;
1193 src_combo.set_sensitive (true);
1195 src_combo.set_sensitive (false);
1198 if (Config->get_only_copy_imported_files()) {
1200 if (selection_can_be_embedded_with_links) {
1201 copy_files_btn.set_sensitive (true);
1203 copy_files_btn.set_sensitive (false);
1208 copy_files_btn.set_sensitive (true);
1216 SoundFileOmega::bad_file_message()
1218 MessageDialog msg (*this,
1219 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1224 resetting_ourselves = true;
1225 chooser.unselect_uri (chooser.get_preview_uri());
1226 resetting_ourselves = false;
1232 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1241 multichannel = false;
1243 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1245 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1246 if (info.channels > 1) {
1247 multichannel = true;
1252 if (sz != info.length) {
1257 if (info.samplerate != _session->frame_rate()) {
1261 } else if (SMFSource::safe_midi_file_extension (*i)) {
1265 if (reader.num_tracks() > 1) {
1266 multichannel = true; // "channel" == track here...
1269 /* XXX we need err = true handling here in case
1270 we can't check the file
1283 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1285 sys::path path = s->session_directory().sound_path() / "linktest";
1286 string tmpdir = path.to_string();
1289 if (mkdir (tmpdir.c_str(), 0744)) {
1290 if (errno != EEXIST) {
1295 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1297 char tmpc[MAXPATHLEN+1];
1299 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1303 if (link ((*i).c_str(), tmpc)) {
1313 rmdir (tmpdir.c_str());
1317 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1318 : SoundFileBrowser (parent, title, s, false)
1320 chooser.set_select_multiple (false);
1321 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1322 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1326 SoundFileChooser::on_hide ()
1328 ArdourDialog::on_hide();
1332 _session->cancel_audition();
1337 SoundFileChooser::get_filename ()
1339 vector<string> paths;
1341 paths = get_paths ();
1343 if (paths.empty()) {
1347 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1351 return paths.front();
1354 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s,
1355 uint32_t selected_audio_tracks,
1356 uint32_t selected_midi_tracks,
1358 Editing::ImportMode mode_hint)
1359 : SoundFileBrowser (parent, title, s, persistent)
1360 , copy_files_btn ( _("Copy files to session"))
1361 , selected_audio_track_cnt (selected_audio_tracks)
1362 , selected_midi_track_cnt (selected_midi_tracks)
1368 set_size_request (-1, 450);
1370 block_two.set_border_width (12);
1371 block_three.set_border_width (12);
1372 block_four.set_border_width (12);
1374 options.set_spacing (12);
1377 str.push_back (_("file timestamp"));
1378 str.push_back (_("edit point"));
1379 str.push_back (_("playhead"));
1380 str.push_back (_("session start"));
1381 set_popdown_strings (where_combo, str);
1382 where_combo.set_active_text (str.front());
1384 Label* l = manage (new Label);
1385 l->set_text (_("Add files:"));
1387 hbox = manage (new HBox);
1388 hbox->set_border_width (12);
1389 hbox->set_spacing (6);
1390 hbox->pack_start (*l, false, false);
1391 hbox->pack_start (action_combo, false, false);
1392 vbox = manage (new VBox);
1393 vbox->pack_start (*hbox, false, false);
1394 options.pack_start (*vbox, false, false);
1396 /* dummy entry for action combo so that it doesn't look odd if we
1397 come up with no tracks selected.
1401 str.push_back (importmode2string (mode_hint));
1402 set_popdown_strings (action_combo, str);
1403 action_combo.set_active_text (str.front());
1404 action_combo.set_sensitive (false);
1406 l = manage (new Label);
1407 l->set_text (_("Insert at:"));
1409 hbox = manage (new HBox);
1410 hbox->set_border_width (12);
1411 hbox->set_spacing (6);
1412 hbox->pack_start (*l, false, false);
1413 hbox->pack_start (where_combo, false, false);
1414 vbox = manage (new VBox);
1415 vbox->pack_start (*hbox, false, false);
1416 options.pack_start (*vbox, false, false);
1419 l = manage (new Label);
1420 l->set_text (_("Mapping:"));
1422 hbox = manage (new HBox);
1423 hbox->set_border_width (12);
1424 hbox->set_spacing (6);
1425 hbox->pack_start (*l, false, false);
1426 hbox->pack_start (channel_combo, false, false);
1427 vbox = manage (new VBox);
1428 vbox->pack_start (*hbox, false, false);
1429 options.pack_start (*vbox, false, false);
1432 str.push_back (_("one track per file"));
1433 set_popdown_strings (channel_combo, str);
1434 channel_combo.set_active_text (str.front());
1435 channel_combo.set_sensitive (false);
1437 l = manage (new Label);
1438 l->set_text (_("Conversion quality:"));
1440 hbox = manage (new HBox);
1441 hbox->set_border_width (12);
1442 hbox->set_spacing (6);
1443 hbox->pack_start (*l, false, false);
1444 hbox->pack_start (src_combo, false, false);
1445 vbox = manage (new VBox);
1446 vbox->pack_start (*hbox, false, false);
1447 options.pack_start (*vbox, false, false);
1450 str.push_back (_("Best"));
1451 str.push_back (_("Good"));
1452 str.push_back (_("Quick"));
1453 str.push_back (_("Fast"));
1454 str.push_back (_("Fastest"));
1456 set_popdown_strings (src_combo, str);
1457 src_combo.set_active_text (str.front());
1458 src_combo.set_sensitive (false);
1462 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1463 channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1465 copy_files_btn.set_active (true);
1467 block_four.pack_start (copy_files_btn, false, false);
1469 options.pack_start (block_four, false, false);
1471 get_vbox()->pack_start (options, false, false);
1473 /* setup disposition map */
1475 disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1476 disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1477 disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1478 disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1480 disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1481 disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1482 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1483 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1485 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1487 /* set size requests for a couple of combos to allow them to display the longest text
1488 they will ever be asked to display. This prevents them being resized when the user
1489 selects a file to import, which in turn prevents the size of the dialog from jumping
1493 t.push_back (_("one track per file"));
1494 t.push_back (_("one track per channel"));
1495 t.push_back (_("sequence files"));
1496 t.push_back (_("all files in one region"));
1497 set_popdown_strings (channel_combo, t);
1500 t.push_back (importmode2string (ImportAsTrack));
1501 t.push_back (importmode2string (ImportToTrack));
1502 t.push_back (importmode2string (ImportAsRegion));
1503 t.push_back (importmode2string (ImportAsTapeTrack));
1504 set_popdown_strings (action_combo, t);
1508 SoundFileOmega::set_mode (ImportMode mode)
1510 action_combo.set_active_text (importmode2string (mode));
1514 SoundFileOmega::get_mode () const
1516 return string2importmode (action_combo.get_active_text());
1520 SoundFileOmega::on_hide ()
1522 ArdourDialog::on_hide();
1524 _session->cancel_audition();
1529 SoundFileOmega::get_position() const
1531 string str = where_combo.get_active_text();
1533 if (str == _("file timestamp")) {
1534 return ImportAtTimestamp;
1535 } else if (str == _("edit point")) {
1536 return ImportAtEditPoint;
1537 } else if (str == _("playhead")) {
1538 return ImportAtPlayhead;
1540 return ImportAtStart;
1545 SoundFileOmega::get_src_quality() const
1547 string str = where_combo.get_active_text();
1549 if (str == _("Best")) {
1551 } else if (str == _("Good")) {
1553 } else if (str == _("Quick")) {
1555 } else if (str == _("Fast")) {
1563 SoundFileOmega::get_channel_disposition () const
1565 /* we use a map here because the channel combo can contain different strings
1566 depending on the state of the other combos. the map contains all possible strings
1567 and the ImportDisposition enum that corresponds to it.
1570 string str = channel_combo.get_active_text();
1571 DispositionMap::const_iterator x = disposition_map.find (str);
1573 if (x == disposition_map.end()) {
1574 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1582 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1584 selected_audio_track_cnt = selected_audio_tracks;
1585 selected_midi_track_cnt = selected_midi_tracks;
1590 SoundFileOmega::file_selection_changed ()
1592 if (resetting_ourselves) {
1596 if (!reset_options ()) {
1597 set_response_sensitive (RESPONSE_OK, false);
1599 if (chooser.get_filenames().size() > 0) {
1600 set_response_sensitive (RESPONSE_OK, true);
1602 set_response_sensitive (RESPONSE_OK, false);