diff --git a/nonlib/Thread.C b/nonlib/Thread.C index 2117f87..f0c6292 100644 --- a/nonlib/Thread.C +++ b/nonlib/Thread.C @@ -127,6 +127,6 @@ Thread::join ( void ) void Thread::exit ( void *retval ) { - pthread_exit( retval ); _thread = 0; + pthread_exit( retval ); } diff --git a/timeline/src/Audio_Region.C b/timeline/src/Audio_Region.C index d70ed37..4ce3633 100644 --- a/timeline/src/Audio_Region.C +++ b/timeline/src/Audio_Region.C @@ -651,7 +651,7 @@ Audio_Region::draw ( void ) if ( peaks < loop_peaks_needed ) { - DMESSAGE( "Peak read came up %lu peaks short", (unsigned long)loop_peaks_needed - peaks ); +// DMESSAGE( "Peak read came up %lu peaks short", (unsigned long)loop_peaks_needed - peaks ); } fo += loop_frames_needed; diff --git a/timeline/src/Control_Sequence.C b/timeline/src/Control_Sequence.C index 9368dfa..61143ef 100644 --- a/timeline/src/Control_Sequence.C +++ b/timeline/src/Control_Sequence.C @@ -783,11 +783,11 @@ Control_Sequence::handle ( int m ) test_press( FL_BUTTON1 ) ) { /* insert new control point */ - timeline->wrlock(); + timeline->sequence_lock.wrlock(); new Control_Point( this, timeline->xoffset + timeline->x_to_ts( Fl::event_x() - drawable_x() ), (float)(Fl::event_y() - y()) / h() ); - timeline->unlock(); + timeline->sequence_lock.unlock(); return 1; } diff --git a/timeline/src/Engine/Audio_Region.C b/timeline/src/Engine/Audio_Region.C index f7ac319..7107b75 100644 --- a/timeline/src/Engine/Audio_Region.C +++ b/timeline/src/Engine/Audio_Region.C @@ -340,8 +340,12 @@ Audio_Region::write ( nframes_t nframes ) } } + timeline->sequence_lock.wrlock(); + _range.length += nframes; + timeline->sequence_lock.unlock(); + return nframes; } @@ -354,8 +358,12 @@ Audio_Region::finalize ( nframes_t frame ) DMESSAGE( "finalizing capture region" ); + timeline->sequence_lock.wrlock(); + _range.length = frame - _range.start; + timeline->sequence_lock.unlock(); + _clip->close(); _clip->open(); diff --git a/timeline/src/Engine/Engine.C b/timeline/src/Engine/Engine.C index c8b0a2c..3f7c84a 100644 --- a/timeline/src/Engine/Engine.C +++ b/timeline/src/Engine/Engine.C @@ -172,40 +172,55 @@ Engine::process ( nframes_t nframes ) transport->poll(); - if ( freewheeling() ) + if ( !timeline) + /* handle chicken/egg problem */ + return 0; + + nframes_t n = 0; + + n += timeline->process_input(nframes); + n += timeline->process_output(nframes); + + if ( n != nframes * 2 ) { - if ( timeline ) - { - timeline->rdlock(); - - timeline->process( nframes ); - - timeline->unlock(); - } + _buffers_dropped++; + WARNING("xrun"); } - else - { - if ( !timeline) - /* handle chicken/egg problem */ - return 0; + + /* if ( freewheeling() ) */ + /* { */ + /* if ( timeline ) */ + /* { */ + /* timeline->rdlock(); */ - if ( timeline->tryrdlock() ) - { - /* the data structures we need to access here (tracks and - * their ports, but not track contents) may be in an - * inconsistent state at the moment. Just punt and drop this - * buffer. */ - ++_buffers_dropped; - return 0; - } + /* timeline->process( nframes ); */ - /* this will initiate the process() call graph for the various - * number and types of tracks, which will in turn send data out - * the appropriate ports. */ - timeline->process( nframes ); + /* timeline->unlock(); */ + /* } */ + /* } */ + /* else */ + /* { */ + /* if ( !timeline) */ + /* /\* handle chicken/egg problem *\/ */ + /* return 0; */ + + /* if ( timeline->tryrdlock() ) */ + /* { */ + /* /\* the data structures we need to access here (tracks and */ + /* * their ports, but not track contents) may be in an */ + /* * inconsistent state at the moment. Just punt and drop this */ + /* * buffer. *\/ */ + /* ++_buffers_dropped; */ + /* return 0; */ + /* } */ - timeline->unlock(); - } + /* /\* this will initiate the process() call graph for the various */ + /* * number and types of tracks, which will in turn send data out */ + /* * the appropriate ports. *\/ */ + /* timeline->process( nframes ); */ + + /* timeline->unlock(); */ + /* } */ return 0; } diff --git a/timeline/src/Engine/Playback_DS.C b/timeline/src/Engine/Playback_DS.C index ce05c52..93b1b0f 100644 --- a/timeline/src/Engine/Playback_DS.C +++ b/timeline/src/Engine/Playback_DS.C @@ -84,7 +84,7 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes ) if ( !timeline ) return; - while ( timeline->tryrdlock() ) + while ( timeline->sequence_lock.tryrdlock() ) { if ( _terminate ) return; @@ -100,7 +100,7 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes ) _frame += nframes; } - timeline->unlock(); + timeline->sequence_lock.unlock(); } void diff --git a/timeline/src/Engine/Record_DS.C b/timeline/src/Engine/Record_DS.C index d429f5f..4c55e67 100644 --- a/timeline/src/Engine/Record_DS.C +++ b/timeline/src/Engine/Record_DS.C @@ -60,10 +60,14 @@ Record_DS::write_block ( sample_t *buf, nframes_t nframes ) if ( ! ( timeline && sequence() ) ) return; + if ( ! _capture ) + { + _capture = new Track::Capture; - if ( ! _capture->audio_file ) + /* if ( ! _capture->audio_file ) */ /* create the file */ track()->record( _capture, _frame ); + } track()->write( _capture, buf, nframes ); @@ -79,83 +83,162 @@ Record_DS::disk_thread ( void ) const nframes_t nframes = _nframes; + _disk_io_blocks = 1; + /* 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 ); +// const size_t block_size = nframes * sizeof( sample_t ); - nframes_t blocks_read = 0; + nframes_t frames_read = 0; + bool punching_in = false; + bool punching_out = false; + bool punched_in = false; + + nframes_t bS = 0; + nframes_t bE = 0; + +again: + + _capture = NULL; + + punched_in = false; + punching_out = false; + + nframes_t pS = _frame; + nframes_t pE = _stop_frame; + + if ( punching_in ) + { + /* write remainder of buffer */ + write_block( buf + ((pS - bS) * channels()), + bE - pS ); + + punching_in = false; + punched_in = true; + } + while ( wait_for_block() ) { /* pull data from the per-channel ringbuffers and interlace it */ - for ( int i = channels(); i--; ) + size_t frames_to_read = nframes; + + /* we read the entire block if a partial... */ + for ( int i = 0; i < channels(); i++ ) { - while ( jack_ringbuffer_read_space( _rb[ i ] ) < block_size ) + while ( jack_ringbuffer_read_space( _rb[ i ] ) < frames_to_read * sizeof( sample_t ) ) usleep( 10 * 1000 ); - - jack_ringbuffer_read( _rb[ i ], ((char*)cbuf), block_size ); - buffer_interleave_one_channel( buf + ( blocks_read * nframes * channels() ), + jack_ringbuffer_read( _rb[ i ], ((char*)cbuf), frames_to_read * sizeof( sample_t ) ); + + buffer_interleave_one_channel( buf, cbuf, i, channels(), - nframes ); + frames_to_read); } + + bS = _first_frame + frames_read; - blocks_read++; + frames_read += frames_to_read; - if ( blocks_read == _disk_io_blocks ) + bE = _first_frame + frames_read; + + punching_in = ! punched_in && bE > pS; + punching_out = punched_in && pE < bE; + + if ( punching_out ) { - write_block( buf, nframes * _disk_io_blocks ); - blocks_read = 0; + write_block( buf, + pE - bS ); + + break; + } + else + if ( punching_in ) + { + write_block( buf + ((pS - bS) * channels()), + bE - pS ); + + punching_in = false; + punched_in = true; + } + else if ( punched_in ) + { + write_block( buf, bE - bS ); } } - DMESSAGE( "capture thread terminating" ); +// 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 ); */ + /* } */ + /* } */ + + + + if ( _capture ) { - while ( blocks_read-- > 0 || ( ! sem_trywait( &_blocks ) && errno != EAGAIN ) ) + DMESSAGE( "finalzing capture" ); + Track::Capture *c = _capture; + + _capture = NULL; + + /* now finalize the recording */ + +// if ( c->audio_file ) + track()->finalize( c, _stop_frame ); + + delete c; + } + + if ( ! _terminate ) + { + nframes_t in, out; + + if ( timeline->next_punch( _stop_frame, &in, &out ) ) { - for ( int i = channels(); i--; ) - { - jack_ringbuffer_read( _rb[ i ], (char*)cbuf, block_size ); + _frame = in; + _stop_frame = out; + _frames_written = 0; - buffer_interleave_one_channel( buf, cbuf, i, channels(), nframes ); - } + punched_in = false; + punching_out = false; + + punching_in = bE > in; - const nframes_t frames_remaining = (_stop_frame - _frame ) - _frames_written; + DMESSAGE( "Next punch: %lu:%lu", (unsigned long)in,(unsigned long)out ); - if ( frames_remaining < nframes ) - { - /* this is the last block, might be partial */ - write_block( buf, frames_remaining ); - break; - } - else - write_block( buf, nframes ); + goto again; } } 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; @@ -168,7 +251,7 @@ Record_DS::disk_thread ( void ) /** begin recording */ void -Record_DS::start ( nframes_t frame ) +Record_DS::start ( nframes_t frame, nframes_t start_frame, nframes_t stop_frame ) { THREAD_ASSERT( UI ); @@ -183,9 +266,10 @@ Record_DS::start ( nframes_t frame ) DMESSAGE( "recording started at frame %lu", (unsigned long)frame); - _frame = frame; + _frame = start_frame; + _stop_frame = stop_frame; - _capture = new Track::Capture; + _first_frame = frame; run(); @@ -227,40 +311,36 @@ Record_DS::process ( nframes_t nframes ) if ( ! _recording ) return 0; - if ( transport->frame < _frame ) - 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. */ +/* 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; +/* offset = _frame - transport->frame; */ -/* DMESSAGE( "offset = %lu", (unsigned long)offset ); */ - } +/* /\* 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--; ) + for ( int i = 0; i < channels(); i++ ) { /* read the entire input buffer */ void *buf = track()->input[ i ].buffer( nframes ); - /* FIXME: this results in a ringbuffer size that is no longer - necessarily a multiple of nframes... how will the other side - handle that? */ - if ( engine->freewheeling() ) { - while ( jack_ringbuffer_write_space( _rb[i] ) < block_size ) + while ( transport->recording && jack_ringbuffer_write_space( _rb[i] ) < block_size ) usleep( 10 * 1000 ); jack_ringbuffer_write( _rb[ i ], ((char*)buf) + offset_size, block_size ); @@ -271,12 +351,14 @@ Record_DS::process ( nframes_t nframes ) { memset( buf, 0, block_size ); /* FIXME: we need to resync somehow */ + WARNING( "xrun" ); ++_xruns; } - else - { - jack_ringbuffer_write( _rb[ i ], ((char*)buf) + offset_size, block_size ); - } + + jack_ringbuffer_write( _rb[ i ], ((char*)buf) + offset_size, block_size ); + +// DMESSAGE( "wrote %lu", (unsigned long) nframes ); + } } diff --git a/timeline/src/Engine/Record_DS.H b/timeline/src/Engine/Record_DS.H index 776a7e0..fb6741c 100644 --- a/timeline/src/Engine/Record_DS.H +++ b/timeline/src/Engine/Record_DS.H @@ -36,7 +36,8 @@ class Record_DS : public Disk_Stream nframes_t _frames_written; volatile nframes_t _stop_frame; - + volatile nframes_t _first_frame; + volatile bool _recording; Audio_File_SF *_af; /* capture file */ @@ -56,8 +57,9 @@ public: _capture = NULL; _recording = false; - _stop_frame = -1; + _stop_frame = 0; _frames_written = 0; + _first_frame = 0; } virtual ~Record_DS ( ) { shutdown(); } @@ -67,7 +69,7 @@ public: const Audio_Region * capture_region ( void ) const; Track::Capture * capture ( void ); - void start ( nframes_t frame ); + void start ( nframes_t frame, nframes_t start_frame, nframes_t stop_frame = 0 ); void stop ( nframes_t frame ); nframes_t process ( nframes_t nframes ); diff --git a/timeline/src/Engine/Timeline.C b/timeline/src/Engine/Timeline.C index e6f6537..9bcfa0f 100644 --- a/timeline/src/Engine/Timeline.C +++ b/timeline/src/Engine/Timeline.C @@ -28,6 +28,8 @@ #include "Thread.H" #include "../Cursor_Sequence.H" +#include "Engine.H" + #include /** Initiate recording for all armed tracks */ @@ -48,14 +50,15 @@ Timeline::record ( void ) _created_new_takes = true; } - transport->recording = true; - deactivate(); Loggable::block_start(); nframes_t frame = transport->frame; + nframes_t _punch_out_frame = 0; +// nframes_t _punch_in_frame = 0; + if ( transport->punch_enabled() ) { DMESSAGE( "Finding next punch region following frame %lu...", (unsigned long)frame); @@ -65,7 +68,7 @@ Timeline::record ( void ) if (p || n ) { - if ( p && frame > p->start() && frame < p->start() + p->length() ) + if ( p && frame >= p->start() && frame < p->start() + p->length() ) { /* recording started in the middle of a punch * cursor... Just start recording and punch out at the @@ -86,33 +89,23 @@ Timeline::record ( void ) } } - _punch_in_frame = frame; +// _punch_in_frame = frame; - punch_in( frame ); - - return true; -} - -void -Timeline::punch_in ( nframes_t frame ) -{ - if ( _punched_in ) - { - WARNING( "Programming error. Attempt to punch in twice" ); - return; - } - - DMESSAGE( "Going to record starting at frame %lu", (unsigned long)frame ); for ( int i = tracks->children(); i-- ; ) { Track *t = (Track*)tracks->child( i ); if ( t->armed() && t->record_ds ) - t->record_ds->start( frame ); + { + t->record_ds->start( transport->frame, frame, _punch_out_frame ); + } } - _punched_in = true; + transport->recording = true; + + + return true; } void @@ -142,10 +135,6 @@ Timeline::punch_out ( nframes_t frame ) } DMESSAGE( "All record threads stopped." ); - - _punched_in = false; - _punch_in_frame = 0; - _punch_out_frame = 0; } /** stop recording for all armed tracks. Does not affect transport. */ @@ -156,13 +145,13 @@ Timeline::stop ( void ) nframes_t frame = transport->frame; - if ( transport->punch_enabled() ) - { - const Sequence_Widget *w = punch_cursor_track->prev( frame ); + /* if ( transport->punch_enabled() ) */ + /* { */ + /* const Sequence_Widget *w = punch_cursor_track->prev( frame ); */ - if ( w && w->start() + w->length() < frame ) - frame = w->start() + w->length(); - } + /* if ( w && w->start() + w->length() < frame ) */ + /* frame = w->start() + w->length(); */ + /* } */ punch_out( frame ); @@ -178,20 +167,26 @@ Timeline::stop ( void ) /* Engine */ /**********/ -/** call process() on each track header */ nframes_t -Timeline::process ( nframes_t nframes ) +Timeline::process_input ( nframes_t nframes ) { - /* there is no need to acquire a readlock here because track * - addition/removal locks process() and track process() calls deal with - ringbuffers instead of reading the sequence data directly. */ - for ( int i = tracks->children(); i-- ; ) - { - Track *t = (Track*)tracks->child( i ); + /* if ( engine->freewheeling() ) */ + /* { */ + /* rdlock(); */ + /* } */ + /* else */ + /* { */ + /* if ( tryrdlock() ) */ + /* return 0; */ + /* } */ - t->process_output( nframes ); - } + if ( ! transport->recording ) + return nframes; + + /* we don't lock here in order to avoid deadlocks. we already know + * that only the record diskthread will be altering timeline + * structures during recording since the GUI is disabled. */ for ( int i = tracks->children(); i-- ; ) { @@ -200,10 +195,46 @@ Timeline::process ( nframes_t nframes ) t->process_input( nframes ); } - /* FIXME: BOGUS */ + /* unlock(); */ + return nframes; } +nframes_t +Timeline::process_output ( nframes_t nframes ) +{ + + /* if ( engine->freewheeling() ) */ + /* { */ + /* rdlock(); */ + /* } */ + /* else */ + /* { */ + /* if ( tryrdlock() ) */ + /* return 0; */ + /* } */ + + bool r = transport->recording || engine->freewheeling(); + + if ( ! r ) + if ( track_lock.tryrdlock() ) + return 0; +// rdlock(); + + for ( int i = tracks->children(); i-- ; ) + { + Track *t = (Track*)tracks->child( i ); + + t->process_output( nframes ); + } + + if ( ! r ) + track_lock.unlock(); + + return nframes; + +} + void Timeline::seek ( nframes_t frame ) { diff --git a/timeline/src/Engine/Track.C b/timeline/src/Engine/Track.C index f6352ef..4bfdb5f 100644 --- a/timeline/src/Engine/Track.C +++ b/timeline/src/Engine/Track.C @@ -261,13 +261,15 @@ Track::resize_buffers ( nframes_t nframes ) #include +static unsigned long uuid_counter = 0; + /** very cheap UUID generator... */ unsigned long long uuid ( void ) { time_t t = time( NULL ); - return (unsigned long long) t; + return (unsigned long long) t + uuid_counter++; } /** create capture region and prepare to record */ @@ -294,11 +296,12 @@ Track::record ( Capture *c, nframes_t frame ) /* must acquire a write lock because the Audio_Region constructor * will add the region to the specified sequence, which might affect playback */ - timeline->wrlock(); + + timeline->sequence_lock.wrlock(); c->region = new Audio_Region( c->audio_file, sequence(), frame ); - timeline->unlock(); + timeline->sequence_lock.unlock(); // Fl::unlock(); @@ -313,6 +316,10 @@ Track::record ( Capture *c, nframes_t frame ) /* in freewheeling mode, assume we're bouncing and only * compensate for capture latency */ _capture_offset = max; + + /* FIXME: hack to compensate for jack 1 period delay when looped back */ +// _capture_offset += engine->playback_latency() / 2; + _capture_offset += engine->nframes(); } else { @@ -353,17 +360,18 @@ Track::finalize ( Capture *c, nframes_t frame ) DMESSAGE( "finalizing audio file" ); c->audio_file->finalize(); - timeline->wrlock(); - DMESSAGE( "Adjusting capture by %lu frames.", (unsigned long)_capture_offset ); + timeline->sequence_lock.wrlock(); + c->region->offset( _capture_offset ); + + timeline->sequence_lock.unlock(); + _capture_offset = 0; /* have to do this last, as it logs the create */ c->region->finalize( frame ); - - timeline->unlock(); } void diff --git a/timeline/src/Sequence.C b/timeline/src/Sequence.C index df1850d..7d8ed2c 100644 --- a/timeline/src/Sequence.C +++ b/timeline/src/Sequence.C @@ -327,7 +327,7 @@ Sequence::handle ( int m ) case FL_SHORTCUT: if ( Fl::test_shortcut( FL_CTRL + FL_Right ) ) { - const Sequence_Widget *w = next( transport->frame ); + const Sequence_Widget *w = next( transport->frame + 1 ); if ( w ) transport->locate( w->start() ); @@ -399,9 +399,9 @@ Sequence::handle ( int m ) { /* accept objects dragged from other sequences of this type */ - timeline->wrlock(); + timeline->sequence_lock.wrlock(); add( Sequence_Widget::pushed() ); - timeline->unlock(); + timeline->sequence_lock.unlock(); damage( FL_DAMAGE_USER1 ); @@ -503,9 +503,9 @@ Sequence::handle ( int m ) Sequence_Widget::belowmouse( NULL ); } - timeline->wrlock(); + timeline->sequence_lock.wrlock(); delete t; - timeline->unlock(); + timeline->sequence_lock.unlock(); } Loggable::block_end(); @@ -557,8 +557,8 @@ const Sequence_Widget * Sequence::next ( nframes_t from ) const { for ( list ::const_iterator i = _widgets.begin(); i != _widgets.end(); i++ ) -// if ( (*i)->start() >= from ) - if ( (*i)->start() > from ) + if ( (*i)->start() >= from ) +// if ( (*i)->start() > from ) return *i; if ( _widgets.size() ) diff --git a/timeline/src/Sequence_Widget.C b/timeline/src/Sequence_Widget.C index 70ba673..350c49c 100644 --- a/timeline/src/Sequence_Widget.C +++ b/timeline/src/Sequence_Widget.C @@ -172,7 +172,7 @@ Sequence_Widget::begin_drag ( const Drag &d ) { _drag = new Drag( d ); - timeline->wrlock(); + timeline->sequence_lock.wrlock(); /* copy current values */ @@ -181,7 +181,7 @@ Sequence_Widget::begin_drag ( const Drag &d ) /* tell display to use temporary */ _r = &_dragging_range; - timeline->unlock(); + timeline->sequence_lock.unlock(); } void @@ -190,7 +190,7 @@ Sequence_Widget::end_drag ( void ) /* swap in the new value */ /* go back to playback and display using same values */ - timeline->wrlock(); + timeline->sequence_lock.wrlock(); _range = _dragging_range; _r = &_range; @@ -201,7 +201,7 @@ Sequence_Widget::end_drag ( void ) /* this will result in a sort */ sequence()->handle_widget_change( _r->start, _r->length ); - timeline->unlock(); + timeline->sequence_lock.unlock(); } /** set position of widget on the timeline. */ @@ -449,9 +449,9 @@ Sequence_Widget::handle ( int m ) if ( test_press( FL_BUTTON1 + FL_CTRL ) && ! _drag->state ) { /* duplication */ - timeline->wrlock(); + timeline->sequence_lock.wrlock(); sequence()->add( this->clone() ); - timeline->unlock(); + timeline->sequence_lock.unlock(); _drag->state = 1; return 1; diff --git a/timeline/src/Tempo_Sequence.C b/timeline/src/Tempo_Sequence.C index c07f91b..50c16b3 100644 --- a/timeline/src/Tempo_Sequence.C +++ b/timeline/src/Tempo_Sequence.C @@ -62,11 +62,11 @@ Tempo_Sequence::handle ( int m ) if ( Tempo_Point::edit( &t ) ) { - timeline->wrlock(); + timeline->sequence_lock.wrlock(); new Tempo_Point( timeline->x_to_offset( Fl::event_x() ), t ); - timeline->unlock(); + timeline->sequence_lock.unlock(); timeline->redraw(); } diff --git a/timeline/src/Time_Sequence.C b/timeline/src/Time_Sequence.C index 972bfd9..f877b8a 100644 --- a/timeline/src/Time_Sequence.C +++ b/timeline/src/Time_Sequence.C @@ -65,11 +65,11 @@ Time_Sequence::handle ( int m ) if ( Time_Point::edit( &t ) ) { - timeline->wrlock(); + timeline->sequence_lock.wrlock(); new Time_Point( timeline->x_to_offset( Fl::event_x() ), t.beats_per_bar, t.beat_type ); - timeline->unlock(); + timeline->sequence_lock.unlock(); timeline->redraw(); } diff --git a/timeline/src/Timeline.C b/timeline/src/Timeline.C index c280ecd..42100ce 100644 --- a/timeline/src/Timeline.C +++ b/timeline/src/Timeline.C @@ -360,7 +360,7 @@ Timeline::add_take_for_armed_tracks ( void ) { THREAD_ASSERT( UI ); - wrlock(); + track_lock.wrlock(); for ( int i = tracks->children(); i-- ; ) { @@ -370,7 +370,7 @@ Timeline::add_take_for_armed_tracks ( void ) t->sequence( new Audio_Sequence( t ) ); } - unlock(); + track_lock.unlock(); } void @@ -598,9 +598,6 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : BASE( X, Y, W play_cursor_track = NULL; _created_new_takes = 0; - _punched_in = 0; - _punch_in_frame = 0; - _punch_out_frame = 0; osc_thread = 0; _sample_rate = 44100; @@ -1271,6 +1268,8 @@ Timeline::draw ( void ) * another thread must use Fl::lock()/unlock()! */ THREAD_ASSERT( UI ); +// rdlock(); + int X, Y, W, H; int bdx = 0; @@ -1368,6 +1367,8 @@ Timeline::draw ( void ) done: +// unlock(); + /* panzoomer->redraw(); */ // update_child( *panzoomer ); @@ -1416,6 +1417,26 @@ Timeline::draw_cursor ( nframes_t frame, Fl_Color color, void (*symbol)(Fl_Color fl_pop_clip(); } +/** set /in/ and /out/ to start and end of next punch region from /frame/ */ +bool +Timeline::next_punch ( nframes_t frame, nframes_t *in, nframes_t *out ) const +{ + if ( !transport->punch_enabled() ) + return false; + + const Sequence_Widget *w = punch_cursor_track->next( frame ); + + if ( w && w->start() >= frame ) + { + *in = w->start(); + *out = w->start() + w->length(); + + return true; + } + + return false; +} + void Timeline::draw_playhead ( void ) { @@ -1429,36 +1450,6 @@ Timeline::redraw_playhead ( void ) // static nframes_t last_playhead = -1; static int last_playhead_x = -1; - /* FIXME: kind of a hackish way to invoke punch / looping stuff from the UI thread... */ - - if ( transport->rolling && - transport->rec_enabled() && - transport->punch_enabled() ) - { - if ( _punched_in && - transport->frame > _punch_in_frame && - transport->frame > _punch_out_frame ) - { - punch_out( _punch_out_frame ); - } - else if ( ! _punched_in ) - { - /* we've passed one or more punch regions... punch in for the next, if available. */ - const Sequence_Widget *w = punch_cursor_track->next( transport->frame ); - - DMESSAGE( "Delayed punch in" ); - if ( w && - w->start() > transport->frame ) - { - _punch_in_frame = w->start(); - _punch_out_frame = w->start() + w->length(); - - punch_in( w->start() ); - } - } - } - - if ( transport->rolling ) { if ( play_cursor_track->active_cursor() ) @@ -1987,36 +1978,36 @@ Timeline::remove_track ( Track *track ) void Timeline::command_move_track_up ( Track *track ) { - wrlock(); + track_lock.wrlock(); insert_track( track, find_track( track ) - 1 ); - unlock(); + track_lock.unlock(); } void Timeline::command_move_track_down ( Track *track ) { - wrlock(); + track_lock.wrlock(); insert_track( track, find_track( track ) + 2 ); - unlock(); + track_lock.unlock(); } void Timeline::command_remove_track ( Track *track ) { - wrlock(); + track_lock.wrlock(); remove_track(track); - unlock(); + track_lock.unlock(); } void Timeline::command_quit ( void ) { - timeline->wrlock(); + track_lock.wrlock(); Project::close(); - timeline->unlock(); - + track_lock.unlock(); + command_save(); while ( Fl::first_window() ) Fl::first_window()->hide(); @@ -2025,9 +2016,10 @@ Timeline::command_quit ( void ) void Timeline::command_undo ( void ) { - wrlock(); + /* FIXME: sequence lock too? */ + track_lock.wrlock(); Project::undo(); - unlock(); + track_lock.unlock(); } bool @@ -2036,9 +2028,9 @@ Timeline::command_load ( const char *name, const char *display_name ) if ( ! name ) return false; - wrlock(); + track_lock.wrlock(); int r = Project::open( name ); - unlock(); + track_lock.unlock(); if ( r < 0 ) { diff --git a/timeline/src/Timeline.H b/timeline/src/Timeline.H index d3da3c8..022c3af 100644 --- a/timeline/src/Timeline.H +++ b/timeline/src/Timeline.H @@ -77,9 +77,8 @@ struct Rectangle Rectangle ( int X, int Y, int W, int H ) : x( X ), y( Y ), w( W ), h( H ) {} }; -class Timeline : public Fl_Group, public RWLock +class Timeline : public Fl_Group { - class Timeline_Panzoomer; static void draw_clip_rulers ( void * v, int X, int Y, int W, int H ); @@ -125,6 +124,9 @@ class Timeline : public Fl_Group, public RWLock public: + RWLock track_lock; /* tracks/sequences */ + RWLock sequence_lock; /* sequence contents */ + void redraw_overlay ( void ); void insert_track ( Track *track, Track *before ); @@ -166,9 +168,6 @@ public: Fl_Menu_Button *menu; - int _punched_in; - nframes_t _punch_out_frame; - nframes_t _punch_in_frame; bool _created_new_takes; nframes_t xoffset; @@ -257,6 +256,7 @@ public: void zoom_out ( void ); void zoom_fit ( void ); + bool next_punch ( nframes_t frame, nframes_t *in, nframes_t *out ) const; /* Engine */ int total_input_buffer_percent ( void ); @@ -267,7 +267,6 @@ public: bool record ( void ); void stop ( void ); - void punch_in ( nframes_t frame ); void punch_out ( nframes_t frame ); void wait_for_buffers ( void ); @@ -315,6 +314,7 @@ private: /* Engine */ void resize_buffers ( nframes_t nframes ); - nframes_t process ( nframes_t nframes ); + nframes_t process_input ( nframes_t nframes ); + nframes_t process_output ( nframes_t nframes ); void seek ( nframes_t frame ); }; diff --git a/timeline/src/Track.C b/timeline/src/Track.C index bad2943..b416407 100644 --- a/timeline/src/Track.C +++ b/timeline/src/Track.C @@ -737,10 +737,10 @@ void Track::command_configure_channels ( int n ) { /* due to locking this should only be invoked by direct user action */ - timeline->wrlock(); + timeline->track_lock.wrlock(); configure_inputs( n ); configure_outputs( n ); - timeline->unlock(); + timeline->track_lock.unlock(); } void @@ -787,9 +787,9 @@ Track::menu_cb ( const Fl_Menu_ *m ) /* add audio track */ char *name = get_unique_control_name( "Control" ); - timeline->wrlock(); + timeline->track_lock.wrlock(); new Control_Sequence( this, name ); - timeline->unlock(); + timeline->track_lock.unlock(); } else if ( ! strcmp( picked, "/Overlay controls" ) ) { @@ -868,9 +868,9 @@ Track::menu_cb ( const Fl_Menu_ *m ) } else if ( !strcmp( picked, "Takes/New" ) ) { - timeline->wrlock(); + timeline->track_lock.wrlock(); sequence( (Audio_Sequence*)sequence()->clone_empty() ); - timeline->unlock(); + timeline->track_lock.unlock(); } else if ( !strcmp( picked, "Takes/Remove" ) ) { @@ -878,7 +878,7 @@ Track::menu_cb ( const Fl_Menu_ *m ) { Loggable::block_start(); - timeline->wrlock(); + timeline->track_lock.wrlock(); Audio_Sequence *s = sequence(); @@ -886,7 +886,7 @@ Track::menu_cb ( const Fl_Menu_ *m ) delete s; - timeline->unlock(); + timeline->track_lock.unlock(); Loggable::block_end(); } @@ -906,9 +906,9 @@ Track::menu_cb ( const Fl_Menu_ *m ) { Audio_Sequence* s = (Audio_Sequence*)m->mvalue()->user_data(); - timeline->wrlock(); + timeline->track_lock.wrlock(); sequence( s ); - timeline->unlock(); + timeline->track_lock.unlock(); } } diff --git a/timeline/src/Waveform.C b/timeline/src/Waveform.C index a5a7fb9..a6bb8b9 100644 --- a/timeline/src/Waveform.C +++ b/timeline/src/Waveform.C @@ -27,6 +27,7 @@ #include using std::min; using std::max; +#include