From 48d7f61f8afad4c1560d8dd01b8bfaef8dcaf7f6 Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Mon, 19 May 2008 23:30:08 -0500 Subject: [PATCH] Respond appropriately to changes in JACK buffer size. --- Timeline/Disk_Stream.C | 65 +++++++++++++++++++++++++++++------------- Timeline/Disk_Stream.H | 10 +++++-- Timeline/Engine.C | 17 +++++++++++ Timeline/Engine.H | 2 ++ Timeline/Playback_DS.C | 3 +- Timeline/Playback_DS.H | 2 ++ Timeline/Record_DS.C | 2 +- Timeline/Record_DS.H | 2 ++ Timeline/Timeline.C | 12 ++++++++ Timeline/Timeline.H | 1 + Timeline/Track.C | 10 ++++++- Timeline/Track.H | 1 + 12 files changed, 101 insertions(+), 26 deletions(-) diff --git a/Timeline/Disk_Stream.C b/Timeline/Disk_Stream.C index 57b389b..b2611f4 100644 --- a/Timeline/Disk_Stream.C +++ b/Timeline/Disk_Stream.C @@ -52,7 +52,6 @@ size_t Disk_Stream::disk_io_kbytes = 256; Disk_Stream::Disk_Stream ( Track *track, float frame_rate, nframes_t nframes, int channels ) : _track( track ) { - assert( channels ); _frame = 0; @@ -60,20 +59,9 @@ Disk_Stream::Disk_Stream ( Track *track, float frame_rate, nframes_t nframes, in _terminate = false; _pending_seek = -1; _xruns = 0; + _frame_rate = frame_rate; - _total_blocks = frame_rate * seconds_to_buffer / nframes; - - _nframes = nframes; - - size_t bufsize = _total_blocks * nframes * sizeof( sample_t ); - - if ( disk_io_kbytes ) - _disk_io_blocks = ( bufsize * channels ) / ( disk_io_kbytes * 1024 ); - else - _disk_io_blocks = 1; - - for ( int i = channels; i--; ) - _rb.push_back( jack_ringbuffer_create( bufsize ) ); + _resize_buffers( nframes, channels ); sem_init( &_blocks, 0, _total_blocks ); } @@ -97,14 +85,13 @@ Disk_Stream::~Disk_Stream ( ) /* THREAD: RT */ /** flush buffers and reset. Must only be called from the RT thread. */ void -Disk_Stream::flush ( bool is_output ) +Disk_Stream::base_flush ( bool is_output ) { /* flush buffers */ - for ( int i = channels(); i--; ) + for ( int i = _rb.size(); i--; ) jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) ); - /* sem_destroy( &_blocks ); */ /* if ( is_output ) */ @@ -114,7 +101,6 @@ Disk_Stream::flush ( bool is_output ) if ( is_output ) { - int n; sem_getvalue( &_blocks, &n ); @@ -145,6 +131,7 @@ Disk_Stream::shutdown ( void ) if ( _thread ) pthread_join( _thread, NULL ); + _thread = 0; _terminate = false; } @@ -168,12 +155,50 @@ Disk_Stream::run ( void ) FATAL( "Could not create IO thread!" ); } +void +Disk_Stream::_resize_buffers ( nframes_t nframes, int channels ) +{ + for ( int i = _rb.size(); i--; ) + jack_ringbuffer_free( _rb[ i ] ); + + _rb.clear(); + + _nframes = nframes; + + _total_blocks = _frame_rate * seconds_to_buffer / nframes; + + size_t bufsize = _total_blocks * nframes * sizeof( sample_t ); + + if ( disk_io_kbytes ) + _disk_io_blocks = ( bufsize * channels ) / ( disk_io_kbytes * 1024 ); + else + _disk_io_blocks = 1; + + for ( int i = channels; i--; ) + _rb.push_back( jack_ringbuffer_create( bufsize ) ); +} + +/* THREAD: RT (non-RT) */ /* to be called when the JACK buffer size changes. */ void -Disk_Stream::resize ( nframes_t nframes ) +Disk_Stream::resize_buffers ( nframes_t nframes ) { if ( nframes != _nframes ) - /* FIXME: to something here! */; + { + DMESSAGE( "resizing buffers" ); + + const bool was_running = _thread; + + if ( was_running ) + shutdown(); + + flush(); + + _resize_buffers( nframes, channels() ); + + if ( was_running ) + run(); + } } diff --git a/Timeline/Disk_Stream.H b/Timeline/Disk_Stream.H index 2f78e5c..871a06c 100644 --- a/Timeline/Disk_Stream.H +++ b/Timeline/Disk_Stream.H @@ -59,6 +59,9 @@ protected: int _total_blocks; /* total number of blocks that we can buffer */ int _disk_io_blocks; /* the number of blocks to read/write to/from disk at once */ + + nframes_t _frame_rate; /* used for buffer size calculations */ + volatile nframes_t _pending_seek; /* absolute transport position to seek to */ volatile int _terminate; @@ -71,6 +74,8 @@ protected: static void *disk_thread ( void *arg ); + void _resize_buffers ( nframes_t nframes, int channels ); + protected: void block_processed ( void ) { sem_post( &_blocks ); } @@ -86,7 +91,8 @@ protected: virtual void disk_thread ( void ) = 0; - void flush ( bool is_output ); + void base_flush ( bool is_output ); + virtual void flush ( void ) = 0; public: @@ -100,7 +106,7 @@ public: virtual ~Disk_Stream ( ); - void resize ( nframes_t nframes ); + void resize_buffers ( nframes_t nframes ); /* void seek ( nframes_t frame ); */ /* bool seek_pending ( void ); */ diff --git a/Timeline/Engine.C b/Timeline/Engine.C index 84131fc..2d8f582 100644 --- a/Timeline/Engine.C +++ b/Timeline/Engine.C @@ -70,6 +70,12 @@ Engine::freewheel ( int starting, void *arg ) ((Engine*)arg)->freewheel( starting ); } +int +Engine::buffer_size ( nframes_t nframes, void *arg ) +{ + return ((Engine*)arg)->buffer_size( nframes ); +} + void @@ -101,6 +107,16 @@ Engine::freewheel ( bool starting ) DMESSAGE( "leaving freewheeling mode" ); } +/* THREAD: RT (non-RT) */ +int +Engine::buffer_size ( nframes_t nframes ) +{ + /* TODO: inform all disktreams the the buffer size has changed */ + timeline->resize_buffers( nframes ); + + return 0; +} + /* THREAD: RT */ /** This is the jack slow-sync callback. */ int @@ -232,6 +248,7 @@ Engine::init ( void ) set_callback( process ); set_callback( xrun ); set_callback( freewheel ); + set_callback( buffer_size ); /* FIXME: should we wait to register this until after the project has been loaded (and we have disk threads running)? */ diff --git a/Timeline/Engine.H b/Timeline/Engine.H index ba2c061..d21e36a 100644 --- a/Timeline/Engine.H +++ b/Timeline/Engine.H @@ -55,6 +55,8 @@ class Engine : public Mutex void timebase ( jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos ); static void freewheel ( int yes, void *arg ); void freewheel ( bool yes ); + static int buffer_size ( nframes_t nframes, void *arg ); + int buffer_size ( nframes_t nframes ); Engine ( const Engine &rhs ); Engine & operator = ( const Engine &rhs ); diff --git a/Timeline/Playback_DS.C b/Timeline/Playback_DS.C index 6f22a56..863b998 100644 --- a/Timeline/Playback_DS.C +++ b/Timeline/Playback_DS.C @@ -54,7 +54,7 @@ Playback_DS::seek ( nframes_t frame ) _pending_seek = frame; - flush( true ); + flush(); } /* THREAD: IO */ @@ -93,7 +93,6 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes ) void Playback_DS::disk_thread ( void ) { - DMESSAGE( "playback thread running" ); /* buffer to hold the interleaved data returned by the track reader */ diff --git a/Timeline/Playback_DS.H b/Timeline/Playback_DS.H index 1bfe8f6..bced5f3 100644 --- a/Timeline/Playback_DS.H +++ b/Timeline/Playback_DS.H @@ -25,6 +25,8 @@ class Playback_DS : public Disk_Stream void read_block ( sample_t *buf, nframes_t nframes ); void disk_thread ( void ); + void flush ( void ) { base_flush( true ); } + public: Playback_DS ( Track *th, float frame_rate, nframes_t nframes, int channels ) : diff --git a/Timeline/Record_DS.C b/Timeline/Record_DS.C index b4ff69d..f65dd3e 100644 --- a/Timeline/Record_DS.C +++ b/Timeline/Record_DS.C @@ -199,7 +199,7 @@ Record_DS::start ( nframes_t frame ) } /* FIXME: safe to do this here? */ - flush( false ); + flush(); _frame = frame; diff --git a/Timeline/Record_DS.H b/Timeline/Record_DS.H index be6facb..fa7d4dc 100644 --- a/Timeline/Record_DS.H +++ b/Timeline/Record_DS.H @@ -43,6 +43,8 @@ class Record_DS : public Disk_Stream void write_block ( sample_t *buf, nframes_t nframes ); void disk_thread ( void ); + void flush ( void ) { base_flush( false ); } + public: Record_DS ( Track *th, float frame_rate, nframes_t nframes, int channels ) : diff --git a/Timeline/Timeline.C b/Timeline/Timeline.C index ba0479e..99ac3a2 100644 --- a/Timeline/Timeline.C +++ b/Timeline/Timeline.C @@ -1233,6 +1233,18 @@ Timeline::seek ( nframes_t frame ) } } +/* THREAD: RT (non-RT) */ +void +Timeline::resize_buffers ( nframes_t nframes ) +{ + for ( int i = tracks->children(); i-- ; ) + { + Track *t = (Track*)tracks->child( i ); + + t->resize_buffers( nframes ); + } +} + /* THREAD: RT */ int Timeline::seek_pending ( void ) diff --git a/Timeline/Timeline.H b/Timeline/Timeline.H index 8ca8349..8453285 100644 --- a/Timeline/Timeline.H +++ b/Timeline/Timeline.H @@ -210,6 +210,7 @@ private: char * get_unique_track_name ( const char *name ); /* Engine */ + void resize_buffers ( nframes_t nframes ); nframes_t process ( nframes_t nframes ); void seek ( nframes_t frame ); int seek_pending ( void ); diff --git a/Timeline/Track.C b/Timeline/Track.C index a6237bd..a7ed8ff 100644 --- a/Timeline/Track.C +++ b/Timeline/Track.C @@ -745,7 +745,15 @@ Track::seek ( nframes_t frame ) return playback_ds->seek( frame ); } - +/* THREAD: RT (non-RT) */ +void +Track::resize_buffers ( nframes_t nframes ) +{ + if ( record_ds ) + record_ds->resize_buffers( nframes ); + if ( playback_ds ) + playback_ds->resize_buffers( nframes ); +} /* FIXME: what about theading issues with this region/audiofile being accessible from the UI thread? Need locking? */ diff --git a/Timeline/Track.H b/Timeline/Track.H index 7099595..8be2498 100644 --- a/Timeline/Track.H +++ b/Timeline/Track.H @@ -265,6 +265,7 @@ public: const Audio_Region *capture ( void ) const { return _capture; } /* Engine */ + void resize_buffers ( nframes_t nframes ); nframes_t process ( nframes_t nframes ); void seek ( nframes_t frame ); void record ( nframes_t nframes );