Browse Source

Timeline: Fix numerous issues with diskstream.

tags/non-daw-v1.2.0
Jonathan Moore Liles 11 years ago
parent
commit
58fdf7d914
6 changed files with 127 additions and 160 deletions
  1. +13
    -35
      timeline/src/Engine/Disk_Stream.C
  2. +8
    -4
      timeline/src/Engine/Disk_Stream.H
  3. +0
    -7
      timeline/src/Engine/Engine.C
  4. +76
    -71
      timeline/src/Engine/Playback_DS.C
  5. +29
    -33
      timeline/src/Engine/Record_DS.C
  6. +1
    -10
      timeline/src/Engine/Timeline.C

+ 13
- 35
timeline/src/Engine/Disk_Stream.C View File

@@ -61,13 +61,14 @@ Disk_Stream::Disk_Stream ( Track *track, float frame_rate, nframes_t nframes, in


_frame = 0; _frame = 0;
_terminate = false; _terminate = false;
_pending_seek = -1;
_pending_seek = false;
_seek_frame = 0;
_xruns = 0; _xruns = 0;
_frame_rate = frame_rate; _frame_rate = frame_rate;


sem_init( &_blocks, 0, 0 );
_resize_buffers( nframes, channels ); _resize_buffers( nframes, channels );

sem_init( &_blocks, 0, _total_blocks );
} }


Disk_Stream::~Disk_Stream ( ) Disk_Stream::~Disk_Stream ( )
@@ -94,37 +95,18 @@ Disk_Stream::~Disk_Stream ( )
void void
Disk_Stream::base_flush ( bool is_output ) Disk_Stream::base_flush ( bool is_output )
{ {
THREAD_ASSERT( RT );
// THREAD_ASSERT( RT );


/* flush buffers */ /* flush buffers */
for ( int i = _rb.size(); i--; )
jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) );

/* sem_destroy( &_blocks ); */

/* if ( is_output ) */
/* sem_init( &_blocks, 0, _total_blocks ); */
/* else */
/* sem_init( &_blocks, 0, 0 ); */
for ( unsigned int i = _rb.size(); i--; )
jack_ringbuffer_reset( _rb[ i ] );


sem_destroy( &_blocks );
if ( is_output ) if ( is_output )
{
int n;
sem_getvalue( &_blocks, &n );

n = _total_blocks - n;

while ( n-- )
sem_post( &_blocks );
}
sem_init( &_blocks, 0, _total_blocks );
else else
{
sem_destroy( &_blocks );

sem_init( &_blocks, 0, 0 ); sem_init( &_blocks, 0, 0 );
}


} }


/** signal thread to terminate, then detach it */ /** signal thread to terminate, then detach it */
@@ -156,10 +138,6 @@ Disk_Stream::shutdown ( void )
} }
_thread.join(); _thread.join();

sem_destroy( &_blocks );

sem_init( &_blocks, 0, 0 );
} }
} }


@@ -195,7 +173,7 @@ Disk_Stream::_resize_buffers ( nframes_t nframes, int channels )


_nframes = nframes; _nframes = nframes;


_total_blocks = _frame_rate * seconds_to_buffer / nframes;
_total_blocks = ( _frame_rate * seconds_to_buffer ) / nframes;


size_t bufsize = _total_blocks * nframes * sizeof( sample_t ); size_t bufsize = _total_blocks * nframes * sizeof( sample_t );


@@ -222,10 +200,10 @@ Disk_Stream::resize_buffers ( nframes_t nframes )
if ( was_running ) if ( was_running )
shutdown(); shutdown();


flush();

_resize_buffers( nframes, channels() ); _resize_buffers( nframes, channels() );


flush();

if ( was_running ) if ( was_running )
run(); run();
} }


+ 8
- 4
timeline/src/Engine/Disk_Stream.H View File

