From bdd9dc56e401ec189582a2501342927f23480abf Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Thu, 1 May 2008 18:35:46 -0500 Subject: [PATCH] Try to get captures to begin and end on the proper frame. --- Timeline/Disk_Stream.C | 40 +++++++++++++++++++++++++++ Timeline/Disk_Stream.H | 4 ++- Timeline/Playback_DS.C | 18 +------------ Timeline/Record_DS.C | 61 +++++++++++++++++++++++++++++------------- Timeline/Record_DS.H | 5 ++++ Timeline/Region.C | 8 ++++-- Timeline/Region.H | 2 +- Timeline/Track.C | 4 +-- 8 files changed, 100 insertions(+), 42 deletions(-) diff --git a/Timeline/Disk_Stream.C b/Timeline/Disk_Stream.C index e9740ae..003de5d 100644 --- a/Timeline/Disk_Stream.C +++ b/Timeline/Disk_Stream.C @@ -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 ) diff --git a/Timeline/Disk_Stream.H b/Timeline/Disk_Stream.H index 0a3b2ae..5532990 100644 --- a/Timeline/Disk_Stream.H +++ b/Timeline/Disk_Stream.H @@ -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 */ diff --git a/Timeline/Playback_DS.C b/Timeline/Playback_DS.C index 4874121..794e172 100644 --- a/Timeline/Playback_DS.C +++ b/Timeline/Playback_DS.C @@ -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 */ diff --git a/Timeline/Record_DS.C b/Timeline/Record_DS.C index 9087884..b56f074 100644 --- a/Timeline/Record_DS.C +++ b/Timeline/Record_DS.C @@ -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,25 +205,17 @@ Record_DS::stop ( nframes_t frame ) return; } + _recording = false; + + /* FIXME: we may still have data in the buffers waiting to be + * written to disk... We should flush it out before stopping... */ + + _stop_frame = frame; + shutdown(); /* FIXME: flush buffers here? */ -/* char *name = strdup( _af->name() ); */ -/* delete _af; */ -/* _af = NULL; */ - -/* Audio_File *af = Audio_File::from_file( name ); */ - -/* if ( ! af ) */ -/* printf( "impossible!\n" ); */ - -/* new Region( af, track(), _frame ); */ - -/* track()->redraw(); */ - - _recording = false; - _th->stop( frame ); printf( "recording finished\n" ); diff --git a/Timeline/Record_DS.H b/Timeline/Record_DS.H index 5d96ae3..abd073e 100644 --- a/Timeline/Record_DS.H +++ b/Timeline/Record_DS.H @@ -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 ); */ diff --git a/Timeline/Region.C b/Timeline/Region.C index c6a94ab..616addd 100644 --- a/Timeline/Region.C +++ b/Timeline/Region.C @@ -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; } diff --git a/Timeline/Region.H b/Timeline/Region.H index 616291d..7e64e84 100644 --- a/Timeline/Region.H +++ b/Timeline/Region.H @@ -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 ); }; diff --git a/Timeline/Track.C b/Timeline/Track.C index 26eac8f..7f3801e 100644 --- a/Timeline/Track.C +++ b/Timeline/Track.C @@ -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; }