Implement capture-offset latency compensation.
This commit is contained in:
parent
1917e9295c
commit
86fa1ce238
|
@ -205,7 +205,6 @@ Engine::timebase ( jack_transport_state_t, jack_nframes_t, jack_position_t *pos,
|
|||
|
||||
/* FIXME: fill this in */
|
||||
pos->bar_start_tick = 0;
|
||||
|
||||
}
|
||||
|
||||
/* THREAD: RT */
|
||||
|
|
|
@ -86,7 +86,14 @@ public:
|
|||
void freewheeling ( bool yes );
|
||||
bool zombified ( void ) const { return _zombified; }
|
||||
|
||||
nframes_t system_latency ( void ) const { return nframes(); }
|
||||
|
||||
float cpu_load ( void ) const { return jack_cpu_load( _client ); }
|
||||
|
||||
float frames_to_milliseconds ( nframes_t frames )
|
||||
{
|
||||
return ( frames * 1000 ) / (float)frame_rate();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -60,6 +60,14 @@ Playback_DS::seek ( nframes_t frame )
|
|||
flush();
|
||||
}
|
||||
|
||||
/** set the playback delay to /frames/ frames. This be called prior to
|
||||
a seek. */
|
||||
void
|
||||
Playback_DS::delay ( nframes_t frames )
|
||||
{
|
||||
_delay = frames;
|
||||
}
|
||||
|
||||
/** read /nframes/ from the attached track into /buf/ */
|
||||
void
|
||||
Playback_DS::read_block ( sample_t *buf, nframes_t nframes )
|
||||
|
@ -76,16 +84,22 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes )
|
|||
|
||||
if ( ! sequence() )
|
||||
{
|
||||
/* FIXME: what to do here? */
|
||||
// _frame += _nframes;
|
||||
return;
|
||||
}
|
||||
|
||||
timeline->rdlock();
|
||||
|
||||
if ( sequence()->play( buf, _frame, nframes, channels() ) )
|
||||
_frame += nframes;
|
||||
else
|
||||
WARNING( "Programming error?" );
|
||||
/* FIXME: how does this work if _delay is not a multiple of bufsize? */
|
||||
|
||||
if ( _frame >= _delay )
|
||||
{
|
||||
if ( ! sequence()->play( buf, _frame - _delay, nframes, channels() ) )
|
||||
WARNING( "Programming error?" );
|
||||
}
|
||||
|
||||
_frame += nframes;
|
||||
|
||||
timeline->unlock();
|
||||
}
|
||||
|
|
|
@ -27,11 +27,15 @@ class Playback_DS : public Disk_Stream
|
|||
|
||||
void flush ( void ) { base_flush( true ); }
|
||||
|
||||
volatile nframes_t _delay; /* number of frames this diskstream should be delayed by */
|
||||
|
||||
public:
|
||||
|
||||
Playback_DS ( Track *th, float frame_rate, nframes_t nframes, int channels ) :
|
||||
Disk_Stream( th, frame_rate, nframes, channels )
|
||||
{
|
||||
_delay = 0;
|
||||
|
||||
run();
|
||||
}
|
||||
|
||||
|
@ -39,4 +43,6 @@ public:
|
|||
void seek ( nframes_t frame );
|
||||
nframes_t process ( nframes_t nframes );
|
||||
|
||||
void delay ( nframes_t v );
|
||||
|
||||
};
|
||||
|
|
|
@ -95,6 +95,33 @@ Port::activate ( const char *name, type_e dir )
|
|||
0 );
|
||||
}
|
||||
|
||||
/** returns the sum of latency of all ports between this one and a
|
||||
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
|
||||
Port::total_latency ( void ) const
|
||||
{
|
||||
return jack_port_get_total_latency( engine->client(), _port );
|
||||
}
|
||||
|
||||
/** returns the number of frames of latency assigned to this port */
|
||||
nframes_t
|
||||
Port::latency ( void ) const
|
||||
{
|
||||
return jack_port_get_latency( _port );
|
||||
}
|
||||
|
||||
/** inform JACK that port has /frames/ frames of latency */
|
||||
void
|
||||
Port::latency ( nframes_t frames )
|
||||
{
|
||||
jack_port_set_latency( _port, frames );
|
||||
}
|
||||
|
||||
void
|
||||
Port::shutdown ( void )
|
||||
{
|
||||
|
|
|
@ -63,7 +63,9 @@ public:
|
|||
const char * name ( void ) const { return _name; }
|
||||
bool name ( const char *name );
|
||||
bool name ( const char *base, int n, const char *type=0 );
|
||||
|
||||
nframes_t total_latency ( void ) const;
|
||||
nframes_t latency ( void ) const;
|
||||
void latency ( nframes_t frames );
|
||||
|
||||
void activate ( const char *name, type_e dir );
|
||||
void shutdown ( void );
|
||||
|
|
|
@ -235,3 +235,15 @@ Timeline::total_capture_xruns ( void )
|
|||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -204,6 +204,15 @@ Track::seek ( nframes_t frame )
|
|||
return playback_ds->seek( frame );
|
||||
}
|
||||
|
||||
void
|
||||
Track::delay ( nframes_t frames )
|
||||
{
|
||||
// THREAD_ASSERT( RT );
|
||||
|
||||
if ( playback_ds )
|
||||
playback_ds->delay( frames );
|
||||
}
|
||||
|
||||
/* THREAD: RT (non-RT) */
|
||||
void
|
||||
Track::resize_buffers ( nframes_t nframes )
|
||||
|
@ -266,9 +275,29 @@ Track::finalize ( Capture *c, nframes_t frame )
|
|||
{
|
||||
THREAD_ASSERT( Capture );
|
||||
|
||||
/* adjust region start for latency */
|
||||
/* FIXME: is just looking at the first channel good enough? */
|
||||
|
||||
c->region->finalize( frame );
|
||||
DMESSAGE( "finalizing audio file" );
|
||||
c->audio_file->finalize();
|
||||
|
||||
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 );
|
||||
|
||||
c->region->offset( capture_offset );
|
||||
|
||||
delete c->audio_file;
|
||||
}
|
||||
|
|
|
@ -205,7 +205,7 @@ Loggable::progress_callback( &TLE::progress_cb, this );} {}
|
|||
label Timeline
|
||||
callback {if ( Fl::event_key() != FL_Escape )
|
||||
o->hide();} open
|
||||
private xywh {133 113 1025 770} type Double resizable xclass Non_DAW visible
|
||||
private xywh {102 111 1025 770} type Double resizable xclass Non_DAW visible
|
||||
} {
|
||||
Fl_Menu_Bar menubar {open
|
||||
private xywh {0 0 1024 25}
|
||||
|
@ -577,7 +577,7 @@ ab.run();}
|
|||
}
|
||||
}
|
||||
Fl_Group {} {open
|
||||
xywh {0 23 1025 51}
|
||||
xywh {0 1 1025 73}
|
||||
} {
|
||||
Fl_Pack {} {open
|
||||
xywh {0 23 483 46} type HORIZONTAL
|
||||
|
@ -669,6 +669,10 @@ ab.run();}
|
|||
code0 {\#include "FL/Fl_Blinker.H"}
|
||||
class Fl_Blinker
|
||||
}
|
||||
Fl_Box stats_box {
|
||||
label {<stats>} selected
|
||||
xywh {810 1 215 21} labelsize 13 labelcolor 53 align 88
|
||||
}
|
||||
}
|
||||
Fl_Progress progress {
|
||||
label {0%}
|
||||
|
@ -682,13 +686,9 @@ ab.run();}
|
|||
}
|
||||
Fl_Box project_name {
|
||||
label {<project name>}
|
||||
private xywh {450 0 475 22} labeltype SHADOW_LABEL labelfont 2
|
||||
private xywh {450 0 365 22} labeltype SHADOW_LABEL labelfont 2
|
||||
code0 {o->label( Project::name() );}
|
||||
}
|
||||
Fl_Value_Output xruns_output {
|
||||
label {xruns:}
|
||||
private xywh {980 2 44 20} maximum 40000 step 1
|
||||
}
|
||||
}
|
||||
}
|
||||
Function {menu_picked_value( const Fl_Menu_ *m )} {private return_type {static int}
|
||||
|
@ -757,9 +757,13 @@ if ( timeline->total_capture_xruns() )
|
|||
if ( timeline->total_playback_xruns() )
|
||||
playback_buffer_progress->selection_color( FL_RED );
|
||||
|
||||
static char stats[100];
|
||||
|
||||
snprintf( stats, sizeof( stats ), "latency: %.1fms, xruns: %d",
|
||||
engine->frames_to_milliseconds( timeline->total_output_latency() ),
|
||||
engine->xruns() );
|
||||
|
||||
xruns_output->value( engine->xruns() );
|
||||
stats_box->label( stats );
|
||||
|
||||
static bool zombie = false;
|
||||
|
||||
|
|
|
@ -205,6 +205,7 @@ public:
|
|||
|
||||
int total_playback_xruns ( void );
|
||||
int total_capture_xruns ( void );
|
||||
nframes_t total_output_latency ( void ) const;
|
||||
|
||||
bool record ( void );
|
||||
void stop ( void );
|
||||
|
|
|
@ -215,6 +215,7 @@ public:
|
|||
nframes_t process_input ( nframes_t nframes );
|
||||
nframes_t process_output ( nframes_t nframes );
|
||||
void seek ( nframes_t frame );
|
||||
void delay ( nframes_t frames );
|
||||
|
||||
void record ( Capture *c, nframes_t frame );
|
||||
void write ( Capture *c, sample_t *buf, nframes_t nframes );
|
||||
|
|
Loading…
Reference in New Issue