diff --git a/gtk2_ardour/port_insert_ui.cc b/gtk2_ardour/port_insert_ui.cc index 0046bcb6de..f32e200a1b 100644 --- a/gtk2_ardour/port_insert_ui.cc +++ b/gtk2_ardour/port_insert_ui.cc @@ -24,69 +24,183 @@ #include #include +#include "gtkmm2ext/keyboard.h" + #include "ardour/audioengine.h" #include "ardour/mtdm.h" #include "ardour/port_insert.h" #include "ardour/session.h" -#include "gtkmm2ext/doi.h" +#include "widgets/binding_proxy.h" -#include "port_insert_ui.h" +#include "context_menu_helper.h" #include "gui_thread.h" +#include "latency_gui.h" +#include "port_insert_ui.h" +#include "timers.h" +#include "utils.h" + #include "pbd/i18n.h" using namespace ARDOUR; -using namespace Gtk; PortInsertUI::PortInsertUI (Gtk::Window* parent, ARDOUR::Session* sess, boost::shared_ptr pi) : _pi (pi) - , latency_button (_("Measure Latency")) - , input_selector (parent, sess, pi->input()) - , output_selector (parent, sess, pi->output()) + , _measure_latency_button (_("Measure Latency")) + , _invert_button (X_("Ø")) + , _input_selector (parent, sess, pi->input ()) + , _output_selector (parent, sess, pi->output ()) + , _input_gpm (sess, 250) + , _output_gpm (sess, 250) + , _parent (parent) + , _latency_gui (0) + , _latency_dialog (0) { - latency_hbox.pack_start (latency_button, false, false); - latency_hbox.pack_start (latency_display, false, false); - latency_hbox.set_spacing (4); + _latency_hbox.pack_start (_measure_latency_button, false, false); + _latency_hbox.pack_start (_edit_latency_button, false, false); + _latency_hbox.pack_start (_latency_display, false, false); + _latency_hbox.set_spacing (4); - output_selector.set_min_height_divisor (2); - input_selector.set_min_height_divisor (2); + _output_selector.set_min_height_divisor (2); + _input_selector.set_min_height_divisor (2); - notebook.append_page (output_selector, _("Send/Output")); - notebook.append_page (input_selector, _("Return/Input")); + _input_vbox.pack_start (_input_gpm, false, false); + _input_vbox.set_spacing (4); + _input_vbox.set_border_width (4); - notebook.set_current_page (0); + _input_hbox.pack_start (_input_vbox, false, false); + _input_hbox.pack_start (_input_selector, true, true); + + _output_vbox.pack_start (_output_gpm, false, false); + _output_vbox.pack_start (_invert_button, false, false); + _output_vbox.set_spacing (4); + _output_vbox.set_border_width (4); + + _output_hbox.pack_start (_output_vbox, false, false); + _output_hbox.pack_start (_output_selector, true, true); + + _notebook.append_page (_output_hbox, _("Send/Output")); + _notebook.append_page (_input_hbox, _("Return/Input")); + + _notebook.set_current_page (0); set_spacing (12); - pack_start (notebook, true, true); - pack_start (latency_hbox, false, false); + pack_start (_notebook, true, true); + pack_start (_latency_hbox, false, false); - update_latency_display (); + _invert_button.set_controllable (_pi->send_polarity_control ()); + _invert_button.watch (); + _invert_button.set_name (X_("invert button")); + _invert_button.signal_button_press_event ().connect (sigc::mem_fun (*this, &PortInsertUI::invert_press), false); + _invert_button.signal_button_release_event ().connect (sigc::mem_fun (*this, &PortInsertUI::invert_release), false); - latency_button.signal_toggled().connect (mem_fun (*this, &PortInsertUI::latency_button_toggled)); - latency_button.set_name (X_("MeasureLatencyButton")); + _edit_latency_button.set_icon (ArdourWidgets::ArdourIcon::LatencyClock); + _edit_latency_button.add_elements (ArdourWidgets::ArdourButton::Text); + _edit_latency_button.signal_clicked.connect (sigc::mem_fun (*this, &PortInsertUI::edit_latency_button_clicked)); + + _measure_latency_button.set_name (X_("MeasureLatencyButton")); + _measure_latency_button.signal_toggled ().connect (mem_fun (*this, &PortInsertUI::latency_button_toggled)); + _measure_latency_button.signal_button_press_event ().connect (sigc::mem_fun (*this, &PortInsertUI::measure_latency_press), false); + + _input_gpm.setup_meters (); + _input_gpm.set_fader_name (X_("SendUIFader")); + _input_gpm.set_controls (boost::shared_ptr (), _pi->return_meter (), _pi->return_amp (), _pi->return_gain_control ()); + + _output_gpm.setup_meters (); + _output_gpm.set_fader_name (X_("SendUIFader")); + _output_gpm.set_controls (boost::shared_ptr (), _pi->send_meter (), _pi->send_amp (), _pi->send_gain_control ()); + + Gtkmm2ext::UI::instance ()->set_tip (_invert_button, _("Click to invert polarity of all send channels")); + Gtkmm2ext::UI::instance ()->set_tip (_edit_latency_button, _("Edit Latency, manually override measured or I/O reported latency")); + Gtkmm2ext::UI::instance ()->set_tip (_measure_latency_button, _("Measure Latency using the first port of each direction\n(note that gain is not applied during measurement).\nRight-click to forget previous meaurements,\nand revert to use default port latency.")); + + _pi->set_metering (true); + _pi->input ()->changed.connect (_connections, invalidator (*this), boost::bind (&PortInsertUI::return_changed, this, _1, _2), gui_context ()); + _pi->output ()->changed.connect (_connections, invalidator (*this), boost::bind (&PortInsertUI::send_changed, this, _1, _2), gui_context ()); + _pi->LatencyChanged.connect (_connections, invalidator (*this), boost::bind (&PortInsertUI::set_latency_label, this), gui_context ()); + + _fast_screen_update_connection = Timers::super_rapid_connect (sigc::mem_fun (*this, &PortInsertUI::fast_update)); + + set_latency_label (); + set_measured_status (NULL); + show_all (); +} + +PortInsertUI::~PortInsertUI () +{ + _pi->set_metering (false); + _fast_screen_update_connection.disconnect (); + delete _latency_gui; + delete _latency_dialog; } void -PortInsertUI::update_latency_display () +PortInsertUI::send_changed (IOChange change, void* /*ignored*/) { - samplecnt_t const sample_rate = AudioEngine::instance()->sample_rate(); - if (sample_rate == 0) { - latency_display.set_text (_("Disconnected from audio engine")); - } else { - char buf[64]; - snprintf (buf, sizeof (buf), "%10.3lf samples %10.3lf ms", - (float)_pi->latency(), (float)_pi->latency() * 1000.0f/sample_rate); - latency_display.set_text(buf); + ENSURE_GUI_THREAD (*this, &PortInsertUI::outs_changed, change, ignored); + if (change.type & IOChange::ConfigurationChanged) { + _output_gpm.setup_meters (); } } +void +PortInsertUI::return_changed (IOChange change, void* /*ignored*/) +{ + ENSURE_GUI_THREAD (*this, &PortInsertUI::outs_changed, change, ignored); + if (change.type & IOChange::ConfigurationChanged) { + _input_gpm.setup_meters (); + } +} + +void +PortInsertUI::fast_update () +{ + if (!get_mapped ()) { + return; + } + + if (Config->get_meter_falloff () > 0.0f) { + _input_gpm.update_meters (); + _output_gpm.update_meters (); + } +} + +bool +PortInsertUI::invert_press (GdkEventButton* ev) +{ + if (ArdourWidgets::BindingProxy::is_bind_action (ev)) { + return false; + } + + if (ev->button != 1 || ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) { + return true; + } + + boost::shared_ptr ac = _pi->send_polarity_control (); + ac->start_touch (timepos_t (ac->session ().audible_sample ())); + return true; +} + +bool +PortInsertUI::invert_release (GdkEventButton* ev) +{ + if (ev->button != 1 || ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) { + return true; + } + + boost::shared_ptr ac = _pi->send_polarity_control (); + ac->set_value (_invert_button.get_active () ? 0 : 1, PBD::Controllable::NoGroup); + ac->stop_touch (timepos_t (ac->session ().audible_sample ())); + return true; +} + bool PortInsertUI::check_latency_measurement () { MTDM* mtdm = _pi->mtdm (); if (mtdm->resolve () < 0) { - latency_display.set_text (_("No signal detected")); + _latency_display.set_text (_("No signal detected")); return true; } @@ -95,118 +209,132 @@ PortInsertUI::check_latency_measurement () mtdm->resolve (); } - char buf[128]; - samplecnt_t const sample_rate = AudioEngine::instance()->sample_rate(); + samplecnt_t const sample_rate = AudioEngine::instance ()->sample_rate (); if (sample_rate == 0) { - latency_display.set_text (_("Disconnected from audio engine")); + _latency_display.set_text (_("Disconnected from audio engine")); _pi->stop_latency_detection (); return false; } - snprintf (buf, sizeof (buf), "%10.3lf samples %10.3lf ms", mtdm->del (), mtdm->del () * 1000.0f/sample_rate); - - bool solid = true; - - if (mtdm->err () > 0.2) { - strcat (buf, " ??"); - solid = false; + if (!(mtdm->err () > 0.2 || mtdm->inv ())) { + _pi->unset_user_latency (); + _pi->set_measured_latency (rint (mtdm->del ())); + _measure_latency_button.set_active (false); } - if (mtdm->inv ()) { - strcat (buf, " (Inv)"); - solid = false; - } - - if (solid) { - _pi->set_measured_latency (rint (mtdm->del())); - latency_button.set_active (false); - strcat (buf, " (set)"); - } - - latency_display.set_text (buf); - + set_measured_status (mtdm); return true; } +void +PortInsertUI::forget_measuremed_latency () +{ + _measure_latency_button.set_active (false); + _pi->stop_latency_detection (); + _pi->set_measured_latency (0); + set_measured_status (NULL); +} + +void +PortInsertUI::set_latency_label () +{ + samplecnt_t const l = _pi->effective_latency (); + float const sr = _pi->session ().sample_rate (); + + _edit_latency_button.set_text (ARDOUR_UI_UTILS::samples_as_time_string (l, sr, true)); + + if (_latency_gui) { + _latency_gui->refresh (); + } +} + +void +PortInsertUI::set_measured_status (MTDM* mtdm) +{ + samplecnt_t const ml = _pi->measured_latency (); + float const sr = _pi->session ().sample_rate (); + if (sr <= 0 || ml <= 0) { + _latency_display.set_text (""); + return; + } + + bool set = false; + if (mtdm && ! (mtdm->err () > 0.2 || mtdm->inv ())) { + set = true; + } + + char buf[256]; + snprintf (buf, sizeof (buf), "%s %ld spl = %.2f ms%s%s%s", + mtdm ? _("Measured:") : _("Previously measured:"), + ml, + ml * 1000.0f / sr, + mtdm && mtdm->err () > 0.2 ? _(" (err)") : "", + mtdm && mtdm->inv () ? _(" (inv)") : "", + set ? _(" (set)") : "" + ); + + _latency_display.set_text (buf); +} + +void +PortInsertUI::edit_latency_button_clicked () +{ + assert (_pi); + if (!_latency_gui) { + _latency_gui = new LatencyGUI (*(_pi.get ()), _pi->session ().sample_rate (), _pi->session ().get_block_size ()); + _latency_dialog = new ArdourWindow (_("Edit Latency")); + /* use both keep-above and transient for to try cover as many + different WM's as possible. + */ + _latency_dialog->set_keep_above (true); + _latency_dialog->set_transient_for (*_parent); + _latency_dialog->add (*_latency_gui); + } + + _latency_gui->refresh (); + _latency_dialog->show_all (); +} + +bool +PortInsertUI::measure_latency_press (GdkEventButton* ev) +{ + if (Gtkmm2ext::Keyboard::is_context_menu_event (ev)) { + using namespace Gtk::Menu_Helpers; + Gtk::Menu* menu = ARDOUR_UI_UTILS::shared_popup_menu (); + MenuList& items = menu->items (); + items.push_back (MenuElem (_("Forget previous measurement"), sigc::mem_fun (*this, &PortInsertUI::forget_measuremed_latency))); + menu->popup (ev->button, ev->time); + return true; + } + return false; +} + void PortInsertUI::latency_button_toggled () { - if (latency_button.get_active ()) { - + if (_measure_latency_button.get_active ()) { _pi->start_latency_detection (); - latency_display.set_text (_("Detecting ...")); - latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &PortInsertUI::check_latency_measurement), 250); - + _latency_display.set_text (_("Detecting ...")); + _latency_timeout = Glib::signal_timeout ().connect (mem_fun (*this, &PortInsertUI::check_latency_measurement), 250); } else { _pi->stop_latency_detection (); - latency_timeout.disconnect (); - update_latency_display (); + _latency_timeout.disconnect (); + set_measured_status (NULL); } } -void -PortInsertUI::redisplay () -{ - input_selector.setup_ports (input_selector.other()); - output_selector.setup_ports (output_selector.other()); -} - void PortInsertUI::finished (IOSelector::Result r) { - input_selector.Finished (r); - output_selector.Finished (r); + _input_selector.Finished (r); + _output_selector.Finished (r); } - -PortInsertWindow::PortInsertWindow (ARDOUR::Session* sess, boost::shared_ptr pi) - : ArdourDialog ("port insert dialog"), - _portinsertui (this, sess, pi) +PortInsertWindow::PortInsertWindow (Gtk::Window& parent, ARDOUR::Session* s, boost::shared_ptr pi) + : ArdourWindow (parent, string_compose (_("Port Insert: %1"), pi->name ())) + , _portinsertui (this, s, pi) { - set_name ("IOSelectorWindow"); - std::string title = _("Port Insert "); - title += pi->name(); - set_title (title); - - get_vbox()->pack_start (_portinsertui); - - Gtk::Button* cancel_but = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - Gtk::Button* ok_but = add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); - - cancel_but->signal_clicked().connect (sigc::mem_fun (*this, &PortInsertWindow::cancel)); - ok_but->signal_clicked().connect (sigc::mem_fun (*this, &PortInsertWindow::accept)); - - signal_delete_event().connect (sigc::mem_fun (*this, &PortInsertWindow::wm_delete), false); + add (_portinsertui); } - -bool -PortInsertWindow::wm_delete (GdkEventAny* /*event*/) -{ - accept (); - return false; -} - -void -PortInsertWindow::on_map () -{ - _portinsertui.redisplay (); - Window::on_map (); -} - - -void -PortInsertWindow::cancel () -{ - _portinsertui.finished (IOSelector::Cancelled); - hide (); -} - -void -PortInsertWindow::accept () -{ - _portinsertui.finished (IOSelector::Accepted); - hide (); -} - diff --git a/gtk2_ardour/port_insert_ui.h b/gtk2_ardour/port_insert_ui.h index 9a42384c9f..dac6cb8547 100644 --- a/gtk2_ardour/port_insert_ui.h +++ b/gtk2_ardour/port_insert_ui.h @@ -19,56 +19,81 @@ #ifndef __gtkardour_port_insert_ui_h__ #define __gtkardour_port_insert_ui_h__ +#include "widgets/ardour_button.h" #include "widgets/stateful_button.h" -#include "ardour_dialog.h" + +#include "ardour_window.h" +#include "gain_meter.h" #include "io_selector.h" -namespace ARDOUR { +namespace ARDOUR +{ class PortInsert; } +class LatencyGUI; +class MTDM; + class PortInsertUI : public Gtk::VBox { public: - PortInsertUI (Gtk::Window*, ARDOUR::Session *, boost::shared_ptr); + PortInsertUI (Gtk::Window*, ARDOUR::Session*, boost::shared_ptr); + ~PortInsertUI (); void redisplay (); void finished (IOSelector::Result); private: - boost::shared_ptr _pi; - - Gtk::Notebook notebook; - ArdourWidgets::StatefulToggleButton latency_button; - IOSelector input_selector; - IOSelector output_selector; - Gtk::Label latency_display; - Gtk::HBox latency_hbox; - sigc::connection latency_timeout; + void fast_update (); + void send_changed (ARDOUR::IOChange, void*); + void return_changed (ARDOUR::IOChange, void*); bool check_latency_measurement (); + void set_latency_label (); + void forget_measuremed_latency (); + void set_measured_status (MTDM* mtdm = NULL); + + bool invert_press (GdkEventButton* ev); + bool invert_release (GdkEventButton* ev); + bool measure_latency_press (GdkEventButton* ev); + void edit_latency_button_clicked (); void latency_button_toggled (); - void update_latency_display (); + + boost::shared_ptr _pi; + + Gtk::Notebook _notebook; + ArdourWidgets::StatefulToggleButton _measure_latency_button; + ArdourWidgets::ArdourButton _invert_button; + ArdourWidgets::ArdourButton _edit_latency_button; + + IOSelector _input_selector; + IOSelector _output_selector; + GainMeter _input_gpm; + GainMeter _output_gpm; + Gtk::HBox _input_hbox; + Gtk::HBox _output_hbox; + Gtk::VBox _input_vbox; + Gtk::VBox _output_vbox; + Gtk::Label _latency_display; + Gtk::HBox _latency_hbox; + + Gtk::Window* _parent; + LatencyGUI* _latency_gui; + ArdourWindow* _latency_dialog; + + sigc::connection _latency_timeout; + sigc::connection _fast_screen_update_connection; + + PBD::ScopedConnectionList _connections; }; -class PortInsertWindow : public ArdourDialog +class PortInsertWindow : public ArdourWindow { - public: - PortInsertWindow (ARDOUR::Session *, boost::shared_ptr); +public: + PortInsertWindow (Gtk::Window&, ARDOUR::Session*, boost::shared_ptr); - protected: - void on_map (); - - private: +private: PortInsertUI _portinsertui; - Gtk::VBox vbox; - - void cancel (); - void accept (); - - PBD::ScopedConnection going_away_connection; - - bool wm_delete (GdkEventAny*); }; #endif /* __gtkardour_port_insert_ui_h__ */ diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index d575f07c0b..41609590f2 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -4027,7 +4027,9 @@ ProcessorBox::get_editor_window (boost::shared_ptr processor, bool us Window* w = get_processor_ui (port_insert); if (w == 0) { - io_selector = new PortInsertWindow (_session, port_insert); + Gtk::Window* tlw = dynamic_cast (get_toplevel ()); + assert (tlw); + io_selector = new PortInsertWindow (*tlw, _session, port_insert); set_processor_ui (port_insert, io_selector); } else { diff --git a/gtk2_ardour/route_params_ui.cc b/gtk2_ardour/route_params_ui.cc index 438bb2650f..6fa8c233eb 100644 --- a/gtk2_ardour/route_params_ui.cc +++ b/gtk2_ardour/route_params_ui.cc @@ -516,7 +516,6 @@ RouteParams_UI::redirect_selected (boost::shared_ptr proc) _active_view = portinsert_ui; redir_hpane.add (*_active_view); - portinsert_ui->redisplay(); redir_hpane.show_all(); }