Exemple #1
0
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();
}
Exemple #2
0
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();
}
Exemple #3
0
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();
}
Exemple #4
0
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;
}