void Playback_DS::disk_thread ( void ) { _thread.name( "Playback" ); DMESSAGE( "playback thread running" ); /* buffer to hold the interleaved data returned by the track reader */ sample_t *buf = buffer_alloc( _nframes * channels() * _disk_io_blocks ); sample_t *cbuf = buffer_alloc( _nframes ); const nframes_t nframes = _nframes; nframes_t blocks_written; while ( ! _terminate ) { seek: blocks_written = 0; read_block( buf, nframes * _disk_io_blocks ); while ( blocks_written < _disk_io_blocks && wait_for_block() ) { // lock(); // for seeking if ( _pending_seek ) { /* FIXME: non-RT-safe IO */ DMESSAGE( "performing seek to frame %lu", (unsigned long)_seek_frame ); _frame = _seek_frame; _pending_seek = false; flush(); goto seek; } /* might have received terminate signal while waiting for block */ if ( _terminate ) goto done; // unlock(); // for seeking /* deinterleave the buffer and stuff it into the per-channel ringbuffers */ const size_t block_size = nframes * sizeof( sample_t ); for ( int i = 0; i < channels(); i++ ) { buffer_deinterleave_one_channel( cbuf, buf + ( blocks_written * nframes * channels() ), i, channels(), nframes ); while ( jack_ringbuffer_write_space( _rb[ i ] ) < block_size ) usleep( 100 * 1000 ); jack_ringbuffer_write( _rb[ i ], ((char*)cbuf), block_size ); } blocks_written++; } } done: DMESSAGE( "playback thread terminating" ); free(buf); free(cbuf); // flush(); _terminate = false; _thread.exit(); }
void Record_DS::disk_thread ( void ) { _thread.name( "Capture" ); DMESSAGE( "capture thread running..." ); const nframes_t nframes = _nframes; /* buffer to hold the interleaved data returned by the track reader */ sample_t *buf = buffer_alloc( nframes * channels() * _disk_io_blocks ); sample_t *cbuf = buffer_alloc( nframes ); const size_t block_size = nframes * sizeof( sample_t ); nframes_t blocks_read = 0; while ( wait_for_block() ) { /* pull data from the per-channel ringbuffers and interlace it */ for ( int i = channels(); i--; ) { while ( jack_ringbuffer_read_space( _rb[ i ] ) < block_size ) usleep( 10 * 1000 ); jack_ringbuffer_read( _rb[ i ], ((char*)cbuf), block_size ); buffer_interleave_one_channel( buf + ( blocks_read * nframes * channels() ), cbuf, i, channels(), nframes ); } blocks_read++; if ( blocks_read == _disk_io_blocks ) { write_block( buf, nframes * _disk_io_blocks ); blocks_read = 0; } } DMESSAGE( "capture thread terminating" ); /* flush what remains in the buffer out to disk */ { while ( blocks_read-- > 0 || ( ! sem_trywait( &_blocks ) && errno != EAGAIN ) ) { for ( int i = channels(); i--; ) { jack_ringbuffer_read( _rb[ i ], (char*)cbuf, block_size ); buffer_interleave_one_channel( buf, cbuf, i, channels(), nframes ); } const nframes_t frames_remaining = (_stop_frame - _frame ) - _frames_written; if ( frames_remaining < nframes ) { /* this is the last block, might be partial */ write_block( buf, frames_remaining ); break; } else write_block( buf, nframes ); } } free(buf); free(cbuf); DMESSAGE( "finalzing capture" ); Track::Capture *c = _capture; _capture = NULL; /* now finalize the recording */ if ( c->audio_file ) track()->finalize( c, _stop_frame ); delete c; flush(); _terminate = false; DMESSAGE( "capture thread gone" ); _thread.exit(); }
void Record_DS::disk_thread ( void ) { _thread.name( "Capture" ); DMESSAGE( "capture thread running..." ); track()->record( _capture, _frame ); const nframes_t nframes = _nframes * _disk_io_blocks; /* buffer to hold the interleaved data returned by the track reader */ sample_t *buf = new sample_t[ nframes * channels() ]; #ifndef AVOID_UNNECESSARY_COPYING sample_t *cbuf = new sample_t[ nframes ]; #endif const size_t block_size = nframes * sizeof( sample_t ); int blocks_ready = 0; while ( wait_for_block() ) { if ( ++blocks_ready < _disk_io_blocks ) continue; else blocks_ready = 0; /* pull data from the per-channel ringbuffers and interlace it */ for ( int i = channels(); i--; ) { #ifdef AVOID_UNNECESSARY_COPYING /* interleave direcectly from the ringbuffer to avoid * unnecessary copying */ jack_ringbuffer_data_t rbd[2]; memset( rbd, 0, sizeof( rbd ) ); jack_ringbuffer_get_read_vector( _rb[ i ], rbd ); if ( rbd[ 0 ].len >= block_size ) { /* it'll all fit in one go */ buffer_interleave_one_channel( buf, (sample_t*)rbd[ 0 ].buf, i, channels(), nframes ); } else if ( rbd[ 0 ].len + rbd[ 1 ].len >= block_size ) { /* there's enough space in the ringbuffer, but it's not contiguous */ assert( ! ( rbd[ 0 ].len % sizeof( sample_t ) ) ); const nframes_t f = rbd[ 0 ].len / sizeof( sample_t ); /* do the first half */ buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), f ); buffer_interleave_one_channel( buf, (sample_t*)rbd[ 0 ].buf, i, channels(), f ); assert( rbd[ 1 ].len >= ( nframes - f ) * sizeof( sample_t ) ); /* do the second half */ buffer_interleave_one_channel( buf + f, (sample_t*)rbd[ 0 ].buf, i, channels(), nframes - f ); } else ++_xruns; jack_ringbuffer_read_advance( _rb[ i ], block_size ); #else if ( jack_ringbuffer_read( _rb[ i ], (char*)cbuf, block_size ) < block_size ) ++_xruns; buffer_interleave_one_channel( buf, cbuf, i, channels(), nframes ); #endif } write_block( buf, nframes ); } DMESSAGE( "capture thread terminating" ); /* flush what remains in the buffer out to disk */ { /* use JACk sized blocks for this last bit */ const nframes_t nframes = _nframes; const size_t block_size = _nframes * sizeof( sample_t ); #ifdef AVOID_UNNECESSARY_COPYING sample_t *cbuf = new sample_t[ nframes ]; #endif while ( blocks_ready-- > 0 || ( ! sem_trywait( &_blocks ) && errno != EAGAIN ) ) { for ( int i = channels(); i--; ) { jack_ringbuffer_read( _rb[ i ], (char*)cbuf, block_size ); buffer_interleave_one_channel( buf, cbuf, i, channels(), nframes ); } const nframes_t frames_remaining = (_stop_frame - _frame ) - _frames_written; if ( frames_remaining < nframes ) { /* this is the last block, might be partial */ write_block( buf, frames_remaining ); break; } else write_block( buf, nframes ); } #ifdef AVOID_UNNECESSARY_COPYING delete[] cbuf; #endif } delete[] buf; #ifndef AVOID_UNNECESSARY_COPYING delete[] cbuf; #endif DMESSAGE( "finalzing capture" ); Track::Capture *c = _capture; _capture = NULL; /* now finalize the recording */ track()->finalize( c, _stop_frame ); delete c; _terminate = false; DMESSAGE( "capture thread gone" ); _thread.exit(); }
void Playback_DS::disk_thread ( void ) { _thread.name( "Playback" ); DMESSAGE( "playback thread running" ); /* buffer to hold the interleaved data returned by the track reader */ sample_t *buf = new sample_t[ _nframes * channels() * _disk_io_blocks ]; #ifndef AVOID_UNNECESSARY_COPYING sample_t *cbuf = new sample_t[ _nframes * _disk_io_blocks ]; #endif int blocks_ready = 0; const nframes_t nframes = _nframes * _disk_io_blocks; while ( wait_for_block() ) { // lock(); // for seeking if ( seek_pending() ) { /* FIXME: non-RT-safe IO */ DMESSAGE( "performing seek to frame %lu", (unsigned long)_pending_seek ); _frame = _pending_seek; _pending_seek = -1; blocks_ready = 0; } if ( ++blocks_ready < _disk_io_blocks ) { /* wait for more space */ continue; } /* reset */ blocks_ready = 0; read_block( buf, nframes ); // unlock(); // for seeking /* deinterleave the buffer and stuff it into the per-channel ringbuffers */ const size_t block_size = nframes * sizeof( sample_t ); for ( int i = channels(); i--; ) { #ifdef AVOID_UNNECESSARY_COPYING /* deinterleave direcectly into the ringbuffer to avoid * unnecessary copying */ jack_ringbuffer_data_t rbd[2]; memset( rbd, 0, sizeof( rbd ) ); jack_ringbuffer_get_write_vector( _rb[ i ], rbd ); if ( rbd[ 0 ].len >= block_size ) { /* it'll all fit in one go */ buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), nframes ); } else if ( rbd[ 0 ].len + rbd[ 1 ].len >= block_size ) { /* there's enough space in the ringbuffer, but it's not contiguous */ assert( ! ( rbd[ 0 ].len % sizeof( sample_t ) ) ); // assert( ! ( rbd[ 1 ].len % sizeof( sample_t ) ) ); const nframes_t f = rbd[ 0 ].len / sizeof( sample_t ); /* do the first half */ buffer_deinterleave_one_channel( (sample_t*)rbd[ 0 ].buf, buf, i, channels(), f ); assert( rbd[ 1 ].len >= ( nframes - f ) * sizeof( sample_t ) ); /* do the second half */ buffer_deinterleave_one_channel( (sample_t*)rbd[ 1 ].buf, buf + f, i, channels(), nframes - f ); } else ++_xruns; jack_ringbuffer_write_advance( _rb[ i ], block_size ); #else buffer_deinterleave_one_channel( cbuf, buf, i, channels(), nframes ); if ( jack_ringbuffer_write( _rb[ i ], (char*)cbuf, block_size ) < block_size ) ++_xruns; #endif } } DMESSAGE( "playback thread terminating" ); delete[] buf; #ifndef AVOID_UNNECESSARY_COPYING delete[] cbuf; #endif _terminate = false; }