@@ -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 ) | |||||
{ | |||||
free( _name ); | |||||
_name = NULL; | |||||
} | |||||
if ( _trackname ) | |||||
{ | |||||
free( _trackname ); | |||||
_trackname = NULL; | |||||
} | |||||
if ( _name ) | |||||
{ | |||||
free( _name ); | |||||
_name = NULL; | |||||
} | |||||
if ( _trackname ) | |||||
{ | |||||
free( _trackname ); | |||||
_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 | |||||
Port::latency ( void ) const | |||||
void | |||||
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; | |||||
jack_port_set_latency_range( _port, _direction == Output ? JackPlaybackLatency : JackCaptureLatency, &range ); | |||||
range.max = max; | |||||
range.min = min; | |||||
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; | |||||
/* Add the system latency twice. Once for the input (usually | |||||
* required) and again for the output latency of whatever we're | |||||
* 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 ); | |||||
DMESSAGE( "Adjusting capture by %lu frames.", (unsigned long)_capture_offset ); | |||||
c->region->offset( capture_offset ); | |||||
c->region->offset( _capture_offset ); | |||||
_capture_offset = 0; | |||||
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; | ||||