| @@ -117,7 +117,7 @@ Audio_Track::handle ( int m ) | |||||
| /* THREAD: IO */ | /* THREAD: IO */ | ||||
| /** determine region coverage and fill /buf/ with interleaved samples | /** determine region coverage and fill /buf/ with interleaved samples | ||||
| * from /frame/ to /nframes/ for exactly /channels/ channels. */ | * from /frame/ to /nframes/ for exactly /channels/ channels. */ | ||||
| void | |||||
| nframes_t | |||||
| Audio_Track::play ( sample_t *buf, nframes_t frame, nframes_t nframes, int channels ) | Audio_Track::play ( sample_t *buf, nframes_t frame, nframes_t nframes, int channels ) | ||||
| { | { | ||||
| sample_t *cbuf = new sample_t[ nframes ]; | sample_t *cbuf = new sample_t[ nframes ]; | ||||
| @@ -125,9 +125,9 @@ Audio_Track::play ( sample_t *buf, nframes_t frame, nframes_t nframes, int chann | |||||
| /* quick and dirty--let the regions figure out coverage for themselves */ | /* quick and dirty--let the regions figure out coverage for themselves */ | ||||
| for ( list <Track_Widget *>::const_iterator i = _widgets.begin(); i != _widgets.end(); i++ ) | for ( list <Track_Widget *>::const_iterator i = _widgets.begin(); i != _widgets.end(); i++ ) | ||||
| { | { | ||||
| const Region *r = (Region*)i; | |||||
| const Region *r = (Region*)(*i); | |||||
| for ( int i = channels; i-- ) | |||||
| for ( int i = channels; i--; ) | |||||
| { | { | ||||
| memset( cbuf, 0, nframes * sizeof( sample_t ) ); | memset( cbuf, 0, nframes * sizeof( sample_t ) ); | ||||
| @@ -136,8 +136,11 @@ Audio_Track::play ( sample_t *buf, nframes_t frame, nframes_t nframes, int chann | |||||
| /* interleave */ | /* interleave */ | ||||
| int k = 0; | int k = 0; | ||||
| for ( int j = 0; j < nframes; j += channels ) | |||||
| for ( unsigned int j = 0; j < nframes; j += channels ) | |||||
| buf[ j ] = cbuf[ k++ ]; | buf[ j ] = cbuf[ k++ ]; | ||||
| } | } | ||||
| } | } | ||||
| /* FIXME: bogus */ | |||||
| return nframes; | |||||
| } | } | ||||
| @@ -22,6 +22,7 @@ | |||||
| #include "Track.H" | #include "Track.H" | ||||
| #include "Region.H" | #include "Region.H" | ||||
| #include <FL/Fl_Input.H> | #include <FL/Fl_Input.H> | ||||
| class Audio_Track : public Track | class Audio_Track : public Track | ||||
| @@ -53,6 +54,6 @@ public: | |||||
| void dump ( void ); | void dump ( void ); | ||||
| void remove_selected ( void ); | void remove_selected ( void ); | ||||
| void play ( sample_t *buf, nframes_t frame, nframes_t nframes, int channels ); | |||||
| nframes_t play ( sample_t *buf, nframes_t frame, nframes_t nframes, int channels ); | |||||
| }; | }; | ||||
| @@ -17,9 +17,12 @@ | |||||
| /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||||
| /*******************************************************************************/ | /*******************************************************************************/ | ||||
| #include "Disk_Stream.H" | |||||
| #include "Track_Header.H" | #include "Track_Header.H" | ||||
| #include "Audio_Track.H" | |||||
| #include "Port.H" | |||||
| static float seconds_to_buffer = 5.0f; | |||||
| float Disk_Stream::seconds_to_buffer = 5.0f; | |||||
| /* 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 | ||||
| @@ -31,9 +34,10 @@ static float seconds_to_buffer = 5.0f; | |||||
| /* FIXME: can this be made to actually handle capture? */ | /* FIXME: can this be made to actually handle capture? */ | ||||
| /* FIXME: needs error handling everywhere! */ | /* FIXME: needs error handling everywhere! */ | ||||
| Disk_Stream::Disk_Stream ( const Track_Header *th, float frame_rate, nframes_t nframes, int channels ) : _th( th ) | |||||
| Disk_Stream::Disk_Stream ( Track_Header *th, float frame_rate, nframes_t nframes, int channels ) : _th( th ) | |||||
| { | { | ||||
| _frame = 0; | _frame = 0; | ||||
| _thread = 0; | |||||
| const int blocks = frame_rate * seconds_to_buffer / nframes; | const int blocks = frame_rate * seconds_to_buffer / nframes; | ||||
| @@ -41,7 +45,7 @@ Disk_Stream::Disk_Stream ( const Track_Header *th, float frame_rate, nframes_t n | |||||
| size_t bufsize = blocks * nframes * sizeof( sample_t ); | size_t bufsize = blocks * nframes * sizeof( sample_t ); | ||||
| for ( int i = channels(); i-- ) | |||||
| for ( int i = channels; i--; ) | |||||
| _rb[ i ] = jack_ringbuffer_create( bufsize ); | _rb[ i ] = jack_ringbuffer_create( bufsize ); | ||||
| sem_init( &_blocks, 0, blocks ); | sem_init( &_blocks, 0, blocks ); | ||||
| @@ -49,18 +53,18 @@ Disk_Stream::Disk_Stream ( const Track_Header *th, float frame_rate, nframes_t n | |||||
| run(); | run(); | ||||
| } | } | ||||
| virtual ~Disk_Stream::Disk_Stream ( ) | |||||
| Disk_Stream::~Disk_Stream ( ) | |||||
| { | { | ||||
| _th = NULL; | _th = NULL; | ||||
| sem_destroy( &_blocks ); | sem_destroy( &_blocks ); | ||||
| for ( int i = channels(); i-- ) | |||||
| for ( int i = channels(); i--; ) | |||||
| jack_ringbuffer_free( _rb[ i ] ); | jack_ringbuffer_free( _rb[ i ] ); | ||||
| } | } | ||||
| Audio_Track * | Audio_Track * | ||||
| Disk_Stream::track ( void ) const | |||||
| Disk_Stream::track ( void ) | |||||
| { | { | ||||
| return (Audio_Track*)_th->track(); | return (Audio_Track*)_th->track(); | ||||
| } | } | ||||
| @@ -69,15 +73,23 @@ Disk_Stream::track ( void ) const | |||||
| void | void | ||||
| Disk_Stream::run ( void ) | Disk_Stream::run ( void ) | ||||
| { | { | ||||
| if ( pthread_create( 0, 0, &Disk_Stream::io_thread, this ) != 0 ) | |||||
| if ( pthread_create( &_thread, NULL, &Disk_Stream::io_thread, this ) != 0 ) | |||||
| /* error */; | /* error */; | ||||
| } | } | ||||
| /* void */ | |||||
| /* DIsk_Stream::shutdown ( void ) */ | |||||
| /* { */ | |||||
| /* pthread_join( &_thread, NULL ); */ | |||||
| /* } */ | |||||
| /* static wrapper */ | /* static wrapper */ | ||||
| void | |||||
| void * | |||||
| Disk_Stream::io_thread ( void *arg ) | Disk_Stream::io_thread ( void *arg ) | ||||
| { | { | ||||
| ((Disk_Stream*)arg)->io_thread(); | ((Disk_Stream*)arg)->io_thread(); | ||||
| return NULL; | |||||
| } | } | ||||
| /* THREAD: IO */ | /* THREAD: IO */ | ||||
| @@ -111,13 +123,13 @@ Disk_Stream::io_thread ( void ) | |||||
| /* deinterleave the buffer and stuff it into the per-channel ringbuffers */ | /* deinterleave the buffer and stuff it into the per-channel ringbuffers */ | ||||
| for ( int i = channels(); i-- ) | |||||
| for ( int i = channels(); i--; ) | |||||
| { | { | ||||
| int k = 0; | int k = 0; | ||||
| for ( int j = i; j < _nframes; j += channels() ) | |||||
| for ( unsigned int j = i; j < _nframes; j += channels() ) | |||||
| cbuf[ k++ ] = buf[ j ]; | cbuf[ k++ ] = buf[ j ]; | ||||
| jack_ringbuffer_write( _rb[ i ], cbuf, block_size ); | |||||
| jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -129,15 +141,16 @@ Disk_Stream::io_thread ( void ) | |||||
| /** 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 */ | ||||
| void | void | ||||
| Disk_Stream::process ( vector <Port*> ports ) | |||||
| Disk_Stream::process ( void ) | |||||
| { | { | ||||
| const size_t block_size = _nframes * sizeof( sample_t ); | const size_t block_size = _nframes * sizeof( sample_t ); | ||||
| for ( int i = channels(); i-- ) | |||||
| for ( int i = channels(); i--; ) | |||||
| { | { | ||||
| sample_t *buf = _th->output[ i ]->buffer(); | |||||
| sample_t *buf = (_th->output)[ i ].buffer( _nframes ); | |||||
| jack_ringbuffer_read( _rb[ i ], buf, block_size ); | |||||
| /* FIXME: handle underrun */ | |||||
| jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size ); | |||||
| } | } | ||||
| block_processed(); | block_processed(); | ||||
| @@ -19,20 +19,29 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "Port.H" // for nframes_t | |||||
| #include <jack/ringbuffer.h> | #include <jack/ringbuffer.h> | ||||
| #include <semaphore.h> | #include <semaphore.h> | ||||
| #include <errno.h> | |||||
| #include <pthread.h> | |||||
| #include <vector> | #include <vector> | ||||
| using std::vector; | using std::vector; | ||||
| class Track_Header; | class Track_Header; | ||||
| class Audio_Track; | |||||
| class Disk_Stream | class Disk_Stream | ||||
| { | { | ||||
| const Track_Header *_th; /* Track_Header we whould be playing */ | |||||
| pthread_t _thread; | |||||
| Track_Header *_th; /* Track_Header we whould be playing */ | |||||
| nframes_t _nframes; | nframes_t _nframes; | ||||
| nframes_t _frame; | |||||
| vector <jack_ringbuffer_t *> _rb; | vector <jack_ringbuffer_t *> _rb; | ||||
| @@ -42,19 +51,21 @@ class Disk_Stream | |||||
| int channels ( void ) const { return _rb.size(); } | int channels ( void ) const { return _rb.size(); } | ||||
| Audio_Track * track ( void ) const; | |||||
| Audio_Track * track ( void ); | |||||
| static void *io_thread ( void *arg ); | |||||
| protected: | protected: | ||||
| void block_processed ( void ) { sem_post( &_blocks ); } | void block_processed ( void ) { sem_post( &_blocks ); } | ||||
| bool wait_for_block ( void ) { while ( sem_wait( &_work ) == EINTR ); return true; } | |||||
| bool wait_for_block ( void ) { while ( sem_wait( &_blocks ) == EINTR ); return true; } | |||||
| public: | public: | ||||
| /* must be set before any Disk_Streams are created */ | /* 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 ); | |||||
| Disk_Stream ( Track_Header *th, float frame_rate, nframes_t nframes, int channels ); | |||||
| virtual ~Disk_Stream ( ); | virtual ~Disk_Stream ( ); | ||||
| @@ -73,9 +84,8 @@ public: | |||||
| } | } | ||||
| void run ( void ); | void run ( void ); | ||||
| void io_thread ( void *arg ); | |||||
| void read_block ( sample_t *buf ); | void read_block ( sample_t *buf ); | ||||
| void io_thread ( void ); | void io_thread ( void ); | ||||
| void process ( vector <Port*> ports ); | |||||
| void process ( void ); | |||||
| }; | }; | ||||
| @@ -11,6 +11,8 @@ SRCS= \ | |||||
| Peaks.C \ | Peaks.C \ | ||||
| Audio_File.C \ | Audio_File.C \ | ||||
| Audio_File_SF.C \ | Audio_File_SF.C \ | ||||
| Port.C \ | |||||
| Disk_Stream.C \ | |||||
| Loggable.C \ | Loggable.C \ | ||||
| OBJS=$(SRCS:.C=.o) | OBJS=$(SRCS:.C=.o) | ||||
| @@ -25,8 +27,10 @@ $(OBJS): Makefile | |||||
| include ../make.inc | include ../make.inc | ||||
| #LIBS:=$(LIBS) -ljack -lpthread | |||||
| timeline: $(OBJS) | timeline: $(OBJS) | ||||
| $(CXX) $(CXXFLAGS) $(INCLUDES) $(LIBS) $(OBJS) -o $@ | |||||
| $(CXX) $(CXXFLAGS) $(INCLUDES) $(LIBS) -ljack -lpthread $(OBJS) -o $@ | |||||
| clean: | clean: | ||||
| rm -f $(OBJS) timeline makedepend | rm -f $(OBJS) timeline makedepend | ||||
| @@ -17,6 +17,10 @@ | |||||
| /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||||
| /*******************************************************************************/ | /*******************************************************************************/ | ||||
| #include "Port.H" | |||||
| #include <string.h> | |||||
| /* nframes is the number of frames to buffer */ | /* nframes is the number of frames to buffer */ | ||||
| Port::Port ( jack_port_t *port ) | Port::Port ( jack_port_t *port ) | ||||
| { | { | ||||
| @@ -32,11 +36,11 @@ Port::~Port ( ) | |||||
| void | void | ||||
| Port::write ( sample_t *buf, nframes_t nframes ) | Port::write ( sample_t *buf, nframes_t nframes ) | ||||
| { | { | ||||
| memcpy( buffer(), buf, nframes * sizeof( sample_t ) ); | |||||
| memcpy( buffer( nframes ), buf, nframes * sizeof( sample_t ) ); | |||||
| } | } | ||||
| sample_t * | sample_t * | ||||
| Port::buffer ( void ) | |||||
| Port::buffer ( nframes_t nframes ) | |||||
| { | { | ||||
| return (sample_t*)jack_port_get_buffer( _port ); | |||||
| return (sample_t*)jack_port_get_buffer( _port, nframes ); | |||||
| } | } | ||||
| @@ -17,6 +17,14 @@ | |||||
| /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||||
| /*******************************************************************************/ | /*******************************************************************************/ | ||||
| #pragma once | |||||
| #include <jack/jack.h> | |||||
| typedef float sample_t; | |||||
| //typedef jack_nframes_t nframes_t; | |||||
| typedef unsigned long nframes_t; | |||||
| class Port | class Port | ||||
| { | { | ||||
| jack_port_t *_port; | jack_port_t *_port; | ||||
| @@ -31,5 +39,5 @@ public: | |||||
| const char * name ( void ) const { return _name; } | const char * name ( void ) const { return _name; } | ||||
| void write ( sample_t *buf, nframes_t nframes ); | void write ( sample_t *buf, nframes_t nframes ); | ||||
| sample_t *buffer ( nframes_t nframes ); | |||||
| }; | }; | ||||
| @@ -551,7 +551,7 @@ Region::normalize ( void ) | |||||
| again? */ | again? */ | ||||
| /* FIXME: should fade-out/fade-ins not be handled here? */ | /* FIXME: should fade-out/fade-ins not be handled here? */ | ||||
| nframes_t | nframes_t | ||||
| Region::read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channel ) | |||||
| Region::read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channel ) const | |||||
| { | { | ||||
| const Range &r = _range; | const Range &r = _range; | ||||
| @@ -206,7 +206,7 @@ public: | |||||
| void normalize ( void ); | void normalize ( void ); | ||||
| nframes_t read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channel ); | |||||
| nframes_t read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channel ) const; | |||||
| }; | }; | ||||
| #endif | #endif | ||||
| @@ -30,6 +30,10 @@ | |||||
| #include "Loggable.H" | #include "Loggable.H" | ||||
| #include "Port.H" | |||||
| #include <vector> | |||||
| using std::vector; | |||||
| class Track_Header : public Fl_Group, public Loggable | class Track_Header : public Fl_Group, public Loggable | ||||
| { | { | ||||
| @@ -68,6 +72,8 @@ public: | |||||
| Fl_Pack *takes; | Fl_Pack *takes; | ||||
| vector <Port> output; /* output ports... */ | |||||
| const char *class_name ( void ) { return "Track_Header"; } | const char *class_name ( void ) { return "Track_Header"; } | ||||