@@ -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/ */ | |||
@@ -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 ); | |||
@@ -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(); | |||
@@ -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 ); | |||
@@ -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 | |||
@@ -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; | |||
} | |||
}; |