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