@@ -477,6 +477,8 @@ Audio_Region::draw_box( void ) | |||||
void | void | ||||
Audio_Region::peaks_ready_callback ( void *v ) | Audio_Region::peaks_ready_callback ( void *v ) | ||||
{ | { | ||||
/* this is called from the peak builder thread */ | |||||
DMESSAGE("Damaging region from peaks ready callback"); | DMESSAGE("Damaging region from peaks ready callback"); | ||||
Fl::lock(); | Fl::lock(); | ||||
((Audio_Region*)v)->redraw(); | ((Audio_Region*)v)->redraw(); | ||||
@@ -85,12 +85,8 @@ Control_Sequence::~Control_Sequence ( ) | |||||
log_destroy(); | log_destroy(); | ||||
engine->lock(); | |||||
track()->remove( this ); | track()->remove( this ); | ||||
engine->unlock(); | |||||
if ( _output ) | if ( _output ) | ||||
{ | { | ||||
_output->shutdown(); | _output->shutdown(); | ||||
@@ -144,8 +140,6 @@ Control_Sequence::name ( const char *s ) | |||||
void | void | ||||
Control_Sequence::update_port_name ( void ) | Control_Sequence::update_port_name ( void ) | ||||
{ | { | ||||
engine->lock(); | |||||
bool needs_activation = false; | bool needs_activation = false; | ||||
if ( ! _output ) | if ( ! _output ) | ||||
{ | { | ||||
@@ -170,8 +164,6 @@ Control_Sequence::update_port_name ( void ) | |||||
_output = NULL; | _output = NULL; | ||||
} | } | ||||
} | } | ||||
engine->unlock(); | |||||
} | } | ||||
void | void | ||||
@@ -621,7 +613,7 @@ Control_Sequence::process_osc ( void ) | |||||
{ | { | ||||
if ( mode() != OSC ) | if ( mode() != OSC ) | ||||
return; | return; | ||||
header()->outputs_indicator->value( _osc_output() && _osc_output()->connected() ); | header()->outputs_indicator->value( _osc_output() && _osc_output()->connected() ); | ||||
if ( _osc_output() && _osc_output()->connected() ) | if ( _osc_output() && _osc_output()->connected() ) | ||||
@@ -769,7 +761,7 @@ Control_Sequence::handle ( int m ) | |||||
add( r ); | add( r ); | ||||
timeline->unlock(); | |||||
timeline->unlock(); | |||||
return 1; | return 1; | ||||
} | } | ||||
@@ -1,4 +1,4 @@ | |||||
/*******************************************************************************/ | /*******************************************************************************/ | ||||
/* Copyright (C) 2008 Jonathan Moore Liles */ | /* Copyright (C) 2008 Jonathan Moore Liles */ | ||||
/* */ | /* */ | ||||
@@ -73,7 +73,8 @@ Disk_Stream::Disk_Stream ( Track *track, float frame_rate, nframes_t nframes, in | |||||
Disk_Stream::~Disk_Stream ( ) | Disk_Stream::~Disk_Stream ( ) | ||||
{ | { | ||||
/* it isn't safe to do all this with the RT thread running */ | /* it isn't safe to do all this with the RT thread running */ | ||||
engine->lock(); | |||||
timeline->wrlock(); | |||||
shutdown(); | shutdown(); | ||||
@@ -84,7 +85,7 @@ Disk_Stream::~Disk_Stream ( ) | |||||
for ( int i = channels(); i--; ) | for ( int i = channels(); i--; ) | ||||
jack_ringbuffer_free( _rb[ i ] ); | jack_ringbuffer_free( _rb[ i ] ); | ||||
engine->unlock(); | |||||
timeline->unlock(); | |||||
} | } | ||||
@@ -146,23 +147,13 @@ Disk_Stream::shutdown ( void ) | |||||
_terminate = true; | _terminate = true; | ||||
/* try to wake the thread so it'll see that it's time to die */ | /* try to wake the thread so it'll see that it's time to die */ | ||||
int total_ms = 0; | |||||
while ( _terminate ) | while ( _terminate ) | ||||
{ | { | ||||
usleep( 1000 * 10 ); | |||||
total_ms += 10; | |||||
usleep( 100 ); | |||||
block_processed(); | block_processed(); | ||||
if ( total_ms > 100 ) | |||||
{ | |||||
WARNING("Disk_Stream thread has taken longer than %ims to respond to terminate signal. Canceling", total_ms ); | |||||
_thread.cancel(); | |||||
break; | |||||
} | |||||
} | } | ||||
if ( ! _terminate ) | |||||
_thread.join(); | |||||
_thread.join(); | |||||
sem_destroy( &_blocks ); | sem_destroy( &_blocks ); | ||||
@@ -168,7 +168,11 @@ Engine::process ( nframes_t nframes ) | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
if ( ! trylock() ) | |||||
if ( !timeline) | |||||
/* handle chicken/egg problem */ | |||||
return 0; | |||||
if ( timeline->tryrdlock() ) | |||||
{ | { | ||||
/* the data structures we need to access here (tracks and | /* the data structures we need to access here (tracks and | ||||
* their ports, but not track contents) may be in an | * their ports, but not track contents) may be in an | ||||
@@ -178,14 +182,12 @@ Engine::process ( nframes_t nframes ) | |||||
return 0; | return 0; | ||||
} | } | ||||
/* handle chicken/egg problem */ | |||||
if ( timeline ) | |||||
/* 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 ); | |||||
/* 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 ); | |||||
unlock(); | |||||
timeline->unlock(); | |||||
} | } | ||||
return 0; | return 0; | ||||
@@ -27,7 +27,7 @@ class Port; | |||||
#include "Thread.H" | #include "Thread.H" | ||||
class Engine : public JACK::Client, public Mutex | |||||
class Engine : public JACK::Client | |||||
{ | { | ||||
Thread _thread; /* only used for thread checking */ | Thread _thread; /* only used for thread checking */ | ||||
@@ -33,6 +33,7 @@ | |||||
#include "const.h" | #include "const.h" | ||||
#include "debug.h" | #include "debug.h" | ||||
#include "Thread.H" | #include "Thread.H" | ||||
#include <unistd.h> | |||||
bool | bool | ||||
Playback_DS::seek_pending ( void ) | Playback_DS::seek_pending ( void ) | ||||
@@ -76,29 +77,36 @@ Playback_DS::read_block ( sample_t *buf, nframes_t nframes ) | |||||
memset( buf, 0, nframes * sizeof( sample_t ) * channels() ); | memset( buf, 0, nframes * sizeof( sample_t ) * channels() ); | ||||
/* stupid chicken/egg */ | |||||
if ( ! timeline ) | |||||
return; | |||||
// printf( "IO: attempting to read block @ %lu\n", _frame ); | // printf( "IO: attempting to read block @ %lu\n", _frame ); | ||||
timeline->rdlock(); | |||||
if ( !timeline ) | |||||
return; | |||||
if ( sequence() ) | |||||
while ( ! _terminate ) | |||||
{ | { | ||||
/* FIXME: how does this work if _delay is not a multiple of bufsize? */ | |||||
if ( _frame >= _delay ) | |||||
if ( ! timeline->tryrdlock() ) | |||||
{ | { | ||||
if ( ! sequence()->play( buf, _frame - _delay, nframes, channels() ) ) | |||||
WARNING( "Programming error?" ); | |||||
if ( sequence() ) | |||||
{ | |||||
/* FIXME: how does this work if _delay is not a multiple of bufsize? */ | |||||
if ( _frame >= _delay ) | |||||
{ | |||||
if ( ! sequence()->play( buf, _frame - _delay, nframes, channels() ) ) | |||||
WARNING( "Programming error?" ); | |||||
} | |||||
_frame += nframes; | |||||
} | |||||
timeline->unlock(); | |||||
return; | |||||
} | } | ||||
_frame += nframes; | |||||
usleep( 1000 * 10 ); | |||||
} | } | ||||
timeline->unlock(); | |||||
} | } | ||||
#define AVOID_UNNECESSARY_COPYING 1 | #define AVOID_UNNECESSARY_COPYING 1 | ||||
@@ -146,6 +154,10 @@ Playback_DS::disk_thread ( void ) | |||||
read_block( buf, nframes ); | read_block( buf, nframes ); | ||||
/* might have received terminate signal while waiting for block */ | |||||
if ( _terminate ) | |||||
goto done; | |||||
// unlock(); // for seeking | // unlock(); // for seeking | ||||
/* deinterleave the buffer and stuff it into the per-channel ringbuffers */ | /* deinterleave the buffer and stuff it into the per-channel ringbuffers */ | ||||
@@ -201,6 +213,8 @@ Playback_DS::disk_thread ( void ) | |||||
} | } | ||||
done: | |||||
DMESSAGE( "playback thread terminating" ); | DMESSAGE( "playback thread terminating" ); | ||||
delete[] buf; | delete[] buf; | ||||
@@ -209,6 +223,8 @@ Playback_DS::disk_thread ( void ) | |||||
#endif | #endif | ||||
_terminate = false; | _terminate = false; | ||||
_thread.exit(); | |||||
} | } | ||||
/** take a single block from the ringbuffers and send it out the | /** take a single block from the ringbuffers and send it out the | ||||
@@ -72,7 +72,7 @@ Track::configure_outputs ( int n ) | |||||
if ( n == on ) | if ( n == on ) | ||||
return true; | return true; | ||||
// engine->lock(); | |||||
DMESSAGE( "Reconfiguring outputs for track %s", name() ); | |||||
if ( playback_ds ) | if ( playback_ds ) | ||||
{ | { | ||||
@@ -111,7 +111,6 @@ Track::configure_outputs ( int n ) | |||||
if ( output.size() ) | if ( output.size() ) | ||||
playback_ds = new Playback_DS( this, engine->frame_rate(), engine->nframes(), output.size() ); | playback_ds = new Playback_DS( this, engine->frame_rate(), engine->nframes(), output.size() ); | ||||
// engine->unlock(); | |||||
/* FIXME: bogus */ | /* FIXME: bogus */ | ||||
return true; | return true; | ||||
} | } | ||||
@@ -124,6 +123,8 @@ Track::configure_inputs ( int n ) | |||||
if ( n == on ) | if ( n == on ) | ||||
return true; | return true; | ||||
DMESSAGE( "Reconfiguring inputs for track %s", name() ); | |||||
// engine->lock(); | // engine->lock(); | ||||
if ( record_ds ) | if ( record_ds ) | ||||
@@ -204,7 +204,9 @@ Project::close ( void ) | |||||
return false; | return false; | ||||
timeline->wrlock(); | timeline->wrlock(); | ||||
Loggable::close(); | Loggable::close(); | ||||
timeline->unlock(); | timeline->unlock(); | ||||
// write_info(); | // write_info(); | ||||
@@ -311,13 +313,11 @@ Project::open ( const char *name ) | |||||
if ( ! engine ) | if ( ! engine ) | ||||
make_engine(); | make_engine(); | ||||
timeline->wrlock(); | |||||
{ | { | ||||
Block_Timer timer( "Replayed journal" ); | Block_Timer timer( "Replayed journal" ); | ||||
if ( ! Loggable::open( "history" ) ) | if ( ! Loggable::open( "history" ) ) | ||||
return E_INVALID; | return E_INVALID; | ||||
} | } | ||||
timeline->unlock(); | |||||
/* /\* really a good idea? *\/ */ | /* /\* really a good idea? *\/ */ | ||||
/* timeline->sample_rate( rate ); */ | /* timeline->sample_rate( rate ); */ | ||||
@@ -76,14 +76,14 @@ Sequence::~Sequence ( ) | |||||
{ | { | ||||
DMESSAGE( "destroying sequence" ); | DMESSAGE( "destroying sequence" ); | ||||
if ( _name ) | |||||
free( _name ); | |||||
if ( _widgets.size() ) | if ( _widgets.size() ) | ||||
FATAL( "programming error: leaf destructor must call Sequence::clear()!" ); | FATAL( "programming error: leaf destructor must call Sequence::clear()!" ); | ||||
if ( parent() ) | if ( parent() ) | ||||
parent()->remove( this ); | parent()->remove( this ); | ||||
if ( _name ) | |||||
free( _name ); | |||||
} | } | ||||
@@ -155,10 +155,10 @@ void | |||||
Sequence::handle_widget_change ( nframes_t start, nframes_t length ) | Sequence::handle_widget_change ( nframes_t start, nframes_t length ) | ||||
{ | { | ||||
/* this might be invoked from Capture or GUI thread */ | /* this might be invoked from Capture or GUI thread */ | ||||
Fl::lock(); | |||||
// Fl::lock(); | |||||
sort(); | sort(); | ||||
timeline->damage_sequence(); | timeline->damage_sequence(); | ||||
Fl::unlock(); | |||||
// Fl::unlock(); | |||||
// timeline->update_length( start + length ); | // timeline->update_length( start + length ); | ||||
} | } | ||||
@@ -211,7 +211,6 @@ Sequence::remove ( Sequence_Widget *r ) | |||||
_widgets.remove( r ); | _widgets.remove( r ); | ||||
handle_widget_change( r->start(), r->length() ); | handle_widget_change( r->start(), r->length() ); | ||||
} | } | ||||
static nframes_t | static nframes_t | ||||
@@ -400,9 +399,7 @@ 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->wrlock(); | ||||
add( Sequence_Widget::pushed() ); | add( Sequence_Widget::pushed() ); | ||||
timeline->unlock(); | timeline->unlock(); | ||||
damage( FL_DAMAGE_USER1 ); | damage( FL_DAMAGE_USER1 ); | ||||
@@ -487,7 +484,6 @@ Sequence::handle ( int m ) | |||||
Loggable::block_start(); | Loggable::block_start(); | ||||
timeline->wrlock(); | timeline->wrlock(); | ||||
while ( _delete_queue.size() ) | while ( _delete_queue.size() ) | ||||
{ | { | ||||
@@ -504,7 +500,6 @@ Sequence::handle ( int m ) | |||||
delete t; | delete t; | ||||
} | } | ||||
timeline->unlock(); | timeline->unlock(); | ||||
Loggable::block_end(); | Loggable::block_end(); | ||||
@@ -168,7 +168,7 @@ Sequence_Widget::begin_drag ( const Drag &d ) | |||||
{ | { | ||||
_drag = new Drag( d ); | _drag = new Drag( d ); | ||||
timeline->rdlock(); | |||||
timeline->wrlock(); | |||||
/* copy current values */ | /* copy current values */ | ||||
@@ -400,9 +400,7 @@ Sequence_Widget::handle ( int m ) | |||||
/* deletion */ | /* deletion */ | ||||
if ( test_press( FL_BUTTON3 + FL_CTRL ) ) | if ( test_press( FL_BUTTON3 + FL_CTRL ) ) | ||||
{ | { | ||||
timeline->wrlock(); | |||||
remove(); | remove(); | ||||
timeline->unlock(); | |||||
return 1; | return 1; | ||||
} | } | ||||
@@ -444,7 +442,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(); | |||||
sequence()->add( this->clone() ); | sequence()->add( this->clone() ); | ||||
timeline->unlock(); | |||||
_drag->state = 1; | _drag->state = 1; | ||||
return 1; | return 1; | ||||
@@ -41,7 +41,6 @@ | |||||
#include "Annotation_Sequence.H" | #include "Annotation_Sequence.H" | ||||
#include "Track.H" | #include "Track.H" | ||||
#include "Transport.H" | #include "Transport.H" | ||||
#include "Engine/Engine.H" // for lock() | |||||
#include "FL/menu_popup.H" | #include "FL/menu_popup.H" | ||||
@@ -362,6 +361,10 @@ Timeline::range ( nframes_t start, nframes_t length ) | |||||
void | void | ||||
Timeline::add_take_for_armed_tracks ( void ) | Timeline::add_take_for_armed_tracks ( void ) | ||||
{ | { | ||||
THREAD_ASSERT( UI ); | |||||
wrlock(); | |||||
for ( int i = tracks->children(); i-- ; ) | for ( int i = tracks->children(); i-- ; ) | ||||
{ | { | ||||
Track *t = (Track*)tracks->child( i ); | Track *t = (Track*)tracks->child( i ); | ||||
@@ -369,6 +372,8 @@ Timeline::add_take_for_armed_tracks ( void ) | |||||
if ( t->armed() && t->sequence()->_widgets.size() ) | if ( t->armed() && t->sequence()->_widgets.size() ) | ||||
t->sequence( new Audio_Sequence( t ) ); | t->sequence( new Audio_Sequence( t ) ); | ||||
} | } | ||||
unlock(); | |||||
} | } | ||||
void | void | ||||
@@ -938,10 +943,12 @@ Timeline::draw_measure_cb ( nframes_t frame, const BBT &bbt, void *v ) | |||||
return; | return; | ||||
if ( bbt.beat ) | if ( bbt.beat ) | ||||
{ | |||||
if ( o->panzoomer->zoom() > 12 ) | if ( o->panzoomer->zoom() > 12 ) | ||||
return; | return; | ||||
else | else | ||||
c = FL_DARK1; | c = FL_DARK1; | ||||
} | |||||
fl_color( fl_color_add_alpha( c, 64 ) ); | fl_color( fl_color_add_alpha( c, 64 ) ); | ||||
@@ -1246,6 +1253,8 @@ Timeline::draw_cursors ( void ) const | |||||
void | void | ||||
Timeline::draw ( void ) | Timeline::draw ( void ) | ||||
{ | { | ||||
THREAD_ASSERT( UI ); | |||||
int X, Y, W, H; | int X, Y, W, H; | ||||
int bdx = 0; | int bdx = 0; | ||||
@@ -1869,14 +1878,10 @@ Timeline::add_track ( Track *track ) | |||||
{ | { | ||||
DMESSAGE( "added new track to the timeline" ); | DMESSAGE( "added new track to the timeline" ); | ||||
engine->lock(); | |||||
tracks->add( track ); | tracks->add( track ); | ||||
// update_track_order(); | // update_track_order(); | ||||
engine->unlock(); | |||||
/* FIXME: why is this necessary? doesn't the above add do DAMAGE_CHILD? */ | /* FIXME: why is this necessary? doesn't the above add do DAMAGE_CHILD? */ | ||||
redraw(); | redraw(); | ||||
@@ -1888,16 +1893,12 @@ Timeline::insert_track ( Track *track, int n ) | |||||
if ( n > tracks->children() || n < 0 ) | if ( n > tracks->children() || n < 0 ) | ||||
return; | return; | ||||
engine->lock(); | |||||
tracks->insert( *track, n ); | tracks->insert( *track, n ); | ||||
update_track_order(); | update_track_order(); | ||||
tracks->redraw(); | tracks->redraw(); | ||||
engine->unlock(); | |||||
/* FIXME: why is this necessary? doesn't the above add do DAMAGE_CHILD? */ | /* FIXME: why is this necessary? doesn't the above add do DAMAGE_CHILD? */ | ||||
// redraw(); | // redraw(); | ||||
} | } | ||||
@@ -1912,7 +1913,7 @@ compare_tracks ( Track *a, Track *b ) | |||||
void | void | ||||
Timeline::apply_track_order ( void ) | Timeline::apply_track_order ( void ) | ||||
{ | { | ||||
engine->lock(); | |||||
/* wrlock(); */ | |||||
std::list<Track*> tl; | std::list<Track*> tl; | ||||
@@ -1931,7 +1932,7 @@ Timeline::apply_track_order ( void ) | |||||
update_track_order(); | update_track_order(); | ||||
engine->unlock(); | |||||
/* unlock(); */ | |||||
} | } | ||||
void | void | ||||
@@ -1947,17 +1948,6 @@ Timeline::find_track ( const Track *track ) const | |||||
return tracks->find( *track ); | return tracks->find( *track ); | ||||
} | } | ||||
void | |||||
Timeline::move_track_up ( Track *track ) | |||||
{ | |||||
insert_track( track, find_track( track ) - 1 ); | |||||
} | |||||
void | |||||
Timeline::move_track_down ( Track *track ) | |||||
{ | |||||
insert_track( track, find_track( track ) + 2 ); | |||||
} | |||||
/** remove /track/ from the timeline */ | /** remove /track/ from the timeline */ | ||||
void | void | ||||
@@ -1965,15 +1955,11 @@ Timeline::remove_track ( Track *track ) | |||||
{ | { | ||||
DMESSAGE( "removed track from the timeline" ); | DMESSAGE( "removed track from the timeline" ); | ||||
engine->lock(); | |||||
/* FIXME: what to do about track contents? */ | /* FIXME: what to do about track contents? */ | ||||
tracks->remove( track ); | tracks->remove( track ); | ||||
update_track_order(); | update_track_order(); | ||||
engine->unlock(); | |||||
/* FIXME: why is this necessary? doesn't the above add do DAMAGE_CHILD? */ | /* FIXME: why is this necessary? doesn't the above add do DAMAGE_CHILD? */ | ||||
redraw(); | redraw(); | ||||
} | } | ||||
@@ -1982,6 +1968,30 @@ Timeline::remove_track ( Track *track ) | |||||
/* Commands */ | /* Commands */ | ||||
/************/ | /************/ | ||||
void | |||||
Timeline::command_move_track_up ( Track *track ) | |||||
{ | |||||
wrlock(); | |||||
insert_track( track, find_track( track ) - 1 ); | |||||
unlock(); | |||||
} | |||||
void | |||||
Timeline::command_move_track_down ( Track *track ) | |||||
{ | |||||
wrlock(); | |||||
insert_track( track, find_track( track ) + 2 ); | |||||
unlock(); | |||||
} | |||||
void | |||||
Timeline::command_remove_track ( Track *track ) | |||||
{ | |||||
wrlock(); | |||||
remove_track(track); | |||||
unlock(); | |||||
} | |||||
void | void | ||||
Timeline::command_quit ( ) | Timeline::command_quit ( ) | ||||
{ | { | ||||
@@ -1998,8 +2008,10 @@ Timeline::command_load ( const char *name, const char *display_name ) | |||||
if ( ! name ) | if ( ! name ) | ||||
return false; | return false; | ||||
wrlock(); | |||||
int r = Project::open( name ); | int r = Project::open( name ); | ||||
unlock(); | |||||
if ( r < 0 ) | if ( r < 0 ) | ||||
{ | { | ||||
const char *s = Project::errstr( r ); | const char *s = Project::errstr( r ); | ||||
@@ -2145,7 +2157,7 @@ Timeline::handle_peer_scan_complete ( void *o ) | |||||
void | void | ||||
Timeline::connect_osc ( void ) | Timeline::connect_osc ( void ) | ||||
{ | { | ||||
wrlock(); | |||||
// rdlock(); | |||||
/* try to (re)connect OSC signals */ | /* try to (re)connect OSC signals */ | ||||
for ( int i = tracks->children(); i-- ; ) | for ( int i = tracks->children(); i-- ; ) | ||||
@@ -2155,7 +2167,7 @@ Timeline::connect_osc ( void ) | |||||
t->connect_osc(); | t->connect_osc(); | ||||
} | } | ||||
unlock(); | |||||
// unlock(); | |||||
} | } | ||||
void | void | ||||
@@ -2183,7 +2195,6 @@ Timeline::process_osc ( void ) | |||||
{ | { | ||||
THREAD_ASSERT( OSC ); | THREAD_ASSERT( OSC ); | ||||
/* FIXME: is holding this lock a problem for recording? */ | |||||
rdlock(); | rdlock(); | ||||
/* reconnect OSC signals */ | /* reconnect OSC signals */ | ||||
@@ -57,6 +57,8 @@ class Cursor_Point; | |||||
class Fl_Panzoomer; | class Fl_Panzoomer; | ||||
class Fl_Tile; | class Fl_Tile; | ||||
#include "RWLock.H" | |||||
namespace OSC { class Endpoint; } | namespace OSC { class Endpoint; } | ||||
#define USE_WIDGET_FOR_TIMELINE | #define USE_WIDGET_FOR_TIMELINE | ||||
@@ -83,7 +85,6 @@ 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 ) {} | ||||
}; | }; | ||||
#include "RWLock.H" | |||||
#ifdef USE_WIDGET_FOR_TIMELINE | #ifdef USE_WIDGET_FOR_TIMELINE | ||||
class Timeline : public Fl_Group, public RWLock | class Timeline : public Fl_Group, public RWLock | ||||
@@ -252,9 +253,10 @@ public: | |||||
void add_track ( Track *track ); | void add_track ( Track *track ); | ||||
void remove_track ( Track *track ); | void remove_track ( Track *track ); | ||||
void command_remove_track ( Track *track ); | |||||
void move_track_up ( Track *track ); | |||||
void move_track_down ( Track *track ); | |||||
void command_move_track_up ( Track *track ); | |||||
void command_move_track_down ( Track *track ); | |||||
int find_track ( const Track * track ) const; | int find_track ( const Track * track ) const; | ||||
@@ -36,8 +36,6 @@ | |||||
#include "FL/Fl_Scalepack.H" | #include "FL/Fl_Scalepack.H" | ||||
#include "FL/Fl_Blink_Button.H" | #include "FL/Fl_Blink_Button.H" | ||||
#include "Engine/Engine.H" // for lock() | |||||
#include "Control_Sequence.H" | #include "Control_Sequence.H" | ||||
#include "Annotation_Sequence.H" | #include "Annotation_Sequence.H" | ||||
@@ -639,12 +637,8 @@ Track::remove ( Control_Sequence *t ) | |||||
if ( ! control ) | if ( ! control ) | ||||
return; | return; | ||||
engine->lock(); | |||||
control->remove( t ); | control->remove( t ); | ||||
engine->unlock(); | |||||
adjust_size(); | adjust_size(); | ||||
} | } | ||||
@@ -681,8 +675,6 @@ Track::add ( Control_Sequence *t ) | |||||
{ | { | ||||
DMESSAGE( "adding control sequence" ); | DMESSAGE( "adding control sequence" ); | ||||
engine->lock(); | |||||
t->track( this ); | t->track( this ); | ||||
t->color( random_color() ); | t->color( random_color() ); | ||||
@@ -690,8 +682,6 @@ Track::add ( Control_Sequence *t ) | |||||
// control->insert( *t, 0 ); | // control->insert( *t, 0 ); | ||||
control->add( t ); | control->add( t ); | ||||
engine->unlock(); | |||||
adjust_size(); | adjust_size(); | ||||
} | } | ||||
@@ -741,6 +731,16 @@ Track::menu_cb ( Fl_Widget *w, void *v ) | |||||
((Track*)v)->menu_cb( (Fl_Menu_*) w ); | ((Track*)v)->menu_cb( (Fl_Menu_*) w ); | ||||
} | } | ||||
void | |||||
Track::command_configure_channels ( int n ) | |||||
{ | |||||
/* due to locking this should only be invoked by direct user action */ | |||||
timeline->wrlock(); | |||||
configure_inputs( n ); | |||||
configure_outputs( n ); | |||||
timeline->unlock(); | |||||
} | |||||
void | void | ||||
Track::menu_cb ( const Fl_Menu_ *m ) | Track::menu_cb ( const Fl_Menu_ *m ) | ||||
{ | { | ||||
@@ -754,18 +754,15 @@ Track::menu_cb ( const Fl_Menu_ *m ) | |||||
if ( ! strcmp( picked, "Type/Mono" ) ) | if ( ! strcmp( picked, "Type/Mono" ) ) | ||||
{ | { | ||||
configure_inputs( 1 ); | |||||
configure_outputs( 1 ); | |||||
command_configure_channels( 1 ); | |||||
} | } | ||||
else if ( ! strcmp( picked, "Type/Stereo" ) ) | else if ( ! strcmp( picked, "Type/Stereo" ) ) | ||||
{ | { | ||||
configure_inputs( 2 ); | |||||
configure_outputs( 2 ); | |||||
command_configure_channels( 2 ); | |||||
} | } | ||||
else if ( ! strcmp( picked, "Type/Quad" ) ) | else if ( ! strcmp( picked, "Type/Quad" ) ) | ||||
{ | { | ||||
configure_inputs( 4 ); | |||||
configure_outputs( 4 ); | |||||
command_configure_channels( 4 ); | |||||
} | } | ||||
else if ( ! strcmp( picked, "Type/..." ) ) | else if ( ! strcmp( picked, "Type/..." ) ) | ||||
{ | { | ||||
@@ -779,8 +776,7 @@ Track::menu_cb ( const Fl_Menu_ *m ) | |||||
fl_alert( "Invalid number of channels." ); | fl_alert( "Invalid number of channels." ); | ||||
else | else | ||||
{ | { | ||||
configure_inputs( c ); | |||||
configure_outputs( c ); | |||||
command_configure_channels(c); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -789,7 +785,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(); | |||||
new Control_Sequence( this, name ); | new Control_Sequence( this, name ); | ||||
timeline->unlock(); | |||||
} | } | ||||
else if ( ! strcmp( picked, "/Overlay controls" ) ) | else if ( ! strcmp( picked, "/Overlay controls" ) ) | ||||
{ | { | ||||
@@ -846,8 +844,8 @@ Track::menu_cb ( const Fl_Menu_ *m ) | |||||
if ( r == 2 ) | if ( r == 2 ) | ||||
{ | { | ||||
timeline->remove_track( this ); | |||||
Fl::delete_widget( this ); | |||||
timeline->command_remove_track( this ); | |||||
Fl::delete_widget( this ); | |||||
} | } | ||||
} | } | ||||
else if ( ! strcmp( picked, "/Rename" ) ) | else if ( ! strcmp( picked, "/Rename" ) ) | ||||
@@ -856,11 +854,11 @@ Track::menu_cb ( const Fl_Menu_ *m ) | |||||
} | } | ||||
else if ( ! strcmp( picked, "/Move Up" ) ) | else if ( ! strcmp( picked, "/Move Up" ) ) | ||||
{ | { | ||||
timeline->move_track_up( this ); | |||||
timeline->command_move_track_up( this ); | |||||
} | } | ||||
else if ( ! strcmp( picked, "/Move Down" ) ) | else if ( ! strcmp( picked, "/Move Down" ) ) | ||||
{ | { | ||||
timeline->move_track_down( this ); | |||||
timeline->command_move_track_down( this ); | |||||
} | } | ||||
else if ( !strcmp( picked, "Takes/Show all takes" ) ) | else if ( !strcmp( picked, "Takes/Show all takes" ) ) | ||||
{ | { | ||||
@@ -868,7 +866,9 @@ Track::menu_cb ( const Fl_Menu_ *m ) | |||||
} | } | ||||
else if ( !strcmp( picked, "Takes/New" ) ) | else if ( !strcmp( picked, "Takes/New" ) ) | ||||
{ | { | ||||
timeline->wrlock(); | |||||
sequence( (Audio_Sequence*)sequence()->clone_empty() ); | sequence( (Audio_Sequence*)sequence()->clone_empty() ); | ||||
timeline->unlock(); | |||||
} | } | ||||
else if ( !strcmp( picked, "Takes/Remove" ) ) | else if ( !strcmp( picked, "Takes/Remove" ) ) | ||||
{ | { | ||||
@@ -876,12 +876,16 @@ Track::menu_cb ( const Fl_Menu_ *m ) | |||||
{ | { | ||||
Loggable::block_start(); | Loggable::block_start(); | ||||
timeline->wrlock(); | |||||
Audio_Sequence *s = sequence(); | Audio_Sequence *s = sequence(); | ||||
sequence( (Audio_Sequence*)takes->child( 0 ) ); | sequence( (Audio_Sequence*)takes->child( 0 ) ); | ||||
delete s; | delete s; | ||||
timeline->unlock(); | |||||
Loggable::block_end(); | Loggable::block_end(); | ||||
} | } | ||||
} | } | ||||
@@ -900,7 +904,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(); | |||||
sequence( s ); | sequence( s ); | ||||
timeline->unlock(); | |||||
} | } | ||||
} | } | ||||
@@ -111,6 +111,7 @@ private: | |||||
bool configure_outputs ( int n ); | bool configure_outputs ( int n ); | ||||
bool configure_inputs ( int n ); | bool configure_inputs ( int n ); | ||||
void command_configure_channels ( int n ); | |||||
void update_port_names ( void ); | void update_port_names ( void ); | ||||
const char *name_for_port( JACK::Port::type_e type, int n ); | const char *name_for_port( JACK::Port::type_e type, int n ); | ||||