@@ -24,7 +24,38 @@ static float seconds_to_buffer = 5.0f; | |||
thread (or vice-versa). */ | |||
/* FIXME: handle termination of IO thread in destructor */ | |||
/* FIXME: could all of this not simply be included in the Track_Header | |||
class? */ | |||
class? */ | |||
/* FIXME: deal with (jack) buffer size changes */ | |||
/* FIXME: can this be made to actually handle capture? */ | |||
/* FIXME: needs error handling everywhere! */ | |||
Disk_Stream::Disk_Stream ( const Track_Header *th, float frame_rate, nframes_t nframes, int channels ) : _th( th ) | |||
{ | |||
_frame = 0; | |||
const int blocks = frame_rate * seconds_to_buffer / nframes; | |||
_nframes = nframes; | |||
size_t bufsize = blocks * nframes * sizeof( sample_t ); | |||
for ( int i = channels(); i-- ) | |||
_rb[ i ] = jack_ringbuffer_create( bufsize ); | |||
sem_init( &_blocks, 0, blocks ); | |||
run(); | |||
} | |||
virtual ~Disk_Stream::Disk_Stream ( ) | |||
{ | |||
_th = NULL; | |||
sem_destroy( &_blocks ); | |||
for ( int i = channels(); i-- ) | |||
jack_ringbuffer_free( _rb[ i ] ); | |||
} | |||
/** start Disk_Stream thread */ | |||
void | |||
@@ -41,13 +72,13 @@ Disk_Stream::io_thread ( void *arg ) | |||
((Disk_Stream*)arg)->io_thread(); | |||
} | |||
/* THREAD: IO */ | |||
/** read a block of data from the track into /buf/ */ | |||
void | |||
Disk_Stream::read_block ( sample_t *buf ) | |||
{ | |||
if ( _th->track()->play( buf, _frame, _nframes, channels() ) ) | |||
_frame += nframes; | |||
_frame += _nframes; | |||
else | |||
/* error */; | |||
} | |||
@@ -87,10 +118,19 @@ Disk_Stream::io_thread ( void ) | |||
} | |||
/* THREAD: RT */ | |||
/** take a block from the ringbuffers and send it out the track's | |||
* ports */ | |||
void | |||
Disk_Stream::process ( nframes_t nframes ) | |||
Disk_Stream::process ( vector <Port*> ports ) | |||
{ | |||
_th->channels(); | |||
const size_t block_size = _nframes * sizeof( sample_t ); | |||
for ( int i = channels(); i-- ) | |||
{ | |||
sample_t *buf = _th->output[ i ]->buffer(); | |||
jack_ringbuffer_read( _rb[ i ], buf, block_size ); | |||
} | |||
block_processed(); | |||
} |
@@ -22,6 +22,8 @@ | |||
#include <jack/ringbuffer.h> | |||
#include <semaphore.h> | |||
#include "Track_Header.H" | |||
class Disk_Stream | |||
{ | |||
@@ -37,6 +39,8 @@ class Disk_Stream | |||
int channels ( void ) const { return _rb.size(); } | |||
Track * track ( void ) const { return _th->track(); } | |||
protected: | |||
void block_processed ( void ) { sem_post( &_blocks ); } | |||
@@ -44,48 +48,31 @@ protected: | |||
public: | |||
/* must be set before any Disk_Streams are created */ | |||
static float seconds_to_buffer; | |||
Disk_Stream ( const Track_Header *th, float frame_rate, nframes_t nframes, int channels ) : _th( th ) | |||
{ | |||
_frame = 0; | |||
const int blocks = frame_rate * seconds_to_buffer / nframes; | |||
Disk_Stream ( const Track_Header *th, float frame_rate, nframes_t nframes, int channels ); | |||
_nframes = nframes; | |||
size_t bufsize = blocks * nframes * sizeof( sample_t ); | |||
for ( int i = channels(); i-- ) | |||
_rb[ i ] = jack_ringbuffer_create( bufsize ); | |||
sem_init( &_blocks, 0, blocks ); | |||
run(); | |||
} | |||
virtual ~Disk_Stream ( ) | |||
{ | |||
_th = NULL; | |||
sem_destroy( &_blocks ); | |||
for ( int i = channels(); i-- ) | |||
jack_ringbuffer_free( _rb[ i ] ); | |||
} | |||
virtual ~Disk_Stream ( ); | |||
void | |||
resize_buffer ( void ) | |||
resize ( nframes_t nframes ) | |||
{ | |||
if ( nframes != _nframes ) | |||
/* FIXME: to something here! */; | |||
} | |||
void | |||
seek ( nframes_t frame ) | |||
{ | |||
_frame = frame; | |||
/* FIXME: need to signal the IO thread somehow? */ | |||
} | |||
void run ( void ); | |||
void io_thread ( void *arg ); | |||
void read_block ( sample_t *buf ); | |||
void io_thread ( void ); | |||
void process ( vector <Port*> ports ); | |||
}; |
@@ -17,36 +17,26 @@ | |||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
/*******************************************************************************/ | |||
/* RT/thread-safe interface to a single jack port. */ | |||
/* nframes is the number of frames to buffer */ | |||
Port::Port ( jack_port_t *port, nframes_t nframes ) | |||
Port::Port ( jack_port_t *port ) | |||
{ | |||
_port = port; | |||
_rb = jack_ringbuffer_create( nframes * sizeof( stample_t ) ); | |||
_name = jack_port_name( _port ); | |||
} | |||
Port::~Port ( ) | |||
{ | |||
jack_ringbuffer_free( _rb ); | |||
/* close port? */ | |||
} | |||
nframes_t | |||
void | |||
Port::write ( sample_t *buf, nframes_t nframes ) | |||
{ | |||
const size_t size = nframes * sizeof( sample_t ); | |||
return jack_ringbuffer_write( _rb, buf, size ) / sizeof( sample_t ); | |||
memcpy( buffer(), buf, nframes * sizeof( sample_t ) ); | |||
} | |||
/* runs in the RT thread! */ | |||
void | |||
Port::process ( nframes_t nframes ) | |||
sample_t * | |||
Port::buffer ( void ) | |||
{ | |||
sample_t *buf = jack_port_get_buffer( _port, nframes ); | |||
/* FIXME: check size */ | |||
jack_ringbuffer_read( _rb, buf, nframes ); | |||
return (sample_t*)jack_port_get_buffer( _port ); | |||
} |
@@ -19,19 +19,17 @@ | |||
class Port | |||
{ | |||
jack_ringbuffer_t _rb; | |||
jack_port_t *_port; | |||
const char *_name; | |||
public: | |||
Port ( jack_port_t *port, nframes_t nframes ); | |||
Port ( jack_port_t *port ); | |||
~Port ( ); | |||
bool connected ( void ) const { return jack_port_connected( _port ); } | |||
const char * name ( void ) const { return _name; } | |||
nframes_t write ( sample_t *buf, nframes_t nframes ); | |||
void process ( nframes_t nframes ); | |||
}; |