Fix show existing automation for audio tracks (part of #3193)
[ArdourMidi.git] / gtk2_ardour / sfdb_ui.cc
blob2e6235e70cefe8f3650d2292680b74fb828d0752
1 /*
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.
20 #include <map>
21 #include <cerrno>
22 #include <sstream>
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/param.h>
28 #include <gtkmm/box.h>
29 #include <gtkmm/stock.h>
30 #include <glibmm/fileutils.h>
32 #include "pbd/convert.h"
33 #include "pbd/tokenizer.h"
34 #include "pbd/enumwriter.h"
35 #include "pbd/pthread_utils.h"
36 #include "pbd/xml++.h"
38 #include <gtkmm2ext/utils.h>
40 #include "evoral/SMF.hpp"
42 #include "ardour/amp.h"
43 #include "ardour/audio_library.h"
44 #include "ardour/auditioner.h"
45 #include "ardour/audioregion.h"
46 #include "ardour/audiofilesource.h"
47 #include "ardour/smf_source.h"
48 #include "ardour/region_factory.h"
49 #include "ardour/source_factory.h"
50 #include "ardour/session.h"
51 #include "ardour/session_directory.h"
52 #include "ardour/profile.h"
54 #include "ardour_ui.h"
55 #include "editing.h"
56 #include "gui_thread.h"
57 #include "prompter.h"
58 #include "sfdb_ui.h"
59 #include "editing.h"
60 #include "utils.h"
61 #include "gain_meter.h"
63 #ifdef FREESOUND
64 #include "sfdb_freesound_mootcher.h"
65 #endif
67 #include "i18n.h"
69 using namespace ARDOUR;
70 using namespace PBD;
71 using namespace std;
72 using namespace Gtk;
73 using namespace Gtkmm2ext;
74 using namespace Editing;
76 using Glib::ustring;
78 ustring SoundFileBrowser::persistent_folder;
80 static ImportMode
81 string2importmode (string str)
83 if (str == _("as new tracks")) {
84 return ImportAsTrack;
85 } else if (str == _("to selected tracks")) {
86 return ImportToTrack;
87 } else if (str == _("to region list")) {
88 return ImportAsRegion;
89 } else if (str == _("as new tape tracks")) {
90 return ImportAsTapeTrack;
93 warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
95 return ImportAsTrack;
98 static string
99 importmode2string (ImportMode mode)
101 switch (mode) {
102 case ImportAsTrack:
103 return _("as new tracks");
104 case ImportToTrack:
105 return _("to selected tracks");
106 case ImportAsRegion:
107 return _("to region list");
108 case ImportAsTapeTrack:
109 return _("as new tape tracks");
111 /*NOTREACHED*/
112 return _("as new tracks");
115 SoundFileBox::SoundFileBox (bool persistent)
116 : table (6, 2),
117 length_clock ("sfboxLengthClock", !persistent, "EditCursorClock", false, false, true, false),
118 timecode_clock ("sfboxTimecodeClock", !persistent, "EditCursorClock", false, false, false, false),
119 main_box (false, 6),
120 autoplay_btn (_("Auto-play"))
123 set_name (X_("SoundFileBox"));
124 set_size_request (300, -1);
126 preview_label.set_markup (_("<b>Sound File Information</b>"));
128 border_frame.set_label_widget (preview_label);
129 border_frame.add (main_box);
131 pack_start (border_frame, true, true);
132 set_border_width (6);
134 main_box.set_border_width (6);
136 length.set_text (_("Length:"));
137 length.set_alignment (1, 0.5);
138 timecode.set_text (_("Timestamp:"));
139 timecode.set_alignment (1, 0.5);
140 format.set_text (_("Format:"));
141 format.set_alignment (1, 0.5);
142 channels.set_text (_("Channels:"));
143 channels.set_alignment (1, 0.5);
144 samplerate.set_text (_("Sample rate:"));
145 samplerate.set_alignment (1, 0.5);
147 format_text.set_max_width_chars (8);
148 format_text.set_ellipsize (Pango::ELLIPSIZE_END);
149 format_text.set_alignment (0, 1);
151 table.set_col_spacings (6);
152 table.set_homogeneous (false);
153 table.set_row_spacings (6);
155 table.attach (channels, 0, 1, 0, 1, FILL, FILL);
156 table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
157 table.attach (format, 0, 1, 2, 4, FILL, FILL);
158 table.attach (length, 0, 1, 4, 5, FILL, FILL);
159 table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
161 table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
162 table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
163 table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
164 table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
165 table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
167 length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock.mode());
168 timecode_clock.set_mode (AudioClock::Timecode);
170 main_box.pack_start (table, false, false);
172 tags_entry.set_editable (true);
173 tags_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
175 Label* label = manage (new Label (_("Tags:")));
176 label->set_alignment (0.0f, 0.5f);
177 main_box.pack_start (*label, false, false);
178 main_box.pack_start (tags_entry, true, true);
180 main_box.pack_start (bottom_box, false, false);
182 play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
183 play_btn.set_label (_("Play"));
185 stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
186 stop_btn.set_label (_("Stop"));
188 bottom_box.set_homogeneous (false);
189 bottom_box.set_spacing (6);
190 bottom_box.pack_start(play_btn, true, true);
191 bottom_box.pack_start(stop_btn, true, true);
192 bottom_box.pack_start(autoplay_btn, false, false);
194 play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
195 stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
197 channels_value.set_alignment (0.0f, 0.5f);
198 samplerate_value.set_alignment (0.0f, 0.5f);
201 void
202 SoundFileBox::set_session(Session* s)
204 SessionHandlePtr::set_session (s);
206 length_clock.set_session (s);
207 timecode_clock.set_session (s);
209 if (!_session) {
210 play_btn.set_sensitive (false);
211 stop_btn.set_sensitive (false);
215 bool
216 SoundFileBox::setup_labels (const ustring& filename)
218 if (!path.empty()) {
219 // save existing tags
220 tags_changed ();
223 path = filename;
225 string error_msg;
227 if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
229 preview_label.set_markup (_("<b>Sound File Information</b>"));
230 format_text.set_text ("");
231 channels_value.set_text ("");
232 samplerate_value.set_text ("");
233 tags_entry.get_buffer()->set_text ("");
235 length_clock.set (0);
236 timecode_clock.set (0);
238 tags_entry.set_sensitive (false);
239 play_btn.set_sensitive (false);
241 return false;
244 preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
245 std::string n = sf_info.format_name;
246 if (n.substr (0, 8) == X_("Format: ")) {
247 n = n.substr (8);
249 format_text.set_text (n);
250 channels_value.set_text (to_string (sf_info.channels, std::dec));
252 if (_session && sf_info.samplerate != _session->frame_rate()) {
253 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
254 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
255 samplerate_value.set_name ("NewSessionSR1Label");
256 samplerate.set_name ("NewSessionSR1Label");
257 } else {
258 samplerate.set_text (_("Sample rate:"));
259 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
260 samplerate_value.set_name ("NewSessionSR2Label");
261 samplerate.set_name ("NewSessionSR2Label");
264 nframes_t const nfr = _session ? _session->nominal_frame_rate() : 25;
265 double src_coef = (double) nfr / sf_info.samplerate;
267 length_clock.set (sf_info.length * src_coef + 0.5, true);
268 timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
270 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
272 vector<string> tags = Library->get_tags (string ("//") + filename);
274 stringstream tag_string;
275 for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
276 if (i != tags.begin()) {
277 tag_string << ", ";
279 tag_string << *i;
281 tags_entry.get_buffer()->set_text (tag_string.str());
283 tags_entry.set_sensitive (true);
284 if (_session) {
285 play_btn.set_sensitive (true);
288 return true;
291 bool
292 SoundFileBox::autoplay() const
294 return autoplay_btn.get_active();
297 bool
298 SoundFileBox::audition_oneshot()
300 audition ();
301 return false;
304 void
305 SoundFileBox::audition ()
307 if (!_session) {
308 return;
311 if (SMFSource::safe_midi_file_extension (path)) {
312 error << _("Auditioning of MIDI files is not yet supported") << endmsg;
313 return;
316 _session->cancel_audition();
318 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
319 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
320 return;
323 boost::shared_ptr<Region> r;
324 SourceList srclist;
325 boost::shared_ptr<AudioFileSource> afs;
326 bool old_sbp = AudioSource::get_build_peakfiles ();
328 /* don't even think of building peakfiles for these files */
330 AudioSource::set_build_peakfiles (false);
332 for (int n = 0; n < sf_info.channels; ++n) {
333 try {
334 afs = boost::dynamic_pointer_cast<AudioFileSource> (
335 SourceFactory::createReadable (DataType::AUDIO, *_session,
336 path, n, Source::Flag (0), false));
338 srclist.push_back(afs);
340 } catch (failed_constructor& err) {
341 error << _("Could not access soundfile: ") << path << endmsg;
342 AudioSource::set_build_peakfiles (old_sbp);
343 return;
347 AudioSource::set_build_peakfiles (old_sbp);
349 if (srclist.empty()) {
350 return;
353 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
354 string rname = region_name_from_path (afs->path(), false);
356 PropertyList plist;
358 plist.add (ARDOUR::Properties::start, 0);
359 plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
360 plist.add (ARDOUR::Properties::name, rname);
361 plist.add (ARDOUR::Properties::layer, 0);
363 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
365 _session->audition_region(r);
368 void
369 SoundFileBox::stop_audition ()
371 if (_session) {
372 _session->cancel_audition();
376 bool
377 SoundFileBox::tags_entry_left (GdkEventFocus *)
379 tags_changed ();
380 return false;
383 void
384 SoundFileBox::tags_changed ()
386 string tag_string = tags_entry.get_buffer()->get_text ();
388 if (tag_string.empty()) {
389 return;
392 vector<string> tags;
394 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
395 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
396 return;
399 save_tags (tags);
402 void
403 SoundFileBox::save_tags (const vector<string>& tags)
405 Library->set_tags (string ("//") + path, tags);
406 Library->save_changes ();
409 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, bool persistent)
410 : ArdourDialog (parent, title, false, false),
411 found_list (ListStore::create(found_list_columns)),
412 freesound_list (ListStore::create(freesound_list_columns)),
413 chooser (FILE_CHOOSER_ACTION_OPEN),
414 preview (persistent),
415 found_search_btn (_("Search")),
416 found_list_view (found_list),
417 freesound_search_btn (_("Start Downloading")),
418 freesound_list_view (freesound_list)
420 resetting_ourselves = false;
421 gm = 0;
423 resetting_ourselves = false;
424 gm = 0;
426 if (ARDOUR::Profile->get_sae()) {
427 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
428 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
431 #ifdef GTKOSX
432 chooser.add_shortcut_folder_uri("file:///Volumes");
433 #endif
435 //add the file chooser
437 chooser.set_border_width (12);
439 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
440 audio_filter.set_name (_("Audio files"));
442 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
443 midi_filter.set_name (_("MIDI files"));
445 matchall_filter.add_pattern ("*.*");
446 matchall_filter.set_name (_("All files"));
448 chooser.add_filter (audio_filter);
449 chooser.add_filter (midi_filter);
450 chooser.add_filter (matchall_filter);
451 chooser.set_select_multiple (true);
452 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
453 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
454 #ifdef GTKOSX
455 /* some broken redraw behaviour - this is a bandaid */
456 chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
457 #endif
459 if (!persistent_folder.empty()) {
460 chooser.set_current_folder (persistent_folder);
462 notebook.append_page (chooser, _("Browse Files"));
465 hpacker.set_spacing (6);
466 hpacker.pack_start (notebook, true, true);
467 hpacker.pack_start (preview, false, false);
469 get_vbox()->pack_start (hpacker, true, true);
471 //add tag search
473 VBox* vbox;
474 HBox* hbox;
477 hbox = manage(new HBox);
478 hbox->pack_start (found_entry);
479 hbox->pack_start (found_search_btn);
481 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
482 scroll->add(found_list_view);
483 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
485 vbox = manage(new VBox);
486 vbox->pack_start (*hbox, PACK_SHRINK);
487 vbox->pack_start (*scroll);
489 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
491 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
493 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
495 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
496 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
498 notebook.append_page (*vbox, _("Search Tags"));
501 //add freesound search
502 #ifdef FREESOUND
504 VBox* vbox;
505 HBox* passbox;
506 Label* label;
508 passbox = manage(new HBox);
509 passbox->set_border_width (12);
510 passbox->set_spacing (6);
512 label = manage (new Label);
513 label->set_text (_("User:"));
514 passbox->pack_start (*label, false, false);
515 passbox->pack_start (freesound_name_entry);
516 label = manage (new Label);
517 label->set_text (_("Password:"));
518 passbox->pack_start (*label, false, false);
519 passbox->pack_start (freesound_pass_entry);
520 label = manage (new Label);
521 label->set_text (_("Tags:"));
522 passbox->pack_start (*label, false, false);
523 passbox->pack_start (freesound_entry, false, false);
524 passbox->pack_start (freesound_search_btn, false, false);
526 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
527 scroll->add(freesound_list_view);
528 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
530 vbox = manage(new VBox);
531 vbox->pack_start (*passbox, PACK_SHRINK);
532 vbox->pack_start(*scroll);
534 //vbox->pack_start (freesound_list_view);
536 freesound_list_view.append_column(_("Paths"), freesound_list_columns.pathname);
537 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
539 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
540 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
541 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
542 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
543 notebook.append_page (*vbox, _("Search Freesound"));
545 #endif
548 notebook.set_size_request (500, -1);
550 set_session (s);
552 add_button (Stock::CANCEL, RESPONSE_CANCEL);
553 add_button (Stock::APPLY, RESPONSE_APPLY);
554 add_button (Stock::OK, RESPONSE_OK);
558 SoundFileBrowser::~SoundFileBrowser ()
560 persistent_folder = chooser.get_current_folder();
564 void
565 SoundFileBrowser::on_show ()
567 ArdourDialog::on_show ();
568 start_metering ();
571 void
572 SoundFileBrowser::clear_selection ()
574 chooser.unselect_all ();
575 found_list_view.get_selection()->unselect_all ();
578 void
579 SoundFileBrowser::chooser_file_activated ()
581 preview.audition ();
584 void
585 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
587 preview.audition ();
590 void
591 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
593 preview.audition ();
596 void
597 SoundFileBrowser::set_session (Session* s)
599 ArdourDialog::set_session (s);
600 preview.set_session (s);
602 if (_session) {
603 add_gain_meter ();
604 } else {
605 remove_gain_meter ();
609 void
610 SoundFileBrowser::add_gain_meter ()
612 delete gm;
614 gm = new GainMeter (_session, 250);
616 boost::shared_ptr<Route> r = _session->the_auditioner ();
618 gm->set_controls (r, r->shared_peak_meter(), r->amp());
620 meter_packer.set_border_width (12);
621 meter_packer.pack_start (*gm, false, true);
622 hpacker.pack_end (meter_packer, false, false);
623 meter_packer.show_all ();
624 start_metering ();
627 void
628 SoundFileBrowser::remove_gain_meter ()
630 if (gm) {
631 meter_packer.remove (*gm);
632 hpacker.remove (meter_packer);
633 delete gm;
634 gm = 0;
638 void
639 SoundFileBrowser::start_metering ()
641 metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
644 void
645 SoundFileBrowser::stop_metering ()
647 metering_connection.disconnect();
650 void
651 SoundFileBrowser::meter ()
653 if (is_mapped () && _session && gm) {
654 gm->update_meters ();
658 bool
659 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
661 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
664 bool
665 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
667 return SMFSource::safe_midi_file_extension (filter_info.filename);
670 void
671 SoundFileBrowser::update_preview ()
673 if (preview.setup_labels (chooser.get_filename())) {
674 if (preview.autoplay()) {
675 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
680 void
681 SoundFileBrowser::found_list_view_selected ()
683 if (!reset_options ()) {
684 set_response_sensitive (RESPONSE_OK, false);
685 } else {
686 ustring file;
688 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
690 if (!rows.empty()) {
691 TreeIter iter = found_list->get_iter(*rows.begin());
692 file = (*iter)[found_list_columns.pathname];
693 chooser.set_filename (file);
694 set_response_sensitive (RESPONSE_OK, true);
695 } else {
696 set_response_sensitive (RESPONSE_OK, false);
699 preview.setup_labels (file);
703 void
704 SoundFileBrowser::freesound_list_view_selected ()
706 if (!reset_options ()) {
707 set_response_sensitive (RESPONSE_OK, false);
708 } else {
709 ustring file;
711 TreeView::Selection::ListHandle_Path rows = freesound_list_view.get_selection()->get_selected_rows ();
713 if (!rows.empty()) {
714 TreeIter iter = freesound_list->get_iter(*rows.begin());
715 file = (*iter)[freesound_list_columns.pathname];
716 chooser.set_filename (file);
717 set_response_sensitive (RESPONSE_OK, true);
718 } else {
719 set_response_sensitive (RESPONSE_OK, false);
722 preview.setup_labels (file);
726 void
727 SoundFileBrowser::found_search_clicked ()
729 string tag_string = found_entry.get_text ();
731 vector<string> tags;
733 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
734 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
735 return;
738 vector<string> results;
739 Library->search_members_and (results, tags);
741 found_list->clear();
742 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
743 TreeModel::iterator new_row = found_list->append();
744 TreeModel::Row row = *new_row;
745 string path = Glib::filename_from_uri (string ("file:") + *i);
746 row[found_list_columns.pathname] = path;
750 void*
751 freesound_search_thread_entry (void* arg)
753 SessionEvent::create_per_thread_pool ("freesound events", 64);
755 static_cast<SoundFileBrowser*>(arg)->freesound_search_thread ();
757 return 0;
760 bool searching = false;
761 bool canceling = false;
763 void
764 SoundFileBrowser::freesound_search_clicked ()
766 if (canceling) //already canceling, button does nothing
767 return;
769 if ( searching ) {
770 freesound_search_btn.set_label(_("Cancelling.."));
771 canceling = true;
772 } else {
773 searching = true;
774 freesound_search_btn.set_label(_("Cancel"));
775 pthread_t freesound_thr;
776 pthread_create_and_store ("freesound_search", &freesound_thr, freesound_search_thread_entry, this);
780 void
781 SoundFileBrowser::freesound_search_thread()
783 #if 0
785 THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD
787 #ifdef FREESOUND
788 freesound_list->clear();
790 string path;
791 path = Glib::get_home_dir();
792 path += "/Freesound/";
793 Mootcher theMootcher(path.c_str());
795 string name_string = freesound_name_entry.get_text ();
796 string pass_string = freesound_pass_entry.get_text ();
797 string search_string = freesound_entry.get_text ();
799 if ( theMootcher.doLogin( name_string, pass_string ) ) {
801 string theString = theMootcher.searchText(search_string);
803 XMLTree doc;
804 doc.read_buffer( theString );
805 XMLNode *root = doc.root();
807 if (root==NULL) return;
809 if ( strcmp(root->name().c_str(), "freesound") == 0) {
811 XMLNode *node = 0;
812 XMLNodeList children = root->children();
813 XMLNodeConstIterator niter;
814 for (niter = children.begin(); niter != children.end() && !canceling; ++niter) {
815 node = *niter;
816 if( strcmp( node->name().c_str(), "sample") == 0 ){
817 XMLProperty *prop=node->property ("id");
818 string filename = theMootcher.getFile( prop->value().c_str() );
819 if ( filename != "" ) {
820 TreeModel::iterator new_row = freesound_list->append();
821 TreeModel::Row row = *new_row;
822 string path = Glib::filename_from_uri (string ("file:") + filename);
823 row[freesound_list_columns.pathname] = path;
830 searching = false;
831 canceling = false;
832 freesound_search_btn.set_label(_("Start Downloading"));
833 #endif
834 #endif
838 vector<ustring>
839 SoundFileBrowser::get_paths ()
841 vector<ustring> results;
843 int n = notebook.get_current_page ();
845 if (n == 0) {
846 vector<ustring> filenames = chooser.get_filenames();
847 vector<ustring>::iterator i;
849 for (i = filenames.begin(); i != filenames.end(); ++i) {
850 struct stat buf;
851 if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
852 results.push_back (*i);
856 } else if (n==1){
858 typedef TreeView::Selection::ListHandle_Path ListPath;
860 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
861 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
862 TreeIter iter = found_list->get_iter(*i);
863 ustring str = (*iter)[found_list_columns.pathname];
865 results.push_back (str);
867 } else {
869 typedef TreeView::Selection::ListHandle_Path ListPath;
871 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
872 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
873 TreeIter iter = freesound_list->get_iter(*i);
874 ustring str = (*iter)[freesound_list_columns.pathname];
876 results.push_back (str);
880 return results;
883 void
884 SoundFileOmega::reset_options_noret ()
886 if (!resetting_ourselves) {
887 (void) reset_options ();
891 bool
892 SoundFileOmega::reset_options ()
894 vector<ustring> paths = get_paths ();
896 if (paths.empty()) {
898 channel_combo.set_sensitive (false);
899 action_combo.set_sensitive (false);
900 where_combo.set_sensitive (false);
901 copy_files_btn.set_sensitive (false);
903 return false;
905 } else {
907 channel_combo.set_sensitive (true);
908 action_combo.set_sensitive (true);
909 where_combo.set_sensitive (true);
911 /* if we get through this function successfully, this may be
912 reset at the end, once we know if we can use hard links
913 to do embedding
916 if (Config->get_only_copy_imported_files()) {
917 copy_files_btn.set_sensitive (false);
918 } else {
919 copy_files_btn.set_sensitive (false);
923 bool same_size;
924 bool src_needed;
925 bool selection_includes_multichannel;
926 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
927 ImportMode mode;
929 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
930 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
931 return false;
934 ustring existing_choice;
935 vector<string> action_strings;
937 if (selected_track_cnt > 0) {
938 if (channel_combo.get_active_text().length()) {
939 ImportDisposition id = get_channel_disposition();
941 switch (id) {
942 case Editing::ImportDistinctFiles:
943 if (selected_track_cnt == paths.size()) {
944 action_strings.push_back (importmode2string (ImportToTrack));
946 break;
948 case Editing::ImportDistinctChannels:
949 /* XXX it would be nice to allow channel-per-selected track
950 but its too hard we don't want to deal with all the
951 different per-file + per-track channel configurations.
953 break;
955 default:
956 action_strings.push_back (importmode2string (ImportToTrack));
957 break;
962 action_strings.push_back (importmode2string (ImportAsTrack));
963 action_strings.push_back (importmode2string (ImportAsRegion));
964 action_strings.push_back (importmode2string (ImportAsTapeTrack));
966 resetting_ourselves = true;
968 existing_choice = action_combo.get_active_text();
970 set_popdown_strings (action_combo, action_strings);
972 /* preserve any existing choice, if possible */
975 if (existing_choice.length()) {
976 vector<string>::iterator x;
977 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
978 if (*x == existing_choice) {
979 action_combo.set_active_text (existing_choice);
980 break;
983 if (x == action_strings.end()) {
984 action_combo.set_active_text (action_strings.front());
986 } else {
987 action_combo.set_active_text (action_strings.front());
990 resetting_ourselves = false;
992 if ((mode = get_mode()) == ImportAsRegion) {
993 where_combo.set_sensitive (false);
994 } else {
995 where_combo.set_sensitive (true);
998 vector<string> channel_strings;
1000 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1001 channel_strings.push_back (_("one track per file"));
1003 if (selection_includes_multichannel) {
1004 channel_strings.push_back (_("one track per channel"));
1007 if (paths.size() > 1) {
1008 /* tape tracks are a single region per track, so we cannot
1009 sequence multiple files.
1011 if (mode != ImportAsTapeTrack) {
1012 channel_strings.push_back (_("sequence files"));
1014 if (same_size) {
1015 channel_strings.push_back (_("all files in one track"));
1020 } else {
1021 channel_strings.push_back (_("one region per file"));
1023 if (selection_includes_multichannel) {
1024 channel_strings.push_back (_("one region per channel"));
1027 if (paths.size() > 1) {
1028 if (same_size) {
1029 channel_strings.push_back (_("all files in one region"));
1034 existing_choice = channel_combo.get_active_text();
1036 set_popdown_strings (channel_combo, channel_strings);
1038 /* preserve any existing choice, if possible */
1040 if (existing_choice.length()) {
1041 vector<string>::iterator x;
1042 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1043 if (*x == existing_choice) {
1044 channel_combo.set_active_text (existing_choice);
1045 break;
1048 if (x == channel_strings.end()) {
1049 channel_combo.set_active_text (channel_strings.front());
1051 } else {
1052 channel_combo.set_active_text (channel_strings.front());
1055 if (src_needed) {
1056 src_combo.set_sensitive (true);
1057 } else {
1058 src_combo.set_sensitive (false);
1061 if (Config->get_only_copy_imported_files()) {
1063 if (selection_can_be_embedded_with_links) {
1064 copy_files_btn.set_sensitive (true);
1065 } else {
1066 copy_files_btn.set_sensitive (false);
1069 } else {
1071 copy_files_btn.set_sensitive (true);
1074 return true;
1078 bool
1079 SoundFileOmega::bad_file_message()
1081 MessageDialog msg (*this,
1082 _("One or more of the selected files\ncannot be used by Ardour"),
1083 true,
1084 Gtk::MESSAGE_INFO,
1085 Gtk::BUTTONS_OK);
1086 msg.run ();
1087 resetting_ourselves = true;
1088 chooser.unselect_uri (chooser.get_preview_uri());
1089 resetting_ourselves = false;
1091 return false;
1094 bool
1095 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1097 SoundFileInfo info;
1098 nframes64_t sz = 0;
1099 bool err = false;
1100 string errmsg;
1102 same_size = true;
1103 src_needed = false;
1104 multichannel = false;
1106 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1108 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1109 if (info.channels > 1) {
1110 multichannel = true;
1112 if (sz == 0) {
1113 sz = info.length;
1114 } else {
1115 if (sz != info.length) {
1116 same_size = false;
1120 if ((nframes_t) info.samplerate != _session->frame_rate()) {
1121 src_needed = true;
1124 } else if (SMFSource::safe_midi_file_extension (*i)) {
1126 Evoral::SMF reader;
1127 reader.open(*i);
1128 if (reader.num_tracks() > 1) {
1129 multichannel = true; // "channel" == track here...
1132 /* XXX we need err = true handling here in case
1133 we can't check the file
1136 } else {
1137 err = true;
1141 return err;
1145 bool
1146 SoundFileOmega::check_link_status (const Session* s, const vector<ustring>& paths)
1148 sys::path path = s->session_directory().sound_path() / "linktest";
1149 string tmpdir = path.to_string();
1150 bool ret = false;
1152 if (mkdir (tmpdir.c_str(), 0744)) {
1153 if (errno != EEXIST) {
1154 return false;
1158 for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1160 char tmpc[MAXPATHLEN+1];
1162 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1164 /* can we link ? */
1166 if (link ((*i).c_str(), tmpc)) {
1167 goto out;
1170 unlink (tmpc);
1173 ret = true;
1175 out:
1176 rmdir (tmpdir.c_str());
1177 return ret;
1180 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
1181 : SoundFileBrowser (parent, title, s, false)
1183 chooser.set_select_multiple (false);
1184 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1185 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1188 void
1189 SoundFileChooser::on_hide ()
1191 ArdourDialog::on_hide();
1192 stop_metering ();
1194 if (_session) {
1195 _session->cancel_audition();
1199 ustring
1200 SoundFileChooser::get_filename ()
1202 vector<ustring> paths;
1204 paths = get_paths ();
1206 if (paths.empty()) {
1207 return ustring ();
1210 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1211 return ustring();
1214 return paths.front();
1217 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks, bool persistent,
1218 Editing::ImportMode mode_hint)
1219 : SoundFileBrowser (parent, title, s, persistent),
1220 copy_files_btn ( _("Copy files to session")),
1221 selected_track_cnt (selected_tracks)
1223 VBox* vbox;
1224 HBox* hbox;
1225 vector<string> str;
1227 set_size_request (-1, 450);
1229 block_two.set_border_width (12);
1230 block_three.set_border_width (12);
1231 block_four.set_border_width (12);
1233 options.set_spacing (12);
1235 str.clear ();
1236 str.push_back (_("file timestamp"));
1237 str.push_back (_("edit point"));
1238 str.push_back (_("playhead"));
1239 str.push_back (_("session start"));
1240 set_popdown_strings (where_combo, str);
1241 where_combo.set_active_text (str.front());
1243 Label* l = manage (new Label);
1244 l->set_text (_("Add files:"));
1246 hbox = manage (new HBox);
1247 hbox->set_border_width (12);
1248 hbox->set_spacing (6);
1249 hbox->pack_start (*l, false, false);
1250 hbox->pack_start (action_combo, false, false);
1251 vbox = manage (new VBox);
1252 vbox->pack_start (*hbox, false, false);
1253 options.pack_start (*vbox, false, false);
1255 /* dummy entry for action combo so that it doesn't look odd if we
1256 come up with no tracks selected.
1259 str.clear ();
1260 str.push_back (importmode2string (mode_hint));
1261 set_popdown_strings (action_combo, str);
1262 action_combo.set_active_text (str.front());
1263 action_combo.set_sensitive (false);
1265 l = manage (new Label);
1266 l->set_text (_("Insert at:"));
1268 hbox = manage (new HBox);
1269 hbox->set_border_width (12);
1270 hbox->set_spacing (6);
1271 hbox->pack_start (*l, false, false);
1272 hbox->pack_start (where_combo, false, false);
1273 vbox = manage (new VBox);
1274 vbox->pack_start (*hbox, false, false);
1275 options.pack_start (*vbox, false, false);
1278 l = manage (new Label);
1279 l->set_text (_("Mapping:"));
1281 hbox = manage (new HBox);
1282 hbox->set_border_width (12);
1283 hbox->set_spacing (6);
1284 hbox->pack_start (*l, false, false);
1285 hbox->pack_start (channel_combo, false, false);
1286 vbox = manage (new VBox);
1287 vbox->pack_start (*hbox, false, false);
1288 options.pack_start (*vbox, false, false);
1290 str.clear ();
1291 str.push_back (_("one track per file"));
1292 set_popdown_strings (channel_combo, str);
1293 channel_combo.set_active_text (str.front());
1294 channel_combo.set_sensitive (false);
1296 l = manage (new Label);
1297 l->set_text (_("Conversion quality:"));
1299 hbox = manage (new HBox);
1300 hbox->set_border_width (12);
1301 hbox->set_spacing (6);
1302 hbox->pack_start (*l, false, false);
1303 hbox->pack_start (src_combo, false, false);
1304 vbox = manage (new VBox);
1305 vbox->pack_start (*hbox, false, false);
1306 options.pack_start (*vbox, false, false);
1308 str.clear ();
1309 str.push_back (_("Best"));
1310 str.push_back (_("Good"));
1311 str.push_back (_("Quick"));
1312 str.push_back (_("Fast"));
1313 str.push_back (_("Fastest"));
1315 set_popdown_strings (src_combo, str);
1316 src_combo.set_active_text (str.front());
1317 src_combo.set_sensitive (false);
1319 reset_options ();
1321 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1323 copy_files_btn.set_active (true);
1325 block_four.pack_start (copy_files_btn, false, false);
1327 options.pack_start (block_four, false, false);
1329 get_vbox()->pack_start (options, false, false);
1331 /* setup disposition map */
1333 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1334 disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1335 disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1336 disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1338 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1339 disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1340 disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1341 disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1343 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1345 /* set size requests for a couple of combos to allow them to display the longest text
1346 they will ever be asked to display. This prevents them being resized when the user
1347 selects a file to import, which in turn prevents the size of the dialog from jumping
1348 around. */
1350 vector<string> t;
1351 t.push_back (_("one track per file"));
1352 t.push_back (_("one track per channel"));
1353 t.push_back (_("sequence files"));
1354 t.push_back (_("all files in one region"));
1355 set_size_request_to_display_given_text (channel_combo, t, COMBO_FUDGE + 10, 15);
1357 t.clear ();
1358 t.push_back (importmode2string (ImportAsTrack));
1359 t.push_back (importmode2string (ImportToTrack));
1360 t.push_back (importmode2string (ImportAsRegion));
1361 t.push_back (importmode2string (ImportAsTapeTrack));
1362 set_size_request_to_display_given_text (action_combo, t, COMBO_FUDGE + 10, 15);
1365 void
1366 SoundFileOmega::set_mode (ImportMode mode)
1368 action_combo.set_active_text (importmode2string (mode));
1371 ImportMode
1372 SoundFileOmega::get_mode () const
1374 return string2importmode (action_combo.get_active_text());
1377 void
1378 SoundFileOmega::on_hide ()
1380 ArdourDialog::on_hide();
1381 if (_session) {
1382 _session->cancel_audition();
1386 ImportPosition
1387 SoundFileOmega::get_position() const
1389 ustring str = where_combo.get_active_text();
1391 if (str == _("file timestamp")) {
1392 return ImportAtTimestamp;
1393 } else if (str == _("edit point")) {
1394 return ImportAtEditPoint;
1395 } else if (str == _("playhead")) {
1396 return ImportAtPlayhead;
1397 } else {
1398 return ImportAtStart;
1402 SrcQuality
1403 SoundFileOmega::get_src_quality() const
1405 ustring str = where_combo.get_active_text();
1407 if (str == _("Best")) {
1408 return SrcBest;
1409 } else if (str == _("Good")) {
1410 return SrcGood;
1411 } else if (str == _("Quick")) {
1412 return SrcQuick;
1413 } else if (str == _("Fast")) {
1414 return SrcFast;
1415 } else {
1416 return SrcFastest;
1420 ImportDisposition
1421 SoundFileOmega::get_channel_disposition () const
1423 /* we use a map here because the channel combo can contain different strings
1424 depending on the state of the other combos. the map contains all possible strings
1425 and the ImportDisposition enum that corresponds to it.
1428 ustring str = channel_combo.get_active_text();
1429 DispositionMap::const_iterator x = disposition_map.find (str);
1431 if (x == disposition_map.end()) {
1432 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1433 /*NOTREACHED*/
1436 return x->second;
1439 void
1440 SoundFileOmega::reset (int selected_tracks)
1442 selected_track_cnt = selected_tracks;
1443 reset_options ();
1446 void
1447 SoundFileOmega::file_selection_changed ()
1449 if (resetting_ourselves) {
1450 return;
1453 if (!reset_options ()) {
1454 set_response_sensitive (RESPONSE_OK, false);
1455 } else {
1456 if (chooser.get_filenames().size() > 0) {
1457 set_response_sensitive (RESPONSE_OK, true);
1458 } else {
1459 set_response_sensitive (RESPONSE_OK, false);