@@ -56,14 +56,15 @@ 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 _disk_io_blocks; /* the number of blocks to read/write to/from disk at once */
nframes_t _total_blocks; /* total number of blocks that we can buffer */
nframes_t _disk_io_blocks; /* the number of blocks to read/write to/from disk at once */




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 _frame; /* location of disk read */
volatile nframes_t _pending_seek; /* absolute transport position to seek to */
volatile nframes_t _seek_frame; /* absolute transport position to seek to */
volatile bool _pending_seek; /* absolute transport position to seek to */
volatile int _terminate; volatile int _terminate;


volatile int _xruns; volatile int _xruns;
@@ -82,6 +83,9 @@ protected:
void block_processed ( void ) { sem_post( &_blocks ); } void block_processed ( void ) { sem_post( &_blocks ); }
bool wait_for_block ( void ) bool wait_for_block ( void )
{ {
if ( _terminate )
return false;

while ( ! sem_wait( &_blocks ) && errno == EINTR ) while ( ! sem_wait( &_blocks ) && errno == EINTR )
{} {}


@@ -117,6 +121,6 @@ public:


virtual nframes_t process ( nframes_t nframes ) = 0; virtual nframes_t process ( nframes_t nframes ) = 0;


int buffer_percent ( void );
virtual int buffer_percent ( void );


}; };

+ 0
- 7
timeline/src/Engine/Engine.C View File

@@ -174,10 +174,6 @@ Engine::process ( nframes_t nframes )


if ( freewheeling() ) if ( freewheeling() )
{ {
/* freewheeling mode/export. We're actually running
non-RT. Assume that everything is quiescent. do I/O
synchronously */
if ( timeline ) if ( timeline )
{ {
timeline->rdlock(); timeline->rdlock();
@@ -185,9 +181,6 @@ Engine::process ( nframes_t nframes )
timeline->process( nframes ); timeline->process( nframes );


timeline->unlock(); timeline->unlock();

/* because we're going faster than realtime. */
timeline->wait_for_buffers();
} }
} }
else else


+ 76
- 71
timeline/src/Engine/Playback_DS.C View File

@@ -38,7 +38,7 @@
bool bool
Playback_DS::seek_pending ( void ) Playback_DS::seek_pending ( void )
{ {
return _pending_seek != (nframes_t)-1;
return _pending_seek || buffer_percent() < 50;
} }


/** request that the IO thread perform a seek and rebuffer. This is /** request that the IO thread perform a seek and rebuffer. This is
@@ -56,9 +56,11 @@ Playback_DS::seek ( nframes_t 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" );


_pending_seek = frame;
_seek_frame = frame;
_pending_seek = true;


flush();
/* wake the IO thread */
block_processed();
} }


/** set the playback delay to /frames/ frames. This be called prior to /** set the playback delay to /frames/ frames. This be called prior to
@@ -82,30 +84,28 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes )
if ( !timeline ) if ( !timeline )
return; return;


while ( ! _terminate )
while ( timeline->tryrdlock() )
{ {
if ( ! timeline->tryrdlock() )
{
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?" );
}
_frame += nframes;
}
timeline->unlock();
if ( _terminate )
return; return;
}

usleep( 1000 * 10 ); usleep( 1000 * 10 );
} }
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?" );
}
_frame += nframes;
}
timeline->unlock();
} }


void void
@@ -117,61 +117,63 @@ Playback_DS::disk_thread ( void )


/* 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 = buffer_alloc( _nframes * channels() * _disk_io_blocks ); sample_t *buf = buffer_alloc( _nframes * channels() * _disk_io_blocks );
sample_t *cbuf = buffer_alloc( _nframes * _disk_io_blocks );

int blocks_ready = 0;
sample_t *cbuf = buffer_alloc( _nframes );


const nframes_t nframes = _nframes * _disk_io_blocks;
const nframes_t nframes = _nframes;
nframes_t blocks_written;


while ( wait_for_block() )
while ( ! _terminate )
{ {


// lock(); // for seeking
seek:


if ( seek_pending() )
{
/* FIXME: non-RT-safe IO */
DMESSAGE( "performing seek to frame %lu", (unsigned long)_pending_seek );

