1 #include <gdkmm/pixbuf.h>
3 #include "pbd/compose.h"
6 #include "gtkmm2ext/bindable_button.h"
7 #include "gtkmm2ext/tearoff.h"
8 #include "gtkmm2ext/actions.h"
10 #include "ardour/dB.h"
11 #include "ardour/monitor_processor.h"
12 #include "ardour/route.h"
13 #include "ardour/utils.h"
15 #include "monitor_section.h"
17 #include "volume_controller.h"
21 using namespace ARDOUR;
23 using namespace Gtkmm2ext;
27 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
28 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
29 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
31 MonitorSection::MonitorSection (Session* s)
37 , gain_adjustment (1.0, 0.0, 2.0, 0.01, 0.1)
39 , dim_adjustment (0.2, 0.0, 1.0, 0.01, 0.1)
41 , solo_boost_adjustment (1.0, 1.0, 2.0, 0.01, 0.1)
42 , solo_boost_control (0)
43 , solo_in_place_button (solo_model_group, _("SiP"))
44 , afl_button (solo_model_group, _("AFL"))
45 , pfl_button (solo_model_group, _("PFL"))
46 , cut_all_button (_("MUTE"))
47 , dim_all_button (_("DIM"))
50 Glib::RefPtr<Action> act;
52 if (!monitor_actions) {
54 /* do some static stuff */
60 _route = _session->control_out ();
63 throw failed_constructor ();
66 _monitor = _route->monitor_control ();
69 throw failed_constructor ();
72 HBox* sub_knob_packer = manage (new HBox);
73 sub_knob_packer->set_spacing (12);
78 gain_control = new VolumeController (big_knob_pixbuf, &gain_adjustment, true);
79 gain_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MonitorSection::gain_value_changed));
80 gain_control->spinner().signal_output().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::nonlinear_gain_printer),
81 &gain_control->spinner()));
83 HBox* center_gain_control = manage (new HBox);
84 center_gain_control->pack_start (*gain_control, true, true);
86 spin_label = manage (new Label (_("Gain (dB)")));
87 spin_packer = manage (new VBox);
88 spin_packer->set_spacing (6);
89 spin_packer->pack_start (*center_gain_control, false, false);
90 spin_packer->pack_start (*spin_label, false, false);
92 knob_packer.pack_start (*spin_packer, false, false);
94 dim_control = new VolumeController (little_knob_pixbuf, &dim_adjustment, true, 30, 30);
95 dim_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MonitorSection::dim_level_changed));
96 dim_control->spinner().signal_output().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::linear_gain_printer),
97 &dim_control->spinner()));
99 spin_label = manage (new Label (_("Dim Cut (dB)")));
100 spin_packer = manage (new VBox);
101 spin_packer->set_spacing (6);
102 spin_packer->pack_start (*dim_control, false, false);
103 spin_packer->pack_start (*spin_label, false, false);
105 sub_knob_packer->pack_start (*spin_packer, false, true);
107 solo_boost_control = new VolumeController (little_knob_pixbuf, &solo_boost_adjustment, true, 30, 30);
108 solo_boost_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &MonitorSection::solo_boost_changed));
109 solo_boost_control->spinner().signal_output().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::linear_gain_printer),
110 &solo_boost_control->spinner()));
112 spin_label = manage (new Label (_("Solo Boost (dB)")));
113 spin_packer = manage (new VBox);
114 spin_packer->set_spacing (6);
115 spin_packer->pack_start (*solo_boost_control, false, false);
116 spin_packer->pack_start (*spin_label, false, false);
118 sub_knob_packer->pack_start (*spin_packer, false, true);
120 knob_packer.pack_start (*sub_knob_packer, false, true);
122 sub_knob_packer->show ();
124 gain_control->show_all ();
125 dim_control->show_all ();
126 solo_boost_control->show_all ();
128 meter.set_meter (&_route->peak_meter());
129 meter.setup_meters (300, 5);
131 table_knob_packer.pack_start (main_table, true, true);
132 table_knob_packer.pack_start (knob_packer, false, false);
134 table_knob_packer.show ();
136 solo_model_box.set_spacing (12);
137 solo_model_box.pack_start (solo_in_place_button, false, false);
138 solo_model_box.pack_start (afl_button, false, false);
139 solo_model_box.pack_start (pfl_button, false, false);
141 solo_in_place_button.show ();
144 solo_model_box.show ();
146 upper_packer.pack_start (solo_model_box, false, false);
148 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
150 act->connect_proxy (cut_all_button);
153 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
155 act->connect_proxy (dim_all_button);
158 cut_all_button.show ();
159 dim_all_button.show ();
161 lower_packer.pack_start (dim_all_button, false, false);
162 lower_packer.pack_start (cut_all_button, false, false);
164 vpacker.set_border_width (12);
165 vpacker.set_spacing (12);
166 vpacker.pack_start (upper_packer, false, false);
167 vpacker.pack_start (table_knob_packer, false, false);
168 vpacker.pack_start (lower_packer, false, false);
170 VBox* keep_meter_under_control = manage (new VBox);
171 keep_meter_under_control->pack_start (meter, false, false);
172 keep_meter_under_control->show ();
174 hpacker.set_border_width (12);
175 hpacker.set_spacing (12);
176 hpacker.pack_start (*keep_meter_under_control, false, false);
177 hpacker.pack_start (vpacker, true, true);
181 upper_packer.show ();
182 lower_packer.show ();
189 _tearoff = new TearOff (hpacker);
190 /* if torn off, make this a normal window */
191 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
192 _tearoff->tearoff_window().set_title (X_("Monitor"));
195 MonitorSection::~MonitorSection ()
200 delete solo_boost_control;
204 MonitorSection::populate_buttons ()
206 Glib::RefPtr<Action> act;
207 uint32_t nchans = _route->monitor_control()->output_streams().n_audio();
209 main_table.resize (nchans+1, 5);
210 main_table.set_col_spacings (6);
211 main_table.set_row_spacings (6);
212 main_table.set_homogeneous (true);
214 Label* l1 = manage (new Label (X_("out")));
215 main_table.attach (*l1, 0, 1, 0, 1, SHRINK|FILL, SHRINK|FILL);
216 l1 = manage (new Label (X_("cut")));
217 main_table.attach (*l1, 1, 2, 0, 1, SHRINK|FILL, SHRINK|FILL);
218 l1 = manage (new Label (X_("dim")));
219 main_table.attach (*l1, 2, 3, 0, 1, SHRINK|FILL, SHRINK|FILL);
220 l1 = manage (new Label (X_("solo")));
221 main_table.attach (*l1, 3, 4, 0, 1, SHRINK|FILL, SHRINK|FILL);
222 l1 = manage (new Label (X_("inv")));
223 main_table.attach (*l1, 4, 5, 0, 1, SHRINK|FILL, SHRINK|FILL);
226 /* the "all" buttons for cut & dim */
228 Label *la = manage (new Label (X_("all")));
229 main_table.attach (*la, 0, 1, 1, 2, SHRINK|FILL, SHRINK|FILL);
234 BindableToggleButton* ca = manage (new BindableToggleButton (X_("")));
235 ca->set_name (X_("MixerMuteButton"));
236 gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (ca->gobj()), false);
237 main_table.attach (*ca, 1, 2, 1, 2, SHRINK|FILL, SHRINK|FILL);
239 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
241 act->connect_proxy (*ca);
246 BindableToggleButton* da = manage (new BindableToggleButton (X_("")));
247 da->set_name (X_("MixerMuteButton"));
248 gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (da->gobj()), false);
249 main_table.attach (*da, 2, 3, 1, 2, SHRINK|FILL, SHRINK|FILL);
251 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
253 act->connect_proxy (*da);
256 uint32_t row_offset = 2;
258 uint32_t row_offset = 1;
261 for (uint32_t i = 0; i < nchans; ++i) {
274 snprintf (buf, sizeof (buf), "%d", i+1);
278 Label* c1 = manage (new Label (l));
279 main_table.attach (*c1, 0, 1, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
283 BindableToggleButton* c2 = manage (new BindableToggleButton (X_("")));
284 c2->set_name (X_("MixerMuteButton"));
285 gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (c2->gobj()), false);
286 main_table.attach (*c2, 1, 2, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
288 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
289 act = ActionManager::get_action (X_("Monitor"), buf);
291 act->connect_proxy (*c2);
296 BindableToggleButton* c3 = manage (new BindableToggleButton (X_("")));
297 c3->set_name (X_("MixerMuteButton"));
298 gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (c2->gobj()), false);
299 main_table.attach (*c3, 2, 3, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
301 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
302 act = ActionManager::get_action (X_("Monitor"), buf);
304 act->connect_proxy (*c3);
309 BindableToggleButton* c4 = manage (new BindableToggleButton (X_("")));
310 c4->set_name (X_("MixerSoloButton"));
311 gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (c2->gobj()), false);
312 main_table.attach (*c4, 3, 4, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
314 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
315 act = ActionManager::get_action (X_("Monitor"), buf);
317 act->connect_proxy (*c4);
320 /* Invert (Polarity/Phase) */
322 BindableToggleButton* c5 = manage (new BindableToggleButton (X_("")));
323 c5->set_name (X_("MixerPhaseInvertButton"));
324 gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (c2->gobj()), false);
325 main_table.attach (*c5, 4, 5, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
327 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
328 act = ActionManager::get_action (X_("Monitor"), buf);
330 act->connect_proxy (*c5);
335 main_table.show_all ();
339 MonitorSection::set_button_names ()
341 rec_enable_button_label.set_text ("rec");
342 mute_button_label.set_text ("rec");
343 solo_button_label.set_text ("rec");
347 MonitorSection::pack_widget () const
353 MonitorSection::dim_all ()
355 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
357 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
358 _monitor->set_dim_all (tact->get_active());
364 MonitorSection::cut_all ()
366 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
368 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
369 _monitor->set_cut_all (tact->get_active());
374 MonitorSection::cut_channel (uint32_t chn)
377 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
379 --chn; // 0-based in backend
381 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
383 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
384 _monitor->set_cut (chn, tact->get_active());
389 MonitorSection::dim_channel (uint32_t chn)
392 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
394 --chn; // 0-based in backend
396 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
398 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
399 _monitor->set_dim (chn, tact->get_active());
405 MonitorSection::solo_channel (uint32_t chn)
408 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
410 --chn; // 0-based in backend
412 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
414 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
415 _monitor->set_solo (chn, tact->get_active());
421 MonitorSection::invert_channel (uint32_t chn)
425 --chn; // 0-based in backend
427 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
428 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
430 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
431 _monitor->set_polarity (chn, tact->get_active());
437 MonitorSection::register_actions ()
442 monitor_actions = ActionGroup::create (X_("Monitor"));
443 ActionManager::add_action_group (monitor_actions);
445 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "",
446 sigc::mem_fun (*this, &MonitorSection::cut_all));
448 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "",
449 sigc::mem_fun (*this, &MonitorSection::dim_all));
451 /* note the 1-based counting for naming vs. 0-based for action */
453 for (uint32_t chn = 1; chn <= 16; ++chn) {
455 /* for the time being, do not use the action description because it always
456 shows up in the buttons, which is undesirable.
459 action_name = string_compose (X_("monitor-cut-%1"), chn);
460 action_descr = string_compose (_("Cut Monitor Chn %1"), chn);
461 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "",
462 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
464 action_name = string_compose (X_("monitor-dim-%1"), chn);
465 action_descr = string_compose (_("Dim Monitor Chn %1"), chn+1);
466 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "",
467 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
469 action_name = string_compose (X_("monitor-solo-%1"), chn);
470 action_descr = string_compose (_("Solo Monitor Chn %1"), chn);
471 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "",
472 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
474 action_name = string_compose (X_("monitor-invert-%1"), chn);
475 action_descr = string_compose (_("Invert Monitor Chn %1"), chn);
476 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "",
477 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
483 MonitorSection::fast_update ()
485 meter.update_meters ();
489 MonitorSection::setup_knob_images ()
493 big_knob_pixbuf = ::get_icon ("knob");
497 error << "No knob image found (or not loadable) at "
500 throw failed_constructor ();
505 little_knob_pixbuf = ::get_icon ("littleknob");
509 error << "No knob image found (or not loadable) at "
512 throw failed_constructor ();
517 MonitorSection::gain_value_changed ()
519 _route->set_gain (slider_position_to_gain (gain_adjustment.get_value()), this);
523 MonitorSection::dim_level_changed ()
525 _monitor->set_dim_level (dim_adjustment.get_value());
529 MonitorSection::solo_boost_changed ()
531 _monitor->set_solo_boost_level (solo_boost_adjustment.get_value());
535 MonitorSection::nonlinear_gain_printer (SpinButton* button)
537 double val = button->get_adjustment()->get_value();
539 snprintf (buf, sizeof (buf), "%.1f", accurate_coefficient_to_dB (slider_position_to_gain (val)));
540 button->set_text (buf);
545 MonitorSection::linear_gain_printer (SpinButton* button)
547 double val = button->get_adjustment()->get_value();
549 snprintf (buf, sizeof (buf), "%.1f", accurate_coefficient_to_dB (val));
550 button->set_text (buf);
555 MonitorSection::map_state ()
557 cerr << "route gain = " << _route->gain_control()->get_value() << endl;
559 gain_control->get_adjustment()->set_value (gain_to_slider_position (_route->gain_control()->get_value()));
560 dim_control->get_adjustment()->set_value (_monitor->dim_level());
561 solo_boost_control->get_adjustment()->set_value (_monitor->solo_boost_level());