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