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 (selected_track_cnt
> 0) {
944 if (channel_combo
.get_active_text().length()) {
945 ImportDisposition id
= get_channel_disposition();
948 case Editing::ImportDistinctFiles
:
949 if (selected_track_cnt
== paths
.size()) {
950 action_strings
.push_back (importmode2string (ImportToTrack
));
954 case Editing::ImportDistinctChannels
:
955 /* XXX it would be nice to allow channel-per-selected track
956 but its too hard we don't want to deal with all the
957 different per-file + per-track channel configurations.
962 action_strings
.push_back (importmode2string (ImportToTrack
));
968 action_strings
.push_back (importmode2string (ImportAsTrack
));
969 action_strings
.push_back (importmode2string (ImportAsRegion
));
970 action_strings
.push_back (importmode2string (ImportAsTapeTrack
));
972 resetting_ourselves
= true;
974 existing_choice
= action_combo
.get_active_text();
976 set_popdown_strings (action_combo
, action_strings
);
978 /* preserve any existing choice, if possible */
981 if (existing_choice
.length()) {
982 vector
<string
>::iterator x
;
983 for (x
= action_strings
.begin(); x
!= action_strings
.end(); ++x
) {
984 if (*x
== existing_choice
) {
985 action_combo
.set_active_text (existing_choice
);
989 if (x
== action_strings
.end()) {
990 action_combo
.set_active_text (action_strings
.front());
993 action_combo
.set_active_text (action_strings
.front());
996 resetting_ourselves
= false;
998 if ((mode
= get_mode()) == ImportAsRegion
) {
999 where_combo
.set_sensitive (false);
1001 where_combo
.set_sensitive (true);
1004 vector
<string
> channel_strings
;
1006 if (mode
== ImportAsTrack
|| mode
== ImportAsTapeTrack
|| mode
== ImportToTrack
) {
1007 channel_strings
.push_back (_("one track per file"));
1009 if (selection_includes_multichannel
) {
1010 channel_strings
.push_back (_("one track per channel"));
1013 if (paths
.size() > 1) {
1014 /* tape tracks are a single region per track, so we cannot
1015 sequence multiple files.
1017 if (mode
!= ImportAsTapeTrack
) {
1018 channel_strings
.push_back (_("sequence files"));
1021 channel_strings
.push_back (_("all files in one track"));
1022 channel_strings
.push_back (_("merge files"));
1028 channel_strings
.push_back (_("one region per file"));
1030 if (selection_includes_multichannel
) {
1031 channel_strings
.push_back (_("one region per channel"));
1034 if (paths
.size() > 1) {
1036 channel_strings
.push_back (_("all files in one region"));
1041 resetting_ourselves
= true;
1043 existing_choice
= channel_combo
.get_active_text();
1045 set_popdown_strings (channel_combo
, channel_strings
);
1047 /* preserve any existing choice, if possible */
1049 if (existing_choice
.length()) {
1050 vector
<string
>::iterator x
;
1051 for (x
= channel_strings
.begin(); x
!= channel_strings
.end(); ++x
) {
1052 if (*x
== existing_choice
) {
1053 channel_combo
.set_active_text (existing_choice
);
1057 if (x
== channel_strings
.end()) {
1058 channel_combo
.set_active_text (channel_strings
.front());
1061 channel_combo
.set_active_text (channel_strings
.front());
1064 resetting_ourselves
= false;
1067 src_combo
.set_sensitive (true);
1069 src_combo
.set_sensitive (false);
1072 if (Config
->get_only_copy_imported_files()) {
1074 if (selection_can_be_embedded_with_links
) {
1075 copy_files_btn
.set_sensitive (true);
1077 copy_files_btn
.set_sensitive (false);
1082 copy_files_btn
.set_sensitive (true);
1090 SoundFileOmega::bad_file_message()
1092 MessageDialog
msg (*this,
1093 string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME
),
1098 resetting_ourselves
= true;
1099 chooser
.unselect_uri (chooser
.get_preview_uri());
1100 resetting_ourselves
= false;
1106 SoundFileOmega::check_info (const vector
<string
>& paths
, bool& same_size
, bool& src_needed
, bool& multichannel
)
1115 multichannel
= false;
1117 for (vector
<string
>::const_iterator i
= paths
.begin(); i
!= paths
.end(); ++i
) {
1119 if (AudioFileSource::get_soundfile_info (*i
, info
, errmsg
)) {
1120 if (info
.channels
> 1) {
1121 multichannel
= true;
1126 if (sz
!= info
.length
) {
1131 if (info
.samplerate
!= _session
->frame_rate()) {
1135 } else if (SMFSource::safe_midi_file_extension (*i
)) {
1139 if (reader
.num_tracks() > 1) {
1140 multichannel
= true; // "channel" == track here...
1143 /* XXX we need err = true handling here in case
1144 we can't check the file
1157 SoundFileOmega::check_link_status (const Session
* s
, const vector
<string
>& paths
)
1159 sys::path path
= s
->session_directory().sound_path() / "linktest";
1160 string tmpdir
= path
.to_string();
1163 if (mkdir (tmpdir
.c_str(), 0744)) {
1164 if (errno
!= EEXIST
) {
1169 for (vector
<string
>::const_iterator i
= paths
.begin(); i
!= paths
.end(); ++i
) {
1171 char tmpc
[MAXPATHLEN
+1];
1173 snprintf (tmpc
, sizeof(tmpc
), "%s/%s", tmpdir
.c_str(), Glib::path_get_basename (*i
).c_str());
1177 if (link ((*i
).c_str(), tmpc
)) {
1187 rmdir (tmpdir
.c_str());
1191 SoundFileChooser::SoundFileChooser (Gtk::Window
& parent
, string title
, ARDOUR::Session
* s
)
1192 : SoundFileBrowser (parent
, title
, s
, false)
1194 chooser
.set_select_multiple (false);
1195 found_list_view
.get_selection()->set_mode (SELECTION_SINGLE
);
1196 freesound_list_view
.get_selection()->set_mode (SELECTION_SINGLE
);
1200 SoundFileChooser::on_hide ()
1202 ArdourDialog::on_hide();
1206 _session
->cancel_audition();
1211 SoundFileChooser::get_filename ()
1213 vector
<string
> paths
;
1215 paths
= get_paths ();
1217 if (paths
.empty()) {
1221 if (!Glib::file_test (paths
.front(), Glib::FILE_TEST_EXISTS
|Glib::FILE_TEST_IS_REGULAR
)) {
1225 return paths
.front();
1228 SoundFileOmega::SoundFileOmega (Gtk::Window
& parent
, string title
, ARDOUR::Session
* s
, int selected_tracks
, bool persistent
,
1229 Editing::ImportMode mode_hint
)
1230 : SoundFileBrowser (parent
, title
, s
, persistent
),
1231 copy_files_btn ( _("Copy files to session")),
1232 selected_track_cnt (selected_tracks
)
1238 set_size_request (-1, 450);
1240 block_two
.set_border_width (12);
1241 block_three
.set_border_width (12);
1242 block_four
.set_border_width (12);
1244 options
.set_spacing (12);
1247 str
.push_back (_("file timestamp"));
1248 str
.push_back (_("edit point"));
1249 str
.push_back (_("playhead"));
1250 str
.push_back (_("session start"));
1251 set_popdown_strings (where_combo
, str
);
1252 where_combo
.set_active_text (str
.front());
1254 Label
* l
= manage (new Label
);
1255 l
->set_text (_("Add files:"));
1257 hbox
= manage (new HBox
);
1258 hbox
->set_border_width (12);
1259 hbox
->set_spacing (6);
1260 hbox
->pack_start (*l
, false, false);
1261 hbox
->pack_start (action_combo
, false, false);
1262 vbox
= manage (new VBox
);
1263 vbox
->pack_start (*hbox
, false, false);
1264 options
.pack_start (*vbox
, false, false);
1266 /* dummy entry for action combo so that it doesn't look odd if we
1267 come up with no tracks selected.
1271 str
.push_back (importmode2string (mode_hint
));
1272 set_popdown_strings (action_combo
, str
);
1273 action_combo
.set_active_text (str
.front());
1274 action_combo
.set_sensitive (false);
1276 l
= manage (new Label
);
1277 l
->set_text (_("Insert at:"));
1279 hbox
= manage (new HBox
);
1280 hbox
->set_border_width (12);
1281 hbox
->set_spacing (6);
1282 hbox
->pack_start (*l
, false, false);
1283 hbox
->pack_start (where_combo
, false, false);
1284 vbox
= manage (new VBox
);
1285 vbox
->pack_start (*hbox
, false, false);
1286 options
.pack_start (*vbox
, false, false);
1289 l
= manage (new Label
);
1290 l
->set_text (_("Mapping:"));
1292 hbox
= manage (new HBox
);
1293 hbox
->set_border_width (12);
1294 hbox
->set_spacing (6);
1295 hbox
->pack_start (*l
, false, false);
1296 hbox
->pack_start (channel_combo
, false, false);
1297 vbox
= manage (new VBox
);
1298 vbox
->pack_start (*hbox
, false, false);
1299 options
.pack_start (*vbox
, false, false);
1302 str
.push_back (_("one track per file"));
1303 set_popdown_strings (channel_combo
, str
);
1304 channel_combo
.set_active_text (str
.front());
1305 channel_combo
.set_sensitive (false);
1307 l
= manage (new Label
);
1308 l
->set_text (_("Conversion quality:"));
1310 hbox
= manage (new HBox
);
1311 hbox
->set_border_width (12);
1312 hbox
->set_spacing (6);
1313 hbox
->pack_start (*l
, false, false);
1314 hbox
->pack_start (src_combo
, false, false);
1315 vbox
= manage (new VBox
);
1316 vbox
->pack_start (*hbox
, false, false);
1317 options
.pack_start (*vbox
, false, false);
1320 str
.push_back (_("Best"));
1321 str
.push_back (_("Good"));
1322 str
.push_back (_("Quick"));
1323 str
.push_back (_("Fast"));
1324 str
.push_back (_("Fastest"));
1326 set_popdown_strings (src_combo
, str
);
1327 src_combo
.set_active_text (str
.front());
1328 src_combo
.set_sensitive (false);
1332 action_combo
.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret
));
1333 channel_combo
.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret
));
1335 copy_files_btn
.set_active (true);
1337 block_four
.pack_start (copy_files_btn
, false, false);
1339 options
.pack_start (block_four
, false, false);
1341 get_vbox()->pack_start (options
, false, false);
1343 /* setup disposition map */
1345 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("one track per file"), ImportDistinctFiles
));
1346 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("one track per channel"), ImportDistinctChannels
));
1347 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("merge files"), ImportMergeFiles
));
1348 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("sequence files"), ImportSerializeFiles
));
1350 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("one region per file"), ImportDistinctFiles
));
1351 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("one region per channel"), ImportDistinctChannels
));
1352 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("all files in one region"), ImportMergeFiles
));
1353 disposition_map
.insert (pair
<string
,ImportDisposition
>(_("all files in one track"), ImportMergeFiles
));
1355 chooser
.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed
));
1357 /* set size requests for a couple of combos to allow them to display the longest text
1358 they will ever be asked to display. This prevents them being resized when the user
1359 selects a file to import, which in turn prevents the size of the dialog from jumping
1363 t
.push_back (_("one track per file"));
1364 t
.push_back (_("one track per channel"));
1365 t
.push_back (_("sequence files"));
1366 t
.push_back (_("all files in one region"));
1367 set_size_request_to_display_given_text (channel_combo
, t
, COMBO_FUDGE
+ 10, 15);
1370 t
.push_back (importmode2string (ImportAsTrack
));
1371 t
.push_back (importmode2string (ImportToTrack
));
1372 t
.push_back (importmode2string (ImportAsRegion
));
1373 t
.push_back (importmode2string (ImportAsTapeTrack
));
1374 set_size_request_to_display_given_text (action_combo
, t
, COMBO_FUDGE
+ 10, 15);
1378 SoundFileOmega::set_mode (ImportMode mode
)
1380 action_combo
.set_active_text (importmode2string (mode
));
1384 SoundFileOmega::get_mode () const
1386 return string2importmode (action_combo
.get_active_text());
1390 SoundFileOmega::on_hide ()
1392 ArdourDialog::on_hide();
1394 _session
->cancel_audition();
1399 SoundFileOmega::get_position() const
1401 string str
= where_combo
.get_active_text();
1403 if (str
== _("file timestamp")) {
1404 return ImportAtTimestamp
;
1405 } else if (str
== _("edit point")) {
1406 return ImportAtEditPoint
;
1407 } else if (str
== _("playhead")) {
1408 return ImportAtPlayhead
;
1410 return ImportAtStart
;
1415 SoundFileOmega::get_src_quality() const
1417 string str
= where_combo
.get_active_text();
1419 if (str
== _("Best")) {
1421 } else if (str
== _("Good")) {
1423 } else if (str
== _("Quick")) {
1425 } else if (str
== _("Fast")) {
1433 SoundFileOmega::get_channel_disposition () const
1435 /* we use a map here because the channel combo can contain different strings
1436 depending on the state of the other combos. the map contains all possible strings
1437 and the ImportDisposition enum that corresponds to it.
1440 string str
= channel_combo
.get_active_text();
1441 DispositionMap::const_iterator x
= disposition_map
.find (str
);
1443 if (x
== disposition_map
.end()) {
1444 fatal
<< string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str
) << endmsg
;
1452 SoundFileOmega::reset (int selected_tracks
)
1454 selected_track_cnt
= selected_tracks
;
1459 SoundFileOmega::file_selection_changed ()
1461 if (resetting_ourselves
) {
1465 if (!reset_options ()) {
1466 set_response_sensitive (RESPONSE_OK
, false);
1468 if (chooser
.get_filenames().size() > 0) {
1469 set_response_sensitive (RESPONSE_OK
, true);
1471 set_response_sensitive (RESPONSE_OK
, false);