| @@ -24,7 +24,38 @@ static float seconds_to_buffer = 5.0f; | |||||
| thread (or vice-versa). */ | thread (or vice-versa). */ | ||||
| /* FIXME: handle termination of IO thread in destructor */ | /* FIXME: handle termination of IO thread in destructor */ | ||||
| /* FIXME: could all of this not simply be included in the Track_Header | /* 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 */ | /** start Disk_Stream thread */ | ||||
| void | void | ||||
| @@ -41,13 +72,13 @@ Disk_Stream::io_thread ( void *arg ) | |||||
| ((Disk_Stream*)arg)->io_thread(); | ((Disk_Stream*)arg)->io_thread(); | ||||
| } | } | ||||
| /* THREAD: IO */ | /* THREAD: IO */ | ||||
| /** read a block of data from the track into /buf/ */ | /** read a block of data from the track into /buf/ */ | ||||
| void | |||||
| Disk_Stream::read_block ( sample_t *buf ) | Disk_Stream::read_block ( sample_t *buf ) | ||||
| { | { | ||||
| if ( _th->track()->play( buf, _frame, _nframes, channels() ) ) | if ( _th->track()->play( buf, _frame, _nframes, channels() ) ) | ||||
| _frame += nframes; | |||||
| _frame += _nframes; | |||||
| else | else | ||||
| /* error */; | /* error */; | ||||
| } | } | ||||
| @@ -87,10 +118,19 @@ Disk_Stream::io_thread ( void ) | |||||
| } | } | ||||
| /* THREAD: RT */ | /* THREAD: RT */ | ||||
| /** take a block from the ringbuffers and send it out the track's | |||||
| * ports */ | |||||
| void | 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(); | block_processed(); | ||||
| } | } | ||||
| @@ -22,6 +22,8 @@ | |||||
| #include <jack/ringbuffer.h> | #include <jack/ringbuffer.h> | ||||
| #include <semaphore.h> | #include <semaphore.h> | ||||
| #include "Track_Header.H" | |||||
| class Disk_Stream | class Disk_Stream | ||||
| { | { | ||||
| @@ -37,6 +39,8 @@ class Disk_Stream | |||||
| int channels ( void ) const { return _rb.size(); } | int channels ( void ) const { return _rb.size(); } | ||||
| Track * track ( void ) const { return _th->track(); } | |||||
| protected: | protected: | ||||
| void block_processed ( void ) { sem_post( &_blocks ); } | void block_processed ( void ) { sem_post( &_blocks ); } | ||||
| @@ -44,48 +48,31 @@ protected: | |||||
| public: | public: | ||||
| /* must be set before any Disk_Streams are created */ | |||||
| static float seconds_to_buffer; | 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 | void | ||||
| resize_buffer ( void ) | |||||
| resize ( nframes_t nframes ) | |||||
| { | { | ||||
| if ( nframes != _nframes ) | |||||
| /* FIXME: to something here! */; | |||||
| } | } | ||||
| void | void | ||||
| seek ( nframes_t frame ) | seek ( nframes_t frame ) | ||||
| { | { | ||||
| _frame = frame; | _frame = frame; | ||||
| /* FIXME: need to signal the IO thread somehow? */ | |||||
| } | } | ||||
| void run ( void ); | 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. */ | /* 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 */ | /* 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; | _port = port; | ||||
| _rb = jack_ringbuffer_create( nframes * sizeof( stample_t ) ); | |||||
| _name = jack_port_name( _port ); | _name = jack_port_name( _port ); | ||||
| } | } | ||||
| Port::~Port ( ) | Port::~Port ( ) | ||||
| { | { | ||||
| jack_ringbuffer_free( _rb ); | |||||
| /* close port? */ | |||||
| } | } | ||||
| nframes_t | |||||
| void | |||||
| Port::write ( sample_t *buf, nframes_t nframes ) | 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 | class Port | ||||
| { | { | ||||
| jack_ringbuffer_t _rb; | |||||
| jack_port_t *_port; | jack_port_t *_port; | ||||
| const char *_name; | const char *_name; | ||||
| public: | public: | ||||
| Port ( jack_port_t *port, nframes_t nframes ); | |||||
| Port ( jack_port_t *port ); | |||||
| ~Port ( ); | ~Port ( ); | ||||
| bool connected ( void ) const { return jack_port_connected( _port ); } | bool connected ( void ) const { return jack_port_connected( _port ); } | ||||
| const char * name ( void ) const { return _name; } | const char * name ( void ) const { return _name; } | ||||
| nframes_t write ( sample_t *buf, nframes_t nframes ); | nframes_t write ( sample_t *buf, nframes_t nframes ); | ||||
| void process ( nframes_t nframes ); | |||||
| }; | }; | ||||