| @@ -33,6 +33,7 @@ Audio_File_SF::from_file ( const char *filename ) | |||||
| SNDFILE *in; | SNDFILE *in; | ||||
| SF_INFO si; | SF_INFO si; | ||||
| Audio_File_SF *c = NULL; | Audio_File_SF *c = NULL; | ||||
| memset( &si, 0, sizeof( si ) ); | memset( &si, 0, sizeof( si ) ); | ||||
| @@ -51,6 +52,7 @@ Audio_File_SF::from_file ( const char *filename ) | |||||
| c = new Audio_File_SF; | c = new Audio_File_SF; | ||||
| c->_current_read = 0; | |||||
| c->_filename = strdup( filename ); | c->_filename = strdup( filename ); | ||||
| c->_length = si.frames; | c->_length = si.frames; | ||||
| c->_channels = si.channels; | c->_channels = si.channels; | ||||
| @@ -90,7 +92,10 @@ Audio_File_SF::close ( void ) | |||||
| void | void | ||||
| Audio_File_SF::seek ( nframes_t offset ) | 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 | /* 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 ); | // printf( "len = %lu, channels = %d\n", len, _channels ); | ||||
| nframes_t rlen; | |||||
| if ( _channels == 1 || channel == -1 ) | if ( _channels == 1 || channel == -1 ) | ||||
| return sf_readf_float( _in, buf, len ); | |||||
| rlen = sf_readf_float( _in, buf, len ); | |||||
| else | else | ||||
| { | { | ||||
| sample_t *tmp = new sample_t[ len * _channels ]; | 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 */ | /* extract the requested channel */ | ||||
| for ( int i = channel; i < rlen; i += _channels ) | for ( int i = channel; i < rlen; i += _channels ) | ||||
| *(buf++) = tmp[ i ]; | *(buf++) = tmp[ i ]; | ||||
| delete tmp; | delete tmp; | ||||
| return rlen; | |||||
| } | } | ||||
| _current_read += rlen; | |||||
| return rlen; | |||||
| } | } | ||||
| /** read samples from /start/ to /end/ into /buf/ */ | /** read samples from /start/ to /end/ into /buf/ */ | ||||
| @@ -27,6 +27,10 @@ class Audio_File_SF : public Audio_File | |||||
| SNDFILE *_in; | SNDFILE *_in; | ||||
| /* used to avoid unnecessary seeking--libsndfile isn't smart | |||||
| * enough to do this for us */ | |||||
| nframes_t _current_read; | |||||
| public: | public: | ||||
| static Audio_File_SF *from_file ( const char *filename ); | static Audio_File_SF *from_file ( const char *filename ); | ||||
| @@ -23,7 +23,8 @@ | |||||
| #include "Port.H" | #include "Port.H" | ||||
| // float Disk_Stream::seconds_to_buffer = 5.0f; | // 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 | /* 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 | 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 ); | 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--; ) | for ( int i = channels; i--; ) | ||||
| _rb.push_back( jack_ringbuffer_create( bufsize ) ); | _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() ) | for ( unsigned int j = i; k < _nframes; j += channels() ) | ||||
| cbuf[ k++ ] = buf[ j ]; | 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 ); | jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -161,19 +171,39 @@ Disk_Stream::io_thread ( void ) | |||||
| /* THREAD: RT */ | /* THREAD: RT */ | ||||
| /** take a block from the ringbuffers and send it out the track's | /** take a block from the ringbuffers and send it out the track's | ||||
| * ports */ | |||||
| * ports */ | |||||
| nframes_t | nframes_t | ||||
| Disk_Stream::process ( nframes_t nframes ) | 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--; ) | for ( int i = channels(); i--; ) | ||||
| { | { | ||||
| void *buf = (_th->output)[ i ].buffer( _nframes ); | |||||
| void *buf = _th->output[ i ].buffer( nframes ); | |||||
| /* FIXME: handle underrun */ | /* 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 ) | 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(); | block_processed(); | ||||
| @@ -49,6 +49,8 @@ class Disk_Stream | |||||
| sem_t _blocks; /* semaphore to wake the IO thread with */ | sem_t _blocks; /* semaphore to wake the IO thread with */ | ||||
| // volatile nframes_t _seek_request; | |||||
| int channels ( void ) const { return _rb.size(); } | int channels ( void ) const { return _rb.size(); } | ||||
| Audio_Track * track ( void ); | Audio_Track * track ( void ); | ||||
| @@ -62,7 +62,6 @@ Engine::process ( nframes_t nframes ) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| /* handle chicken/egg problem */ | /* handle chicken/egg problem */ | ||||
| if ( timeline ) | if ( timeline ) | ||||
| /* this will initiate the process() call graph for the various | /* this will initiate the process() call graph for the various | ||||
| @@ -30,7 +30,6 @@ public: | |||||
| Mutex ( ) | Mutex ( ) | ||||
| { | { | ||||
| // _lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; | |||||
| pthread_mutex_init( &_lock, NULL ); | pthread_mutex_init( &_lock, NULL ); | ||||
| } | } | ||||
| @@ -51,10 +50,10 @@ public: | |||||
| pthread_mutex_unlock( &_lock ); | pthread_mutex_unlock( &_lock ); | ||||
| } | } | ||||
| int | |||||
| bool | |||||
| trylock ( void ) | trylock ( void ) | ||||
| { | { | ||||
| return pthread_mutex_trylock( &_lock ); | |||||
| return pthread_mutex_trylock( &_lock ) == 0; | |||||
| } | } | ||||
| }; | }; | ||||