Vkeybd: add a mod-wheel
[ardour.git] / gtk2_ardour / sfdb_ui.cc
index d3979959fd715defc15da7169bf4e42f9c8154fd..940e7dd0350d830885e3164331d3e334a2029cca 100644 (file)
@@ -1,27 +1,38 @@
 /*
-    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"
@@ -62,7 +75,6 @@
 #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"
@@ -73,6 +85,8 @@
 
 #include "sfdb_freesound_mootcher.h"
 
+#include "pbd/i18n.h"
+
 using namespace ARDOUR;
 using namespace PBD;
 using namespace std;
@@ -108,7 +122,7 @@ string2importmode (string const & str)
                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;
@@ -128,7 +142,7 @@ importmode2string (ImportMode mode)
        case ImportToTrack:
                return _("to selected tracks");
        case ImportAsRegion:
-               return _("to region list");
+               return _("to source list");
        case ImportAsTapeTrack:
                return _("as new tape tracks");
        }
@@ -143,7 +157,9 @@ SoundFileBox::SoundFileBox (bool /*persistent*/)
          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"));
@@ -197,7 +213,7 @@ SoundFileBox::SoundFileBox (bool /*persistent*/)
        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);
@@ -235,6 +251,9 @@ SoundFileBox::SoundFileBox (bool /*persistent*/)
        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);
@@ -270,7 +289,7 @@ SoundFileBox::audition_active(bool active) {
 }
 
 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);
@@ -325,15 +344,15 @@ SoundFileBox::setup_labels (const string& filename)
 
                if (ms) {
                        if (ms->is_type0()) {
-                               channels_value.set_text (to_string(ms->channels().size(), std::dec));
+                               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(), std::dec) + _("(Tracks)"));
+                                       channels_value.set_text (to_string(ms->num_tracks()) + _("(Tracks)"));
                                } else {
-                                       channels_value.set_text (to_string(ms->num_tracks(), std::dec));
+                                       channels_value.set_text (to_string(ms->num_tracks()));
                                }
                        }
-                       length_clock.set (ms->length(ms->timeline_position()));
+                       length_clock.set (ms->length(ms->natural_position()));
                        switch (ms->num_tempos()) {
                        case 0:
                                tempomap_value.set_text (_("No tempo data"));
@@ -344,7 +363,7 @@ SoundFileBox::setup_labels (const string& filename)
                                tempomap_value.set_text (string_compose (_("%1/%2 \u2669 = %3"),
                                                                         t->numerator,
                                                                         t->denominator,
-                                                                        (1000000 / t->microseconds_per_quarter_note) * 60));
+                                                                        t->tempo ()));
                                break;
                        }
                        default:
@@ -390,9 +409,9 @@ SoundFileBox::setup_labels (const string& filename)
                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");
@@ -404,7 +423,7 @@ SoundFileBox::setup_labels (const string& filename)
                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);
@@ -431,6 +450,22 @@ SoundFileBox::setup_labels (const string& filename)
        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
 {
@@ -472,7 +507,7 @@ SoundFileBox::audition ()
                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);
 
@@ -495,7 +530,7 @@ SoundFileBox::audition ()
                                        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 {
@@ -521,23 +556,23 @@ SoundFileBox::audition ()
                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 ();
@@ -604,7 +639,6 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persi
        , _status (0)
        , _done (false)
        , import_button (_("Import"))
-       , close_button (Stock::CLOSE)
        , gm (0)
 {
 
@@ -780,14 +814,11 @@ SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persi
        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);
 
@@ -821,6 +852,12 @@ SoundFileBrowser::set_action_sensitive (bool yn)
        import_button.set_sensitive (yn);
 }
 
+bool
+SoundFileBrowser::get_action_sensitive () const
+{
+       return import_button.get_sensitive ();
+}
+
 void
 SoundFileBrowser::do_something (int action)
 {
@@ -832,9 +869,26 @@ void
 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 ()
 {
@@ -845,7 +899,7 @@ SoundFileBrowser::clear_selection ()
 void
 SoundFileBrowser::chooser_file_activated ()
 {
-       preview.audition ();
+       do_something (RESPONSE_OK);
 }
 
 void
@@ -1380,6 +1434,7 @@ SoundFileOmega::reset_options ()
 
        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;
@@ -1391,7 +1446,7 @@ SoundFileOmega::reset_options ()
        }
        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;
        }
@@ -1485,12 +1540,12 @@ SoundFileOmega::reset_options ()
 
        if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
 
+               channel_strings.push_back (_("one track per file"));
+
                if (selection_includes_multichannel) {
                        channel_strings.push_back (_("one track per channel"));
                }
 
-               channel_strings.push_back (_("one track per file"));
-
                if (paths.size() > 1) {
                        /* tape tracks are a single region per track, so we cannot
                           sequence multiple files.
@@ -1552,7 +1607,7 @@ SoundFileOmega::reset_options ()
 
        /* 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()) {
 
@@ -1594,16 +1649,17 @@ SoundFileOmega::bad_file_message()
 }
 
 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) {
 
@@ -1619,9 +1675,12 @@ SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool&
                                }
                        }
 
-                       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)) {
 
@@ -1656,11 +1715,7 @@ SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool&
 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) {
@@ -1671,24 +1726,17 @@ SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths
        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)
@@ -1758,6 +1806,9 @@ SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s,
        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);
@@ -1944,6 +1995,12 @@ SoundFileOmega::where_combo_changed()
        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
 {
@@ -1989,13 +2046,15 @@ SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tr
                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;
        }
 
@@ -2015,7 +2074,7 @@ SoundFileOmega::do_something (int action)
 {
        SoundFileBrowser::do_something (action);
 
-       if (action == RESPONSE_CLOSE) {
+       if (action == RESPONSE_CLOSE || !ARDOUR_UI_UTILS::engine_is_running ()) {
                hide ();
                return;
        }
@@ -2027,7 +2086,7 @@ SoundFileOmega::do_something (int action)
        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);
 
@@ -2039,10 +2098,10 @@ SoundFileOmega::do_something (int action)
                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;
        }