@@ -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 ) | Disk_Stream::Disk_Stream ( Track *track, float frame_rate, nframes_t nframes, int channels ) : _track( track ) | ||||
{ | { | ||||
assert( channels ); | assert( channels ); | ||||
_frame = 0; | _frame = 0; | ||||
@@ -60,20 +59,9 @@ Disk_Stream::Disk_Stream ( Track *track, float frame_rate, nframes_t nframes, in | |||||
_terminate = false; | _terminate = false; | ||||
_pending_seek = -1; | _pending_seek = -1; | ||||
_xruns = 0; | _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 ); | sem_init( &_blocks, 0, _total_blocks ); | ||||
} | } | ||||
@@ -97,14 +85,13 @@ Disk_Stream::~Disk_Stream ( ) | |||||
/* THREAD: RT */ | /* THREAD: RT */ | ||||
/** flush buffers and reset. Must only be called from the RT thread. */ | /** flush buffers and reset. Must only be called from the RT thread. */ | ||||
void | void | ||||
Disk_Stream::flush ( bool is_output ) | |||||
Disk_Stream::base_flush ( bool is_output ) | |||||
{ | { | ||||
/* flush buffers */ | /* 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 ] ) ); | jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) ); | ||||
/* sem_destroy( &_blocks ); */ | /* sem_destroy( &_blocks ); */ | ||||
/* if ( is_output ) */ | /* if ( is_output ) */ | ||||
@@ -114,7 +101,6 @@ Disk_Stream::flush ( bool is_output ) | |||||
if ( is_output ) | if ( is_output ) | ||||
{ | { | ||||
int n; | int n; | ||||
sem_getvalue( &_blocks, &n ); | sem_getvalue( &_blocks, &n ); | ||||
@@ -145,6 +131,7 @@ Disk_Stream::shutdown ( void ) | |||||
if ( _thread ) | if ( _thread ) | ||||
pthread_join( _thread, NULL ); | pthread_join( _thread, NULL ); | ||||
_thread = 0; | |||||
_terminate = false; | _terminate = false; | ||||
} | } | ||||
@@ -168,12 +155,50 @@ Disk_Stream::run ( void ) | |||||
FATAL( "Could not create IO thread!" ); | 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. */ | /* to be called when the JACK buffer size changes. */ | ||||
void | void | ||||
Disk_Stream::resize ( nframes_t nframes ) | |||||
Disk_Stream::resize_buffers ( nframes_t nframes ) | |||||
{ | { | ||||
if ( nframes != _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(); | |||||
} | |||||
} | } | ||||
@@ -59,6 +59,9 @@ protected: | |||||
int _total_blocks; /* total number of blocks that we can buffer */ | 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 */ | 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 nframes_t _pending_seek; /* absolute transport position to seek to */ | ||||
volatile int _terminate; | volatile int _terminate; | ||||
@@ -71,6 +74,8 @@ protected: | |||||
static void *disk_thread ( void *arg ); | static void *disk_thread ( void *arg ); | ||||
void _resize_buffers ( nframes_t nframes, int channels ); | |||||
protected: | protected: | ||||
void block_processed ( void ) { sem_post( &_blocks ); } | void block_processed ( void ) { sem_post( &_blocks ); } | ||||
@@ -86,7 +91,8 @@ protected: | |||||
virtual void disk_thread ( void ) = 0; | virtual void disk_thread ( void ) = 0; | ||||
void flush ( bool is_output ); | |||||
void base_flush ( bool is_output ); | |||||
virtual void flush ( void ) = 0; | |||||
public: | public: | ||||
@@ -100,7 +106,7 @@ public: | |||||
virtual ~Disk_Stream ( ); | virtual ~Disk_Stream ( ); | ||||
void resize ( nframes_t nframes ); | |||||
void resize_buffers ( nframes_t nframes ); | |||||
/* void seek ( nframes_t frame ); */ | /* void seek ( nframes_t frame ); */ | ||||
/* bool seek_pending ( void ); */ | /* bool seek_pending ( void ); */ | ||||
@@ -70,6 +70,12 @@ Engine::freewheel ( int starting, void *arg ) | |||||
((Engine*)arg)->freewheel( starting ); | ((Engine*)arg)->freewheel( starting ); | ||||
} | } | ||||
int | |||||
Engine::buffer_size ( nframes_t nframes, void *arg ) | |||||
{ | |||||
return ((Engine*)arg)->buffer_size( nframes ); | |||||
} | |||||
void | void | ||||
@@ -101,6 +107,16 @@ Engine::freewheel ( bool starting ) | |||||
DMESSAGE( "leaving freewheeling mode" ); | 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 */ | /* THREAD: RT */ | ||||
/** This is the jack slow-sync callback. */ | /** This is the jack slow-sync callback. */ | ||||
int | int | ||||
@@ -232,6 +248,7 @@ Engine::init ( void ) | |||||
set_callback( process ); | set_callback( process ); | ||||
set_callback( xrun ); | set_callback( xrun ); | ||||
set_callback( freewheel ); | set_callback( freewheel ); | ||||
set_callback( buffer_size ); | |||||
/* FIXME: should we wait to register this until after the project | /* FIXME: should we wait to register this until after the project | ||||
has been loaded (and we have disk threads running)? */ | has been loaded (and we have disk threads running)? */ | ||||
@@ -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 ); | 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 ); | static void freewheel ( int yes, void *arg ); | ||||
void freewheel ( bool yes ); | void freewheel ( bool yes ); | ||||
static int buffer_size ( nframes_t nframes, void *arg ); | |||||
int buffer_size ( nframes_t nframes ); | |||||
Engine ( const Engine &rhs ); | Engine ( const Engine &rhs ); | ||||
Engine & operator = ( const Engine &rhs ); | Engine & operator = ( const Engine &rhs ); | ||||
@@ -54,7 +54,7 @@ Playback_DS::seek ( nframes_t frame ) | |||||
_pending_seek = frame; | _pending_seek = frame; | ||||
flush( true ); | |||||
flush(); | |||||
} | } | ||||
/* THREAD: IO */ | /* THREAD: IO */ | ||||
@@ -93,7 +93,6 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes ) | |||||
void | void | ||||
Playback_DS::disk_thread ( void ) | Playback_DS::disk_thread ( void ) | ||||
{ | { | ||||
DMESSAGE( "playback thread running" ); | DMESSAGE( "playback thread running" ); | ||||
/* buffer to hold the interleaved data returned by the track reader */ | /* buffer to hold the interleaved data returned by the track reader */ | ||||
@@ -25,6 +25,8 @@ class Playback_DS : public Disk_Stream | |||||
void read_block ( sample_t *buf, nframes_t nframes ); | void read_block ( sample_t *buf, nframes_t nframes ); | ||||
void disk_thread ( void ); | void disk_thread ( void ); | ||||
void flush ( void ) { base_flush( true ); } | |||||
public: | public: | ||||
Playback_DS ( Track *th, float frame_rate, nframes_t nframes, int channels ) : | Playback_DS ( Track *th, float frame_rate, nframes_t nframes, int channels ) : | ||||
@@ -199,7 +199,7 @@ Record_DS::start ( nframes_t frame ) | |||||
} | } | ||||
/* FIXME: safe to do this here? */ | /* FIXME: safe to do this here? */ | ||||
flush( false ); | |||||
flush(); | |||||
_frame = frame; | _frame = frame; | ||||
@@ -43,6 +43,8 @@ class Record_DS : public Disk_Stream | |||||
void write_block ( sample_t *buf, nframes_t nframes ); | void write_block ( sample_t *buf, nframes_t nframes ); | ||||
void disk_thread ( void ); | void disk_thread ( void ); | ||||
void flush ( void ) { base_flush( false ); } | |||||
public: | public: | ||||
Record_DS ( Track *th, float frame_rate, nframes_t nframes, int channels ) : | Record_DS ( Track *th, float frame_rate, nframes_t nframes, int channels ) : | ||||
@@ -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 */ | /* THREAD: RT */ | ||||
int | int | ||||
Timeline::seek_pending ( void ) | Timeline::seek_pending ( void ) | ||||
@@ -210,6 +210,7 @@ private: | |||||
char * get_unique_track_name ( const char *name ); | char * get_unique_track_name ( const char *name ); | ||||
/* Engine */ | /* Engine */ | ||||
void resize_buffers ( nframes_t nframes ); | |||||
nframes_t process ( nframes_t nframes ); | nframes_t process ( nframes_t nframes ); | ||||
void seek ( nframes_t frame ); | void seek ( nframes_t frame ); | ||||
int seek_pending ( void ); | int seek_pending ( void ); | ||||
@@ -745,7 +745,15 @@ Track::seek ( nframes_t frame ) | |||||
return playback_ds->seek( 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 | /* FIXME: what about theading issues with this region/audiofile being | ||||
accessible from the UI thread? Need locking? */ | accessible from the UI thread? Need locking? */ | ||||
@@ -265,6 +265,7 @@ public: | |||||
const Audio_Region *capture ( void ) const { return _capture; } | const Audio_Region *capture ( void ) const { return _capture; } | ||||
/* Engine */ | /* Engine */ | ||||
void resize_buffers ( nframes_t nframes ); | |||||
nframes_t process ( nframes_t nframes ); | nframes_t process ( nframes_t nframes ); | ||||
void seek ( nframes_t frame ); | void seek ( nframes_t frame ); | ||||
void record ( nframes_t nframes ); | void record ( nframes_t nframes ); | ||||