/** take a single block from the ringbuffers and send it out the * attached track's ports */ nframes_t Playback_DS::process ( nframes_t nframes ) { THREAD_ASSERT( RT ); const size_t block_size = nframes * sizeof( sample_t ); // printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes ); for ( int i = channels(); i--; ) { void *buf = track()->output[ i ].buffer( nframes ); if ( jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size ) < block_size ) { ++_xruns; memset( buf, 0, block_size ); /* FIXME: we need to resync somehow */ } /* TODO: figure out a way to stop IO while muted without losing sync */ if ( track()->mute() || ( Track::soloing() && ! track()->solo() ) ) buffer_fill_with_silence( (sample_t*)buf, nframes ); } block_processed(); /* FIXME: bogus */ return nframes; }
/** signal thread to terminate, then detach it */ void Disk_Stream::detach ( void ) { _terminate = true; block_processed(); _thread.detach(); }
/** stop the IO thread. */ void Disk_Stream::shutdown ( void ) { _terminate = true; /* try to wake the thread so it'll see that it's time to die */ block_processed(); if ( _thread.running() ) _thread.join(); }
/** read from the attached track's ports and stuff the ringbuffers */ nframes_t Record_DS::process ( nframes_t nframes ) { THREAD_ASSERT( RT ); if ( ! _recording ) return 0; if ( transport->frame < _frame ) return 0; /* DMESSAGE( "recording actually happening at %lu (start frame %lu)", (unsigned long)transport->frame, (unsigned long)_frame); */ nframes_t offset = 0; if ( _frame > transport->frame && _frame < transport->frame + nframes ) { /* The record start frame falls somewhere within the current buffer. We must discard the unneeded portion and only stuff the part requested into the ringbuffer. */ offset = _frame - transport->frame; /* DMESSAGE( "offset = %lu", (unsigned long)offset ); */ } const size_t offset_size = offset * sizeof( sample_t ); const size_t block_size = ( nframes * sizeof( sample_t ) ) - offset_size; for ( int i = channels(); i--; ) { /* read the entire input buffer */ void *buf = track()->input[ i ].buffer( nframes ); /* if ( buffer_is_digital_black( (sample_t*)buf, nframes ) ) */ /* DWARNING( "recording an entirely blank buffer" ); */ /* FIXME: this results in a ringbuffer size that is no longer necessarily a multiple of nframes... how will the other side handle that? */ if ( jack_ringbuffer_write( _rb[ i ], (char*)buf + offset, block_size ) < block_size ) { ++_xruns; memset( buf, 0, block_size ); /* FIXME: we need to resync somehow */ } } block_processed(); /* FIXME: bogus */ return nframes; }
/** request that the IO thread perform a seek and rebuffer. This is called for each Disk_Stream whenever the RT thread determines that the transport has jumped to a new position. This is called *before* process. */ void Playback_DS::seek ( nframes_t frame ) { THREAD_ASSERT( RT ); /* FIXME: non-RT-safe IO */ DMESSAGE( "requesting seek to frame %lu", (unsigned long)frame ); if ( seek_pending() ) printf( "seek error, attempt to seek while seek is pending\n" ); _seek_frame = frame; _pending_seek = true; /* wake the IO thread */ block_processed(); }
/** stop the IO thread. */ void Disk_Stream::shutdown ( void ) { if ( _thread.running() ) { DMESSAGE( "Sending terminate signal to diskthread." ); _terminate = true; /* try to wake the thread so it'll see that it's time to die */ while ( _terminate ) { block_processed(); usleep( 10 * 1000 ); } _thread.join(); } }