/*
- Copyright (C) 2005-2006 Paul Davis
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
+ * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
+ * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
+ * Copyright (C) 2006-2018 Paul Davis <paul@linuxaudiosystems.com>
+ * Copyright (C) 2006 Doug McLain <doug@nostar.net>
+ * Copyright (C) 2006 Nick Mainsbridge <mainsbridge@gmail.com>
+ * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
+ * Copyright (C) 2012-2017 Tim Mayberry <mojofunk@gmail.com>
+ * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2013-2015 John Emmas <john@creativepost.co.uk>
+ * Copyright (C) 2013 Colin Fletcher <colin.m.fletcher@googlemail.com>
+ * Copyright (C) 2019-2018 Ben Loftis <ben@harrisonconsoles.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
#ifdef WAF_BUILD
#include "gtk2ardour-config.h"
#endif
-#include "pbd/i18n.h"
+#ifdef PLATFORM_WINDOWS
+#include <windows.h>
+#endif
#include <map>
#include <cerrno>
#include <limits.h>
#include <gtkmm/box.h>
+#include <gtkmm/scrolledwindow.h>
#include <gtkmm/stock.h>
#include "pbd/gstdio_compat.h"
#include <glibmm/fileutils.h>
-#include "pbd/convert.h"
#include "pbd/tokenizer.h"
#include "pbd/enumwriter.h"
+#include "pbd/file_utils.h"
#include "pbd/pthread_utils.h"
+#include "pbd/string_convert.h"
#include "pbd/xml++.h"
#include <gtkmm2ext/utils.h>
-#include "evoral/SMF.hpp"
+#include "evoral/SMF.h"
#include "ardour/audio_library.h"
#include "ardour/auditioner.h"
#include "ardour/session.h"
#include "ardour/session_directory.h"
#include "ardour/srcfilesource.h"
+#include "ardour/profile.h"
#include "ardour_ui.h"
#include "editing.h"
#include "gui_thread.h"
-#include "prompter.h"
#include "sfdb_ui.h"
#include "editing.h"
#include "gain_meter.h"
#include "sfdb_freesound_mootcher.h"
+#include "pbd/i18n.h"
+
using namespace ARDOUR;
using namespace PBD;
using namespace std;
string SoundFileBrowser::persistent_folder;
typedef TreeView::Selection::ListHandle_Path ListPath;
+static MidiTrackNameSource
+string2miditracknamesource (string const & str)
+{
+ if (str == _("by track number")) {
+ return SMFTrackNumber;
+ } else if (str == _("by track name")) {
+ return SMFTrackName;
+ } else if (str == _("by instrument name")) {
+ return SMFInstrumentName;
+ }
+
+ warning << string_compose (_("programming error: unknown midi track name source string %1"), str) << endmsg;
+
+ return SMFTrackNumber;
+}
+
static ImportMode
-string2importmode (string str)
+string2importmode (string const & str)
{
if (str == _("as new tracks")) {
return ImportAsTrack;
} else if (str == _("to selected tracks")) {
return ImportToTrack;
- } else if (str == _("to region list")) {
+ } else if (str == _("to source list")) {
return ImportAsRegion;
} else if (str == _("as new tape tracks")) {
return ImportAsTapeTrack;
case ImportToTrack:
return _("to selected tracks");
case ImportAsRegion:
- return _("to region list");
+ return _("to source list");
case ImportAsTapeTrack:
return _("as new tape tracks");
}
}
SoundFileBox::SoundFileBox (bool /*persistent*/)
- : table (6, 2),
+ : table (7, 2),
length_clock ("sfboxLengthClock", true, "", false, false, true, false),
timecode_clock ("sfboxTimecodeClock", true, "", false, false, false, false),
main_box (false, 6),
autoplay_btn (_("Auto-play")),
seek_slider(0,1000,1),
- _seeking(false)
+ _seeking(false),
+ _src_quality (SrcBest),
+ _import_position (ImportAtTimestamp)
{
set_name (X_("SoundFileBox"));
channels.set_alignment (1, 0.5);
samplerate.set_text (_("Sample rate:"));
samplerate.set_alignment (1, 0.5);
+ tempomap.set_text (_("Tempo Map:"));
+ tempomap.set_alignment (1, 0.5);
preview_label.set_max_width_chars (50);
preview_label.set_ellipsize (Pango::ELLIPSIZE_END);
table.attach (format, 0, 1, 2, 4, FILL, FILL);
table.attach (length, 0, 1, 4, 5, FILL, FILL);
table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
+ table.attach (tempomap, 0, 1, 6, 7, FILL, FILL);
table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
+ table.attach (tempomap_value, 1, 2, 6, 7, FILL, FILL);
- length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock->mode());
+ length_clock.set_mode (ARDOUR_UI::instance()->primary_clock->mode());
timecode_clock.set_mode (AudioClock::Timecode);
main_box.pack_start (table, false, false);
play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
+ update_autoplay ();
+ autoplay_btn.signal_toggled().connect(sigc::mem_fun (*this, &SoundFileBox::autoplay_toggled));
+
stop_btn.set_sensitive (false);
channels_value.set_alignment (0.0f, 0.5f);
}
void
-SoundFileBox::audition_progress(ARDOUR::framecnt_t pos, ARDOUR::framecnt_t len) {
+SoundFileBox::audition_progress(ARDOUR::samplecnt_t pos, ARDOUR::samplecnt_t len) {
if (!_seeking) {
seek_slider.set_value( 1000.0 * pos / len);
seek_slider.set_sensitive (true);
tags_entry.set_sensitive (false);
if (ms) {
- channels_value.set_text (to_string(ms->num_tracks(), std::dec));
- length_clock.set (ms->length(ms->timeline_position()));
+ if (ms->is_type0()) {
+ channels_value.set_text (to_string<uint32_t>(ms->channels().size()));
+ } else {
+ if (ms->num_tracks() > 1) {
+ channels_value.set_text (to_string(ms->num_tracks()) + _("(Tracks)"));
+ } else {
+ channels_value.set_text (to_string(ms->num_tracks()));
+ }
+ }
+ length_clock.set (ms->length(ms->natural_position()));
+ switch (ms->num_tempos()) {
+ case 0:
+ tempomap_value.set_text (_("No tempo data"));
+ break;
+ case 1: {
+ Evoral::SMF::Tempo* t = ms->nth_tempo (0);
+ assert (t);
+ tempomap_value.set_text (string_compose (_("%1/%2 \u2669 = %3"),
+ t->numerator,
+ t->denominator,
+ t->tempo ()));
+ break;
+ }
+ default:
+ tempomap_value.set_text (string_compose (_("map with %1 sections"),
+ ms->num_tempos()));
+ break;
+ }
} else {
channels_value.set_text ("");
length_clock.set (0);
+ tempomap_value.set_text (_("No tempo data"));
}
if (_session && ms) {
n = n.substr (8);
}
format_text.set_text (n);
- channels_value.set_text (to_string (sf_info.channels, std::dec));
+ channels_value.set_text (to_string (sf_info.channels));
- if (_session && sf_info.samplerate != _session->frame_rate()) {
+ if (_session && sf_info.samplerate != _session->sample_rate()) {
samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
samplerate_value.set_name ("NewSessionSR1Label");
samplerate.set_name ("NewSessionSR2Label");
}
- framecnt_t const nfr = _session ? _session->nominal_frame_rate() : 25;
+ samplecnt_t const nfr = _session ? _session->nominal_sample_rate() : 25;
double src_coef = (double) nfr / sf_info.samplerate;
length_clock.set (sf_info.length * src_coef + 0.5, true);
return true;
}
+void
+SoundFileBox::update_autoplay ()
+{
+ const bool config_autoplay = UIConfiguration::instance().get_autoplay_files();
+
+ if (autoplay_btn.get_active() != config_autoplay) {
+ autoplay_btn.set_active (config_autoplay);
+ }
+}
+
+void
+SoundFileBox::autoplay_toggled()
+{
+ UIConfiguration::instance().set_autoplay_files(autoplay_btn.get_active());
+}
+
bool
SoundFileBox::autoplay() const
{
PropertyList plist;
plist.add (ARDOUR::Properties::start, 0);
- plist.add (ARDOUR::Properties::length, ms->length(ms->timeline_position()));
+ plist.add (ARDOUR::Properties::length, ms->length(ms->natural_position()));
plist.add (ARDOUR::Properties::name, rname);
plist.add (ARDOUR::Properties::layer, 0);
SourceFactory::createExternal (DataType::AUDIO, *_session,
path, n,
Source::Flag (ARDOUR::AudioFileSource::NoPeakFile), false));
- if (afs->sample_rate() != _session->nominal_frame_rate()) {
+ if (afs->sample_rate() != _session->nominal_sample_rate()) {
boost::shared_ptr<SrcFileSource> sfs (new SrcFileSource(*_session, afs, _src_quality));
srclist.push_back(sfs);
} else {
PropertyList plist;
plist.add (ARDOUR::Properties::start, 0);
- plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
+ plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->natural_position()));
plist.add (ARDOUR::Properties::name, rname);
plist.add (ARDOUR::Properties::layer, 0);
r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
}
- frameoffset_t audition_position = 0;
+ sampleoffset_t audition_position = 0;
switch(_import_position) {
case ImportAtTimestamp:
audition_position = 0;
break;
case ImportAtPlayhead:
- audition_position = _session->transport_frame();
+ audition_position = _session->transport_sample();
break;
case ImportAtStart:
- audition_position = _session->current_start_frame();
+ audition_position = _session->current_start_sample();
break;
case ImportAtEditPoint:
audition_position = PublicEditor::instance().get_preferred_edit_position ();
, _status (0)
, _done (false)
, import_button (_("Import"))
- , close_button (Stock::CLOSE)
, gm (0)
{
Gtk::HButtonBox* button_box = manage (new HButtonBox);
button_box->set_layout (BUTTONBOX_END);
- button_box->pack_start (close_button, false, false);
- close_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_CLOSE));
button_box->pack_start (import_button, false, false);
import_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_OK));
Gtkmm2ext::UI::instance()->set_tip (import_button, _("Press to import selected files"));
- Gtkmm2ext::UI::instance()->set_tip (close_button, _("Press to close this window without importing any files"));
vpacker.pack_end (*button_box, false, false);
import_button.set_sensitive (yn);
}
+bool
+SoundFileBrowser::get_action_sensitive () const
+{
+ return import_button.get_sensitive ();
+}
+
void
SoundFileBrowser::do_something (int action)
{
SoundFileBrowser::on_show ()
{
ArdourWindow::on_show ();
+ reset_options ();
start_metering ();
}
+bool
+SoundFileBrowser::on_key_press_event (GdkEventKey* ev)
+{
+ if (ev->keyval == GDK_Escape) {
+ do_something (RESPONSE_CLOSE);
+ return true;
+ }
+ if (ev->keyval == GDK_space && ev->type == GDK_KEY_PRESS) {
+ if (get_action_sensitive()) {
+ preview.audition();
+ return true;
+ }
+ }
+ return ArdourWindow::on_key_press_event (ev);
+}
+
void
SoundFileBrowser::clear_selection ()
{
void
SoundFileBrowser::chooser_file_activated ()
{
- preview.audition ();
+ do_something (RESPONSE_OK);
}
void
bool same_size;
bool src_needed;
+ bool must_copy;
bool selection_includes_multichannel;
bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
ImportMode mode;
}
bool const have_a_midi_file = (i != paths.end ());
- if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
+ if (check_info (paths, same_size, src_needed, selection_includes_multichannel, must_copy)) {
Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
return false;
}
+ if (have_a_midi_file) {
+ smf_tempo_btn.show ();
+ } else {
+ smf_tempo_btn.hide ();
+ }
+
string existing_choice;
vector<string> action_strings;
action_strings.push_back (importmode2string (ImportAsTrack));
action_strings.push_back (importmode2string (ImportAsRegion));
- action_strings.push_back (importmode2string (ImportAsTapeTrack));
+ if (!Profile->get_mixbus()) {
+ action_strings.push_back (importmode2string (ImportAsTapeTrack));
+ }
existing_choice = action_combo.get_active_text();
vector<string> channel_strings;
if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
+
channel_strings.push_back (_("one track per file"));
if (selection_includes_multichannel) {
/* We must copy MIDI files or those from Freesound
* or any file if we are under nsm control */
- bool const must_copy = _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
+ must_copy |= _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
if (UIConfiguration::instance().get_only_copy_imported_files()) {
}
bool
-SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
+SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel, bool& must_copy)
{
SoundFileInfo info;
- framepos_t sz = 0;
+ samplepos_t sz = 0;
bool err = false;
string errmsg;
same_size = true;
src_needed = false;
multichannel = false;
+ must_copy = false;
for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
}
}
- if (info.samplerate != _session->frame_rate()) {
+ if (info.samplerate != _session->sample_rate()) {
src_needed = true;
}
+ if (!info.seekable) {
+ must_copy = true;
+ }
} else if (SMFSource::valid_midi_file (*i)) {
Evoral::SMF reader;
- reader.open(*i);
- if (reader.num_tracks() > 1) {
- multichannel = true; // "channel" == track here...
- }
- /* XXX we need err = true handling here in case
- we can't check the file
- */
+ if (reader.open (*i)) {
+ err = true;
+ } else {
+ if (reader.is_type0 ()) {
+ if (reader.channels().size() > 1) {
+ /* for type-0 files, we can split
+ * "one track per channel"
+ */
+ multichannel = true;
+ }
+ } else {
+ if (reader.num_tracks() > 1) {
+ multichannel = true;
+ }
+ }
+ }
} else {
err = true;
bool
SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
{
-#ifdef PLATFORM_WINDOWS
- return false;
-#else
std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
- bool ret = false;
if (g_mkdir (tmpdir.c_str(), 0744)) {
if (errno != EEXIST) {
for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
char tmpc[PATH_MAX+1];
-
snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
/* can we link ? */
-
- if (link ((*i).c_str(), tmpc)) {
- goto out;
+ if (PBD::hard_link (/*existing file*/(*i).c_str(), tmpc)) {
+ ::g_unlink (tmpc);
}
-
- ::g_unlink (tmpc);
}
- ret = true;
-
- out:
g_rmdir (tmpdir.c_str());
- return ret;
-#endif
+
+ return true;
}
SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
Editing::ImportMode mode_hint)
: SoundFileBrowser (title, s, persistent)
, copy_files_btn ( _("Copy files to session"))
+ , smf_tempo_btn (_("Use MIDI Tempo Map (if defined)"))
, selected_audio_track_cnt (selected_audio_tracks)
, selected_midi_track_cnt (selected_midi_tracks)
, _import_active (false)
where_combo.set_active_text (str.back());
where_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::where_combo_changed));
+ instrument_combo_changed();
+ instrument_combo.signal_changed().connect(sigc::mem_fun(*this, &SoundFileOmega::instrument_combo_changed) );
+
Label* l = manage (new Label);
l->set_markup (_("<b>Add files ...</b>"));
options.attach (*l, 0, 1, 0, 1, FILL, SHRINK, 8, 0);
options.attach (*l, 1, 2, 3, 4, FILL, SHRINK, 8, 0);
options.attach (src_combo, 1, 2, 4, 5, FILL, SHRINK, 8, 0);
+ l = manage (new Label);
+ l->set_markup (_("<b>MIDI Track Names</b>"));
+ options.attach (*l, 2, 3, 0, 1, FILL, SHRINK, 8, 0);
+ options.attach (midi_track_name_combo, 2, 3, 1, 2, FILL, SHRINK, 8, 0);
+
+ options.attach (smf_tempo_btn, 2, 3, 3, 4, FILL, SHRINK, 8, 0);
+
l = manage (new Label);
l->set_markup (_("<b>Instrument</b>"));
options.attach (*l, 3, 4, 0, 1, FILL, SHRINK, 8, 0);
vspace->set_size_request (2, 2);
options.attach (*vspace, 2, 3, 0, 3, EXPAND, SHRINK, 0, 0);
+ str.clear ();
+ str.push_back (_("by track number"));
+ str.push_back (_("by track name"));
+ str.push_back (_("by instrument name"));
+ set_popdown_strings (midi_track_name_combo, str);
+ midi_track_name_combo.set_active_text (str.front());
+
str.clear ();
str.push_back (_("one track per file"));
set_popdown_strings (channel_combo, str);
preview.set_import_position(get_position());
}
+void
+SoundFileOmega::instrument_combo_changed()
+{
+ _session->the_auditioner()->set_audition_synth_info( instrument_combo.selected_instrument() );
+}
+
+MidiTrackNameSource
+SoundFileOmega::get_midi_track_name_source () const
+{
+ return string2miditracknamesource (midi_track_name_combo.get_active_text());
+}
+
+bool
+SoundFileOmega::get_use_smf_tempo_map () const
+{
+ return smf_tempo_btn.get_active ();
+}
+
ImportDisposition
SoundFileOmega::get_channel_disposition () const
{
chooser.set_filter (audio_and_midi_filter);
}
- reset_options ();
+ if (is_visible()) {
+ reset_options ();
+ }
}
void
SoundFileOmega::file_selection_changed ()
{
- if (resetting_ourselves) {
+ if (resetting_ourselves || !is_visible ()) {
return;
}
{
SoundFileBrowser::do_something (action);
- if (action == RESPONSE_CLOSE) {
+ if (action == RESPONSE_CLOSE || !ARDOUR_UI_UTILS::engine_is_running ()) {
hide ();
return;
}
ImportMode mode = get_mode ();
ImportDisposition chns = get_channel_disposition ();
PluginInfoPtr instrument = instrument_combo.selected_instrument();
- framepos_t where;
+ samplepos_t where;
+ MidiTrackNameSource mts = get_midi_track_name_source ();
+ MidiTempoMapDisposition mtd = (get_use_smf_tempo_map () ? SMFTempoUse : SMFTempoIgnore);
switch (pos) {
case ImportAtEditPoint:
where = -1;
break;
case ImportAtPlayhead:
- where = _session->transport_frame();
+ where = _session->transport_sample();
break;
case ImportAtStart:
- where = _session->current_start_frame();
+ where = _session->current_start_sample();
break;
}
_import_active = true;
if (copy_files_btn.get_active()) {
- PublicEditor::instance().do_import (paths, chns, mode, quality, where, instrument);
+ PublicEditor::instance().do_import (paths, chns, mode, quality, mts, mtd, where, instrument);
} else {
PublicEditor::instance().do_embed (paths, chns, mode, where, instrument);
}
reset_options ();
}
}
-