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 region 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 region 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);
1437 bool selection_includes_multichannel;
1438 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1441 /* See if we are thinking about importing any MIDI files */
1442 vector<string>::iterator i = paths.begin ();
1443 while (i != paths.end() && SMFSource::valid_midi_file (*i) == false) {
1446 bool const have_a_midi_file = (i != paths.end ());
1448 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1449 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1453 if (have_a_midi_file) {
1454 smf_tempo_btn.show ();
1456 smf_tempo_btn.hide ();
1459 string existing_choice;
1460 vector<string> action_strings;
1462 resetting_ourselves = true;
1464 if (chooser.get_filter() == &audio_filter) {
1468 if (selected_audio_track_cnt > 0) {
1469 if (channel_combo.get_active_text().length()) {
1470 ImportDisposition id = get_channel_disposition();
1473 case Editing::ImportDistinctFiles:
1474 if (selected_audio_track_cnt == paths.size()) {
1475 action_strings.push_back (importmode2string (ImportToTrack));
1479 case Editing::ImportDistinctChannels:
1480 /* XXX it would be nice to allow channel-per-selected track
1481 but its too hard we don't want to deal with all the
1482 different per-file + per-track channel configurations.
1487 action_strings.push_back (importmode2string (ImportToTrack));
1497 if (selected_midi_track_cnt > 0) {
1498 action_strings.push_back (importmode2string (ImportToTrack));
1502 action_strings.push_back (importmode2string (ImportAsTrack));
1503 action_strings.push_back (importmode2string (ImportAsRegion));
1504 if (!Profile->get_mixbus()) {
1505 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1508 existing_choice = action_combo.get_active_text();
1510 set_popdown_strings (action_combo, action_strings);
1512 /* preserve any existing choice, if possible */
1515 if (existing_choice.length()) {
1516 vector<string>::iterator x;
1517 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1518 if (*x == existing_choice) {
1519 action_combo.set_active_text (existing_choice);
1523 if (x == action_strings.end()) {
1524 action_combo.set_active_text (action_strings.front());
1527 action_combo.set_active_text (action_strings.front());
1530 resetting_ourselves = false;
1532 if ((mode = get_mode()) == ImportAsRegion) {
1533 where_combo.set_sensitive (false);
1535 where_combo.set_sensitive (true);
1538 vector<string> channel_strings;
1540 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1542 channel_strings.push_back (_("one track per file"));
1544 if (selection_includes_multichannel) {
1545 channel_strings.push_back (_("one track per channel"));
1548 if (paths.size() > 1) {
1549 /* tape tracks are a single region per track, so we cannot
1550 sequence multiple files.
1552 if (mode != ImportAsTapeTrack) {
1553 channel_strings.push_back (_("sequence files"));
1556 channel_strings.push_back (_("all files in one track"));
1557 channel_strings.push_back (_("merge files"));
1563 channel_strings.push_back (_("one region per file"));
1565 if (selection_includes_multichannel) {
1566 channel_strings.push_back (_("one region per channel"));
1569 if (paths.size() > 1) {
1571 channel_strings.push_back (_("all files in one region"));
1576 resetting_ourselves = true;
1578 existing_choice = channel_combo.get_active_text();
1580 set_popdown_strings (channel_combo, channel_strings);
1582 /* preserve any existing choice, if possible */
1584 if (existing_choice.length()) {
1585 vector<string>::iterator x;
1586 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1587 if (*x == existing_choice) {
1588 channel_combo.set_active_text (existing_choice);
1592 if (x == channel_strings.end()) {
1593 channel_combo.set_active_text (channel_strings.front());
1596 channel_combo.set_active_text (channel_strings.front());
1599 resetting_ourselves = false;
1602 src_combo.set_sensitive (true);
1604 src_combo.set_sensitive (false);
1607 /* We must copy MIDI files or those from Freesound
1608 * or any file if we are under nsm control */
1609 bool const must_copy = _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
1611 if (UIConfiguration::instance().get_only_copy_imported_files()) {
1613 if (selection_can_be_embedded_with_links && !must_copy) {
1614 copy_files_btn.set_sensitive (true);
1617 copy_files_btn.set_active (true);
1619 copy_files_btn.set_sensitive (false);
1625 copy_files_btn.set_active (true);
1627 copy_files_btn.set_sensitive (!must_copy);
1635 SoundFileOmega::bad_file_message()
1637 MessageDialog msg (*this,
1638 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1643 resetting_ourselves = true;
1644 chooser.unselect_uri (chooser.get_preview_uri());
1645 resetting_ourselves = false;
1651 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1660 multichannel = false;
1662 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1664 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1665 if (info.channels > 1) {
1666 multichannel = true;
1671 if (sz != info.length) {
1676 if (info.samplerate != _session->sample_rate()) {
1680 } else if (SMFSource::valid_midi_file (*i)) {
1684 if (reader.open (*i)) {
1687 if (reader.is_type0 ()) {
1688 if (reader.channels().size() > 1) {
1689 /* for type-0 files, we can split
1690 * "one track per channel"
1692 multichannel = true;
1695 if (reader.num_tracks() > 1) {
1696 multichannel = true;
1711 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1713 std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1715 if (g_mkdir (tmpdir.c_str(), 0744)) {
1716 if (errno != EEXIST) {
1721 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1723 char tmpc[PATH_MAX+1];
1724 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1727 if (PBD::hard_link (/*existing file*/(*i).c_str(), tmpc)) {
1732 g_rmdir (tmpdir.c_str());
1737 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1738 : SoundFileBrowser (title, s, false)
1740 chooser.set_select_multiple (false);
1741 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1742 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1746 SoundFileChooser::on_hide ()
1748 ArdourWindow::on_hide();
1752 _session->cancel_audition();
1757 SoundFileChooser::get_filename ()
1759 vector<string> paths;
1761 paths = get_paths ();
1763 if (paths.empty()) {
1767 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1771 return paths.front();
1774 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s,
1775 uint32_t selected_audio_tracks,
1776 uint32_t selected_midi_tracks,
1778 Editing::ImportMode mode_hint)
1779 : SoundFileBrowser (title, s, persistent)
1780 , copy_files_btn ( _("Copy files to session"))
1781 , smf_tempo_btn (_("Use MIDI Tempo Map (if defined)"))
1782 , selected_audio_track_cnt (selected_audio_tracks)
1783 , selected_midi_track_cnt (selected_midi_tracks)
1784 , _import_active (false)
1785 , _reset_post_import (false)
1789 set_size_request (-1, 550);
1791 block_two.set_border_width (12);
1792 block_three.set_border_width (12);
1793 block_four.set_border_width (12);
1796 str.push_back (_("file timestamp"));
1797 str.push_back (_("edit point"));
1798 str.push_back (_("playhead"));
1799 str.push_back (_("session start"));
1800 set_popdown_strings (where_combo, str);
1801 where_combo.set_active_text (str.back());
1802 where_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::where_combo_changed));
1804 instrument_combo_changed();
1805 instrument_combo.signal_changed().connect(sigc::mem_fun(*this, &SoundFileOmega::instrument_combo_changed) );
1807 Label* l = manage (new Label);
1808 l->set_markup (_("<b>Add files ...</b>"));
1809 options.attach (*l, 0, 1, 0, 1, FILL, SHRINK, 8, 0);
1810 options.attach (action_combo, 0, 1, 1, 2, FILL, SHRINK, 8, 0);
1812 l = manage (new Label);
1813 l->set_markup (_("<b>Insert at</b>"));
1814 options.attach (*l, 0, 1, 3, 4, FILL, SHRINK, 8, 0);
1815 options.attach (where_combo, 0, 1, 4, 5, FILL, SHRINK, 8, 0);
1817 l = manage (new Label);
1818 l->set_markup (_("<b>Mapping</b>"));
1819 options.attach (*l, 1, 2, 0, 1, FILL, SHRINK, 8, 0);
1820 options.attach (channel_combo, 1, 2, 1, 2, FILL, SHRINK, 8, 0);
1822 l = manage (new Label);
1823 l->set_markup (_("<b>Conversion quality</b>"));
1824 options.attach (*l, 1, 2, 3, 4, FILL, SHRINK, 8, 0);
1825 options.attach (src_combo, 1, 2, 4, 5, FILL, SHRINK, 8, 0);
1827 l = manage (new Label);
1828 l->set_markup (_("<b>MIDI Track Names</b>"));
1829 options.attach (*l, 2, 3, 0, 1, FILL, SHRINK, 8, 0);
1830 options.attach (midi_track_name_combo, 2, 3, 1, 2, FILL, SHRINK, 8, 0);
1832 options.attach (smf_tempo_btn, 2, 3, 3, 4, FILL, SHRINK, 8, 0);
1834 l = manage (new Label);
1835 l->set_markup (_("<b>Instrument</b>"));
1836 options.attach (*l, 3, 4, 0, 1, FILL, SHRINK, 8, 0);
1837 options.attach (instrument_combo, 3, 4, 1, 2, FILL, SHRINK, 8, 0);
1839 Alignment *hspace = manage (new Alignment ());
1840 hspace->set_size_request (2, 2);
1841 options.attach (*hspace, 0, 3, 2, 3, FILL, SHRINK, 0, 8);
1843 Alignment *vspace = manage (new Alignment ());
1844 vspace->set_size_request (2, 2);
1845 options.attach (*vspace, 2, 3, 0, 3, EXPAND, SHRINK, 0, 0);
1848 str.push_back (_("by track number"));
1849 str.push_back (_("by track name"));
1850 str.push_back (_("by instrument name"));
1851 set_popdown_strings (midi_track_name_combo, str);
1852 midi_track_name_combo.set_active_text (str.front());
1855 str.push_back (_("one track per file"));
1856 set_popdown_strings (channel_combo, str);
1857 channel_combo.set_active_text (str.front());
1858 channel_combo.set_sensitive (false);
1861 str.push_back (_("Best"));
1862 str.push_back (_("Good"));
1863 str.push_back (_("Quick"));
1864 str.push_back (_("Fast"));
1865 str.push_back (_("Fastest"));
1867 set_popdown_strings (src_combo, str);
1868 src_combo.set_active_text (str.front());
1869 src_combo.set_sensitive (false);
1870 src_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::src_combo_changed));
1872 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1873 channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1875 copy_files_btn.set_active (true);
1877 Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1880 copy_label->set_size_request (175, -1);
1881 copy_label->set_line_wrap (true);
1884 block_four.pack_start (copy_files_btn, false, false);
1885 options.attach (block_four, 3, 4, 4, 5, FILL, SHRINK, 8, 0);
1887 vpacker.pack_start (options, false, true);
1889 /* setup disposition map */
1891 disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1892 disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1893 disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1894 disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1896 disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1897 disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1898 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1899 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1901 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1903 /* set size requests for a couple of combos to allow them to display the longest text
1904 they will ever be asked to display. This prevents them being resized when the user
1905 selects a file to import, which in turn prevents the size of the dialog from jumping
1909 str.push_back (_("one track per file"));
1910 str.push_back (_("one track per channel"));
1911 str.push_back (_("sequence files"));
1912 str.push_back (_("all files in one region"));
1913 set_popdown_strings (channel_combo, str);
1916 str.push_back (importmode2string (ImportAsTrack));
1917 str.push_back (importmode2string (ImportToTrack));
1918 str.push_back (importmode2string (ImportAsRegion));
1919 str.push_back (importmode2string (ImportAsTapeTrack));
1920 set_popdown_strings (action_combo, str);
1921 action_combo.set_active_text (importmode2string(mode_hint));
1923 reset (selected_audio_tracks, selected_midi_tracks);
1927 SoundFileOmega::set_mode (ImportMode mode)
1929 action_combo.set_active_text (importmode2string (mode));
1933 SoundFileOmega::get_mode () const
1935 return string2importmode (action_combo.get_active_text());
1939 SoundFileOmega::on_hide ()
1941 ArdourWindow::on_hide();
1943 _session->cancel_audition();
1948 SoundFileOmega::get_position() const
1950 string str = where_combo.get_active_text();
1952 if (str == _("file timestamp")) {
1953 return ImportAtTimestamp;
1954 } else if (str == _("edit point")) {
1955 return ImportAtEditPoint;
1956 } else if (str == _("playhead")) {
1957 return ImportAtPlayhead;
1959 return ImportAtStart;
1964 SoundFileOmega::get_src_quality() const
1966 string str = src_combo.get_active_text();
1968 if (str == _("Best")) {
1970 } else if (str == _("Good")) {
1972 } else if (str == _("Quick")) {
1974 } else if (str == _("Fast")) {
1982 SoundFileOmega::src_combo_changed()
1984 preview.set_src_quality(get_src_quality());
1988 SoundFileOmega::where_combo_changed()
1990 preview.set_import_position(get_position());
1994 SoundFileOmega::instrument_combo_changed()
1996 _session->the_auditioner()->set_audition_synth_info( instrument_combo.selected_instrument() );
2000 SoundFileOmega::get_midi_track_name_source () const
2002 return string2miditracknamesource (midi_track_name_combo.get_active_text());
2006 SoundFileOmega::get_use_smf_tempo_map () const
2008 return smf_tempo_btn.get_active ();
2012 SoundFileOmega::get_channel_disposition () const
2014 /* we use a map here because the channel combo can contain different strings
2015 depending on the state of the other combos. the map contains all possible strings
2016 and the ImportDisposition enum that corresponds to it.
2019 string str = channel_combo.get_active_text();
2020 DispositionMap::const_iterator x = disposition_map.find (str);
2022 if (x == disposition_map.end()) {
2023 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
2024 abort(); /*NOTREACHED*/
2031 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
2033 selected_audio_track_cnt = selected_audio_tracks;
2034 selected_midi_track_cnt = selected_midi_tracks;
2036 if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
2037 chooser.set_filter (midi_filter);
2038 } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
2039 chooser.set_filter (audio_filter);
2041 chooser.set_filter (audio_and_midi_filter);
2050 SoundFileOmega::file_selection_changed ()
2052 if (resetting_ourselves || !is_visible ()) {
2056 if (!reset_options ()) {
2057 set_action_sensitive (false);
2059 if (chooser.get_filenames().size() > 0) {
2060 set_action_sensitive (true);
2062 set_action_sensitive (false);
2068 SoundFileOmega::do_something (int action)
2070 SoundFileBrowser::do_something (action);
2072 if (action == RESPONSE_CLOSE || !ARDOUR_UI_UTILS::engine_is_running ()) {
2079 vector<string> paths = get_paths ();
2080 ImportPosition pos = get_position ();
2081 ImportMode mode = get_mode ();
2082 ImportDisposition chns = get_channel_disposition ();
2083 PluginInfoPtr instrument = instrument_combo.selected_instrument();
2085 MidiTrackNameSource mts = get_midi_track_name_source ();
2086 MidiTempoMapDisposition mtd = (get_use_smf_tempo_map () ? SMFTempoUse : SMFTempoIgnore);
2089 case ImportAtEditPoint:
2090 where = PublicEditor::instance().get_preferred_edit_position ();
2092 case ImportAtTimestamp:
2095 case ImportAtPlayhead:
2096 where = _session->transport_sample();
2099 where = _session->current_start_sample();
2103 SrcQuality quality = get_src_quality();
2105 _import_active = true;
2107 if (copy_files_btn.get_active()) {
2108 PublicEditor::instance().do_import (paths, chns, mode, quality, mts, mtd, where, instrument);
2110 PublicEditor::instance().do_embed (paths, chns, mode, where, instrument);
2113 _import_active = false;
2115 if (_reset_post_import) {
2116 _reset_post_import = false;