_frame = _pending_seek;
_pending_seek = -1;
blocks_ready = 0;
}
blocks_written = 0;
read_block( buf, nframes * _disk_io_blocks );


if ( ++blocks_ready < _disk_io_blocks )
while ( blocks_written < _disk_io_blocks &&
wait_for_block() )
{ {
/* wait for more space */
continue;
}

/* reset */
blocks_ready = 0;

read_block( buf, nframes );
// lock(); // for seeking
if ( _pending_seek )
{
/* FIXME: non-RT-safe IO */
DMESSAGE( "performing seek to frame %lu", (unsigned long)_seek_frame );
_frame = _seek_frame;
_pending_seek = false;


/* might have received terminate signal while waiting for block */
if ( _terminate )
goto done;
flush();
goto seek;
}


/* might have received terminate signal while waiting for block */
if ( _terminate )
goto done;
// unlock(); // for seeking // unlock(); // for seeking
/* deinterleave the buffer and stuff it into the per-channel ringbuffers */


/* deinterleave the buffer and stuff it into the per-channel ringbuffers */

const size_t block_size = nframes * sizeof( sample_t );
const size_t block_size = nframes * sizeof( sample_t );


for ( int i = channels(); i--; )
{
buffer_deinterleave_one_channel( cbuf, buf, i, channels(), nframes );
for ( int i = 0; i < channels(); i++ )
{
buffer_deinterleave_one_channel( cbuf,
buf + ( blocks_written * nframes * channels() ),
i,
channels(),
nframes );


size_t wr = 0;
while ( jack_ringbuffer_write_space( _rb[ i ] ) < block_size )
usleep( 100 * 1000 );


while ( wr < block_size )
{
wr += jack_ringbuffer_write( _rb[ i ], ((char*)cbuf) + wr, block_size - wr );
// usleep( 10 * 1000 );
jack_ringbuffer_write( _rb[ i ], ((char*)cbuf), block_size );
} }
}


blocks_written++;
}
} }


done: done:
@@ -203,22 +205,25 @@ Playback_DS::process ( nframes_t nframes )


if ( engine->freewheeling() ) if ( engine->freewheeling() )
{ {
size_t rd = 0;

while ( rd < block_size )
{
rd += jack_ringbuffer_read( _rb[ i ], ((char*)buf) + rd, block_size - rd );
// usleep( 10 * 1000 );
}
/* only ever read nframes at a time */
while ( jack_ringbuffer_read_space( _rb[i] ) < block_size )
usleep( 10 * 1000 );
jack_ringbuffer_read( _rb[ i ], ((char*)buf), block_size );
} }
else else
{
if ( jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size ) < block_size )
{
/* only ever read nframes at a time */
if ( jack_ringbuffer_read_space( _rb[i] ) < block_size )
{ {
++_xruns; ++_xruns;
memset( buf, 0, block_size ); memset( buf, 0, block_size );
/* FIXME: we need to resync somehow */ /* FIXME: we need to resync somehow */
} }
else
{
jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size );
}
} }


/* TODO: figure out a way to stop IO while muted without losing sync */ /* TODO: figure out a way to stop IO while muted without losing sync */


+ 29
- 33
timeline/src/Engine/Record_DS.C View File

@@ -74,39 +74,40 @@ Record_DS::disk_thread ( void )


track()->record( _capture, _frame ); track()->record( _capture, _frame );


const nframes_t nframes = _nframes * _disk_io_blocks;
const nframes_t nframes = _nframes;


