basic Midi latency measurement GUI (re-use Audio latency notebook)

This commit is contained in:
Robin Gareus 2014-06-08 14:48:10 +02:00
parent 81182b5bf6
commit eb289a76af
2 changed files with 150 additions and 64 deletions

View File

@ -40,6 +40,7 @@
#include "ardour/audio_backend.h"
#include "ardour/audioengine.h"
#include "ardour/mtdm.h"
#include "ardour/mididm.h"
#include "ardour/rc_configuration.h"
#include "ardour/types.h"
@ -80,7 +81,8 @@ EngineControl::EngineControl ()
, lm_measure_label (_("Measure"))
, lm_use_button (_("Use results"))
, lm_back_button (_("Back to settings ... (ignore results)"))
, lm_button (_("Calibrate..."))
, lm_button_audio (_("Calibrate Audio"))
, lm_button_midi (_("Calibrate Midi"))
, lm_table (12, 3)
, have_lm_results (false)
, lm_running (false)
@ -88,6 +90,7 @@ EngineControl::EngineControl ()
, ignore_changes (0)
, _desired_sample_rate (0)
, started_at_least_once (false)
, _measure_midi(false)
{
using namespace Notebook_Helpers;
vector<string> strings;
@ -335,8 +338,12 @@ EngineControl::EngineControl ()
basic_packer.attach (*label, 0, 1, 0, 1, xopt, (AttachOptions) 0);
basic_packer.attach (backend_combo, 1, 2, 0, 1, xopt, (AttachOptions) 0);
lm_button.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_latency));
lm_button.set_name ("generic button");
lm_button_audio.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_audio_latency));
lm_button_audio.set_name ("generic button");
lm_button_midi.signal_clicked.connect (sigc::mem_fun (*this, &EngineControl::calibrate_midi_latency));
lm_button_midi.set_name ("generic button");
if (_have_control) {
build_full_control_notebook ();
} else {
@ -445,12 +452,13 @@ EngineControl::EngineControl ()
/* button spans 2 rows */
basic_packer.attach (lm_button, 3, 4, row-1, row+1, xopt, xopt);
basic_packer.attach (lm_button_audio, 3, 4, row-1, row+1, xopt, xopt);
++row;
label = manage (left_aligned_label (_("MIDI System")));
basic_packer.attach (*label, 0, 1, row, row + 1, xopt, (AttachOptions) 0);
basic_packer.attach (midi_option_combo, 1, 2, row, row + 1, SHRINK, (AttachOptions) 0);
basic_packer.attach (lm_button_midi, 3, 4, row, row+1, xopt, xopt);
row++;
}
@ -515,8 +523,9 @@ EngineControl::EngineControl ()
vector<string> outputs;
vector<string> inputs;
ARDOUR::AudioEngine::instance()->get_physical_outputs (ARDOUR::DataType::AUDIO, outputs);
ARDOUR::AudioEngine::instance()->get_physical_inputs (ARDOUR::DataType::AUDIO, inputs);
ARDOUR::DataType const type = _measure_midi ? ARDOUR::DataType::MIDI : ARDOUR::DataType::AUDIO;
ARDOUR::AudioEngine::instance()->get_physical_outputs (type, outputs);
ARDOUR::AudioEngine::instance()->get_physical_inputs (type, inputs);
if (inputs.empty() || outputs.empty()) {
MessageDialog msg (_("Your selected audio configuration is playback- or capture-only.\n\nLatency calibration requires playback and capture"));
@ -1639,58 +1648,117 @@ EngineControl::EngineControl ()
/* latency measurement */
bool
EngineControl::check_latency_measurement ()
{
MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
bool
EngineControl::check_audio_latency_measurement ()
{
MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
if (mtdm->resolve () < 0) {
lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
return true;
}
if (mtdm->resolve () < 0) {
lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
return true;
}
if (mtdm->err () > 0.3) {
mtdm->invert ();
mtdm->resolve ();
}
if (mtdm->err () > 0.3) {
mtdm->invert ();
mtdm->resolve ();
}
char buf[128];
ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
char buf[256];
ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
if (sample_rate == 0) {
lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
ARDOUR::AudioEngine::instance()->stop_latency_detection ();
return false;
}
if (sample_rate == 0) {
lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
ARDOUR::AudioEngine::instance()->stop_latency_detection ();
return false;
}
uint32_t frames_total = mtdm->del();
uint32_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
int frames_total = mtdm->del();
int extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
snprintf (buf, sizeof (buf), "%u samples / %.3lf ms", extra, extra * 1000.0f/sample_rate);
snprintf (buf, sizeof (buf), "%s%d samples (%.3lf ms)\n%s%d samples (%.3lf ms)",
_("Detected roundtrip latency: "),
frames_total, frames_total * 1000.0f/sample_rate,
_("Systemic latency: "),
extra, extra * 1000.0f/sample_rate);
bool solid = true;
bool solid = true;
if (mtdm->err () > 0.2) {
strcat (buf, " ");
strcat (buf, _("(signal detection error)"));
solid = false;
}
if (mtdm->err () > 0.2) {
strcat (buf, " ");
strcat (buf, _("(signal detection error)"));
solid = false;
}
if (mtdm->inv ()) {
strcat (buf, " ");
strcat (buf, _("(inverted - bad wiring)"));
solid = false;
}
if (mtdm->inv ()) {
strcat (buf, " ");
strcat (buf, _("(inverted - bad wiring)"));
solid = false;
}
if (solid) {
end_latency_detection ();
lm_use_button.set_sensitive (true);
have_lm_results = true;
}
lm_results.set_markup (string_compose (results_markup, string_compose (_("Detected roundtrip latency: %1"), buf)));
if (solid) {
end_latency_detection ();
lm_use_button.set_sensitive (true);
have_lm_results = true;
}
return true;
lm_results.set_markup (string_compose (results_markup, buf));
return true;
}
bool
EngineControl::check_midi_latency_measurement ()
{
ARDOUR::MIDIDM* mididm = ARDOUR::AudioEngine::instance()->mididm ();
if (!mididm->have_signal () || mididm->latency () == 0) {
lm_results.set_markup (string_compose (results_markup, _("No signal detected ")));
return true;
}
char buf[256];
ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
if (sample_rate == 0) {
lm_results.set_markup (string_compose (results_markup, _("Disconnected from audio engine")));
ARDOUR::AudioEngine::instance()->stop_latency_detection ();
return false;
}
ARDOUR::framecnt_t frames_total = mididm->latency();
ARDOUR::framecnt_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
snprintf (buf, sizeof (buf), "%s%" PRId64" samples (%.1lf ms) dev: %.2f[spl]\n%s%" PRId64" samples (%.1lf ms)",
_("Detected roundtrip latency: "),
frames_total, frames_total * 1000.0f / sample_rate, mididm->deviation (),
_("Systemic latency: "),
extra, extra * 1000.0f / sample_rate);
bool solid = true;
if (!mididm->ok ()) {
strcat (buf, " ");
strcat (buf, _("(averaging)"));
solid = false;
}
if (mididm->deviation () > 50.0) {
strcat (buf, " ");
strcat (buf, _("(too large jitter)"));
solid = false;
} else if (mididm->deviation () > 10.0) {
strcat (buf, " ");
strcat (buf, _("(large jitter)"));
}
if (solid) {
end_latency_detection ();
lm_use_button.set_sensitive (false); // XXX TODO
have_lm_results = true;
}
lm_results.set_markup (string_compose (results_markup, buf));
return true;
}
void
@ -1699,9 +1767,13 @@ EngineControl::start_latency_detection ()
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());
if (ARDOUR::AudioEngine::instance()->start_latency_detection (false) == 0) {
if (ARDOUR::AudioEngine::instance()->start_latency_detection (_measure_midi) == 0) {
lm_results.set_markup (string_compose (results_markup, _("Detecting ...")));
latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_latency_measurement), 100);
if (_measure_midi) {
latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_midi_latency_measurement), 100);
} else {
latency_timeout = Glib::signal_timeout().connect (mem_fun (*this, &EngineControl::check_audio_latency_measurement), 100);
}
lm_measure_label.set_text (_("Cancel"));
have_lm_results = false;
lm_use_button.set_sensitive (false);
@ -1734,25 +1806,27 @@ EngineControl::latency_button_clicked ()
start_latency_detection ();
} else {
end_latency_detection ();
}
}
}
void
EngineControl::use_latency_button_clicked ()
{
MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
if (_measure_midi) {
MTDM* mtdm = ARDOUR::AudioEngine::instance()->mtdm ();
if (!mtdm) {
return;
if (!mtdm) {
return;
}
uint32_t frames_total = mtdm->del();
uint32_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
uint32_t one_way = extra/2;
input_latency_adjustment.set_value (one_way);
output_latency_adjustment.set_value (one_way);
}
uint32_t frames_total = mtdm->del();
uint32_t extra = frames_total - ARDOUR::AudioEngine::instance()->latency_signal_delay();
uint32_t one_way = extra/2;
input_latency_adjustment.set_value (one_way);
output_latency_adjustment.set_value (one_way);
/* back to settings page */
notebook.set_current_page (0);
@ -1809,8 +1883,16 @@ EngineControl::connect_disconnect_click()
}
void
EngineControl::calibrate_latency ()
EngineControl::calibrate_audio_latency ()
{
_measure_midi = false;
notebook.set_current_page (latency_tab);
}
void
EngineControl::calibrate_midi_latency ()
{
_measure_midi = true;
notebook.set_current_page (latency_tab);
}

View File

@ -90,7 +90,8 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
Gtk::Button lm_measure_button;
Gtk::Button lm_use_button;
Gtk::Button lm_back_button;
ArdourButton lm_button;
ArdourButton lm_button_audio;
ArdourButton lm_button_midi;
Gtk::Label lm_title;
Gtk::Label lm_results;
Gtk::Table lm_table;
@ -196,7 +197,8 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
/* latency measurement */
void latency_button_clicked ();
bool check_latency_measurement ();
bool check_audio_latency_measurement ();
bool check_midi_latency_measurement ();
sigc::connection latency_timeout;
void enable_latency_tab ();
void disable_latency_tab ();
@ -212,7 +214,9 @@ class EngineControl : public ArdourDialog, public PBD::ScopedConnectionList {
PBD::ScopedConnection stopped_connection;
void connect_disconnect_click ();
void calibrate_latency ();
void calibrate_audio_latency ();
void calibrate_midi_latency ();
bool _measure_midi;
};
#endif /* __gtk2_ardour_engine_dialog_h__ */