@@ -51,7 +51,6 @@ protected: | |||||
nframes_t _nframes; /* buffer size */ | nframes_t _nframes; /* buffer size */ | ||||
nframes_t _frame; /* location of disk read */ | |||||
std::vector < jack_ringbuffer_t * >_rb; /* one ringbuffer for each channel */ | std::vector < jack_ringbuffer_t * >_rb; /* one ringbuffer for each channel */ | ||||
@@ -63,6 +62,7 @@ protected: | |||||
nframes_t _frame_rate; /* used for buffer size calculations */ | nframes_t _frame_rate; /* used for buffer size calculations */ | ||||
volatile nframes_t _frame; /* location of disk read */ | |||||
volatile nframes_t _pending_seek; /* absolute transport position to seek to */ | volatile nframes_t _pending_seek; /* absolute transport position to seek to */ | ||||
volatile int _terminate; | volatile int _terminate; | ||||
@@ -49,7 +49,8 @@ Playback_DS::seek ( nframes_t frame ) | |||||
{ | { | ||||
THREAD_ASSERT( RT ); | THREAD_ASSERT( RT ); | ||||
DMESSAGE( "requesting seek" ); | |||||
/* FIXME: non-RT-safe IO */ | |||||
DMESSAGE( "requesting seek to frame %lu", (unsigned long)frame ); | |||||
if ( seek_pending() ) | if ( seek_pending() ) | ||||
printf( "seek error, attempt to seek while seek is pending\n" ); | printf( "seek error, attempt to seek while seek is pending\n" ); | ||||
@@ -104,7 +105,7 @@ Playback_DS::disk_thread ( void ) | |||||
sample_t *cbuf = new sample_t[ _nframes * _disk_io_blocks ]; | sample_t *cbuf = new sample_t[ _nframes * _disk_io_blocks ]; | ||||
#endif | #endif | ||||
int blocks_ready = 1; | |||||
int blocks_ready = 0; | |||||
const nframes_t nframes = _nframes * _disk_io_blocks; | const nframes_t nframes = _nframes * _disk_io_blocks; | ||||
@@ -115,27 +116,22 @@ Playback_DS::disk_thread ( void ) | |||||
if ( seek_pending() ) | if ( seek_pending() ) | ||||
{ | { | ||||
DMESSAGE( "performing seek" ); | |||||
/* FIXME: non-RT-safe IO */ | |||||
DMESSAGE( "performing seek to frame %lu", (unsigned long)_pending_seek ); | |||||
_frame = _pending_seek; | _frame = _pending_seek; | ||||
_pending_seek = -1; | _pending_seek = -1; | ||||
blocks_ready = 1; | |||||
/* finish flushing the buffer */ | |||||
/* for ( int i = channels(); i-- ) */ | |||||
/* jack_ringbuffer_write_advance( _rb[ i ], jack_ringbuffer_write_space( _rb[ i ] ) ); */ | |||||
blocks_ready = 0; | |||||
} | } | ||||
if ( blocks_ready < _disk_io_blocks ) | |||||
if ( ++blocks_ready < _disk_io_blocks ) | |||||
{ | { | ||||
++blocks_ready; | |||||
/* wait for more space */ | /* wait for more space */ | ||||
continue; | continue; | ||||
} | } | ||||
/* reset */ | /* reset */ | ||||
blocks_ready = 1; | |||||
blocks_ready = 0; | |||||
read_block( buf, nframes ); | read_block( buf, nframes ); | ||||
@@ -211,6 +207,7 @@ Playback_DS::process ( nframes_t nframes ) | |||||
{ | { | ||||
THREAD_ASSERT( RT ); | THREAD_ASSERT( RT ); | ||||
const size_t block_size = nframes * sizeof( sample_t ); | const size_t block_size = nframes * sizeof( sample_t ); | ||||
// printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes ); | // printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes ); | ||||
@@ -72,7 +72,6 @@ Record_DS::disk_thread ( void ) | |||||
DMESSAGE( "capture thread running..." ); | DMESSAGE( "capture thread running..." ); | ||||
const nframes_t nframes = _nframes * _disk_io_blocks; | const nframes_t nframes = _nframes * _disk_io_blocks; | ||||
/* buffer to hold the interleaved data returned by the track reader */ | /* buffer to hold the interleaved data returned by the track reader */ | ||||
@@ -83,18 +82,14 @@ Record_DS::disk_thread ( void ) | |||||
const size_t block_size = nframes * sizeof( sample_t ); | const size_t block_size = nframes * sizeof( sample_t ); | ||||
int blocks_ready = 1; | |||||
int blocks_ready = 0; | |||||
while ( wait_for_block() ) | while ( wait_for_block() ) | ||||
{ | { | ||||
if ( blocks_ready < _disk_io_blocks ) | |||||
{ | |||||
++blocks_ready; | |||||
if ( ++blocks_ready < _disk_io_blocks ) | |||||
continue; | continue; | ||||
} | |||||
blocks_ready = 1; | |||||
else | |||||
blocks_ready = 0; | |||||
/* pull data from the per-channel ringbuffers and interlace it */ | /* pull data from the per-channel ringbuffers and interlace it */ | ||||
for ( int i = channels(); i--; ) | for ( int i = channels(); i--; ) | ||||
@@ -204,6 +199,7 @@ Record_DS::disk_thread ( void ) | |||||
_capture = NULL; | _capture = NULL; | ||||
/* now finalize the recording */ | /* now finalize the recording */ | ||||
track()->finalize( c, _stop_frame ); | track()->finalize( c, _stop_frame ); | ||||
delete c; | delete c; | ||||
@@ -228,6 +224,8 @@ Record_DS::start ( nframes_t frame ) | |||||
/* /\* FIXME: safe to do this here? *\/ */ | /* /\* FIXME: safe to do this here? *\/ */ | ||||
/* flush(); */ | /* flush(); */ | ||||
DMESSAGE( "recording started at frame %lu", (unsigned long)frame); | |||||
_frame = frame; | _frame = frame; | ||||
_capture = new Track::Capture; | _capture = new Track::Capture; | ||||
@@ -260,6 +258,9 @@ Record_DS::stop ( nframes_t frame ) | |||||
} | } | ||||
#include "../Transport.H" | |||||
extern Transport *transport; | |||||
/** read from the attached track's ports and stuff the ringbuffers */ | /** read from the attached track's ports and stuff the ringbuffers */ | ||||
nframes_t | nframes_t | ||||
Record_DS::process ( nframes_t nframes ) | Record_DS::process ( nframes_t nframes ) | ||||
@@ -269,13 +270,40 @@ Record_DS::process ( nframes_t nframes ) | |||||
if ( ! _recording ) | if ( ! _recording ) | ||||
return 0; | return 0; | ||||
const size_t block_size = nframes * sizeof( sample_t ); | |||||
if ( transport->frame < _frame ) | |||||
return 0; | |||||
/* DMESSAGE( "recording actually happening at %lu (start frame %lu)", (unsigned long)transport->frame, (unsigned long)_frame); */ | |||||
nframes_t offset = 0; | |||||
if ( _frame > transport->frame && | |||||
_frame < transport->frame + nframes ) | |||||
{ | |||||
/* The record start frame falls somewhere within the current | |||||
buffer. We must discard the unneeded portion and only | |||||
stuff the part requested into the ringbuffer. */ | |||||
offset = _frame - transport->frame; | |||||
/* DMESSAGE( "offset = %lu", (unsigned long)offset ); */ | |||||
} | |||||
const size_t offset_size = offset * sizeof( sample_t ); | |||||
const size_t block_size = ( nframes * sizeof( sample_t ) ) - offset_size; | |||||
for ( int i = channels(); i--; ) | for ( int i = channels(); i--; ) | ||||
{ | { | ||||
/* read the entire input buffer */ | |||||
void *buf = track()->input[ i ].buffer( nframes ); | void *buf = track()->input[ i ].buffer( nframes ); | ||||
if ( jack_ringbuffer_write( _rb[ i ], (char*)buf, block_size ) < block_size ) | |||||
/* if ( buffer_is_digital_black( (sample_t*)buf, nframes ) ) */ | |||||
/* DWARNING( "recording an entirely blank buffer" ); */ | |||||
/* FIXME: this results in a ringbuffer size that is no longer | |||||
necessarily a multiple of nframes... how will the other side | |||||
handle that? */ | |||||
if ( jack_ringbuffer_write( _rb[ i ], (char*)buf + offset, block_size ) < block_size ) | |||||
{ | { | ||||
++_xruns; | ++_xruns; | ||||
memset( buf, 0, block_size ); | memset( buf, 0, block_size ); | ||||
@@ -38,6 +38,8 @@ Timeline::record ( void ) | |||||
nframes_t frame = transport->frame; | nframes_t frame = transport->frame; | ||||
DMESSAGE( "Going to record starting at frame %lu", (unsigned long)frame ); | |||||
for ( int i = tracks->children(); i-- ; ) | for ( int i = tracks->children(); i-- ; ) | ||||
{ | { | ||||
Track *t = (Track*)tracks->child( i ); | Track *t = (Track*)tracks->child( i ); | ||||
@@ -85,7 +87,14 @@ Timeline::process ( nframes_t nframes ) | |||||
{ | { | ||||
Track *t = (Track*)tracks->child( i ); | Track *t = (Track*)tracks->child( i ); | ||||
t->process( nframes ); | |||||
t->process_output( nframes ); | |||||
} | |||||
for ( int i = tracks->children(); i-- ; ) | |||||
{ | |||||
Track *t = (Track*)tracks->child( i ); | |||||
t->process_input( nframes ); | |||||
} | } | ||||
/* FIXME: BOGUS */ | /* FIXME: BOGUS */ | ||||
@@ -151,33 +151,50 @@ Track::configure_inputs ( int n ) | |||||
} | } | ||||
nframes_t | nframes_t | ||||
Track::process ( nframes_t nframes ) | |||||
Track::process_input ( nframes_t nframes ) | |||||
{ | { | ||||
THREAD_ASSERT( RT ); | THREAD_ASSERT( RT ); | ||||
if ( ! transport->rolling ) | if ( ! transport->rolling ) | ||||
{ | { | ||||
for ( int i = output.size(); i--; ) | |||||
output[ i ].silence( nframes ); | |||||
for ( int i = input.size(); i--; ) | for ( int i = input.size(); i--; ) | ||||
input[ i ].silence( nframes ); | input[ i ].silence( nframes ); | ||||
return 0; | return 0; | ||||
} | } | ||||
if ( record_ds ) | |||||
return record_ds->process( nframes ); | |||||
else | |||||
return 0; | |||||
} | |||||
nframes_t | |||||
Track::process_output ( nframes_t nframes ) | |||||
{ | |||||
THREAD_ASSERT( RT ); | |||||
if ( ! transport->rolling ) | |||||
{ | |||||
for ( int i = output.size(); i--; ) | |||||
output[ i ].silence( nframes ); | |||||
return 0; | |||||
} | |||||
/* FIXME: should we blank the control output here or leave it floating? */ | |||||
for ( int i = control->children(); i--; ) | for ( int i = control->children(); i--; ) | ||||
((Control_Sequence*)control->child( i ))->process( nframes ); | ((Control_Sequence*)control->child( i ))->process( nframes ); | ||||
if ( playback_ds ) | if ( playback_ds ) | ||||
{ | |||||
record_ds->process( nframes ); | |||||
return playback_ds->process( nframes ); | return playback_ds->process( nframes ); | ||||
} | |||||
else | else | ||||
return 0; | return 0; | ||||
} | } | ||||
void | void | ||||
Track::seek ( nframes_t frame ) | Track::seek ( nframes_t frame ) | ||||
{ | { | ||||
@@ -95,3 +95,15 @@ buffer_fill_with_silence ( sample_t *buf, nframes_t nframes ) | |||||
{ | { | ||||
memset( buf, 0, nframes * sizeof( sample_t ) ); | memset( buf, 0, nframes * sizeof( sample_t ) ); | ||||
} | } | ||||
bool | |||||
buffer_is_digital_black ( sample_t *buf, nframes_t nframes ) | |||||
{ | |||||
while ( nframes-- ) | |||||
{ | |||||
if ( 0 != buf[nframes] ) | |||||
return false; | |||||
} | |||||
return true; | |||||
} |
@@ -29,3 +29,4 @@ void buffer_interleave_one_channel ( sample_t *dst, sample_t *src, int channel, | |||||
void buffer_interleave_one_channel_and_mix ( sample_t *dst, sample_t *src, int channel, int channels, nframes_t nframes ); | void buffer_interleave_one_channel_and_mix ( sample_t *dst, sample_t *src, int channel, int channels, nframes_t nframes ); | ||||
void buffer_deinterleave_one_channel ( sample_t *dst, sample_t *src, int channel, int channels, nframes_t nframes ); | void buffer_deinterleave_one_channel ( sample_t *dst, sample_t *src, int channel, int channels, nframes_t nframes ); | ||||
void buffer_fill_with_silence ( sample_t *buf, nframes_t nframes ); | void buffer_fill_with_silence ( sample_t *buf, nframes_t nframes ); | ||||
bool buffer_is_digital_black ( sample_t *buf, nframes_t nframes ); |
@@ -207,7 +207,8 @@ public: | |||||
const Audio_Region *capture_region ( void ) const; | const Audio_Region *capture_region ( void ) const; | ||||
void resize_buffers ( nframes_t nframes ); | void resize_buffers ( nframes_t nframes ); | ||||
nframes_t process ( nframes_t nframes ); | |||||
nframes_t process_input ( nframes_t nframes ); | |||||
nframes_t process_output ( nframes_t nframes ); | |||||
void seek ( nframes_t frame ); | void seek ( nframes_t frame ); | ||||
void record ( Capture *c, nframes_t frame ); | void record ( Capture *c, nframes_t frame ); | ||||