| @@ -96,6 +96,46 @@ Disk_Stream::~Disk_Stream ( ) | |||
| engine->unlock(); | |||
| } | |||
| /* THREAD: RT */ | |||
| /** flush buffers and reset. Must only be called from the RT thread. */ | |||
| void | |||
| Disk_Stream::flush ( bool is_output ) | |||
| { | |||
| /* flush buffers */ | |||
| for ( int i = channels(); i--; ) | |||
| jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) ); | |||
| /* sem_destroy( &_blocks ); */ | |||
| /* if ( is_output ) */ | |||
| /* sem_init( &_blocks, 0, _total_blocks ); */ | |||
| /* else */ | |||
| /* sem_init( &_blocks, 0, 0 ); */ | |||
| if ( is_output ) | |||
| { | |||
| int n; | |||
| sem_getvalue( &_blocks, &n ); | |||
| n = _total_blocks - n; | |||
| while ( n-- ) | |||
| sem_post( &_blocks ); | |||
| } | |||
| else | |||
| { | |||
| sem_destroy( &_blocks ); | |||
| sem_init( &_blocks, 0, 0 ); | |||
| } | |||
| } | |||
| /** stop the IO thread, block until it finishes. */ | |||
| void | |||
| Disk_Stream::shutdown ( void ) | |||
| @@ -71,7 +71,7 @@ protected: | |||
| void block_processed ( void ) { sem_post( &_blocks ); } | |||
| bool wait_for_block ( void ) | |||
| { | |||
| while ( sem_wait( &_blocks ) == EINTR ); | |||
| while ( ! sem_wait( &_blocks ) && errno == EINTR ); | |||
| if ( _terminate ) | |||
| return false; | |||
| @@ -81,6 +81,8 @@ protected: | |||
| virtual void disk_thread ( void ) = 0; | |||
| void flush ( bool is_output ); | |||
| public: | |||
| /* must be set before any Disk_Streams are created */ | |||
| @@ -52,23 +52,7 @@ Playback_DS::seek ( nframes_t frame ) | |||
| _pending_seek = frame; | |||
| /* flush buffers */ | |||
| for ( int i = channels(); i--; ) | |||
| jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) ); | |||
| /* dirty hack... reset the semaphore. Should we just call sem_init | |||
| * again instead? */ | |||
| /* sem_init( &_blocks, 0, _total_blocks ); */ | |||
| int n; | |||
| sem_getvalue( &_blocks, &n ); | |||
| n = _total_blocks - n; | |||
| while ( n-- ) | |||
| sem_post( &_blocks ); | |||
| flush( true ); | |||
| } | |||
| /* THREAD: IO */ | |||
| @@ -43,7 +43,7 @@ Record_DS::write_block ( sample_t *buf, nframes_t nframes ) | |||
| _th->write( buf, nframes ); | |||
| // track()->record( buf, _frame, nframes, channels() ); | |||
| _frames_written += nframes; | |||
| // timeline->unlock(); | |||
| } | |||
| @@ -52,7 +52,6 @@ Record_DS::write_block ( sample_t *buf, nframes_t nframes ) | |||
| void | |||
| Record_DS::disk_thread ( void ) | |||
| { | |||
| printf( "IO thread running...\n" ); | |||
| const nframes_t nframes = _nframes * _disk_io_blocks; | |||
| @@ -134,17 +133,47 @@ Record_DS::disk_thread ( void ) | |||
| printf( "IO thread terminating.\n" ); | |||
| /* 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 ); | |||
| 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 ); | |||
| } | |||
| } | |||
| delete[] cbuf; | |||
| delete[] buf; | |||
| } | |||
| /** begin recording */ | |||
| /* FIXME: we need to make note of the exact frame we were on when recording began */ | |||
| void | |||
| Record_DS::start ( nframes_t frame ) | |||
| { | |||
| /* FIXME: flush buffers here? */ | |||
| if ( _recording ) | |||
| { | |||
| @@ -152,6 +181,8 @@ Record_DS::start ( nframes_t frame ) | |||
| return; | |||
| } | |||
| /* FIXME: safe to do this here? */ | |||
| flush( false ); | |||
| _frame = frame; | |||
| @@ -174,24 +205,16 @@ Record_DS::stop ( nframes_t frame ) | |||
| return; | |||
| } | |||
| shutdown(); | |||
| /* FIXME: flush buffers here? */ | |||
| /* char *name = strdup( _af->name() ); */ | |||
| /* delete _af; */ | |||
| /* _af = NULL; */ | |||
| /* Audio_File *af = Audio_File::from_file( name ); */ | |||
| _recording = false; | |||
| /* if ( ! af ) */ | |||
| /* printf( "impossible!\n" ); */ | |||
| /* FIXME: we may still have data in the buffers waiting to be | |||
| * written to disk... We should flush it out before stopping... */ | |||
| /* new Region( af, track(), _frame ); */ | |||
| _stop_frame = frame; | |||
| /* track()->redraw(); */ | |||
| shutdown(); | |||
| _recording = false; | |||
| /* FIXME: flush buffers here? */ | |||
| _th->stop( frame ); | |||
| @@ -28,6 +28,9 @@ class Peak_Writer; | |||
| class Record_DS : public Disk_Stream | |||
| { | |||
| nframes_t _frames_written; | |||
| volatile nframes_t _stop_frame; | |||
| volatile bool _recording; | |||
| Audio_File_SF *_af; /* capture file */ | |||
| @@ -44,6 +47,8 @@ public: | |||
| sem_init( &_blocks, 0, 0 ); | |||
| _recording = false; | |||
| _stop_frame = -1; | |||
| _frames_written = 0; | |||
| } | |||
| /* bool seek_pending ( void ); */ | |||
| @@ -947,14 +947,18 @@ Region::prepare ( void ) | |||
| /** finalize region capture. Assumes that this *is* a captured region | |||
| and that no other regions refer to the same source */ | |||
| bool | |||
| Region::finalize ( void ) | |||
| Region::finalize ( nframes_t frame ) | |||
| { | |||
| log_end(); | |||
| _clip->close(); | |||
| _clip->open(); | |||
| _range.end = _clip->length(); | |||
| /* FIXME: should we attempt to truncate the file? */ | |||
| _range.end = frame - _range.offset; | |||
| redraw(); | |||
| return true; | |||
| } | |||
| @@ -204,6 +204,6 @@ public: | |||
| nframes_t read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channel ) const; | |||
| nframes_t write ( nframes_t nframes ); | |||
| void prepare ( void ); | |||
| bool finalize ( void ); | |||
| bool finalize ( nframes_t frame ); | |||
| }; | |||
| @@ -749,9 +749,9 @@ Track::write ( sample_t *buf, nframes_t nframes ) | |||
| /* THREAD: IO */ | |||
| void | |||
| Track::stop ( nframes_t nframes ) | |||
| Track::stop ( nframes_t frame ) | |||
| { | |||
| _capture->finalize(); | |||
| _capture->finalize( frame ); | |||
| _capture = NULL; | |||
| } | |||