/* 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 = buffer_alloc( nframes * channels() );
sample_t *buf = buffer_alloc( nframes * channels() * _disk_io_blocks );
sample_t *cbuf = buffer_alloc( nframes ); sample_t *cbuf = buffer_alloc( nframes );


const size_t block_size = nframes * sizeof( sample_t ); const size_t block_size = nframes * sizeof( sample_t );


int blocks_ready = 0;
nframes_t blocks_read = 0;


while ( wait_for_block() ) while ( wait_for_block() )
{ {
if ( ++blocks_ready < _disk_io_blocks )
continue;
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--; )
{ {
size_t rd = 0;

while ( rd < block_size )
{
rd += jack_ringbuffer_read( _rb[ i ], ((char*)cbuf) + rd, block_size - rd );
// usleep( 10 * 1000 );
}

buffer_interleave_one_channel( buf, cbuf, i, channels(), nframes );
while ( jack_ringbuffer_read_space( _rb[ i ] ) < block_size )
usleep( 10 * 1000 );

jack_ringbuffer_read( _rb[ i ], ((char*)cbuf), block_size );
buffer_interleave_one_channel( buf + ( blocks_read * nframes * channels() ),
cbuf,
i,
channels(),
nframes );
} }


write_block( buf, nframes );
blocks_read++;


if ( blocks_read == _disk_io_blocks )
{
write_block( buf, nframes * _disk_io_blocks );
blocks_read = 0;
}
} }


DMESSAGE( "capture thread terminating" ); DMESSAGE( "capture thread terminating" );
@@ -114,11 +115,7 @@ Record_DS::disk_thread ( void )
/* flush what remains in the buffer out to disk */ /* flush what remains in the buffer out to disk */


{ {
/* use JACk sized blocks for this last bit */
const nframes_t nframes = _nframes;
const size_t block_size = _nframes * sizeof( sample_t );

while ( blocks_ready-- > 0 || ( ! sem_trywait( &_blocks ) && errno != EAGAIN ) )
while ( blocks_read-- > 0 || ( ! sem_trywait( &_blocks ) && errno != EAGAIN ) )
{ {
for ( int i = channels(); i--; ) for ( int i = channels(); i--; )
{ {
@@ -138,8 +135,6 @@ Record_DS::disk_thread ( void )
else else
write_block( buf, nframes ); write_block( buf, nframes );
} }


} }


free(buf); free(buf);
@@ -259,21 +254,22 @@ Record_DS::process ( nframes_t nframes )


if ( engine->freewheeling() ) if ( engine->freewheeling() )
{ {
size_t wr = 0;
while ( jack_ringbuffer_write_space( _rb[i] ) < block_size )
usleep( 10 * 1000 );


while ( wr < block_size )
{
wr += jack_ringbuffer_write( _rb[ i ], ((char*)buf) + offset_size + wr, block_size - wr );
// usleep( 10 * 1000 );
}
jack_ringbuffer_write( _rb[ i ], ((char*)buf) + offset_size, block_size );
} }
else else
{ {
if ( jack_ringbuffer_write( _rb[ i ], ((char*)buf) + offset_size, block_size ) < block_size )
if ( jack_ringbuffer_write_space( _rb[i] ) < block_size )
{ {
++_xruns;
memset( buf, 0, block_size ); memset( buf, 0, block_size );
/* FIXME: we need to resync somehow */ /* FIXME: we need to resync somehow */
++_xruns;
}
else
{
jack_ringbuffer_write( _rb[ i ], ((char*)buf) + offset_size, block_size );
} }
} }
} }


+ 1
- 10
timeline/src/Engine/Timeline.C View File

@@ -225,7 +225,7 @@ Timeline::seek_pending ( void )
Track *t = (Track*)tracks->child( i ); Track *t = (Track*)tracks->child( i );


if ( t->playback_ds ) if ( t->playback_ds )
if ( t->playback_ds->buffer_percent() < 50 )
if ( t->playback_ds->seek_pending() )
return true; return true;
} }


@@ -283,15 +283,6 @@ Timeline::total_output_buffer_percent ( void )
return r / cnt; return r / cnt;
} }


/** wait for I/O threads to fill their buffers */
void
Timeline::wait_for_buffers ( void )
{
while ( total_output_buffer_percent() + total_input_buffer_percent() < 200 )
usleep( 5000 );
}


int int
Timeline::total_playback_xruns ( void ) Timeline::total_playback_xruns ( void )
{ {


Loading…
Cancel
Save