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.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
182 Label* label = manage (new Label (_("Tags:")));
183 label->set_alignment (0.0f, 0.5f);
184 main_box.pack_start (*label, false, false);
185 main_box.pack_start (tags_entry, true, true);
187 main_box.pack_start (bottom_box, false, false);
189 play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
190 play_btn.set_label (_("Play"));
192 stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
193 stop_btn.set_label (_("Stop"));
195 bottom_box.set_homogeneous (false);
196 bottom_box.set_spacing (6);
197 bottom_box.pack_start(play_btn, true, true);
198 bottom_box.pack_start(stop_btn, true, true);
199 bottom_box.pack_start(autoplay_btn, false, false);
201 play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
202 stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
204 channels_value.set_alignment (0.0f, 0.5f);
205 samplerate_value.set_alignment (0.0f, 0.5f);
209 SoundFileBox::set_session(Session* s)
211 SessionHandlePtr::set_session (s);
213 length_clock.set_session (s);
214 timecode_clock.set_session (s);
217 play_btn.set_sensitive (false);
218 stop_btn.set_sensitive (false);
223 SoundFileBox::setup_labels (const string& filename)
226 // save existing tags
234 if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
236 preview_label.set_markup (_("<b>Sound File Information</b>"));
237 format_text.set_text ("");
238 channels_value.set_text ("");
239 samplerate_value.set_text ("");
240 tags_entry.get_buffer()->set_text ("");
242 length_clock.set (0);
243 timecode_clock.set (0);
245 tags_entry.set_sensitive (false);
246 play_btn.set_sensitive (false);
251 preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
252 std::string n = sf_info.format_name;
253 if (n.substr (0, 8) == X_("Format: ")) {
256 format_text.set_text (n);
257 channels_value.set_text (to_string (sf_info.channels, std::dec));
259 if (_session && sf_info.samplerate != _session->frame_rate()) {
260 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
261 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
262 samplerate_value.set_name ("NewSessionSR1Label");
263 samplerate.set_name ("NewSessionSR1Label");
265 samplerate.set_text (_("Sample rate:"));
266 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
267 samplerate_value.set_name ("NewSessionSR2Label");
268 samplerate.set_name ("NewSessionSR2Label");
271 framecnt_t const nfr = _session ? _session->nominal_frame_rate() : 25;
272 double src_coef = (double) nfr / sf_info.samplerate;
274 length_clock.set (sf_info.length * src_coef + 0.5, true);
275 timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
277 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
279 vector<string> tags = Library->get_tags (string ("//") + filename);
281 stringstream tag_string;
282 for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
283 if (i != tags.begin()) {
288 tags_entry.get_buffer()->set_text (tag_string.str());
290 tags_entry.set_sensitive (true);
292 play_btn.set_sensitive (true);
299 SoundFileBox::autoplay() const
301 return autoplay_btn.get_active();
305 SoundFileBox::audition_oneshot()
312 SoundFileBox::audition ()
318 if (SMFSource::safe_midi_file_extension (path)) {
319 error << _("Auditioning of MIDI files is not yet supported") << endmsg;
323 _session->cancel_audition();
325 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
326 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
330 boost::shared_ptr<Region> r;
332 boost::shared_ptr<AudioFileSource> afs;
333 bool old_sbp = AudioSource::get_build_peakfiles ();
335 /* don't even think of building peakfiles for these files */
337 AudioSource::set_build_peakfiles (false);
339 for (int n = 0; n < sf_info.channels; ++n) {
341 afs = boost::dynamic_pointer_cast<AudioFileSource> (
342 SourceFactory::createReadable (DataType::AUDIO, *_session,
343 path, n, Source::Flag (0), false));
345 srclist.push_back(afs);
347 } catch (failed_constructor& err) {
348 error << _("Could not access soundfile: ") << path << endmsg;
349 AudioSource::set_build_peakfiles (old_sbp);
354 AudioSource::set_build_peakfiles (old_sbp);
356 if (srclist.empty()) {
360 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
361 string rname = region_name_from_path (afs->path(), false);
365 plist.add (ARDOUR::Properties::start, 0);
366 plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
367 plist.add (ARDOUR::Properties::name, rname);
368 plist.add (ARDOUR::Properties::layer, 0);
370 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
372 _session->audition_region(r);
376 SoundFileBox::stop_audition ()
379 _session->cancel_audition();
384 SoundFileBox::tags_entry_left (GdkEventFocus *)
391 SoundFileBox::tags_changed ()
393 string tag_string = tags_entry.get_buffer()->get_text ();
395 if (tag_string.empty()) {
401 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
402 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
410 SoundFileBox::save_tags (const vector<string>& tags)
412 Library->set_tags (string ("//") + path, tags);
413 Library->save_changes ();
416 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
417 : ArdourDialog (parent, title, false, false),
418 found_list (ListStore::create(found_list_columns)),
419 freesound_list (ListStore::create(freesound_list_columns)),
420 chooser (FILE_CHOOSER_ACTION_OPEN),
421 preview (persistent),
422 found_search_btn (_("Search")),
423 found_list_view (found_list),
424 freesound_search_btn (_("Search")),
425 freesound_list_view (freesound_list)
427 resetting_ourselves = false;
430 resetting_ourselves = false;
434 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
435 chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
436 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
438 chooser.add_shortcut_folder_uri("file:///Volumes");
441 //add the file chooser
443 chooser.set_border_width (12);
445 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
446 audio_filter.set_name (_("Audio files"));
448 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
449 midi_filter.set_name (_("MIDI files"));
451 matchall_filter.add_pattern ("*.*");
452 matchall_filter.set_name (_("All files"));
454 chooser.add_filter (audio_filter);
455 chooser.add_filter (midi_filter);
456 chooser.add_filter (matchall_filter);
457 chooser.set_select_multiple (true);
458 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
459 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
461 /* some broken redraw behaviour - this is a bandaid */
462 chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
465 if (!persistent_folder.empty()) {
466 chooser.set_current_folder (persistent_folder);
468 notebook.append_page (chooser, _("Browse Files"));
471 hpacker.set_spacing (6);
472 hpacker.pack_start (notebook, true, true);
473 hpacker.pack_start (preview, false, false);
475 get_vbox()->pack_start (hpacker, true, true);
483 hbox = manage(new HBox);
484 hbox->pack_start (found_entry);
485 hbox->pack_start (found_search_btn);
487 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
488 scroll->add(found_list_view);
489 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
491 vbox = manage(new VBox);
492 vbox->pack_start (*hbox, PACK_SHRINK);
493 vbox->pack_start (*scroll);
495 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
497 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
499 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
501 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
502 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
504 notebook.append_page (*vbox, _("Search Tags"));
507 //add freesound search
514 passbox = manage(new HBox);
515 passbox->set_border_width (12);
516 passbox->set_spacing (6);
518 label = manage (new Label);
519 label->set_text (_("Tags:"));
520 passbox->pack_start (*label, false, false);
521 passbox->pack_start (freesound_entry, false, false);
523 label = manage (new Label);
524 label->set_text (_("Sort:"));
525 passbox->pack_start (*label, false, false);
526 passbox->pack_start (freesound_sort, false, false);
527 freesound_sort.clear_items();
529 // Order of the following must correspond with enum sortMethod
530 // in sfdb_freesound_mootcher.h
531 freesound_sort.append_text(_("None"));
532 freesound_sort.append_text(_("Longest"));
533 freesound_sort.append_text(_("Shortest"));
534 freesound_sort.append_text(_("Newest"));
535 freesound_sort.append_text(_("Oldest"));
536 freesound_sort.append_text(_("Most downloaded"));
537 freesound_sort.append_text(_("Least downloaded"));
538 freesound_sort.append_text(_("Highest rated"));
539 freesound_sort.append_text(_("Lowest rated"));
540 freesound_sort.set_active(0);
542 label = manage (new Label);
543 label->set_text (_("Page:"));
544 passbox->pack_start (*label, false, false);
545 passbox->pack_start (freesound_page, false, false);
546 freesound_page.set_range(1, 1000);
547 freesound_page.set_increments(1, 10);
549 passbox->pack_start (freesound_search_btn, false, false);
550 passbox->pack_start (progress_bar);
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.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
567 freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
568 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
569 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
570 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
571 freesound_stop_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_stop_clicked));
572 notebook.append_page (*vbox, _("Search Freesound"));
577 notebook.set_size_request (500, -1);
581 add_button (Stock::CANCEL, RESPONSE_CANCEL);
582 add_button (Stock::APPLY, RESPONSE_APPLY);
583 add_button (Stock::OK, RESPONSE_OK);
587 SoundFileBrowser::~SoundFileBrowser ()
589 persistent_folder = chooser.get_current_folder();
594 SoundFileBrowser::on_show ()
596 ArdourDialog::on_show ();
601 SoundFileBrowser::clear_selection ()
603 chooser.unselect_all ();
604 found_list_view.get_selection()->unselect_all ();
608 SoundFileBrowser::chooser_file_activated ()
614 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
620 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
626 SoundFileBrowser::set_session (Session* s)
628 ArdourDialog::set_session (s);
629 preview.set_session (s);
634 remove_gain_meter ();
639 SoundFileBrowser::add_gain_meter ()
643 gm = new GainMeter (_session, 250);
645 boost::shared_ptr<Route> r = _session->the_auditioner ();
647 gm->set_controls (r, r->shared_peak_meter(), r->amp());
649 meter_packer.set_border_width (12);
650 meter_packer.pack_start (*gm, false, true);
651 hpacker.pack_end (meter_packer, false, false);
652 meter_packer.show_all ();
657 SoundFileBrowser::remove_gain_meter ()
660 meter_packer.remove (*gm);
661 hpacker.remove (meter_packer);
668 SoundFileBrowser::start_metering ()
670 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
674 SoundFileBrowser::stop_metering ()
676 metering_connection.disconnect();
680 SoundFileBrowser::meter ()
682 if (is_mapped () && _session && gm) {
683 gm->update_meters ();
688 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
690 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
694 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
696 return SMFSource::safe_midi_file_extension (filter_info.filename);
700 SoundFileBrowser::update_preview ()
702 if (preview.setup_labels (chooser.get_filename())) {
703 if (preview.autoplay()) {
704 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
710 SoundFileBrowser::found_list_view_selected ()
712 if (!reset_options ()) {
713 set_response_sensitive (RESPONSE_OK, false);
717 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
720 TreeIter iter = found_list->get_iter(*rows.begin());
721 file = (*iter)[found_list_columns.pathname];
722 chooser.set_filename (file);
723 set_response_sensitive (RESPONSE_OK, true);
725 set_response_sensitive (RESPONSE_OK, false);
728 preview.setup_labels (file);
733 SoundFileBrowser::freesound_list_view_selected ()
736 if (!reset_options ()) {
737 set_response_sensitive (RESPONSE_OK, false);
741 path = Glib::get_home_dir();
742 path += "/Freesound/";
743 Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser
747 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
750 TreeIter iter = freesound_list->get_iter(*rows.begin());
752 string id = (*iter)[freesound_list_columns.id];
753 string uri = (*iter)[freesound_list_columns.uri];
754 string ofn = (*iter)[freesound_list_columns.filename];
756 // download the sound file
757 GdkCursor *prev_cursor;
758 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
759 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
762 freesound_stop = false;
763 file = theMootcher.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 ()
811 SoundFileBrowser::freesound_stop_clicked ()
813 freesound_stop = true;
818 SoundFileBrowser::freesound_search()
821 freesound_list->clear();
824 path = Glib::get_home_dir();
825 path += "/Freesound/";
826 Mootcher theMootcher(path.c_str());
828 string search_string = freesound_entry.get_text ();
829 enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
830 int page = freesound_page.get_value_as_int();
832 GdkCursor *prev_cursor;
833 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
834 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
837 string theString = theMootcher.searchText(
840 "", // filter, could do, e.g. "type:wav"
844 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
847 doc.read_buffer( theString );
848 XMLNode *root = doc.root();
851 cerr << "no root XML node!" << endl;
855 if ( strcmp(root->name().c_str(), "response") != 0) {
856 cerr << "root node name == " << root->name() << ", != \"response\"!" << endl;
860 XMLNode *sounds_root = root->child("sounds");
863 cerr << "no child node \"sounds\" found!" << endl;
867 XMLNodeList sounds = sounds_root->children();
868 XMLNodeConstIterator niter;
870 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
872 if( strcmp( node->name().c_str(), "resource") != 0 ){
873 cerr << "node->name()=" << node->name() << ",!= \"resource\"!" << endl;
877 // node->dump(cerr, "node:");
879 XMLNode *id_node = node->child ("id");
880 XMLNode *uri_node = node->child ("serve");
881 XMLNode *ofn_node = node->child ("original_filename");
883 if (id_node && uri_node && ofn_node) {
885 std::string id = id_node->child("text")->content();
886 std::string uri = uri_node->child("text")->content();
887 std::string ofn = ofn_node->child("text")->content();
890 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << endl;
892 TreeModel::iterator new_row = freesound_list->append();
893 TreeModel::Row row = *new_row;
895 row[freesound_list_columns.id ] = id;
896 row[freesound_list_columns.uri ] = uri;
897 row[freesound_list_columns.filename] = ofn;
905 SoundFileBrowser::get_paths ()
907 vector<string> results;
909 int n = notebook.get_current_page ();
912 vector<string> filenames = chooser.get_filenames();
913 vector<string>::iterator i;
915 for (i = filenames.begin(); i != filenames.end(); ++i) {
917 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
918 results.push_back (*i);
924 typedef TreeView::Selection::ListHandle_Path ListPath;
926 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
927 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
928 TreeIter iter = found_list->get_iter(*i);
929 string str = (*iter)[found_list_columns.pathname];
931 results.push_back (str);
935 typedef TreeView::Selection::ListHandle_Path ListPath;
938 path = Glib::get_home_dir();
939 path += "/Freesound/";
940 Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser
943 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
944 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
945 TreeIter iter = freesound_list->get_iter(*i);
946 string id = (*iter)[freesound_list_columns.id];
947 string uri = (*iter)[freesound_list_columns.uri];
948 string ofn = (*iter)[freesound_list_columns.filename];
950 GdkCursor *prev_cursor;
951 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
952 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
955 freesound_stop = false;
956 string str = theMootcher.getAudioFile(ofn, id, uri, this);
958 results.push_back (str);
961 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
971 SoundFileOmega::reset_options_noret ()
973 if (!resetting_ourselves) {
974 (void) reset_options ();
979 SoundFileOmega::reset_options ()
981 vector<string> paths = get_paths ();
985 channel_combo.set_sensitive (false);
986 action_combo.set_sensitive (false);
987 where_combo.set_sensitive (false);
988 copy_files_btn.set_sensitive (false);
994 channel_combo.set_sensitive (true);
995 action_combo.set_sensitive (true);
996 where_combo.set_sensitive (true);
998 /* if we get through this function successfully, this may be
999 reset at the end, once we know if we can use hard links
1003 if (Config->get_only_copy_imported_files()) {
1004 copy_files_btn.set_sensitive (false);
1006 copy_files_btn.set_sensitive (false);
1012 bool selection_includes_multichannel;
1013 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1016 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1017 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1021 string existing_choice;
1022 vector<string> action_strings;
1024 if (chooser.get_filter() == &audio_filter) {
1028 if (selected_audio_track_cnt > 0) {
1029 if (channel_combo.get_active_text().length()) {
1030 ImportDisposition id = get_channel_disposition();
1033 case Editing::ImportDistinctFiles:
1034 if (selected_audio_track_cnt == paths.size()) {
1035 action_strings.push_back (importmode2string (ImportToTrack));
1039 case Editing::ImportDistinctChannels:
1040 /* XXX it would be nice to allow channel-per-selected track
1041 but its too hard we don't want to deal with all the
1042 different per-file + per-track channel configurations.
1047 action_strings.push_back (importmode2string (ImportToTrack));
1057 if (selected_midi_track_cnt > 0) {
1058 action_strings.push_back (importmode2string (ImportToTrack));
1062 action_strings.push_back (importmode2string (ImportAsTrack));
1063 action_strings.push_back (importmode2string (ImportAsRegion));
1064 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1066 resetting_ourselves = true;
1068 existing_choice = action_combo.get_active_text();
1070 set_popdown_strings (action_combo, action_strings);
1072 /* preserve any existing choice, if possible */
1075 if (existing_choice.length()) {
1076 vector<string>::iterator x;
1077 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1078 if (*x == existing_choice) {
1079 action_combo.set_active_text (existing_choice);
1083 if (x == action_strings.end()) {
1084 action_combo.set_active_text (action_strings.front());
1087 action_combo.set_active_text (action_strings.front());
1090 resetting_ourselves = false;
1092 if ((mode = get_mode()) == ImportAsRegion) {
1093 where_combo.set_sensitive (false);
1095 where_combo.set_sensitive (true);
1098 vector<string> channel_strings;
1100 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1101 channel_strings.push_back (_("one track per file"));
1103 if (selection_includes_multichannel) {
1104 channel_strings.push_back (_("one track per channel"));
1107 if (paths.size() > 1) {
1108 /* tape tracks are a single region per track, so we cannot
1109 sequence multiple files.
1111 if (mode != ImportAsTapeTrack) {
1112 channel_strings.push_back (_("sequence files"));
1115 channel_strings.push_back (_("all files in one track"));
1116 channel_strings.push_back (_("merge files"));
1122 channel_strings.push_back (_("one region per file"));
1124 if (selection_includes_multichannel) {
1125 channel_strings.push_back (_("one region per channel"));
1128 if (paths.size() > 1) {
1130 channel_strings.push_back (_("all files in one region"));
1135 resetting_ourselves = true;
1137 existing_choice = channel_combo.get_active_text();
1139 set_popdown_strings (channel_combo, channel_strings);
1141 /* preserve any existing choice, if possible */
1143 if (existing_choice.length()) {
1144 vector<string>::iterator x;
1145 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1146 if (*x == existing_choice) {
1147 channel_combo.set_active_text (existing_choice);
1151 if (x == channel_strings.end()) {
1152 channel_combo.set_active_text (channel_strings.front());
1155 channel_combo.set_active_text (channel_strings.front());
1158 resetting_ourselves = false;
1161 src_combo.set_sensitive (true);
1163 src_combo.set_sensitive (false);
1166 if (Config->get_only_copy_imported_files()) {
1168 if (selection_can_be_embedded_with_links) {
1169 copy_files_btn.set_sensitive (true);
1171 copy_files_btn.set_sensitive (false);
1176 copy_files_btn.set_sensitive (true);
1184 SoundFileOmega::bad_file_message()
1186 MessageDialog msg (*this,
1187 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1192 resetting_ourselves = true;
1193 chooser.unselect_uri (chooser.get_preview_uri());
1194 resetting_ourselves = false;
1200 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1209 multichannel = false;
1211 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1213 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1214 if (info.channels > 1) {
1215 multichannel = true;
1220 if (sz != info.length) {
1225 if (info.samplerate != _session->frame_rate()) {
1229 } else if (SMFSource::safe_midi_file_extension (*i)) {
1233 if (reader.num_tracks() > 1) {
1234 multichannel = true; // "channel" == track here...
1237 /* XXX we need err = true handling here in case
1238 we can't check the file
1251 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1253 sys::path path = s->session_directory().sound_path() / "linktest";
1254 string tmpdir = path.to_string();
1257 if (mkdir (tmpdir.c_str(), 0744)) {
1258 if (errno != EEXIST) {
1263 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1265 char tmpc[MAXPATHLEN+1];
1267 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1271 if (link ((*i).c_str(), tmpc)) {
1281 rmdir (tmpdir.c_str());
1285 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1286 : SoundFileBrowser (parent, title, s, false)
1288 chooser.set_select_multiple (false);
1289 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1290 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1294 SoundFileChooser::on_hide ()
1296 ArdourDialog::on_hide();
1300 _session->cancel_audition();
1305 SoundFileChooser::get_filename ()
1307 vector<string> paths;
1309 paths = get_paths ();
1311 if (paths.empty()) {
1315 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1319 return paths.front();
1322 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s,
1323 uint32_t selected_audio_tracks,
1324 uint32_t selected_midi_tracks,
1326 Editing::ImportMode mode_hint)
1327 : SoundFileBrowser (parent, title, s, persistent)
1328 , copy_files_btn ( _("Copy files to session"))
1329 , selected_audio_track_cnt (selected_audio_tracks)
1330 , selected_midi_track_cnt (selected_midi_tracks)
1336 set_size_request (-1, 450);
1338 block_two.set_border_width (12);
1339 block_three.set_border_width (12);
1340 block_four.set_border_width (12);
1342 options.set_spacing (12);
1345 str.push_back (_("file timestamp"));
1346 str.push_back (_("edit point"));
1347 str.push_back (_("playhead"));
1348 str.push_back (_("session start"));
1349 set_popdown_strings (where_combo, str);
1350 where_combo.set_active_text (str.front());
1352 Label* l = manage (new Label);
1353 l->set_text (_("Add files:"));
1355 hbox = manage (new HBox);
1356 hbox->set_border_width (12);
1357 hbox->set_spacing (6);
1358 hbox->pack_start (*l, false, false);
1359 hbox->pack_start (action_combo, false, false);
1360 vbox = manage (new VBox);
1361 vbox->pack_start (*hbox, false, false);
1362 options.pack_start (*vbox, false, false);
1364 /* dummy entry for action combo so that it doesn't look odd if we
1365 come up with no tracks selected.
1369 str.push_back (importmode2string (mode_hint));
1370 set_popdown_strings (action_combo, str);
1371 action_combo.set_active_text (str.front());
1372 action_combo.set_sensitive (false);
1374 l = manage (new Label);
1375 l->set_text (_("Insert at:"));
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 (where_combo, false, false);
1382 vbox = manage (new VBox);
1383 vbox->pack_start (*hbox, false, false);
1384 options.pack_start (*vbox, false, false);
1387 l = manage (new Label);
1388 l->set_text (_("Mapping:"));
1390 hbox = manage (new HBox);
1391 hbox->set_border_width (12);
1392 hbox->set_spacing (6);
1393 hbox->pack_start (*l, false, false);
1394 hbox->pack_start (channel_combo, false, false);
1395 vbox = manage (new VBox);
1396 vbox->pack_start (*hbox, false, false);
1397 options.pack_start (*vbox, false, false);
1400 str.push_back (_("one track per file"));
1401 set_popdown_strings (channel_combo, str);
1402 channel_combo.set_active_text (str.front());
1403 channel_combo.set_sensitive (false);
1405 l = manage (new Label);
1406 l->set_text (_("Conversion quality:"));
1408 hbox = manage (new HBox);
1409 hbox->set_border_width (12);
1410 hbox->set_spacing (6);
1411 hbox->pack_start (*l, false, false);
1412 hbox->pack_start (src_combo, false, false);
1413 vbox = manage (new VBox);
1414 vbox->pack_start (*hbox, false, false);
1415 options.pack_start (*vbox, false, false);
1418 str.push_back (_("Best"));
1419 str.push_back (_("Good"));
1420 str.push_back (_("Quick"));
1421 str.push_back (_("Fast"));
1422 str.push_back (_("Fastest"));
1424 set_popdown_strings (src_combo, str);
1425 src_combo.set_active_text (str.front());
1426 src_combo.set_sensitive (false);
1430 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1431 channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1433 copy_files_btn.set_active (true);
1435 block_four.pack_start (copy_files_btn, false, false);
1437 options.pack_start (block_four, false, false);
1439 get_vbox()->pack_start (options, false, false);
1441 /* setup disposition map */
1443 disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1444 disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1445 disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1446 disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1448 disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1449 disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1450 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1451 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1453 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1455 /* set size requests for a couple of combos to allow them to display the longest text
1456 they will ever be asked to display. This prevents them being resized when the user
1457 selects a file to import, which in turn prevents the size of the dialog from jumping
1461 t.push_back (_("one track per file"));
1462 t.push_back (_("one track per channel"));
1463 t.push_back (_("sequence files"));
1464 t.push_back (_("all files in one region"));
1465 set_popdown_strings (channel_combo, t);
1468 t.push_back (importmode2string (ImportAsTrack));
1469 t.push_back (importmode2string (ImportToTrack));
1470 t.push_back (importmode2string (ImportAsRegion));
1471 t.push_back (importmode2string (ImportAsTapeTrack));
1472 set_popdown_strings (action_combo, t);
1476 SoundFileOmega::set_mode (ImportMode mode)
1478 action_combo.set_active_text (importmode2string (mode));
1482 SoundFileOmega::get_mode () const
1484 return string2importmode (action_combo.get_active_text());
1488 SoundFileOmega::on_hide ()
1490 ArdourDialog::on_hide();
1492 _session->cancel_audition();
1497 SoundFileOmega::get_position() const
1499 string str = where_combo.get_active_text();
1501 if (str == _("file timestamp")) {
1502 return ImportAtTimestamp;
1503 } else if (str == _("edit point")) {
1504 return ImportAtEditPoint;
1505 } else if (str == _("playhead")) {
1506 return ImportAtPlayhead;
1508 return ImportAtStart;
1513 SoundFileOmega::get_src_quality() const
1515 string str = where_combo.get_active_text();
1517 if (str == _("Best")) {
1519 } else if (str == _("Good")) {
1521 } else if (str == _("Quick")) {
1523 } else if (str == _("Fast")) {
1531 SoundFileOmega::get_channel_disposition () const
1533 /* we use a map here because the channel combo can contain different strings
1534 depending on the state of the other combos. the map contains all possible strings
1535 and the ImportDisposition enum that corresponds to it.
1538 string str = channel_combo.get_active_text();
1539 DispositionMap::const_iterator x = disposition_map.find (str);
1541 if (x == disposition_map.end()) {
1542 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1550 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1552 selected_audio_track_cnt = selected_audio_tracks;
1553 selected_midi_track_cnt = selected_midi_tracks;
1558 SoundFileOmega::file_selection_changed ()
1560 if (resetting_ourselves) {
1564 if (!reset_options ()) {
1565 set_response_sensitive (RESPONSE_OK, false);
1567 if (chooser.get_filenames().size() > 0) {
1568 set_response_sensitive (RESPONSE_OK, true);
1570 set_response_sensitive (RESPONSE_OK, false);