13
0
livetrax/gtk2_ardour/livetrax_rc_option_editor.cc

2256 lines
81 KiB
C++

/*
* Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2009-2015 David Robillard <d@drobilla.net>
* Copyright (C) 2009-2019 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
* Copyright (C) 2013-2016 Nick Mainsbridge <mainsbridge@gmail.com>
* Copyright (C) 2013-2018 Colin Fletcher <colin.m.fletcher@googlemail.com>
* Copyright (C) 2013 John Emmas <john@creativepost.co.uk>
* Copyright (C) 2014-2016 Tim Mayberry <mojofunk@gmail.com>
* Copyright (C) 2014-2019 Ben Loftis <ben@harrisonconsoles.com>
* Copyright (C) 2018 Len Ovens <len@ovenwerks.net>
*
* 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 <cairo/cairo.h>
#include <boost/algorithm/string.hpp>
#include <gtkmm/liststore.h>
#include <gtkmm/stock.h>
#include <gtkmm/scale.h>
#include "gtkmm2ext/keyboard.h"
#include "gtkmm2ext/utils.h"
#include "gtkmm2ext/gtk_ui.h"
#include "gtkmm2ext/window_title.h"
#include "pbd/file_utils.h"
#include "pbd/fpu.h"
#include "pbd/cpus.h"
#include "pbd/unwind.h"
#include "pbd/i18n.h"
#include "ardour/audio_backend.h"
#include "ardour/audioengine.h"
#include "ardour/clip_library.h"
#include "ardour/control_protocol_manager.h"
#include "ardour/dB.h"
#include "ardour/parameter_descriptor.h"
#include "ardour/port_manager.h"
#include "ardour/plugin_manager.h"
#include "ardour/profile.h"
#include "ardour/rc_configuration.h"
#include "ardour/transport_master_manager.h"
#include "control_protocol/control_protocol.h"
#include "waveview/wave_view.h"
#include "widgets/paths_dialog.h"
#include "widgets/tooltips.h"
#include "actions.h"
#include "ardour_ui.h"
#include "ardour_dialog.h"
#include "ardour_ui.h"
#include "ardour_window.h"
#include "color_theme_manager.h"
#include "gui_thread.h"
#include "keyboard.h"
#include "meter_patterns.h"
#include "midi_tracer.h"
#include "plugin_scan_dialog.h"
#include "livetrax_rc_option_editor.h"
#include "sfdb_ui.h"
#include "transport_masters_dialog.h"
#include "ui_config.h"
#include "utils.h"
using namespace std;
using namespace Gtk;
using namespace Gtkmm2ext;
using namespace PBD;
using namespace ARDOUR;
using namespace ARDOUR_UI_UTILS;
using namespace ArdourWidgets;
class UndoOptions : public OptionEditorComponent
{
public:
UndoOptions (RCConfiguration* c) :
_rc_config (c),
_limit_undo_button (_("Limit undo history to")),
_save_undo_button (_("Save undo history of"))
{
// TODO get rid of GTK -> use OptionEditor SpinOption
_limit_undo_spin.set_range (0, 512);
_limit_undo_spin.set_increments (1, 10);
_save_undo_spin.set_range (0, 512);
_save_undo_spin.set_increments (1, 10);
_limit_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_toggled));
_limit_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_changed));
_save_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_toggled));
_save_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_changed));
}
void parameter_changed (string const & p)
{
if (p == "history-depth") {
int32_t const d = _rc_config->get_history_depth();
_limit_undo_button.set_active (d != 0);
_limit_undo_spin.set_sensitive (d != 0);
_limit_undo_spin.set_value (d);
} else if (p == "save-history") {
bool const x = _rc_config->get_save_history ();
_save_undo_button.set_active (x);
_save_undo_spin.set_sensitive (x);
} else if (p == "save-history-depth") {
_save_undo_spin.set_value (_rc_config->get_saved_history_depth());
}
}
void set_state_from_config ()
{
parameter_changed ("save-history");
parameter_changed ("history-depth");
parameter_changed ("save-history-depth");
}
void limit_undo_toggled ()
{
bool const x = _limit_undo_button.get_active ();
_limit_undo_spin.set_sensitive (x);
int32_t const n = x ? 16 : 0;
_limit_undo_spin.set_value (n);
_rc_config->set_history_depth (n);
}
void limit_undo_changed ()
{
_rc_config->set_history_depth (_limit_undo_spin.get_value_as_int ());
}
void save_undo_toggled ()
{
bool const x = _save_undo_button.get_active ();
_rc_config->set_save_history (x);
}
void save_undo_changed ()
{
_rc_config->set_saved_history_depth (_save_undo_spin.get_value_as_int ());
}
void add_to_page (OptionEditorPage* p)
{
int const n = p->table.property_n_rows();
Table* t = & p->table;
t->resize (n + 2, 3);
Label* l = manage (left_aligned_label (_("commands")));
HBox* box = manage (new HBox());
box->set_spacing (4);
box->pack_start (_limit_undo_spin, false, false);
box->pack_start (*l, true, true);
t->attach (_limit_undo_button, 1, 2, n, n +1, FILL);
t->attach (*box, 2, 3, n, n + 1, FILL | EXPAND);
l = manage (left_aligned_label (_("commands")));
box = manage (new HBox());
box->set_spacing (4);
box->pack_start (_save_undo_spin, false, false);
box->pack_start (*l, true, true);
t->attach (_save_undo_button, 1, 2, n + 1, n + 2, FILL);
t->attach (*box, 2, 3, n + 1, n + 2, FILL | EXPAND);
}
Gtk::Widget& tip_widget() {
return _limit_undo_button; // unused
}
private:
RCConfiguration* _rc_config;
CheckButton _limit_undo_button;
SpinButton _limit_undo_spin;
CheckButton _save_undo_button;
SpinButton _save_undo_spin;
};
static const struct {
const char *name;
guint modifier;
} modifiers[] = {
{ "Unmodified", 0 },
#ifdef __APPLE__
/* Command = Meta
Option/Alt = Mod1
*/
{ "Key|Shift", GDK_SHIFT_MASK },
{ "Command", GDK_MOD2_MASK },
{ "Control", GDK_CONTROL_MASK },
{ "Option", GDK_MOD1_MASK },
{ "Command-Shift", GDK_MOD2_MASK|GDK_SHIFT_MASK },
{ "Command-Option", GDK_MOD2_MASK|GDK_MOD1_MASK },
{ "Command-Control", GDK_MOD2_MASK|GDK_CONTROL_MASK },
{ "Command-Option-Control", GDK_MOD2_MASK|GDK_MOD1_MASK|GDK_CONTROL_MASK },
{ "Option-Control", GDK_MOD1_MASK|GDK_CONTROL_MASK },
{ "Option-Shift", GDK_MOD1_MASK|GDK_SHIFT_MASK },
{ "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
{ "Shift-Command-Option", GDK_MOD5_MASK|GDK_SHIFT_MASK|GDK_MOD2_MASK },
#else
{ "Key|Shift", GDK_SHIFT_MASK },
{ "Control", GDK_CONTROL_MASK },
{ "Alt", GDK_MOD1_MASK },
{ "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
{ "Control-Alt", GDK_CONTROL_MASK|GDK_MOD1_MASK },
{ "Control-Windows", GDK_CONTROL_MASK|GDK_MOD4_MASK },
{ "Control-Shift-Alt", GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_MOD1_MASK },
{ "Alt-Windows", GDK_MOD1_MASK|GDK_MOD4_MASK },
{ "Alt-Shift", GDK_MOD1_MASK|GDK_SHIFT_MASK },
{ "Alt-Shift-Windows", GDK_MOD1_MASK|GDK_SHIFT_MASK|GDK_MOD4_MASK },
{ "Mod2", GDK_MOD2_MASK },
{ "Mod3", GDK_MOD3_MASK },
{ "Windows", GDK_MOD4_MASK },
{ "Mod5", GDK_MOD5_MASK },
#endif
{ 0, 0 }
};
class FontScalingOptions : public HSliderOption
{
public:
FontScalingOptions ()
: HSliderOption ("font-scale", _("GUI and Font scaling"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_font_scale),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_font_scale),
50, 250, 1, 5,
1024, false)
{
const std::string dflt = _("100%");
const std::string dbl = _("200%");
const std::string empty = X_(""); // despite gtk-doc saying so, NULL does not work as reference
_hscale.set_name("FontScaleSlider");
_hscale.set_draw_value(false);
_hscale.add_mark(50, Gtk::POS_TOP, empty);
_hscale.add_mark(60, Gtk::POS_TOP, empty);
_hscale.add_mark(70, Gtk::POS_TOP, empty);
_hscale.add_mark(80, Gtk::POS_TOP, empty);
_hscale.add_mark(90, Gtk::POS_TOP, empty);
_hscale.add_mark(100, Gtk::POS_TOP, dflt);
_hscale.add_mark(125, Gtk::POS_TOP, empty);
_hscale.add_mark(150, Gtk::POS_TOP, empty);
_hscale.add_mark(175, Gtk::POS_TOP, empty);
_hscale.add_mark(200, Gtk::POS_TOP, dbl);
_hscale.add_mark(250, Gtk::POS_TOP, empty);
set_note (_("Adjusting the scale requires an application restart for fully accurate re-layout."));
}
void changed ()
{
HSliderOption::changed ();
/* XXX: should be triggered from the parameter changed signal */
UIConfiguration::instance().reset_dpi ();
}
};
class ClipLevelOptions : public HSliderOption
{
public:
ClipLevelOptions ()
: HSliderOption (X_("waveform-clip-level"),
_("Waveform Clip Level (dBFS)"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_clip_level),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_clip_level),
-50.0, -0.5, 0.1, 1.0, /* units of dB */
1.0,
false)
{
}
void parameter_changed (string const & p)
{
if (p == "waveform-clip-level") {
ArdourWaveView::WaveView::set_clip_level (UIConfiguration::instance().get_waveform_clip_level());
}
if (p == "show-waveform-clipping") {
_hscale.set_sensitive (UIConfiguration::instance().get_show_waveform_clipping ());
}
}
void set_state_from_config ()
{
parameter_changed ("waveform-clip-level");
parameter_changed ("show-waveform-clipping");
}
};
class BufferingOptions : public OptionEditorComponent
{
public:
BufferingOptions (RCConfiguration* c)
: _rc_config (c)
, _label (_("Preset:"))
, _playback ("playback-buffer-seconds", _("Playback (seconds of buffering)"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_audio_playback_buffer_seconds),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_audio_playback_buffer_seconds),
1, 60, 1, 4)
, _capture ("capture-buffer-seconds", _("Recording (seconds of buffering)"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_audio_capture_buffer_seconds),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_audio_capture_buffer_seconds),
1, 60, 1, 4)
{
// TODO use ComboOption
vector<string> presets;
/* these must match the order of the enums for BufferingPreset */
presets.push_back (_("Small sessions (4-16 tracks)"));
presets.push_back (_("Medium sessions (16-64 tracks)"));
presets.push_back (_("Large sessions (64+ tracks)"));
presets.push_back (_("Custom (set by sliders below)"));
set_popdown_strings (_buffering_presets_combo, presets);
_buffering_presets_combo.signal_changed().connect (sigc::mem_fun (*this, &BufferingOptions::preset_changed));
_label.set_name ("OptionsLabel");
_label.set_alignment (0, 0.5);
}
void
add_to_page (OptionEditorPage* p)
{
add_widgets_to_page (p, &_label, &_buffering_presets_combo);
_playback.add_to_page (p);
_capture.add_to_page (p);
}
void parameter_changed (string const & p)
{
if (p == "buffering-preset") {
switch (_rc_config->get_buffering_preset()) {
case Small:
_playback.set_sensitive (false);
_capture.set_sensitive (false);
_buffering_presets_combo.set_active (0);
break;
case Medium:
_playback.set_sensitive (false);
_capture.set_sensitive (false);
_buffering_presets_combo.set_active (1);
break;
case Large:
_playback.set_sensitive (false);
_capture.set_sensitive (false);
_buffering_presets_combo.set_active (2);
break;
case Custom:
_playback.set_sensitive (true);
_capture.set_sensitive (true);
_buffering_presets_combo.set_active (3);
break;
}
}
_playback.parameter_changed (p);
_capture.parameter_changed (p);
}
void set_state_from_config ()
{
parameter_changed ("buffering-preset");
_playback.set_state_from_config();
_capture.set_state_from_config();
}
Gtk::Widget& tip_widget() { return _buffering_presets_combo; }
private:
void preset_changed ()
{
int index = _buffering_presets_combo.get_active_row_number ();
if (index < 0) {
return;
}
switch (index) {
case 0:
_rc_config->set_buffering_preset (Small);
break;
case 1:
_rc_config->set_buffering_preset (Medium);
break;
case 2:
_rc_config->set_buffering_preset (Large);
break;
case 3:
_rc_config->set_buffering_preset (Custom);
break;
default:
error << string_compose (_("programming error: unknown buffering preset string, index = %1"), index) << endmsg;
break;
}
}
RCConfiguration* _rc_config;
Label _label;
HSliderOption _playback;
HSliderOption _capture;
ComboBoxText _buffering_presets_combo;
};
class PortSelectOption : public OptionEditorComponent, public sigc::trackable {
public:
PortSelectOption (RCConfiguration* c, SessionHandlePtr* shp, std::string const & tooltip, std::string const & parameter_name, std::string const & label, DataType dt, PortFlags pf)
: _rc_config (c)
, _shp (shp)
, _label (label)
, _ignore_change (false)
, data_type (dt)
, port_flags (pf)
{
_store = ListStore::create (_port_columns);
_combo.set_model (_store);
_combo.pack_start (_port_columns.short_name);
set_tooltip (_combo, tooltip);
_combo.signal_map ().connect (sigc::mem_fun (*this, &PortSelectOption::on_map));
_combo.signal_unmap ().connect (sigc::mem_fun (*this, &PortSelectOption::on_unmap));
_combo.signal_changed ().connect (sigc::mem_fun (*this, &PortSelectOption::port_changed));
}
void add_to_page (OptionEditorPage* p)
{
add_widgets_to_page (p, &_label, &_combo);
}
Gtk::Widget& tip_widget()
{
return _combo;
}
void parameter_changed (string const & p)
{
if (p == parameter_name) {
update_selection ();
}
}
void set_state_from_config ()
{
parameter_changed (parameter_name);
}
protected:
struct PortColumns : public Gtk::TreeModel::ColumnRecord {
PortColumns() {
add (short_name);
add (full_name);
}
Gtk::TreeModelColumn<std::string> short_name;
Gtk::TreeModelColumn<std::string> full_name;
};
RCConfiguration* _rc_config;
SessionHandlePtr* _shp;
Label _label;
Gtk::ComboBox _combo;
bool _ignore_change;
std::string parameter_name;
ARDOUR::DataType data_type;
ARDOUR::PortFlags port_flags;
PortColumns _port_columns;
Glib::RefPtr<Gtk::ListStore> _store;
PBD::ScopedConnectionList _engine_connection;
void on_map ()
{
AudioEngine::instance()->PortRegisteredOrUnregistered.connect (
_engine_connection,
invalidator (*this),
std::bind (&PortSelectOption::update_port_combo, this),
gui_context());
AudioEngine::instance()->PortPrettyNameChanged.connect (
_engine_connection,
invalidator (*this),
std::bind (&PortSelectOption::update_port_combo, this),
gui_context());
}
void on_unmap ()
{
_engine_connection.drop_connections ();
}
void update_port_combo ()
{
vector<string> ports;
ARDOUR::AudioEngine::instance()->get_ports ("", data_type, port_flags, ports);
PBD::Unwinder<bool> uw (_ignore_change, true);
_store->clear ();
TreeModel::Row row;
row = *_store->append ();
row[_port_columns.full_name] = string();
row[_port_columns.short_name] = _("Disconnected");
for (vector<string>::const_iterator p = ports.begin(); p != ports.end(); ++p) {
row = *_store->append ();
row[_port_columns.full_name] = *p;
std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*p);
if (pn.empty ()) {
pn = (*p).substr ((*p).find (':') + 1);
}
row[_port_columns.short_name] = pn;
}
update_selection ();
}
virtual void update_selection() = 0;
virtual void port_changed () = 0;
};
class LTCPortSelectOption : public PortSelectOption
{
public:
LTCPortSelectOption (RCConfiguration* c, SessionHandlePtr* shp)
: PortSelectOption (c, shp,
_("The LTC generator output will be auto-connected to this port when a session is loaded."),
X_("ltc-output-port"),
_("LTC Output Port:"),
ARDOUR::DataType::AUDIO,
ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsTerminal)) {
/* cannot call from parent due to the method being pure virtual */
update_port_combo ();
}
void port_changed ()
{
if (_ignore_change) {
return;
}
TreeModel::iterator active = _combo.get_active ();
string new_port = (*active)[_port_columns.full_name];
_rc_config->set_ltc_output_port (new_port);
if (!_shp->session()) {
return;
}
std::shared_ptr<Port> ltc_port = _shp->session()->ltc_output_port ();
if (!ltc_port) {
return;
}
if (ltc_port->connected_to (new_port)) {
return;
}
ltc_port->disconnect_all ();
if (!new_port.empty()) {
ltc_port->connect (new_port);
}
}
void update_selection ()
{
int n;
Gtk::TreeModel::Children children = _store->children();
Gtk::TreeModel::Children::iterator i = children.begin();
++i; /* skip "Disconnected" */
std::string const& pn = _rc_config->get_ltc_output_port ();
std::shared_ptr<Port> ltc_port;
if (_shp->session()) {
ltc_port = _shp->session()->ltc_output_port ();
}
PBD::Unwinder<bool> uw (_ignore_change, true);
/* try match preference with available port-names */
for (n = 1; i != children.end(); ++i, ++n) {
string port_name = (*i)[_port_columns.full_name];
if (port_name == pn) {
_combo.set_active (n);
return;
}
}
/* Set preference to current port connection
* (LTC is auto-connected at session load).
*/
if (ltc_port) {
i = children.begin();
++i; /* skip "Disconnected" */
for (n = 1; i != children.end(); ++i, ++n) {
string port_name = (*i)[_port_columns.full_name];
if (ltc_port->connected_to (port_name)) {
_combo.set_active (n);
return;
}
}
}
if (pn.empty ()) {
_combo.set_active (0); /* disconnected */
} else {
/* The port is currently not available, retain preference */
TreeModel::Row row = *_store->append ();
row[_port_columns.full_name] = pn;
row[_port_columns.short_name] = (pn).substr ((pn).find (':') + 1);
_combo.set_active (n);
}
}
};
class ControlSurfacesOptions : public OptionEditorMiniPage
{
public:
ControlSurfacesOptions ()
: _ignore_view_change (0)
{
_store = ListStore::create (_model);
_view.set_model (_store);
_view.append_column_editable (_("Enable"), _model.enabled);
_view.append_column (_("Control Surface Protocol"), _model.name);
_view.get_column(1)->set_resizable (true);
_view.get_column(1)->set_expand (true);
Gtk::HBox* edit_box = manage (new Gtk::HBox);
edit_box->set_spacing(3);
edit_box->show ();
Label* label = manage (new Label);
label->set_text (_("Edit the settings for selected protocol (it must be ENABLED first):"));
edit_box->pack_start (*label, false, false);
label->show ();
edit_button = manage (new Button(_("Show Protocol Settings")));
edit_button->signal_clicked().connect (sigc::mem_fun(*this, &ControlSurfacesOptions::edit_btn_clicked));
edit_box->pack_start (*edit_button, true, true);
edit_button->set_sensitive (false);
edit_button->show ();
int const n = table.property_n_rows();
table.resize (n + 2, 3);
table.attach (_view, 0, 3, n, n + 1);
table.attach (*edit_box, 0, 3, n + 1, n + 2);
ControlProtocolManager& m = ControlProtocolManager::instance ();
m.ProtocolStatusChange.connect (protocol_status_connection, MISSING_INVALIDATOR,
std::bind (&ControlSurfacesOptions::protocol_status_changed, this, _1), gui_context());
_store->signal_row_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::view_changed));
_view.signal_button_press_event().connect_notify (sigc::mem_fun(*this, &ControlSurfacesOptions::edit_clicked));
_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::selection_changed));
}
void parameter_changed (std::string const &)
{
}
void set_state_from_config ()
{
_store->clear ();
ControlProtocolManager& m = ControlProtocolManager::instance ();
for (auto const& i : m.control_protocol_info) {
TreeModel::Row r = *_store->append ();
r[_model.name] = i->name;
r[_model.enabled] = 0 != i->protocol;
r[_model.protocol_info] = i;
}
}
private:
void protocol_status_changed (ControlProtocolInfo* cpi) {
/* find the row */
TreeModel::Children rows = _store->children();
for (TreeModel::Children::iterator x = rows.begin(); x != rows.end(); ++x) {
string n = ((*x)[_model.name]);
if ((*x)[_model.protocol_info] == cpi) {
_ignore_view_change++;
(*x)[_model.enabled] = 0 != cpi->protocol;
_ignore_view_change--;
selection_changed (); // update sensitivity
break;
}
}
}
void selection_changed ()
{
//enable the Edit button when a row is selected for editing
TreeModel::Row row = *(_view.get_selection()->get_selected());
if (row && row[_model.enabled]) {
ControlProtocolInfo* cpi = row[_model.protocol_info];
edit_button->set_sensitive (cpi && cpi->protocol && cpi->protocol->has_editor ());
} else {
edit_button->set_sensitive (false);
}
}
void view_changed (TreeModel::Path const &, TreeModel::iterator const & i)
{
TreeModel::Row r = *i;
if (_ignore_view_change) {
return;
}
ControlProtocolInfo* cpi = r[_model.protocol_info];
if (!cpi) {
return;
}
bool const was_enabled = (cpi->protocol != 0);
bool const is_enabled = r[_model.enabled];
if (was_enabled != is_enabled) {
if (!was_enabled) {
ControlProtocolManager::instance().activate (*cpi);
} else {
ControlProtocolManager::instance().deactivate (*cpi);
}
}
selection_changed ();
}
void edit_btn_clicked ()
{
std::string name;
ControlProtocolInfo* cpi;
TreeModel::Row row;
row = *(_view.get_selection()->get_selected());
if (!row[_model.enabled]) {
return;
}
cpi = row[_model.protocol_info];
if (!cpi || !cpi->protocol || !cpi->protocol->has_editor ()) {
return;
}
Box* box = (Box*) cpi->protocol->get_gui ();
if (!box) {
return;
}
if (box->get_parent()) {
static_cast<ArdourWindow*>(box->get_parent())->present();
return;
}
WindowTitle title (Glib::get_application_name());
title += row[_model.name];
title += _("Configuration");
/* once created, the window is managed by the surface itself (as ->get_parent())
* Surface's tear_down_gui() is called on session close, when de-activating
* or re-initializing a surface.
* tear_down_gui() hides an deletes the Window if it exists.
*/
ArdourWindow* win = new ArdourWindow (*((Gtk::Window*) _view.get_toplevel()), title.get_string());
win->set_title (_("Control Protocol Settings"));
win->add (*box);
box->show ();
win->present ();
}
void edit_clicked (GdkEventButton* ev)
{
if (ev->type != GDK_2BUTTON_PRESS) {
return;
}
edit_btn_clicked();
}
class ControlSurfacesModelColumns : public TreeModelColumnRecord
{
public:
ControlSurfacesModelColumns ()
{
add (name);
add (enabled);
add (protocol_info);
}
TreeModelColumn<string> name;
TreeModelColumn<bool> enabled;
TreeModelColumn<ControlProtocolInfo*> protocol_info;
};
Glib::RefPtr<ListStore> _store;
ControlSurfacesModelColumns _model;
TreeView _view;
PBD::ScopedConnection protocol_status_connection;
uint32_t _ignore_view_change;
Gtk::Button* edit_button;
};
class ColumVisibilityOption : public Option
{
public:
ColumVisibilityOption (string id, string name, uint32_t n_col, sigc::slot<uint32_t> get, sigc::slot<bool, uint32_t> set)
: Option (id, name)
, _heading (name)
, _n_col (n_col)
, _get (get)
, _set (set)
{
cb = (CheckButton**) malloc (sizeof (CheckButton*) * n_col);
for (uint32_t i = 0; i < n_col; ++i) {
CheckButton* col = manage (new CheckButton (string_compose (_("Column %1 (Actions %2 + %3)"), i + 1, i * 2 + 1, i * 2 + 2)));
col->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &ColumVisibilityOption::column_toggled), i));
_vbox.pack_start (*col);
cb[i] = col;
}
parameter_changed (id);
}
~ColumVisibilityOption () {
free (cb);
}
Gtk::Widget& tip_widget() { return _vbox; }
void set_state_from_config ()
{
uint32_t c = _get();
for (uint32_t i = 0; i < _n_col; ++i) {
bool en = (c & (1<<i)) ? true : false;
if (cb[i]->get_active () != en) {
cb[i]->set_active (en);
}
}
}
void add_to_page (OptionEditorPage* p)
{
_heading.add_to_page (p);
add_widget_to_page (p, &_vbox);
}
private:
void column_toggled (int b) {
uint32_t c = _get();
uint32_t cc = c;
if (cb[b]->get_active ()) {
c |= (1<<b);
} else {
c &= ~(1<<b);
}
if (cc != c) {
_set (c);
}
}
VBox _vbox;
OptionEditorHeading _heading;
CheckButton** cb;
uint32_t _n_col;
sigc::slot<uint32_t> _get;
sigc::slot<bool, uint32_t> _set;
};
RCOptionEditor::RCOptionEditor ()
: OptionEditorWindow (Config, _("Preferences"))
, _rc_config (Config)
, _mixer_strip_visibility ("mixer-element-visibility")
, _cairo_image_surface (0)
, audiomidi_tab_button (_("Audio\nSystem\nSettings"))
, midi_tab_button (_("MIDI\nSystem\nSettings"))
, session_tab_button (_("Session\nSettings"))
, preferences_tab_button (_("Preferences"))
, sync_tab_button (_("Sync"))
{
UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RCOptionEditor::parameter_changed));
BoolOption* bo;
button_box().pack_start (audiomidi_tab_button, true, true);
button_box().pack_start (midi_tab_button, true, true);
button_box().pack_start (session_tab_button, true, true);
button_box().pack_start (preferences_tab_button, true, true);
button_box().pack_start (sync_tab_button, true, true);
button_box().set_homogeneous (true);
button_box().show_all ();
/* These bindings all use the page title, which is the full first (string argument) to ::add_option() */
audiomidi_tab_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &OptionEditor::set_current_page), _("General")));
midi_tab_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &OptionEditor::set_current_page), _("MIDI")));
preferences_tab_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &OptionEditor::set_current_page), _("General")));
sync_tab_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &OptionEditor::set_current_page), _("Transport")));
/* GENERAL *****************************************************************/
add_option (_("General"), new OptionEditorHeading (_("Audio/MIDI Setup")));
add_option (_("General"),
new RcActionButton (_("Show Audio/MIDI Setup Window"),
sigc::mem_fun (*this, &RCOptionEditor::show_audio_setup)));
bo = new BoolOption (
"try-autostart-engine",
_("Try to auto-launch audio/midi engine"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_try_autostart_engine),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_try_autostart_engine)
);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
_("When opening an existing session, if the most recent audio engine is available and can open the session's sample rate, the audio engine dialog may be skipped."));
add_option (_("General"), bo );
#if 0
/* "preferred-time-domain"
unlike other preferences, this variable would not actually 'change' anything; the session's domain is stored in session-config
so we don't show the rc-config value here. instead, it is invisibly stored in the rc-config, with the user's most recent selection */
#endif
add_option (_("General"), new OptionEditorHeading (S_("Options|Editor Undo")));
add_option (_("General"), new UndoOptions (_rc_config));
add_option (_("General"),
new BoolOption (
"verify-remove-last-capture",
_("Verify removal of last capture"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_verify_remove_last_capture),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_verify_remove_last_capture)
));
add_option (_("General"), new OptionEditorHeading (_("Session Management")));
add_option (_("General"),
new BoolOption (
"periodic-safety-backups",
_("Make periodic backups of the session file"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_periodic_safety_backups),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups)
));
add_option (_("General"), new DirectoryOption (
X_("default-session-parent-dir"),
_("Default folder for new sessions:"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_session_parent_dir),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_session_parent_dir)
));
add_option (_("General"),
new SpinOption<uint32_t> (
"max-recent-sessions",
_("Maximum number of recent sessions"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_max_recent_sessions),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_max_recent_sessions),
0, 1000, 1, 20
));
add_option (_("General"), new OptionEditorHeading (_("Import")));
add_option (_("General"),
new BoolOption (
"only-copy-imported-files",
_("Drag and drop import always copies files to session"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_only_copy_imported_files),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_only_copy_imported_files)
));
add_option (_("General"),
new DirectoryOption (
X_("freesound-dir"),
_("Cache Folder for downloaded Freesound clips:"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_freesound_dir),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_freesound_dir)
));
add_option (_("General"), new OptionEditorHeading (_("Export")));
add_option (_("General"),
new BoolOption (
"save-export-analysis-image",
_("Save loudness analysis as image file after export"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_save_export_analysis_image),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_save_export_analysis_image)
));
#if defined PHONE_HOME && !defined MIXBUS
add_option (_("General"), new OptionEditorHeading (_("New Version Check")));
bo = new BoolOption (
"check-announcements",
_("Check for announcements at application start"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_check_announcements),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_check_announcements)
);
bo ->set_note (string_compose (_("An anonymous request is performed to query announcements by contacting\n%1"), Config->get_pingback_url ()));
add_option (_("General"), bo);
#endif
/* APPEARANCE ***************************************************************/
if (!ARDOUR::Profile->get_mixbus()) {
add_option (_("Appearance"), new OptionEditorHeading (_("GUI Lock")));
/* Lock GUI timeout */
HSliderOption *slts = new HSliderOption("lock-gui-after-seconds",
_("Lock timeout (seconds)"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_lock_gui_after_seconds),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_lock_gui_after_seconds),
0, 1000, 1, 10
);
slts->scale().set_digits (0);
Gtkmm2ext::UI::instance()->set_tip (
slts->tip_widget(),
_("Lock GUI after this many idle seconds (zero to never lock)"));
add_option (_("Appearance"), slts);
ComboOption<ScreenSaverMode>* scsvr = new ComboOption<ScreenSaverMode> (
"screen-saver-mode",
_("System Screensaver Mode"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_screen_saver_mode),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_screen_saver_mode)
);
scsvr->add (InhibitNever, _("Never Inhibit"));
scsvr->add (InhibitWhileRecording, _("Inhibit while Recording"));
scsvr->add (InhibitAlways, string_compose (_("Inhibit while %1 is running"), PROGRAM_NAME));
add_option (_("Appearance"), scsvr);
} // !mixbus
add_option (_("Appearance"), new OptionEditorHeading (_("Theme")));
add_option (_("Appearance"), new BoolOption (
"meter-style-led",
_("LED meter style"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_style_led),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_style_led)
));
add_option (_("Appearance"), new OptionEditorHeading (_("Graphical User Interface")));
add_option (_("Appearance"),
new BoolOption (
"widget-prelight",
_("Highlight widgets on mouseover"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_widget_prelight),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_widget_prelight)
));
add_option (_("Appearance"),
new BoolOption (
"use-tooltips",
_("Show tooltips if mouse hovers over a control"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_tooltips),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_tooltips)
));
bo = new BoolOption (
"super-rapid-clock-update",
_("Update clocks at TC Frame rate"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_super_rapid_clock_update),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_super_rapid_clock_update)
);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
_("<b>When enabled</b> clock displays are updated every Timecode Frame (fps).\n\n"
"<b>When disabled</b> clock displays are updated only every 100ms."
));
add_option (_("Appearance"), bo);
add_option (_("Appearance"),
new BoolOption (
"blink-rec-arm",
_("Blink Rec-Arm buttons"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_blink_rec_arm),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_blink_rec_arm)
));
add_option (_("Appearance"),
new BoolOption (
"blink-alert-indicators",
_("Blink Alert Indicators"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_blink_alert_indicators),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_blink_alert_indicators)
));
BoolOption* strobe = new BoolOption (
"no-strobe",
_("Avoid strobing/blinking/flashing elements"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_no_strobe),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_no_strobe)
);
Gtkmm2ext::UI::instance()->set_tip (strobe->tip_widget(), _("If enabled, disables meters in editor &amp; mixer, running clock updates and most blinking."));
add_option (_("Appearance"), strobe);
add_option (_("Appearance/Recorder"), new OptionEditorHeading (_("Input Meter Layout")));
ComboOption<InputMeterLayout>* iml = new ComboOption<InputMeterLayout> (
"input-meter-layout",
_("Input Meter Layout"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_input_meter_layout),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_input_meter_layout)
);
iml->add (LayoutAutomatic, _("Automatic"));
iml->add (LayoutHorizontal, _("Horizontal"));
iml->add (LayoutVertical, _("Vertical"));
add_option (S_("Appearance/Recorder"), iml);
add_option (_("Appearance/Editor"), new OptionEditorHeading (_("General")));
add_option (_("Appearance/Editor"),
new BoolOption (
"color-regions-using-track-color",
_("Region color follows track color"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_color_regions_using_track_color),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_color_regions_using_track_color)
));
add_option (_("Appearance/Editor"),
new BoolOption (
"show-region-names",
_("Show Region Names"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_region_name),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_region_name)
));
ComboOption<int>* emode = new ComboOption<int> (
"time-axis-name-ellipsize-mode",
_("Track name ellipsize mode"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_time_axis_name_ellipsize_mode),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_time_axis_name_ellipsize_mode)
);
emode->add (-1, _("Ellipsize start of name"));
emode->add (0, _("Ellipsize middle of name"));
emode->add (1, _("Ellipsize end of name"));
Gtkmm2ext::UI::instance()->set_tip (emode->tip_widget(), _("Choose which part of long track names are hidden in the editor's track headers"));
add_option (_("Appearance/Editor"), emode);
add_option (_("Appearance/Editor"), new OptionEditorHeading (_("Editor Meters")));
add_option (_("Appearance/Editor"),
new BoolOption (
"show-track-meters",
_("Show meters in track headers"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_track_meters),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_track_meters)
));
add_option (_("Appearance/Editor"), new OptionEditorBlank ());
add_option (_("Appearance/Waveform"), new OptionEditorHeading (_("Editor Waveforms")));
if (!Profile->get_mixbus()) {
add_option (_("Appearance/Waveform"),
new BoolOption (
"show-waveforms",
_("Show waveforms in regions"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms)
));
} // !mixbus
add_option (_("Appearance/Waveform"),
new BoolOption (
"show-waveforms-while-recording",
_("Show waveforms while recording"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms_while_recording),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms_while_recording)
));
add_option (_("Appearance/Waveform"),
new BoolOption (
"show-waveform-clipping",
_("Show waveform clipping"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveform_clipping),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveform_clipping)
));
add_option (_("Appearance/Waveform"), new ClipLevelOptions ());
ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
"waveform-scale",
_("Waveform scale"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_scale),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_scale)
);
wfs->add (Linear, _("linear"));
wfs->add (Logarithmic, _("logarithmic"));
add_option (_("Appearance/Waveform"), wfs);
ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
"waveform-shape",
_("Waveform shape"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_shape),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_shape)
);
wfsh->add (Traditional, _("traditional"));
wfsh->add (Rectified, _("rectified"));
add_option (_("Appearance/Waveform"), wfsh);
add_option (_("Appearance/Waveform"), new OptionEditorBlank ());
#ifndef MIXBUS
add_option (_("Appearance/Mixer"),
new BoolOption (
"default-narrow_ms",
_("Use narrow strips in the mixer for new strips by default"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_default_narrow_ms),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_default_narrow_ms)
));
#endif
add_option (_("Appearance/Mixer"), new OptionEditorBlank ());
add_option (_("Appearance/Toolbar"), new OptionEditorHeading (_("Main Transport Toolbar Items")));
add_option (_("Appearance/Toolbar"), new OptionEditorBlank ());
/* size and scale */
#if (!defined __APPLE__ || defined MIXBUS)
add_option (_("Appearance/Size and Scale"), new OptionEditorHeading (_("User Interface Size and Scale")));
#endif
#ifndef __APPLE__
/* font scaling does nothing with GDK/Quartz */
add_option (_("Appearance/Size and Scale"), new FontScalingOptions ());
#endif
add_option (_("Appearance/Colors"), new OptionEditorHeading (_("Colors")));
add_option (_("Appearance/Colors"), new ColorThemeManager);
add_option (_("Appearance/Colors"), new OptionEditorBlank ());
/* Quirks */
OptionEditorHeading* quirks_head = new OptionEditorHeading (_("Various Workarounds for Windowing Systems"));
quirks_head->set_note (string_compose (_("Rules for closing, minimizing, maximizing, and stay-on-top can vary \
with each version of your OS, and the preferences that you've set in your OS.\n\n\
You can adjust the options, below, to change how application windows and dialogs behave.\n\n\
These settings will only take effect after %1 is restarted.\n\
"), PROGRAM_NAME));
add_option (_("Appearance/Quirks"), quirks_head);
bo = new BoolOption (
"use-wm-visibility",
_("Use visibility information provided by your Window Manager/Desktop"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_wm_visibility),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_wm_visibility)
);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
_("If you have trouble toggling between hidden Editor and Mixer windows, try changing this setting."));
add_option (_("Appearance/Quirks"), bo);
#ifndef __APPLE__
#ifndef PLATFORM_WINDOWS
bo = new BoolOption (
"hide-splash-screen",
_("Show/Hide splash screen instead of setting z-axis stack order"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_hide_splash_screen),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_hide_splash_screen)
);
add_option (_("Appearance/Quirks"), bo);
#endif
bo = new BoolOption (
"all-floating-windows-are-dialogs",
_("All floating windows are dialogs"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_all_floating_windows_are_dialogs),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_all_floating_windows_are_dialogs)
);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
_("Mark all floating windows to be type \"Dialog\" rather than using \"Utility\" for some.\nThis may help with some window managers."));
add_option (_("Appearance/Quirks"), bo);
bo = new BoolOption (
"transients-follow-front",
_("Transient windows follow front window."),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_transients_follow_front),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_transients_follow_front)
);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
_("Make transient windows follow the front window when toggling between the editor and mixer."));
add_option (_("Appearance/Quirks"), bo);
#endif
#if !(defined PLATFORM_WINDOWS || defined __APPLE__)
bo = new BoolOption (
"allow-to-resize-engine-dialog",
_("Allow to resize Engine Dialog"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_allow_to_resize_engine_dialog),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_allow_to_resize_engine_dialog)
);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
_("On some XWayland systems the engine-dialog is blank when shown a second time (from the main menu). Allowing to resize the window works around this oddity."));
add_option (_("Appearance/Quirks"), bo);
#endif
#ifdef __APPLE__
BoolOption* bco = new BoolOption (
"use-cocoa-invalidation",
_("Use macOS to determine GUI redraw areas"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_cocoa_invalidation),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_cocoa_invalidation)
);
Gtkmm2ext::UI::instance()->set_tip (bco->tip_widget(), string_compose (_("When enabled, macOS is in charge of what areas of the GUI are redrawn.\nWhen disabled, %1 manages this by itself"), PROGRAM_NAME));
add_option (_("Appearance/Quirks"), bco);
#endif
add_option (_("Appearance/Quirks"), new OptionEditorBlank ());
#if (!defined USE_CAIRO_IMAGE_SURFACE || defined CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE || defined __APPLE__)
add_option (_("Appearance"), new OptionEditorHeading (_("Graphics Acceleration")));
#endif
#ifdef __APPLE__
ComboOption<AppleNSGLViewMode>* glmode = new ComboOption<AppleNSGLViewMode> (
"nsgl-view-mode",
_("Render Canvas on openGL texture (requires restart)"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_nsgl_view_mode),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_nsgl_view_mode)
);
glmode->add (NSGLHiRes, _("Yes, with Retina scaling"));
glmode->add (NSGLLoRes, _("Yes, low resolution"));
glmode->add (NSGLDisable, _("No"));
Gtkmm2ext::UI::instance()->set_tip (glmode->tip_widget(), string_compose (
_("Render editor canvas, on a openGL texture which may improve graphics performance.\nThis requires restarting %1 before having an effect"), PROGRAM_NAME));
add_option (_("Appearance"), glmode);
#endif
#ifndef USE_CAIRO_IMAGE_SURFACE
_cairo_image_surface = new BoolOption (
"cairo-image-surface",
_("Use intermediate image-surface to render canvas (requires restart)"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_cairo_image_surface),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_cairo_image_surface)
);
Gtkmm2ext::UI::instance()->set_tip (_cairo_image_surface->tip_widget(), string_compose (
_("Render large parts of the application user-interface in software, instead of using 2D-graphics acceleration.\nThis requires restarting %1 before having an effect"), PROGRAM_NAME));
add_option (_("Appearance"), _cairo_image_surface);
#endif
#ifdef CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE
BoolOption* bgo = new BoolOption (
"buggy-gradients",
_("Possibly improve slow graphical performance (requires restart)"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_buggy_gradients),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_buggy_gradients)
);
Gtkmm2ext::UI::instance()->set_tip (bgo->tip_widget(), string_compose (_("Disables hardware gradient rendering on buggy video drivers (\"buggy gradients patch\").\nThis requires restarting %1 before having an effect"), PROGRAM_NAME));
add_option (_("Appearance"), bgo);
#endif
#if ENABLE_NLS
add_option (_("Appearance/Translation"), new OptionEditorHeading (_("Internationalization")));
bo = new BoolOption (
"enable-translation",
_("Use translations"),
sigc::ptr_fun (ARDOUR::translations_are_enabled),
sigc::ptr_fun (ARDOUR::set_translations_enabled)
);
bo->set_note (string_compose (_("These settings will only take effect after %1 is restarted (if available for your language preferences)."), PROGRAM_NAME));
add_option (_("Appearance/Translation"), bo);
parameter_changed ("enable-translation");
#endif // ENABLE_NLS
/* EDITOR *******************************************************************/
// XXX Long label, pushes other ComboBoxes to the right
ComboOption<float>* eet = new ComboOption<float> (
"extra-ui-extents-time",
_("Limit zoom & summary view beyond session extents to"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_extra_ui_extents_time),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_extra_ui_extents_time)
);
eet->add (1, _("1 minute"));
eet->add (2, _("2 minutes"));
eet->add (20, _("20 minutes"));
eet->add (60, _("1 hour"));
eet->add (60*2, _("2 hours"));
eet->add (60*24, _("24 hours"));
add_option (_("Editor"), eet);
add_option (_("Editor"), new OptionEditorHeading (_("Editor Behavior")));
add_option (_("Editor"), new OptionEditorHeading (_("Split/Separate")));
ComboOption<RangeSelectionAfterSplit> *rras = new ComboOption<RangeSelectionAfterSplit> (
"range-selection-after-separate",
_("After a Separate operation, in Range mode"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_range_selection_after_split),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_range_selection_after_split));
rras->add(ClearSel, _("Clear the Range Selection"));
rras->add(PreserveSel, _("Preserve the Range Selection"));
rras->add(ForceSel, _("Select the regions under the range."));
add_option (_("Editor"), rras);
#if 1 // XXX very wide ComboBox
ComboOption<RegionSelectionAfterSplit> *rsas = new ComboOption<RegionSelectionAfterSplit> (
"region-selection-after-split",
_("After a Split operation, in Object mode"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_selection_after_split),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_selection_after_split));
// TODO: decide which of these modes are really useful
rsas->add (None, _("Clear the Region Selection"));
rsas->add (NewlyCreatedLeft, _("Select the newly-created regions BEFORE the split point"));
rsas->add (NewlyCreatedRight, _("Select only the newly-created regions AFTER the split point"));
rsas->add (NewlyCreatedBoth, _("Select the newly-created regions"));
#if 0
rsas->add(Existing, _("unmodified regions in the existing selection"));
rsas->add(ExistingNewlyCreatedLeft, _("existing selection and newly-created regions before the split"));
rsas->add(ExistingNewlyCreatedRight, _("existing selection and newly-created regions after the split"));
#endif
rsas->add(ExistingNewlyCreatedBoth, _("Preserve existing selection, and select newly-created regions"));
add_option (_("Editor"), rsas);
#endif
/* TRANSPORT & SYNC *********************************************************/
add_option (_("Transport"), new OptionEditorHeading (_("General")));
bo = new BoolOption (
"name-new-markers",
_("Prompt for new marker names"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_name_new_markers),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_name_new_markers)
);
add_option (_("Transport"), bo);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(), _("<b>When enabled</b>, popup a dialog when a new marker is created to allow its name to be set as it is created."
"\n\nYou can always rename markers by right-clicking on them."));
bo = new BoolOption (
"stop-at-session-end",
_("Stop at the end of the session"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
string_compose (_("<b>When enabled</b> if %1 is <b>not recording</b>, and <b>all trigger-slots are unused</b> "
"the transport is stopped when it reaches the current session end marker\n\n"
"<b>When disabled</b> %1 will continue to roll past the session end marker at all times"),
PROGRAM_NAME));
add_option (_("Transport"), bo);
bo = new BoolOption (
"latched-record-enable",
_("Keep record-enable engaged on stop"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
);
add_option (_("Transport"), bo);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
_("<b>When enabled</b> master record will remain engaged when the transport transitions to stop.\n<b>When disabled</b> master record will be disabled when the transport transitions to stop."));
bo = new BoolOption (
"disable-disarm-during-roll",
_("Disable per-track record disarm while rolling"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_disable_disarm_during_roll),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_disable_disarm_during_roll)
);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(), _("<b>When enabled</b> this will prevent you from accidentally stopping specific tracks recording during a take."));
add_option (_("Transport"), bo);
bo = new BoolOption (
"mark-at-pgm-change",
_("Create a marker when a MIDI program change is received (and RECORDING)"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_mark_at_pgm_change),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_mark_at_pgm_change)
);
add_option (_("Transport"), bo);
bo = new BoolOption (
"locate-to-pgm-change",
_("Locate to the next matching scene marker when a MIDI program change is received (and NOT recording)"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_locate_to_pgm_change),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_locate_to_pgm_change)
);
add_option (_("Transport"), bo);
add_option (_("Transport"), new OptionEditorHeading (_("Looping")));
bo = new BoolOption (
"loop-is-mode",
_("Play loop is a transport mode"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_is_mode),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_is_mode)
);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
(_("<b>When enabled</b> the loop button does not start playback but forces playback to always play the loop\n\n"
"<b>When disabled</b> the loop button starts playing the loop, but stop then cancels loop playback")));
add_option (_("Transport"), bo);
ComboOption<LoopFadeChoice>* lca = new ComboOption<LoopFadeChoice> (
"loop-fade-choice",
_("Loop Fades"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_fade_choice),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_fade_choice)
);
lca->add (NoLoopFade, _("No fades at loop boundaries"));
lca->add (EndLoopFade, _("Fade out at loop end"));
lca->add (BothLoopFade, _("Fade in at loop start & Fade out at loop end"));
lca->add (XFadeLoop, _("Cross-fade loop end and start"));
add_option (_("Transport"), lca);
Gtkmm2ext::UI::instance()->set_tip (lca->tip_widget(), _("Options for fades/crossfades at loop boundaries"));
add_option (_("Transport"), new OptionEditorHeading (_("Dropout (xrun) Handling")));
bo = new BoolOption (
"stop-recording-on-xrun",
_("Stop recording when an xrun occurs"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
string_compose (_("<b>When enabled</b> %1 will stop recording if an over- or underrun is detected by the audio engine"),
PROGRAM_NAME));
add_option (_("Transport"), bo);
bo = new BoolOption (
"create-xrun-marker",
_("Create markers where xruns occur"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
);
add_option (_("Transport"), bo);
bo = new BoolOption (
"recording-resets-xrun-count",
_("Reset xrun counter when starting to record"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_recording_resets_xrun_count),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_recording_resets_xrun_count)
);
add_option (_("Transport"), bo);
add_option (_("Transport/Chase"), new OptionEditorHeading (_("MIDI Machine Control (MMC)")));
add_option (_("Transport/Chase"),
new BoolOption (
"mmc-control",
_("Respond to MMC commands"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_control),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control)
));
add_option (_("Transport/Chase"),
new SpinOption<uint8_t> (
"mmc-receive-device-id",
_("Inbound MMC device ID"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
0, 127, 1, 10
));
add_option (_("Transport/Chase"), new OptionEditorHeading (_("Transport Masters")));
add_option (_("Transport/Chase"),
new RcActionButton (_("Show Transport Masters Window"),
sigc::mem_fun (*this, &RCOptionEditor::show_transport_masters)));
_sync_framerate = new BoolOption (
"timecode-sync-frame-rate",
_("Match session video frame rate to external timecode"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_sync_frame_rate),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_sync_frame_rate)
);
Gtkmm2ext::UI::instance()->set_tip
(_sync_framerate->tip_widget(),
string_compose (_("This option controls the value of the video frame rate <i>while chasing</i> an external timecode source.\n\n"
"<b>When enabled</b> the session video frame rate will be changed to match that of the selected external timecode source.\n\n"
"<b>When disabled</b> the session video frame rate will not be changed to match that of the selected external timecode source."
"Instead the frame rate indication in the main clock will flash red and %1 will convert between the external "
"timecode standard and the session standard."), PROGRAM_NAME));
add_option (_("Transport/Chase"), _sync_framerate);
auto mcr = new SpinOption<double> (
"midi-clock-resolution",
_("BPM Resolution for incoming MIDI Clock"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_clock_resolution),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_clock_resolution),
0., 1., 0.01, 0.1, _("quarters"), 1, 2
);
Gtkmm2ext::UI::instance()->set_tip
(mcr->tip_widget(),
_("This option can be used to quantize incoming MIDI clock to whole (or fractions of a) quarter note.\n\n"
"Setting it to zero prevents any quantization, which can result in a rather jittery response to incoming MIDI Clock.\n\n"
"Setting it to 1.0 quantizes to whole (integer) BPM values, and is the default.\n\n"
"If you are using a MIDI clock source that quantizes to some fraction of a quarter note then adjust this setting to reflect that."));
add_option (_("Transport/Chase"), new OptionEditorHeading (_("MIDI Clock")));
add_option (_("Transport/Chase"), mcr);
add_option (_("Transport/Generate"), new OptionEditorHeading (_("Linear Timecode (LTC) Generator")));
add_option (_("Transport/Generate"),
new BoolOption (
"send-ltc",
_("Enable LTC generator"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_ltc),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_ltc)
));
_ltc_send_continuously = new BoolOption (
"ltc-send-continuously",
_("Send LTC while stopped"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_send_continuously),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_send_continuously)
);
Gtkmm2ext::UI::instance()->set_tip
(_ltc_send_continuously->tip_widget(),
string_compose (_("<b>When enabled</b> %1 will continue to send LTC information even when the transport (playhead) is not moving"), PROGRAM_NAME));
add_option (_("Transport/Generate"), _ltc_send_continuously);
_ltc_volume_slider = new HSliderOption("ltcvol", _("LTC generator level [dBFS]"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_output_volume),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_output_volume),
-50, 0, .5, 5,
.05, true);
Gtkmm2ext::UI::instance()->set_tip
(_ltc_volume_slider->tip_widget(),
_("Specify the Peak Volume of the generated LTC signal in dBFS. A good value is 0dBu ^= -18dBFS in an EBU calibrated system"));
add_option (_("Transport/Generate"), _ltc_volume_slider);
add_option (_("Transport/Generate"), new LTCPortSelectOption (_rc_config, this));
add_option (_("Transport/Generate"), new OptionEditorHeading (_("MIDI Time Code (MTC) Generator")));
add_option (_("Transport/Generate"),
new BoolOption (
"send-mtc",
_("Enable MTC Generator"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mtc),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc)
));
SpinOption<int>* soi = new SpinOption<int> (
"mtc-qf-speed-tolerance",
_("Max MTC varispeed (%)"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_mtc_qf_speed_tolerance),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_mtc_qf_speed_tolerance),
0, 20, 1, 5
);
Gtkmm2ext::UI::instance()->set_tip (soi->tip_widget(), _("Percentage either side of normal transport speed to transmit MTC."));
add_option (_("Transport/Generate"), soi);
add_option (_("Transport/Generate"), new OptionEditorHeading (_("MIDI Machine Control (MMC)")));
add_option (_("Transport/Generate"),
new BoolOption (
"send-mmc",
_("Send MMC commands"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mmc),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc)
));
add_option (_("Transport/Generate"),
new SpinOption<uint8_t> (
"mmc-send-device-id",
_("Outbound MMC device ID"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
0, 127, 1, 10
));
add_option (_("Transport/Generate"), new OptionEditorHeading (_("MIDI Beat Clock (Mclk) Generator")));
add_option (_("Transport/Generate"),
new BoolOption (
"send-midi-clock",
_("Enable Mclk generator"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_midi_clock),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_midi_clock)
));
add_option (_("Transport"), new OptionEditorHeading (_("Plugins")));
/* MONITORING, SOLO) ********************************************************/
add_option (_("Monitoring"), new OptionEditorHeading (_("Monitoring")));
ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
"monitoring-model",
_("Record monitoring handled by"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
);
if (AudioEngine::instance()->port_engine().can_monitor_input()) {
mm->add (HardwareMonitoring, _("Audio Driver"));
}
string prog (PROGRAM_NAME);
boost::algorithm::to_lower (prog);
mm->add (SoftwareMonitoring, string_compose (_("%1"), prog));
mm->add (ExternalMonitoring, _("Audio Hardware"));
add_option (_("Monitoring"), mm);
bo = new BoolOption (
"auto-input-does-talkback",
_("Auto Input does 'talkback'"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_input_does_talkback),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_input_does_talkback)
);
add_option (_("Monitoring"), bo);
Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
string_compose (_("<b>When enabled</b>, and Transport -> Auto-Input is enabled, %1 will always monitor audio inputs when transport is stopped, even if tracks aren't armed."),
PROGRAM_NAME));
add_option (_("Monitoring"), new OptionEditorHeading (_("Solo")));
_solo_control_is_listen_control = new BoolOption (
"solo-control-is-listen-control",
_("Solo controls are Listen controls"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control)
);
add_option (_("Monitoring"), _solo_control_is_listen_control);
add_option (_("Monitoring"),
new BoolOption (
"exclusive-solo",
_("Exclusive solo"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo)
));
add_option (_("Monitoring"),
new BoolOption (
"show-solo-mutes",
_("Show solo muting"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
));
add_option (_("Monitoring"),
new BoolOption (
"solo-mute-override",
_("Soloing overrides muting"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
));
add_option (_("Monitoring"),
new FaderOption (
"solo-mute-gain",
_("Solo-in-place mute cut (dB)"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_gain),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_gain)
));
/* SIGNAL FLOW **************************************************************/
add_option (_("Signal Flow"), new OptionEditorHeading (_("Master")));
ComboOption<uint32_t>* zitaq = new ComboOption<uint32_t> (
"port-resampler-quality",
_("I/O Resampler (vari-speed) quality"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_port_resampler_quality),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_port_resampler_quality)
);
zitaq->add (0, _("Off (no vari-speed)"));
zitaq->add (9, _("Low (16 samples latency)"));
zitaq->add (17, _("Moderate (32 samples latency), default"));
zitaq->add (33, _("Medium (64 samples latency)"));
zitaq->add (49, _("High (96 samples latency)"));
zitaq->add (65, _("Very High (128 samples latency)"));
zitaq->add (93, _("Extreme (184 samples latency)"));
uint32_t prq_val = _rc_config->get_port_resampler_quality ();
if (!(prq_val == 0 || prq_val == 9 || prq_val == 17 || prq_val == 33 || prq_val == 65 || prq_val == 93)) {
if (prq_val < 8) {
_rc_config->set_port_resampler_quality (8);
prq_val = 8;
}
if (prq_val > 96) {
_rc_config->set_port_resampler_quality (96);
prq_val = 96;
}
zitaq->add (prq_val, string_compose (_("Custom (%1 samples latency)"), prq_val - 1));
}
zitaq->set_note (_("This setting will only take effect when the Audio Engine is restarted."));
set_tooltip (zitaq->tip_widget(), _("To facilitate vari-speed playback/recording, audio is resampled to change pitch and speed. This introduces latency depending on the quality. For consistency this latency is also present when not vari-speeding (even if no resampling happens).\n\nIt is possible to disable this feature, which will also disable vari-speed. - Except if the audio-engine runs at a different sample-rate than the session, the quality is set to be at least 'Very High' (128 samples round-trip latency)"));
add_option (_("Signal Flow"), zitaq);
add_option (_("Signal Flow"), new OptionEditorHeading (_("Default Track / Bus Muting Options")));
add_option (_("Signal Flow"), new OptionEditorHeading (_("Audio Regions")));
/* CONTROL SURFACES *********************************************************/
add_option (_("Control Surfaces"), new OptionEditorHeading (_("Control Surfaces")));
add_option (_("Control Surfaces"), new ControlSurfacesOptions ());
/* METERS *******************************************************************/
if (Profile->get_mixbus()) {
add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Meterbridge meters")));
} else {
add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Metering")));
}
ComboOption<float>* mht = new ComboOption<float> (
"meter-hold",
_("Peak hold time"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_hold),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_hold)
);
mht->add (MeterHoldOff, _("off"));
mht->add (MeterHoldShort, _("short"));
mht->add (MeterHoldMedium, _("medium"));
mht->add (MeterHoldLong, _("long"));
add_option (S_("Preferences|Metering"), mht);
ComboOption<float>* mfo = new ComboOption<float> (
"meter-falloff",
_("DPM fall-off"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
);
mfo->add (METER_FALLOFF_OFF, _("off"));
mfo->add (METER_FALLOFF_SLOWEST, _("slowest [6.6dB/sec]"));
mfo->add (METER_FALLOFF_SLOW, _("slow [8.6dB/sec] (BBC PPM, EBU PPM)"));
mfo->add (METER_FALLOFF_SLOWISH, _("moderate [12.0dB/sec] (DIN)"));
mfo->add (METER_FALLOFF_MODERATE, _("medium [13.3dB/sec] (EBU Digi PPM, IRT Digi PPM)"));
mfo->add (METER_FALLOFF_MEDIUM, _("fast [20dB/sec]"));
mfo->add (METER_FALLOFF_FAST, _("very fast [32dB/sec]"));
add_option (S_("Preferences|Metering"), mfo);
ComboOption<MeterLineUp>* mlu = new ComboOption<MeterLineUp> (
"meter-line-up-level",
_("Meter line-up level; 0dBu"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_level),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_level)
);
mlu->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
mlu->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
mlu->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
mlu->add (MeteringLineUp15, _("-15dBFS (DIN)"));
Gtkmm2ext::UI::instance()->set_tip (mlu->tip_widget(), _("Configure meter-marks and color-knee point for dBFS scale DPM, set reference level for IEC1/Nordic, IEC2 PPM and VU meter."));
add_option (S_("Preferences|Metering"), mlu);
ComboOption<MeterLineUp>* mld = new ComboOption<MeterLineUp> (
"meter-line-up-din",
_("IEC1/DIN Meter line-up level; 0dBu"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_din),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_din)
);
mld->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
mld->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
mld->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
mld->add (MeteringLineUp15, _("-15dBFS (DIN)"));
Gtkmm2ext::UI::instance()->set_tip (mld->tip_widget(), _("Reference level for IEC1/DIN meter."));
add_option (S_("Preferences|Metering"), mld);
ComboOption<VUMeterStandard>* mvu = new ComboOption<VUMeterStandard> (
"meter-vu-standard",
_("VU Meter standard"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_vu_standard),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_vu_standard)
);
mvu->add (MeteringVUfrench, _("0VU = -2dBu (France)"));
mvu->add (MeteringVUamerican, _("0VU = 0dBu (North America, Australia)"));
mvu->add (MeteringVUstandard, _("0VU = +4dBu (standard)"));
mvu->add (MeteringVUeight, _("0VU = +8dBu"));
add_option (S_("Preferences|Metering"), mvu);
HSliderOption *mpks = new HSliderOption("meter-peak",
_("Peak indicator threshold [dBFS]"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_peak),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_peak),
-10, 0, .1, .1
);
Gtkmm2ext::UI::instance()->set_tip (
mpks->tip_widget(),
_("Specify the audio signal level in dBFS at and above which the meter-peak indicator will flash red."));
add_option (S_("Preferences|Metering"), mpks);
OptionEditorHeading* default_meter_head = new OptionEditorHeading (_("Default Meter Types"));
default_meter_head->set_note (_("These settings apply to newly created tracks and busses. For the Master bus, this will be when a new session is created."));
add_option (S_("Preferences|Metering"), default_meter_head);
ComboOption<MeterType>* mtm = new ComboOption<MeterType> (
"meter-type-master",
_("Default Meter Type for Master Bus"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_master),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_master)
);
mtm->add (MeterPeak, ArdourMeter::meter_type_string(MeterPeak));
mtm->add (MeterPeak0dB, ArdourMeter::meter_type_string(MeterPeak0dB));
mtm->add (MeterK20, ArdourMeter::meter_type_string(MeterK20));
mtm->add (MeterK14, ArdourMeter::meter_type_string(MeterK14));
mtm->add (MeterK12, ArdourMeter::meter_type_string(MeterK12));
mtm->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
mtm->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
mtm->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
mtm->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
add_option (S_("Preferences|Metering"), mtm);
ComboOption<MeterType>* mtb = new ComboOption<MeterType> (
"meter-type-bus",
_("Default meter type for busses"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_bus),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_bus)
);
mtb->add (MeterPeak, ArdourMeter::meter_type_string(MeterPeak));
mtb->add (MeterPeak0dB, ArdourMeter::meter_type_string(MeterPeak0dB));
mtb->add (MeterK20, ArdourMeter::meter_type_string(MeterK20));
mtb->add (MeterK14, ArdourMeter::meter_type_string(MeterK14));
mtb->add (MeterK12, ArdourMeter::meter_type_string(MeterK12));
mtb->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
mtb->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
mtb->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
mtb->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
add_option (S_("Preferences|Metering"), mtb);
ComboOption<MeterType>* mtt = new ComboOption<MeterType> (
"meter-type-track",
_("Default meter type for tracks"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_track),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_track)
);
mtt->add (MeterPeak, ArdourMeter::meter_type_string(MeterPeak));
mtt->add (MeterPeak0dB, ArdourMeter::meter_type_string(MeterPeak0dB));
mtt->add (MeterK20, ArdourMeter::meter_type_string(MeterK20));
mtt->add (MeterK14, ArdourMeter::meter_type_string(MeterK14));
mtt->add (MeterK12, ArdourMeter::meter_type_string(MeterK12));
mtt->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
mtt->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
mtt->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
mtt->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
add_option (S_("Preferences|Metering"), mtt);
add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Region Analysis"))); //needs translation
add_option (S_("Preferences|Metering"),
new BoolOption (
"auto-analyse-audio",
_("Enable automatic analysis of audio"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
));
/* PERFORMANCE **************************************************************/
uint32_t hwcpus = hardware_concurrency ();
if (hwcpus > 1) {
add_option (_("Performance"), new OptionEditorHeading (_("DSP CPU Utilization")));
ComboOption<int32_t>* procs = new ComboOption<int32_t> (
"processor-usage",
_("Signal processing uses"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage)
);
procs->add (-1, _("all but one processor"));
procs->add (0, _("all available processors"));
for (uint32_t i = 1; i <= hwcpus; ++i) {
procs->add (i, string_compose (P_("%1 processor", "%1 processors", i), i));
}
procs->set_note (string_compose (_("This setting will only take effect when %1 is restarted."), PROGRAM_NAME));
add_option (_("Performance"), procs);
}
#if !(defined PLATFORM_WINDOWS || defined __APPLE__)
if (Glib::file_test ("/dev/cpu_dma_latency", Glib::FILE_TEST_EXISTS)) {
ComboOption<int32_t>* cpudma = new ComboOption<int32_t> (
"cpu-dma-latency",
_("Power Management, CPU DMA latency"),
sigc::mem_fun (*_rc_config, &RCConfiguration::get_cpu_dma_latency),
sigc::mem_fun (*_rc_config, &RCConfiguration::set_cpu_dma_latency)
);
set<int> lvalues;
vector<string> latency_files;
Searchpath sp ("/sys/devices/system/cpu/cpu0/cpuidle/");
find_files_matching_regex (latency_files, sp, "latency$", true);
for (vector<string>::const_iterator i = latency_files.begin(); i != latency_files.end (); ++i) {
try {
std::string l = Glib::file_get_contents (*i);
int lv = atoi (l.c_str());
if (lv > 0) {
lvalues.insert (lv);
}
} catch (...) { }
}
if (lvalues.empty ()) {
lvalues.insert (5);
lvalues.insert (55);
lvalues.insert (100);
}
int32_t cpudma_val = _rc_config->get_cpu_dma_latency ();
if (cpudma_val > 0) {
lvalues.insert (cpudma_val);
}
cpudma->add (-1, _("Unset"));
cpudma->add (0, _("Lowest (prevent CPU sleep states)"));
for (set<int>::const_iterator i = lvalues.begin(); i != lvalues.end (); ++i) {
cpudma->add (*i, string_compose (_("%1 usec"), *i));
}
set_tooltip (cpudma->tip_widget(), _("This setting sets the maximum tolerable CPU DMA latency. This prevents the CPU from entering power-save states which can be beneficial for reliable low latency."));
if (access ("/dev/cpu_dma_latency", W_OK)) {
cpudma->set_note (_("This setting requires write access to `/dev/cpu_dma_latency'."));
}
add_option (_("Performance"), cpudma);
}
#endif
add_option (_("Performance"), new OptionEditorHeading (_("Disk I/O Buffering"))); //ToDo: this changed, needs translation. disambiguated from soundcard i/o buffering
add_option (_("Performance"), new BufferingOptions (_rc_config));
/* Image cache size */
add_option (_("Performance"), new OptionEditorHeading (_("Memory Usage")));
HSliderOption *sics = new HSliderOption ("waveform-cache-size",
_("Waveform image cache size (megabytes)"),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_cache_size),
sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_cache_size),
1, 1024, 10 /* 1 MB to 1GB in steps of 10MB */
);
sics->scale().set_digits (0);
Gtkmm2ext::UI::instance()->set_tip (
sics->tip_widget(),
_("Increasing the cache size uses more memory to store waveform images, which can improve graphical performance."));
add_option (_("Performance"), sics);
add_option (_("Performance"), new OptionEditorHeading (_("Automation")));
/* END OF SECTIONS/OPTIONS etc */
Widget::show_all ();
//trigger some parameter-changed messages which affect widget-visibility or -sensitivity
parameter_changed ("send-ltc");
parameter_changed ("sync-source");
parameter_changed ("open-gui-after-adding-plugin");
#ifdef __APPLE__
parameter_changed ("use-opengl-view");
#endif
// XMLNode* node = ARDOUR_UI::instance()->preferences_settings();
set_current_page (_("General"));
/* Connect metadata */
for (auto p : pages()) {
for (auto oc : p.second->components) {
Option* o = dynamic_cast<Option*> (oc);
if (o) {
Configuration::Metadata const * m = Configuration::get_metadata (o->id());
if (m) {
oc->set_metadata (*m);
}
}
}
}
}
bool
RCOptionEditor::on_key_release_event (GdkEventKey* event)
{
if (Keyboard::modifier_state_equals (event->state, Keyboard::close_window_modifier)) {
if (event->keyval == (guint) Keyboard::close_window_key) {
hide ();
return true;
}
}
return false;
}
void
RCOptionEditor::set_session (Session *s)
{
ArdourWindow::set_session (s);
_transport_masters_widget.set_session (s);
}
void
RCOptionEditor::parameter_changed (string const & p)
{
OptionEditor::parameter_changed (p);
if (p == "use-monitor-bus") {
bool const s = Config->get_use_monitor_bus ();
if (!s) {
/* we can't use this if we don't have a monitor bus */
Config->set_solo_control_is_listen_control (false); // XXX
}
_solo_control_is_listen_control->set_sensitive (s);
_listen_position->set_sensitive (s);
} else if (p == "sync-source") {
std::shared_ptr<TransportMaster> tm (TransportMasterManager::instance().current());
if (std::dynamic_pointer_cast<TimecodeTransportMaster> (tm)) {
_sync_framerate->set_sensitive (true);
} else {
_sync_framerate->set_sensitive (false);
}
} else if (p == "send-ltc") {
bool const s = Config->get_send_ltc ();
_ltc_send_continuously->set_sensitive (s);
_ltc_volume_slider->set_sensitive (s);
}
}
void RCOptionEditor::reset_clip_library_dir () {
_rc_config->set_clip_library_dir ("@default@");
clip_library_dir (false);
}
void RCOptionEditor::show_audio_setup () {
Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Window", "toggle-audio-midi-setup");
tact->set_active();
}
void RCOptionEditor::show_transport_masters () {
Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Window", "toggle-transport-masters");
tact->set_active();
}
XMLNode&
RCOptionEditor::get_state () const
{
XMLNode* node = new XMLNode (X_("Preferences"));
return *node;
}
std::string
RCOptionEditor::get_default_lower_midi_note ()
{
return ParameterDescriptor::midi_note_name (UIConfiguration::instance().get_default_lower_midi_note());
}
bool
RCOptionEditor::set_default_lower_midi_note (std::string str)
{
int note = ParameterDescriptor::midi_note_num (str);
if (note < 0) {
mru_option->set_state_from_config ();
return false;
}
return UIConfiguration::instance().set_default_lower_midi_note (note);
}
std::string
RCOptionEditor::get_default_upper_midi_note ()
{
return ParameterDescriptor::midi_note_name (UIConfiguration::instance().get_default_upper_midi_note());
}
bool
RCOptionEditor::set_default_upper_midi_note (std::string str)
{
int note = ParameterDescriptor::midi_note_num (str);
if (note < 0) {
mru_option->set_state_from_config ();
return false;
}
return UIConfiguration::instance().set_default_upper_midi_note (note);
}