diff --git a/Timeline/Audio_File_SF.C b/Timeline/Audio_File_SF.C index 8062f36..79cda35 100644 --- a/Timeline/Audio_File_SF.C +++ b/Timeline/Audio_File_SF.C @@ -33,6 +33,7 @@ Audio_File_SF::from_file ( const char *filename ) SNDFILE *in; SF_INFO si; + Audio_File_SF *c = NULL; memset( &si, 0, sizeof( si ) ); @@ -51,6 +52,7 @@ Audio_File_SF::from_file ( const char *filename ) c = new Audio_File_SF; + c->_current_read = 0; c->_filename = strdup( filename ); c->_length = si.frames; c->_channels = si.channels; @@ -90,7 +92,10 @@ Audio_File_SF::close ( void ) void Audio_File_SF::seek ( nframes_t offset ) { - sf_seek( _in, offset, SEEK_SET ); + if ( offset != _current_read ) + { + sf_seek( _in, _current_read = offset, SEEK_SET ); + } } /* if channels is -1, then all channels are read into buffer @@ -103,22 +108,26 @@ Audio_File_SF::read ( sample_t *buf, int channel, nframes_t len ) // printf( "len = %lu, channels = %d\n", len, _channels ); + nframes_t rlen; + if ( _channels == 1 || channel == -1 ) - return sf_readf_float( _in, buf, len ); + rlen = sf_readf_float( _in, buf, len ); else { sample_t *tmp = new sample_t[ len * _channels ]; - nframes_t rlen = sf_readf_float( _in, tmp, len ); + rlen = sf_readf_float( _in, tmp, len ); /* extract the requested channel */ for ( int i = channel; i < rlen; i += _channels ) *(buf++) = tmp[ i ]; delete tmp; - - return rlen; } + + _current_read += rlen; + + return rlen; } /** read samples from /start/ to /end/ into /buf/ */ diff --git a/Timeline/Audio_File_SF.H b/Timeline/Audio_File_SF.H index d43375e..1384ca8 100644 --- a/Timeline/Audio_File_SF.H +++ b/Timeline/Audio_File_SF.H @@ -27,6 +27,10 @@ class Audio_File_SF : public Audio_File SNDFILE *_in; + /* used to avoid unnecessary seeking--libsndfile isn't smart + * enough to do this for us */ + nframes_t _current_read; + public: static Audio_File_SF *from_file ( const char *filename ); diff --git a/Timeline/Disk_Stream.C b/Timeline/Disk_Stream.C index 0c81a24..a554845 100644 --- a/Timeline/Disk_Stream.C +++ b/Timeline/Disk_Stream.C @@ -23,7 +23,8 @@ #include "Port.H" // float Disk_Stream::seconds_to_buffer = 5.0f; -float Disk_Stream::seconds_to_buffer = 1.0f; +float Disk_Stream::seconds_to_buffer = 5.0f; +// size_t Disk_Stream::disk_block_frames = 2048; /* A Disk_Stream uses a separate I/O thread to stream a track's regions from disk into a ringbuffer, to be processed by the RT @@ -48,6 +49,9 @@ Disk_Stream::Disk_Stream ( Track_Header *th, float frame_rate, nframes_t nframes size_t bufsize = blocks * nframes * sizeof( sample_t ); +/* const int blocks = 64; */ +/* const size_t bufsize = (blocks * (nframes * sizeof( sample_t ))) + sizeof( sample_t ); */ + for ( int i = channels; i--; ) _rb.push_back( jack_ringbuffer_create( bufsize ) ); @@ -151,6 +155,12 @@ Disk_Stream::io_thread ( void ) for ( unsigned int j = i; k < _nframes; j += channels() ) cbuf[ k++ ] = buf[ j ]; + while ( jack_ringbuffer_write_space( _rb[ i ] ) < block_size ) + { + printf( "IO: disk buffer overrun!\n" ); + usleep( 2000 ); + } + jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size ); } } @@ -161,19 +171,39 @@ Disk_Stream::io_thread ( void ) /* THREAD: RT */ /** take a block from the ringbuffers and send it out the track's - * ports */ + * ports */ nframes_t Disk_Stream::process ( nframes_t nframes ) { - 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 ); for ( int i = channels(); i--; ) { - void *buf = (_th->output)[ i ].buffer( _nframes ); + + void *buf = _th->output[ i ].buffer( nframes ); /* FIXME: handle underrun */ + +/* if ( jack_ringbuffer_read_space( _rb[ i ] ) < block_size ) */ +/* { */ +/* printf( "disktream (rt): buffer underrun!\n" ); */ +/* memset( buf, 0, block_size ); */ +/* } */ +/* else */ + if ( jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size ) < block_size ) - printf( "disktream (rt): buffer underrun!\n" ); + { + printf( "RT: buffer underrun (disk can't keep up).\n" ); + memset( buf, 0, block_size ); + } + +/* /\* testing. *\/ */ +/* FILE *fp = fopen( "testing.au", "a" ); */ +/* fwrite( buf, block_size, 1, fp ); */ +/* fclose( fp ); */ + } block_processed(); diff --git a/Timeline/Disk_Stream.H b/Timeline/Disk_Stream.H index 52d987a..8efada0 100644 --- a/Timeline/Disk_Stream.H +++ b/Timeline/Disk_Stream.H @@ -49,6 +49,8 @@ class Disk_Stream sem_t _blocks; /* semaphore to wake the IO thread with */ +// volatile nframes_t _seek_request; + int channels ( void ) const { return _rb.size(); } Audio_Track * track ( void ); diff --git a/Timeline/Engine.C b/Timeline/Engine.C index 26f5ef4..492e20e 100644 --- a/Timeline/Engine.C +++ b/Timeline/Engine.C @@ -62,7 +62,6 @@ Engine::process ( nframes_t nframes ) return 0; } - /* handle chicken/egg problem */ if ( timeline ) /* this will initiate the process() call graph for the various diff --git a/Timeline/Mutex.H b/Timeline/Mutex.H index 3d6eb3d..f98f9eb 100644 --- a/Timeline/Mutex.H +++ b/Timeline/Mutex.H @@ -30,7 +30,6 @@ public: Mutex ( ) { -// _lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; pthread_mutex_init( &_lock, NULL ); } @@ -51,10 +50,10 @@ public: pthread_mutex_unlock( &_lock ); } - int + bool trylock ( void ) { - return pthread_mutex_trylock( &_lock ); + return pthread_mutex_trylock( &_lock ) == 0; } };