X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=gtk2_ardour%2Frc_option_editor.cc;h=978cea87cc7116ea0240384a8cc1a9c963d68c94;hb=6a24f75a6f9cfede66441a8e3c036d116ee5c8ed;hp=a53e98871272aa437a0da6ec6edb559d89ec2689;hpb=3fa522e5df8401e8351c9a87f2f761f87a87a31a;p=ardour.git diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index a53e988712..978cea87cc 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -1,13 +1,37 @@ +/* + Copyright (C) 2001-2011 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. + +*/ + +#ifdef WAF_BUILD +#include "gtk2ardour-config.h" +#endif + #include #include #include #include #include +#include #include "pbd/fpu.h" +#include "pbd/cpus.h" #include "midi++/manager.h" -#include "midi++/factory.h" #include "ardour/audioengine.h" #include "ardour/dB.h" @@ -15,6 +39,8 @@ #include "ardour/control_protocol_manager.h" #include "control_protocol/control_protocol.h" +#include "ardour_window.h" +#include "ardour_dialog.h" #include "gui_thread.h" #include "midi_tracer.h" #include "rc_option_editor.h" @@ -30,253 +56,34 @@ using namespace Gtkmm2ext; using namespace PBD; using namespace ARDOUR; -class MIDIPorts : public OptionEditorBox -{ -public: - MIDIPorts (RCConfiguration* c, list* > const & o) - : _rc_config (c), - _add_port_button (Stock::ADD), - _port_combos (o) - { - _store = ListStore::create (_model); - _view.set_model (_store); - _view.append_column (_("Name"), _model.name); - _view.get_column(0)->set_resizable (true); - _view.get_column(0)->set_expand (true); - _view.append_column_editable (_("Online"), _model.online); - _view.append_column_editable (_("Trace input"), _model.trace_input); - _view.append_column_editable (_("Trace output"), _model.trace_output); - - HBox* h = manage (new HBox); - h->set_spacing (4); - h->pack_start (_view, true, true); - - VBox* v = manage (new VBox); - v->set_spacing (4); - v->pack_start (_add_port_button, false, false); - h->pack_start (*v, false, false); - - _box->pack_start (*h); - - ports_changed (); - - _store->signal_row_changed().connect (sigc::mem_fun (*this, &MIDIPorts::model_changed)); - - _add_port_button.signal_clicked().connect (sigc::mem_fun (*this, &MIDIPorts::add_port_clicked)); - } - - void parameter_changed (string const &) {} - void set_state_from_config () {} - -private: - - typedef std::map PortTraceMap; - PortTraceMap port_input_trace_map; - PortTraceMap port_output_trace_map; - - void model_changed (TreeModel::Path const &, TreeModel::iterator const & i) - { - TreeModel::Row r = *i; - - MIDI::Port* port = r[_model.port]; - if (!port) { - return; - } - - if (port->input()) { - - if (r[_model.online] == port->input()->offline()) { - port->input()->set_offline (!r[_model.online]); - } - - if (r[_model.trace_input] != port->input()->tracing()) { - PortTraceMap::iterator x = port_input_trace_map.find (port); - MidiTracer* mt; - - if (x == port_input_trace_map.end()) { - mt = new MidiTracer (port->name() + string (" [input]"), *port->input()); - port_input_trace_map.insert (pair (port, mt)); - } else { - mt = x->second; - } - mt->present (); - } - } - - if (port->output()) { - - if (r[_model.trace_output] != port->output()->tracing()) { - PortTraceMap::iterator x = port_output_trace_map.find (port); - MidiTracer* mt; - - if (x == port_output_trace_map.end()) { - mt = new MidiTracer (port->name() + string (" [output]"), *port->output()); - port_output_trace_map.insert (pair (port, mt)); - } else { - mt = x->second; - } - mt->present (); - } - - } - } - - void setup_ports_combo (ComboOption* c) - { - c->clear (); - MIDI::Manager::PortList const & ports = MIDI::Manager::instance()->get_midi_ports (); - for (MIDI::Manager::PortList::const_iterator i = ports.begin(); i != ports.end(); ++i) { - c->add ((*i)->name(), (*i)->name()); - } - } - - void ports_changed () - { - /* XXX: why is this coming from here? */ - MIDI::Manager::PortList const & ports = MIDI::Manager::instance()->get_midi_ports (); - - _store->clear (); - port_connections.drop_connections (); - - for (MIDI::Manager::PortList::const_iterator i = ports.begin(); i != ports.end(); ++i) { - - TreeModel::Row r = *_store->append (); - - r[_model.name] = (*i)->name(); - - if ((*i)->input()) { - r[_model.online] = !(*i)->input()->offline(); - (*i)->input()->OfflineStatusChanged.connect (port_connections, MISSING_INVALIDATOR, boost::bind (&MIDIPorts::port_offline_changed, this, (*i)), gui_context()); - r[_model.trace_input] = (*i)->input()->tracing(); - } - - if ((*i)->output()) { - r[_model.trace_output] = (*i)->output()->tracing(); - } - - r[_model.port] = (*i); - } - - for (list* >::iterator i = _port_combos.begin(); i != _port_combos.end(); ++i) { - setup_ports_combo (*i); - } - } - - void port_offline_changed (MIDI::Port* p) - { - if (!p->input()) { - return; - } - - for (TreeModel::Children::iterator i = _store->children().begin(); i != _store->children().end(); ++i) { - if ((*i)[_model.port] == p) { - (*i)[_model.online] = !p->input()->offline(); - } - } - } - - void add_port_clicked () - { - MidiPortDialog dialog; - - dialog.set_position (WIN_POS_MOUSE); - - dialog.show (); - - int const r = dialog.run (); - - switch (r) { - case RESPONSE_ACCEPT: - break; - default: - return; - break; - } - - Glib::ustring const mode = dialog.port_mode_combo.get_active_text (); - string smod; - - if (mode == _("input")) { - smod = X_("input"); - } else if (mode == (_("output"))) { - smod = X_("output"); - } else { - smod = "duplex"; - } - - XMLNode node (X_("MIDI-port")); - - node.add_property ("tag", dialog.port_name.get_text()); - node.add_property ("device", X_("ardour")); // XXX this can't be right for all types - node.add_property ("type", MIDI::PortFactory::default_port_type()); - node.add_property ("mode", smod); - - if (MIDI::Manager::instance()->add_port (node) != 0) { - cerr << " there are now " << MIDI::Manager::instance()->nports() << endl; - ports_changed (); - } - } - - class MIDIModelColumns : public TreeModelColumnRecord - { - public: - MIDIModelColumns () - { - add (name); - add (online); - add (trace_input); - add (trace_output); - add (port); - } - - TreeModelColumn name; - TreeModelColumn online; - TreeModelColumn trace_input; - TreeModelColumn trace_output; - TreeModelColumn port; - }; - - RCConfiguration* _rc_config; - Glib::RefPtr _store; - MIDIModelColumns _model; - TreeView _view; - Button _add_port_button; - ComboBoxText _mtc_combo; - ComboBoxText _midi_clock_combo; - ComboBoxText _mmc_combo; - ComboBoxText _mpc_combo; - list* > _port_combos; - PBD::ScopedConnectionList port_connections; -}; - - class ClickOptions : public OptionEditorBox { public: - ClickOptions (RCConfiguration* c, ArdourDialog* p) + ClickOptions (RCConfiguration* c, Gtk::Window* p) : _rc_config (c), _parent (p) { Table* t = manage (new Table (2, 3)); t->set_spacings (4); - Label* l = manage (new Label (_("Click audio file:"))); - l->set_alignment (0, 0.5); + Label* l = manage (left_aligned_label (_("Click audio file:"))); t->attach (*l, 0, 1, 0, 1, FILL); t->attach (_click_path_entry, 1, 2, 0, 1, FILL); Button* b = manage (new Button (_("Browse..."))); b->signal_clicked().connect (sigc::mem_fun (*this, &ClickOptions::click_browse_clicked)); t->attach (*b, 2, 3, 0, 1, FILL); - l = manage (new Label (_("Click emphasis audio file:"))); - l->set_alignment (0, 0.5); + l = manage (left_aligned_label (_("Click emphasis audio file:"))); t->attach (*l, 0, 1, 1, 2, FILL); t->attach (_click_emphasis_path_entry, 1, 2, 1, 2, FILL); b = manage (new Button (_("Browse..."))); b->signal_clicked().connect (sigc::mem_fun (*this, &ClickOptions::click_emphasis_browse_clicked)); t->attach (*b, 2, 3, 1, 2, FILL); - + _box->pack_start (*t, false, false); + + _click_path_entry.signal_activate().connect (sigc::mem_fun (*this, &ClickOptions::click_changed)); + _click_emphasis_path_entry.signal_activate().connect (sigc::mem_fun (*this, &ClickOptions::click_emphasis_changed)); } void parameter_changed (string const & p) @@ -314,6 +121,11 @@ private: _rc_config->set_click_sound (path); } + void click_changed () + { + click_chosen (_click_path_entry.get_text ()); + } + void click_emphasis_browse_clicked () { SoundFileChooser sfdb (*_parent, _("Choose Click Emphasis")); @@ -332,8 +144,13 @@ private: _rc_config->set_click_emphasis_sound (path); } + void click_emphasis_changed () + { + click_emphasis_chosen (_click_emphasis_path_entry.get_text ()); + } + RCConfiguration* _rc_config; - ArdourDialog* _parent; + Gtk::Window* _parent; Entry _click_path_entry; Entry _click_emphasis_path_entry; }; @@ -353,16 +170,14 @@ public: _limit_undo_spin.set_range (0, 512); _limit_undo_spin.set_increments (1, 10); t->attach (_limit_undo_spin, 1, 2, 0, 1, FILL | EXPAND); - Label* l = manage (new Label (_("commands"))); - l->set_alignment (0, 0.5); + Label* l = manage (left_aligned_label (_("commands"))); t->attach (*l, 2, 3, 0, 1); t->attach (_save_undo_button, 0, 1, 1, 2, FILL); _save_undo_spin.set_range (0, 512); _save_undo_spin.set_increments (1, 10); t->attach (_save_undo_spin, 1, 2, 1, 2, FILL | EXPAND); - l = manage (new Label (_("commands"))); - l->set_alignment (0, 0.5); + l = manage (left_aligned_label (_("commands"))); t->attach (*l, 2, 3, 1, 2); _box->pack_start (*t); @@ -443,7 +258,7 @@ static const struct { /* Command = Meta Option/Alt = Mod1 */ - { "Shift", GDK_SHIFT_MASK }, + { "Key|Shift", GDK_SHIFT_MASK }, { "Command", GDK_META_MASK }, { "Control", GDK_CONTROL_MASK }, { "Option", GDK_MOD1_MASK }, @@ -453,7 +268,7 @@ static const struct { { "Shift-Command-Option", GDK_MOD5_MASK|GDK_SHIFT_MASK|GDK_META_MASK }, #else - { "Shift", GDK_SHIFT_MASK }, + { "Key|Shift", GDK_SHIFT_MASK }, { "Control", GDK_CONTROL_MASK }, { "Alt (Mod1)", GDK_MOD1_MASK }, { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK }, @@ -476,14 +291,15 @@ public: _delete_button_adjustment (3, 1, 12), _delete_button_spin (_delete_button_adjustment), _edit_button_adjustment (3, 1, 5), - _edit_button_spin (_edit_button_adjustment) - + _edit_button_spin (_edit_button_adjustment), + _insert_note_button_adjustment (3, 1, 5), + _insert_note_button_spin (_insert_note_button_adjustment) { /* internationalize and prepare for use with combos */ vector dumb; for (int i = 0; modifiers[i].name; ++i) { - dumb.push_back (_(modifiers[i].name)); + dumb.push_back (S_(modifiers[i].name)); } set_popdown_strings (_edit_modifier_combo, dumb); @@ -491,7 +307,7 @@ public: for (int x = 0; modifiers[x].name; ++x) { if (modifiers[x].modifier == Keyboard::edit_modifier ()) { - _edit_modifier_combo.set_active_text (_(modifiers[x].name)); + _edit_modifier_combo.set_active_text (S_(modifiers[x].name)); break; } } @@ -499,9 +315,8 @@ public: Table* t = manage (new Table (4, 4)); t->set_spacings (4); - Label* l = manage (new Label (_("Edit using:"))); + Label* l = manage (left_aligned_label (_("Edit using:"))); l->set_name ("OptionsLabel"); - l->set_alignment (0, 0.5); t->attach (*l, 0, 1, 0, 1, FILL | EXPAND, FILL); t->attach (_edit_modifier_combo, 1, 2, 0, 1, FILL | EXPAND, FILL); @@ -521,14 +336,13 @@ public: for (int x = 0; modifiers[x].name; ++x) { if (modifiers[x].modifier == Keyboard::delete_modifier ()) { - _delete_modifier_combo.set_active_text (_(modifiers[x].name)); + _delete_modifier_combo.set_active_text (S_(modifiers[x].name)); break; } } - l = manage (new Label (_("Delete using:"))); + l = manage (left_aligned_label (_("Delete using:"))); l->set_name ("OptionsLabel"); - l->set_alignment (0, 0.5); t->attach (*l, 0, 1, 1, 2, FILL | EXPAND, FILL); t->attach (_delete_modifier_combo, 1, 2, 1, 2, FILL | EXPAND, FILL); @@ -543,22 +357,49 @@ public: _delete_button_adjustment.set_value (Keyboard::delete_button()); _delete_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_button_changed)); + + set_popdown_strings (_insert_note_modifier_combo, dumb); + _insert_note_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::insert_note_modifier_chosen)); + + for (int x = 0; modifiers[x].name; ++x) { + if (modifiers[x].modifier == Keyboard::insert_note_modifier ()) { + _insert_note_modifier_combo.set_active_text (S_(modifiers[x].name)); + break; + } + } + + l = manage (left_aligned_label (_("Insert note using:"))); + l->set_name ("OptionsLabel"); + + t->attach (*l, 0, 1, 2, 3, FILL | EXPAND, FILL); + t->attach (_insert_note_modifier_combo, 1, 2, 2, 3, FILL | EXPAND, FILL); + + l = manage (new Label (_("+ button"))); + l->set_name ("OptionsLabel"); + + t->attach (*l, 3, 4, 2, 3, FILL | EXPAND, FILL); + t->attach (_insert_note_button_spin, 4, 5, 2, 3, FILL | EXPAND, FILL); + + _insert_note_button_spin.set_name ("OptionsEntry"); + _insert_note_button_adjustment.set_value (Keyboard::insert_note_button()); + _insert_note_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::insert_note_button_changed)); + + set_popdown_strings (_snap_modifier_combo, dumb); _snap_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::snap_modifier_chosen)); for (int x = 0; modifiers[x].name; ++x) { if (modifiers[x].modifier == (guint) Keyboard::snap_modifier ()) { - _snap_modifier_combo.set_active_text (_(modifiers[x].name)); + _snap_modifier_combo.set_active_text (S_(modifiers[x].name)); break; } } - l = manage (new Label (_("Toggle snap using:"))); + l = manage (left_aligned_label (_("Toggle snap using:"))); l->set_name ("OptionsLabel"); - l->set_alignment (0, 0.5); - t->attach (*l, 0, 1, 2, 3, FILL | EXPAND, FILL); - t->attach (_snap_modifier_combo, 1, 2, 2, 3, FILL | EXPAND, FILL); + t->attach (*l, 0, 1, 3, 4, FILL | EXPAND, FILL); + t->attach (_snap_modifier_combo, 1, 2, 3, 4, FILL | EXPAND, FILL); vector strs; @@ -570,12 +411,11 @@ public: _keyboard_layout_selector.set_active_text (Keyboard::current_binding_name()); _keyboard_layout_selector.signal_changed().connect (sigc::mem_fun (*this, &KeyboardOptions::bindings_changed)); - l = manage (new Label (_("Keyboard layout:"))); + l = manage (left_aligned_label (_("Keyboard layout:"))); l->set_name ("OptionsLabel"); - l->set_alignment (0, 0.5); - t->attach (*l, 0, 1, 3, 4, FILL | EXPAND, FILL); - t->attach (_keyboard_layout_selector, 1, 2, 3, 4, FILL | EXPAND, FILL); + t->attach (*l, 0, 1, 4, 5, FILL | EXPAND, FILL); + t->attach (_keyboard_layout_selector, 1, 2, 4, 5, FILL | EXPAND, FILL); _box->pack_start (*t, false, false); } @@ -631,6 +471,18 @@ private: } } + void insert_note_modifier_chosen () + { + string const txt = _insert_note_modifier_combo.get_active_text(); + + for (int i = 0; modifiers[i].name; ++i) { + if (txt == _(modifiers[i].name)) { + Keyboard::set_insert_note_modifier (modifiers[i].modifier); + break; + } + } + } + void snap_modifier_chosen () { string const txt = _snap_modifier_combo.get_active_text(); @@ -653,14 +505,23 @@ private: Keyboard::set_edit_button (_edit_button_spin.get_value_as_int()); } + void insert_note_button_changed () + { + Keyboard::set_insert_note_button (_insert_note_button_spin.get_value_as_int()); + } + ComboBoxText _keyboard_layout_selector; ComboBoxText _edit_modifier_combo; ComboBoxText _delete_modifier_combo; + ComboBoxText _insert_note_modifier_combo; ComboBoxText _snap_modifier_combo; Adjustment _delete_button_adjustment; SpinButton _delete_button_spin; Adjustment _edit_button_adjustment; SpinButton _edit_button_spin; + Adjustment _insert_note_button_adjustment; + SpinButton _insert_note_button_spin; + }; class FontScalingOptions : public OptionEditorBox @@ -713,86 +574,84 @@ private: HScale _dpi_slider; }; -class SoloMuteOptions : public OptionEditorBox +class BufferingOptions : public OptionEditorBox { public: - SoloMuteOptions (RCConfiguration* c) : - _rc_config (c), - // 0.781787 is the value needed for gain to be set to 0. - _db_adjustment (0.781787, 0.0, 1.0, 0.01, 0.1) - + BufferingOptions (RCConfiguration* c) + : _rc_config (c) + , _playback_adjustment (5, 1, 60, 1, 4) + , _capture_adjustment (5, 1, 60, 1, 4) + , _playback_slider (_playback_adjustment) + , _capture_slider (_capture_adjustment) { - if ((pix = ::get_icon ("fader_belt_h")) == 0) { - throw failed_constructor(); - } + _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds()); - _db_slider = manage (new HSliderController (pix, - &_db_adjustment, - 115, - false)); - - parameter_changed ("solo-mute-gain"); - - Label* l = manage (new Label (_("Solo mute cut (dB):"))); + Label* l = manage (new Label (_("Playback (seconds of buffering):"))); l->set_name ("OptionsLabel"); + _playback_slider.set_update_policy (UPDATE_DISCONTINUOUS); HBox* h = manage (new HBox); h->set_spacing (4); h->pack_start (*l, false, false); - h->pack_start (*_db_slider, false, false); - h->pack_start (_db_display, false, false); - h->show_all (); - - set_size_request_to_display_given_text (_db_display, "-99.0", 12, 12); + h->pack_start (_playback_slider, true, true); _box->pack_start (*h, false, false); - _db_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &SoloMuteOptions::db_changed)); - } + _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds()); - void parameter_changed (string const & p) - { - if (p == "solo-mute-gain") { - gain_t val = _rc_config->get_solo_mute_gain(); + l = manage (new Label (_("Recording (seconds of buffering):"))); + l->set_name ("OptionsLabel"); - _db_adjustment.set_value (gain_to_slider_position (val)); + _capture_slider.set_update_policy (UPDATE_DISCONTINUOUS); + h = manage (new HBox); + h->set_spacing (4); + h->pack_start (*l, false, false); + h->pack_start (_capture_slider, true, true); - char buf[16]; + _box->pack_start (*h, false, false); - if (val == 0.0) { - snprintf (buf, sizeof (buf), "-inf"); - } else { - snprintf (buf, sizeof (buf), "%.2f", accurate_coefficient_to_dB (val)); - } + _capture_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::capture_changed)); + _playback_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::playback_changed)); + } - _db_display.set_text (buf); - } + void parameter_changed (string const & p) + { + if (p == "playback-buffer-seconds") { + _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds()); + } else if (p == "capture-buffer-seconds") { + _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds()); + } } void set_state_from_config () { - parameter_changed ("solo-mute-gain"); + parameter_changed ("playback-buffer-seconds"); + parameter_changed ("capture-buffer-seconds"); } private: - void db_changed () + void playback_changed () { - _rc_config->set_solo_mute_gain (slider_position_to_gain (_db_adjustment.get_value())); + _rc_config->set_audio_playback_buffer_seconds ((long) _playback_adjustment.get_value()); + } + + void capture_changed () + { + _rc_config->set_audio_capture_buffer_seconds ((long) _capture_adjustment.get_value()); } RCConfiguration* _rc_config; - Adjustment _db_adjustment; - Gtkmm2ext::HSliderController* _db_slider; - Glib::RefPtr pix; - Entry _db_display; + Adjustment _playback_adjustment; + Adjustment _capture_adjustment; + HScale _playback_slider; + HScale _capture_slider; }; - class ControlSurfacesOptions : public OptionEditorBox { public: - ControlSurfacesOptions (ArdourDialog& parent) + ControlSurfacesOptions (Gtk::Window& parent) : _parent (parent) { _store = ListStore::create (_model); @@ -810,8 +669,12 @@ public: _box->pack_start (*label, false, false); label->show (); - - _store->signal_row_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::model_changed)); + + ControlProtocolManager& m = ControlProtocolManager::instance (); + m.ProtocolStatusChange.connect (protocol_status_connection, MISSING_INVALIDATOR, + boost::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)); } @@ -839,7 +702,18 @@ public: private: - void model_changed (TreeModel::Path const &, TreeModel::iterator const & i) + 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) { + if ((*x)[_model.protocol_info] == cpi) { + (*x)[_model.enabled] = (cpi->protocol || cpi->requested); + break; + } + } + } + + void view_changed (TreeModel::Path const &, TreeModel::iterator const & i) { TreeModel::Row r = *i; @@ -855,7 +729,18 @@ private: if (!was_enabled) { ControlProtocolManager::instance().instantiate (*cpi); } else { + Gtk::Window* win = r[_model.editor]; + if (win) { + win->hide (); + } + ControlProtocolManager::instance().teardown (*cpi); + + if (win) { + delete win; + } + r[_model.editor] = 0; + cpi->requested = false; } } @@ -876,21 +761,22 @@ private: std::string name; ControlProtocolInfo* cpi; TreeModel::Row row; - + row = *(_view.get_selection()->get_selected()); Window* win = row[_model.editor]; if (win && !win->is_visible()) { - win->present (); + win->present (); } else { cpi = row[_model.protocol_info]; - + if (cpi && cpi->protocol && cpi->protocol->has_editor ()) { Box* box = (Box*) cpi->protocol->get_gui (); if (box) { string title = row[_model.name]; - ArdourDialog* win = new ArdourDialog (_parent, title); - win->get_vbox()->pack_start (*box, false, false); + ArdourWindow* win = new ArdourWindow (_parent, title); + win->set_title ("Control Protocol Options"); + win->add (*box); box->show (); win->present (); row[_model.editor] = win; @@ -923,59 +809,105 @@ private: ControlSurfacesModelColumns _model; TreeView _view; Gtk::Window& _parent; + PBD::ScopedConnection protocol_status_connection; +}; + +/** A class which allows control of visibility of some editor components usign + * a VisibilityGroup. The caller should pass in a `dummy' VisibilityGroup + * which has the correct members, but with null widget pointers. This + * class allows the user to set visibility of the members, the details + * of which are stored in a configuration variable which can be watched + * by parts of the editor that actually contain the widgets whose visibility + * is being controlled. + */ + +class VisibilityOption : public Option +{ +public: + /** @param name User-visible name for this group. + * @param g `Dummy' VisibilityGroup (as described above). + * @param get Method to get the value of the appropriate configuration variable. + * @param set Method to set the value of the appropriate configuration variable. + */ + VisibilityOption (string name, VisibilityGroup* g, sigc::slot get, sigc::slot set) + : Option (g->get_state_name(), name) + , _heading (name) + , _visibility_group (g) + , _get (get) + , _set (set) + { + /* Watch for changes made by the user to our members */ + _visibility_group->VisibilityChanged.connect_same_thread ( + _visibility_group_connection, sigc::bind (&VisibilityOption::changed, this) + ); + } + + void set_state_from_config () + { + /* Set our state from the current configuration */ + _visibility_group->set_state (_get ()); + } + + void add_to_page (OptionEditorPage* p) + { + _heading.add_to_page (p); + add_widget_to_page (p, _visibility_group->list_view ()); + } + + Gtk::Widget& tip_widget() { return *_visibility_group->list_view (); } + +private: + void changed () + { + /* The user has changed something, so reflect this change + in the RCConfiguration. + */ + _set (_visibility_group->get_state_value ()); + } + + OptionEditorHeading _heading; + VisibilityGroup* _visibility_group; + sigc::slot _get; + sigc::slot _set; + PBD::ScopedConnection _visibility_group_connection; }; RCOptionEditor::RCOptionEditor () : OptionEditor (Config, string_compose (_("%1 Preferences"), PROGRAM_NAME)) , _rc_config (Config) + , _mixer_strip_visibility ("mixer-strip-visibility") { /* MISC */ - add_option (_("Misc"), new OptionEditorHeading (_("Metering"))); + uint32_t hwcpus = hardware_concurrency (); - ComboOption* mht = new ComboOption ( - "meter-hold", - _("Meter hold time"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_hold), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_hold) - ); + if (hwcpus > 1) { + add_option (_("Misc"), new OptionEditorHeading (_("DSP CPU Utilization"))); - mht->add (MeterHoldOff, _("off")); - mht->add (MeterHoldShort, _("short")); - mht->add (MeterHoldMedium, _("medium")); - mht->add (MeterHoldLong, _("long")); + ComboOption* procs = new ComboOption ( + "processor-usage", + _("Signal processing uses"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage) + ); - add_option (_("Misc"), mht); + procs->add (-1, _("all but one processor")); + procs->add (0, _("all available processors")); - ComboOption* mfo = new ComboOption ( - "meter-falloff", - _("Meter fall-off"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff) - ); + for (uint32_t i = 1; i <= hwcpus; ++i) { + procs->add (i, string_compose (_("%1 processors"), i)); + } - mfo->add (METER_FALLOFF_OFF, _("off")); - mfo->add (METER_FALLOFF_SLOWEST, _("slowest")); - mfo->add (METER_FALLOFF_SLOW, _("slow")); - mfo->add (METER_FALLOFF_MEDIUM, _("medium")); - mfo->add (METER_FALLOFF_FAST, _("fast")); - mfo->add (METER_FALLOFF_FASTER, _("faster")); - mfo->add (METER_FALLOFF_FASTEST, _("fastest")); + procs->set_note (string_compose (_("This setting will only take effect when %1 is restarted."), PROGRAM_NAME)); - add_option (_("Misc"), mfo); + add_option (_("Misc"), procs); + } - add_option (_("Misc"), new OptionEditorHeading (_("Undo"))); + add_option (_("Misc"), new OptionEditorHeading (S_("Options|Undo"))); add_option (_("Misc"), new UndoOptions (_rc_config)); - add_option (_("Misc"), new OptionEditorHeading (_("Misc"))); - -#ifndef GTKOSX - /* font scaling does nothing with GDK/Quartz */ - add_option (_("Misc"), new FontScalingOptions (_rc_config)); -#endif - add_option (_("Misc"), new BoolOption ( "verify-remove-last-capture", @@ -992,13 +924,7 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups) )); - add_option (_("Misc"), - new BoolOption ( - "sync-all-route-ordering", - _("Syncronise editor and mixer track order"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_all_route_ordering), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_all_route_ordering) - )); + add_option (_("Misc"), new OptionEditorHeading (_("Session Management"))); add_option (_("Misc"), new BoolOption ( @@ -1008,87 +934,228 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_only_copy_imported_files) )); + add_option (_("Misc"), 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 (_("Misc"), - new BoolOption ( - "default-narrow_ms", - _("Use narrow mixer strips"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_narrow_ms), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_narrow_ms) + new SpinOption ( + "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 (_("Misc"), new OptionEditorHeading (_("Click"))); + + add_option (_("Misc"), new ClickOptions (_rc_config, this)); + add_option (_("Misc"), - new BoolOption ( - "name-new-markers", - _("Name new markers"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_name_new_markers), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_name_new_markers) + new FaderOption ( + "click-gain", + _("Click gain level"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_click_gain), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_click_gain) + )); + + add_option (_("Misc"), new OptionEditorHeading (_("Automation"))); + + add_option (_("Misc"), + new SpinOption ( + "automation-thinning-factor", + _("Thinning factor (larger value => less data)"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_thinning_factor), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_thinning_factor), + 0, 1000, 1, 20 )); /* TRANSPORT */ - add_option (_("Transport"), - new BoolOption ( + BoolOption* tsf; + + tsf = 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) - )); + ); + // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("")); + add_option (_("Transport"), tsf); - add_option (_("Transport"), - new BoolOption ( + tsf = 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 (tsf->tip_widget(), _("When enabled Ardour will stop recording if an over- or underrun is detected by the audio engine")); + add_option (_("Transport"), tsf); - add_option (_("Transport"), - new BoolOption ( + tsf = 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) - )); + ); + // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("")); + add_option (_("Transport"), tsf); - add_option (_("Transport"), - new BoolOption ( + tsf = 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) - )); - - add_option (_("Transport"), - new BoolOption ( - "primary-clock-delta-edit-cursor", - _("Primary clock delta to edit cursor"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_primary_clock_delta_edit_cursor), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_primary_clock_delta_edit_cursor) - )); - - add_option (_("Transport"), - new BoolOption ( - "secondary-clock-delta-edit-cursor", - _("Secondary clock delta to edit cursor"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_secondary_clock_delta_edit_cursor), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_secondary_clock_delta_edit_cursor) - )); - - add_option (_("Transport"), - new BoolOption ( + ); + Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("When enabled if Ardour is not recording, it will stop the transport " + "when it reaches the current session end marker\n\n" + "When disabled Ardour will continue to roll past the session end marker at all times")); + add_option (_("Transport"), tsf); + + tsf = new BoolOption ( + "seamless-loop", + _("Do seamless looping (not possible when slaved to MTC, JACK etc)"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_seamless_loop), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_seamless_loop) + ); + Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("When enabled this will loop by reading ahead and wrapping around at the loop point, " + "preventing any need to do a transport locate at the end of the loop\n\n" + "When disabled looping is done by locating back to the start of the loop when Ardour reaches the end " + "which will often cause a small click or delay")); + add_option (_("Transport"), tsf); + + tsf = 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 (tsf->tip_widget(), _("When enabled this will prevent you from accidentally stopping specific tracks recording during a take")); + add_option (_("Transport"), tsf); - add_option (_("Transport"), - new BoolOption ( + tsf = new BoolOption ( "quieten_at_speed", _("12dB gain reduction during fast-forward and fast-rewind"), sigc::mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed), sigc::mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed) - )); + ); + Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("This will reduce the unpleasant increase in perceived volume " + "that occurs when fast-forwarding or rewinding through some kinds of audio")); + add_option (_("Transport"), tsf); + + add_option (_("Transport"), new OptionEditorHeading (S_("Sync/Slave"))); + + _sync_source = new ComboOption ( + "sync-source", + _("External timecode source"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_source), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_source) + ); + + populate_sync_options (); + add_option (_("Transport"), _sync_source); + + _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(), + _("This option controls the value of the video frame rate while chasing an external timecode source.\n\n" + "When enabled the session video frame rate will be changed to match that of the selected external timecode source.\n\n" + "When disabled 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 Ardour will convert between the external " + "timecode standard and the session standard.")); + + add_option (_("Transport"), _sync_framerate); + + _sync_genlock = new BoolOption ( + "timecode-source-is-synced", + _("External timecode is sync locked"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_is_synced), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_is_synced) + ); + Gtkmm2ext::UI::instance()->set_tip + (_sync_genlock->tip_widget(), + _("When enabled indicates that the selected external timecode source shares sync (Black & Burst, Wordclock, etc) with the audio interface.")); + + + add_option (_("Transport"), _sync_genlock); + + _sync_source_2997 = new BoolOption ( + "timecode-source-2997", + _("Lock to 29.9700 fps instead of 30000/1001"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_2997), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_2997) + ); + Gtkmm2ext::UI::instance()->set_tip + (_sync_source_2997->tip_widget(), + _("When enabled the external timecode source is assumed to use 29.97 fps instead of 30000/1001.\n" + "SMPTE 12M-1999 specifies 29.97df as 30000/1001. The spec further mentions that " + "drop-frame timecode has an accumulated error of -86ms over a 24-hour period.\n" + "Drop-frame timecode would compensate exactly for a NTSC color frame rate of 30 * 0.9990 (ie 29.970000). " + "That is not the actual rate, however some vendor use that rate - despite it being against the specs - " + "because the variant of using exactly 29.97 fps has zero timecode drift.\n" + )); + + add_option (_("Transport"), _sync_source_2997); + + _ltc_port = new ComboStringOption ( + "ltc-source-port", + _("LTC incoming port"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_source_port), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_source_port) + ); + + vector physical_inputs; + physical_inputs.push_back (_("None")); + AudioEngine::instance()->get_physical_inputs (DataType::AUDIO, physical_inputs); + _ltc_port->set_popdown_strings (physical_inputs); + + add_option (_("Transport"), _ltc_port); + +#ifdef HAVE_LTC + // TODO; rather disable this button than not compile it.. + add_option (_("Transport"), new OptionEditorHeading (S_("LTC Generator"))); + + add_option (_("Transport"), + 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(), + _("When enabled Ardour will continue to send LTC information even when the transport (playhead) is not moving")); + add_option (_("Transport"), _ltc_send_continuously); + + _ltc_volume_adjustment = new Gtk::Adjustment(-18, -50, 0, .5, 5); + _ltc_volume_adjustment->set_value (20 * log10(_rc_config->get_ltc_output_volume())); + _ltc_volume_adjustment->signal_value_changed().connect (sigc::mem_fun (*this, &RCOptionEditor::ltc_generator_volume_changed)); + _ltc_volume_slider = new HSliderOption("ltcvol", ("LTC generator level:"), *_ltc_volume_adjustment); + + 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"), _ltc_volume_slider); + parameter_changed ("send-ltc"); +#endif + + parameter_changed ("sync-source"); /* EDITOR */ @@ -1103,7 +1170,7 @@ RCOptionEditor::RCOptionEditor () add_option (_("Editor"), new BoolOption ( "automation-follows-regions", - _("Move relevant automation when regions are moved"), + _("Move relevant automation when audio regions are moved"), sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_follows_regions), sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_follows_regions) )); @@ -1140,6 +1207,16 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_waveforms) )); + add_option (_("Editor"), + new BoolComboOption ( + "show-region-gain-envelopes", + _("Show gain envelopes in audio regions"), + _("in all modes"), + _("only in region gain mode"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_region_gain), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_region_gain) + )); + ComboOption* wfs = new ComboOption ( "waveform-scale", _("Waveform scale"), @@ -1172,55 +1249,68 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_waveforms_while_recording) )); - /* AUDIO */ - - add_option (_("Audio"), new OptionEditorHeading (_("Solo"))); - - add_option (_("Audio"), - 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) - )); - - ComboOption* lp = new ComboOption ( - "listen-position", - _("Listen Position"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position) - ); + add_option (_("Editor"), + new BoolOption ( + "show-zoom-tools", + _("Show zoom toolbar"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_zoom_tools), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_zoom_tools) + )); - lp->add (AfterFaderListen, _("after-fader listen")); - lp->add (PreFaderListen, _("pre-fader listen")); + add_option (_("Editor"), + new BoolOption ( + "color-regions-using-track-color", + _("Color regions using their track's color"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_color_regions_using_track_color), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_color_regions_using_track_color) + )); - add_option (_("Audio"), lp); - add_option (_("Audio"), new SoloMuteOptions (_rc_config)); + add_option (_("Editor"), + new BoolOption ( + "update-editor-during-summary-drag", + _("Update editor window during drags of the summary"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_update_editor_during_summary_drag), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_update_editor_during_summary_drag) + )); - add_option (_("Audio"), + add_option (_("Editor"), new BoolOption ( - "exclusive-solo", - _("Exclusive solo"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo) + "sync-all-route-ordering", + _("Synchronise editor and mixer track order"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_all_route_ordering), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_all_route_ordering) )); - add_option (_("Audio"), + add_option (_("Editor"), 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) + "link-editor-and-mixer-selection", + _("Synchronise editor and mixer selection"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_editor_and_mixer_selection), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_editor_and_mixer_selection) )); - add_option (_("Audio"), + add_option (_("Editor"), 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) + "name-new-markers", + _("Name new markers"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_name_new_markers), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_name_new_markers) )); + add_option (_("Editor"), + new BoolOption ( + "autoscroll-editor", + _("Auto-scroll editor window when dragging near its edges"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_autoscroll_editor), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_autoscroll_editor) + )); + + /* AUDIO */ + + add_option (_("Audio"), new OptionEditorHeading (_("Buffering"))); + + add_option (_("Audio"), new BufferingOptions (_rc_config)); + add_option (_("Audio"), new OptionEditorHeading (_("Monitoring"))); add_option (_("Audio"), @@ -1233,7 +1323,7 @@ RCOptionEditor::RCOptionEditor () ComboOption* mm = new ComboOption ( "monitoring-model", - _("Monitoring handled by"), + _("Record monitoring handled by"), sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model), sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model) ); @@ -1269,7 +1359,7 @@ RCOptionEditor::RCOptionEditor () ComboOption* iac = new ComboOption ( "input-auto-connect", - _("Connect track and bus inputs"), + _("Connect track inputs"), sigc::mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect), sigc::mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect) ); @@ -1287,7 +1377,7 @@ RCOptionEditor::RCOptionEditor () ); oac->add (AutoConnectPhysical, _("automatically to physical outputs")); - oac->add (AutoConnectMaster, _("automatically to master outputs")); + oac->add (AutoConnectMaster, _("automatically to master bus")); oac->add (ManualConnect, _("manually")); add_option (_("Audio"), oac); @@ -1322,7 +1412,7 @@ RCOptionEditor::RCOptionEditor () } if (fpu.has_flush_to_zero() && fpu.has_denormals_are_zero()) { - dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZerO")); + dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZero")); } add_option (_("Audio"), dm); @@ -1332,7 +1422,7 @@ RCOptionEditor::RCOptionEditor () add_option (_("Audio"), new BoolOption ( "plugins-stop-with-transport", - _("Stop plugins when the transport is stopped"), + _("Silence plugins when the transport is stopped"), sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport), sigc::mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport) )); @@ -1361,45 +1451,138 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio) )); - /* MIDI CONTROL */ - - list* > midi_combos; - - midi_combos.push_back (new ComboOption ( - "mtc-port-name", - _("Send/Receive MTC via"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_mtc_port_name), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_mtc_port_name) - )); - - midi_combos.push_back (new ComboOption ( - "midi-clock-port-name", - _("Send/Receive MIDI clock via"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_clock_port_name), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_clock_port_name) - )); - - midi_combos.push_back (new ComboOption ( - "mmc-port-name", - _("Send/Receive MMC via"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_port_name), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_port_name) - )); - - midi_combos.push_back (new ComboOption ( - "midi-port-name", - _("Send/Receive MIDI parameter control via"), - sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_port_name), - sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_port_name) - )); - - add_option (_("MIDI control"), new MIDIPorts (_rc_config, midi_combos)); + add_option (_("Audio"), + new BoolOption ( + "replicate-missing-region-channels", + _("Replicate missing region channels"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_replicate_missing_region_channels), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_replicate_missing_region_channels) + )); - for (list* >::iterator i = midi_combos.begin(); i != midi_combos.end(); ++i) { - add_option (_("MIDI control"), *i); - } + /* SOLO AND MUTE */ + + add_option (_("Solo / mute"), + 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) + )); - add_option (_("MIDI control"), + _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 (_("Solo / mute"), _solo_control_is_listen_control); + + _listen_position = new ComboOption ( + "listen-position", + _("Listen Position"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position) + ); + + _listen_position->add (AfterFaderListen, _("after-fader (AFL)")); + _listen_position->add (PreFaderListen, _("pre-fader (PFL)")); + + add_option (_("Solo / mute"), _listen_position); + + ComboOption* pp = new ComboOption ( + "pfl-position", + _("PFL signals come from"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_pfl_position), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_pfl_position) + ); + + pp->add (PFLFromBeforeProcessors, _("before pre-fader processors")); + pp->add (PFLFromAfterProcessors, _("pre-fader but after pre-fader processors")); + + add_option (_("Solo / mute"), pp); + + ComboOption* pa = new ComboOption ( + "afl-position", + _("AFL signals come from"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_afl_position), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_afl_position) + ); + + pa->add (AFLFromBeforeProcessors, _("immediately post-fader")); + pa->add (AFLFromAfterProcessors, _("after post-fader processors (before pan)")); + + add_option (_("Solo / mute"), pa); + + parameter_changed ("use-monitor-bus"); + + add_option (_("Solo / mute"), + 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 (_("Solo / mute"), + 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 (_("Solo / mute"), + 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 (_("Solo / mute"), new OptionEditorHeading (_("Default track / bus muting options"))); + + add_option (_("Solo / mute"), + new BoolOption ( + "mute-affects-pre-fader", + _("Mute affects pre-fader sends"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_pre_fader), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_pre_fader) + )); + + add_option (_("Solo / mute"), + new BoolOption ( + "mute-affects-post-fader", + _("Mute affects post-fader sends"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_post_fader), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_post_fader) + )); + + add_option (_("Solo / mute"), + new BoolOption ( + "mute-affects-control-outs", + _("Mute affects control outputs"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_control_outs), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_control_outs) + )); + + add_option (_("Solo / mute"), + new BoolOption ( + "mute-affects-main-outs", + _("Mute affects main outputs"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_main_outs), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs) + )); + + add_option (_("MIDI"), + new BoolOption ( + "send-midi-clock", + _("Send MIDI Clock"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_midi_clock), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_midi_clock) + )); + + add_option (_("MIDI"), new BoolOption ( "send-mtc", _("Send MIDI Time Code"), @@ -1407,7 +1590,16 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc) )); - add_option (_("MIDI control"), + add_option (_("MIDI"), + new SpinOption ( + "mtc-qf-speed-tolerance", + _("Percentage either side of normal transport speed to transmit MTC"), + 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 + )); + + add_option (_("MIDI"), new BoolOption ( "mmc-control", _("Obey MIDI Machine Control commands"), @@ -1415,8 +1607,7 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control) )); - - add_option (_("MIDI control"), + add_option (_("MIDI"), new BoolOption ( "send-mmc", _("Send MIDI Machine Control commands"), @@ -1424,7 +1615,7 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc) )); - add_option (_("MIDI control"), + add_option (_("MIDI"), new BoolOption ( "midi-feedback", _("Send MIDI control feedback"), @@ -1432,7 +1623,7 @@ RCOptionEditor::RCOptionEditor () sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_feedback) )); - add_option (_("MIDI control"), + add_option (_("MIDI"), new SpinOption ( "mmc-receive-device-id", _("Inbound MMC device ID"), @@ -1441,7 +1632,7 @@ RCOptionEditor::RCOptionEditor () 0, 128, 1, 10 )); - add_option (_("MIDI control"), + add_option (_("MIDI"), new SpinOption ( "mmc-send-device-id", _("Outbound MMC device ID"), @@ -1450,7 +1641,7 @@ RCOptionEditor::RCOptionEditor () 0, 128, 1, 10 )); - add_option (_("MIDI control"), + add_option (_("MIDI"), new SpinOption ( "initial-program-change", _("Initial program change"), @@ -1459,9 +1650,39 @@ RCOptionEditor::RCOptionEditor () -1, 65536, 1, 10 )); - /* CONTROL SURFACES */ + add_option (_("MIDI"), + new BoolOption ( + "diplay-first-midi-bank-as-zero", + _("Display first MIDI bank/program as 0"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_first_midi_bank_is_zero), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_first_midi_bank_is_zero) + )); + + add_option (_("MIDI"), + new BoolOption ( + "never-display-periodic-midi", + _("Never display periodic MIDI messages (MTC, MIDI Clock)"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_never_display_periodic_midi), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_never_display_periodic_midi) + )); + + add_option (_("MIDI"), + new BoolOption ( + "sound-midi-notes", + _("Sound MIDI notes as they are selected"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_sound_midi_notes), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_sound_midi_notes) + )); + + /* USER INTERACTION */ + + add_option (_("User interaction"), new OptionEditorHeading (_("Keyboard"))); + + add_option (_("User interaction"), new KeyboardOptions); + + add_option (_("User interaction"), new OptionEditorHeading (_("Control surfaces"))); - add_option (_("Control surfaces"), new ControlSurfacesOptions (*this)); + add_option (_("User interaction"), new ControlSurfacesOptions (*this)); ComboOption* rm = new ComboOption ( "remote-model", @@ -1474,15 +1695,144 @@ RCOptionEditor::RCOptionEditor () rm->add (MixerOrdered, _("follows order of mixer")); rm->add (EditorOrdered, _("follows order of editor")); - add_option (_("Control surfaces"), rm); + add_option (_("User interaction"), rm); - /* CLICK */ + /* INTERFACE */ - add_option (_("Click"), new ClickOptions (_rc_config, this)); + add_option (S_("GUI"), + new BoolOption ( + "widget-prelight", + _("Graphically indicate mouse pointer hovering over various widgets"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_widget_prelight), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_widget_prelight) + )); + +#ifndef GTKOSX + /* font scaling does nothing with GDK/Quartz */ + add_option (S_("GUI"), new FontScalingOptions (_rc_config)); +#endif + add_option (S_("GUI"), + new BoolOption ( + "use-own-plugin-gui", + _("Use plugins' own interfaces instead of Ardour's"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_plugin_own_gui), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_plugin_own_gui) + )); + + /* The names of these controls must be the same as those given in MixerStrip + for the actual widgets being controlled. + */ + _mixer_strip_visibility.add (0, X_("PhaseInvert"), _("Phase Invert")); + _mixer_strip_visibility.add (0, X_("SoloSafe"), _("Solo Safe")); + _mixer_strip_visibility.add (0, X_("SoloIsolated"), _("Solo Isolated")); + _mixer_strip_visibility.add (0, X_("Comments"), _("Comments")); + _mixer_strip_visibility.add (0, X_("Group"), _("Group")); + _mixer_strip_visibility.add (0, X_("MeterPoint"), _("Meter Point")); + + add_option ( + S_("GUI"), + new VisibilityOption ( + _("Mixer Strip"), + &_mixer_strip_visibility, + sigc::mem_fun (*_rc_config, &RCConfiguration::get_mixer_strip_visibility), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_mixer_strip_visibility) + ) + ); + + add_option (S_("GUI"), + new BoolOption ( + "default-narrow_ms", + _("Use narrow strips in the mixer by default"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_narrow_ms), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_narrow_ms) + )); + + add_option (S_("GUI"), new OptionEditorHeading (_("Metering"))); + + ComboOption* mht = new ComboOption ( + "meter-hold", + _("Meter hold time"), + sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_hold), + sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_hold) + ); + + mht->add (MeterHoldOff, _("off")); + mht->add (MeterHoldShort, _("short")); + mht->add (MeterHoldMedium, _("medium")); + mht->add (MeterHoldLong, _("long")); - /* KEYBOARD */ + add_option (S_("GUI"), mht); - add_option (_("Keyboard"), new KeyboardOptions); + ComboOption* mfo = new ComboOption ( + "meter-falloff", + _("Meter 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")); + mfo->add (METER_FALLOFF_SLOW, _("slow")); + mfo->add (METER_FALLOFF_MEDIUM, _("medium")); + mfo->add (METER_FALLOFF_FAST, _("fast")); + mfo->add (METER_FALLOFF_FASTER, _("faster")); + mfo->add (METER_FALLOFF_FASTEST, _("fastest")); + + add_option (S_("GUI"), mfo); } +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); + } + _solo_control_is_listen_control->set_sensitive (s); + _listen_position->set_sensitive (s); + } else if (p == "sync-source") { + _sync_source->set_sensitive (true); + if (_session) { + _sync_source->set_sensitive (_session->config.get_external_sync()); + } + switch(Config->get_sync_source()) { + case ARDOUR::MTC: + case ARDOUR::LTC: + _sync_genlock->set_sensitive (true); + _sync_framerate->set_sensitive (true); + _sync_source_2997->set_sensitive (true); + break; + default: + _sync_genlock->set_sensitive (false); + _sync_framerate->set_sensitive (false); + _sync_source_2997->set_sensitive (false); + break; + } +#ifdef HAVE_LTC + } else if (p == "send-ltc") { + bool const s = Config->get_send_ltc (); + _ltc_send_continuously->set_sensitive (s); + _ltc_volume_slider->set_sensitive (s); +#endif /*HAVE_LTC*/ + } +} + +void RCOptionEditor::ltc_generator_volume_changed () { + _rc_config->set_ltc_output_volume (pow(10, _ltc_volume_adjustment->get_value() / 20)); +} + +void +RCOptionEditor::populate_sync_options () +{ + vector sync_opts = ARDOUR::get_available_sync_options (); + + _sync_source->clear (); + + for (vector::iterator i = sync_opts.begin(); i != sync_opts.end(); ++i) { + _sync_source->add (*i, sync_source_to_string (*i)); + } +}