@@ -66,9 +66,9 @@ Playback_DS::seek ( nframes_t frame ) | |||||
/** set the playback delay to /frames/ frames. This be called prior to | /** set the playback delay to /frames/ frames. This be called prior to | ||||
a seek. */ | a seek. */ | ||||
void | void | ||||
Playback_DS::delay ( nframes_t frames ) | |||||
Playback_DS::undelay ( nframes_t delay ) | |||||
{ | { | ||||
_delay = frames; | |||||
_undelay = delay; | |||||
} | } | ||||
/** read /nframes/ from the attached track into /buf/ */ | /** read /nframes/ from the attached track into /buf/ */ | ||||
@@ -94,13 +94,8 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes ) | |||||
if ( sequence() ) | if ( sequence() ) | ||||
{ | { | ||||
/* 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?" ); | |||||
} | |||||
if ( ! sequence()->play( buf, _frame + _undelay, nframes, channels() ) ) | |||||
WARNING( "Programming error?" ); | |||||
_frame += nframes; | _frame += nframes; | ||||
} | } | ||||
@@ -27,14 +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 */ | |||||
volatile nframes_t _undelay; /* number of frames this diskstream | |||||
* should be undelayed 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; | |||||
_undelay = 0; | |||||
run(); | run(); | ||||
} | } | ||||
@@ -45,6 +46,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 ); | |||||
void undelay ( nframes_t v ); | |||||
}; | }; |
@@ -234,17 +234,19 @@ Track::seek ( nframes_t frame ) | |||||
{ | { | ||||
THREAD_ASSERT( RT ); | THREAD_ASSERT( RT ); | ||||
compute_latency_compensation(); | |||||
if ( playback_ds ) | if ( playback_ds ) | ||||
return playback_ds->seek( frame ); | return playback_ds->seek( frame ); | ||||
} | } | ||||
void | void | ||||
Track::delay ( nframes_t frames ) | |||||
Track::undelay ( nframes_t nframes ) | |||||
{ | { | ||||
// THREAD_ASSERT( RT ); | // THREAD_ASSERT( RT ); | ||||
if ( playback_ds ) | if ( playback_ds ) | ||||
playback_ds->delay( frames ); | |||||
playback_ds->undelay( nframes ); | |||||
} | } | ||||
/* THREAD: RT (non-RT) */ | /* THREAD: RT (non-RT) */ | ||||
@@ -360,3 +362,21 @@ Track::finalize ( Capture *c, nframes_t frame ) | |||||
timeline->unlock(); | timeline->unlock(); | ||||
} | } | ||||
void | |||||
Track::compute_latency_compensation ( void ) | |||||
{ | |||||
if ( Timeline::playback_latency_compensation && output.size() ) | |||||
{ | |||||
nframes_t min,max; | |||||
output[0].get_latency( JACK::Port::Output, &min, &max ); | |||||
DMESSAGE( "Track %s, setting undelay to %lu", name(), (unsigned long)min); | |||||
undelay( min ); | |||||
} | |||||
else | |||||
{ | |||||
undelay( 0 ); | |||||
} | |||||
} |
@@ -325,6 +325,11 @@ pi.run();} | |||||
label {Capture Format} open | label {Capture Format} open | ||||
xywh {25 25 74 25} | xywh {25 25 74 25} | ||||
} {} | } {} | ||||
MenuItem {} { | |||||
label {Playback Latency Compensation} | |||||
callback {Timeline::playback_latency_compensation = menu_picked_value( o );} selected | |||||
xywh {55 55 40 25} type Toggle | |||||
} | |||||
} | } | ||||
MenuItem {} { | MenuItem {} { | ||||
label {&New} | label {&New} | ||||
@@ -364,9 +369,7 @@ main_window->redraw();} | |||||
} | } | ||||
MenuItem {} { | MenuItem {} { | ||||
label {&Open} | label {&Open} | ||||
callback { | |||||
char *path = read_line( user_config_dir, "default_path" ); | |||||
callback {char *path = read_line( user_config_dir, "default_path" ); | |||||
const char *name = fl_dir_chooser( "Open Project", path ); | const char *name = fl_dir_chooser( "Open Project", path ); | ||||
@@ -1107,7 +1110,7 @@ if ( logo_box->image() ) | |||||
code1 {o->label( NULL );} | code1 {o->label( NULL );} | ||||
} | } | ||||
Fl_Text_Editor notes_field { | Fl_Text_Editor notes_field { | ||||
label {Notes:} selected | |||||
label {Notes:} | |||||
private xywh {20 420 480 245} color 47 selection_color 31 textsize 18 textcolor 92 | private xywh {20 420 480 245} color 47 selection_color 31 textsize 18 textcolor 92 | ||||
code0 {o->buffer( new Fl_Text_Buffer() );} | code0 {o->buffer( new Fl_Text_Buffer() );} | ||||
code1 {o->buffer()->loadfile( "notes" );} | code1 {o->buffer()->loadfile( "notes" );} | ||||
@@ -73,6 +73,7 @@ bool Timeline::snapping_on_hold = false; | |||||
bool Timeline::snap_magnetic = true; | bool Timeline::snap_magnetic = true; | ||||
bool Timeline::follow_playhead = true; | bool Timeline::follow_playhead = true; | ||||
bool Timeline::center_playhead = true; | bool Timeline::center_playhead = true; | ||||
bool Timeline::playback_latency_compensation = false; | |||||
const float UPDATE_FREQ = 1.0f / 18.0f; | const float UPDATE_FREQ = 1.0f / 18.0f; | ||||
@@ -155,6 +155,7 @@ public: | |||||
static bool snap_magnetic; | static bool snap_magnetic; | ||||
static bool follow_playhead; | static bool follow_playhead; | ||||
static bool center_playhead; | static bool center_playhead; | ||||
static bool playback_latency_compensation; | |||||
Tempo_Sequence *tempo_track; | Tempo_Sequence *tempo_track; | ||||
Time_Sequence *time_track; | Time_Sequence *time_track; | ||||
@@ -253,8 +253,8 @@ 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 undelay ( nframes_t frames ); | |||||
void compute_latency_compensation ( void ); | |||||
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 ); | ||||
void finalize ( Capture *c, nframes_t frame ); | void finalize ( Capture *c, nframes_t frame ); | ||||