provide jdelay-based hardware/port insert latency measurement

git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@5729 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-10-05 17:17:44 +00:00
parent d31649b4b4
commit b96d96f3f9
5 changed files with 180 additions and 15 deletions

View file

@ -30,6 +30,7 @@
#include <ardour/route.h>
#include <ardour/audioengine.h>
#include <ardour/port.h>
#include <ardour/mtdm.h>
#include <ardour/insert.h>
#include <ardour/session.h>
#include <ardour/audio_diskstream.h>
@ -141,8 +142,8 @@ IOSelector::IOSelector (Session& sess, boost::shared_ptr<IO> ior, bool input)
io (ior),
for_input (input),
port_frame (for_input? _("Inputs") : _("Outputs")),
add_port_button (for_input? _("Add Input") : _("Add Output")),
remove_port_button (for_input? _("Remove Input") : _("Remove Output")),
add_port_button (for_input? _("Add") : _("Add")),
remove_port_button (for_input? _("Remove") : _("Remove")),
clear_connections_button (_("Disconnect All"))
{
selected_port = 0;
@ -717,20 +718,92 @@ IOSelector::redisplay ()
}
PortInsertUI::PortInsertUI (Session& sess, boost::shared_ptr<PortInsert> pi)
: input_selector (sess, pi, true),
output_selector (sess, pi, false)
: _pi (pi)
, latency_button (_("Measure Latency"))
, input_selector (sess, pi, true)
, output_selector (sess, pi, false)
{
latency_hbox.pack_start (latency_button, false, false);
latency_hbox.pack_start (latency_display, false, false);
latency_frame.add (latency_hbox);
hbox.pack_start (output_selector, true, true);
hbox.pack_start (input_selector, true, true);
set_spacing (6);
set_border_width (12);
pack_start (latency_frame);
pack_start (hbox);
latency_button.signal_toggled().connect (mem_fun (*this, &PortInsertUI::latency_button_toggled));
}
bool
PortInsertUI::check_latency_measurement ()
{
MTDM* mtdm = _pi->mtdm ();
if (mtdm->resolve () < 0) {
latency_display.set_text (_("No signal detected"));
return true;
}
if (mtdm->err () > 0.3) {
mtdm->invert ();
mtdm->resolve ();
}
char buf[64];
nframes_t sample_rate = input_selector.session.engine().frame_rate();
if (sample_rate == 0) {
latency_display.set_text (_("Disconnected from audio engine"));
_pi->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 ((nframes_t) rint (mtdm->del()));
strcat (buf, " (set)");
}
latency_display.set_text (buf);
return true;
}
void
PortInsertUI::latency_button_toggled ()
{
if (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);
} else {
_pi->stop_latency_detection ();
latency_timeout.disconnect ();
}
}
void
PortInsertUI::redisplay()
{
input_selector.redisplay();
output_selector.redisplay();
}

View file

@ -34,6 +34,7 @@ using __gnu_cxx::slist;
#include <gtkmm/box.h>
#include <gtkmm/frame.h>
#include <gtkmm/button.h>
#include <gtkmm/togglebutton.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/notebook.h>
#include <gtkmm/treeview.h>
@ -64,7 +65,6 @@ class IOSelector : public Gtk::VBox {
sigc::signal<void,Result> Finished;
protected:
ARDOUR::Session& session;
private:
@ -157,7 +157,6 @@ class IOSelectorWindow : public ArdourDialog
void accept ();
};
class PortInsertUI : public Gtk::VBox
{
public:
@ -167,11 +166,19 @@ class PortInsertUI : public Gtk::VBox
void finished (IOSelector::Result);
private:
boost::shared_ptr<ARDOUR::PortInsert> _pi;
Gtk::ToggleButton latency_button;
Gtk::Label latency_display;
Gtk::Frame latency_frame;
Gtk::HBox latency_hbox;
sigc::connection latency_timeout;
bool check_latency_measurement ();
void latency_button_toggled ();
Gtk::HBox hbox;
IOSelector input_selector;
IOSelector output_selector;
};
class PortInsertWindow : public ArdourDialog

