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_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
451 audio_filter.set_name (_("Audio files"));
453 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
454 midi_filter.set_name (_("MIDI files"));
456 matchall_filter.add_pattern ("*.*");
457 matchall_filter.set_name (_("All files"));
459 chooser.add_filter (audio_filter);
460 chooser.add_filter (midi_filter);
461 chooser.add_filter (matchall_filter);
462 chooser.set_select_multiple (true);
463 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
464 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
466 /* some broken redraw behaviour - this is a bandaid */
467 chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
470 if (!persistent_folder.empty()) {
471 chooser.set_current_folder (persistent_folder);
473 notebook.append_page (chooser, _("Browse Files"));
476 hpacker.set_spacing (6);
477 hpacker.pack_start (notebook, true, true);
478 hpacker.pack_start (preview, false, false);
480 get_vbox()->pack_start (hpacker, true, true);
488 hbox = manage(new HBox);
489 hbox->pack_start (found_entry);
490 hbox->pack_start (found_search_btn);
492 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
493 scroll->add(found_list_view);
494 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
496 vbox = manage(new VBox);
497 vbox->pack_start (*hbox, PACK_SHRINK);
498 vbox->pack_start (*scroll);
500 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
502 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
504 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
506 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
507 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
509 freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
511 notebook.append_page (*vbox, _("Search Tags"));
514 //add freesound search
521 passbox = manage(new HBox);
522 passbox->set_border_width (12);
523 passbox->set_spacing (6);
525 label = manage (new Label);
526 label->set_text (_("Tags:"));
527 passbox->pack_start (*label, false, false);
528 passbox->pack_start (freesound_entry, false, false);
530 label = manage (new Label);
531 label->set_text (_("Sort:"));
532 passbox->pack_start (*label, false, false);
533 passbox->pack_start (freesound_sort, false, false);
534 freesound_sort.clear_items();
536 // Order of the following must correspond with enum sortMethod
537 // in sfdb_freesound_mootcher.h
538 freesound_sort.append_text(_("None"));
539 freesound_sort.append_text(_("Longest"));
540 freesound_sort.append_text(_("Shortest"));
541 freesound_sort.append_text(_("Newest"));
542 freesound_sort.append_text(_("Oldest"));
543 freesound_sort.append_text(_("Most downloaded"));
544 freesound_sort.append_text(_("Least downloaded"));
545 freesound_sort.append_text(_("Highest rated"));
546 freesound_sort.append_text(_("Lowest rated"));
547 freesound_sort.set_active(0);
549 passbox->pack_start (freesound_search_btn, false, false);
550 passbox->pack_start (freesound_progress_bar);
551 passbox->pack_end (freesound_stop_btn, false, false);
552 freesound_stop_btn.set_label(_("Stop"));
554 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
555 scroll->add(freesound_list_view);
556 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
558 vbox = manage(new VBox);
559 vbox->pack_start (*passbox, PACK_SHRINK);
560 vbox->pack_start (*scroll);
562 freesound_list_view.append_column(_("ID") , freesound_list_columns.id);
563 freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
564 // freesound_list_view.append_column(_("URI") , freesound_list_columns.uri);
565 freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
566 freesound_list_view.get_column(1)->set_expand(true);
568 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
570 freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
571 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
572 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
573 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
574 freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
575 notebook.append_page (*vbox, _("Search Freesound"));
581 notebook.set_size_request (500, -1);
585 add_button (Stock::CANCEL, RESPONSE_CANCEL);
586 add_button (Stock::APPLY, RESPONSE_APPLY);
587 add_button (Stock::OK, RESPONSE_OK);
591 SoundFileBrowser::~SoundFileBrowser ()
593 persistent_folder = chooser.get_current_folder();
598 SoundFileBrowser::on_show ()
600 ArdourDialog::on_show ();
605 SoundFileBrowser::clear_selection ()
607 chooser.unselect_all ();
608 found_list_view.get_selection()->unselect_all ();
612 SoundFileBrowser::chooser_file_activated ()
618 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
624 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
630 SoundFileBrowser::set_session (Session* s)
632 ArdourDialog::set_session (s);
633 preview.set_session (s);
638 remove_gain_meter ();
643 SoundFileBrowser::add_gain_meter ()
647 gm = new GainMeter (_session, 250);
649 boost::shared_ptr<Route> r = _session->the_auditioner ();
651 gm->set_controls (r, r->shared_peak_meter(), r->amp());
653 meter_packer.set_border_width (12);
654 meter_packer.pack_start (*gm, false, true);
655 hpacker.pack_end (meter_packer, false, false);
656 meter_packer.show_all ();
661 SoundFileBrowser::remove_gain_meter ()
664 meter_packer.remove (*gm);
665 hpacker.remove (meter_packer);
672 SoundFileBrowser::start_metering ()
674 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
678 SoundFileBrowser::stop_metering ()
680 metering_connection.disconnect();
684 SoundFileBrowser::meter ()
686 if (is_mapped () && _session && gm) {
687 gm->update_meters ();
692 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
694 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
698 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
700 return SMFSource::safe_midi_file_extension (filter_info.filename);
704 SoundFileBrowser::update_preview ()
706 if (preview.setup_labels (chooser.get_filename())) {
707 if (preview.autoplay()) {
708 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
714 SoundFileBrowser::found_list_view_selected ()
716 if (!reset_options ()) {
717 set_response_sensitive (RESPONSE_OK, false);
721 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
724 TreeIter iter = found_list->get_iter(*rows.begin());
725 file = (*iter)[found_list_columns.pathname];
726 chooser.set_filename (file);
727 set_response_sensitive (RESPONSE_OK, true);
729 set_response_sensitive (RESPONSE_OK, false);
732 preview.setup_labels (file);
737 SoundFileBrowser::freesound_list_view_selected ()
739 freesound_download_cancel = false;
742 if (!reset_options ()) {
743 set_response_sensitive (RESPONSE_OK, false);
748 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
751 TreeIter iter = freesound_list->get_iter(*rows.begin());
753 string id = (*iter)[freesound_list_columns.id];
754 string uri = (*iter)[freesound_list_columns.uri];
755 string ofn = (*iter)[freesound_list_columns.filename];
757 // download the sound file
758 GdkCursor *prev_cursor;
759 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
760 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
763 file = mootcher->getAudioFile(ofn, id, uri, this);
765 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
768 chooser.set_filename (file);
769 set_response_sensitive (RESPONSE_OK, true);
772 set_response_sensitive (RESPONSE_OK, false);
775 preview.setup_labels (file);
781 SoundFileBrowser::found_search_clicked ()
783 string tag_string = found_entry.get_text ();
787 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
788 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
792 vector<string> results;
793 Library->search_members_and (results, tags);
796 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
797 TreeModel::iterator new_row = found_list->append();
798 TreeModel::Row row = *new_row;
799 string path = Glib::filename_from_uri (string ("file:") + *i);
800 row[found_list_columns.pathname] = path;
805 SoundFileBrowser::freesound_search_clicked ()
807 freesound_search_cancel = false;
812 SoundFileBrowser::freesound_stop_clicked ()
814 freesound_download_cancel = true;
815 freesound_search_cancel = true;
820 SoundFileBrowser::freesound_search()
823 freesound_list->clear();
825 string search_string = freesound_entry.get_text ();
826 enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
828 GdkCursor *prev_cursor;
829 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
830 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
832 for (int page = 1; page <= 99; page++ ) {
835 prog = string_compose (_("Page %1, [Stop]->"), page);
836 freesound_progress_bar.set_text(prog);
837 while (Glib::MainContext::get_default()->iteration (false)) {
841 std::string theString = mootcher->searchText(
844 "", // filter, could do, e.g. "type:wav"
849 doc.read_buffer( theString );
850 XMLNode *root = doc.root();
853 cerr << "no root XML node!" << endl;
857 if ( strcmp(root->name().c_str(), "response") != 0) {
858 cerr << "root node name == " << root->name() << ", != \"response\"!" << endl;
862 XMLNode *sounds_root = root->child("sounds");
865 cerr << "no child node \"sounds\" found!" << endl;
869 XMLNodeList sounds = sounds_root->children();
870 XMLNodeConstIterator niter;
872 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
874 if( strcmp( node->name().c_str(), "resource") != 0 ){
875 cerr << "node->name()=" << node->name() << ",!= \"resource\"!" << endl;
876 freesound_search_cancel = true;
880 // node->dump(cerr, "node:");
882 XMLNode *id_node = node->child ("id");
883 XMLNode *uri_node = node->child ("serve");
884 XMLNode *ofn_node = node->child ("original_filename");
885 XMLNode *dur_node = node->child ("duration");
887 if (id_node && uri_node && ofn_node) {
889 std::string id = id_node->child("text")->content();
890 std::string uri = uri_node->child("text")->content();
891 std::string ofn = ofn_node->child("text")->content();
892 std::string dur = dur_node->child("text")->content();
895 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
897 double duration_seconds = atof(dur.c_str());
899 char duration_hhmmss[16];
900 if (duration_seconds >= 99 * 60 * 60) {
901 strcpy(duration_hhmmss, ">99h");
903 s = modf(duration_seconds/60, &m) * 60;
904 m = modf(m/60, &h) * 60;
905 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
910 TreeModel::iterator new_row = freesound_list->append();
911 TreeModel::Row row = *new_row;
913 row[freesound_list_columns.id ] = id;
914 row[freesound_list_columns.uri ] = uri;
915 row[freesound_list_columns.filename] = ofn;
916 row[freesound_list_columns.duration] = duration_hhmmss;
921 if (freesound_search_cancel)
926 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
928 freesound_progress_bar.set_text("");
934 SoundFileBrowser::get_paths ()
936 vector<string> results;
938 int n = notebook.get_current_page ();
941 vector<string> filenames = chooser.get_filenames();
942 vector<string>::iterator i;
944 for (i = filenames.begin(); i != filenames.end(); ++i) {
946 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
947 results.push_back (*i);
953 typedef TreeView::Selection::ListHandle_Path ListPath;
955 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
956 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
957 TreeIter iter = found_list->get_iter(*i);
958 string str = (*iter)[found_list_columns.pathname];
960 results.push_back (str);
964 typedef TreeView::Selection::ListHandle_Path ListPath;
966 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
967 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
968 TreeIter iter = freesound_list->get_iter(*i);
969 string id = (*iter)[freesound_list_columns.id];
970 string uri = (*iter)[freesound_list_columns.uri];
971 string ofn = (*iter)[freesound_list_columns.filename];
973 GdkCursor *prev_cursor;
974 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
975 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
978 string str = mootcher->getAudioFile(ofn, id, uri, this);
980 results.push_back (str);
983 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
993 SoundFileOmega::reset_options_noret ()
995 if (!resetting_ourselves) {
996 (void) reset_options ();
1001 SoundFileOmega::reset_options ()
1003 vector<string> paths = get_paths ();
1005 if (paths.empty()) {
1007 channel_combo.set_sensitive (false);
1008 action_combo.set_sensitive (false);
1009 where_combo.set_sensitive (false);
1010 copy_files_btn.set_sensitive (false);
1016 channel_combo.set_sensitive (true);
1017 action_combo.set_sensitive (true);
1018 where_combo.set_sensitive (true);
1020 /* if we get through this function successfully, this may be
1021 reset at the end, once we know if we can use hard links
1025 if (Config->get_only_copy_imported_files()) {
1026 copy_files_btn.set_sensitive (false);
1028 copy_files_btn.set_sensitive (false);
1034 bool selection_includes_multichannel;
1035 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1038 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1039 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1043 string existing_choice;
1044 vector<string> action_strings;
1046 if (chooser.get_filter() == &audio_filter) {
1050 if (selected_audio_track_cnt > 0) {
1051 if (channel_combo.get_active_text().length()) {
1052 ImportDisposition id = get_channel_disposition();
1055 case Editing::ImportDistinctFiles:
1056 if (selected_audio_track_cnt == paths.size()) {
1057 action_strings.push_back (importmode2string (ImportToTrack));
1061 case Editing::ImportDistinctChannels:
1062 /* XXX it would be nice to allow channel-per-selected track
1063 but its too hard we don't want to deal with all the
1064 different per-file + per-track channel configurations.
1069 action_strings.push_back (importmode2string (ImportToTrack));
1079 if (selected_midi_track_cnt > 0) {
1080 action_strings.push_back (importmode2string (ImportToTrack));
1084 action_strings.push_back (importmode2string (ImportAsTrack));
1085 action_strings.push_back (importmode2string (ImportAsRegion));
1086 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1088 resetting_ourselves = true;
1090 existing_choice = action_combo.get_active_text();
1092 set_popdown_strings (action_combo, action_strings);
1094 /* preserve any existing choice, if possible */
1097 if (existing_choice.length()) {
1098 vector<string>::iterator x;
1099 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1100 if (*x == existing_choice) {
1101 action_combo.set_active_text (existing_choice);
1105 if (x == action_strings.end()) {
1106 action_combo.set_active_text (action_strings.front());
1109 action_combo.set_active_text (action_strings.front());
1112 resetting_ourselves = false;
1114 if ((mode = get_mode()) == ImportAsRegion) {
1115 where_combo.set_sensitive (false);
1117 where_combo.set_sensitive (true);
1120 vector<string> channel_strings;
1122 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1123 channel_strings.push_back (_("one track per file"));
1125 if (selection_includes_multichannel) {
1126 channel_strings.push_back (_("one track per channel"));
1129 if (paths.size() > 1) {
1130 /* tape tracks are a single region per track, so we cannot
1131 sequence multiple files.
1133 if (mode != ImportAsTapeTrack) {
1134 channel_strings.push_back (_("sequence files"));
1137 channel_strings.push_back (_("all files in one track"));
1138 channel_strings.push_back (_("merge files"));
1144 channel_strings.push_back (_("one region per file"));
1146 if (selection_includes_multichannel) {
1147 channel_strings.push_back (_("one region per channel"));
1150 if (paths.size() > 1) {
1152 channel_strings.push_back (_("all files in one region"));
1157 resetting_ourselves = true;
1159 existing_choice = channel_combo.get_active_text();
1161 set_popdown_strings (channel_combo, channel_strings);
1163 /* preserve any existing choice, if possible */
1165 if (existing_choice.length()) {
1166 vector<string>::iterator x;
1167 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1168 if (*x == existing_choice) {
1169 channel_combo.set_active_text (existing_choice);
1173 if (x == channel_strings.end()) {
1174 channel_combo.set_active_text (channel_strings.front());
1177 channel_combo.set_active_text (channel_strings.front());
1180 resetting_ourselves = false;
1183 src_combo.set_sensitive (true);
1185 src_combo.set_sensitive (false);
1188 if (Config->get_only_copy_imported_files()) {
1190 if (selection_can_be_embedded_with_links) {
1191 copy_files_btn.set_sensitive (true);
1193 copy_files_btn.set_sensitive (false);
1198 copy_files_btn.set_sensitive (true);
1206 SoundFileOmega::bad_file_message()
1208 MessageDialog msg (*this,
1209 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1214 resetting_ourselves = true;
1215 chooser.unselect_uri (chooser.get_preview_uri());
1216 resetting_ourselves = false;
1222 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1231 multichannel = false;
1233 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1235 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1236 if (info.channels > 1) {
1237 multichannel = true;
1242 if (sz != info.length) {
1247 if (info.samplerate != _session->frame_rate()) {
1251 } else if (SMFSource::safe_midi_file_extension (*i)) {
1255 if (reader.num_tracks() > 1) {
1256 multichannel = true; // "channel" == track here...
1259 /* XXX we need err = true handling here in case
1260 we can't check the file
1273 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1275 sys::path path = s->session_directory().sound_path() / "linktest";
1276 string tmpdir = path.to_string();
1279 if (mkdir (tmpdir.c_str(), 0744)) {
1280 if (errno != EEXIST) {
1285 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1287 char tmpc[MAXPATHLEN+1];
1289 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1293 if (link ((*i).c_str(), tmpc)) {
1303 rmdir (tmpdir.c_str());
1307 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1308 : SoundFileBrowser (parent, title, s, false)
1310 chooser.set_select_multiple (false);
1311 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1312 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1316 SoundFileChooser::on_hide ()
1318 ArdourDialog::on_hide();
1322 _session->cancel_audition();
1327 SoundFileChooser::get_filename ()
1329 vector<string> paths;
1331 paths = get_paths ();
1333 if (paths.empty()) {
1337 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1341 return paths.front();
1344 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s,
1345 uint32_t selected_audio_tracks,
1346 uint32_t selected_midi_tracks,
1348 Editing::ImportMode mode_hint)
1349 : SoundFileBrowser (parent, title, s, persistent)
1350 , copy_files_btn ( _("Copy files to session"))
1351 , selected_audio_track_cnt (selected_audio_tracks)
1352 , selected_midi_track_cnt (selected_midi_tracks)
1358 set_size_request (-1, 450);
1360 block_two.set_border_width (12);
1361 block_three.set_border_width (12);
1362 block_four.set_border_width (12);
1364 options.set_spacing (12);
1367 str.push_back (_("file timestamp"));
1368 str.push_back (_("edit point"));
1369 str.push_back (_("playhead"));
1370 str.push_back (_("session start"));
1371 set_popdown_strings (where_combo, str);
1372 where_combo.set_active_text (str.front());
1374 Label* l = manage (new Label);
1375 l->set_text (_("Add files:"));
1377 hbox = manage (new HBox);
1378 hbox->set_border_width (12);
1379 hbox->set_spacing (6);
1380 hbox->pack_start (*l, false, false);
1381 hbox->pack_start (action_combo, false, false);
1382 vbox = manage (new VBox);
1383 vbox->pack_start (*hbox, false, false);
1384 options.pack_start (*vbox, false, false);
1386 /* dummy entry for action combo so that it doesn't look odd if we
1387 come up with no tracks selected.
1391 str.push_back (importmode2string (mode_hint));
1392 set_popdown_strings (action_combo, str);
1393 action_combo.set_active_text (str.front());
1394 action_combo.set_sensitive (false);
1396 l = manage (new Label);
1397 l->set_text (_("Insert at:"));
1399 hbox = manage (new HBox);
1400 hbox->set_border_width (12);
1401 hbox->set_spacing (6);
1402 hbox->pack_start (*l, false, false);
1403 hbox->pack_start (where_combo, false, false);
1404 vbox = manage (new VBox);
1405 vbox->pack_start (*hbox, false, false);
1406 options.pack_start (*vbox, false, false);
1409 l = manage (new Label);
1410 l->set_text (_("Mapping:"));
1412 hbox = manage (new HBox);
1413 hbox->set_border_width (12);
1414 hbox->set_spacing (6);
1415 hbox->pack_start (*l, false, false);
1416 hbox->pack_start (channel_combo, false, false);
1417 vbox = manage (new VBox);
1418 vbox->pack_start (*hbox, false, false);
1419 options.pack_start (*vbox, false, false);
1422 str.push_back (_("one track per file"));
1423 set_popdown_strings (channel_combo, str);
1424 channel_combo.set_active_text (str.front());
1425 channel_combo.set_sensitive (false);
1427 l = manage (new Label);
1428 l->set_text (_("Conversion quality:"));
1430 hbox = manage (new HBox);
1431 hbox->set_border_width (12);
1432 hbox->set_spacing (6);
1433 hbox->pack_start (*l, false, false);
1434 hbox->pack_start (src_combo, false, false);
1435 vbox = manage (new VBox);
1436 vbox->pack_start (*hbox, false, false);
1437 options.pack_start (*vbox, false, false);
1440 str.push_back (_("Best"));
1441 str.push_back (_("Good"));
1442 str.push_back (_("Quick"));
1443 str.push_back (_("Fast"));
1444 str.push_back (_("Fastest"));
1446 set_popdown_strings (src_combo, str);
1447 src_combo.set_active_text (str.front());
1448 src_combo.set_sensitive (false);
1452 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1453 channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1455 copy_files_btn.set_active (true);
1457 block_four.pack_start (copy_files_btn, false, false);
1459 options.pack_start (block_four, false, false);
1461 get_vbox()->pack_start (options, false, false);
1463 /* setup disposition map */
1465 disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1466 disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1467 disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1468 disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1470 disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1471 disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1472 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1473 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1475 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1477 /* set size requests for a couple of combos to allow them to display the longest text
1478 they will ever be asked to display. This prevents them being resized when the user
1479 selects a file to import, which in turn prevents the size of the dialog from jumping
1483 t.push_back (_("one track per file"));
1484 t.push_back (_("one track per channel"));
1485 t.push_back (_("sequence files"));
1486 t.push_back (_("all files in one region"));
1487 set_popdown_strings (channel_combo, t);
1490 t.push_back (importmode2string (ImportAsTrack));
1491 t.push_back (importmode2string (ImportToTrack));
1492 t.push_back (importmode2string (ImportAsRegion));
1493 t.push_back (importmode2string (ImportAsTapeTrack));
1494 set_popdown_strings (action_combo, t);
1498 SoundFileOmega::set_mode (ImportMode mode)
1500 action_combo.set_active_text (importmode2string (mode));
1504 SoundFileOmega::get_mode () const
1506 return string2importmode (action_combo.get_active_text());
1510 SoundFileOmega::on_hide ()
1512 ArdourDialog::on_hide();
1514 _session->cancel_audition();
1519 SoundFileOmega::get_position() const
1521 string str = where_combo.get_active_text();
1523 if (str == _("file timestamp")) {
1524 return ImportAtTimestamp;
1525 } else if (str == _("edit point")) {
1526 return ImportAtEditPoint;
1527 } else if (str == _("playhead")) {
1528 return ImportAtPlayhead;
1530 return ImportAtStart;
1535 SoundFileOmega::get_src_quality() const
1537 string str = where_combo.get_active_text();
1539 if (str == _("Best")) {
1541 } else if (str == _("Good")) {
1543 } else if (str == _("Quick")) {
1545 } else if (str == _("Fast")) {
1553 SoundFileOmega::get_channel_disposition () const
1555 /* we use a map here because the channel combo can contain different strings
1556 depending on the state of the other combos. the map contains all possible strings
1557 and the ImportDisposition enum that corresponds to it.
1560 string str = channel_combo.get_active_text();
1561 DispositionMap::const_iterator x = disposition_map.find (str);
1563 if (x == disposition_map.end()) {
1564 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1572 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1574 selected_audio_track_cnt = selected_audio_tracks;
1575 selected_midi_track_cnt = selected_midi_tracks;
1580 SoundFileOmega::file_selection_changed ()
1582 if (resetting_ourselves) {
1586 if (!reset_options ()) {
1587 set_response_sensitive (RESPONSE_OK, false);
1589 if (chooser.get_filenames().size() > 0) {
1590 set_response_sensitive (RESPONSE_OK, true);
1592 set_response_sensitive (RESPONSE_OK, false);