13
0
livetrax/gtk2_ardour/monitor_section.cc
Ben Loftis 3f297f7dab Fix ArdourButton event sequence.
Always give ArdourButton a chance to handle Press or Release events if you override them.
This allows ArdourButtons to do the "Pressed" animation
And it now correctly eats the event so button clicks don't select the channelstrip.
2014-08-28 10:31:57 -05:00

1185 lines
40 KiB
C++

/*
Copyright (C) 2012 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.
*/
#include <gdkmm/pixbuf.h>
#include "pbd/compose.h"
#include "pbd/error.h"
#include "gtkmm2ext/bindable_button.h"
#include "gtkmm2ext/tearoff.h"
#include "gtkmm2ext/actions.h"
#include "gtkmm2ext/motionfeedback.h"
#include <gtkmm/menu.h>
#include <gtkmm/menuitem.h>
#include "ardour/monitor_processor.h"
#include "ardour/route.h"
#include "ardour_ui.h"
#include "gui_thread.h"
#include "monitor_section.h"
#include "public_editor.h"
#include "volume_controller.h"
#include "utils.h"
#include "i18n.h"
using namespace ARDOUR;
using namespace ARDOUR_UI_UTILS;
using namespace Gtk;
using namespace Gtkmm2ext;
using namespace PBD;
using namespace std;
Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
MonitorSection::MonitorSection (Session* s)
: AxisView (s)
, RouteUI (s)
, _tearoff (0)
, channel_table_viewport (*channel_table_scroller.get_hadjustment(),
*channel_table_scroller.get_vadjustment ())
, gain_control (0)
, dim_control (0)
, solo_boost_control (0)
, solo_cut_control (0)
, gain_display (0)
, dim_display (0)
, solo_boost_display (0)
, solo_cut_display (0)
, solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
, afl_button (_("AFL"), ArdourButton::led_default_elements)
, pfl_button (_("PFL"), ArdourButton::led_default_elements)
, exclusive_solo_button (ArdourButton::led_default_elements)
, solo_mute_override_button (ArdourButton::led_default_elements)
, _inhibit_solo_model_update (false)
{
using namespace Menu_Helpers;
Glib::RefPtr<Action> act;
if (!monitor_actions) {
/* do some static stuff */
register_actions ();
}
set_session (s);
VBox* spin_packer;
Label* spin_label;
/* Rude Solo */
rude_solo_button.set_text (_("Soloing"));
rude_solo_button.set_name ("rude solo");
rude_solo_button.show ();
rude_iso_button.set_text (_("Isolated"));
rude_iso_button.set_name ("rude isolate");
rude_iso_button.show ();
rude_audition_button.set_text (_("Auditioning"));
rude_audition_button.set_name ("rude audition");
rude_audition_button.show ();
ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo), false);
UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
solo_in_place_button.set_name ("monitor section solo model");
afl_button.set_name ("monitor section solo model");
pfl_button.set_name ("monitor section solo model");
solo_model_box.set_spacing (6);
solo_model_box.pack_start (solo_in_place_button, true, false);
solo_model_box.pack_start (afl_button, true, false);
solo_model_box.pack_start (pfl_button, true, false);
solo_in_place_button.show ();
afl_button.show ();
pfl_button.show ();
solo_model_box.show ();
act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
ARDOUR_UI::instance()->tooltips().set_tip (solo_in_place_button, _("Solo controls affect solo-in-place"));
if (act) {
solo_in_place_button.set_related_action (act);
}
act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
ARDOUR_UI::instance()->tooltips().set_tip (afl_button, _("Solo controls toggle after-fader-listen"));
if (act) {
afl_button.set_related_action (act);
}
act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
ARDOUR_UI::instance()->tooltips().set_tip (pfl_button, _("Solo controls toggle pre-fader-listen"));
if (act) {
pfl_button.set_related_action (act);
}
/* Solo Boost */
solo_boost_control = new ArdourKnob ();
solo_boost_control->set_name("monitor knob");
solo_boost_control->set_size_request(40,40);
ARDOUR_UI::instance()->tooltips().set_tip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
solo_boost_display = new ArdourDisplay ();
solo_boost_display->set_name("monitor section cut");
solo_boost_display->set_size_request(80,20);
solo_boost_display->add_controllable_preset("0dB", 0.0);
solo_boost_display->add_controllable_preset("3 dB", 3.0);
solo_boost_display->add_controllable_preset("6 dB", 6.0);
solo_boost_display->add_controllable_preset("10 dB", 10.0);
HBox* solo_packer = manage (new HBox);
solo_packer->set_spacing (6);
solo_packer->show ();
spin_label = manage (new Label (_("Solo Boost")));
spin_packer = manage (new VBox);
spin_packer->show ();
spin_packer->set_spacing (3);
spin_packer->pack_start (*spin_label, false, false);
spin_packer->pack_start (*solo_boost_control, false, false);
spin_packer->pack_start (*solo_boost_display, false, false);
solo_packer->pack_start (*spin_packer, true, false);
/* Solo (SiP) cut */
solo_cut_control = new ArdourKnob ();
solo_cut_control->set_name ("monitor knob");
solo_cut_control->set_size_request (40,40);
ARDOUR_UI::instance()->tooltips().set_tip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
solo_cut_display = new ArdourDisplay ();
solo_cut_display->set_name("monitor section cut");
solo_cut_display->set_size_request(80,20);
solo_cut_display->add_controllable_preset("0dB", 0.0);
solo_cut_display->add_controllable_preset("-6 dB", -6.0);
solo_cut_display->add_controllable_preset("-12 dB", -12.0);
solo_cut_display->add_controllable_preset("-20 dB", -20.0);
solo_cut_display->add_controllable_preset("OFF", -1200.0);
spin_label = manage (new Label (_("SiP Cut")));
spin_packer = manage (new VBox);
spin_packer->show ();
spin_packer->set_spacing (3);
spin_packer->pack_start (*spin_label, false, false);
spin_packer->pack_start (*solo_cut_control, false, false);
spin_packer->pack_start (*solo_cut_display, false, false);
solo_packer->pack_start (*spin_packer, true, false);
/* Dim */
dim_control = new ArdourKnob ();
dim_control->set_name ("monitor knob");
dim_control->set_size_request (40,40);
ARDOUR_UI::instance()->tooltips().set_tip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
dim_display = new ArdourDisplay ();
dim_display->set_name("monitor section cut");
dim_display->set_size_request(80,20);
dim_display->add_controllable_preset("0dB", 0.0);
dim_display->add_controllable_preset("-3 dB", -3.0);
dim_display->add_controllable_preset("-6 dB", -6.0);
dim_display->add_controllable_preset("-12 dB", -12.0);
dim_display->add_controllable_preset("-20 dB", -20.0);
HBox* dim_packer = manage (new HBox);
dim_packer->show ();
spin_label = manage (new Label (_("Dim")));
spin_packer = manage (new VBox);
spin_packer->show ();
spin_packer->set_spacing (3);
spin_packer->pack_start (*spin_label, false, false);
spin_packer->pack_start (*dim_control, false, false);
spin_packer->pack_start (*dim_display, false, false);
dim_packer->pack_start (*spin_packer, true, false);
exclusive_solo_button.set_text (_("Excl. Solo"));
exclusive_solo_button.set_name (X_("monitor solo exclusive"));
ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
if (act) {
exclusive_solo_button.set_related_action (act);
}
solo_mute_override_button.set_text (_("Solo » Mute"));
solo_mute_override_button.set_name (X_("monitor solo override"));
ARDOUR_UI::instance()->set_tip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
if (act) {
solo_mute_override_button.set_related_action (act);
}
HBox* solo_opt_box = manage (new HBox);
solo_opt_box->set_spacing (12);
solo_opt_box->set_homogeneous (true);
solo_opt_box->pack_start (exclusive_solo_button);
solo_opt_box->pack_start (solo_mute_override_button);
solo_opt_box->show ();
upper_packer.set_spacing (6);
Gtk::HBox* rude_box = manage (new HBox);
rude_box->pack_start (rude_solo_button, true, true);
rude_box->pack_start (rude_iso_button, true, true);
upper_packer.pack_start (*rude_box, false, false);
upper_packer.pack_start (rude_audition_button, false, false);
upper_packer.pack_start (solo_model_box, false, false, 12);
upper_packer.pack_start (*solo_opt_box, false, false);
upper_packer.pack_start (*solo_packer, false, false, 12);
cut_all_button.set_text (_("Mute"));
cut_all_button.set_name ("monitor section cut");
cut_all_button.set_name (X_("monitor section cut"));
cut_all_button.set_size_request (-1,50);
cut_all_button.show ();
act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
if (act) {
cut_all_button.set_related_action (act);
}
dim_all_button.set_text (_("Dim"));
dim_all_button.set_name ("monitor section dim");
act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
if (act) {
dim_all_button.set_related_action (act);
}
mono_button.set_text (_("Mono"));
mono_button.set_name ("monitor section mono");
act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
if (act) {
mono_button.set_related_action (act);
}
HBox* bbox = manage (new HBox);
bbox->set_spacing (12);
bbox->pack_start (mono_button, true, true);
bbox->pack_start (dim_all_button, true, true);
lower_packer.set_spacing (12);
lower_packer.pack_start (*bbox, false, false);
lower_packer.pack_start (cut_all_button, false, false);
/* Gain */
gain_control = new ArdourKnob ();
gain_control->set_name("monitor knob");
gain_control->set_size_request(80,80);
gain_display = new ArdourDisplay ();
gain_display->set_name("monitor section cut");
gain_display->set_size_request(40,20);
gain_display->add_controllable_preset("0dB", 0.0);
gain_display->add_controllable_preset("-3 dB", -3.0);
gain_display->add_controllable_preset("-6 dB", -6.0);
gain_display->add_controllable_preset("-12 dB", -12.0);
gain_display->add_controllable_preset("-20 dB", -20.0);
gain_display->add_controllable_preset("-30 dB", -30.0);
spin_label = manage (new Label (_("Monitor")));
spin_packer = manage (new VBox);
spin_packer->show ();
spin_packer->set_spacing (3);
spin_packer->pack_start (*spin_label, false, false);
spin_packer->pack_start (*gain_control, false, false);
spin_packer->pack_start (*gain_display, false, false);
lower_packer.pack_start (*spin_packer, true, true);
channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
channel_table_scroller.set_size_request (-1, 150);
channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
channel_table_scroller.show ();
channel_table_scroller.add (channel_table_viewport);
channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
channel_size_group->add_widget (channel_table_header);
channel_size_group->add_widget (channel_table);
channel_table_header.resize (1, 5);
Label* l1 = manage (new Label (X_(" ")));
l1->set_name (X_("MonitorSectionLabel"));
channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
l1 = manage (new Label (X_("Mute")));
l1->set_name (X_("MonitorSectionLabel"));
channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
l1 = manage (new Label (X_("Dim")));
l1->set_name (X_("MonitorSectionLabel"));
channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
l1 = manage (new Label (X_("Solo")));
l1->set_name (X_("MonitorSectionLabel"));
channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
l1 = manage (new Label (X_("Inv")));
l1->set_name (X_("MonitorSectionLabel"));
channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
channel_table_header.show ();
table_hpacker.pack_start (channel_table, true, true);
/* note that we don't pack the table_hpacker till later
*/
vpacker.set_border_width (6);
vpacker.set_spacing (12);
vpacker.pack_start (upper_packer, false, false);
vpacker.pack_start (*dim_packer, false, false);
vpacker.pack_start (channel_table_header, false, false);
vpacker.pack_start (channel_table_packer, false, false);
vpacker.pack_start (lower_packer, false, false);
hpacker.pack_start (vpacker, true, true);
gain_control->show_all ();
gain_display->show_all ();
dim_control->show_all ();
dim_display->show_all();
solo_boost_control->show_all ();
solo_boost_display->show_all();
channel_table.show ();
hpacker.show ();
upper_packer.show ();
lower_packer.show ();
vpacker.show ();
populate_buttons ();
map_state ();
assign_controllables ();
_tearoff = new TearOff (hpacker);
/* if torn off, make this a normal window */
_tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
_tearoff->tearoff_window().set_title (X_("Monitor"));
_tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
/* catch changes that affect us */
Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
}
MonitorSection::~MonitorSection ()
{
for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
delete *i;
}
_channel_buttons.clear ();
delete gain_control;
delete gain_display;
delete dim_control;
delete dim_display;
delete solo_boost_control;
delete solo_boost_display;
delete solo_cut_control;
delete solo_cut_display;
delete _tearoff;
}
void
MonitorSection::set_session (Session* s)
{
AxisView::set_session (s);
if (_session) {
_route = _session->monitor_out ();
if (_route) {
/* session with monitor section */
_monitor = _route->monitor_control ();
assign_controllables ();
} else {
/* session with no monitor section */
_monitor.reset ();
_route.reset ();
}
if (channel_table_scroller.get_parent()) {
/* scroller is packed, so remove it */
channel_table_packer.remove (channel_table_scroller);
}
if (table_hpacker.get_parent () == &channel_table_packer) {
/* this occurs when the table hpacker is directly
packed, so remove it.
*/
channel_table_packer.remove (table_hpacker);
} else if (table_hpacker.get_parent()) {
channel_table_viewport.remove ();
}
if (_monitor->output_streams().n_audio() > 7) {
/* put the table into a scrolled window, and then put
* that into the channel vpacker, after the table header
*/
channel_table_viewport.add (table_hpacker);
channel_table_packer.pack_start (channel_table_scroller, true, true);
channel_table_viewport.show ();
channel_table_scroller.show ();
} else {
/* just put the channel table itself into the channel
* vpacker, after the table header
*/
channel_table_packer.pack_start (table_hpacker, true, true);
channel_table_scroller.hide ();
}
table_hpacker.show ();
channel_table.show ();
} else {
/* no session */
_monitor.reset ();
_route.reset ();
control_connections.drop_connections ();
rude_iso_button.unset_active_state ();
rude_solo_button.unset_active_state ();
assign_controllables ();
}
}
MonitorSection::ChannelButtonSet::ChannelButtonSet ()
{
cut.set_diameter (3);
dim.set_diameter (3);
solo.set_diameter (3);
invert.set_diameter (3);
cut.set_name (X_("monitor section cut"));
dim.set_name (X_("monitor section dim"));
solo.set_name (X_("monitor section solo"));
invert.set_name (X_("monitor section invert"));
cut.unset_flags (Gtk::CAN_FOCUS);
dim.unset_flags (Gtk::CAN_FOCUS);
solo.unset_flags (Gtk::CAN_FOCUS);
invert.unset_flags (Gtk::CAN_FOCUS);
}
void
MonitorSection::populate_buttons ()
{
if (!_monitor) {
return;
}
Glib::RefPtr<Action> act;
uint32_t nchans = _monitor->output_streams().n_audio();
channel_table.resize (nchans, 5);
channel_table.set_col_spacings (6);
channel_table.set_row_spacings (6);
channel_table.set_homogeneous (true);
const uint32_t row_offset = 0;
for (uint32_t i = 0; i < nchans; ++i) {
string l;
char buf[64];
if (nchans == 2) {
if (i == 0) {
l = "L";
} else {
l = "R";
}
} else {
char buf[32];
snprintf (buf, sizeof (buf), "%d", i+1);
l = buf;
}
Label* label = manage (new Label (l));
channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
ChannelButtonSet* cbs = new ChannelButtonSet;
_channel_buttons.push_back (cbs);
channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
act = ActionManager::get_action (X_("Monitor"), buf);
if (act) {
cbs->cut.set_related_action (act);
}
snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
act = ActionManager::get_action (X_("Monitor"), buf);
if (act) {
cbs->dim.set_related_action (act);
}
snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
act = ActionManager::get_action (X_("Monitor"), buf);
if (act) {
cbs->solo.set_related_action (act);
}
snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
act = ActionManager::get_action (X_("Monitor"), buf);
if (act) {
cbs->invert.set_related_action (act);
}
}
channel_table.show_all ();
}
void
MonitorSection::toggle_exclusive_solo ()
{
if (!_monitor) {
return;
}
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
Config->set_exclusive_solo (tact->get_active());
}
}
void
MonitorSection::toggle_mute_overrides_solo ()
{
if (!_monitor) {
return;
}
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
Config->set_solo_mute_override (tact->get_active());
}
}
void
MonitorSection::dim_all ()
{
if (!_monitor) {
return;
}
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
_monitor->set_dim_all (tact->get_active());
}
}
void
MonitorSection::cut_all ()
{
if (!_monitor) {
return;
}
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
_monitor->set_cut_all (tact->get_active());
}
}
void
MonitorSection::mono ()
{
if (!_monitor) {
return;
}
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
_monitor->set_mono (tact->get_active());
}
}
void
MonitorSection::cut_channel (uint32_t chn)
{
if (!_monitor) {
return;
}
char buf[64];
snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
--chn; // 0-based in backend
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
_monitor->set_cut (chn, tact->get_active());
}
}
void
MonitorSection::dim_channel (uint32_t chn)
{
if (!_monitor) {
return;
}
char buf[64];
snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
--chn; // 0-based in backend
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
_monitor->set_dim (chn, tact->get_active());
}
}
void
MonitorSection::solo_channel (uint32_t chn)
{
if (!_monitor) {
return;
}
char buf[64];
snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
--chn; // 0-based in backend
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
_monitor->set_solo (chn, tact->get_active());
}
}
void
MonitorSection::invert_channel (uint32_t chn)
{
if (!_monitor) {
return;
}
char buf[64];
snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
--chn; // 0-based in backend
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
_monitor->set_polarity (chn, tact->get_active());
}
}
void
MonitorSection::register_actions ()
{
string action_name;
string action_descr;
Glib::RefPtr<Action> act;
monitor_actions = ActionGroup::create (X_("Monitor"));
ActionManager::add_action_group (monitor_actions);
ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
sigc::mem_fun (*this, &MonitorSection::mono));
ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
sigc::mem_fun (*this, &MonitorSection::cut_all));
ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
sigc::mem_fun (*this, &MonitorSection::dim_all));
act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
tact->set_active (Config->get_exclusive_solo());
act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
tact->set_active (Config->get_solo_mute_override());
/* note the 1-based counting (for naming - backend uses 0-based) */
for (uint32_t chn = 1; chn <= 16; ++chn) {
action_name = string_compose (X_("monitor-cut-%1"), chn);
action_descr = string_compose (_("Cut monitor channel %1"), chn);
ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
action_name = string_compose (X_("monitor-dim-%1"), chn);
action_descr = string_compose (_("Dim monitor channel %1"), chn);
ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
action_name = string_compose (X_("monitor-solo-%1"), chn);
action_descr = string_compose (_("Solo monitor channel %1"), chn);
ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
action_name = string_compose (X_("monitor-invert-%1"), chn);
action_descr = string_compose (_("Invert monitor channel %1"), chn);
ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
}
Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
RadioAction::Group solo_group;
ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
ActionManager::add_action_group (solo_actions);
}
void
MonitorSection::solo_use_in_place ()
{
/* this is driven by a toggle on a radio group, and so is invoked twice,
once for the item that became inactive and once for the one that became
active.
*/
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
if (act) {
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
if (ract) {
if (!ract->get_active ()) {
/* We are turning SiP off, which means that AFL or PFL will be turned on
shortly; don't update the solo model in the mean time, as if the currently
configured listen position is not the one that is about to be turned on,
things will go wrong.
*/
_inhibit_solo_model_update = true;
}
Config->set_solo_control_is_listen_control (!ract->get_active());
_inhibit_solo_model_update = false;
}
}
}
void
MonitorSection::solo_use_afl ()
{
/* this is driven by a toggle on a radio group, and so is invoked twice,
once for the item that became inactive and once for the one that became
active.
*/
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
if (act) {
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
if (ract) {
if (ract->get_active()) {
Config->set_solo_control_is_listen_control (true);
Config->set_listen_position (AfterFaderListen);
}
}
}
}
void
MonitorSection::solo_use_pfl ()
{
/* this is driven by a toggle on a radio group, and so is invoked twice,
once for the item that became inactive and once for the one that became
active.
*/
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
if (act) {
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
if (ract) {
if (ract->get_active()) {
Config->set_solo_control_is_listen_control (true);
Config->set_listen_position (PreFaderListen);
}
}
}
}
void
MonitorSection::setup_knob_images ()
{
try {
uint32_t c = ARDOUR_UI::config()->color_by_name ("monitor knob");
char buf[16];
snprintf (buf, 16, "#%x", (c >> 8));
MotionFeedback::set_lamp_color (buf);
big_knob_pixbuf = MotionFeedback::render_pixbuf (80);
} catch (...) {
error << "No usable large knob image" << endmsg;
throw failed_constructor ();
}
if (!big_knob_pixbuf) {
error << "No usable large knob image" << endmsg;
throw failed_constructor ();
}
try {
little_knob_pixbuf = MotionFeedback::render_pixbuf (30);
} catch (...) {
error << "No usable small knob image" << endmsg;
throw failed_constructor ();
}
if (!little_knob_pixbuf) {
error << "No usable small knob image" << endmsg;
throw failed_constructor ();
}
}
void
MonitorSection::update_solo_model ()
{
if (_inhibit_solo_model_update) {
return;
}
const char* action_name = 0;
Glib::RefPtr<Action> act;
if (Config->get_solo_control_is_listen_control()) {
switch (Config->get_listen_position()) {
case AfterFaderListen:
action_name = X_("solo-use-afl");
break;
case PreFaderListen:
action_name = X_("solo-use-pfl");
break;
}
} else {
action_name = X_("solo-use-in-place");
}
act = ActionManager::get_action (X_("Solo"), action_name);
if (act) {
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
if (ract) {
/* because these are radio buttons, one of them will be
active no matter what. to trigger a change in the
action so that the view picks it up, toggle it.
*/
if (ract->get_active()) {
ract->set_active (false);
}
ract->set_active (true);
}
}
}
void
MonitorSection::map_state ()
{
if (!_route || !_monitor) {
return;
}
Glib::RefPtr<Action> act;
update_solo_model ();
act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
if (tact) {
tact->set_active (_monitor->cut_all());
}
}
act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
if (tact) {
tact->set_active (_monitor->dim_all());
}
}
act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
if (tact) {
tact->set_active (_monitor->mono());
}
}
uint32_t nchans = _monitor->output_streams().n_audio();
assert (nchans == _channel_buttons.size ());
for (uint32_t n = 0; n < nchans; ++n) {
char action_name[32];
snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
act = ActionManager::get_action (X_("Monitor"), action_name);
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
if (tact) {
tact->set_active (_monitor->cut (n));
}
}
snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
act = ActionManager::get_action (X_("Monitor"), action_name);
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
if (tact) {
tact->set_active (_monitor->dimmed (n));
}
}
snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
act = ActionManager::get_action (X_("Monitor"), action_name);
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
if (tact) {
tact->set_active (_monitor->soloed (n));
}
}
snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
act = ActionManager::get_action (X_("Monitor"), action_name);
if (act) {
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
if (tact) {
tact->set_active (_monitor->inverted (n));
}
}
}
}
void
MonitorSection::do_blink (bool onoff)
{
solo_blink (onoff);
audition_blink (onoff);
}
void
MonitorSection::audition_blink (bool onoff)
{
if (_session == 0) {
return;
}
if (_session->is_auditioning()) {
rude_audition_button.set_active (onoff);
} else {
rude_audition_button.set_active (false);
}
}
void
MonitorSection::solo_blink (bool onoff)
{
if (_session == 0) {
return;
}
if (_session->soloing() || _session->listening()) {
rude_solo_button.set_active (onoff);
if (_session->soloing()) {
if (_session->solo_isolated()) {
rude_iso_button.set_active (false);
}
}
} else {
rude_solo_button.set_active (false);
rude_iso_button.set_active (false);
}
}
bool
MonitorSection::cancel_solo (GdkEventButton*)
{
if (_session) {
if (_session->soloing()) {
_session->set_solo (_session->get_routes(), false);
} else if (_session->listening()) {
_session->set_listen (_session->get_routes(), false);
}
}
return true;
}
bool
MonitorSection::cancel_isolate (GdkEventButton*)
{
if (_session) {
boost::shared_ptr<RouteList> rl (_session->get_routes ());
_session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
}
return true;
}
bool
MonitorSection::cancel_audition (GdkEventButton*)
{
if (_session) {
_session->cancel_audition();
}
return true;
}
void
MonitorSection::parameter_changed (std::string name)
{
if (name == "solo-control-is-listen-control") {
update_solo_model ();
} else if (name == "listen-position") {
update_solo_model ();
}
}
void
MonitorSection::assign_controllables ()
{
boost::shared_ptr<Controllable> none;
if (!gain_control) {
/* too early - GUI controls not set up yet */
return;
}
if (_session) {
solo_cut_control->set_controllable (_session->solo_cut_control());
solo_cut_display->set_controllable (_session->solo_cut_control());
} else {
solo_cut_control->set_controllable (none);
solo_cut_display->set_controllable (none);
}
if (_route) {
gain_control->set_controllable (_route->gain_control());
gain_display->set_controllable (_route->gain_control());
} else {
gain_control->set_controllable (none);
}
if (_monitor) {
cut_all_button.set_controllable (_monitor->cut_control());
cut_all_button.watch ();
dim_all_button.set_controllable (_monitor->dim_control());
dim_all_button.watch ();
mono_button.set_controllable (_monitor->mono_control());
mono_button.watch ();
dim_control->set_controllable (_monitor->dim_level_control ());
dim_display->set_controllable (_monitor->dim_level_control ());
solo_boost_control->set_controllable (_monitor->solo_boost_control ());
solo_boost_display->set_controllable (_monitor->solo_boost_control ());
} else {
cut_all_button.set_controllable (none);
dim_all_button.set_controllable (none);
mono_button.set_controllable (none);
dim_control->set_controllable (none);
dim_display->set_controllable (none);
solo_boost_control->set_controllable (none);
solo_boost_display->set_controllable (none);
}
}
string
MonitorSection::state_id() const
{
return "monitor-section";
}