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, "EditCursorClock", false, false, true, false),
122 timecode_clock ("sfboxTimecodeClock", !persistent, "EditCursorClock", 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);
552 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
553 scroll->add(freesound_list_view);
554 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
556 vbox = manage(new VBox);
557 vbox->pack_start (*passbox, PACK_SHRINK);
558 vbox->pack_start (*scroll);
560 freesound_list_view.append_column(_("ID") , freesound_list_columns.id);
561 freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
562 freesound_list_view.append_column(_("URI") , freesound_list_columns.uri);
563 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
565 freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
566 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
567 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
568 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
569 notebook.append_page (*vbox, _("Search Freesound"));
574 notebook.set_size_request (500, -1);
578 add_button (Stock::CANCEL, RESPONSE_CANCEL);
579 add_button (Stock::APPLY, RESPONSE_APPLY);
580 add_button (Stock::OK, RESPONSE_OK);
584 SoundFileBrowser::~SoundFileBrowser ()
586 persistent_folder = chooser.get_current_folder();
591 SoundFileBrowser::on_show ()
593 ArdourDialog::on_show ();
598 SoundFileBrowser::clear_selection ()
600 chooser.unselect_all ();
601 found_list_view.get_selection()->unselect_all ();
605 SoundFileBrowser::chooser_file_activated ()
611 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
617 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
623 SoundFileBrowser::set_session (Session* s)
625 ArdourDialog::set_session (s);
626 preview.set_session (s);
631 remove_gain_meter ();
636 SoundFileBrowser::add_gain_meter ()
640 gm = new GainMeter (_session, 250);
642 boost::shared_ptr<Route> r = _session->the_auditioner ();
644 gm->set_controls (r, r->shared_peak_meter(), r->amp());
646 meter_packer.set_border_width (12);
647 meter_packer.pack_start (*gm, false, true);
648 hpacker.pack_end (meter_packer, false, false);
649 meter_packer.show_all ();
654 SoundFileBrowser::remove_gain_meter ()
657 meter_packer.remove (*gm);
658 hpacker.remove (meter_packer);
665 SoundFileBrowser::start_metering ()
667 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
671 SoundFileBrowser::stop_metering ()
673 metering_connection.disconnect();
677 SoundFileBrowser::meter ()
679 if (is_mapped () && _session && gm) {
680 gm->update_meters ();
685 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
687 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
691 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
693 return SMFSource::safe_midi_file_extension (filter_info.filename);
697 SoundFileBrowser::update_preview ()
699 if (preview.setup_labels (chooser.get_filename())) {
700 if (preview.autoplay()) {
701 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
707 SoundFileBrowser::found_list_view_selected ()
709 if (!reset_options ()) {
710 set_response_sensitive (RESPONSE_OK, false);
714 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
717 TreeIter iter = found_list->get_iter(*rows.begin());
718 file = (*iter)[found_list_columns.pathname];
719 chooser.set_filename (file);
720 set_response_sensitive (RESPONSE_OK, true);
722 set_response_sensitive (RESPONSE_OK, false);
725 preview.setup_labels (file);
730 SoundFileBrowser::freesound_list_view_selected ()
732 if (!reset_options ()) {
733 set_response_sensitive (RESPONSE_OK, false);
737 path = Glib::get_home_dir();
738 path += "/Freesound/";
739 Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser
743 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
746 TreeIter iter = freesound_list->get_iter(*rows.begin());
748 string id = (*iter)[freesound_list_columns.id];
749 string uri = (*iter)[freesound_list_columns.uri];
750 string ofn = (*iter)[freesound_list_columns.filename];
752 // download the sound file
753 GdkCursor *prev_cursor;
754 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
755 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
758 file = theMootcher.getAudioFile(ofn, id, uri, &progress_bar);
760 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
762 chooser.set_filename (file);
763 set_response_sensitive (RESPONSE_OK, true);
765 set_response_sensitive (RESPONSE_OK, false);
768 preview.setup_labels (file);
773 SoundFileBrowser::found_search_clicked ()
775 string tag_string = found_entry.get_text ();
779 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
780 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
784 vector<string> results;
785 Library->search_members_and (results, tags);
788 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
789 TreeModel::iterator new_row = found_list->append();
790 TreeModel::Row row = *new_row;
791 string path = Glib::filename_from_uri (string ("file:") + *i);
792 row[found_list_columns.pathname] = path;
797 SoundFileBrowser::freesound_search_clicked ()
804 SoundFileBrowser::freesound_search()
807 freesound_list->clear();
810 path = Glib::get_home_dir();
811 path += "/Freesound/";
812 Mootcher theMootcher(path.c_str());
814 string search_string = freesound_entry.get_text ();
815 enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
816 int page = freesound_page.get_value_as_int();
818 GdkCursor *prev_cursor;
819 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
820 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
823 string theString = theMootcher.searchText(
826 "", // filter, could do, e.g. "type:wav"
830 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
833 doc.read_buffer( theString );
834 XMLNode *root = doc.root();
837 cerr << "no root XML node!" << endl;
841 if ( strcmp(root->name().c_str(), "response") != 0) {
842 cerr << "root node name == " << root->name() << ", != \"response\"!" << endl;
846 XMLNode *sounds_root = root->child("sounds");
849 cerr << "no child node \"sounds\" found!" << endl;
853 XMLNodeList sounds = sounds_root->children();
854 XMLNodeConstIterator niter;
856 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
858 if( strcmp( node->name().c_str(), "resource") != 0 ){
859 cerr << "node->name()=" << node->name() << ",!= \"resource\"!" << endl;
863 // node->dump(cerr, "node:");
865 XMLNode *id_node = node->child ("id");
866 XMLNode *uri_node = node->child ("serve");
867 XMLNode *ofn_node = node->child ("original_filename");
869 if (id_node && uri_node && ofn_node) {
871 std::string id = id_node->child("text")->content();
872 std::string uri = uri_node->child("text")->content();
873 std::string ofn = ofn_node->child("text")->content();
876 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << endl;
878 TreeModel::iterator new_row = freesound_list->append();
879 TreeModel::Row row = *new_row;
881 row[freesound_list_columns.id ] = id;
882 row[freesound_list_columns.uri ] = uri;
883 row[freesound_list_columns.filename] = ofn;
891 SoundFileBrowser::get_paths ()
893 vector<string> results;
895 int n = notebook.get_current_page ();
898 vector<string> filenames = chooser.get_filenames();
899 vector<string>::iterator i;
901 for (i = filenames.begin(); i != filenames.end(); ++i) {
903 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
904 results.push_back (*i);
910 typedef TreeView::Selection::ListHandle_Path ListPath;
912 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
913 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
914 TreeIter iter = found_list->get_iter(*i);
915 string str = (*iter)[found_list_columns.pathname];
917 results.push_back (str);
921 typedef TreeView::Selection::ListHandle_Path ListPath;
924 path = Glib::get_home_dir();
925 path += "/Freesound/";
926 Mootcher theMootcher(path.c_str()); // XXX should be a member of SoundFileBrowser
929 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
930 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
931 TreeIter iter = freesound_list->get_iter(*i);
932 string id = (*iter)[freesound_list_columns.id];
933 string uri = (*iter)[freesound_list_columns.uri];
934 string ofn = (*iter)[freesound_list_columns.filename];
936 GdkCursor *prev_cursor;
937 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
938 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
941 string str = theMootcher.getAudioFile(ofn, id, uri, &progress_bar);
942 results.push_back (str);
944 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
953 SoundFileOmega::reset_options_noret ()
955 if (!resetting_ourselves) {
956 (void) reset_options ();
961 SoundFileOmega::reset_options ()
963 vector<string> paths = get_paths ();
967 channel_combo.set_sensitive (false);
968 action_combo.set_sensitive (false);
969 where_combo.set_sensitive (false);
970 copy_files_btn.set_sensitive (false);
976 channel_combo.set_sensitive (true);
977 action_combo.set_sensitive (true);
978 where_combo.set_sensitive (true);
980 /* if we get through this function successfully, this may be
981 reset at the end, once we know if we can use hard links
985 if (Config->get_only_copy_imported_files()) {
986 copy_files_btn.set_sensitive (false);
988 copy_files_btn.set_sensitive (false);
994 bool selection_includes_multichannel;
995 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
998 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
999 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1003 string existing_choice;
1004 vector<string> action_strings;
1006 if (chooser.get_filter() == &audio_filter) {
1010 if (selected_audio_track_cnt > 0) {
1011 if (channel_combo.get_active_text().length()) {
1012 ImportDisposition id = get_channel_disposition();
1015 case Editing::ImportDistinctFiles:
1016 if (selected_audio_track_cnt == paths.size()) {
1017 action_strings.push_back (importmode2string (ImportToTrack));
1021 case Editing::ImportDistinctChannels:
1022 /* XXX it would be nice to allow channel-per-selected track
1023 but its too hard we don't want to deal with all the
1024 different per-file + per-track channel configurations.
1029 action_strings.push_back (importmode2string (ImportToTrack));
1039 if (selected_midi_track_cnt > 0) {
1040 action_strings.push_back (importmode2string (ImportToTrack));
1044 action_strings.push_back (importmode2string (ImportAsTrack));
1045 action_strings.push_back (importmode2string (ImportAsRegion));
1046 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1048 resetting_ourselves = true;
1050 existing_choice = action_combo.get_active_text();
1052 set_popdown_strings (action_combo, action_strings);
1054 /* preserve any existing choice, if possible */
1057 if (existing_choice.length()) {
1058 vector<string>::iterator x;
1059 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1060 if (*x == existing_choice) {
1061 action_combo.set_active_text (existing_choice);
1065 if (x == action_strings.end()) {
1066 action_combo.set_active_text (action_strings.front());
1069 action_combo.set_active_text (action_strings.front());
1072 resetting_ourselves = false;
1074 if ((mode = get_mode()) == ImportAsRegion) {
1075 where_combo.set_sensitive (false);
1077 where_combo.set_sensitive (true);
1080 vector<string> channel_strings;
1082 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1083 channel_strings.push_back (_("one track per file"));
1085 if (selection_includes_multichannel) {
1086 channel_strings.push_back (_("one track per channel"));
1089 if (paths.size() > 1) {
1090 /* tape tracks are a single region per track, so we cannot
1091 sequence multiple files.
1093 if (mode != ImportAsTapeTrack) {
1094 channel_strings.push_back (_("sequence files"));
1097 channel_strings.push_back (_("all files in one track"));
1098 channel_strings.push_back (_("merge files"));
1104 channel_strings.push_back (_("one region per file"));
1106 if (selection_includes_multichannel) {
1107 channel_strings.push_back (_("one region per channel"));
1110 if (paths.size() > 1) {
1112 channel_strings.push_back (_("all files in one region"));
1117 resetting_ourselves = true;
1119 existing_choice = channel_combo.get_active_text();
1121 set_popdown_strings (channel_combo, channel_strings);
1123 /* preserve any existing choice, if possible */
1125 if (existing_choice.length()) {
1126 vector<string>::iterator x;
1127 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1128 if (*x == existing_choice) {
1129 channel_combo.set_active_text (existing_choice);
1133 if (x == channel_strings.end()) {
1134 channel_combo.set_active_text (channel_strings.front());
1137 channel_combo.set_active_text (channel_strings.front());
1140 resetting_ourselves = false;
1143 src_combo.set_sensitive (true);
1145 src_combo.set_sensitive (false);
1148 if (Config->get_only_copy_imported_files()) {
1150 if (selection_can_be_embedded_with_links) {
1151 copy_files_btn.set_sensitive (true);
1153 copy_files_btn.set_sensitive (false);
1158 copy_files_btn.set_sensitive (true);
1166 SoundFileOmega::bad_file_message()
1168 MessageDialog msg (*this,
1169 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1174 resetting_ourselves = true;
1175 chooser.unselect_uri (chooser.get_preview_uri());
1176 resetting_ourselves = false;
1182 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1191 multichannel = false;
1193 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1195 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1196 if (info.channels > 1) {
1197 multichannel = true;
1202 if (sz != info.length) {
1207 if (info.samplerate != _session->frame_rate()) {
1211 } else if (SMFSource::safe_midi_file_extension (*i)) {
1215 if (reader.num_tracks() > 1) {
1216 multichannel = true; // "channel" == track here...
1219 /* XXX we need err = true handling here in case
1220 we can't check the file
1233 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1235 sys::path path = s->session_directory().sound_path() / "linktest";
1236 string tmpdir = path.to_string();
1239 if (mkdir (tmpdir.c_str(), 0744)) {
1240 if (errno != EEXIST) {
1245 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1247 char tmpc[MAXPATHLEN+1];
1249 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1253 if (link ((*i).c_str(), tmpc)) {
1263 rmdir (tmpdir.c_str());
1267 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1268 : SoundFileBrowser (parent, title, s, false)
1270 chooser.set_select_multiple (false);
1271 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1272 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1276 SoundFileChooser::on_hide ()
1278 ArdourDialog::on_hide();
1282 _session->cancel_audition();
1287 SoundFileChooser::get_filename ()
1289 vector<string> paths;
1291 paths = get_paths ();
1293 if (paths.empty()) {
1297 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1301 return paths.front();
1304 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s,
1305 uint32_t selected_audio_tracks,
1306 uint32_t selected_midi_tracks,
1308 Editing::ImportMode mode_hint)
1309 : SoundFileBrowser (parent, title, s, persistent)
1310 , copy_files_btn ( _("Copy files to session"))
1311 , selected_audio_track_cnt (selected_audio_tracks)
1312 , selected_midi_track_cnt (selected_midi_tracks)
1318 set_size_request (-1, 450);
1320 block_two.set_border_width (12);
1321 block_three.set_border_width (12);
1322 block_four.set_border_width (12);
1324 options.set_spacing (12);
1327 str.push_back (_("file timestamp"));
1328 str.push_back (_("edit point"));
1329 str.push_back (_("playhead"));
1330 str.push_back (_("session start"));
1331 set_popdown_strings (where_combo, str);
1332 where_combo.set_active_text (str.front());
1334 Label* l = manage (new Label);
1335 l->set_text (_("Add files:"));
1337 hbox = manage (new HBox);
1338 hbox->set_border_width (12);
1339 hbox->set_spacing (6);
1340 hbox->pack_start (*l, false, false);
1341 hbox->pack_start (action_combo, false, false);
1342 vbox = manage (new VBox);
1343 vbox->pack_start (*hbox, false, false);
1344 options.pack_start (*vbox, false, false);
1346 /* dummy entry for action combo so that it doesn't look odd if we
1347 come up with no tracks selected.
1351 str.push_back (importmode2string (mode_hint));
1352 set_popdown_strings (action_combo, str);
1353 action_combo.set_active_text (str.front());
1354 action_combo.set_sensitive (false);
1356 l = manage (new Label);
1357 l->set_text (_("Insert at:"));
1359 hbox = manage (new HBox);
1360 hbox->set_border_width (12);
1361 hbox->set_spacing (6);
1362 hbox->pack_start (*l, false, false);
1363 hbox->pack_start (where_combo, false, false);
1364 vbox = manage (new VBox);
1365 vbox->pack_start (*hbox, false, false);
1366 options.pack_start (*vbox, false, false);
1369 l = manage (new Label);
1370 l->set_text (_("Mapping:"));
1372 hbox = manage (new HBox);
1373 hbox->set_border_width (12);
1374 hbox->set_spacing (6);
1375 hbox->pack_start (*l, false, false);
1376 hbox->pack_start (channel_combo, false, false);
1377 vbox = manage (new VBox);
1378 vbox->pack_start (*hbox, false, false);
1379 options.pack_start (*vbox, false, false);
1382 str.push_back (_("one track per file"));
1383 set_popdown_strings (channel_combo, str);
1384 channel_combo.set_active_text (str.front());
1385 channel_combo.set_sensitive (false);
1387 l = manage (new Label);
1388 l->set_text (_("Conversion quality:"));
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 (src_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 (_("Best"));
1401 str.push_back (_("Good"));
1402 str.push_back (_("Quick"));
1403 str.push_back (_("Fast"));
1404 str.push_back (_("Fastest"));
1406 set_popdown_strings (src_combo, str);
1407 src_combo.set_active_text (str.front());
1408 src_combo.set_sensitive (false);
1412 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1413 channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1415 copy_files_btn.set_active (true);
1417 block_four.pack_start (copy_files_btn, false, false);
1419 options.pack_start (block_four, false, false);
1421 get_vbox()->pack_start (options, false, false);
1423 /* setup disposition map */
1425 disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1426 disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1427 disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1428 disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1430 disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1431 disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1432 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1433 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1435 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1437 /* set size requests for a couple of combos to allow them to display the longest text
1438 they will ever be asked to display. This prevents them being resized when the user
1439 selects a file to import, which in turn prevents the size of the dialog from jumping
1443 t.push_back (_("one track per file"));
1444 t.push_back (_("one track per channel"));
1445 t.push_back (_("sequence files"));
1446 t.push_back (_("all files in one region"));
1447 set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
1450 t.push_back (importmode2string (ImportAsTrack));
1451 t.push_back (importmode2string (ImportToTrack));
1452 t.push_back (importmode2string (ImportAsRegion));
1453 t.push_back (importmode2string (ImportAsTapeTrack));
1454 set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
1458 SoundFileOmega::set_mode (ImportMode mode)
1460 action_combo.set_active_text (importmode2string (mode));
1464 SoundFileOmega::get_mode () const
1466 return string2importmode (action_combo.get_active_text());
1470 SoundFileOmega::on_hide ()
1472 ArdourDialog::on_hide();
1474 _session->cancel_audition();
1479 SoundFileOmega::get_position() const
1481 string str = where_combo.get_active_text();
1483 if (str == _("file timestamp")) {
1484 return ImportAtTimestamp;
1485 } else if (str == _("edit point")) {
1486 return ImportAtEditPoint;
1487 } else if (str == _("playhead")) {
1488 return ImportAtPlayhead;
1490 return ImportAtStart;
1495 SoundFileOmega::get_src_quality() const
1497 string str = where_combo.get_active_text();
1499 if (str == _("Best")) {
1501 } else if (str == _("Good")) {
1503 } else if (str == _("Quick")) {
1505 } else if (str == _("Fast")) {
1513 SoundFileOmega::get_channel_disposition () const
1515 /* we use a map here because the channel combo can contain different strings
1516 depending on the state of the other combos. the map contains all possible strings
1517 and the ImportDisposition enum that corresponds to it.
1520 string str = channel_combo.get_active_text();
1521 DispositionMap::const_iterator x = disposition_map.find (str);
1523 if (x == disposition_map.end()) {
1524 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1532 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1534 selected_audio_track_cnt = selected_audio_tracks;
1535 selected_midi_track_cnt = selected_midi_tracks;
1540 SoundFileOmega::file_selection_changed ()
1542 if (resetting_ourselves) {
1546 if (!reset_options ()) {
1547 set_response_sensitive (RESPONSE_OK, false);
1549 if (chooser.get_filenames().size() > 0) {
1550 set_response_sensitive (RESPONSE_OK, true);
1552 set_response_sensitive (RESPONSE_OK, false);