Timeline: Move punch logic to record diskthread. Punches are now sample accurate and work better in freewheeling mode.
This commit is contained in:
parent
6f3e96f311
commit
55bbce6d24
|
@ -127,6 +127,6 @@ Thread::join ( void )
|
||||||
void
|
void
|
||||||
Thread::exit ( void *retval )
|
Thread::exit ( void *retval )
|
||||||
{
|
{
|
||||||
pthread_exit( retval );
|
|
||||||
_thread = 0;
|
_thread = 0;
|
||||||
|
pthread_exit( retval );
|
||||||
}
|
}
|
||||||
|
|
|
@ -651,7 +651,7 @@ Audio_Region::draw ( void )
|
||||||
|
|
||||||
if ( peaks < loop_peaks_needed )
|
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;
|
fo += loop_frames_needed;
|
||||||
|
|
|
@ -783,11 +783,11 @@ Control_Sequence::handle ( int m )
|
||||||
test_press( FL_BUTTON1 ) )
|
test_press( FL_BUTTON1 ) )
|
||||||
{
|
{
|
||||||
/* insert new control point */
|
/* 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() );
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,8 +340,12 @@ Audio_Region::write ( nframes_t nframes )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timeline->sequence_lock.wrlock();
|
||||||
|
|
||||||
_range.length += nframes;
|
_range.length += nframes;
|
||||||
|
|
||||||
|
timeline->sequence_lock.unlock();
|
||||||
|
|
||||||
return nframes;
|
return nframes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,8 +358,12 @@ Audio_Region::finalize ( nframes_t frame )
|
||||||
|
|
||||||
DMESSAGE( "finalizing capture region" );
|
DMESSAGE( "finalizing capture region" );
|
||||||
|
|
||||||
|
timeline->sequence_lock.wrlock();
|
||||||
|
|
||||||
_range.length = frame - _range.start;
|
_range.length = frame - _range.start;
|
||||||
|
|
||||||
|
timeline->sequence_lock.unlock();
|
||||||
|
|
||||||
_clip->close();
|
_clip->close();
|
||||||
_clip->open();
|
_clip->open();
|
||||||
|
|
||||||
|
|
|
@ -172,40 +172,55 @@ Engine::process ( nframes_t nframes )
|
||||||
|
|
||||||
transport->poll();
|
transport->poll();
|
||||||
|
|
||||||
if ( freewheeling() )
|
|
||||||
{
|
|
||||||
if ( timeline )
|
|
||||||
{
|
|
||||||
timeline->rdlock();
|
|
||||||
|
|
||||||
timeline->process( nframes );
|
|
||||||
|
|
||||||
timeline->unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( !timeline)
|
if ( !timeline)
|
||||||
/* handle chicken/egg problem */
|
/* handle chicken/egg problem */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ( timeline->tryrdlock() )
|
nframes_t n = 0;
|
||||||
|
|
||||||
|
n += timeline->process_input(nframes);
|
||||||
|
n += timeline->process_output(nframes);
|
||||||
|
|
||||||
|
if ( n != nframes * 2 )
|
||||||
{
|
{
|
||||||
/* the data structures we need to access here (tracks and
|
_buffers_dropped++;
|
||||||
* their ports, but not track contents) may be in an
|
WARNING("xrun");
|
||||||
* inconsistent state at the moment. Just punt and drop this
|
|
||||||
* buffer. */
|
|
||||||
++_buffers_dropped;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this will initiate the process() call graph for the various
|
/* if ( freewheeling() ) */
|
||||||
* number and types of tracks, which will in turn send data out
|
/* { */
|
||||||
* the appropriate ports. */
|
/* if ( timeline ) */
|
||||||
timeline->process( nframes );
|
/* { */
|
||||||
|
/* timeline->rdlock(); */
|
||||||
|
|
||||||
timeline->unlock();
|
/* 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; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* /\* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes )
|
||||||
if ( !timeline )
|
if ( !timeline )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while ( timeline->tryrdlock() )
|
while ( timeline->sequence_lock.tryrdlock() )
|
||||||
{
|
{
|
||||||
if ( _terminate )
|
if ( _terminate )
|
||||||
return;
|
return;
|
||||||
|
@ -100,7 +100,7 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes )
|
||||||
_frame += nframes;
|
_frame += nframes;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeline->unlock();
|
timeline->sequence_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -60,10 +60,14 @@ Record_DS::write_block ( sample_t *buf, nframes_t nframes )
|
||||||
if ( ! ( timeline && sequence() ) )
|
if ( ! ( timeline && sequence() ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if ( ! _capture )
|
||||||
|
{
|
||||||
|
_capture = new Track::Capture;
|
||||||
|
|
||||||
if ( ! _capture->audio_file )
|
/* if ( ! _capture->audio_file ) */
|
||||||
/* create the file */
|
/* create the file */
|
||||||
track()->record( _capture, _frame );
|
track()->record( _capture, _frame );
|
||||||
|
}
|
||||||
|
|
||||||
track()->write( _capture, buf, nframes );
|
track()->write( _capture, buf, nframes );
|
||||||
|
|
||||||
|
@ -79,82 +83,161 @@ Record_DS::disk_thread ( void )
|
||||||
|
|
||||||
const nframes_t nframes = _nframes;
|
const nframes_t nframes = _nframes;
|
||||||
|
|
||||||
|
_disk_io_blocks = 1;
|
||||||
|
|
||||||
/* buffer to hold the interleaved data returned by the track reader */
|
/* buffer to hold the interleaved data returned by the track reader */
|
||||||
sample_t *buf = buffer_alloc( nframes * channels() * _disk_io_blocks );
|
sample_t *buf = buffer_alloc( nframes * channels() * _disk_io_blocks );
|
||||||
sample_t *cbuf = buffer_alloc( nframes );
|
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() )
|
while ( wait_for_block() )
|
||||||
{
|
{
|
||||||
/* pull data from the per-channel ringbuffers and interlace it */
|
/* 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 );
|
usleep( 10 * 1000 );
|
||||||
|
|
||||||
jack_ringbuffer_read( _rb[ i ], ((char*)cbuf), block_size );
|
jack_ringbuffer_read( _rb[ i ], ((char*)cbuf), frames_to_read * sizeof( sample_t ) );
|
||||||
|
|
||||||
buffer_interleave_one_channel( buf + ( blocks_read * nframes * channels() ),
|
buffer_interleave_one_channel( buf,
|
||||||
cbuf,
|
cbuf,
|
||||||
i,
|
i,
|
||||||
channels(),
|
channels(),
|
||||||
nframes );
|
frames_to_read);
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks_read++;
|
bS = _first_frame + frames_read;
|
||||||
|
|
||||||
if ( blocks_read == _disk_io_blocks )
|
frames_read += frames_to_read;
|
||||||
|
|
||||||
|
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 );
|
write_block( buf,
|
||||||
blocks_read = 0;
|
pE - bS );
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
write_block( buf, nframes );
|
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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
// DMESSAGE( "capture thread terminating" );
|
||||||
free(cbuf);
|
|
||||||
|
|
||||||
|
/* 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 )
|
||||||
|
{
|
||||||
DMESSAGE( "finalzing capture" );
|
DMESSAGE( "finalzing capture" );
|
||||||
|
|
||||||
Track::Capture *c = _capture;
|
Track::Capture *c = _capture;
|
||||||
|
|
||||||
_capture = NULL;
|
_capture = NULL;
|
||||||
|
|
||||||
/* now finalize the recording */
|
/* now finalize the recording */
|
||||||
|
|
||||||
if ( c->audio_file )
|
// if ( c->audio_file )
|
||||||
track()->finalize( c, _stop_frame );
|
track()->finalize( c, _stop_frame );
|
||||||
|
|
||||||
delete c;
|
delete c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! _terminate )
|
||||||
|
{
|
||||||
|
nframes_t in, out;
|
||||||
|
|
||||||
|
if ( timeline->next_punch( _stop_frame, &in, &out ) )
|
||||||
|
{
|
||||||
|
_frame = in;
|
||||||
|
_stop_frame = out;
|
||||||
|
_frames_written = 0;
|
||||||
|
|
||||||
|
punched_in = false;
|
||||||
|
punching_out = false;
|
||||||
|
|
||||||
|
punching_in = bE > in;
|
||||||
|
|
||||||
|
DMESSAGE( "Next punch: %lu:%lu", (unsigned long)in,(unsigned long)out );
|
||||||
|
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
free(cbuf);
|
||||||
|
|
||||||
flush();
|
flush();
|
||||||
|
|
||||||
|
@ -168,7 +251,7 @@ Record_DS::disk_thread ( void )
|
||||||
|
|
||||||
/** begin recording */
|
/** begin recording */
|
||||||
void
|
void
|
||||||
Record_DS::start ( nframes_t frame )
|
Record_DS::start ( nframes_t frame, nframes_t start_frame, nframes_t stop_frame )
|
||||||
{
|
{
|
||||||
THREAD_ASSERT( UI );
|
THREAD_ASSERT( UI );
|
||||||
|
|
||||||
|
@ -183,9 +266,10 @@ Record_DS::start ( nframes_t frame )
|
||||||
|
|
||||||
DMESSAGE( "recording started at frame %lu", (unsigned long)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();
|
run();
|
||||||
|
|
||||||
|
@ -227,40 +311,36 @@ Record_DS::process ( nframes_t nframes )
|
||||||
if ( ! _recording )
|
if ( ! _recording )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ( transport->frame < _frame )
|
/* if ( transport->frame < _frame ) */
|
||||||
return 0;
|
/* return 0; */
|
||||||
|
|
||||||
/* DMESSAGE( "recording actually happening at %lu (start frame %lu)", (unsigned long)transport->frame, (unsigned long)_frame); */
|
/* DMESSAGE( "recording actually happening at %lu (start frame %lu)", (unsigned long)transport->frame, (unsigned long)_frame); */
|
||||||
|
|
||||||
nframes_t offset = 0;
|
nframes_t offset = 0;
|
||||||
|
|
||||||
if ( _frame > transport->frame &&
|
/* if ( _frame > transport->frame && */
|
||||||
_frame < transport->frame + nframes )
|
/* _frame < transport->frame + nframes ) */
|
||||||
{
|
/* { */
|
||||||
/* The record start frame falls somewhere within the current
|
/* /\* The record start frame falls somewhere within the current */
|
||||||
buffer. We must discard the unneeded portion and only
|
/* buffer. We must discard the unneeded portion and only */
|
||||||
stuff the part requested into the ringbuffer. */
|
/* 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 offset_size = offset * sizeof( sample_t );
|
||||||
const size_t block_size = ( nframes * sizeof( sample_t ) ) - offset_size;
|
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 */
|
/* read the entire input buffer */
|
||||||
void *buf = track()->input[ i ].buffer( nframes );
|
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() )
|
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 );
|
usleep( 10 * 1000 );
|
||||||
|
|
||||||
jack_ringbuffer_write( _rb[ i ], ((char*)buf) + offset_size, block_size );
|
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 );
|
memset( buf, 0, block_size );
|
||||||
/* FIXME: we need to resync somehow */
|
/* FIXME: we need to resync somehow */
|
||||||
|
WARNING( "xrun" );
|
||||||
++_xruns;
|
++_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 );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ class Record_DS : public Disk_Stream
|
||||||
|
|
||||||
nframes_t _frames_written;
|
nframes_t _frames_written;
|
||||||
volatile nframes_t _stop_frame;
|
volatile nframes_t _stop_frame;
|
||||||
|
volatile nframes_t _first_frame;
|
||||||
|
|
||||||
volatile bool _recording;
|
volatile bool _recording;
|
||||||
|
|
||||||
|
@ -56,8 +57,9 @@ public:
|
||||||
|
|
||||||
_capture = NULL;
|
_capture = NULL;
|
||||||
_recording = false;
|
_recording = false;
|
||||||
_stop_frame = -1;
|
_stop_frame = 0;
|
||||||
_frames_written = 0;
|
_frames_written = 0;
|
||||||
|
_first_frame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Record_DS ( ) { shutdown(); }
|
virtual ~Record_DS ( ) { shutdown(); }
|
||||||
|
@ -67,7 +69,7 @@ public:
|
||||||
const Audio_Region * capture_region ( void ) const;
|
const Audio_Region * capture_region ( void ) const;
|
||||||
Track::Capture * capture ( void );
|
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 );
|
void stop ( nframes_t frame );
|
||||||
nframes_t process ( nframes_t nframes );
|
nframes_t process ( nframes_t nframes );
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
#include "Thread.H"
|
#include "Thread.H"
|
||||||
#include "../Cursor_Sequence.H"
|
#include "../Cursor_Sequence.H"
|
||||||
|
|
||||||
|
#include "Engine.H"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/** Initiate recording for all armed tracks */
|
/** Initiate recording for all armed tracks */
|
||||||
|
@ -48,14 +50,15 @@ Timeline::record ( void )
|
||||||
_created_new_takes = true;
|
_created_new_takes = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
transport->recording = true;
|
|
||||||
|
|
||||||
deactivate();
|
deactivate();
|
||||||
|
|
||||||
Loggable::block_start();
|
Loggable::block_start();
|
||||||
|
|
||||||
nframes_t frame = transport->frame;
|
nframes_t frame = transport->frame;
|
||||||
|
|
||||||
|
nframes_t _punch_out_frame = 0;
|
||||||
|
// nframes_t _punch_in_frame = 0;
|
||||||
|
|
||||||
if ( transport->punch_enabled() )
|
if ( transport->punch_enabled() )
|
||||||
{
|
{
|
||||||
DMESSAGE( "Finding next punch region following frame %lu...", (unsigned long)frame);
|
DMESSAGE( "Finding next punch region following frame %lu...", (unsigned long)frame);
|
||||||
|
@ -65,7 +68,7 @@ Timeline::record ( void )
|
||||||
|
|
||||||
if (p || n )
|
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
|
/* recording started in the middle of a punch
|
||||||
* cursor... Just start recording and punch out at the
|
* 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-- ; )
|
for ( int i = tracks->children(); i-- ; )
|
||||||
{
|
{
|
||||||
Track *t = (Track*)tracks->child( i );
|
Track *t = (Track*)tracks->child( i );
|
||||||
|
|
||||||
if ( t->armed() && t->record_ds )
|
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
|
void
|
||||||
|
@ -142,10 +135,6 @@ Timeline::punch_out ( nframes_t frame )
|
||||||
}
|
}
|
||||||
|
|
||||||
DMESSAGE( "All record threads stopped." );
|
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. */
|
/** stop recording for all armed tracks. Does not affect transport. */
|
||||||
|
@ -156,13 +145,13 @@ Timeline::stop ( void )
|
||||||
|
|
||||||
nframes_t frame = transport->frame;
|
nframes_t frame = transport->frame;
|
||||||
|
|
||||||
if ( transport->punch_enabled() )
|
/* if ( transport->punch_enabled() ) */
|
||||||
{
|
/* { */
|
||||||
const Sequence_Widget *w = punch_cursor_track->prev( frame );
|
/* const Sequence_Widget *w = punch_cursor_track->prev( frame ); */
|
||||||
|
|
||||||
if ( w && w->start() + w->length() < frame )
|
/* if ( w && w->start() + w->length() < frame ) */
|
||||||
frame = w->start() + w->length();
|
/* frame = w->start() + w->length(); */
|
||||||
}
|
/* } */
|
||||||
|
|
||||||
punch_out( frame );
|
punch_out( frame );
|
||||||
|
|
||||||
|
@ -178,20 +167,26 @@ Timeline::stop ( void )
|
||||||
/* Engine */
|
/* Engine */
|
||||||
/**********/
|
/**********/
|
||||||
|
|
||||||
/** call process() on each track header */
|
|
||||||
nframes_t
|
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-- ; )
|
/* if ( engine->freewheeling() ) */
|
||||||
{
|
/* { */
|
||||||
Track *t = (Track*)tracks->child( i );
|
/* 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-- ; )
|
for ( int i = tracks->children(); i-- ; )
|
||||||
{
|
{
|
||||||
|
@ -200,10 +195,46 @@ Timeline::process ( nframes_t nframes )
|
||||||
t->process_input( nframes );
|
t->process_input( nframes );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: BOGUS */
|
/* unlock(); */
|
||||||
|
|
||||||
return nframes;
|
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
|
void
|
||||||
Timeline::seek ( nframes_t frame )
|
Timeline::seek ( nframes_t frame )
|
||||||
{
|
{
|
||||||
|
|
|
@ -261,13 +261,15 @@ Track::resize_buffers ( nframes_t nframes )
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
static unsigned long uuid_counter = 0;
|
||||||
|
|
||||||
/** very cheap UUID generator... */
|
/** very cheap UUID generator... */
|
||||||
unsigned long long
|
unsigned long long
|
||||||
uuid ( void )
|
uuid ( void )
|
||||||
{
|
{
|
||||||
time_t t = time( NULL );
|
time_t t = time( NULL );
|
||||||
|
|
||||||
return (unsigned long long) t;
|
return (unsigned long long) t + uuid_counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** create capture region and prepare to record */
|
/** 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
|
/* must acquire a write lock because the Audio_Region constructor
|
||||||
* will add the region to the specified sequence, which might affect playback */
|
* 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 );
|
c->region = new Audio_Region( c->audio_file, sequence(), frame );
|
||||||
|
|
||||||
timeline->unlock();
|
timeline->sequence_lock.unlock();
|
||||||
|
|
||||||
// Fl::unlock();
|
// Fl::unlock();
|
||||||
|
|
||||||
|
@ -313,6 +316,10 @@ Track::record ( Capture *c, nframes_t frame )
|
||||||
/* in freewheeling mode, assume we're bouncing and only
|
/* in freewheeling mode, assume we're bouncing and only
|
||||||
* compensate for capture latency */
|
* compensate for capture latency */
|
||||||
_capture_offset = max;
|
_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
|
else
|
||||||
{
|
{
|
||||||
|
@ -353,17 +360,18 @@ Track::finalize ( Capture *c, nframes_t frame )
|
||||||
DMESSAGE( "finalizing audio file" );
|
DMESSAGE( "finalizing audio file" );
|
||||||
c->audio_file->finalize();
|
c->audio_file->finalize();
|
||||||
|
|
||||||
timeline->wrlock();
|
|
||||||
|
|
||||||
DMESSAGE( "Adjusting capture by %lu frames.", (unsigned long)_capture_offset );
|
DMESSAGE( "Adjusting capture by %lu frames.", (unsigned long)_capture_offset );
|
||||||
|
|
||||||
|
timeline->sequence_lock.wrlock();
|
||||||
|
|
||||||
c->region->offset( _capture_offset );
|
c->region->offset( _capture_offset );
|
||||||
|
|
||||||
|
timeline->sequence_lock.unlock();
|
||||||
|
|
||||||
_capture_offset = 0;
|
_capture_offset = 0;
|
||||||
|
|
||||||
/* have to do this last, as it logs the create */
|
/* have to do this last, as it logs the create */
|
||||||
c->region->finalize( frame );
|
c->region->finalize( frame );
|
||||||
|
|
||||||
timeline->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -327,7 +327,7 @@ Sequence::handle ( int m )
|
||||||
case FL_SHORTCUT:
|
case FL_SHORTCUT:
|
||||||
if ( Fl::test_shortcut( FL_CTRL + FL_Right ) )
|
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 )
|
if ( w )
|
||||||
transport->locate( w->start() );
|
transport->locate( w->start() );
|
||||||
|
@ -399,9 +399,9 @@ Sequence::handle ( int m )
|
||||||
{
|
{
|
||||||
/* accept objects dragged from other sequences of this type */
|
/* accept objects dragged from other sequences of this type */
|
||||||
|
|
||||||
timeline->wrlock();
|
timeline->sequence_lock.wrlock();
|
||||||
add( Sequence_Widget::pushed() );
|
add( Sequence_Widget::pushed() );
|
||||||
timeline->unlock();
|
timeline->sequence_lock.unlock();
|
||||||
|
|
||||||
damage( FL_DAMAGE_USER1 );
|
damage( FL_DAMAGE_USER1 );
|
||||||
|
|
||||||
|
@ -503,9 +503,9 @@ Sequence::handle ( int m )
|
||||||
Sequence_Widget::belowmouse( NULL );
|
Sequence_Widget::belowmouse( NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
timeline->wrlock();
|
timeline->sequence_lock.wrlock();
|
||||||
delete t;
|
delete t;
|
||||||
timeline->unlock();
|
timeline->sequence_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
Loggable::block_end();
|
Loggable::block_end();
|
||||||
|
@ -557,8 +557,8 @@ const Sequence_Widget *
|
||||||
Sequence::next ( nframes_t from ) const
|
Sequence::next ( nframes_t from ) const
|
||||||
{
|
{
|
||||||
for ( list <Sequence_Widget*>::const_iterator i = _widgets.begin(); i != _widgets.end(); i++ )
|
for ( list <Sequence_Widget*>::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;
|
return *i;
|
||||||
|
|
||||||
if ( _widgets.size() )
|
if ( _widgets.size() )
|
||||||
|
|
|
@ -172,7 +172,7 @@ Sequence_Widget::begin_drag ( const Drag &d )
|
||||||
{
|
{
|
||||||
_drag = new Drag( d );
|
_drag = new Drag( d );
|
||||||
|
|
||||||
timeline->wrlock();
|
timeline->sequence_lock.wrlock();
|
||||||
|
|
||||||
/* copy current values */
|
/* copy current values */
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ Sequence_Widget::begin_drag ( const Drag &d )
|
||||||
/* tell display to use temporary */
|
/* tell display to use temporary */
|
||||||
_r = &_dragging_range;
|
_r = &_dragging_range;
|
||||||
|
|
||||||
timeline->unlock();
|
timeline->sequence_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -190,7 +190,7 @@ Sequence_Widget::end_drag ( void )
|
||||||
/* swap in the new value */
|
/* swap in the new value */
|
||||||
/* go back to playback and display using same values */
|
/* go back to playback and display using same values */
|
||||||
|
|
||||||
timeline->wrlock();
|
timeline->sequence_lock.wrlock();
|
||||||
|
|
||||||
_range = _dragging_range;
|
_range = _dragging_range;
|
||||||
_r = &_range;
|
_r = &_range;
|
||||||
|
@ -201,7 +201,7 @@ Sequence_Widget::end_drag ( void )
|
||||||
/* this will result in a sort */
|
/* this will result in a sort */
|
||||||
sequence()->handle_widget_change( _r->start, _r->length );
|
sequence()->handle_widget_change( _r->start, _r->length );
|
||||||
|
|
||||||
timeline->unlock();
|
timeline->sequence_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** set position of widget on the timeline. */
|
/** 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 )
|
if ( test_press( FL_BUTTON1 + FL_CTRL ) && ! _drag->state )
|
||||||
{
|
{
|
||||||
/* duplication */
|
/* duplication */
|
||||||
timeline->wrlock();
|
timeline->sequence_lock.wrlock();
|
||||||
sequence()->add( this->clone() );
|
sequence()->add( this->clone() );
|
||||||
timeline->unlock();
|
timeline->sequence_lock.unlock();
|
||||||
|
|
||||||
_drag->state = 1;
|
_drag->state = 1;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -62,11 +62,11 @@ Tempo_Sequence::handle ( int m )
|
||||||
|
|
||||||
if ( Tempo_Point::edit( &t ) )
|
if ( Tempo_Point::edit( &t ) )
|
||||||
{
|
{
|
||||||
timeline->wrlock();
|
timeline->sequence_lock.wrlock();
|
||||||
|
|
||||||
new Tempo_Point( timeline->x_to_offset( Fl::event_x() ), t );
|
new Tempo_Point( timeline->x_to_offset( Fl::event_x() ), t );
|
||||||
|
|
||||||
timeline->unlock();
|
timeline->sequence_lock.unlock();
|
||||||
|
|
||||||
timeline->redraw();
|
timeline->redraw();
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,11 +65,11 @@ Time_Sequence::handle ( int m )
|
||||||
|
|
||||||
if ( Time_Point::edit( &t ) )
|
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 );
|
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();
|
timeline->redraw();
|
||||||
}
|
}
|
||||||
|
|
|
@ -360,7 +360,7 @@ Timeline::add_take_for_armed_tracks ( void )
|
||||||
{
|
{
|
||||||
THREAD_ASSERT( UI );
|
THREAD_ASSERT( UI );
|
||||||
|
|
||||||
wrlock();
|
track_lock.wrlock();
|
||||||
|
|
||||||
for ( int i = tracks->children(); i-- ; )
|
for ( int i = tracks->children(); i-- ; )
|
||||||
{
|
{
|
||||||
|
@ -370,7 +370,7 @@ Timeline::add_take_for_armed_tracks ( void )
|
||||||
t->sequence( new Audio_Sequence( t ) );
|
t->sequence( new Audio_Sequence( t ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock();
|
track_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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;
|
play_cursor_track = NULL;
|
||||||
|
|
||||||
_created_new_takes = 0;
|
_created_new_takes = 0;
|
||||||
_punched_in = 0;
|
|
||||||
_punch_in_frame = 0;
|
|
||||||
_punch_out_frame = 0;
|
|
||||||
osc_thread = 0;
|
osc_thread = 0;
|
||||||
_sample_rate = 44100;
|
_sample_rate = 44100;
|
||||||
|
|
||||||
|
@ -1271,6 +1268,8 @@ Timeline::draw ( void )
|
||||||
* another thread must use Fl::lock()/unlock()! */
|
* another thread must use Fl::lock()/unlock()! */
|
||||||
THREAD_ASSERT( UI );
|
THREAD_ASSERT( UI );
|
||||||
|
|
||||||
|
// rdlock();
|
||||||
|
|
||||||
int X, Y, W, H;
|
int X, Y, W, H;
|
||||||
|
|
||||||
int bdx = 0;
|
int bdx = 0;
|
||||||
|
@ -1368,6 +1367,8 @@ Timeline::draw ( void )
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
|
// unlock();
|
||||||
|
|
||||||
/* panzoomer->redraw(); */
|
/* panzoomer->redraw(); */
|
||||||
// update_child( *panzoomer );
|
// update_child( *panzoomer );
|
||||||
|
|
||||||
|
@ -1416,6 +1417,26 @@ Timeline::draw_cursor ( nframes_t frame, Fl_Color color, void (*symbol)(Fl_Color
|
||||||
fl_pop_clip();
|
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
|
void
|
||||||
Timeline::draw_playhead ( void )
|
Timeline::draw_playhead ( void )
|
||||||
{
|
{
|
||||||
|
@ -1429,36 +1450,6 @@ Timeline::redraw_playhead ( void )
|
||||||
// static nframes_t last_playhead = -1;
|
// static nframes_t last_playhead = -1;
|
||||||
static int last_playhead_x = -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 ( transport->rolling )
|
||||||
{
|
{
|
||||||
if ( play_cursor_track->active_cursor() )
|
if ( play_cursor_track->active_cursor() )
|
||||||
|
@ -1987,35 +1978,35 @@ Timeline::remove_track ( Track *track )
|
||||||
void
|
void
|
||||||
Timeline::command_move_track_up ( Track *track )
|
Timeline::command_move_track_up ( Track *track )
|
||||||
{
|
{
|
||||||
wrlock();
|
track_lock.wrlock();
|
||||||
insert_track( track, find_track( track ) - 1 );
|
insert_track( track, find_track( track ) - 1 );
|
||||||
unlock();
|
track_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Timeline::command_move_track_down ( Track *track )
|
Timeline::command_move_track_down ( Track *track )
|
||||||
{
|
{
|
||||||
wrlock();
|
track_lock.wrlock();
|
||||||
insert_track( track, find_track( track ) + 2 );
|
insert_track( track, find_track( track ) + 2 );
|
||||||
unlock();
|
track_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Timeline::command_remove_track ( Track *track )
|
Timeline::command_remove_track ( Track *track )
|
||||||
{
|
{
|
||||||
wrlock();
|
track_lock.wrlock();
|
||||||
remove_track(track);
|
remove_track(track);
|
||||||
unlock();
|
track_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Timeline::command_quit ( void )
|
Timeline::command_quit ( void )
|
||||||
{
|
{
|
||||||
timeline->wrlock();
|
track_lock.wrlock();
|
||||||
|
|
||||||
Project::close();
|
Project::close();
|
||||||
|
|
||||||
timeline->unlock();
|
track_lock.unlock();
|
||||||
|
|
||||||
command_save();
|
command_save();
|
||||||
|
|
||||||
|
@ -2025,9 +2016,10 @@ Timeline::command_quit ( void )
|
||||||
void
|
void
|
||||||
Timeline::command_undo ( void )
|
Timeline::command_undo ( void )
|
||||||
{
|
{
|
||||||
wrlock();
|
/* FIXME: sequence lock too? */
|
||||||
|
track_lock.wrlock();
|
||||||
Project::undo();
|
Project::undo();
|
||||||
unlock();
|
track_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -2036,9 +2028,9 @@ Timeline::command_load ( const char *name, const char *display_name )
|
||||||
if ( ! name )
|
if ( ! name )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
wrlock();
|
track_lock.wrlock();
|
||||||
int r = Project::open( name );
|
int r = Project::open( name );
|
||||||
unlock();
|
track_lock.unlock();
|
||||||
|
|
||||||
if ( r < 0 )
|
if ( r < 0 )
|
||||||
{
|
{
|
||||||
|
|
|
@ -77,9 +77,8 @@ struct Rectangle
|
||||||
Rectangle ( int X, int Y, int W, int H ) : x( X ), y( Y ), w( W ), h( H ) {}
|
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;
|
class Timeline_Panzoomer;
|
||||||
|
|
||||||
static void draw_clip_rulers ( void * v, int X, int Y, int W, int H );
|
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:
|
public:
|
||||||
|
|
||||||
|
RWLock track_lock; /* tracks/sequences */
|
||||||
|
RWLock sequence_lock; /* sequence contents */
|
||||||
|
|
||||||
void redraw_overlay ( void );
|
void redraw_overlay ( void );
|
||||||
|
|
||||||
void insert_track ( Track *track, Track *before );
|
void insert_track ( Track *track, Track *before );
|
||||||
|
@ -166,9 +168,6 @@ public:
|
||||||
|
|
||||||
Fl_Menu_Button *menu;
|
Fl_Menu_Button *menu;
|
||||||
|
|
||||||
int _punched_in;
|
|
||||||
nframes_t _punch_out_frame;
|
|
||||||
nframes_t _punch_in_frame;
|
|
||||||
bool _created_new_takes;
|
bool _created_new_takes;
|
||||||
|
|
||||||
nframes_t xoffset;
|
nframes_t xoffset;
|
||||||
|
@ -257,6 +256,7 @@ public:
|
||||||
void zoom_out ( void );
|
void zoom_out ( void );
|
||||||
void zoom_fit ( void );
|
void zoom_fit ( void );
|
||||||
|
|
||||||
|
bool next_punch ( nframes_t frame, nframes_t *in, nframes_t *out ) const;
|
||||||
|
|
||||||
/* Engine */
|
/* Engine */
|
||||||
int total_input_buffer_percent ( void );
|
int total_input_buffer_percent ( void );
|
||||||
|
@ -267,7 +267,6 @@ public:
|
||||||
|
|
||||||
bool record ( void );
|
bool record ( void );
|
||||||
void stop ( void );
|
void stop ( void );
|
||||||
void punch_in ( nframes_t frame );
|
|
||||||
void punch_out ( nframes_t frame );
|
void punch_out ( nframes_t frame );
|
||||||
|
|
||||||
void wait_for_buffers ( void );
|
void wait_for_buffers ( void );
|
||||||
|
@ -315,6 +314,7 @@ private:
|
||||||
|
|
||||||
/* Engine */
|
/* Engine */
|
||||||
void resize_buffers ( nframes_t nframes );
|
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 );
|
void seek ( nframes_t frame );
|
||||||
};
|
};
|
||||||
|
|
|
@ -737,10 +737,10 @@ void
|
||||||
Track::command_configure_channels ( int n )
|
Track::command_configure_channels ( int n )
|
||||||
{
|
{
|
||||||
/* due to locking this should only be invoked by direct user action */
|
/* due to locking this should only be invoked by direct user action */
|
||||||
timeline->wrlock();
|
timeline->track_lock.wrlock();
|
||||||
configure_inputs( n );
|
configure_inputs( n );
|
||||||
configure_outputs( n );
|
configure_outputs( n );
|
||||||
timeline->unlock();
|
timeline->track_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -787,9 +787,9 @@ Track::menu_cb ( const Fl_Menu_ *m )
|
||||||
/* add audio track */
|
/* add audio track */
|
||||||
char *name = get_unique_control_name( "Control" );
|
char *name = get_unique_control_name( "Control" );
|
||||||
|
|
||||||
timeline->wrlock();
|
timeline->track_lock.wrlock();
|
||||||
new Control_Sequence( this, name );
|
new Control_Sequence( this, name );
|
||||||
timeline->unlock();
|
timeline->track_lock.unlock();
|
||||||
}
|
}
|
||||||
else if ( ! strcmp( picked, "/Overlay controls" ) )
|
else if ( ! strcmp( picked, "/Overlay controls" ) )
|
||||||
{
|
{
|
||||||
|
@ -868,9 +868,9 @@ Track::menu_cb ( const Fl_Menu_ *m )
|
||||||
}
|
}
|
||||||
else if ( !strcmp( picked, "Takes/New" ) )
|
else if ( !strcmp( picked, "Takes/New" ) )
|
||||||
{
|
{
|
||||||
timeline->wrlock();
|
timeline->track_lock.wrlock();
|
||||||
sequence( (Audio_Sequence*)sequence()->clone_empty() );
|
sequence( (Audio_Sequence*)sequence()->clone_empty() );
|
||||||
timeline->unlock();
|
timeline->track_lock.unlock();
|
||||||
}
|
}
|
||||||
else if ( !strcmp( picked, "Takes/Remove" ) )
|
else if ( !strcmp( picked, "Takes/Remove" ) )
|
||||||
{
|
{
|
||||||
|
@ -878,7 +878,7 @@ Track::menu_cb ( const Fl_Menu_ *m )
|
||||||
{
|
{
|
||||||
Loggable::block_start();
|
Loggable::block_start();
|
||||||
|
|
||||||
timeline->wrlock();
|
timeline->track_lock.wrlock();
|
||||||
|
|
||||||
Audio_Sequence *s = sequence();
|
Audio_Sequence *s = sequence();
|
||||||
|
|
||||||
|
@ -886,7 +886,7 @@ Track::menu_cb ( const Fl_Menu_ *m )
|
||||||
|
|
||||||
delete s;
|
delete s;
|
||||||
|
|
||||||
timeline->unlock();
|
timeline->track_lock.unlock();
|
||||||
|
|
||||||
Loggable::block_end();
|
Loggable::block_end();
|
||||||
}
|
}
|
||||||
|
@ -906,9 +906,9 @@ Track::menu_cb ( const Fl_Menu_ *m )
|
||||||
{
|
{
|
||||||
Audio_Sequence* s = (Audio_Sequence*)m->mvalue()->user_data();
|
Audio_Sequence* s = (Audio_Sequence*)m->mvalue()->user_data();
|
||||||
|
|
||||||
timeline->wrlock();
|
timeline->track_lock.wrlock();
|
||||||
sequence( s );
|
sequence( s );
|
||||||
timeline->unlock();
|
timeline->track_lock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::max;
|
using std::max;
|
||||||
|
#include <dsp.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue