Browse Source

Implement capture-offset latency compensation.

tags/non-daw-v1.1.0
Jonathan Moore Liles 16 years ago
parent
commit
86fa1ce238
11 changed files with 116 additions and 14 deletions
  1. +0
    -1
      Timeline/Engine/Engine.C
  2. +7
    -0
      Timeline/Engine/Engine.H
  3. +18
    -4
      Timeline/Engine/Playback_DS.C
  4. +6
    -0
      Timeline/Engine/Playback_DS.H
  5. +27
    -0
      Timeline/Engine/Port.C
  6. +3
    -1
      Timeline/Engine/Port.H
  7. +12
    -0
      Timeline/Engine/Timeline.C
  8. +29
    -0
      Timeline/Engine/Track.C
  9. +12
    -8
      Timeline/TLE.fl
  10. +1
    -0
      Timeline/Timeline.H
  11. +1
    -0
      Timeline/Track.H

+ 0
- 1
Timeline/Engine/Engine.C View File

@@ -205,7 +205,6 @@ Engine::timebase ( jack_transport_state_t, jack_nframes_t, jack_position_t *pos,


/* FIXME: fill this in */ /* FIXME: fill this in */
pos->bar_start_tick = 0; pos->bar_start_tick = 0;

} }


/* THREAD: RT */ /* THREAD: RT */


+ 7
- 0
Timeline/Engine/Engine.H View File

@@ -86,7 +86,14 @@ public:
void freewheeling ( bool yes ); void freewheeling ( bool yes );
bool zombified ( void ) const { return _zombified; } 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 cpu_load ( void ) const { return jack_cpu_load( _client ); }

float frames_to_milliseconds ( nframes_t frames )
{
return ( frames * 1000 ) / (float)frame_rate();
}
}; };






+ 18
- 4
Timeline/Engine/Playback_DS.C View File

@@ -60,6 +60,14 @@ Playback_DS::seek ( nframes_t frame )
flush(); 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/ */ /** read /nframes/ from the attached track into /buf/ */
void void
Playback_DS::read_block ( sample_t *buf, nframes_t nframes ) 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() ) if ( ! sequence() )
{ {
/* FIXME: what to do here? */
// _frame += _nframes; // _frame += _nframes;
return; return;
} }


timeline->rdlock(); 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(); timeline->unlock();
} }


+ 6
- 0
Timeline/Engine/Playback_DS.H View File

@@ -27,11 +27,15 @@ class Playback_DS : public Disk_Stream


void flush ( void ) { base_flush( true ); } void flush ( void ) { base_flush( true ); }


volatile nframes_t _delay; /* number of frames this diskstream should be delayed by */

public: public:


Playback_DS ( Track *th, float frame_rate, nframes_t nframes, int channels ) : Playback_DS ( Track *th, float frame_rate, nframes_t nframes, int channels ) :
Disk_Stream( th, frame_rate, nframes, channels ) Disk_Stream( th, frame_rate, nframes, channels )
{ {
_delay = 0;

run(); run();
} }


@@ -39,4 +43,6 @@ public:
void seek ( nframes_t frame ); void seek ( nframes_t frame );
nframes_t process ( nframes_t nframes ); nframes_t process ( nframes_t nframes );


void delay ( nframes_t v );

}; };

+ 27
- 0
Timeline/Engine/Port.C View File

@@ -95,6 +95,33 @@ Port::activate ( const char *name, type_e dir )
0 ); 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 void
Port::shutdown ( void ) Port::shutdown ( void )
{ {


+ 3
- 1
Timeline/Engine/Port.H View File

@@ -63,7 +63,9 @@ public:
const char * name ( void ) const { return _name; } const char * name ( void ) const { return _name; }
bool name ( const char *name ); bool name ( const char *name );
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 latency ( void ) const;
void latency ( nframes_t frames );


void activate ( const char *name, type_e dir ); void activate ( const char *name, type_e dir );
void shutdown ( void ); void shutdown ( void );


+ 12
- 0
Timeline/Engine/Timeline.C View File

@@ -235,3 +235,15 @@ 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();
}

+ 29
- 0
Timeline/Engine/Track.C View File

@@ -204,6 +204,15 @@ Track::seek ( nframes_t frame )
return playback_ds->seek( 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) */ /* THREAD: RT (non-RT) */
void void
Track::resize_buffers ( nframes_t nframes ) Track::resize_buffers ( nframes_t nframes )
@@ -266,9 +275,29 @@ Track::finalize ( Capture *c, nframes_t frame )
{ {
THREAD_ASSERT( Capture ); THREAD_ASSERT( Capture );


/* adjust region start for latency */
/* FIXME: is just looking at the first channel good enough? */

c->region->finalize( frame ); c->region->finalize( frame );
DMESSAGE( "finalizing audio file" ); DMESSAGE( "finalizing audio file" );
c->audio_file->finalize(); 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; delete c->audio_file;
} }

+ 12
- 8
Timeline/TLE.fl View File

@@ -205,7 +205,7 @@ Loggable::progress_callback( &TLE::progress_cb, this );} {}
label Timeline label Timeline
callback {if ( Fl::event_key() != FL_Escape ) callback {if ( Fl::event_key() != FL_Escape )
o->hide();} open 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 Fl_Menu_Bar menubar {open
private xywh {0 0 1024 25} private xywh {0 0 1024 25}
@@ -577,7 +577,7 @@ ab.run();}
} }
} }
Fl_Group {} {open Fl_Group {} {open
xywh {0 23 1025 51}
xywh {0 1 1025 73}
} { } {
Fl_Pack {} {open Fl_Pack {} {open
xywh {0 23 483 46} type HORIZONTAL xywh {0 23 483 46} type HORIZONTAL
@@ -669,6 +669,10 @@ ab.run();}
code0 {\#include "FL/Fl_Blinker.H"} code0 {\#include "FL/Fl_Blinker.H"}
class Fl_Blinker class Fl_Blinker
} }
Fl_Box stats_box {
label {<stats>} selected
xywh {810 1 215 21} labelsize 13 labelcolor 53 align 88
}
} }
Fl_Progress progress { Fl_Progress progress {
label {0%} label {0%}
@@ -682,13 +686,9 @@ ab.run();}
} }
Fl_Box project_name { Fl_Box project_name {
label {<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() );} 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} 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() ) if ( timeline->total_playback_xruns() )
playback_buffer_progress->selection_color( FL_RED ); 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; static bool zombie = false;




+ 1
- 0
Timeline/Timeline.H View File

@@ -205,6 +205,7 @@ 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 );


+ 1
- 0
Timeline/Track.H View File

@@ -215,6 +215,7 @@ public:
nframes_t process_input ( nframes_t nframes ); nframes_t process_input ( nframes_t nframes );
nframes_t process_output ( nframes_t nframes ); nframes_t process_output ( nframes_t nframes );
void seek ( nframes_t frame ); void seek ( nframes_t frame );
void delay ( nframes_t frames );


void record ( Capture *c, nframes_t frame ); void record ( Capture *c, nframes_t frame );
void write ( Capture *c, sample_t *buf, nframes_t nframes ); void write ( Capture *c, sample_t *buf, nframes_t nframes );


Loading…
Cancel
Save