diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2013-09-10 22:58:33 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2013-09-10 22:58:33 -0400 |
commit | 676ff806970925972b165cd7621ba7ea8c82c08a (patch) | |
tree | 8a28169d0f08824c0b3ce1f5cec375a89029d9f2 /gtk2_ardour | |
parent | 209e4bdcaed8e0f7d66fa5673f9049948e1f1d53 (diff) |
basic functionality for hardware latency measurement
Diffstat (limited to 'gtk2_ardour')
-rw-r--r-- | gtk2_ardour/engine_dialog.cc | 182 | ||||
-rw-r--r-- | gtk2_ardour/engine_dialog.h | 24 |
2 files changed, 204 insertions, 2 deletions
diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc index b97a7133e6..8c84c5d3b9 100644 --- a/gtk2_ardour/engine_dialog.cc +++ b/gtk2_ardour/engine_dialog.cc @@ -36,12 +36,15 @@ #include "ardour/audio_backend.h" #include "ardour/audioengine.h" +#include "ardour/mtdm.h" #include "ardour/rc_configuration.h" +#include "ardour/types.h" #include "pbd/convert.h" #include "pbd/error.h" #include "engine_dialog.h" +#include "gui_thread.h" #include "i18n.h" using namespace std; @@ -63,6 +66,9 @@ EngineControl::EngineControl () , ports_adjustment (128, 8, 1024, 1, 16) , ports_spinner (ports_adjustment) , control_app_button (_("Launch Control App")) + , lm_measure_button (_("Measure latency")) + , lm_use_button (_("Use results")) + , lm_table (5, 2) , basic_packer (9, 3) , ignore_changes (0) , _desired_sample_rate (0) @@ -89,6 +95,15 @@ EngineControl::EngineControl () if (audio_setup) { set_state (*audio_setup); } + + ARDOUR::AudioEngine::instance()->Stopped.connect (*this, MISSING_INVALIDATOR, boost::bind (&EngineControl::disable_latency_tab, this), gui_context()); + + if (!ARDOUR::AudioEngine::instance()->connected()) { + ARDOUR::AudioEngine::instance()->Running.connect (*this, MISSING_INVALIDATOR, boost::bind (&EngineControl::enable_latency_tab, this), gui_context()); + disable_latency_tab (); + } else { + enable_latency_tab (); + } } void @@ -131,7 +146,7 @@ EngineControl::build_notebook () row = 0; - const AttachOptions xopt = AttachOptions (FILL|EXPAND); + AttachOptions xopt = AttachOptions (FILL|EXPAND); label = manage (left_aligned_label (_("Audio System:"))); basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0); @@ -200,8 +215,59 @@ EngineControl::build_notebook () midi_packer.set_border_width (12); + /* latency measurement tab */ + + lm_title.set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Latency Measurement Tool"))); + + row = 0; + lm_table.set_row_spacings (12); + + lm_table.attach (lm_title, 0, 2, row, row+1, xopt, (AttachOptions) 0); + row++; + + lm_preamble.set_width_chars (60); + lm_preamble.set_line_wrap (true); + lm_preamble.set_markup (_("This tool will allow you to <i>precisely</i> measure the signal delay \ +within your audio hardware setup that is not controlled by Ardour or its audio backend.\n\n\ +Connect the two channels that you select below using either a cable or (less ideally) a speaker \ +and microphone.\n\n\ +Once the channels are connected, click the \"Measure latency\" button.\n\n\ +When you are satisfied with the results, click the \"Use results\" button to use them with your audio \ +setup parameters. <i>Note: they will not take effect until you restart</i>")); + + lm_table.attach (lm_preamble, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); + row++; + + label = manage (left_aligned_label (_("Output channel"))); + lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0); + lm_table.attach (lm_output_channel_combo, 1, 2, row, row+1, xopt, (AttachOptions) 0); + ++row; + + label = manage (left_aligned_label (_("Input channel"))); + lm_table.attach (*label, 0, 1, row, row+1, xopt, (AttachOptions) 0); + lm_table.attach (lm_input_channel_combo, 1, 2, row, row+1, xopt, (AttachOptions) 0); + ++row; + + xopt = AttachOptions(0); + + lm_measure_button.signal_toggled().connect (sigc::mem_fun (*this, &EngineControl::latency_button_toggled)); + + lm_table.attach (lm_measure_button, 0, 2, row, row+1, xopt, (AttachOptions) 0); + ++row; + lm_table.attach (lm_results, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), (AttachOptions) 0); + ++row; + lm_table.attach (lm_use_button, 0, 2, row, row+1, xopt, (AttachOptions) 0); + ++row; + + lm_results.set_text ("Measured results: 786 samples"); + + lm_vbox.pack_start (lm_table, false, false); + + /* pack it all up */ + notebook.pages().push_back (TabElem (basic_vbox, _("Audio"))); notebook.pages().push_back (TabElem (midi_hbox, _("MIDI"))); + notebook.pages().push_back (TabElem (lm_vbox, _("Latency"))); notebook.set_border_width (12); notebook.set_tab_pos (POS_RIGHT); @@ -226,6 +292,28 @@ EngineControl::~EngineControl () } void +EngineControl::disable_latency_tab () +{ + vector<string> empty; + set_popdown_strings (lm_output_channel_combo, empty); + set_popdown_strings (lm_input_channel_combo, empty); +} + +void +EngineControl::enable_latency_tab () +{ + vector<string> outputs; + ARDOUR::AudioEngine::instance()->get_physical_outputs (ARDOUR::DataType::AUDIO, outputs); + set_popdown_strings (lm_output_channel_combo, outputs); + lm_output_channel_combo.set_active_text (outputs.front()); + + vector<string> inputs; + ARDOUR::AudioEngine::instance()->get_physical_inputs (ARDOUR::DataType::AUDIO, inputs); + set_popdown_strings (lm_input_channel_combo, inputs); + lm_input_channel_combo.set_active_text (inputs.front()); +} + +void EngineControl::backend_changed () { if (ignore_changes) { @@ -861,3 +949,95 @@ EngineControl::set_desired_sample_rate (uint32_t sr) _desired_sample_rate = sr; device_changed (); } + +/* latency measurement */ + +void +EngineControl::update_latency_display () +{ + ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate(); + if (sample_rate == 0) { + lm_results.set_text (_("Disconnected from audio engine")); + } else { + char buf[64]; + //snprintf (buf, sizeof (buf), "%10.3lf frames %10.3lf ms", + //(float)_pi->latency(), (float)_pi->latency() * 1000.0f/sample_rate); + strcpy (buf, "got something"); + lm_results.set_text(buf); + } +} + +bool +EngineControl::check_latency_measurement () +{ + MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm (); + static uint32_t cnt = 0; + + if (mtdm->resolve () < 0) { + cerr << "no resolution\n"; + string txt = _("No signal detected "); + uint32_t dots = cnt++%10; + for (uint32_t i = 0; i < dots; ++i) { + txt += '.'; + } + lm_results.set_text (txt); + return true; + } + + if (mtdm->err () > 0.3) { + mtdm->invert (); + mtdm->resolve (); + } + + char buf[128]; + ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate(); + + if (sample_rate == 0) { + lm_results.set_text (_("Disconnected from audio engine")); + ARDOUR::AudioEngine::instance()->stop_latency_detection (); + return false; + } + + snprintf (buf, sizeof (buf), "%10.3lf frames %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->inv ()) { + strcat (buf, " (Inv)"); + solid = false; + } + + if (solid) { + // _pi->set_measured_latency (rint (mtdm->del())); + lm_measure_button.set_active (false); + strcat (buf, " (set)"); + } + + lm_results.set_text (buf); + + return true; +} + +void +EngineControl::latency_button_toggled () +{ + if (lm_measure_button.get_active ()) { + + ARDOUR::AudioEngine::instance()->set_latency_input_port (lm_input_channel_combo.get_active_text()); + ARDOUR::AudioEngine::instance()->set_latency_output_port (lm_output_channel_combo.get_active_text()); + cerr << "latency detection on " << lm_input_channel_combo.get_active_text() << " => " << lm_output_channel_combo.get_active_text() << endl; + ARDOUR::AudioEngine::instance()->start_latency_detection (); + lm_results.set_text (_("Detecting ...")); + latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_latency_measurement), 250); + + } else { + ARDOUR::AudioEngine::instance()->stop_latency_detection (); + latency_timeout.disconnect (); + update_latency_display (); + } +} diff --git a/gtk2_ardour/engine_dialog.h b/gtk2_ardour/engine_dialog.h index a92d0629f2..940f594421 100644 --- a/gtk2_ardour/engine_dialog.h +++ b/gtk2_ardour/engine_dialog.h @@ -33,9 +33,11 @@ #include <gtkmm/buttonbox.h> #include <gtkmm/button.h> +#include "pbd/signals.h" + #include "ardour_dialog.h" -class EngineControl : public ArdourDialog { +class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList { public: EngineControl (); ~EngineControl (); @@ -71,6 +73,18 @@ class EngineControl : public ArdourDialog { Gtk::Button control_app_button; + /* latency measurement */ + + Gtk::ComboBoxText lm_output_channel_combo; + Gtk::ComboBoxText lm_input_channel_combo; + Gtk::ToggleButton lm_measure_button; + Gtk::Button lm_use_button; + Gtk::Label lm_title; + Gtk::Label lm_preamble; + Gtk::Label lm_results; + Gtk::Table lm_table; + Gtk::VBox lm_vbox; + /* JACK specific */ Gtk::CheckButton realtime_button; @@ -156,6 +170,14 @@ class EngineControl : public ArdourDialog { void manage_control_app_sensitivity (); int push_state_to_backend (bool start); uint32_t _desired_sample_rate; + + /* latency measurement */ + void latency_button_toggled (); + bool check_latency_measurement (); + void update_latency_display (); + sigc::connection latency_timeout; + void enable_latency_tab (); + void disable_latency_tab (); }; #endif /* __gtk2_ardour_engine_dialog_h__ */ |