View file

@ -65,6 +65,7 @@ ladspa_plugin.cc
location.cc
mix.cc
mtc_slave.cc
mtdm.cc
named_selection.cc
onset_detector.cc
panner.cc

View file

@ -30,6 +30,7 @@
#include <ardour/types.h>
class XMLNode;
class MTDM;
namespace MIDI {
class Port;
@ -81,8 +82,18 @@ class PortInsert : public Insert
int32_t configure_io (int32_t magic, int32_t in, int32_t out);
uint32_t bit_slot() const { return bitslot; }
void start_latency_detection ();
void stop_latency_detection ();
MTDM* mtdm () const { return _mtdm; }
void set_measured_latency (nframes_t);
private:
uint32_t bitslot;
uint32_t bitslot;
MTDM* _mtdm;
bool _latency_detect;
nframes_t _latency_flush_frames;
nframes_t _measured_latency;
};
class PluginInsert : public Insert

View file

@ -26,6 +26,7 @@
#include <pbd/stacktrace.h>
#include <ardour/insert.h>
#include <ardour/mtdm.h>
#include <ardour/plugin.h>
#include <ardour/port.h>
#include <ardour/route.h>
@ -905,12 +906,19 @@ PortInsert::PortInsert (const PortInsert& other)
void
PortInsert::init ()
{
_mtdm = 0;
_latency_detect = false;
_latency_flush_frames = false;
_measured_latency = 0;
}
PortInsert::PortInsert (Session& s, const XMLNode& node)
: Insert (s, "will change", PreFader)
{
init ();
bitslot = 0xffffffff;
if (set_state (node)) {
throw failed_constructor();
}
@ -920,9 +928,36 @@ PortInsert::PortInsert (Session& s, const XMLNode& node)
PortInsert::~PortInsert ()
{
delete _mtdm;
GoingAway ();
}
void
PortInsert::start_latency_detection ()
{
if (_mtdm != 0) {
delete _mtdm;
}
_mtdm = new MTDM;
_latency_flush_frames = false;
_latency_detect = true;
_measured_latency = 0;
}
void
PortInsert::stop_latency_detection ()
{
_latency_flush_frames = latency() + _session.engine().frames_per_cycle();
_latency_detect = false;
}
void
PortInsert::set_measured_latency (nframes_t n)
{
_measured_latency = n;
}
void
PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes)
{
@ -930,23 +965,57 @@ PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, nframes_t nframes)
return;
}
vector<Port*>::iterator o;
if (_latency_detect) {
if (n_inputs() != 0) {
Sample* in = get_input_buffer (0, nframes);
Sample* out = get_output_buffer (0, nframes);
_mtdm->process (nframes, in, out);
for (o = _outputs.begin(); o != _outputs.end(); ++o) {
(*o)->mark_silence (false);
}
}
return;
} else if (_latency_flush_frames) {
/* wait for the entire input buffer to drain before picking up input again so that we can't
hear the remnants of whatever MTDM pumped into the pipeline.
*/
silence (nframes);
if (_latency_flush_frames > nframes) {
_latency_flush_frames -= nframes;
} else {
_latency_flush_frames = 0;
}
return;
}
if (!active()) {
/* deliver silence */
silence (nframes);
return;
}
uint32_t n;
vector<Port*>::iterator o;
vector<Port*>::iterator i;
/* deliver output */
uint32_t n;
for (o = _outputs.begin(), n = 0; o != _outputs.end(); ++o, ++n) {
memcpy (get_output_buffer (n, nframes), bufs[min(nbufs,n)], sizeof (Sample) * nframes);
(*o)->mark_silence (false);
}
vector<Port*>::iterator i;
/* collect input */
for (i = _inputs.begin(), n = 0; i != _inputs.end(); ++i, ++n) {
@ -1027,7 +1096,11 @@ PortInsert::latency()
need to take that into account too.
*/
return _session.engine().frames_per_cycle() + input_latency();
if (_measured_latency == 0) {
return _session.engine().frames_per_cycle() + input_latency();
} else {
return _measured_latency;
}
}
int32_t