mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-15 18:06:06 +01:00
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:
parent
d31649b4b4
commit
b96d96f3f9
5 changed files with 180 additions and 15 deletions
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ ladspa_plugin.cc
|
|||
location.cc
|
||||
mix.cc
|
||||
mtc_slave.cc
|
||||
mtdm.cc
|
||||
named_selection.cc
|
||||
onset_detector.cc
|
||||
panner.cc
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue