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"
30 #include <sys/param.h>
32 #include <gtkmm/box.h>
33 #include <gtkmm/stock.h>
34 #include <glibmm/fileutils.h>
36 #include "pbd/convert.h"
37 #include "pbd/tokenizer.h"
38 #include "pbd/enumwriter.h"
39 #include "pbd/pthread_utils.h"
40 #include "pbd/xml++.h"
42 #include <gtkmm2ext/utils.h>
44 #include "evoral/SMF.hpp"
46 #include "ardour/amp.h"
47 #include "ardour/audio_library.h"
48 #include "ardour/auditioner.h"
49 #include "ardour/audioregion.h"
50 #include "ardour/audiofilesource.h"
51 #include "ardour/smf_source.h"
52 #include "ardour/region_factory.h"
53 #include "ardour/source_factory.h"
54 #include "ardour/session.h"
55 #include "ardour/session_directory.h"
56 #include "ardour/profile.h"
58 #include "ardour_ui.h"
60 #include "gui_thread.h"
65 #include "gain_meter.h"
68 #include "sfdb_freesound_mootcher.h"
73 using namespace ARDOUR
;
77 using namespace Gtkmm2ext
;
78 using namespace Editing
;
82 string
SoundFileBrowser::persistent_folder
;
85 string2importmode (string str
)
87 if (str
== _("as new tracks")) {
89 } else if (str
== _("to selected tracks")) {
91 } else if (str
== _("to region list")) {
92 return ImportAsRegion
;
93 } else if (str
== _("as new tape tracks")) {
94 return ImportAsTapeTrack
;
97 warning
<< string_compose (_("programming error: unknown import mode string %1"), str
) << endmsg
;
103 importmode2string (ImportMode mode
)
107 return _("as new tracks");
109 return _("to selected tracks");
111 return _("to region list");
112 case ImportAsTapeTrack
:
113 return _("as new tape tracks");
116 return _("as new tracks");
119 SoundFileBox::SoundFileBox (bool persistent
)
121 length_clock ("sfboxLengthClock", !persistent
, "EditCursorClock", false, false, true, false),
122 timecode_clock ("sfboxTimecodeClock", !persistent
, "EditCursorClock", false, false, false, false),
124 autoplay_btn (_("Auto-play"))
127 set_name (X_("SoundFileBox"));
128 set_size_request (300, -1);
130 preview_label
.set_markup (_("<b>Sound File Information</b>"));
132 border_frame
.set_label_widget (preview_label
);
133 border_frame
.add (main_box
);
135 pack_start (border_frame
, true, true);
136 set_border_width (6);
138 main_box
.set_border_width (6);
140 length
.set_text (_("Length:"));
141 length
.set_alignment (1, 0.5);
142 timecode
.set_text (_("Timestamp:"));
143 timecode
.set_alignment (1, 0.5);
144 format
.set_text (_("Format:"));
145 format
.set_alignment (1, 0.5);
146 channels
.set_text (_("Channels:"));
147 channels
.set_alignment (1, 0.5);
148 samplerate
.set_text (_("Sample rate:"));
149 samplerate
.set_alignment (1, 0.5);
151 preview_label
.set_max_width_chars (50);
152 preview_label
.set_ellipsize (Pango::ELLIPSIZE_END
);
154 format_text
.set_max_width_chars (20);
155 format_text
.set_ellipsize (Pango::ELLIPSIZE_END
);
156 format_text
.set_alignment (0, 1);
158 table
.set_col_spacings (6);
159 table
.set_homogeneous (false);
160 table
.set_row_spacings (6);
162 table
.attach (channels
, 0, 1, 0, 1, FILL
, FILL
);
163 table
.attach (samplerate
, 0, 1, 1, 2, FILL
, FILL
);
164 table
.attach (format
, 0, 1, 2, 4, FILL
, FILL
);
165 table
.attach (length
, 0, 1, 4, 5, FILL
, FILL
);
166 table
.attach (timecode
, 0, 1, 5, 6, FILL
, FILL
);
168 table
.attach (channels_value
, 1, 2, 0, 1, FILL
, FILL
);
169 table
.attach (samplerate_value
, 1, 2, 1, 2, FILL
, FILL
);
170 table
.attach (format_text
, 1, 2, 2, 4, FILL
, FILL
);
171 table
.attach (length_clock
, 1, 2, 4, 5, FILL
, FILL
);
172 table
.attach (timecode_clock
, 1, 2, 5, 6, FILL
, FILL
);
174 length_clock
.set_mode (ARDOUR_UI::instance()->secondary_clock
->mode());
175 timecode_clock
.set_mode (AudioClock::Timecode
);
177 main_box
.pack_start (table
, false, false);
179 tags_entry
.set_editable (true);
180 tags_entry
.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left
));
182 Label
* label
= manage (new Label (_("Tags:")));
183 label
->set_alignment (0.0f
, 0.5f
);
184 main_box
.pack_start (*label
, false, false);
185 main_box
.pack_start (tags_entry
, true, true);
187 main_box
.pack_start (bottom_box
, false, false);
189 play_btn
.set_image (*(manage (new Image (Stock::MEDIA_PLAY
, ICON_SIZE_BUTTON
))));
190 play_btn
.set_label (_("Play"));
192 stop_btn
.set_image (*(manage (new Image (Stock::MEDIA_STOP
, ICON_SIZE_BUTTON
))));
193 stop_btn
.set_label (_("Stop"));
195 bottom_box
.set_homogeneous (false);
196 bottom_box
.set_spacing (6);
197 bottom_box
.pack_start(play_btn
, true, true);
198 bottom_box
.pack_start(stop_btn
, true, true);
199 bottom_box
.pack_start(autoplay_btn
, false, false);
201 play_btn
.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition
));
202 stop_btn
.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition
));
204 channels_value
.set_alignment (0.0f
, 0.5f
);
205 samplerate_value
.set_alignment (0.0f
, 0.5f
);
209 SoundFileBox::set_session(Session
* s
)
211 SessionHandlePtr::set_session (s
);
213 length_clock
.set_session (s
);
214 timecode_clock
.set_session (s
);
217 play_btn
.set_sensitive (false);
218 stop_btn
.set_sensitive (false);
223 SoundFileBox::setup_labels (const string
& filename
)
226 // save existing tags
234 if(!AudioFileSource::get_soundfile_info (filename
, sf_info
, error_msg
)) {
236 preview_label
.set_markup (_("<b>Sound File Information</b>"));
237 format_text
.set_text ("");
238 channels_value
.set_text ("");
239 samplerate_value
.set_text ("");
240 tags_entry
.get_buffer()->set_text ("");
242 length_clock
.set (0);
243 timecode_clock
.set (0);
245 tags_entry
.set_sensitive (false);
246 play_btn
.set_sensitive (false);
251 preview_label
.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename
)));
252 std::string n
= sf_info
.format_name
;
253 if (n
.substr (0, 8) == X_("Format: ")) {
256 format_text
.set_text (n
);
257 channels_value
.set_text (to_string (sf_info
.channels
, std::dec
));
259 if (_session
&& sf_info
.samplerate
!= _session
->frame_rate()) {
260 samplerate
.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
261 samplerate_value
.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info
.samplerate
));
262 samplerate_value
.set_name ("NewSessionSR1Label");
263 samplerate
.set_name ("NewSessionSR1Label");
265 samplerate
.set_text (_("Sample rate:"));
266 samplerate_value
.set_text (string_compose (X_("%1 Hz"), sf_info
.samplerate
));
267 samplerate_value
.set_name ("NewSessionSR2Label");
268 samplerate
.set_name ("NewSessionSR2Label");
271 framecnt_t
const nfr
= _session
? _session
->nominal_frame_rate() : 25;
272 double src_coef
= (double) nfr
/ sf_info
.samplerate
;
274 length_clock
.set (sf_info
.length
* src_coef
+ 0.5, true);
275 timecode_clock
.set (sf_info
.timecode
* src_coef
+ 0.5, true);
277 // this is a hack that is fixed in trunk, i think (august 26th, 2007)
279 vector
<string
> tags
= Library
->get_tags (string ("//") + filename
);
281 stringstream tag_string
;
282 for (vector
<string
>::iterator i
= tags
.begin(); i
!= tags
.end(); ++i
) {
283 if (i
!= tags
.begin()) {
288 tags_entry
.get_buffer()->set_text (tag_string
.str());
290 tags_entry
.set_sensitive (true);
292 play_btn
.set_sensitive (true);
299 SoundFileBox::autoplay() const
301 return autoplay_btn
.get_active();
305 SoundFileBox::audition_oneshot()
312 SoundFileBox::audition ()
318 if (SMFSource::safe_midi_file_extension (path
)) {
319 error
<< _("Auditioning of MIDI files is not yet supported") << endmsg
;
323 _session
->cancel_audition();
325 if (!Glib::file_test (path
, Glib::FILE_TEST_EXISTS
)) {
326 warning
<< string_compose(_("Could not read file: %1 (%2)."), path
, strerror(errno
)) << endmsg
;
330 boost::shared_ptr
<Region
> r
;
332 boost::shared_ptr
<AudioFileSource
> afs
;
333 bool old_sbp
= AudioSource::get_build_peakfiles ();
335 /* don't even think of building peakfiles for these files */
337 AudioSource::set_build_peakfiles (false);
339 for (int n
= 0; n
< sf_info
.channels
; ++n
) {
341 afs
= boost::dynamic_pointer_cast
<AudioFileSource
> (
342 SourceFactory::createReadable (DataType::AUDIO
, *_session
,
343 path
, n
, Source::Flag (0), false));
345 srclist
.push_back(afs
);
347 } catch (failed_constructor
& err
) {
348 error
<< _("Could not access soundfile: ") << path
<< endmsg
;
349 AudioSource::set_build_peakfiles (old_sbp
);
354 AudioSource::set_build_peakfiles (old_sbp
);
356 if (srclist
.empty()) {
360 afs
= boost::dynamic_pointer_cast
<AudioFileSource
> (srclist
[0]);
361 string rname
= region_name_from_path (afs
->path(), false);
365 plist
.add (ARDOUR::Properties::start
, 0);
366 plist
.add (ARDOUR::Properties::length
, srclist
[0]->length(srclist
[0]->timeline_position()));
367 plist
.add (ARDOUR::Properties::name
, rname
);
368 plist
.add (ARDOUR::Properties::layer
, 0);
370 r
= boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (srclist
, plist
, false));
372 _session
->audition_region(r
);
376 SoundFileBox::stop_audition ()
379 _session
->cancel_audition();
384 SoundFileBox::tags_entry_left (GdkEventFocus
*)
391 SoundFileBox::tags_changed ()
393 string tag_string
= tags_entry
.get_buffer()->get_text ();
395 if (tag_string
.empty()) {
401 if (!PBD::tokenize (tag_string
, string(",\n"), std::back_inserter (tags
), true)) {
402 warning
<< _("SoundFileBox: Could not tokenize string: ") << tag_string
<< endmsg
;
410 SoundFileBox::save_tags (const vector
<string
>& tags
)
412 Library
->set_tags (string ("//") + path
, tags
);
413 Library
->save_changes ();
416 SoundFileBrowser::SoundFileBrowser (Gtk::Window
& parent
, string title
, ARDOUR::Session
* s
, bool persistent
)
417 : ArdourDialog (parent
, title
, false, false),
418 found_list (ListStore::create(found_list_columns
)),
419 freesound_list (ListStore::create(freesound_list_columns
)),
420 chooser (FILE_CHOOSER_ACTION_OPEN
),
421 preview (persistent
),
422 found_search_btn (_("Search")),
423 found_list_view (found_list
),
424 freesound_search_btn (_("Start Downloading")),
425 freesound_list_view (freesound_list
)
427 resetting_ourselves
= false;
430 resetting_ourselves
= false;
434 chooser
.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
435 chooser
.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
436 chooser
.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
438 chooser
.add_shortcut_folder_uri("file:///Volumes");
441 //add the file chooser
443 chooser
.set_border_width (12);
445 audio_filter
.add_custom (FILE_FILTER_FILENAME
, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter
));
446 audio_filter
.set_name (_("Audio files"));
448 midi_filter
.add_custom (FILE_FILTER_FILENAME
, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter
));
449 midi_filter
.set_name (_("MIDI files"));
451 matchall_filter
.add_pattern ("*.*");
452 matchall_filter
.set_name (_("All files"));
454 chooser
.add_filter (audio_filter
);
455 chooser
.add_filter (midi_filter
);
456 chooser
.add_filter (matchall_filter
);
457 chooser
.set_select_multiple (true);
458 chooser
.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview
));
459 chooser
.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated
));
461 /* some broken redraw behaviour - this is a bandaid */
462 chooser
.signal_selection_changed().connect (mem_fun (chooser
, &Widget::queue_draw
));
465 if (!persistent_folder
.empty()) {
466 chooser
.set_current_folder (persistent_folder
);
468 notebook
.append_page (chooser
, _("Browse Files"));
471 hpacker
.set_spacing (6);
472 hpacker
.pack_start (notebook
, true, true);
473 hpacker
.pack_start (preview
, false, false);
475 get_vbox()->pack_start (hpacker
, true, true);
483 hbox
= manage(new HBox
);
484 hbox
->pack_start (found_entry
);
485 hbox
->pack_start (found_search_btn
);
487 Gtk::ScrolledWindow
*scroll
= manage(new ScrolledWindow
);
488 scroll
->add(found_list_view
);
489 scroll
->set_policy(Gtk::POLICY_AUTOMATIC
, Gtk::POLICY_AUTOMATIC
);
491 vbox
= manage(new VBox
);
492 vbox
->pack_start (*hbox
, PACK_SHRINK
);
493 vbox
->pack_start (*scroll
);
495 found_list_view
.append_column(_("Paths"), found_list_columns
.pathname
);
497 found_list_view
.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected
));
499 found_list_view
.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated
));
501 found_search_btn
.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked
));
502 found_entry
.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked
));
504 notebook
.append_page (*vbox
, _("Search Tags"));
507 //add freesound search
514 passbox
= manage(new HBox
);
515 passbox
->set_border_width (12);
516 passbox
->set_spacing (6);
518 label
= manage (new Label
);
519 label
->set_text (_("User:"));
520 passbox
->pack_start (*label
, false, false);
521 passbox
->pack_start (freesound_name_entry
);
522 label
= manage (new Label
);
523 label
->set_text (_("Password:"));
524 passbox
->pack_start (*label
, false, false);
525 passbox
->pack_start (freesound_pass_entry
);
526 label
= manage (new Label
);
527 label
->set_text (_("Tags:"));
528 passbox
->pack_start (*label
, false, false);
529 passbox
->pack_start (freesound_entry
, false, false);
530 passbox
->pack_start (freesound_search_btn
, false, false);
532 Gtk::ScrolledWindow
*scroll
= manage(new ScrolledWindow
);
533 scroll
->add(freesound_list_view
);
534 scroll
->set_policy(Gtk::POLICY_AUTOMATIC
, Gtk::POLICY_AUTOMATIC
);
536 vbox
= manage(new VBox
);
537 vbox
->pack_start (*passbox
, PACK_SHRINK
);
538 vbox
->pack_start(*scroll
);
540 //vbox->pack_start (freesound_list_view);
542 freesound_list_view
.append_column(_("Paths"), freesound_list_columns
.pathname
);
543 freesound_list_view
.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected
));
545 //freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
546 freesound_list_view
.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated
));
547 freesound_search_btn
.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked
));
548 freesound_entry
.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked
));
549 notebook
.append_page (*vbox
, _("Search Freesound"));
554 notebook
.set_size_request (500, -1);
558 add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
559 add_button (Stock::APPLY
, RESPONSE_APPLY
);
560 add_button (Stock::OK
, RESPONSE_OK
);
564 SoundFileBrowser::~SoundFileBrowser ()
566 persistent_folder
= chooser
.get_current_folder();
571 SoundFileBrowser::on_show ()
573 ArdourDialog::on_show ();
578 SoundFileBrowser::clear_selection ()
580 chooser
.unselect_all ();
581 found_list_view
.get_selection()->unselect_all ();
585 SoundFileBrowser::chooser_file_activated ()
591 SoundFileBrowser::found_list_view_activated (const TreeModel::Path
&, TreeViewColumn
*)
597 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path
&, TreeViewColumn
*)
603 SoundFileBrowser::set_session (Session
* s
)
605 ArdourDialog::set_session (s
);
606 preview
.set_session (s
);
611 remove_gain_meter ();
616 SoundFileBrowser::add_gain_meter ()
620 gm
= new GainMeter (_session
, 250);
622 boost::shared_ptr
<Route
> r
= _session
->the_auditioner ();
624 gm
->set_controls (r
, r
->shared_peak_meter(), r
->amp());
626 meter_packer
.set_border_width (12);
627 meter_packer
.pack_start (*gm
, false, true);
628 hpacker
.pack_end (meter_packer
, false, false);
629 meter_packer
.show_all ();
634 SoundFileBrowser::remove_gain_meter ()
637 meter_packer
.remove (*gm
);
638 hpacker
.remove (meter_packer
);
645 SoundFileBrowser::start_metering ()
647 metering_connection
= ARDOUR_UI::instance()->SuperRapidScreenUpdate
.connect (sigc::mem_fun(*this, &SoundFileBrowser::meter
));
651 SoundFileBrowser::stop_metering ()
653 metering_connection
.disconnect();
657 SoundFileBrowser::meter ()
659 if (is_mapped () && _session
&& gm
) {
660 gm
->update_meters ();
665 SoundFileBrowser::on_audio_filter (const FileFilter::Info
& filter_info
)
667 return AudioFileSource::safe_audio_file_extension (filter_info
.filename
);
671 SoundFileBrowser::on_midi_filter (const FileFilter::Info
& filter_info
)
673 return SMFSource::safe_midi_file_extension (filter_info
.filename
);
677 SoundFileBrowser::update_preview ()
679 if (preview
.setup_labels (chooser
.get_filename())) {
680 if (preview
.autoplay()) {
681 Glib::signal_idle().connect (sigc::mem_fun (preview
, &SoundFileBox::audition_oneshot
));
687 SoundFileBrowser::found_list_view_selected ()
689 if (!reset_options ()) {
690 set_response_sensitive (RESPONSE_OK
, false);
694 TreeView::Selection::ListHandle_Path rows
= found_list_view
.get_selection()->get_selected_rows ();
697 TreeIter iter
= found_list
->get_iter(*rows
.begin());
698 file
= (*iter
)[found_list_columns
.pathname
];
699 chooser
.set_filename (file
);
700 set_response_sensitive (RESPONSE_OK
, true);
702 set_response_sensitive (RESPONSE_OK
, false);
705 preview
.setup_labels (file
);
710 SoundFileBrowser::freesound_list_view_selected ()
712 if (!reset_options ()) {
713 set_response_sensitive (RESPONSE_OK
, false);
717 TreeView::Selection::ListHandle_Path rows
= freesound_list_view
.get_selection()->get_selected_rows ();
720 TreeIter iter
= freesound_list
->get_iter(*rows
.begin());
721 file
= (*iter
)[freesound_list_columns
.pathname
];
722 chooser
.set_filename (file
);
723 set_response_sensitive (RESPONSE_OK
, true);
725 set_response_sensitive (RESPONSE_OK
, false);
728 preview
.setup_labels (file
);
733 SoundFileBrowser::found_search_clicked ()
735 string tag_string
= found_entry
.get_text ();
739 if (!PBD::tokenize (tag_string
, string(","), std::back_inserter (tags
), true)) {
740 warning
<< _("SoundFileBrowser: Could not tokenize string: ") << tag_string
<< endmsg
;
744 vector
<string
> results
;
745 Library
->search_members_and (results
, tags
);
748 for (vector
<string
>::iterator i
= results
.begin(); i
!= results
.end(); ++i
) {
749 TreeModel::iterator new_row
= found_list
->append();
750 TreeModel::Row row
= *new_row
;
751 string path
= Glib::filename_from_uri (string ("file:") + *i
);
752 row
[found_list_columns
.pathname
] = path
;
757 freesound_search_thread_entry (void* arg
)
759 SessionEvent::create_per_thread_pool ("freesound events", 64);
761 static_cast<SoundFileBrowser
*>(arg
)->freesound_search_thread ();
766 bool searching
= false;
767 bool canceling
= false;
770 SoundFileBrowser::freesound_search_clicked ()
772 if (canceling
) //already canceling, button does nothing
776 freesound_search_btn
.set_label(_("Cancelling.."));
780 freesound_search_btn
.set_label(_("Cancel"));
781 pthread_t freesound_thr
;
782 pthread_create_and_store ("freesound_search", &freesound_thr
, freesound_search_thread_entry
, this);
787 SoundFileBrowser::freesound_search_thread()
791 THIS IS ALL TOTALLY THREAD
-ILLEGAL
... YOU CANNOT DO GTK STUFF IN THIS THREAD
794 freesound_list
->clear();
797 path
= Glib::get_home_dir();
798 path
+= "/Freesound/";
799 Mootcher
theMootcher(path
.c_str());
801 string name_string
= freesound_name_entry
.get_text ();
802 string pass_string
= freesound_pass_entry
.get_text ();
803 string search_string
= freesound_entry
.get_text ();
805 if ( theMootcher
.doLogin( name_string
, pass_string
) ) {
807 string theString
= theMootcher
.searchText(search_string
);
810 doc
.read_buffer( theString
);
811 XMLNode
*root
= doc
.root();
813 if (root
==NULL
) return;
815 if ( strcmp(root
->name().c_str(), "freesound") == 0) {
818 XMLNodeList children
= root
->children();
819 XMLNodeConstIterator niter
;
820 for (niter
= children
.begin(); niter
!= children
.end() && !canceling
; ++niter
) {
822 if( strcmp( node
->name().c_str(), "sample") == 0 ){
823 XMLProperty
*prop
=node
->property ("id");
824 string filename
= theMootcher
.getFile( prop
->value().c_str() );
825 if ( filename
!= "" ) {
826 TreeModel::iterator new_row
= freesound_list
->append();
827 TreeModel::Row row
= *new_row
;
828 string path
= Glib::filename_from_uri (string ("file:") + filename
);
829 row
[freesound_list_columns
.pathname
] = path
;
838 freesound_search_btn
.set_label(_("Start Downloading"));
845 SoundFileBrowser::get_paths ()
847 vector
<string
> results
;
849 int n
= notebook
.get_current_page ();
852 vector
<string
> filenames
= chooser
.get_filenames();
853 vector
<string
>::iterator i
;
855 for (i
= filenames
.begin(); i
!= filenames
.end(); ++i
) {
857 if ((!stat((*i
).c_str(), &buf
)) && S_ISREG(buf
.st_mode
)) {
858 results
.push_back (*i
);
864 typedef TreeView::Selection::ListHandle_Path ListPath
;
866 ListPath rows
= found_list_view
.get_selection()->get_selected_rows ();
867 for (ListPath::iterator i
= rows
.begin() ; i
!= rows
.end(); ++i
) {
868 TreeIter iter
= found_list
->get_iter(*i
);
869 string str
= (*iter
)[found_list_columns
.pathname
];
871 results
.push_back (str
);
875 typedef TreeView::Selection::ListHandle_Path ListPath
;
877 ListPath rows
= freesound_list_view
.get_selection()->get_selected_rows ();
878 for (ListPath::iterator i
= rows
.begin() ; i
!= rows
.end(); ++i
) {
879 TreeIter iter
= freesound_list
->get_iter(*i
);
880 string str
= (*iter
)[freesound_list_columns
.pathname
];
882 results
.push_back (str
);
890 SoundFileOmega::reset_options_noret ()
892 if (!resetting_ourselves
) {
893 (void) reset_options ();
898 SoundFileOmega::reset_options ()
900 vector
<string
> paths
= get_paths ();
904 channel_combo
.set_sensitive (false);
905 action_combo
.set_sensitive (false);
906 where_combo
.set_sensitive (false);
907 copy_files_btn
.set_sensitive (false);
913 channel_combo
.set_sensitive (true);
914 action_combo
.set_sensitive (true);
915 where_combo
.set_sensitive (true);
917 /* if we get through this function successfully, this may be
918 reset at the end, once we know if we can use hard links
922 if (Config
->get_only_copy_imported_files()) {
923 copy_files_btn
.set_sensitive (false);
925 copy_files_btn
.set_sensitive (false);
931 bool selection_includes_multichannel
;
932 bool selection_can_be_embedded_with_links
= check_link_status (_session
, paths
);
935 if (check_info (paths
, same_size
, src_needed
, selection_includes_multichannel
)) {
936 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message
));
940 string existing_choice
;
941 vector
<string
> action_strings
;
943 if (chooser
.get_filter() == &audio_filter
) {
947 if (selected_audio_track_cnt
> 0) {
948 if (channel_combo
.get_active_text().length()) {
949 ImportDisposition id
= get_channel_disposition();
952 case Editing::ImportDistinctFiles
:
953 if (selected_audio_track_cnt
== paths
.size()) {
954 action_strings
.push_back (importmode2string (ImportToTrack
));
958 case Editing::ImportDistinctChannels
:
959 /* XXX it would be nice to allow channel-per-selected track
960 but its too hard we don't want to deal with all the
961 different per-file + per-track channel configurations.
966 action_strings
.push_back (importmode2string (ImportToTrack
));
976 if (selected_midi_track_cnt
> 0) {
977 action_strings
.push_back (importmode2string (ImportToTrack
));
981 action_strings
.push_back (importmode2string (ImportAsTrack
));
982 action_strings
.push_back (importmode2string (ImportAsRegion
));
983 action_strings
.push_back (importmode2string (ImportAsTapeTrack
));
985 resetting_ourselves
= true;
987 existing_choice
= action_combo
.get_active_text();
989 set_popdown_strings (action_combo
, action_strings
);
991 /* preserve any existing choice, if possible */
994 if (existing_choice
.length()) {
995 vector
<string
>::iterator x
;
996 for (x
= action_strings
.begin(); x
!= action_strings
.end(); ++x
) {
997 if (*x
== existing_choice
) {
998 action_combo
.set_active_text (existing_choice
);
1002 if (x
== action_strings
.end()) {
1003 action_combo
.set_active_text (action_strings
.front());
1006 action_combo
.set_active_text (action_strings
.front());
1009 resetting_ourselves
= false;
1011 if ((mode
= get_mode()) == ImportAsRegion
) {
1012 where_combo
.set_sensitive (false);
1014 where_combo
.set_sensitive (true);
1017 vector
<string
> channel_strings
;
1019 if (mode
== ImportAsTrack
|| mode
== ImportAsTapeTrack
|| mode
== ImportToTrack
) {
1020 channel_strings
.push_back (_("one track per file"));
1022 if (selection_includes_multichannel
) {
1023 channel_strings
.push_back (_("one track per channel"));
1026 if (paths
.size() > 1) {
1027 /* tape tracks are a single region per track, so we cannot
1028 sequence multiple files.
1030 if (mode
!= ImportAsTapeTrack
) {
1031 channel_strings
.push_back (_("sequence files"));
1034 channel_strings
.push_back (_("all files in one track"));
1035 channel_strings
.push_back (_("merge files"));
1041 channel_strings
.push_back (_("one region per file"));
1043 if (selection_includes_multichannel
) {
1044 channel_strings
.push_back (_("one region per channel"));
1047 if (paths
.size() > 1) {
1049 channel_strings
.push_back (_("all files in one region"));
1054 resetting_ourselves
= true;
1056 existing_choice
= channel_combo
.get_active_text();
1058 set_popdown_strings (channel_combo
, channel_strings
);
1060 /* preserve any existing choice, if possible */
1062 if (existing_choice
.length()) {
1063 vector
<string
>::iterator x
;
1064 for (x
= channel_strings
.begin(); x
!= channel_strings
.end(); ++x
) {
1065 if (*x
== existing_choice
) {
1066 channel_combo
.set_active_text (existing_choice
);
1070 if (x
== channel_strings
.end()) {
1071 channel_combo
.set_active_text (channel_strings
.front());
1074 channel_combo
.set_active_text (channel_strings
.front());
1077 resetting_ourselves
= false;
1080 src_combo
.set_sensitive (true);
1082 src_combo
.set_sensitive (false);
1085 if (Config
->get_only_copy_imported_files()) {
1087 if (selection_can_be_embedded_with_links
) {
1088 copy_files_btn
.set_sensitive (true);
1090 copy_files_btn
.set_sensitive (false);
1095 copy_files_btn
.set_sensitive (true);
1103 SoundFileOmega::bad_file_message()
1105 MessageDialog
msg (*this,
1106 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME
),
1111 resetting_ourselves
= true;
1112 chooser
.unselect_uri (chooser
.get_preview_uri());
1113 resetting_ourselves
= false;
1119 SoundFileOmega::check_info (const vector
<string
>& paths
, bool& same_size
, bool& src_needed
, bool& multichannel
)
1128 multichannel
= false;
1130 for (vector
<string
>::const_iterator i
= paths
.begin(); i
!= paths
.end(); ++i
) {
1132 if (AudioFileSource::get_soundfile_info (*i
, info
, errmsg
)) {
1133 if (info
.channels
> 1) {
1134 multichannel
= true;
1139 if (sz
!= info
.length
) {
1144 if (info
.samplerate
!= _session
->frame_rate()) {
1148 } else if (SMFSource::safe_midi_file_extension (*i
)) {
1152 if (reader
.num_tracks() > 1) {
1153 multichannel
= true; // "channel" == track here...
1156 /* XXX we need err = true handling here in case
1157 we can't check the file
1170 SoundFileOmega::check_link_status (const Session
* s
, const vector
<string
>& paths
)
1172 sys::path path
= s
->session_directory().sound_path() / "linktest";
1173 string tmpdir
= path
.to_string();
1176 if (mkdir (tmpdir
.c_str(), 0744)) {
1177 if (errno
!= EEXIST
) {
1182 for (vector
<string
>::const_iterator i
= paths
.begin(); i
!= paths
.end(); ++i
) {
1184 char tmpc
[MAXPATHLEN
+1];
1186 snprintf (tmpc
, sizeof(tmpc
), "%s/%s", tmpdir
.c_str(), Glib::path_get_basename (*i
).c_str());
1190 if (link ((*i
).c_str(), tmpc
)) {
1200 rmdir (tmpdir
.c_str());
1204 SoundFileChooser::SoundFileChooser (Gtk::Window
& parent
, string title
, ARDOUR::Session
* s
)
1205 : SoundFileBrowser (parent
, title
, s
, false)
1207 chooser
.set_select_multiple (false);
1208 found_list_view
.get_selection()->set_mode (SELECTION_SINGLE
);
1209 freesound_list_view
.get_selection()->set_mode (SELECTION_SINGLE
);
1213 SoundFileChooser::on_hide ()
1215 ArdourDialog::on_hide();
1219 _session
->cancel_audition();
1224 SoundFileChooser::get_filename ()
1226 vector
<string
> paths
;
1228 paths
= get_paths ();
1230 if (paths
.empty()) {
1234 if (!Glib::file_test (paths
.front(), Glib::FILE_TEST_EXISTS
|Glib::FILE_TEST_IS_REGULAR
)) {
1238 return paths
.front();
1241 SoundFileOmega::SoundFileOmega (Gtk::Window
& parent
, string title
, ARDOUR::Session
* s
,
1242 uint32_t selected_audio_tracks
,
1243 uint32_t selected_midi_tracks
,
1245 Editing::ImportMode mode_hint
)
1246 : SoundFileBrowser (parent
, title
, s
, persistent
)
1247 , copy_files_btn ( _("Copy files to session"))
1248 , selected_audio_track_cnt (selected_audio_tracks
)
1249 , selected_midi_track_cnt (selected_midi_tracks
)
1255 set_size_request (-1, 450);
1257 block_two
.set_border_width (12);
1258 block_three
.set_border_width (12);
1259 block_four
.set_border_width (12);
1261 options
.set_spacing (12);
1264 str
.push_back (_("file timestamp"));
1265 str
.push_back (_("edit point"));
1266 str
.push_back (_("playhead"));
1267 str
.push_back (_("session start"));
1268 set_popdown_strings (where_combo
, str
);
1269 where_combo
.set_active_text (str
.front());
1271 Label
* l
= manage (new Label
);
1272 l
->set_text (_("Add files:"));
1274 hbox
= manage (new HBox
);
1275 hbox
->set_border_width (12);
1276 hbox
->set_spacing (6);
1277 hbox
->pack_start (*l
, false, false);
1278 hbox
->pack_start (action_combo
, false, false);
1279 vbox
= manage (new VBox
);
1280 vbox
->pack_start (*hbox
, false, false);
1281 options
.pack_start (*vbox
, false, false);
1283 /* dummy entry for action combo so that it doesn't look odd if we
1284 come up with no tracks selected.
1288 str
.push_back (importmode2string (mode_hint
));
1289 set_popdown_strings (action_combo
, str
);
1290 action_combo
.set_active_text (str
.front());
1291 action_combo
.set_sensitive (false);
1293 l
= manage (new Label
);
1294 l
->set_text (_("Insert at:"));
1296 hbox
= manage (new HBox
);
1297 hbox
->set_border_width (12);
1298 hbox
->set_spacing (6);
1299 hbox
->pack_start (*l
, false, false);
1300 hbox
->pack_start (where_combo
, false, false);
1301 vbox
= manage (new VBox
);
1302 vbox
->pack_start (*hbox
, false, false);
1303 options
.pack_start (*vbox
, false, false);
1306 l
= manage (new Label
);
1307 l
->set_text (_("Mapping:"));
1309 hbox
= manage (new HBox
);
1310 hbox
->set_border_width (12);
1311 hbox
->set_spacing (6);
1312 hbox
->pack_start (*l
, false, false);
1313 hbox
->pack_start (channel_combo
, false, false);
1314 vbox
= manage (new VBox
);
1315 vbox
->pack_start (*hbox
, false, false);
1316 options
.pack_start (*vbox
, false, false);
1319 str
.push_back (_("one track per file"));
1320 set_popdown_strings (channel_combo
, str
);
1321 channel_combo
.set_active_text (str
.front());
1322 channel_combo
.set_sensitive (false);
1324 l
= manage (new Label
);
1325 l
->set_text (_("Conversion quality:"));
1327 hbox
= manage (new HBox
);
1328 hbox
->set_border_width (12);
1329 hbox
->set_spacing (6);
1330 hbox
->pack_start (*l
, false, false);
1331 hbox
->pack_start (src_combo
, false, false);
1332 vbox
= manage (new VBox
);
1333 vbox
->pack_start (*hbox
, false, false);
1334 options
.pack_start (*vbox
, false, false);
1337 str
.push_back (_("Best"));
1338 str
.push_back (_("Good"));
1339 str
.push_back (_("Quick"));
1340 str
.push_back (_("Fast"));
1341 str
.push_back (_("Fastest"));
1343 set_popdown_strings (src_combo
, str
);
1344 src_combo
.set_active_text (str
.front());
1345 src_combo
.set_sensitive (false);
1349 action_combo
.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret
));
1350 channel_combo
.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret
));
1352 copy_files_btn
.set_active (true);
1354 block_four
.pack_start (copy_files_btn
, false, false);
1356 options
.pack_start (block_four
, false, false);
1358 get_vbox()->pack_start (options
, false, false);
1360 /* setup disposition map */
1362 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("one track per file"), ImportDistinctFiles
));
1363 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("one track per channel"), ImportDistinctChannels
));
1364 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("merge files"), ImportMergeFiles
));
1365 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("sequence files"), ImportSerializeFiles
));
1367 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("one region per file"), ImportDistinctFiles
));
1368 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("one region per channel"), ImportDistinctChannels
));
1369 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("all files in one region"), ImportMergeFiles
));
1370 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("all files in one track"), ImportMergeFiles
));
1372 chooser
.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed
));
1374 /* set size requests for a couple of combos to allow them to display the longest text
1375 they will ever be asked to display. This prevents them being resized when the user
1376 selects a file to import, which in turn prevents the size of the dialog from jumping
1380 t
.push_back (_("one track per file"));
1381 t
.push_back (_("one track per channel"));
1382 t
.push_back (_("sequence files"));
1383 t
.push_back (_("all files in one region"));
1384 set_size_request_to_display_given_text (channel_combo
, t
, COMBO_FUDGE
+ 10, 15);
1387 t
.push_back (importmode2string (ImportAsTrack
));
1388 t
.push_back (importmode2string (ImportToTrack
));
1389 t
.push_back (importmode2string (ImportAsRegion
));
1390 t
.push_back (importmode2string (ImportAsTapeTrack
));
1391 set_size_request_to_display_given_text (action_combo
, t
, COMBO_FUDGE
+ 10, 15);
1395 SoundFileOmega::set_mode (ImportMode mode
)
1397 action_combo
.set_active_text (importmode2string (mode
));
1401 SoundFileOmega::get_mode () const
1403 return string2importmode (action_combo
.get_active_text());
1407 SoundFileOmega::on_hide ()
1409 ArdourDialog::on_hide();
1411 _session
->cancel_audition();
1416 SoundFileOmega::get_position() const
1418 string str
= where_combo
.get_active_text();
1420 if (str
== _("file timestamp")) {
1421 return ImportAtTimestamp
;
1422 } else if (str
== _("edit point")) {
1423 return ImportAtEditPoint
;
1424 } else if (str
== _("playhead")) {
1425 return ImportAtPlayhead
;
1427 return ImportAtStart
;
1432 SoundFileOmega::get_src_quality() const
1434 string str
= where_combo
.get_active_text();
1436 if (str
== _("Best")) {
1438 } else if (str
== _("Good")) {
1440 } else if (str
== _("Quick")) {
1442 } else if (str
== _("Fast")) {
1450 SoundFileOmega::get_channel_disposition () const
1452 /* we use a map here because the channel combo can contain different strings
1453 depending on the state of the other combos. the map contains all possible strings
1454 and the ImportDisposition enum that corresponds to it.
1457 string str
= channel_combo
.get_active_text();
1458 DispositionMap::const_iterator x
= disposition_map
.find (str
);
1460 if (x
== disposition_map
.end()) {
1461 fatal
<< string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str
) << endmsg
;
1469 SoundFileOmega::reset (uint32_t selected_audio_tracks
, uint32_t selected_midi_tracks
)
1471 selected_audio_track_cnt
= selected_audio_tracks
;
1472 selected_midi_track_cnt
= selected_midi_tracks
;
1477 SoundFileOmega::file_selection_changed ()
1479 if (resetting_ourselves
) {
1483 if (!reset_options ()) {
1484 set_response_sensitive (RESPONSE_OK
, false);
1486 if (chooser
.get_filenames().size() > 0) {
1487 set_response_sensitive (RESPONSE_OK
, true);
1489 set_response_sensitive (RESPONSE_OK
, false);