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