2 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
3 * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
4 * Copyright (C) 2006-2018 Paul Davis <paul@linuxaudiosystems.com>
5 * Copyright (C) 2006 Doug McLain <doug@nostar.net>
6 * Copyright (C) 2006 Nick Mainsbridge <mainsbridge@gmail.com>
7 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8 * Copyright (C) 2012-2017 Tim Mayberry <mojofunk@gmail.com>
9 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
10 * Copyright (C) 2013-2015 John Emmas <john@creativepost.co.uk>
11 * Copyright (C) 2013 Colin Fletcher <colin.m.fletcher@googlemail.com>
12 * Copyright (C) 2019-2018 Ben Loftis <ben@harrisonconsoles.com>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "gtk2ardour-config.h"
33 #ifdef PLATFORM_WINDOWS
44 #include <gtkmm/box.h>
45 #include <gtkmm/scrolledwindow.h>
46 #include <gtkmm/stock.h>
48 #include "pbd/gstdio_compat.h"
49 #include <glibmm/fileutils.h>
51 #include "pbd/tokenizer.h"
52 #include "pbd/enumwriter.h"
53 #include "pbd/file_utils.h"
54 #include "pbd/pthread_utils.h"
55 #include "pbd/string_convert.h"
56 #include "pbd/xml++.h"
58 #include <gtkmm2ext/utils.h>
60 #include "evoral/SMF.h"
62 #include "ardour/audio_library.h"
63 #include "ardour/auditioner.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/audiofilesource.h"
66 #include "ardour/midi_region.h"
67 #include "ardour/smf_source.h"
68 #include "ardour/region_factory.h"
69 #include "ardour/source_factory.h"
70 #include "ardour/session.h"
71 #include "ardour/session_directory.h"
72 #include "ardour/srcfilesource.h"
73 #include "ardour/profile.h"
75 #include "ardour_ui.h"
77 #include "gui_thread.h"
80 #include "gain_meter.h"
81 #include "main_clock.h"
82 #include "public_editor.h"
84 #include "ui_config.h"
86 #include "sfdb_freesound_mootcher.h"
90 using namespace ARDOUR;
94 using namespace Gtkmm2ext;
95 using namespace Editing;
99 string SoundFileBrowser::persistent_folder;
100 typedef TreeView::Selection::ListHandle_Path ListPath;
102 static MidiTrackNameSource
103 string2miditracknamesource (string const & str)
105 if (str == _("by track number")) {
106 return SMFTrackNumber;
107 } else if (str == _("by track name")) {
109 } else if (str == _("by instrument name")) {
110 return SMFInstrumentName;
113 warning << string_compose (_("programming error: unknown midi track name source string %1"), str) << endmsg;
115 return SMFTrackNumber;
119 string2importmode (string const & str)
121 if (str == _("as new tracks")) {
122 return ImportAsTrack;
123 } else if (str == _("to selected tracks")) {
124 return ImportToTrack;
125 } else if (str == _("to source list")) {
126 return ImportAsRegion;
127 } else if (str == _("as new tape tracks")) {
128 return ImportAsTapeTrack;
131 warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
133 return ImportAsTrack;
137 importmode2string (ImportMode mode)
141 return _("as new tracks");
143 return _("to selected tracks");
145 return _("to source list");
146 case ImportAsTapeTrack:
147 return _("as new tape tracks");
149 abort(); /*NOTREACHED*/
150 return _("as new tracks");
153 SoundFileBox::SoundFileBox (bool /*persistent*/)
155 length_clock ("sfboxLengthClock", true, "", false, false, true, false),
156 timecode_clock ("sfboxTimecodeClock", true, "", false, false, false, false),
158 autoplay_btn (_("Auto-play")),
159 seek_slider(0,1000,1),
161 _src_quality (SrcBest),
162 _import_position (ImportAtTimestamp)
165 set_name (X_("SoundFileBox"));
166 set_size_request (300, -1);
168 preview_label.set_markup (_("<b>Sound File Information</b>"));
170 border_frame.set_label_widget (preview_label);
171 border_frame.add (main_box);
173 pack_start (border_frame, true, true);
174 set_border_width (6);
176 main_box.set_border_width (6);
178 length.set_text (_("Length:"));
179 length.set_alignment (1, 0.5);
180 timecode.set_text (_("Timestamp:"));
181 timecode.set_alignment (1, 0.5);
182 format.set_text (_("Format:"));
183 format.set_alignment (1, 0.5);
184 channels.set_text (_("Channels:"));
185 channels.set_alignment (1, 0.5);
186 samplerate.set_text (_("Sample rate:"));
187 samplerate.set_alignment (1, 0.5);
188 tempomap.set_text (_("Tempo Map:"));
189 tempomap.set_alignment (1, 0.5);
191 preview_label.set_max_width_chars (50);
192 preview_label.set_ellipsize (Pango::ELLIPSIZE_END);
194 format_text.set_max_width_chars (20);
195 format_text.set_ellipsize (Pango::ELLIPSIZE_END);
196 format_text.set_alignment (0, 1);
198 table.set_col_spacings (6);
199 table.set_homogeneous (false);
200 table.set_row_spacings (6);
202 table.attach (channels, 0, 1, 0, 1, FILL, FILL);
203 table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
204 table.attach (format, 0, 1, 2, 4, FILL, FILL);
205 table.attach (length, 0, 1, 4, 5, FILL, FILL);
206 table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
207 table.attach (tempomap, 0, 1, 6, 7, FILL, FILL);
209 table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
210 table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
211 table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
212 table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
213 table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
214 table.attach (tempomap_value, 1, 2, 6, 7, FILL, FILL);
216 length_clock.set_mode (ARDOUR_UI::instance()->primary_clock->mode());
217 timecode_clock.set_mode (AudioClock::Timecode);
219 main_box.pack_start (table, false, false);
221 tags_entry.set_editable (true);
222 tags_entry.set_wrap_mode(Gtk::WRAP_WORD);
223 tags_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
225 Label* label = manage (new Label (_("Tags:")));
226 label->set_alignment (0.0f, 0.5f);
227 main_box.pack_start (*label, false, false);
228 main_box.pack_start (tags_entry, true, true);
230 main_box.pack_start (bottom_box, false, false);
232 play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
233 // play_btn.set_label (_("Play"));
235 stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
236 // stop_btn.set_label (_("Stop"));
238 bottom_box.set_homogeneous (false);
239 bottom_box.set_spacing (6);
240 bottom_box.pack_start(play_btn, true, true);
241 bottom_box.pack_start(stop_btn, true, true);
242 bottom_box.pack_start(autoplay_btn, false, false);
244 seek_slider.set_draw_value(false);
246 seek_slider.add_events(Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
247 seek_slider.signal_button_press_event().connect(sigc::mem_fun(*this, &SoundFileBox::seek_button_press), false);
248 seek_slider.signal_button_release_event().connect(sigc::mem_fun(*this, &SoundFileBox::seek_button_release), false);
249 main_box.pack_start (seek_slider, false, false);
251 play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
252 stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
255 autoplay_btn.signal_toggled().connect(sigc::mem_fun (*this, &SoundFileBox::autoplay_toggled));
257 stop_btn.set_sensitive (false);
259 channels_value.set_alignment (0.0f, 0.5f);
260 samplerate_value.set_alignment (0.0f, 0.5f);
264 SoundFileBox::set_session(Session* s)
266 SessionHandlePtr::set_session (s);
268 length_clock.set_session (s);
269 timecode_clock.set_session (s);
272 play_btn.set_sensitive (false);
273 stop_btn.set_sensitive (false);
274 auditioner_connections.drop_connections();
276 auditioner_connections.drop_connections();
277 _session->AuditionActive.connect(auditioner_connections, invalidator (*this), boost::bind (&SoundFileBox::audition_active, this, _1), gui_context());
278 _session->the_auditioner()->AuditionProgress.connect(auditioner_connections, invalidator (*this), boost::bind (&SoundFileBox::audition_progress, this, _1, _2), gui_context());
283 SoundFileBox::audition_active(bool active) {
284 stop_btn.set_sensitive (active);
285 seek_slider.set_sensitive (active);
287 seek_slider.set_value(0);
292 SoundFileBox::audition_progress(ARDOUR::samplecnt_t pos, ARDOUR::samplecnt_t len) {
294 seek_slider.set_value( 1000.0 * pos / len);
295 seek_slider.set_sensitive (true);
300 SoundFileBox::seek_button_press(GdkEventButton*) {
302 return false; // pass on to slider
306 SoundFileBox::seek_button_release(GdkEventButton*) {
308 _session->the_auditioner()->seek_to_percent(seek_slider.get_value() / 10.0);
309 seek_slider.set_sensitive (false);
310 return false; // pass on to slider
314 SoundFileBox::setup_labels (const string& filename)
317 // save existing tags
325 if (SMFSource::valid_midi_file (path)) {
327 boost::shared_ptr<SMFSource> ms;
329 ms = boost::dynamic_pointer_cast<SMFSource> (
330 SourceFactory::createExternal (DataType::MIDI, *_session,
331 path, 0, Source::Flag (0), false));
332 } catch (const std::exception& e) {
333 error << string_compose(_("Could not read file: %1 (%2)."),
334 path, e.what()) << endmsg;
337 preview_label.set_markup (_("<b>Midi File Information</b>"));
339 format_text.set_text ("MIDI");
340 samplerate_value.set_text ("-");
341 tags_entry.get_buffer()->set_text ("");
342 timecode_clock.set (0);
343 tags_entry.set_sensitive (false);
346 if (ms->is_type0()) {
347 channels_value.set_text (to_string<uint32_t>(ms->channels().size()));
349 if (ms->num_tracks() > 1) {
350 channels_value.set_text (to_string(ms->num_tracks()) + _("(Tracks)"));
352 channels_value.set_text (to_string(ms->num_tracks()));
355 length_clock.set (ms->length(ms->natural_position()));
356 switch (ms->num_tempos()) {
358 tempomap_value.set_text (_("No tempo data"));
361 Evoral::SMF::Tempo* t = ms->nth_tempo (0);
363 tempomap_value.set_text (string_compose (_("%1/%2 \u2669 = %3"),
370 tempomap_value.set_text (string_compose (_("map with %1 sections"),
375 channels_value.set_text ("");
376 length_clock.set (0);
377 tempomap_value.set_text (_("No tempo data"));
380 if (_session && ms) {
381 play_btn.set_sensitive (true);
383 play_btn.set_sensitive (false);
389 if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
391 preview_label.set_markup (_("<b>Sound File Information</b>"));
392 format_text.set_text ("");
393 channels_value.set_text ("");
394 samplerate_value.set_text ("");
395 tags_entry.get_buffer()->set_text ("");
397 length_clock.set (0);
398 timecode_clock.set (0);
400 tags_entry.set_sensitive (false);
401 play_btn.set_sensitive (false);
406 preview_label.set_markup (string_compose ("<b>%1</b>", Glib::Markup::escape_text (Glib::path_get_basename (filename))));
407 std::string n = sf_info.format_name;
408 if (n.substr (0, 8) == X_("Format: ")) {
411 format_text.set_text (n);
412 channels_value.set_text (to_string (sf_info.channels));
414 if (_session && sf_info.samplerate != _session->sample_rate()) {
415 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
416 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
417 samplerate_value.set_name ("NewSessionSR1Label");
418 samplerate.set_name ("NewSessionSR1Label");
420 samplerate.set_text (_("Sample rate:"));
421 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
422 samplerate_value.set_name ("NewSessionSR2Label");
423 samplerate.set_name ("NewSessionSR2Label");
426 samplecnt_t const nfr = _session ? _session->nominal_sample_rate() : 25;
427 double src_coef = (double) nfr / sf_info.samplerate;
429 length_clock.set (sf_info.length * src_coef + 0.5, true);
430 timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
432 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
434 vector<string> tags = Library->get_tags (string ("//") + filename);
436 stringstream tag_string;
437 for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
438 if (i != tags.begin()) {
443 tags_entry.get_buffer()->set_text (tag_string.str());
445 tags_entry.set_sensitive (true);
447 play_btn.set_sensitive (true);
454 SoundFileBox::update_autoplay ()
456 const bool config_autoplay = UIConfiguration::instance().get_autoplay_files();
458 if (autoplay_btn.get_active() != config_autoplay) {
459 autoplay_btn.set_active (config_autoplay);
464 SoundFileBox::autoplay_toggled()
466 UIConfiguration::instance().set_autoplay_files(autoplay_btn.get_active());
470 SoundFileBox::autoplay() const
472 return autoplay_btn.get_active();
476 SoundFileBox::audition_oneshot()
483 SoundFileBox::audition ()
489 _session->cancel_audition();
491 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
492 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
496 boost::shared_ptr<Region> r;
498 if (SMFSource::valid_midi_file (path)) {
500 boost::shared_ptr<SMFSource> ms =
501 boost::dynamic_pointer_cast<SMFSource> (
502 SourceFactory::createExternal (DataType::MIDI, *_session,
503 path, 0, Source::Flag (0), false));
505 string rname = region_name_from_path (ms->path(), false);
509 plist.add (ARDOUR::Properties::start, 0);
510 plist.add (ARDOUR::Properties::length, ms->length(ms->natural_position()));
511 plist.add (ARDOUR::Properties::name, rname);
512 plist.add (ARDOUR::Properties::layer, 0);
514 r = boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (boost::dynamic_pointer_cast<Source>(ms), plist, false));
520 boost::shared_ptr<AudioFileSource> afs;
521 bool old_sbp = AudioSource::get_build_peakfiles ();
523 /* don't even think of building peakfiles for these files */
525 AudioSource::set_build_peakfiles (false);
527 for (int n = 0; n < sf_info.channels; ++n) {
529 afs = boost::dynamic_pointer_cast<AudioFileSource> (
530 SourceFactory::createExternal (DataType::AUDIO, *_session,
532 Source::Flag (ARDOUR::AudioFileSource::NoPeakFile), false));
533 if (afs->sample_rate() != _session->nominal_sample_rate()) {
534 boost::shared_ptr<SrcFileSource> sfs (new SrcFileSource(*_session, afs, _src_quality));
535 srclist.push_back(sfs);
537 srclist.push_back(afs);
540 } catch (failed_constructor& err) {
541 error << _("Could not access soundfile: ") << path << endmsg;
542 AudioSource::set_build_peakfiles (old_sbp);
547 AudioSource::set_build_peakfiles (old_sbp);
549 if (srclist.empty()) {
553 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
554 string rname = region_name_from_path (afs->path(), false);
558 plist.add (ARDOUR::Properties::start, 0);
559 plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->natural_position()));
560 plist.add (ARDOUR::Properties::name, rname);
561 plist.add (ARDOUR::Properties::layer, 0);
563 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
566 sampleoffset_t audition_position = 0;
567 switch(_import_position) {
568 case ImportAtTimestamp:
569 audition_position = 0;
571 case ImportAtPlayhead:
572 audition_position = _session->transport_sample();
575 audition_position = _session->current_start_sample();
577 case ImportAtEditPoint:
578 audition_position = PublicEditor::instance().get_preferred_edit_position ();
581 r->set_position(audition_position);
583 _session->audition_region(r);
587 SoundFileBox::stop_audition ()
590 _session->cancel_audition();
595 SoundFileBox::tags_entry_left (GdkEventFocus *)
602 SoundFileBox::tags_changed ()
604 string tag_string = tags_entry.get_buffer()->get_text ();
606 if (tag_string.empty()) {
612 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
613 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
621 SoundFileBox::save_tags (const vector<string>& tags)
623 Library->set_tags (string ("//") + path, tags);
624 Library->save_changes ();
627 SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persistent)
628 : ArdourWindow (title)
629 , found_list (ListStore::create(found_list_columns))
630 , freesound_list (ListStore::create(freesound_list_columns))
631 , chooser (FILE_CHOOSER_ACTION_OPEN)
632 , preview (persistent)
633 , found_search_btn (_("Search"))
634 , found_list_view (found_list)
635 , freesound_search_btn (_("Search"))
636 , freesound_list_view (freesound_list)
637 , resetting_ourselves (false)
641 , import_button (_("Import"))
647 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
648 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
649 chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
650 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
652 catch (Glib::Error & e) {
653 std::cerr << "sfdb.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
656 Gtkmm2ext::add_volume_shortcuts (chooser);
658 //add the file chooser
660 chooser.set_border_width (12);
662 audio_and_midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun (*this, &SoundFileBrowser::on_audio_and_midi_filter));
663 audio_and_midi_filter.set_name (_("Audio and MIDI files"));
665 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
666 audio_filter.set_name (_("Audio files"));
668 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
669 midi_filter.set_name (_("MIDI files"));
671 matchall_filter.add_pattern ("*.*");
672 matchall_filter.set_name (_("All files"));
674 chooser.add_filter (audio_and_midi_filter);
675 chooser.add_filter (audio_filter);
676 chooser.add_filter (midi_filter);
677 chooser.add_filter (matchall_filter);
678 chooser.set_select_multiple (true);
679 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
680 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
683 /* some broken redraw behaviour - this is a bandaid */
684 chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
687 if (!persistent_folder.empty()) {
688 chooser.set_current_folder (persistent_folder);
691 notebook.append_page (chooser, _("Browse Files"));
693 hpacker.set_spacing (6);
694 hpacker.pack_start (notebook, true, true);
695 hpacker.pack_start (preview, false, false);
697 vpacker.set_spacing (6);
698 vpacker.pack_start (hpacker, true, true);
708 hbox = manage(new HBox);
709 hbox->pack_start (found_entry);
710 hbox->pack_start (found_search_btn);
712 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
713 scroll->add(found_list_view);
714 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
716 vbox = manage(new VBox);
717 vbox->pack_start (*hbox, PACK_SHRINK);
718 vbox->pack_start (*scroll);
720 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
722 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
724 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
726 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
727 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
729 notebook.append_page (*vbox, _("Search Tags"));
731 //add freesound search
732 #ifdef FREESOUND_GOT_FIXED
737 passbox = manage(new HBox);
738 passbox->set_spacing (6);
740 label = manage (new Label);
741 label->set_text (_("Tags:"));
742 passbox->pack_start (*label, false, false);
743 passbox->pack_start (freesound_entry, true, true);
745 label = manage (new Label);
746 label->set_text (_("Sort:"));
747 passbox->pack_start (*label, false, false);
748 passbox->pack_start (freesound_sort, false, false);
749 freesound_sort.clear_items();
751 // Order of the following must correspond with enum sortMethod
752 // in sfdb_freesound_mootcher.h
753 freesound_sort.append_text(_("None"));
754 freesound_sort.append_text(_("Longest"));
755 freesound_sort.append_text(_("Shortest"));
756 freesound_sort.append_text(_("Newest"));
757 freesound_sort.append_text(_("Oldest"));
758 freesound_sort.append_text(_("Most downloaded"));
759 freesound_sort.append_text(_("Least downloaded"));
760 freesound_sort.append_text(_("Highest rated"));
761 freesound_sort.append_text(_("Lowest rated"));
762 freesound_sort.set_active(0);
764 passbox->pack_start (freesound_search_btn, false, false);
765 passbox->pack_start (freesound_more_btn, false, false);
766 freesound_more_btn.set_label(_("More"));
767 freesound_more_btn.set_sensitive(false);
769 passbox->pack_start (freesound_similar_btn, false, false);
770 freesound_similar_btn.set_label(_("Similar"));
771 freesound_similar_btn.set_sensitive(false);
773 scroll = manage(new ScrolledWindow);
774 scroll->add(freesound_list_view);
775 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
777 vbox = manage(new VBox);
778 vbox->set_spacing (3);
779 vbox->pack_start (*passbox, PACK_SHRINK);
780 vbox->pack_start (*scroll);
782 freesound_list_view.append_column(_("ID") , freesound_list_columns.id);
783 freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
784 // freesound_list_view.append_column(_("URI") , freesound_list_columns.uri);
785 freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
786 freesound_list_view.append_column(_("Size"), freesound_list_columns.filesize);
787 freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
788 freesound_list_view.append_column(_("License"), freesound_list_columns.license);
789 freesound_list_view.get_column(0)->set_alignment(0.5);
790 freesound_list_view.get_column(1)->set_expand(true); // filename
791 freesound_list_view.get_column(1)->set_resizable(true); // filename
792 freesound_list_view.get_column(2)->set_alignment(0.5);
793 freesound_list_view.get_column(3)->set_alignment(0.5);
794 freesound_list_view.get_column(4)->set_alignment(0.5);
795 freesound_list_view.get_column(5)->set_alignment(0.5);
797 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
798 freesound_list_view.set_tooltip_column(1);
800 freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
801 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
802 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
803 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
804 freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
805 freesound_similar_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_similar_clicked));
806 notebook.append_page (*vbox, _("Search Freesound"));
809 notebook.set_size_request (500, -1);
810 notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options)))));
814 Gtk::HButtonBox* button_box = manage (new HButtonBox);
816 button_box->set_layout (BUTTONBOX_END);
818 button_box->pack_start (import_button, false, false);
819 import_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_OK));
821 Gtkmm2ext::UI::instance()->set_tip (import_button, _("Press to import selected files"));
823 vpacker.pack_end (*button_box, false, false);
825 set_wmclass (X_("import"), PROGRAM_NAME);
828 SoundFileBrowser::~SoundFileBrowser ()
830 persistent_folder = chooser.get_current_folder();
834 SoundFileBrowser::run ()
843 gtk_main_iteration ();
850 SoundFileBrowser::set_action_sensitive (bool yn)
852 import_button.set_sensitive (yn);
856 SoundFileBrowser::get_action_sensitive () const
858 return import_button.get_sensitive ();
862 SoundFileBrowser::do_something (int action)
869 SoundFileBrowser::on_show ()
871 ArdourWindow::on_show ();
877 SoundFileBrowser::on_key_press_event (GdkEventKey* ev)
879 if (ev->keyval == GDK_Escape) {
880 do_something (RESPONSE_CLOSE);
883 if (ev->keyval == GDK_space && ev->type == GDK_KEY_PRESS) {
884 if (get_action_sensitive()) {
889 return ArdourWindow::on_key_press_event (ev);
893 SoundFileBrowser::clear_selection ()
895 chooser.unselect_all ();
896 found_list_view.get_selection()->unselect_all ();
900 SoundFileBrowser::chooser_file_activated ()
902 do_something (RESPONSE_OK);
906 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
912 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
918 SoundFileBrowser::set_session (Session* s)
920 ArdourWindow::set_session (s);
921 preview.set_session (s);
926 remove_gain_meter ();
931 SoundFileBrowser::add_gain_meter ()
935 gm = new GainMeter (_session, 250);
937 boost::shared_ptr<Route> r = _session->the_auditioner ();
939 gm->set_controls (r, r->shared_peak_meter(), r->amp(), r->gain_control());
940 gm->set_fader_name (X_("GainFader"));
942 meter_packer.set_border_width (12);
943 meter_packer.pack_start (*gm, false, true);
944 hpacker.pack_end (meter_packer, false, false);
945 meter_packer.show_all ();
950 SoundFileBrowser::remove_gain_meter ()
953 meter_packer.remove (*gm);
954 hpacker.remove (meter_packer);
961 SoundFileBrowser::start_metering ()
963 metering_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
967 SoundFileBrowser::stop_metering ()
969 metering_connection.disconnect();
973 SoundFileBrowser::meter ()
975 if (is_mapped () && _session && gm) {
976 gm->update_meters ();
981 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
983 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
987 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
989 return SMFSource::safe_midi_file_extension (filter_info.filename);
993 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
995 return on_audio_filter (filter_info) || on_midi_filter (filter_info);
999 SoundFileBrowser::update_preview ()
1001 if (preview.setup_labels (chooser.get_preview_filename())) {
1002 if (preview.autoplay()) {
1003 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
1009 SoundFileBrowser::found_list_view_selected ()
1011 if (!reset_options ()) {
1012 set_action_sensitive (false);
1016 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1018 if (!rows.empty()) {
1019 TreeIter iter = found_list->get_iter(*rows.begin());
1020 file = (*iter)[found_list_columns.pathname];
1021 chooser.set_filename (file);
1022 set_action_sensitive (true);
1024 set_action_sensitive (false);
1027 preview.setup_labels (file);
1032 SoundFileBrowser::found_search_clicked ()
1034 string tag_string = found_entry.get_text ();
1036 vector<string> tags;
1038 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
1039 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
1043 vector<string> results;
1044 Library->search_members_and (results, tags);
1046 found_list->clear();
1047 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
1048 TreeModel::iterator new_row = found_list->append();
1049 TreeModel::Row row = *new_row;
1050 string path = Glib::filename_from_uri (string ("file:") + *i);
1051 row[found_list_columns.pathname] = path;
1057 SoundFileBrowser::freesound_get_audio_file(Gtk::TreeIter iter)
1060 Mootcher *mootcher = new Mootcher;
1063 string id = (*iter)[freesound_list_columns.id];
1064 string uri = (*iter)[freesound_list_columns.uri];
1065 string ofn = (*iter)[freesound_list_columns.filename];
1067 if (mootcher->checkAudioFile(ofn, id)) {
1068 // file already exists, no need to download it again
1069 file = mootcher->audioFileName;
1071 (*iter)[freesound_list_columns.started] = false;
1074 if (!(*iter)[freesound_list_columns.started]) {
1075 // start downloading the sound file
1076 (*iter)[freesound_list_columns.started] = true;
1077 mootcher->fetchAudioFile(ofn, id, uri, this);
1083 SoundFileBrowser::freesound_list_view_selected ()
1086 if (!reset_options ()) {
1087 set_action_sensitive (false);
1090 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1091 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1092 file = freesound_get_audio_file (freesound_list->get_iter(*i));
1095 switch (rows.size()) {
1098 freesound_similar_btn.set_sensitive(false);
1099 set_action_sensitive (false);
1102 // exactly one item selected
1104 // file exists on disk already
1105 chooser.set_filename (file);
1106 preview.setup_labels (file);
1107 set_action_sensitive (true);
1109 freesound_similar_btn.set_sensitive(true);
1112 // multiple items selected
1113 preview.setup_labels ("");
1114 freesound_similar_btn.set_sensitive(false);
1122 SoundFileBrowser::refresh_display(std::string ID, std::string file)
1124 // called when the mootcher has finished downloading a file
1125 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1126 if (rows.size() == 1) {
1127 // there's a single item selected in the freesound list
1128 //XXX make a function to be used to construct the actual file name both here and in the mootcher
1129 Gtk::TreeIter row = freesound_list->get_iter(*rows.begin());
1130 std::string selected_ID = (*row)[freesound_list_columns.id];
1131 if (ID == selected_ID) {
1132 // the selected item in the freesound list is the item that has just finished downloading
1133 chooser.set_filename(file);
1134 preview.setup_labels (file);
1135 set_action_sensitive (true);
1141 SoundFileBrowser::freesound_search_clicked ()
1144 freesound_list->clear();
1150 SoundFileBrowser::freesound_more_clicked ()
1155 snprintf(row_path, 21, "%d", (freesound_page - 1) * 100);
1156 freesound_list_view.scroll_to_row(Gtk::TreePath(row_path), 0);
1160 SoundFileBrowser::freesound_similar_clicked ()
1162 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1163 if (rows.size() == 1) {
1166 Gtk::TreeIter iter = freesound_list->get_iter(*rows.begin());
1167 id = (*iter)[freesound_list_columns.id];
1168 freesound_list->clear();
1170 GdkCursor *prev_cursor;
1171 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1172 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1175 std::string theString = mootcher.searchSimilar(id);
1177 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1178 handle_freesound_results(theString);
1183 SoundFileBrowser::freesound_search()
1187 string search_string = freesound_entry.get_text ();
1188 enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
1190 GdkCursor *prev_cursor;
1191 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1192 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1195 std::string theString = mootcher.searchText(
1199 "", // OSX eats anything incl mp3
1201 "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
1206 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1207 handle_freesound_results(theString);
1211 SoundFileBrowser::handle_freesound_results(std::string theString) {
1213 doc.read_buffer( theString );
1214 XMLNode *root = doc.root();
1217 error << "no root XML node!" << endmsg;
1221 if ( strcmp(root->name().c_str(), "response") != 0) {
1222 error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
1226 // find out how many pages are available to search
1227 int freesound_n_pages = 1;
1228 XMLNode *res = root->child("num_pages");
1230 string result = res->child("text")->content();
1231 freesound_n_pages = atoi(result);
1234 int more_pages = freesound_n_pages - freesound_page;
1236 if (more_pages > 0) {
1237 freesound_more_btn.set_sensitive(true);
1238 freesound_more_btn.set_tooltip_text(string_compose(P_(
1239 "%1 more page of 100 results available",
1240 "%1 more pages of 100 results available",
1241 more_pages), more_pages));
1243 freesound_more_btn.set_sensitive(false);
1244 freesound_more_btn.set_tooltip_text(_("No more results available"));
1247 XMLNode *sounds_root = root->child("sounds");
1249 error << "no child node \"sounds\" found!" << endmsg;
1253 XMLNodeList sounds = sounds_root->children();
1254 if (sounds.size() == 0) {
1259 XMLNodeConstIterator niter;
1261 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
1263 if( strcmp( node->name().c_str(), "resource") != 0 ) {
1264 error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
1268 // node->dump(cerr, "node:");
1271 XMLNode *id_node = node->child ("id");
1272 XMLNode *uri_node = node->child ("serve");
1273 XMLNode *ofn_node = node->child ("original_filename");
1274 XMLNode *dur_node = node->child ("duration");
1275 XMLNode *siz_node = node->child ("filesize");
1276 XMLNode *srt_node = node->child ("samplerate");
1277 XMLNode *lic_node = node->child ("license");
1279 if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
1281 std::string id = id_node->child("text")->content();
1282 std::string uri = uri_node->child("text")->content();
1283 std::string ofn = ofn_node->child("text")->content();
1284 std::string dur = dur_node->child("text")->content();
1285 std::string siz = siz_node->child("text")->content();
1286 std::string srt = srt_node->child("text")->content();
1287 std::string lic = lic_node->child("text")->content();
1290 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
1292 double duration_seconds = atof(dur);
1294 char duration_hhmmss[16];
1295 if (duration_seconds >= 99 * 60 * 60) {
1296 strcpy(duration_hhmmss, ">99h");
1298 s = modf(duration_seconds/60, &m) * 60;
1299 m = modf(m/60, &h) * 60;
1300 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
1305 double size_bytes = atof(siz);
1307 if (size_bytes < 1000) {
1308 sprintf(bsize, "%.0f %s", size_bytes, _("B"));
1309 } else if (size_bytes < 1000000 ) {
1310 sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
1311 } else if (size_bytes < 10000000) {
1312 sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
1313 } else if (size_bytes < 1000000000) {
1314 sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
1316 sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
1319 /* see http://www.freesound.org/help/faq/#licenses */
1320 char shortlicense[64];
1321 if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
1322 sprintf(shortlicense, "CC-BY-NC");
1323 } else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
1324 sprintf(shortlicense, "CC-BY");
1325 } else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
1326 sprintf(shortlicense, "sampling+");
1327 } else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
1328 sprintf(shortlicense, "PD");
1330 snprintf(shortlicense, 64, "%s", lic.c_str());
1331 shortlicense[63]= '\0';
1334 TreeModel::iterator new_row = freesound_list->append();
1335 TreeModel::Row row = *new_row;
1337 row[freesound_list_columns.id ] = id;
1338 row[freesound_list_columns.uri ] = uri;
1339 row[freesound_list_columns.filename] = ofn;
1340 row[freesound_list_columns.duration] = duration_hhmmss;
1341 row[freesound_list_columns.filesize] = bsize;
1342 row[freesound_list_columns.smplrate] = srt;
1343 row[freesound_list_columns.license ] = shortlicense;
1350 SoundFileBrowser::get_paths ()
1352 vector<string> results;
1354 int n = notebook.get_current_page ();
1357 vector<string> filenames = chooser.get_filenames();
1358 vector<string>::iterator i;
1360 for (i = filenames.begin(); i != filenames.end(); ++i) {
1362 if ((!g_stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1363 results.push_back (*i);
1367 } else if (n == 1) {
1369 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1370 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1371 TreeIter iter = found_list->get_iter(*i);
1372 string str = (*iter)[found_list_columns.pathname];
1374 results.push_back (str);
1377 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1378 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1379 string str = freesound_get_audio_file (freesound_list->get_iter(*i));
1381 results.push_back (str);
1390 SoundFileOmega::reset_options_noret ()
1392 if (!resetting_ourselves) {
1393 (void) reset_options ();
1398 SoundFileOmega::reset_options ()
1400 if (_import_active) {
1401 _reset_post_import = true;
1405 vector<string> paths = get_paths ();
1407 if (paths.empty()) {
1409 channel_combo.set_sensitive (false);
1410 action_combo.set_sensitive (false);
1411 where_combo.set_sensitive (false);
1412 copy_files_btn.set_active (true);
1413 copy_files_btn.set_sensitive (false);
1419 channel_combo.set_sensitive (true);
1420 action_combo.set_sensitive (true);
1421 where_combo.set_sensitive (true);
1423 /* if we get through this function successfully, this may be
1424 reset at the end, once we know if we can use hard links
1425 to do embedding (or if we are importing a MIDI file).
1428 if (UIConfiguration::instance().get_only_copy_imported_files()) {
1429 copy_files_btn.set_sensitive (false);
1431 copy_files_btn.set_sensitive (false);
1438 bool selection_includes_multichannel;
1439 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1442 /* See if we are thinking about importing any MIDI files */
1443 vector<string>::iterator i = paths.begin ();
1444 while (i != paths.end() && SMFSource::valid_midi_file (*i) == false) {
1447 bool const have_a_midi_file = (i != paths.end ());
1449 if (check_info (paths, same_size, src_needed, selection_includes_multichannel, must_copy)) {
1450 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1454 if (have_a_midi_file) {
1455 smf_tempo_btn.show ();
1457 smf_tempo_btn.hide ();
1460 string existing_choice;
1461 vector<string> action_strings;
1463 resetting_ourselves = true;
1465 if (chooser.get_filter() == &audio_filter) {
1469 if (selected_audio_track_cnt > 0) {
1470 if (channel_combo.get_active_text().length()) {
1471 ImportDisposition id = get_channel_disposition();
1474 case Editing::ImportDistinctFiles:
1475 if (selected_audio_track_cnt == paths.size()) {
1476 action_strings.push_back (importmode2string (ImportToTrack));
1480 case Editing::ImportDistinctChannels:
1481 /* XXX it would be nice to allow channel-per-selected track
1482 but its too hard we don't want to deal with all the
1483 different per-file + per-track channel configurations.
1488 action_strings.push_back (importmode2string (ImportToTrack));
1498 if (selected_midi_track_cnt > 0) {
1499 action_strings.push_back (importmode2string (ImportToTrack));
1503 action_strings.push_back (importmode2string (ImportAsTrack));
1504 action_strings.push_back (importmode2string (ImportAsRegion));
1505 if (!Profile->get_mixbus()) {
1506 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1509 existing_choice = action_combo.get_active_text();
1511 set_popdown_strings (action_combo, action_strings);
1513 /* preserve any existing choice, if possible */
1516 if (existing_choice.length()) {
1517 vector<string>::iterator x;
1518 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1519 if (*x == existing_choice) {
1520 action_combo.set_active_text (existing_choice);
1524 if (x == action_strings.end()) {
1525 action_combo.set_active_text (action_strings.front());
1528 action_combo.set_active_text (action_strings.front());
1531 resetting_ourselves = false;
1533 if ((mode = get_mode()) == ImportAsRegion) {
1534 where_combo.set_sensitive (false);
1536 where_combo.set_sensitive (true);
1539 vector<string> channel_strings;
1541 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1543 channel_strings.push_back (_("one track per file"));
1545 if (selection_includes_multichannel) {
1546 channel_strings.push_back (_("one track per channel"));
1549 if (paths.size() > 1) {
1550 /* tape tracks are a single region per track, so we cannot
1551 sequence multiple files.
1553 if (mode != ImportAsTapeTrack) {
1554 channel_strings.push_back (_("sequence files"));
1557 channel_strings.push_back (_("all files in one track"));
1558 channel_strings.push_back (_("merge files"));
1564 channel_strings.push_back (_("one region per file"));
1566 if (selection_includes_multichannel) {
1567 channel_strings.push_back (_("one region per channel"));
1570 if (paths.size() > 1) {
1572 channel_strings.push_back (_("all files in one region"));
1577 resetting_ourselves = true;
1579 existing_choice = channel_combo.get_active_text();
1581 set_popdown_strings (channel_combo, channel_strings);
1583 /* preserve any existing choice, if possible */
1585 if (existing_choice.length()) {
1586 vector<string>::iterator x;
1587 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1588 if (*x == existing_choice) {
1589 channel_combo.set_active_text (existing_choice);
1593 if (x == channel_strings.end()) {
1594 channel_combo.set_active_text (channel_strings.front());
1597 channel_combo.set_active_text (channel_strings.front());
1600 resetting_ourselves = false;
1603 src_combo.set_sensitive (true);
1605 src_combo.set_sensitive (false);
1608 /* We must copy MIDI files or those from Freesound
1609 * or any file if we are under nsm control */
1610 must_copy |= _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
1612 if (UIConfiguration::instance().get_only_copy_imported_files()) {
1614 if (selection_can_be_embedded_with_links && !must_copy) {
1615 copy_files_btn.set_sensitive (true);
1618 copy_files_btn.set_active (true);
1620 copy_files_btn.set_sensitive (false);
1626 copy_files_btn.set_active (true);
1628 copy_files_btn.set_sensitive (!must_copy);
1636 SoundFileOmega::bad_file_message()
1638 MessageDialog msg (*this,
1639 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1644 resetting_ourselves = true;
1645 chooser.unselect_uri (chooser.get_preview_uri());
1646 resetting_ourselves = false;
1652 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel, bool& must_copy)
1661 multichannel = false;
1664 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1666 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1667 if (info.channels > 1) {
1668 multichannel = true;
1673 if (sz != info.length) {
1678 if (info.samplerate != _session->sample_rate()) {
1681 if (!info.seekable) {
1685 } else if (SMFSource::valid_midi_file (*i)) {
1689 if (reader.open (*i)) {
1692 if (reader.is_type0 ()) {
1693 if (reader.channels().size() > 1) {
1694 /* for type-0 files, we can split
1695 * "one track per channel"
1697 multichannel = true;
1700 if (reader.num_tracks() > 1) {
1701 multichannel = true;
1716 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1718 std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1720 if (g_mkdir (tmpdir.c_str(), 0744)) {
1721 if (errno != EEXIST) {
1726 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1728 char tmpc[PATH_MAX+1];
1729 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1732 if (PBD::hard_link (/*existing file*/(*i).c_str(), tmpc)) {
1737 g_rmdir (tmpdir.c_str());
1742 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1743 : SoundFileBrowser (title, s, false)
1745 chooser.set_select_multiple (false);
1746 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1747 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1751 SoundFileChooser::on_hide ()
1753 ArdourWindow::on_hide();
1757 _session->cancel_audition();
1762 SoundFileChooser::get_filename ()
1764 vector<string> paths;
1766 paths = get_paths ();
1768 if (paths.empty()) {
1772 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1776 return paths.front();
1779 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s,
1780 uint32_t selected_audio_tracks,
1781 uint32_t selected_midi_tracks,
1783 Editing::ImportMode mode_hint)
1784 : SoundFileBrowser (title, s, persistent)
1785 , copy_files_btn ( _("Copy files to session"))
1786 , smf_tempo_btn (_("Use MIDI Tempo Map (if defined)"))
1787 , selected_audio_track_cnt (selected_audio_tracks)
1788 , selected_midi_track_cnt (selected_midi_tracks)
1789 , _import_active (false)
1790 , _reset_post_import (false)
1794 set_size_request (-1, 550);
1796 block_two.set_border_width (12);
1797 block_three.set_border_width (12);
1798 block_four.set_border_width (12);
1801 str.push_back (_("file timestamp"));
1802 str.push_back (_("edit point"));
1803 str.push_back (_("playhead"));
1804 str.push_back (_("session start"));
1805 set_popdown_strings (where_combo, str);
1806 where_combo.set_active_text (str.back());
1807 where_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::where_combo_changed));
1809 instrument_combo_changed();
1810 instrument_combo.signal_changed().connect(sigc::mem_fun(*this, &SoundFileOmega::instrument_combo_changed) );
1812 Label* l = manage (new Label);
1813 l->set_markup (_("<b>Add files ...</b>"));
1814 options.attach (*l, 0, 1, 0, 1, FILL, SHRINK, 8, 0);
1815 options.attach (action_combo, 0, 1, 1, 2, FILL, SHRINK, 8, 0);
1817 l = manage (new Label);
1818 l->set_markup (_("<b>Insert at</b>"));
1819 options.attach (*l, 0, 1, 3, 4, FILL, SHRINK, 8, 0);
1820 options.attach (where_combo, 0, 1, 4, 5, FILL, SHRINK, 8, 0);
1822 l = manage (new Label);
1823 l->set_markup (_("<b>Mapping</b>"));
1824 options.attach (*l, 1, 2, 0, 1, FILL, SHRINK, 8, 0);
1825 options.attach (channel_combo, 1, 2, 1, 2, FILL, SHRINK, 8, 0);
1827 l = manage (new Label);
1828 l->set_markup (_("<b>Conversion quality</b>"));
1829 options.attach (*l, 1, 2, 3, 4, FILL, SHRINK, 8, 0);
1830 options.attach (src_combo, 1, 2, 4, 5, FILL, SHRINK, 8, 0);
1832 l = manage (new Label);
1833 l->set_markup (_("<b>MIDI Track Names</b>"));
1834 options.attach (*l, 2, 3, 0, 1, FILL, SHRINK, 8, 0);
1835 options.attach (midi_track_name_combo, 2, 3, 1, 2, FILL, SHRINK, 8, 0);
1837 options.attach (smf_tempo_btn, 2, 3, 3, 4, FILL, SHRINK, 8, 0);
1839 l = manage (new Label);
1840 l->set_markup (_("<b>Instrument</b>"));
1841 options.attach (*l, 3, 4, 0, 1, FILL, SHRINK, 8, 0);
1842 options.attach (instrument_combo, 3, 4, 1, 2, FILL, SHRINK, 8, 0);
1844 Alignment *hspace = manage (new Alignment ());
1845 hspace->set_size_request (2, 2);
1846 options.attach (*hspace, 0, 3, 2, 3, FILL, SHRINK, 0, 8);
1848 Alignment *vspace = manage (new Alignment ());
1849 vspace->set_size_request (2, 2);
1850 options.attach (*vspace, 2, 3, 0, 3, EXPAND, SHRINK, 0, 0);
1853 str.push_back (_("by track number"));
1854 str.push_back (_("by track name"));
1855 str.push_back (_("by instrument name"));
1856 set_popdown_strings (midi_track_name_combo, str);
1857 midi_track_name_combo.set_active_text (str.front());
1860 str.push_back (_("one track per file"));
1861 set_popdown_strings (channel_combo, str);
1862 channel_combo.set_active_text (str.front());
1863 channel_combo.set_sensitive (false);
1866 str.push_back (_("Best"));
1867 str.push_back (_("Good"));
1868 str.push_back (_("Quick"));
1869 str.push_back (_("Fast"));
1870 str.push_back (_("Fastest"));
1872 set_popdown_strings (src_combo, str);
1873 src_combo.set_active_text (str.front());
1874 src_combo.set_sensitive (false);
1875 src_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::src_combo_changed));
1877 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1878 channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1880 copy_files_btn.set_active (true);
1882 Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1885 copy_label->set_size_request (175, -1);
1886 copy_label->set_line_wrap (true);
1889 block_four.pack_start (copy_files_btn, false, false);
1890 options.attach (block_four, 3, 4, 4, 5, FILL, SHRINK, 8, 0);
1892 vpacker.pack_start (options, false, true);
1894 /* setup disposition map */
1896 disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1897 disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1898 disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1899 disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1901 disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1902 disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1903 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1904 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1906 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1908 /* set size requests for a couple of combos to allow them to display the longest text
1909 they will ever be asked to display. This prevents them being resized when the user
1910 selects a file to import, which in turn prevents the size of the dialog from jumping
1914 str.push_back (_("one track per file"));
1915 str.push_back (_("one track per channel"));
1916 str.push_back (_("sequence files"));
1917 str.push_back (_("all files in one region"));
1918 set_popdown_strings (channel_combo, str);
1921 str.push_back (importmode2string (ImportAsTrack));
1922 str.push_back (importmode2string (ImportToTrack));
1923 str.push_back (importmode2string (ImportAsRegion));
1924 str.push_back (importmode2string (ImportAsTapeTrack));
1925 set_popdown_strings (action_combo, str);
1926 action_combo.set_active_text (importmode2string(mode_hint));
1928 reset (selected_audio_tracks, selected_midi_tracks);
1932 SoundFileOmega::set_mode (ImportMode mode)
1934 action_combo.set_active_text (importmode2string (mode));
1938 SoundFileOmega::get_mode () const
1940 return string2importmode (action_combo.get_active_text());
1944 SoundFileOmega::on_hide ()
1946 ArdourWindow::on_hide();
1948 _session->cancel_audition();
1953 SoundFileOmega::get_position() const
1955 string str = where_combo.get_active_text();
1957 if (str == _("file timestamp")) {
1958 return ImportAtTimestamp;
1959 } else if (str == _("edit point")) {
1960 return ImportAtEditPoint;
1961 } else if (str == _("playhead")) {
1962 return ImportAtPlayhead;
1964 return ImportAtStart;
1969 SoundFileOmega::get_src_quality() const
1971 string str = src_combo.get_active_text();
1973 if (str == _("Best")) {
1975 } else if (str == _("Good")) {
1977 } else if (str == _("Quick")) {
1979 } else if (str == _("Fast")) {
1987 SoundFileOmega::src_combo_changed()
1989 preview.set_src_quality(get_src_quality());
1993 SoundFileOmega::where_combo_changed()
1995 preview.set_import_position(get_position());
1999 SoundFileOmega::instrument_combo_changed()
2001 _session->the_auditioner()->set_audition_synth_info( instrument_combo.selected_instrument() );
2005 SoundFileOmega::get_midi_track_name_source () const
2007 return string2miditracknamesource (midi_track_name_combo.get_active_text());
2011 SoundFileOmega::get_use_smf_tempo_map () const
2013 return smf_tempo_btn.get_active ();
2017 SoundFileOmega::get_channel_disposition () const
2019 /* we use a map here because the channel combo can contain different strings
2020 depending on the state of the other combos. the map contains all possible strings
2021 and the ImportDisposition enum that corresponds to it.
2024 string str = channel_combo.get_active_text();
2025 DispositionMap::const_iterator x = disposition_map.find (str);
2027 if (x == disposition_map.end()) {
2028 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
2029 abort(); /*NOTREACHED*/
2036 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
2038 selected_audio_track_cnt = selected_audio_tracks;
2039 selected_midi_track_cnt = selected_midi_tracks;
2041 if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
2042 chooser.set_filter (midi_filter);
2043 } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
2044 chooser.set_filter (audio_filter);
2046 chooser.set_filter (audio_and_midi_filter);
2055 SoundFileOmega::file_selection_changed ()
2057 if (resetting_ourselves || !is_visible ()) {
2061 if (!reset_options ()) {
2062 set_action_sensitive (false);
2064 if (chooser.get_filenames().size() > 0) {
2065 set_action_sensitive (true);
2067 set_action_sensitive (false);
2073 SoundFileOmega::do_something (int action)
2075 SoundFileBrowser::do_something (action);
2077 if (action == RESPONSE_CLOSE || !ARDOUR_UI_UTILS::engine_is_running ()) {
2084 vector<string> paths = get_paths ();
2085 ImportPosition pos = get_position ();
2086 ImportMode mode = get_mode ();
2087 ImportDisposition chns = get_channel_disposition ();
2088 PluginInfoPtr instrument = instrument_combo.selected_instrument();
2090 MidiTrackNameSource mts = get_midi_track_name_source ();
2091 MidiTempoMapDisposition mtd = (get_use_smf_tempo_map () ? SMFTempoUse : SMFTempoIgnore);
2094 case ImportAtEditPoint:
2095 where = PublicEditor::instance().get_preferred_edit_position ();
2097 case ImportAtTimestamp:
2100 case ImportAtPlayhead:
2101 where = _session->transport_sample();
2104 where = _session->current_start_sample();
2108 SrcQuality quality = get_src_quality();
2110 _import_active = true;
2112 if (copy_files_btn.get_active()) {
2113 PublicEditor::instance().do_import (paths, chns, mode, quality, mts, mtd, where, instrument);
2115 PublicEditor::instance().do_embed (paths, chns, mode, where, instrument);
2118 _import_active = false;
2120 if (_reset_post_import) {
2121 _reset_post_import = false;