Read from disk in larger chunks.
This commit is contained in:
parent
7793863d46
commit
f596d205db
|
@ -37,25 +37,24 @@
|
||||||
that is, at startup time. The default is 5 seconds, which may or
|
that is, at startup time. The default is 5 seconds, which may or
|
||||||
may not be excessive depending on various external factors. */
|
may not be excessive depending on various external factors. */
|
||||||
|
|
||||||
/* FIXME: handle termination of IO thread in destructor */
|
|
||||||
/* FIXME: deal with (jack) buffer size changes */
|
/* FIXME: deal with (jack) buffer size changes */
|
||||||
/* FIXME: needs error handling everywhere! */
|
/* FIXME: needs error handling everywhere! */
|
||||||
/* TODO: handle capture too. For this to work with some kind of
|
|
||||||
* punch-in/out system, I believe we'll have to always keep at least
|
|
||||||
* one buffer's worth of input. We would need this anyway in order to
|
|
||||||
* pass input through to output (software monitoring). What about
|
|
||||||
* looped recording? */
|
|
||||||
/* TODO: latency compensation? Does this really apply to us? (we're
|
|
||||||
* not hosting plugins here) */
|
|
||||||
/* TODO: read/write data from/to disk in larger chunks to avoid
|
/* TODO: read/write data from/to disk in larger chunks to avoid
|
||||||
* excessive seeking. 256k is supposedly the sweetspot. */
|
* excessive seeking. 256k is supposedly the sweetspot. */
|
||||||
|
|
||||||
// float Disk_Stream::seconds_to_buffer = 5.0f;
|
float Disk_Stream::seconds_to_buffer = 5.0f;
|
||||||
float Disk_Stream::seconds_to_buffer = 2.0f;
|
//float Disk_Stream::seconds_to_buffer = 2.0f;
|
||||||
// size_t Disk_Stream::disk_block_frames = 2048;
|
/* this is really only a rough estimate. The actual amount of data
|
||||||
|
read depends on many factors. Overlapping regions, for example, will
|
||||||
|
require more data to be read from disk, as will varying channel
|
||||||
|
counts.*/
|
||||||
|
size_t Disk_Stream::disk_io_kbytes = 256;
|
||||||
|
|
||||||
Disk_Stream::Disk_Stream ( Track *th, float frame_rate, nframes_t nframes, int channels ) : _th( th )
|
Disk_Stream::Disk_Stream ( Track *th, float frame_rate, nframes_t nframes, int channels ) : _th( th )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
assert( channels );
|
||||||
|
|
||||||
_frame = 0;
|
_frame = 0;
|
||||||
_thread = 0;
|
_thread = 0;
|
||||||
_terminate = false;
|
_terminate = false;
|
||||||
|
@ -69,6 +68,10 @@ Disk_Stream::Disk_Stream ( Track *th, float frame_rate, nframes_t nframes, int c
|
||||||
|
|
||||||
size_t bufsize = _total_blocks * nframes * sizeof( sample_t );
|
size_t bufsize = _total_blocks * nframes * sizeof( sample_t );
|
||||||
|
|
||||||
|
_disk_io_blocks = ( bufsize * channels ) / ( disk_io_kbytes * 1024 );
|
||||||
|
|
||||||
|
assert( _disk_io_blocks );
|
||||||
|
|
||||||
for ( int i = channels; i--; )
|
for ( int i = channels; i--; )
|
||||||
_rb.push_back( jack_ringbuffer_create( bufsize ) );
|
_rb.push_back( jack_ringbuffer_create( bufsize ) );
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ protected:
|
||||||
sem_t _blocks; /* semaphore to wake the IO thread with */
|
sem_t _blocks; /* semaphore to wake the IO thread with */
|
||||||
|
|
||||||
int _total_blocks; /* total number of blocks that we can buffer */
|
int _total_blocks; /* total number of blocks that we can buffer */
|
||||||
|
int _disk_io_blocks; /* the number of blocks to read/write to/from disk at once */
|
||||||
|
|
||||||
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;
|
||||||
|
@ -83,6 +84,7 @@ public:
|
||||||
|
|
||||||
/* must be set before any Disk_Streams are created */
|
/* must be set before any Disk_Streams are created */
|
||||||
static float seconds_to_buffer;
|
static float seconds_to_buffer;
|
||||||
|
static size_t disk_io_kbytes;
|
||||||
|
|
||||||
Disk_Stream ( Track *th, float frame_rate, nframes_t nframes, int channels );
|
Disk_Stream ( Track *th, float frame_rate, nframes_t nframes, int channels );
|
||||||
|
|
||||||
|
|
|
@ -109,9 +109,10 @@ Playback_DS::disk_thread ( void )
|
||||||
printf( "IO thread running...\n" );
|
printf( "IO thread running...\n" );
|
||||||
|
|
||||||
/* buffer to hold the interleaved data returned by the track reader */
|
/* buffer to hold the interleaved data returned by the track reader */
|
||||||
sample_t *buf = new sample_t[ _nframes * channels() ];
|
sample_t *buf = new sample_t[ _nframes * channels() * _disk_io_blocks ];
|
||||||
|
|
||||||
const size_t block_size = _nframes * sizeof( sample_t );
|
// const size_t block_size = _nframes * sizeof( sample_t );
|
||||||
|
int blocks_ready = 1;
|
||||||
|
|
||||||
while ( wait_for_block() )
|
while ( wait_for_block() )
|
||||||
{
|
{
|
||||||
|
@ -126,6 +127,7 @@ Playback_DS::disk_thread ( void )
|
||||||
printf( "performing seek\n" );
|
printf( "performing seek\n" );
|
||||||
_frame = _pending_seek;
|
_frame = _pending_seek;
|
||||||
_pending_seek = -1;
|
_pending_seek = -1;
|
||||||
|
blocks_ready = 1;
|
||||||
/* finish flushing the buffer */
|
/* finish flushing the buffer */
|
||||||
|
|
||||||
/* for ( int i = channels(); i-- ) */
|
/* for ( int i = channels(); i-- ) */
|
||||||
|
@ -133,8 +135,20 @@ Playback_DS::disk_thread ( void )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( blocks_ready < _disk_io_blocks )
|
||||||
|
{
|
||||||
|
++blocks_ready;
|
||||||
|
/* wait for more space */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset */
|
||||||
|
blocks_ready = 1;
|
||||||
|
|
||||||
|
const nframes_t nframes = _nframes * _disk_io_blocks;
|
||||||
|
|
||||||
/* FIXME: should we not read from disk in larger-than-JACK-buffer blocks? */
|
/* FIXME: should we not read from disk in larger-than-JACK-buffer blocks? */
|
||||||
read_block( buf, _nframes );
|
read_block( buf, nframes );
|
||||||
|
|
||||||
// unlock(); // for seeking
|
// unlock(); // for seeking
|
||||||
|
|
||||||
|
@ -157,22 +171,22 @@ Playback_DS::disk_thread ( void )
|
||||||
|
|
||||||
jack_ringbuffer_get_write_vector( _rb[ i ], rbd );
|
jack_ringbuffer_get_write_vector( _rb[ i ], rbd );
|
||||||
|
|
||||||
if ( rbd[ 0 ].len >= _nframes )
|
if ( rbd[ 0 ].len >= nframes )
|
||||||
/* it'll all fit in one go */
|
/* it'll all fit in one go */
|
||||||
buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), _nframes );
|
buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), nframes );
|
||||||
else if ( rbd[ 1 ].len )
|
else if ( rbd[ 1 ].len )
|
||||||
{
|
{
|
||||||
/* there's enough space in the ringbuffer, but it's not contiguous */
|
/* there's enough space in the ringbuffer, but it's not contiguous */
|
||||||
|
|
||||||
/* do the first half */
|
/* do the first half */
|
||||||
const nframes_t f = rbd[ 1 ].len / sizeof( sample_t );
|
const nframes_t f = rbd[ 0 ].len / sizeof( sample_t );
|
||||||
|
|
||||||
buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), f );
|
buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), f );
|
||||||
|
|
||||||
assert( rbd[ 1 ].len >= (_nframes - f) * sizeof( sample_t ) );
|
assert( rbd[ 1 ].len >= (nframes - f) * sizeof( sample_t ) );
|
||||||
|
|
||||||
/* do the second half */
|
/* do the second half */
|
||||||
buffer_deinterleave_one_channel( (sample_t*)rbd[ 1 ].buf, buf + f, i, channels(), _nframes - f );
|
buffer_deinterleave_one_channel( (sample_t*)rbd[ 1 ].buf, buf + f, i, channels(), nframes - f );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf( "programming error: expected more space in ringbuffer\n" );
|
printf( "programming error: expected more space in ringbuffer\n" );
|
||||||
|
@ -180,7 +194,7 @@ Playback_DS::disk_thread ( void )
|
||||||
/* buffer_deinterleave_one_channel( (sample_t*)rbd.buf, buf, i, channels(), _nframes ); */
|
/* buffer_deinterleave_one_channel( (sample_t*)rbd.buf, buf, i, channels(), _nframes ); */
|
||||||
/* jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size ); */
|
/* jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size ); */
|
||||||
|
|
||||||
jack_ringbuffer_write_advance( _rb[ i ], _nframes * sizeof( sample_t ) );
|
jack_ringbuffer_write_advance( _rb[ i ], nframes * sizeof( sample_t ) );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,16 +55,29 @@ Record_DS::disk_thread ( void )
|
||||||
|
|
||||||
printf( "IO thread running...\n" );
|
printf( "IO thread running...\n" );
|
||||||
|
|
||||||
/* buffer to hold the interleaved data returned by the track reader */
|
const nframes_t nframes = _nframes * _disk_io_blocks;
|
||||||
sample_t *buf = new sample_t[ _nframes * channels() ];
|
|
||||||
sample_t *cbuf = new sample_t[ _nframes ];
|
|
||||||
|
|
||||||
const size_t block_size = _nframes * sizeof( sample_t );
|
/* buffer to hold the interleaved data returned by the track reader */
|
||||||
|
sample_t *buf = new sample_t[ nframes * channels() ];
|
||||||
|
sample_t *cbuf = new sample_t[ nframes ];
|
||||||
|
|
||||||
|
const size_t block_size = nframes * sizeof( sample_t );
|
||||||
|
|
||||||
|
int blocks_ready = 1;
|
||||||
|
|
||||||
while ( wait_for_block() )
|
while ( wait_for_block() )
|
||||||
{
|
{
|
||||||
/* pull data from the per-channel ringbuffers and interlace it */
|
|
||||||
|
|
||||||
|
if ( blocks_ready < _disk_io_blocks )
|
||||||
|
{
|
||||||
|
++blocks_ready;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks_ready = 1;
|
||||||
|
|
||||||
|
|
||||||
|
/* pull data from the per-channel ringbuffers and interlace it */
|
||||||
for ( int i = channels(); i--; )
|
for ( int i = channels(); i--; )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -79,7 +92,7 @@ Record_DS::disk_thread ( void )
|
||||||
|
|
||||||
jack_ringbuffer_read( _rb[ i ], (char*)cbuf, block_size );
|
jack_ringbuffer_read( _rb[ i ], (char*)cbuf, block_size );
|
||||||
|
|
||||||
buffer_interleave_one_channel( buf, cbuf, i, channels(), _nframes );
|
buffer_interleave_one_channel( buf, cbuf, i, channels(), nframes );
|
||||||
|
|
||||||
|
|
||||||
/* /\* deinterleave direcectly into the ringbuffer to avoid */
|
/* /\* deinterleave direcectly into the ringbuffer to avoid */
|
||||||
|
@ -118,7 +131,7 @@ Record_DS::disk_thread ( void )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write_block( buf, _nframes );
|
write_block( buf, nframes );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,9 @@ Track::init ( void )
|
||||||
_show_all_takes = false;
|
_show_all_takes = false;
|
||||||
_size = 1;
|
_size = 1;
|
||||||
|
|
||||||
|
record_ds = NULL;
|
||||||
|
playback_ds = NULL;
|
||||||
|
|
||||||
labeltype( FL_NO_LABEL );
|
labeltype( FL_NO_LABEL );
|
||||||
|
|
||||||
Fl_Group::size( timeline->w(), height() );
|
Fl_Group::size( timeline->w(), height() );
|
||||||
|
@ -215,8 +218,6 @@ Track::init ( void )
|
||||||
}
|
}
|
||||||
end();
|
end();
|
||||||
|
|
||||||
playback_ds = new Playback_DS( this, engine->frame_rate(), engine->nframes(), output.size() );
|
|
||||||
record_ds = new Record_DS( this, engine->frame_rate(), engine->nframes(), input.size() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -561,11 +562,14 @@ Track::configure_outputs ( int n )
|
||||||
|
|
||||||
// engine->lock();
|
// engine->lock();
|
||||||
|
|
||||||
Playback_DS *ds = playback_ds;
|
if ( playback_ds )
|
||||||
playback_ds = NULL;
|
{
|
||||||
|
Playback_DS *ds = playback_ds;
|
||||||
|
playback_ds = NULL;
|
||||||
|
|
||||||
ds->shutdown();
|
ds->shutdown();
|
||||||
delete ds;
|
delete ds;
|
||||||
|
}
|
||||||
|
|
||||||
if ( n > on )
|
if ( n > on )
|
||||||
{
|
{
|
||||||
|
@ -606,11 +610,14 @@ Track::configure_inputs ( int n )
|
||||||
|
|
||||||
// engine->lock();
|
// engine->lock();
|
||||||
|
|
||||||
Record_DS *ds = record_ds;
|
if ( record_ds )
|
||||||
record_ds = NULL;
|
{
|
||||||
|
Record_DS *ds = record_ds;
|
||||||
|
record_ds = NULL;
|
||||||
|
|
||||||
ds->shutdown();
|
ds->shutdown();
|
||||||
delete ds;
|
delete ds;
|
||||||
|
}
|
||||||
|
|
||||||
if ( n > on )
|
if ( n > on )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue