2 Copyright (C) 2005-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
33 #include <gtkmm/box.h>
34 #include <gtkmm/stock.h>
36 #include "pbd/gstdio_compat.h"
37 #include <glibmm/fileutils.h>
39 #include "pbd/convert.h"
40 #include "pbd/tokenizer.h"
41 #include "pbd/enumwriter.h"
42 #include "pbd/pthread_utils.h"
43 #include "pbd/xml++.h"
45 #include <gtkmm2ext/utils.h>
47 #include "evoral/SMF.hpp"
49 #include "ardour/audio_library.h"
50 #include "ardour/auditioner.h"
51 #include "ardour/audioregion.h"
52 #include "ardour/audiofilesource.h"
53 #include "ardour/midi_region.h"
54 #include "ardour/smf_source.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/source_factory.h"
57 #include "ardour/session.h"
58 #include "ardour/session_directory.h"
59 #include "ardour/srcfilesource.h"
61 #include "ardour_ui.h"
63 #include "gui_thread.h"
67 #include "gain_meter.h"
68 #include "main_clock.h"
69 #include "public_editor.h"
71 #include "ui_config.h"
73 #include "sfdb_freesound_mootcher.h"
75 using namespace ARDOUR;
79 using namespace Gtkmm2ext;
80 using namespace Editing;
84 string SoundFileBrowser::persistent_folder;
85 typedef TreeView::Selection::ListHandle_Path ListPath;
87 static MidiTrackNameSource
88 string2miditracknamesource (string const & str)
90 if (str == _("by track number")) {
91 return SMFTrackNumber;
92 } else if (str == _("by track name")) {
94 } else if (str == _("by instrument name")) {
95 return SMFInstrumentName;
98 warning << string_compose (_("programming error: unknown midi track name source string %1"), str) << endmsg;
100 return SMFTrackNumber;
104 string2importmode (string const & str)
106 if (str == _("as new tracks")) {
107 return ImportAsTrack;
108 } else if (str == _("to selected tracks")) {
109 return ImportToTrack;
110 } else if (str == _("to region list")) {
111 return ImportAsRegion;
112 } else if (str == _("as new tape tracks")) {
113 return ImportAsTapeTrack;
116 warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
118 return ImportAsTrack;
122 importmode2string (ImportMode mode)
126 return _("as new tracks");
128 return _("to selected tracks");
130 return _("to region list");
131 case ImportAsTapeTrack:
132 return _("as new tape tracks");
134 abort(); /*NOTREACHED*/
135 return _("as new tracks");
138 SoundFileBox::SoundFileBox (bool /*persistent*/)
140 length_clock ("sfboxLengthClock", true, "", false, false, true, false),
141 timecode_clock ("sfboxTimecodeClock", true, "", false, false, false, false),
143 autoplay_btn (_("Auto-play")),
144 seek_slider(0,1000,1),
148 set_name (X_("SoundFileBox"));
149 set_size_request (300, -1);
151 preview_label.set_markup (_("<b>Sound File Information</b>"));
153 border_frame.set_label_widget (preview_label);
154 border_frame.add (main_box);
156 pack_start (border_frame, true, true);
157 set_border_width (6);
159 main_box.set_border_width (6);
161 length.set_text (_("Length:"));
162 length.set_alignment (1, 0.5);
163 timecode.set_text (_("Timestamp:"));
164 timecode.set_alignment (1, 0.5);
165 format.set_text (_("Format:"));
166 format.set_alignment (1, 0.5);
167 channels.set_text (_("Channels:"));
168 channels.set_alignment (1, 0.5);
169 samplerate.set_text (_("Sample rate:"));
170 samplerate.set_alignment (1, 0.5);
172 preview_label.set_max_width_chars (50);
173 preview_label.set_ellipsize (Pango::ELLIPSIZE_END);
175 format_text.set_max_width_chars (20);
176 format_text.set_ellipsize (Pango::ELLIPSIZE_END);
177 format_text.set_alignment (0, 1);
179 table.set_col_spacings (6);
180 table.set_homogeneous (false);
181 table.set_row_spacings (6);
183 table.attach (channels, 0, 1, 0, 1, FILL, FILL);
184 table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
185 table.attach (format, 0, 1, 2, 4, FILL, FILL);
186 table.attach (length, 0, 1, 4, 5, FILL, FILL);
187 table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
189 table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
190 table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
191 table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
192 table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
193 table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
195 length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock->mode());
196 timecode_clock.set_mode (AudioClock::Timecode);
198 main_box.pack_start (table, false, false);
200 tags_entry.set_editable (true);
201 tags_entry.set_wrap_mode(Gtk::WRAP_WORD);
202 tags_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
204 Label* label = manage (new Label (_("Tags:")));
205 label->set_alignment (0.0f, 0.5f);
206 main_box.pack_start (*label, false, false);
207 main_box.pack_start (tags_entry, true, true);
209 main_box.pack_start (bottom_box, false, false);
211 play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
212 // play_btn.set_label (_("Play"));
214 stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
215 // stop_btn.set_label (_("Stop"));
217 bottom_box.set_homogeneous (false);
218 bottom_box.set_spacing (6);
219 bottom_box.pack_start(play_btn, true, true);
220 bottom_box.pack_start(stop_btn, true, true);
221 bottom_box.pack_start(autoplay_btn, false, false);
223 seek_slider.set_draw_value(false);
225 seek_slider.add_events(Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
226 seek_slider.signal_button_press_event().connect(sigc::mem_fun(*this, &SoundFileBox::seek_button_press), false);
227 seek_slider.signal_button_release_event().connect(sigc::mem_fun(*this, &SoundFileBox::seek_button_release), false);
228 main_box.pack_start (seek_slider, false, false);
230 play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
231 stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
233 stop_btn.set_sensitive (false);
235 channels_value.set_alignment (0.0f, 0.5f);
236 samplerate_value.set_alignment (0.0f, 0.5f);
240 SoundFileBox::set_session(Session* s)
242 SessionHandlePtr::set_session (s);
244 length_clock.set_session (s);
245 timecode_clock.set_session (s);
248 play_btn.set_sensitive (false);
249 stop_btn.set_sensitive (false);
250 auditioner_connections.drop_connections();
252 auditioner_connections.drop_connections();
253 _session->AuditionActive.connect(auditioner_connections, invalidator (*this), boost::bind (&SoundFileBox::audition_active, this, _1), gui_context());
254 _session->the_auditioner()->AuditionProgress.connect(auditioner_connections, invalidator (*this), boost::bind (&SoundFileBox::audition_progress, this, _1, _2), gui_context());
259 SoundFileBox::audition_active(bool active) {
260 stop_btn.set_sensitive (active);
261 seek_slider.set_sensitive (active);
263 seek_slider.set_value(0);
268 SoundFileBox::audition_progress(ARDOUR::framecnt_t pos, ARDOUR::framecnt_t len) {
270 seek_slider.set_value( 1000.0 * pos / len);
271 seek_slider.set_sensitive (true);
276 SoundFileBox::seek_button_press(GdkEventButton*) {
278 return false; // pass on to slider
282 SoundFileBox::seek_button_release(GdkEventButton*) {
284 _session->the_auditioner()->seek_to_percent(seek_slider.get_value() / 10.0);
285 seek_slider.set_sensitive (false);
286 return false; // pass on to slider
290 SoundFileBox::setup_labels (const string& filename)
293 // save existing tags
301 if (SMFSource::valid_midi_file (path)) {
303 boost::shared_ptr<SMFSource> ms;
305 ms = boost::dynamic_pointer_cast<SMFSource> (
306 SourceFactory::createExternal (DataType::MIDI, *_session,
307 path, 0, Source::Flag (0), false));
308 } catch (const std::exception& e) {
309 error << string_compose(_("Could not read file: %1 (%2)."),
310 path, e.what()) << endmsg;
313 preview_label.set_markup (_("<b>Midi File Information</b>"));
315 format_text.set_text ("MIDI");
316 samplerate_value.set_text ("-");
317 tags_entry.get_buffer()->set_text ("");
318 timecode_clock.set (0);
319 tags_entry.set_sensitive (false);
322 if (ms->is_type0()) {
323 channels_value.set_text (to_string(ms->channels().size(), std::dec));
325 if (ms->num_tracks() > 1) {
326 channels_value.set_text (to_string(ms->num_tracks(), std::dec) + _("(Tracks)"));
328 channels_value.set_text (to_string(ms->num_tracks(), std::dec));
331 length_clock.set (ms->length(ms->timeline_position()));
333 channels_value.set_text ("");
334 length_clock.set (0);
337 if (_session && ms) {
338 play_btn.set_sensitive (true);
340 play_btn.set_sensitive (false);
346 if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
348 preview_label.set_markup (_("<b>Sound File Information</b>"));
349 format_text.set_text ("");
350 channels_value.set_text ("");
351 samplerate_value.set_text ("");
352 tags_entry.get_buffer()->set_text ("");
354 length_clock.set (0);
355 timecode_clock.set (0);
357 tags_entry.set_sensitive (false);
358 play_btn.set_sensitive (false);
363 preview_label.set_markup (string_compose ("<b>%1</b>", Glib::Markup::escape_text (Glib::path_get_basename (filename))));
364 std::string n = sf_info.format_name;
365 if (n.substr (0, 8) == X_("Format: ")) {
368 format_text.set_text (n);
369 channels_value.set_text (to_string (sf_info.channels, std::dec));
371 if (_session && sf_info.samplerate != _session->frame_rate()) {
372 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
373 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
374 samplerate_value.set_name ("NewSessionSR1Label");
375 samplerate.set_name ("NewSessionSR1Label");
377 samplerate.set_text (_("Sample rate:"));
378 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
379 samplerate_value.set_name ("NewSessionSR2Label");
380 samplerate.set_name ("NewSessionSR2Label");
383 framecnt_t const nfr = _session ? _session->nominal_frame_rate() : 25;
384 double src_coef = (double) nfr / sf_info.samplerate;
386 length_clock.set (sf_info.length * src_coef + 0.5, true);
387 timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
389 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
391 vector<string> tags = Library->get_tags (string ("//") + filename);
393 stringstream tag_string;
394 for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
395 if (i != tags.begin()) {
400 tags_entry.get_buffer()->set_text (tag_string.str());
402 tags_entry.set_sensitive (true);
404 play_btn.set_sensitive (true);
411 SoundFileBox::autoplay() const
413 return autoplay_btn.get_active();
417 SoundFileBox::audition_oneshot()
424 SoundFileBox::audition ()
430 _session->cancel_audition();
432 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
433 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
437 boost::shared_ptr<Region> r;
439 if (SMFSource::valid_midi_file (path)) {
441 boost::shared_ptr<SMFSource> ms =
442 boost::dynamic_pointer_cast<SMFSource> (
443 SourceFactory::createExternal (DataType::MIDI, *_session,
444 path, 0, Source::Flag (0), false));
446 string rname = region_name_from_path (ms->path(), false);
450 plist.add (ARDOUR::Properties::start, 0);
451 plist.add (ARDOUR::Properties::length, ms->length(ms->timeline_position()));
452 plist.add (ARDOUR::Properties::name, rname);
453 plist.add (ARDOUR::Properties::layer, 0);
455 r = boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (boost::dynamic_pointer_cast<Source>(ms), plist, false));
461 boost::shared_ptr<AudioFileSource> afs;
462 bool old_sbp = AudioSource::get_build_peakfiles ();
464 /* don't even think of building peakfiles for these files */
466 AudioSource::set_build_peakfiles (false);
468 for (int n = 0; n < sf_info.channels; ++n) {
470 afs = boost::dynamic_pointer_cast<AudioFileSource> (
471 SourceFactory::createExternal (DataType::AUDIO, *_session,
473 Source::Flag (ARDOUR::AudioFileSource::NoPeakFile), false));
474 if (afs->sample_rate() != _session->nominal_frame_rate()) {
475 boost::shared_ptr<SrcFileSource> sfs (new SrcFileSource(*_session, afs, _src_quality));
476 srclist.push_back(sfs);
478 srclist.push_back(afs);
481 } catch (failed_constructor& err) {
482 error << _("Could not access soundfile: ") << path << endmsg;
483 AudioSource::set_build_peakfiles (old_sbp);
488 AudioSource::set_build_peakfiles (old_sbp);
490 if (srclist.empty()) {
494 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
495 string rname = region_name_from_path (afs->path(), false);
499 plist.add (ARDOUR::Properties::start, 0);
500 plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
501 plist.add (ARDOUR::Properties::name, rname);
502 plist.add (ARDOUR::Properties::layer, 0);
504 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
507 frameoffset_t audition_position = 0;
508 switch(_import_position) {
509 case ImportAtTimestamp:
510 audition_position = 0;
512 case ImportAtPlayhead:
513 audition_position = _session->transport_frame();
516 audition_position = _session->current_start_frame();
518 case ImportAtEditPoint:
519 audition_position = PublicEditor::instance().get_preferred_edit_position ();
522 r->set_position(audition_position);
524 _session->audition_region(r);
528 SoundFileBox::stop_audition ()
531 _session->cancel_audition();
536 SoundFileBox::tags_entry_left (GdkEventFocus *)
543 SoundFileBox::tags_changed ()
545 string tag_string = tags_entry.get_buffer()->get_text ();
547 if (tag_string.empty()) {
553 if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
554 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
562 SoundFileBox::save_tags (const vector<string>& tags)
564 Library->set_tags (string ("//") + path, tags);
565 Library->save_changes ();
568 SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persistent)
569 : ArdourWindow (title)
570 , found_list (ListStore::create(found_list_columns))
571 , freesound_list (ListStore::create(freesound_list_columns))
572 , chooser (FILE_CHOOSER_ACTION_OPEN)
573 , preview (persistent)
574 , found_search_btn (_("Search"))
575 , found_list_view (found_list)
576 , freesound_search_btn (_("Search"))
577 , freesound_list_view (freesound_list)
578 , resetting_ourselves (false)
582 , import_button (_("Import"))
583 , close_button (Stock::CLOSE)
589 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
590 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
591 chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
592 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
594 catch (Glib::Error & e) {
595 std::cerr << "sfdb.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
598 Gtkmm2ext::add_volume_shortcuts (chooser);
600 //add the file chooser
602 chooser.set_border_width (12);
604 audio_and_midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun (*this, &SoundFileBrowser::on_audio_and_midi_filter));
605 audio_and_midi_filter.set_name (_("Audio and MIDI files"));
607 audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
608 audio_filter.set_name (_("Audio files"));
610 midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
611 midi_filter.set_name (_("MIDI files"));
613 matchall_filter.add_pattern ("*.*");
614 matchall_filter.set_name (_("All files"));
616 chooser.add_filter (audio_and_midi_filter);
617 chooser.add_filter (audio_filter);
618 chooser.add_filter (midi_filter);
619 chooser.add_filter (matchall_filter);
620 chooser.set_select_multiple (true);
621 chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
622 chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
625 /* some broken redraw behaviour - this is a bandaid */
626 chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
629 if (!persistent_folder.empty()) {
630 chooser.set_current_folder (persistent_folder);
633 notebook.append_page (chooser, _("Browse Files"));
635 hpacker.set_spacing (6);
636 hpacker.pack_start (notebook, true, true);
637 hpacker.pack_start (preview, false, false);
639 vpacker.set_spacing (6);
640 vpacker.pack_start (hpacker, true, true);
650 hbox = manage(new HBox);
651 hbox->pack_start (found_entry);
652 hbox->pack_start (found_search_btn);
654 Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
655 scroll->add(found_list_view);
656 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
658 vbox = manage(new VBox);
659 vbox->pack_start (*hbox, PACK_SHRINK);
660 vbox->pack_start (*scroll);
662 found_list_view.append_column(_("Paths"), found_list_columns.pathname);
664 found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
666 found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
668 found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
669 found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
671 notebook.append_page (*vbox, _("Search Tags"));
673 //add freesound search
674 #ifdef FREESOUND_GOT_FIXED
679 passbox = manage(new HBox);
680 passbox->set_spacing (6);
682 label = manage (new Label);
683 label->set_text (_("Tags:"));
684 passbox->pack_start (*label, false, false);
685 passbox->pack_start (freesound_entry, true, true);
687 label = manage (new Label);
688 label->set_text (_("Sort:"));
689 passbox->pack_start (*label, false, false);
690 passbox->pack_start (freesound_sort, false, false);
691 freesound_sort.clear_items();
693 // Order of the following must correspond with enum sortMethod
694 // in sfdb_freesound_mootcher.h
695 freesound_sort.append_text(_("None"));
696 freesound_sort.append_text(_("Longest"));
697 freesound_sort.append_text(_("Shortest"));
698 freesound_sort.append_text(_("Newest"));
699 freesound_sort.append_text(_("Oldest"));
700 freesound_sort.append_text(_("Most downloaded"));
701 freesound_sort.append_text(_("Least downloaded"));
702 freesound_sort.append_text(_("Highest rated"));
703 freesound_sort.append_text(_("Lowest rated"));
704 freesound_sort.set_active(0);
706 passbox->pack_start (freesound_search_btn, false, false);
707 passbox->pack_start (freesound_more_btn, false, false);
708 freesound_more_btn.set_label(_("More"));
709 freesound_more_btn.set_sensitive(false);
711 passbox->pack_start (freesound_similar_btn, false, false);
712 freesound_similar_btn.set_label(_("Similar"));
713 freesound_similar_btn.set_sensitive(false);
715 scroll = manage(new ScrolledWindow);
716 scroll->add(freesound_list_view);
717 scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
719 vbox = manage(new VBox);
720 vbox->set_spacing (3);
721 vbox->pack_start (*passbox, PACK_SHRINK);
722 vbox->pack_start (*scroll);
724 freesound_list_view.append_column(_("ID") , freesound_list_columns.id);
725 freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
726 // freesound_list_view.append_column(_("URI") , freesound_list_columns.uri);
727 freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
728 freesound_list_view.append_column(_("Size"), freesound_list_columns.filesize);
729 freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
730 freesound_list_view.append_column(_("License"), freesound_list_columns.license);
731 freesound_list_view.get_column(0)->set_alignment(0.5);
732 freesound_list_view.get_column(1)->set_expand(true); // filename
733 freesound_list_view.get_column(1)->set_resizable(true); // filename
734 freesound_list_view.get_column(2)->set_alignment(0.5);
735 freesound_list_view.get_column(3)->set_alignment(0.5);
736 freesound_list_view.get_column(4)->set_alignment(0.5);
737 freesound_list_view.get_column(5)->set_alignment(0.5);
739 freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
740 freesound_list_view.set_tooltip_column(1);
742 freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
743 freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
744 freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
745 freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
746 freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
747 freesound_similar_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_similar_clicked));
748 notebook.append_page (*vbox, _("Search Freesound"));
751 notebook.set_size_request (500, -1);
752 notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options)))));
756 Gtk::HButtonBox* button_box = manage (new HButtonBox);
758 button_box->set_layout (BUTTONBOX_END);
759 button_box->pack_start (close_button, false, false);
760 close_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_CLOSE));
762 button_box->pack_start (import_button, false, false);
763 import_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_OK));
765 Gtkmm2ext::UI::instance()->set_tip (import_button, _("Press to import selected files"));
766 Gtkmm2ext::UI::instance()->set_tip (close_button, _("Press to close this window without importing any files"));
768 vpacker.pack_end (*button_box, false, false);
770 set_wmclass (X_("import"), PROGRAM_NAME);
773 SoundFileBrowser::~SoundFileBrowser ()
775 persistent_folder = chooser.get_current_folder();
779 SoundFileBrowser::run ()
788 gtk_main_iteration ();
795 SoundFileBrowser::set_action_sensitive (bool yn)
797 import_button.set_sensitive (yn);
801 SoundFileBrowser::do_something (int action)
808 SoundFileBrowser::on_show ()
810 ArdourWindow::on_show ();
815 SoundFileBrowser::clear_selection ()
817 chooser.unselect_all ();
818 found_list_view.get_selection()->unselect_all ();
822 SoundFileBrowser::chooser_file_activated ()
828 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
834 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
840 SoundFileBrowser::set_session (Session* s)
842 ArdourWindow::set_session (s);
843 preview.set_session (s);
848 remove_gain_meter ();
853 SoundFileBrowser::add_gain_meter ()
857 gm = new GainMeter (_session, 250);
859 boost::shared_ptr<Route> r = _session->the_auditioner ();
861 gm->set_controls (r, r->shared_peak_meter(), r->amp(), r->gain_control());
862 gm->set_fader_name (X_("GainFader"));
864 meter_packer.set_border_width (12);
865 meter_packer.pack_start (*gm, false, true);
866 hpacker.pack_end (meter_packer, false, false);
867 meter_packer.show_all ();
872 SoundFileBrowser::remove_gain_meter ()
875 meter_packer.remove (*gm);
876 hpacker.remove (meter_packer);
883 SoundFileBrowser::start_metering ()
885 metering_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
889 SoundFileBrowser::stop_metering ()
891 metering_connection.disconnect();
895 SoundFileBrowser::meter ()
897 if (is_mapped () && _session && gm) {
898 gm->update_meters ();
903 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
905 return AudioFileSource::safe_audio_file_extension (filter_info.filename);
909 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
911 return SMFSource::safe_midi_file_extension (filter_info.filename);
915 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
917 return on_audio_filter (filter_info) || on_midi_filter (filter_info);
921 SoundFileBrowser::update_preview ()
923 if (preview.setup_labels (chooser.get_preview_filename())) {
924 if (preview.autoplay()) {
925 Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
931 SoundFileBrowser::found_list_view_selected ()
933 if (!reset_options ()) {
934 set_action_sensitive (false);
938 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
941 TreeIter iter = found_list->get_iter(*rows.begin());
942 file = (*iter)[found_list_columns.pathname];
943 chooser.set_filename (file);
944 set_action_sensitive (true);
946 set_action_sensitive (false);
949 preview.setup_labels (file);
954 SoundFileBrowser::found_search_clicked ()
956 string tag_string = found_entry.get_text ();
960 if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
961 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
965 vector<string> results;
966 Library->search_members_and (results, tags);
969 for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
970 TreeModel::iterator new_row = found_list->append();
971 TreeModel::Row row = *new_row;
972 string path = Glib::filename_from_uri (string ("file:") + *i);
973 row[found_list_columns.pathname] = path;
979 SoundFileBrowser::freesound_get_audio_file(Gtk::TreeIter iter)
982 Mootcher *mootcher = new Mootcher;
985 string id = (*iter)[freesound_list_columns.id];
986 string uri = (*iter)[freesound_list_columns.uri];
987 string ofn = (*iter)[freesound_list_columns.filename];
989 if (mootcher->checkAudioFile(ofn, id)) {
990 // file already exists, no need to download it again
991 file = mootcher->audioFileName;
993 (*iter)[freesound_list_columns.started] = false;
996 if (!(*iter)[freesound_list_columns.started]) {
997 // start downloading the sound file
998 (*iter)[freesound_list_columns.started] = true;
999 mootcher->fetchAudioFile(ofn, id, uri, this);
1005 SoundFileBrowser::freesound_list_view_selected ()
1008 if (!reset_options ()) {
1009 set_action_sensitive (false);
1012 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1013 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1014 file = freesound_get_audio_file (freesound_list->get_iter(*i));
1017 switch (rows.size()) {
1020 freesound_similar_btn.set_sensitive(false);
1021 set_action_sensitive (false);
1024 // exactly one item selected
1026 // file exists on disk already
1027 chooser.set_filename (file);
1028 preview.setup_labels (file);
1029 set_action_sensitive (true);
1031 freesound_similar_btn.set_sensitive(true);
1034 // multiple items selected
1035 preview.setup_labels ("");
1036 freesound_similar_btn.set_sensitive(false);
1044 SoundFileBrowser::refresh_display(std::string ID, std::string file)
1046 // called when the mootcher has finished downloading a file
1047 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1048 if (rows.size() == 1) {
1049 // there's a single item selected in the freesound list
1050 //XXX make a function to be used to construct the actual file name both here and in the mootcher
1051 Gtk::TreeIter row = freesound_list->get_iter(*rows.begin());
1052 std::string selected_ID = (*row)[freesound_list_columns.id];
1053 if (ID == selected_ID) {
1054 // the selected item in the freesound list is the item that has just finished downloading
1055 chooser.set_filename(file);
1056 preview.setup_labels (file);
1057 set_action_sensitive (true);
1063 SoundFileBrowser::freesound_search_clicked ()
1066 freesound_list->clear();
1072 SoundFileBrowser::freesound_more_clicked ()
1077 snprintf(row_path, 21, "%d", (freesound_page - 1) * 100);
1078 freesound_list_view.scroll_to_row(Gtk::TreePath(row_path), 0);
1082 SoundFileBrowser::freesound_similar_clicked ()
1084 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1085 if (rows.size() == 1) {
1088 Gtk::TreeIter iter = freesound_list->get_iter(*rows.begin());
1089 id = (*iter)[freesound_list_columns.id];
1090 freesound_list->clear();
1092 GdkCursor *prev_cursor;
1093 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1094 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1097 std::string theString = mootcher.searchSimilar(id);
1099 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1100 handle_freesound_results(theString);
1105 SoundFileBrowser::freesound_search()
1109 string search_string = freesound_entry.get_text ();
1110 enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
1112 GdkCursor *prev_cursor;
1113 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1114 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1117 std::string theString = mootcher.searchText(
1121 "", // OSX eats anything incl mp3
1123 "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
1128 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1129 handle_freesound_results(theString);
1133 SoundFileBrowser::handle_freesound_results(std::string theString) {
1135 doc.read_buffer( theString );
1136 XMLNode *root = doc.root();
1139 error << "no root XML node!" << endmsg;
1143 if ( strcmp(root->name().c_str(), "response") != 0) {
1144 error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
1148 // find out how many pages are available to search
1149 int freesound_n_pages = 1;
1150 XMLNode *res = root->child("num_pages");
1152 string result = res->child("text")->content();
1153 freesound_n_pages = atoi(result);
1156 int more_pages = freesound_n_pages - freesound_page;
1158 if (more_pages > 0) {
1159 freesound_more_btn.set_sensitive(true);
1160 freesound_more_btn.set_tooltip_text(string_compose(P_(
1161 "%1 more page of 100 results available",
1162 "%1 more pages of 100 results available",
1163 more_pages), more_pages));
1165 freesound_more_btn.set_sensitive(false);
1166 freesound_more_btn.set_tooltip_text(_("No more results available"));
1169 XMLNode *sounds_root = root->child("sounds");
1171 error << "no child node \"sounds\" found!" << endmsg;
1175 XMLNodeList sounds = sounds_root->children();
1176 if (sounds.size() == 0) {
1181 XMLNodeConstIterator niter;
1183 for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
1185 if( strcmp( node->name().c_str(), "resource") != 0 ) {
1186 error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
1190 // node->dump(cerr, "node:");
1193 XMLNode *id_node = node->child ("id");
1194 XMLNode *uri_node = node->child ("serve");
1195 XMLNode *ofn_node = node->child ("original_filename");
1196 XMLNode *dur_node = node->child ("duration");
1197 XMLNode *siz_node = node->child ("filesize");
1198 XMLNode *srt_node = node->child ("samplerate");
1199 XMLNode *lic_node = node->child ("license");
1201 if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
1203 std::string id = id_node->child("text")->content();
1204 std::string uri = uri_node->child("text")->content();
1205 std::string ofn = ofn_node->child("text")->content();
1206 std::string dur = dur_node->child("text")->content();
1207 std::string siz = siz_node->child("text")->content();
1208 std::string srt = srt_node->child("text")->content();
1209 std::string lic = lic_node->child("text")->content();
1212 // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
1214 double duration_seconds = atof(dur);
1216 char duration_hhmmss[16];
1217 if (duration_seconds >= 99 * 60 * 60) {
1218 strcpy(duration_hhmmss, ">99h");
1220 s = modf(duration_seconds/60, &m) * 60;
1221 m = modf(m/60, &h) * 60;
1222 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
1227 double size_bytes = atof(siz);
1229 if (size_bytes < 1000) {
1230 sprintf(bsize, "%.0f %s", size_bytes, _("B"));
1231 } else if (size_bytes < 1000000 ) {
1232 sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
1233 } else if (size_bytes < 10000000) {
1234 sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
1235 } else if (size_bytes < 1000000000) {
1236 sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
1238 sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
1241 /* see http://www.freesound.org/help/faq/#licenses */
1242 char shortlicense[64];
1243 if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
1244 sprintf(shortlicense, "CC-BY-NC");
1245 } else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
1246 sprintf(shortlicense, "CC-BY");
1247 } else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
1248 sprintf(shortlicense, "sampling+");
1249 } else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
1250 sprintf(shortlicense, "PD");
1252 snprintf(shortlicense, 64, "%s", lic.c_str());
1253 shortlicense[63]= '\0';
1256 TreeModel::iterator new_row = freesound_list->append();
1257 TreeModel::Row row = *new_row;
1259 row[freesound_list_columns.id ] = id;
1260 row[freesound_list_columns.uri ] = uri;
1261 row[freesound_list_columns.filename] = ofn;
1262 row[freesound_list_columns.duration] = duration_hhmmss;
1263 row[freesound_list_columns.filesize] = bsize;
1264 row[freesound_list_columns.smplrate] = srt;
1265 row[freesound_list_columns.license ] = shortlicense;
1272 SoundFileBrowser::get_paths ()
1274 vector<string> results;
1276 int n = notebook.get_current_page ();
1279 vector<string> filenames = chooser.get_filenames();
1280 vector<string>::iterator i;
1282 for (i = filenames.begin(); i != filenames.end(); ++i) {
1284 if ((!g_stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1285 results.push_back (*i);
1289 } else if (n == 1) {
1291 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1292 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1293 TreeIter iter = found_list->get_iter(*i);
1294 string str = (*iter)[found_list_columns.pathname];
1296 results.push_back (str);
1299 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1300 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1301 string str = freesound_get_audio_file (freesound_list->get_iter(*i));
1303 results.push_back (str);
1312 SoundFileOmega::reset_options_noret ()
1314 if (!resetting_ourselves) {
1315 (void) reset_options ();
1320 SoundFileOmega::reset_options ()
1322 if (_import_active) {
1323 _reset_post_import = true;
1327 vector<string> paths = get_paths ();
1329 if (paths.empty()) {
1331 channel_combo.set_sensitive (false);
1332 action_combo.set_sensitive (false);
1333 where_combo.set_sensitive (false);
1334 copy_files_btn.set_active (true);
1335 copy_files_btn.set_sensitive (false);
1341 channel_combo.set_sensitive (true);
1342 action_combo.set_sensitive (true);
1343 where_combo.set_sensitive (true);
1345 /* if we get through this function successfully, this may be
1346 reset at the end, once we know if we can use hard links
1347 to do embedding (or if we are importing a MIDI file).
1350 if (UIConfiguration::instance().get_only_copy_imported_files()) {
1351 copy_files_btn.set_sensitive (false);
1353 copy_files_btn.set_sensitive (false);
1359 bool selection_includes_multichannel;
1360 bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1363 /* See if we are thinking about importing any MIDI files */
1364 vector<string>::iterator i = paths.begin ();
1365 while (i != paths.end() && SMFSource::valid_midi_file (*i) == false) {
1368 bool const have_a_midi_file = (i != paths.end ());
1370 if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1371 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1375 string existing_choice;
1376 vector<string> action_strings;
1378 resetting_ourselves = true;
1380 if (chooser.get_filter() == &audio_filter) {
1384 if (selected_audio_track_cnt > 0) {
1385 if (channel_combo.get_active_text().length()) {
1386 ImportDisposition id = get_channel_disposition();
1389 case Editing::ImportDistinctFiles:
1390 if (selected_audio_track_cnt == paths.size()) {
1391 action_strings.push_back (importmode2string (ImportToTrack));
1395 case Editing::ImportDistinctChannels:
1396 /* XXX it would be nice to allow channel-per-selected track
1397 but its too hard we don't want to deal with all the
1398 different per-file + per-track channel configurations.
1403 action_strings.push_back (importmode2string (ImportToTrack));
1413 if (selected_midi_track_cnt > 0) {
1414 action_strings.push_back (importmode2string (ImportToTrack));
1418 action_strings.push_back (importmode2string (ImportAsTrack));
1419 action_strings.push_back (importmode2string (ImportAsRegion));
1420 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1422 existing_choice = action_combo.get_active_text();
1424 set_popdown_strings (action_combo, action_strings);
1426 /* preserve any existing choice, if possible */
1429 if (existing_choice.length()) {
1430 vector<string>::iterator x;
1431 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1432 if (*x == existing_choice) {
1433 action_combo.set_active_text (existing_choice);
1437 if (x == action_strings.end()) {
1438 action_combo.set_active_text (action_strings.front());
1441 action_combo.set_active_text (action_strings.front());
1444 resetting_ourselves = false;
1446 if ((mode = get_mode()) == ImportAsRegion) {
1447 where_combo.set_sensitive (false);
1449 where_combo.set_sensitive (true);
1452 vector<string> channel_strings;
1454 if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1456 if (selection_includes_multichannel) {
1457 channel_strings.push_back (_("one track per channel"));
1460 channel_strings.push_back (_("one track per file"));
1462 if (paths.size() > 1) {
1463 /* tape tracks are a single region per track, so we cannot
1464 sequence multiple files.
1466 if (mode != ImportAsTapeTrack) {
1467 channel_strings.push_back (_("sequence files"));
1470 channel_strings.push_back (_("all files in one track"));
1471 channel_strings.push_back (_("merge files"));
1477 channel_strings.push_back (_("one region per file"));
1479 if (selection_includes_multichannel) {
1480 channel_strings.push_back (_("one region per channel"));
1483 if (paths.size() > 1) {
1485 channel_strings.push_back (_("all files in one region"));
1490 resetting_ourselves = true;
1492 existing_choice = channel_combo.get_active_text();
1494 set_popdown_strings (channel_combo, channel_strings);
1496 /* preserve any existing choice, if possible */
1498 if (existing_choice.length()) {
1499 vector<string>::iterator x;
1500 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1501 if (*x == existing_choice) {
1502 channel_combo.set_active_text (existing_choice);
1506 if (x == channel_strings.end()) {
1507 channel_combo.set_active_text (channel_strings.front());
1510 channel_combo.set_active_text (channel_strings.front());
1513 resetting_ourselves = false;
1516 src_combo.set_sensitive (true);
1518 src_combo.set_sensitive (false);
1521 /* We must copy MIDI files or those from Freesound
1522 * or any file if we are under nsm control */
1523 bool const must_copy = _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
1525 if (UIConfiguration::instance().get_only_copy_imported_files()) {
1527 if (selection_can_be_embedded_with_links && !must_copy) {
1528 copy_files_btn.set_sensitive (true);
1531 copy_files_btn.set_active (true);
1533 copy_files_btn.set_sensitive (false);
1539 copy_files_btn.set_active (true);
1541 copy_files_btn.set_sensitive (!must_copy);
1549 SoundFileOmega::bad_file_message()
1551 MessageDialog msg (*this,
1552 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1557 resetting_ourselves = true;
1558 chooser.unselect_uri (chooser.get_preview_uri());
1559 resetting_ourselves = false;
1565 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1574 multichannel = false;
1576 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1578 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1579 if (info.channels > 1) {
1580 multichannel = true;
1585 if (sz != info.length) {
1590 if (info.samplerate != _session->frame_rate()) {
1594 } else if (SMFSource::valid_midi_file (*i)) {
1598 if (reader.open (*i)) {
1601 if (reader.is_type0 ()) {
1602 if (reader.channels().size() > 1) {
1603 /* for type-0 files, we can split
1604 * "one track per channel"
1606 multichannel = true;
1609 if (reader.num_tracks() > 1) {
1610 multichannel = true;
1625 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1627 #ifdef PLATFORM_WINDOWS
1630 std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1633 if (g_mkdir (tmpdir.c_str(), 0744)) {
1634 if (errno != EEXIST) {
1639 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1641 char tmpc[PATH_MAX+1];
1643 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1647 if (link ((*i).c_str(), tmpc)) {
1657 g_rmdir (tmpdir.c_str());
1662 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1663 : SoundFileBrowser (title, s, false)
1665 chooser.set_select_multiple (false);
1666 found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1667 freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1671 SoundFileChooser::on_hide ()
1673 ArdourWindow::on_hide();
1677 _session->cancel_audition();
1682 SoundFileChooser::get_filename ()
1684 vector<string> paths;
1686 paths = get_paths ();
1688 if (paths.empty()) {
1692 if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1696 return paths.front();
1699 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s,
1700 uint32_t selected_audio_tracks,
1701 uint32_t selected_midi_tracks,
1703 Editing::ImportMode mode_hint)
1704 : SoundFileBrowser (title, s, persistent)
1705 , copy_files_btn ( _("Copy files to session"))
1706 , selected_audio_track_cnt (selected_audio_tracks)
1707 , selected_midi_track_cnt (selected_midi_tracks)
1708 , _import_active (false)
1709 , _reset_post_import (false)
1713 set_size_request (-1, 550);
1715 block_two.set_border_width (12);
1716 block_three.set_border_width (12);
1717 block_four.set_border_width (12);
1720 str.push_back (_("file timestamp"));
1721 str.push_back (_("edit point"));
1722 str.push_back (_("playhead"));
1723 str.push_back (_("session start"));
1724 set_popdown_strings (where_combo, str);
1725 where_combo.set_active_text (str.back());
1726 where_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::where_combo_changed));
1728 Label* l = manage (new Label);
1729 l->set_markup (_("<b>Add files ...</b>"));
1730 options.attach (*l, 0, 1, 0, 1, FILL, SHRINK, 8, 0);
1731 options.attach (action_combo, 0, 1, 1, 2, FILL, SHRINK, 8, 0);
1733 l = manage (new Label);
1734 l->set_markup (_("<b>Insert at</b>"));
1735 options.attach (*l, 0, 1, 3, 4, FILL, SHRINK, 8, 0);
1736 options.attach (where_combo, 0, 1, 4, 5, FILL, SHRINK, 8, 0);
1738 l = manage (new Label);
1739 l->set_markup (_("<b>Mapping</b>"));
1740 options.attach (*l, 1, 2, 0, 1, FILL, SHRINK, 8, 0);
1741 options.attach (channel_combo, 1, 2, 1, 2, FILL, SHRINK, 8, 0);
1743 l = manage (new Label);
1744 l->set_markup (_("<b>Conversion quality</b>"));
1745 options.attach (*l, 1, 2, 3, 4, FILL, SHRINK, 8, 0);
1746 options.attach (src_combo, 1, 2, 4, 5, FILL, SHRINK, 8, 0);
1748 l = manage (new Label);
1749 l->set_markup (_("<b>MIDI Track Names</b>"));
1750 options.attach (*l, 3, 4, 0, 1, FILL, SHRINK, 8, 0);
1751 options.attach (midi_track_name_combo, 3, 4, 1, 2, FILL, SHRINK, 8, 0);
1753 l = manage (new Label);
1754 l->set_markup (_("<b>Instrument</b>"));
1755 options.attach (*l, 3, 4, 2, 3, FILL, SHRINK, 8, 0);
1756 options.attach (instrument_combo, 3, 4, 3, 4, FILL, SHRINK, 8, 0);
1758 Alignment *hspace = manage (new Alignment ());
1759 hspace->set_size_request (2, 2);
1760 options.attach (*hspace, 0, 3, 2, 3, FILL, SHRINK, 0, 8);
1762 Alignment *vspace = manage (new Alignment ());
1763 vspace->set_size_request (2, 2);
1764 options.attach (*vspace, 2, 3, 0, 3, EXPAND, SHRINK, 0, 0);
1767 str.push_back (_("by track number"));
1768 str.push_back (_("by track name"));
1769 str.push_back (_("by instrument name"));
1770 set_popdown_strings (midi_track_name_combo, str);
1771 midi_track_name_combo.set_active_text (str.front());
1774 str.push_back (_("one track per file"));
1775 set_popdown_strings (channel_combo, str);
1776 channel_combo.set_active_text (str.front());
1777 channel_combo.set_sensitive (false);
1780 str.push_back (_("Best"));
1781 str.push_back (_("Good"));
1782 str.push_back (_("Quick"));
1783 str.push_back (_("Fast"));
1784 str.push_back (_("Fastest"));
1786 set_popdown_strings (src_combo, str);
1787 src_combo.set_active_text (str.front());
1788 src_combo.set_sensitive (false);
1789 src_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::src_combo_changed));
1791 action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1792 channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1794 copy_files_btn.set_active (true);
1796 Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1799 copy_label->set_size_request (175, -1);
1800 copy_label->set_line_wrap (true);
1803 block_four.pack_start (copy_files_btn, false, false);
1804 options.attach (block_four, 3, 4, 4, 5, FILL, SHRINK, 8, 0);
1806 vpacker.pack_start (options, false, true);
1808 /* setup disposition map */
1810 disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1811 disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1812 disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1813 disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1815 disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1816 disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1817 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1818 disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1820 chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1822 /* set size requests for a couple of combos to allow them to display the longest text
1823 they will ever be asked to display. This prevents them being resized when the user
1824 selects a file to import, which in turn prevents the size of the dialog from jumping
1828 str.push_back (_("one track per file"));
1829 str.push_back (_("one track per channel"));
1830 str.push_back (_("sequence files"));
1831 str.push_back (_("all files in one region"));
1832 set_popdown_strings (channel_combo, str);
1835 str.push_back (importmode2string (ImportAsTrack));
1836 str.push_back (importmode2string (ImportToTrack));
1837 str.push_back (importmode2string (ImportAsRegion));
1838 str.push_back (importmode2string (ImportAsTapeTrack));
1839 set_popdown_strings (action_combo, str);
1840 action_combo.set_active_text (importmode2string(mode_hint));
1842 reset (selected_audio_tracks, selected_midi_tracks);
1846 SoundFileOmega::set_mode (ImportMode mode)
1848 action_combo.set_active_text (importmode2string (mode));
1852 SoundFileOmega::get_mode () const
1854 return string2importmode (action_combo.get_active_text());
1858 SoundFileOmega::on_hide ()
1860 ArdourWindow::on_hide();
1862 _session->cancel_audition();
1867 SoundFileOmega::get_position() const
1869 string str = where_combo.get_active_text();
1871 if (str == _("file timestamp")) {
1872 return ImportAtTimestamp;
1873 } else if (str == _("edit point")) {
1874 return ImportAtEditPoint;
1875 } else if (str == _("playhead")) {
1876 return ImportAtPlayhead;
1878 return ImportAtStart;
1883 SoundFileOmega::get_src_quality() const
1885 string str = src_combo.get_active_text();
1887 if (str == _("Best")) {
1889 } else if (str == _("Good")) {
1891 } else if (str == _("Quick")) {
1893 } else if (str == _("Fast")) {
1901 SoundFileOmega::src_combo_changed()
1903 preview.set_src_quality(get_src_quality());
1907 SoundFileOmega::where_combo_changed()
1909 preview.set_import_position(get_position());
1913 SoundFileOmega::get_midi_track_name_source () const
1915 return string2miditracknamesource (midi_track_name_combo.get_active_text());
1919 SoundFileOmega::get_channel_disposition () const
1921 /* we use a map here because the channel combo can contain different strings
1922 depending on the state of the other combos. the map contains all possible strings
1923 and the ImportDisposition enum that corresponds to it.
1926 string str = channel_combo.get_active_text();
1927 DispositionMap::const_iterator x = disposition_map.find (str);
1929 if (x == disposition_map.end()) {
1930 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1931 abort(); /*NOTREACHED*/
1938 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1940 selected_audio_track_cnt = selected_audio_tracks;
1941 selected_midi_track_cnt = selected_midi_tracks;
1943 if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1944 chooser.set_filter (midi_filter);
1945 } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1946 chooser.set_filter (audio_filter);
1948 chooser.set_filter (audio_and_midi_filter);
1955 SoundFileOmega::file_selection_changed ()
1957 if (resetting_ourselves) {
1961 if (!reset_options ()) {
1962 set_action_sensitive (false);
1964 if (chooser.get_filenames().size() > 0) {
1965 set_action_sensitive (true);
1967 set_action_sensitive (false);
1973 SoundFileOmega::do_something (int action)
1975 SoundFileBrowser::do_something (action);
1977 if (action == RESPONSE_CLOSE) {
1984 vector<string> paths = get_paths ();
1985 ImportPosition pos = get_position ();
1986 ImportMode mode = get_mode ();
1987 ImportDisposition chns = get_channel_disposition ();
1988 PluginInfoPtr instrument = instrument_combo.selected_instrument();
1990 MidiTrackNameSource mts = get_midi_track_name_source ();
1993 case ImportAtEditPoint:
1994 where = PublicEditor::instance().get_preferred_edit_position ();
1996 case ImportAtTimestamp:
1999 case ImportAtPlayhead:
2000 where = _session->transport_frame();
2003 where = _session->current_start_frame();
2007 SrcQuality quality = get_src_quality();
2009 _import_active = true;
2011 if (copy_files_btn.get_active()) {
2012 PublicEditor::instance().do_import (paths, chns, mode, quality, mts, where, instrument);
2014 PublicEditor::instance().do_embed (paths, chns, mode, where, instrument);
2017 _import_active = false;
2019 if (_reset_post_import) {
2020 _reset_post_import = false;