Update latency compensation code for new JACK latency API.
This commit is contained in:
parent
40352db651
commit
96a6709fe8
2
lib/ntk
2
lib/ntk
|
@ -1 +1 @@
|
||||||
Subproject commit d0063527aa360a3f1fd34e76fc0dd9125efb9202
|
Subproject commit 38275d616800d5af826fd4a9c761a98068e7311a
|
|
@ -395,6 +395,32 @@ Chain::configure_ports ( void )
|
||||||
parent()->redraw();
|
parent()->redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** invoked from the JACK latency callback... We need to update the latency values on this chains ports */
|
||||||
|
void
|
||||||
|
Chain::set_latency ( JACK::Port::direction_e dir )
|
||||||
|
{
|
||||||
|
nframes_t total_latency = 0;
|
||||||
|
|
||||||
|
if ( dir == JACK::Port::Input )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < modules(); ++i )
|
||||||
|
{
|
||||||
|
Module *m = module( i );
|
||||||
|
total_latency += m->get_latency( dir );
|
||||||
|
m->set_latency( dir, total_latency );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( int i = modules(); i--; )
|
||||||
|
{
|
||||||
|
Module *m = module( i );
|
||||||
|
total_latency += m->get_latency( dir );
|
||||||
|
m->set_latency( dir, total_latency );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Chain::get_module_instance_number ( Module *m )
|
Chain::get_module_instance_number ( Module *m )
|
||||||
{
|
{
|
||||||
|
|
|
@ -125,6 +125,8 @@ public:
|
||||||
_configure_outputs_userdata = v;
|
_configure_outputs_userdata = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_latency ( JACK::Port::direction_e );
|
||||||
|
|
||||||
Fl_Callback * configure_outputs_callback ( void ) const { return _configure_outputs_callback; }
|
Fl_Callback * configure_outputs_callback ( void ) const { return _configure_outputs_callback; }
|
||||||
|
|
||||||
virtual void log_children ( void ) const;
|
virtual void log_children ( void ) const;
|
||||||
|
|
|
@ -98,6 +98,18 @@ Group::set ( Log_Entry &e )
|
||||||
/* Callbacks */
|
/* Callbacks */
|
||||||
/*************/
|
/*************/
|
||||||
|
|
||||||
|
void
|
||||||
|
Group::latency ( jack_latency_callback_mode_t mode )
|
||||||
|
{
|
||||||
|
for ( std::list<Mixer_Strip*>::iterator i = strips.begin();
|
||||||
|
i != strips.end();
|
||||||
|
i++ )
|
||||||
|
{
|
||||||
|
if ( (*i)->chain() )
|
||||||
|
(*i)->chain()->set_latency(mode == JackCaptureLatency ? JACK::Port::Input : JACK::Port::Output );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* THREAD: RT */
|
/* THREAD: RT */
|
||||||
/** This is the jack xrun callback */
|
/** This is the jack xrun callback */
|
||||||
int
|
int
|
||||||
|
|
|
@ -52,6 +52,7 @@ class Group : public Loggable, public JACK::Client, public Mutex
|
||||||
int buffer_size ( nframes_t nframes );
|
int buffer_size ( nframes_t nframes );
|
||||||
void thread_init ( void );
|
void thread_init ( void );
|
||||||
void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect );
|
void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect );
|
||||||
|
virtual void latency ( jack_latency_callback_mode_t mode );
|
||||||
|
|
||||||
/* not allowed */
|
/* not allowed */
|
||||||
Group ( const Group &rhs );
|
Group ( const Group &rhs );
|
||||||
|
|
|
@ -79,6 +79,7 @@ public:
|
||||||
|
|
||||||
LOG_CREATE_FUNC( JACK_Module );
|
LOG_CREATE_FUNC( JACK_Module );
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void process ( nframes_t nframes );
|
virtual void process ( nframes_t nframes );
|
||||||
|
|
|
@ -127,6 +127,7 @@ Module::~Module ( )
|
||||||
void
|
void
|
||||||
Module::init ( void )
|
Module::init ( void )
|
||||||
{
|
{
|
||||||
|
// _latency = 0;
|
||||||
_is_default = false;
|
_is_default = false;
|
||||||
_editor = 0;
|
_editor = 0;
|
||||||
_chain = 0;
|
_chain = 0;
|
||||||
|
@ -1089,6 +1090,76 @@ Module::thaw_ports ( void )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nframes_t
|
||||||
|
Module::get_latency ( JACK::Port::direction_e dir ) const
|
||||||
|
{
|
||||||
|
nframes_t tmin = 0;
|
||||||
|
nframes_t tmax = 0;
|
||||||
|
|
||||||
|
if ( dir == JACK::Port::Input )
|
||||||
|
{
|
||||||
|
if ( aux_audio_input.size() )
|
||||||
|
{
|
||||||
|
for ( unsigned int i = 0; i < aux_audio_input.size(); i++ )
|
||||||
|
{
|
||||||
|
nframes_t min,max;
|
||||||
|
|
||||||
|
aux_audio_input[i].jack_port()->get_latency( dir, &min, &max );
|
||||||
|
|
||||||
|
tmin += min;
|
||||||
|
tmax += max;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmin /= aux_audio_input.size();
|
||||||
|
tmax /= aux_audio_input.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmin;
|
||||||
|
/* for ( unsigned int i = 0; i < aux_audio_output.size(); i++ ) */
|
||||||
|
/* aux_audio_output[i].set_latency( dir, tmin, tmax ); */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( aux_audio_output.size() )
|
||||||
|
{
|
||||||
|
for ( unsigned int i = 0; i < aux_audio_output.size(); i++ )
|
||||||
|
{
|
||||||
|
nframes_t min,max;
|
||||||
|
|
||||||
|
aux_audio_output[i].jack_port()->get_latency( dir, &min, &max );
|
||||||
|
|
||||||
|
tmin += min;
|
||||||
|
tmax += max;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmin /= aux_audio_output.size();
|
||||||
|
tmax /= aux_audio_output.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmin;
|
||||||
|
|
||||||
|
|
||||||
|
/* for ( unsigned int i = 0; i < aux_audio_output.size(); i++ ) */
|
||||||
|
/* aux_audio_output[i].set_latency( dir, tmin, tmax ); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Module::set_latency ( JACK::Port::direction_e dir, nframes_t latency )
|
||||||
|
{
|
||||||
|
if ( dir == JACK::Port::Input )
|
||||||
|
{
|
||||||
|
for ( unsigned int i = 0; i < aux_audio_output.size(); i++ )
|
||||||
|
aux_audio_output[i].jack_port()->set_latency( dir, latency, latency );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( unsigned int i = 0; i < aux_audio_input.size(); i++ )
|
||||||
|
aux_audio_input[i].jack_port()->set_latency( dir, latency, latency );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Module::add_aux_port ( bool input, const char *prefix, int i )
|
Module::add_aux_port ( bool input, const char *prefix, int i )
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,6 +46,7 @@ class Module : public Fl_Group, public Loggable {
|
||||||
nframes_t _nframes;
|
nframes_t _nframes;
|
||||||
Chain *_chain;
|
Chain *_chain;
|
||||||
bool _is_default;
|
bool _is_default;
|
||||||
|
// nframes_t _latency;
|
||||||
|
|
||||||
Module_Parameter_Editor *_editor;
|
Module_Parameter_Editor *_editor;
|
||||||
|
|
||||||
|
@ -71,6 +72,9 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
virtual nframes_t get_latency ( JACK::Port::direction_e dir ) const;
|
||||||
|
virtual void set_latency ( JACK::Port::direction_e dir, nframes_t latency );
|
||||||
|
|
||||||
/* true if this module was added by default and not under normal user control */
|
/* true if this module was added by default and not under normal user control */
|
||||||
bool is_default ( void ) const { return _is_default; }
|
bool is_default ( void ) const { return _is_default; }
|
||||||
void is_default ( bool v ) { _is_default = v; }
|
void is_default ( bool v ) { _is_default = v; }
|
||||||
|
@ -276,7 +280,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void jack_port ( JACK::Port *v ) { _jack_port = v; }
|
void jack_port ( JACK::Port *v ) { _jack_port = v; }
|
||||||
JACK::Port *jack_port ( void ) { return _jack_port; }
|
JACK::Port *jack_port ( void ) const { return _jack_port; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,8 @@ Plugin_Module::set ( Log_Entry &e )
|
||||||
void
|
void
|
||||||
Plugin_Module::init ( void )
|
Plugin_Module::init ( void )
|
||||||
{
|
{
|
||||||
|
_latency = 0;
|
||||||
|
_last_latency = 0;
|
||||||
_idata = new Plugin_Module::ImplementationData();
|
_idata = new Plugin_Module::ImplementationData();
|
||||||
_idata->handle.clear();
|
_idata->handle.clear();
|
||||||
/* module will be bypassed until plugin is loaded */
|
/* module will be bypassed until plugin is loaded */
|
||||||
|
@ -138,6 +140,19 @@ Plugin_Module::init ( void )
|
||||||
bbox( tx, ty, tw, th );
|
bbox( tx, ty, tw, th );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Plugin_Module::update ( void )
|
||||||
|
{
|
||||||
|
if ( _last_latency != _latency )
|
||||||
|
{
|
||||||
|
DMESSAGE( "Plugin latency changed to %lu", (unsigned long)_latency );
|
||||||
|
|
||||||
|
chain()->client()->recompute_latencies();
|
||||||
|
}
|
||||||
|
|
||||||
|
_last_latency = _latency;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Plugin_Module::can_support_inputs ( int n )
|
Plugin_Module::can_support_inputs ( int n )
|
||||||
{
|
{
|
||||||
|
@ -341,7 +356,7 @@ Plugin_Module::plugin_instances ( unsigned int n )
|
||||||
{
|
{
|
||||||
LADSPA_Handle h;
|
LADSPA_Handle h;
|
||||||
|
|
||||||
DMESSAGE( "Instantiating plugin..." );
|
DMESSAGE( "Instantiating plugin... with sample rate %lu", (unsigned long)sample_rate());
|
||||||
|
|
||||||
if ( ! (h = _idata->descriptor->instantiate( _idata->descriptor, sample_rate() ) ) )
|
if ( ! (h = _idata->descriptor->instantiate( _idata->descriptor, sample_rate() ) ) )
|
||||||
{
|
{
|
||||||
|
@ -391,6 +406,31 @@ Plugin_Module::bypass ( bool v )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nframes_t
|
||||||
|
Plugin_Module::get_plugin_latency ( void ) const
|
||||||
|
{
|
||||||
|
for ( unsigned int i = ncontrol_outputs(); i--; )
|
||||||
|
{
|
||||||
|
if ( !strcasecmp( "latency", control_output[i].name() ) )
|
||||||
|
{
|
||||||
|
return control_output[i].control_value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nframes_t
|
||||||
|
Plugin_Module::get_latency ( JACK::Port::direction_e dir ) const
|
||||||
|
{
|
||||||
|
nframes_t latency = Module::get_latency( dir );
|
||||||
|
|
||||||
|
latency += get_plugin_latency();
|
||||||
|
|
||||||
|
return latency;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Plugin_Module::load ( unsigned long id )
|
Plugin_Module::load ( unsigned long id )
|
||||||
{
|
{
|
||||||
|
@ -467,6 +507,7 @@ Plugin_Module::load ( unsigned long id )
|
||||||
|
|
||||||
Port p( this, d, Port::CONTROL, _idata->descriptor->PortNames[ i ] );
|
Port p( this, d, Port::CONTROL, _idata->descriptor->PortNames[ i ] );
|
||||||
|
|
||||||
|
p.hints.default_value = 0;
|
||||||
|
|
||||||
LADSPA_PortRangeHintDescriptor hd = _idata->descriptor->PortRangeHints[i].HintDescriptor;
|
LADSPA_PortRangeHintDescriptor hd = _idata->descriptor->PortRangeHints[i].HintDescriptor;
|
||||||
|
|
||||||
|
@ -768,6 +809,8 @@ Plugin_Module::process ( nframes_t nframes )
|
||||||
buffer_copy( (sample_t*)audio_output[1].buffer(), (sample_t*)audio_input[0].buffer(), nframes );
|
buffer_copy( (sample_t*)audio_output[1].buffer(), (sample_t*)audio_input[0].buffer(), nframes );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_latency = get_plugin_latency();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,11 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
volatile nframes_t _latency;
|
||||||
|
nframes_t _last_latency;
|
||||||
|
|
||||||
|
nframes_t get_plugin_latency ( void ) const;
|
||||||
|
|
||||||
void init ( void );
|
void init ( void );
|
||||||
|
|
||||||
void bbox ( int &X, int &Y, int &W, int &H )
|
void bbox ( int &X, int &Y, int &W, int &H )
|
||||||
|
@ -106,6 +111,9 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
virtual void update ( void );
|
||||||
|
virtual nframes_t get_latency ( JACK::Port::direction_e dir ) const;
|
||||||
|
|
||||||
static std::list<Plugin_Info> get_all_plugins ( void );
|
static std::list<Plugin_Info> get_all_plugins ( void );
|
||||||
|
|
||||||
static void spawn_discover_thread ( void );
|
static void spawn_discover_thread ( void );
|
||||||
|
|
|
@ -123,6 +123,12 @@ namespace JACK
|
||||||
((Client*)arg)->thread_init();
|
((Client*)arg)->thread_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Client::latency ( jack_latency_callback_mode_t mode, void *arg )
|
||||||
|
{
|
||||||
|
((Client*)arg)->latency( mode );
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Client::shutdown ( void *arg )
|
Client::shutdown ( void *arg )
|
||||||
{
|
{
|
||||||
|
@ -175,6 +181,10 @@ namespace JACK
|
||||||
set_callback( port_connect );
|
set_callback( port_connect );
|
||||||
|
|
||||||
jack_set_sample_rate_callback( _client, &Client::sample_rate_changed, this );
|
jack_set_sample_rate_callback( _client, &Client::sample_rate_changed, this );
|
||||||
|
|
||||||
|
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
|
||||||
|
set_callback( latency );
|
||||||
|
#endif
|
||||||
|
|
||||||
/* FIXME: should we wait to register this until after the project
|
/* FIXME: should we wait to register this until after the project
|
||||||
has been loaded (and we have disk threads running)? */
|
has been loaded (and we have disk threads running)? */
|
||||||
|
@ -296,6 +306,12 @@ namespace JACK
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Client::recompute_latencies ( void )
|
||||||
|
{
|
||||||
|
jack_recompute_total_latencies( _client );
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Client::transport_stop ( )
|
Client::transport_stop ( )
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,6 +66,9 @@ namespace JACK
|
||||||
static void thread_init ( void *arg );
|
static void thread_init ( void *arg );
|
||||||
virtual void thread_init ( void ) = 0;
|
virtual void thread_init ( void ) = 0;
|
||||||
|
|
||||||
|
static void latency ( jack_latency_callback_mode_t mode, void *arg );
|
||||||
|
virtual void latency ( jack_latency_callback_mode_t mode ) { }
|
||||||
|
|
||||||
Client ( const Client &rhs );
|
Client ( const Client &rhs );
|
||||||
Client & operator = ( const Client &rhs );
|
Client & operator = ( const Client &rhs );
|
||||||
|
|
||||||
|
@ -89,7 +92,7 @@ namespace JACK
|
||||||
SLOW_SYNC = 1 << 0,
|
SLOW_SYNC = 1 << 0,
|
||||||
TIMEBASE_MASTER = 1 << 1 };
|
TIMEBASE_MASTER = 1 << 1 };
|
||||||
|
|
||||||
jack_client_t * jack_client ( void ) { return _client; }
|
jack_client_t * jack_client ( void ) const { return _client; }
|
||||||
|
|
||||||
void port_added ( JACK::Port * p );
|
void port_added ( JACK::Port * p );
|
||||||
void port_removed ( JACK::Port *p );
|
void port_removed ( JACK::Port *p );
|
||||||
|
@ -116,7 +119,8 @@ namespace JACK
|
||||||
void transport_start ( void );
|
void transport_start ( void );
|
||||||
void transport_locate ( nframes_t frame );
|
void transport_locate ( nframes_t frame );
|
||||||
jack_transport_state_t transport_query ( jack_position_t *pos );
|
jack_transport_state_t transport_query ( jack_position_t *pos );
|
||||||
|
|
||||||
|
void recompute_latencies ( void );
|
||||||
|
|
||||||
static int maximum_name_length ( void ) { return jack_client_name_size(); }
|
static int maximum_name_length ( void ) { return jack_client_name_size(); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,8 +38,7 @@ namespace JACK
|
||||||
{
|
{
|
||||||
return jack_port_name_size() - jack_client_name_size() - 6;
|
return jack_port_name_size() - jack_client_name_size() - 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Port::Port ( const Port &rhs )
|
Port::Port ( const Port &rhs )
|
||||||
{
|
{
|
||||||
_connections = NULL;
|
_connections = NULL;
|
||||||
|
@ -131,16 +130,16 @@ namespace JACK
|
||||||
{
|
{
|
||||||
_client->port_removed( this );
|
_client->port_removed( this );
|
||||||
|
|
||||||
if ( _name )
|
if ( _name )
|
||||||
{
|
{
|
||||||
free( _name );
|
free( _name );
|
||||||
_name = NULL;
|
_name = NULL;
|
||||||
}
|
}
|
||||||
if ( _trackname )
|
if ( _trackname )
|
||||||
{
|
{
|
||||||
free( _trackname );
|
free( _trackname );
|
||||||
_trackname = NULL;
|
_trackname = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,18 +206,13 @@ namespace JACK
|
||||||
|
|
||||||
/** returns the sum of latency of all ports between this one and a
|
/** returns the sum of latency of all ports between this one and a
|
||||||
terminal port. */
|
terminal port. */
|
||||||
/* FIMXE: how does JACK know that input A of client Foo connects to
|
|
||||||
output Z of the same client in order to draw the line through Z to a
|
|
||||||
terminal port? And, if this determination cannot be made, what use is
|
|
||||||
this function? */
|
|
||||||
|
|
||||||
nframes_t
|
nframes_t
|
||||||
Port::total_latency ( void ) const
|
Port::total_latency ( void ) const
|
||||||
{
|
{
|
||||||
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
|
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
|
||||||
jack_latency_range_t range;
|
jack_latency_range_t range;
|
||||||
|
|
||||||
jack_port_get_latency_range( _port, _direction == Output ? JackPlaybackLatency : JackCaptureLatency, &range );
|
jack_port_get_latency_range( _port, _direction == Input ? JackPlaybackLatency : JackCaptureLatency, &range );
|
||||||
|
|
||||||
return range.max;
|
return range.max;
|
||||||
#else
|
#else
|
||||||
|
@ -227,33 +221,36 @@ namespace JACK
|
||||||
}
|
}
|
||||||
|
|
||||||
/** returns the number of frames of latency assigned to this port */
|
/** returns the number of frames of latency assigned to this port */
|
||||||
nframes_t
|
void
|
||||||
Port::latency ( void ) const
|
Port::get_latency ( direction_e dir, nframes_t *min, nframes_t *max ) const
|
||||||
{
|
{
|
||||||
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
|
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
|
||||||
jack_latency_range_t range;
|
jack_latency_range_t range;
|
||||||
|
|
||||||
jack_port_get_latency_range( _port, _direction == Output ? JackPlaybackLatency : JackCaptureLatency, &range );
|
jack_port_get_latency_range( _port, dir == Output ? JackPlaybackLatency : JackCaptureLatency, &range );
|
||||||
|
|
||||||
return range.max;
|
*min = range.min;
|
||||||
|
*max = range.max;
|
||||||
#else
|
#else
|
||||||
return jack_port_get_latency( _port );
|
*min = *max = jack_port_get_latency( _port );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** inform JACK that port has /frames/ frames of latency */
|
/** inform JACK that port has /frames/ frames of latency */
|
||||||
void
|
void
|
||||||
Port::latency ( nframes_t frames )
|
Port::set_latency ( direction_e dir, nframes_t min, nframes_t max )
|
||||||
{
|
{
|
||||||
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
|
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
|
||||||
jack_latency_range_t range;
|
jack_latency_range_t range;
|
||||||
|
// DMESSAGE( "Setting port latency!" );
|
||||||
|
|
||||||
range.min = range.max = frames;
|
range.max = max;
|
||||||
|
range.min = min;
|
||||||
jack_port_set_latency_range( _port, _direction == Output ? JackPlaybackLatency : JackCaptureLatency, &range );
|
|
||||||
|
jack_port_set_latency_range( _port, dir == Output ? JackPlaybackLatency : JackCaptureLatency, &range );
|
||||||
#else
|
#else
|
||||||
jack_port_set_latency( _port, frames );
|
jack_port_set_latency( _port, max );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,8 +72,11 @@ namespace JACK
|
||||||
// bool name ( const char *base, int n, const char *type=0 );
|
// bool name ( const char *base, int n, const char *type=0 );
|
||||||
|
|
||||||
nframes_t total_latency ( void ) const;
|
nframes_t total_latency ( void ) const;
|
||||||
nframes_t latency ( void ) const;
|
|
||||||
void latency ( nframes_t frames );
|
void get_latency ( direction_e dir, nframes_t *min, nframes_t *max ) const;
|
||||||
|
|
||||||
|
/* it's only valid to call this in a latency callback! */
|
||||||
|
void set_latency ( direction_e dir, nframes_t min, nframes_t max );
|
||||||
|
|
||||||
void terminal ( bool b ) { _terminal = b; }
|
void terminal ( bool b ) { _terminal = b; }
|
||||||
bool activate ( void );
|
bool activate ( void );
|
||||||
|
@ -96,6 +99,8 @@ namespace JACK
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
friend class Client;
|
||||||
|
|
||||||
direction_e _direction;
|
direction_e _direction;
|
||||||
type_e _type;
|
type_e _type;
|
||||||
bool _terminal;
|
bool _terminal;
|
||||||
|
|
|
@ -643,7 +643,8 @@ Audio_Region::draw ( void )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
WARNING( "Pbuf == %p, peaks = %lu", pbuf, (unsigned long)peaks );
|
;
|
||||||
|
// WARNING( "Pbuf == %p, peaks = %lu", pbuf, (unsigned long)peaks );
|
||||||
|
|
||||||
if ( peaks < loop_peaks_needed )
|
if ( peaks < loop_peaks_needed )
|
||||||
{
|
{
|
||||||
|
|
|
@ -80,6 +80,22 @@ Engine::buffer_size ( nframes_t nframes )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nframes_t
|
||||||
|
Engine::playback_latency ( void ) const
|
||||||
|
{
|
||||||
|
#ifdef HAVE_JACK_PORT_GET_LATENCY_RANGE
|
||||||
|
jack_latency_range_t range;
|
||||||
|
|
||||||
|
jack_port_get_latency_range( jack_port_by_name( jack_client(), "system:playback_1" ),
|
||||||
|
JackPlaybackLatency,
|
||||||
|
&range );
|
||||||
|
|
||||||
|
return range.min;
|
||||||
|
#else
|
||||||
|
return jack_port_get_latency( jack_port_by_name( jack_client(), "system:playback_1" ) );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* THREAD: RT */
|
/* THREAD: RT */
|
||||||
/** This is the jack slow-sync callback. */
|
/** This is the jack slow-sync callback. */
|
||||||
int
|
int
|
||||||
|
|
|
@ -61,6 +61,7 @@ public:
|
||||||
int dropped ( void ) const { return _buffers_dropped; }
|
int dropped ( void ) const { return _buffers_dropped; }
|
||||||
|
|
||||||
nframes_t system_latency ( void ) const { return nframes(); }
|
nframes_t system_latency ( void ) const { return nframes(); }
|
||||||
|
nframes_t playback_latency ( void ) const;
|
||||||
|
|
||||||
float frames_to_milliseconds ( nframes_t frames )
|
float frames_to_milliseconds ( nframes_t frames )
|
||||||
{
|
{
|
||||||
|
|
|
@ -323,15 +323,3 @@ Timeline::total_capture_xruns ( void )
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "Engine.H"
|
|
||||||
extern Engine *engine;
|
|
||||||
|
|
||||||
nframes_t
|
|
||||||
Timeline::total_output_latency ( void ) const
|
|
||||||
{
|
|
||||||
/* Due to flaws in the JACK latency reporting API, we cannot
|
|
||||||
* reliably account for software latency. Using the system latency
|
|
||||||
* is the best we can do here. */
|
|
||||||
return engine->system_latency();
|
|
||||||
}
|
|
||||||
|
|
|
@ -301,6 +301,28 @@ Track::record ( Capture *c, nframes_t frame )
|
||||||
// Fl::unlock();
|
// Fl::unlock();
|
||||||
|
|
||||||
c->region->prepare();
|
c->region->prepare();
|
||||||
|
|
||||||
|
nframes_t min,max;
|
||||||
|
|
||||||
|
input[0].get_latency( JACK::Port::Input, &min, &max );
|
||||||
|
|
||||||
|
if ( transport->freewheel_enabled() )
|
||||||
|
{
|
||||||
|
/* in freewheeling mode, assume we're bouncing and only
|
||||||
|
* compensate for capture latency */
|
||||||
|
_capture_offset = min;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* not freewheeling, so assume we're overdubbing and need to
|
||||||
|
* compensate for both capture and playback latency */
|
||||||
|
_capture_offset = min;
|
||||||
|
|
||||||
|
/* since the track output might not be connected to
|
||||||
|
* anything, just get the playback latency */
|
||||||
|
|
||||||
|
_capture_offset += engine->playback_latency();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** write a block to the (already opened) capture file */
|
/** write a block to the (already opened) capture file */
|
||||||
|
@ -331,22 +353,10 @@ Track::finalize ( Capture *c, nframes_t frame )
|
||||||
|
|
||||||
c->region->finalize( frame );
|
c->region->finalize( frame );
|
||||||
|
|
||||||
nframes_t capture_offset = 0;
|
DMESSAGE( "Adjusting capture by %lu frames.", (unsigned long)_capture_offset );
|
||||||
|
|
||||||
/* Add the system latency twice. Once for the input (usually
|
c->region->offset( _capture_offset );
|
||||||
* required) and again for the output latency of whatever we're
|
_capture_offset = 0;
|
||||||
* playing along to (should only apply when overdubbing) */
|
|
||||||
|
|
||||||
/* Limitations in the JACK latency reporting API prevent us from
|
|
||||||
* compensating from any software latency introduced by other
|
|
||||||
* clients in our graph... Oh well */
|
|
||||||
|
|
||||||
capture_offset += engine->system_latency();
|
|
||||||
capture_offset += engine->system_latency();
|
|
||||||
|
|
||||||
DMESSAGE( "Adjusting capture by %lu frames.", (unsigned long)capture_offset );
|
|
||||||
|
|
||||||
c->region->offset( capture_offset );
|
|
||||||
|
|
||||||
timeline->unlock();
|
timeline->unlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -923,7 +923,7 @@ static char stats[100];
|
||||||
if ( engine && ! engine->zombified() )
|
if ( engine && ! engine->zombified() )
|
||||||
{
|
{
|
||||||
snprintf( stats, sizeof( stats ), "latency: %.1fms, xruns: %d",
|
snprintf( stats, sizeof( stats ), "latency: %.1fms, xruns: %d",
|
||||||
engine->frames_to_milliseconds( timeline->total_output_latency() ),
|
engine->frames_to_milliseconds( engine->system_latency() ),
|
||||||
engine->xruns() );
|
engine->xruns() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -263,7 +263,6 @@ public:
|
||||||
|
|
||||||
int total_playback_xruns ( void );
|
int total_playback_xruns ( void );
|
||||||
int total_capture_xruns ( void );
|
int total_capture_xruns ( void );
|
||||||
nframes_t total_output_latency ( void ) const;
|
|
||||||
|
|
||||||
bool record ( void );
|
bool record ( void );
|
||||||
void stop ( void );
|
void stop ( void );
|
||||||
|
|
|
@ -128,6 +128,7 @@ Track::~Track ( )
|
||||||
void
|
void
|
||||||
Track::init ( void )
|
Track::init ( void )
|
||||||
{
|
{
|
||||||
|
_capture_offset = 0;
|
||||||
_row = 0;
|
_row = 0;
|
||||||
_sequence = NULL;
|
_sequence = NULL;
|
||||||
_name = NULL;
|
_name = NULL;
|
||||||
|
|
|
@ -105,6 +105,8 @@ private:
|
||||||
|
|
||||||
int _row;
|
int _row;
|
||||||
|
|
||||||
|
nframes_t _capture_offset;
|
||||||
|
|
||||||
enum { AUDIO } _type;
|
enum { AUDIO } _type;
|
||||||
|
|
||||||
Audio_Sequence *_sequence;
|
Audio_Sequence *_sequence;
|
||||||
|
|
|
@ -190,6 +190,12 @@ Transport::toggle_record ( void )
|
||||||
update_record_state();
|
update_record_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Transport::freewheel_enabled ( void ) const
|
||||||
|
{
|
||||||
|
return _freewheel_button->value();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Transport::rec_enabled ( void ) const
|
Transport::rec_enabled ( void ) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
|
|
||||||
Transport ( int X, int Y, int W, int H, const char *L=0 );
|
Transport ( int X, int Y, int W, int H, const char *L=0 );
|
||||||
|
|
||||||
|
bool freewheel_enabled ( void ) const;
|
||||||
bool rec_enabled ( void ) const;
|
bool rec_enabled ( void ) const;
|
||||||
bool punch_enabled ( void ) const;
|
bool punch_enabled ( void ) const;
|
||||||
bool loop_enabled ( void ) const;
|
bool loop_enabled ( void ) const;
|
||||||
|
|
Loading…
Reference in New Issue