| @@ -94,34 +94,30 @@ static int osc_add_strip ( const char *path, const char *, lo_arg **, int , lo_m | |||
| return 0; | |||
| } | |||
| int | |||
| Mixer::osc_non_hello ( const char *, const char *, lo_arg **, int , lo_message msg, void * ) | |||
| { | |||
| mixer->handle_hello( msg ); | |||
| return 0; | |||
| } | |||
| void | |||
| Mixer::reply_to_finger ( lo_message msg ) | |||
| Mixer::handle_hello ( lo_message msg ) | |||
| { | |||
| int argc = lo_message_get_argc( msg ); | |||
| lo_arg **argv = lo_message_get_argv( msg ); | |||
| if ( argc >= 4 ) | |||
| { | |||
| const char *url = &argv[0]->s; | |||
| const char *name = &argv[1]->s; | |||
| const char *version = &argv[2]->s; | |||
| const char *id = &argv[3]->s; | |||
| MESSAGE( "Discovered NON peer %s (%s) @ %s with ID \"%s\"", name, version, url, id ); | |||
| MESSAGE( "Registering Signals" ); | |||
| lo_address to = lo_address_new_from_url( &argv[0]->s ); | |||
| osc_endpoint->send( to, | |||
| "/non/hello", | |||
| osc_endpoint->url(), | |||
| APP_NAME, | |||
| VERSION, | |||
| instance_name ); | |||
| mixer->osc_endpoint->hello( url ); | |||
| lo_address_free( to ); | |||
| MESSAGE( "Got hello from NON peer %s (%s) @ %s with ID \"%s\"", name, version, url, id ); | |||
| mixer->osc_endpoint->handle_hello( id, url ); | |||
| } | |||
| } | |||
| @@ -450,6 +446,9 @@ Mixer::init_osc ( const char *osc_port ) | |||
| printf( "OSC=%s\n", osc_endpoint->url() ); | |||
| osc_endpoint->add_method( "/non/hello", "ssss", &Mixer::osc_non_hello, osc_endpoint, "" ); | |||
| // | |||
| osc_endpoint->add_method( "/non/mixer/add_strip", "", osc_add_strip, osc_endpoint, "" ); | |||
| osc_endpoint->start(); | |||
| @@ -732,22 +731,6 @@ Mixer::handle ( int m ) | |||
| void | |||
| Mixer::discover_peers ( void ) | |||
| { | |||
| if ( nsm->is_active() ) | |||
| { | |||
| lo_message m = lo_message_new(); | |||
| lo_message_add_string( m, "/non/finger" ); | |||
| lo_message_add_string( m, osc_endpoint->url() ); | |||
| nsm->broadcast( m ); | |||
| lo_message_free( m ); | |||
| } | |||
| } | |||
| /************/ | |||
| /* Commands */ | |||
| /************/ | |||
| @@ -71,6 +71,8 @@ private: | |||
| static void handle_dirty ( int, void *v ); | |||
| static int osc_non_hello ( const char *, const char *, lo_arg **, int , lo_message msg, void * ); | |||
| protected: | |||
| int handle ( int m ); | |||
| @@ -100,7 +102,7 @@ public: | |||
| Mixer ( int X, int Y, int W, int H, const char *L ); | |||
| virtual ~Mixer(); | |||
| void reply_to_finger ( lo_message msg ); | |||
| void handle_hello ( lo_message msg ); | |||
| void announce ( const char *nash_url, const char *process_name ); | |||
| @@ -110,8 +112,6 @@ public: | |||
| void say_hello ( void ); | |||
| void discover_peers ( void ); | |||
| public: | |||
| bool command_save ( void ); | |||
| @@ -45,7 +45,7 @@ NSM_Client::command_broadcast ( const char *path, lo_message msg ) | |||
| if ( !strcmp( path, "/non/hello" ) ) | |||
| { | |||
| mixer->reply_to_finger( msg ); | |||
| mixer->handle_hello( msg ); | |||
| return 0; | |||
| } | |||
| else | |||
| @@ -103,7 +103,7 @@ NSM_Client::command_open ( const char *name, const char *display_name, const cha | |||
| } | |||
| } | |||
| mixer->discover_peers(); | |||
| mixer->say_hello(); | |||
| Fl::unlock(); | |||
| @@ -305,8 +305,6 @@ main ( int argc, char **argv ) | |||
| } | |||
| } | |||
| mixer->say_hello(); | |||
| Fl::add_check( check_sigterm ); | |||
| if ( ! no_ui ) | |||
| @@ -60,7 +60,9 @@ namespace OSC | |||
| Signal::Signal ( const char *path, Direction dir ) | |||
| { | |||
| _direction = dir; | |||
| _path = strdup( path ); | |||
| _path = NULL; | |||
| if ( path ) | |||
| _path = strdup( path ); | |||
| _id = ++next_id; | |||
| _value = 0.0f; | |||
| _endpoint = NULL; | |||
| @@ -77,8 +79,9 @@ namespace OSC | |||
| { | |||
| _endpoint->del_signal( this ); | |||
| } | |||
| free( _path ); | |||
| if ( _path ) | |||
| free( _path ); | |||
| _path = NULL; | |||
| _endpoint = NULL; | |||
| @@ -170,7 +173,9 @@ namespace OSC | |||
| } | |||
| Endpoint::Endpoint ( ) | |||
| { | |||
| { | |||
| _peer_signal_notification_callback = 0; | |||
| _peer_signal_notification_userdata = 0; | |||
| _peer_scan_complete_callback = 0; | |||
| _peer_scan_complete_userdata = 0; | |||
| _server = 0; | |||
| @@ -289,30 +294,62 @@ namespace OSC | |||
| lo_address_free( addr ); | |||
| } | |||
| int | |||
| Endpoint::osc_sig_hello ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
| void | |||
| Endpoint::handle_hello ( const char *peer_name, const char *peer_url ) | |||
| { | |||
| Endpoint *ep = (Endpoint*)user_data; | |||
| const char *peer_name = &argv[0]->s; | |||
| const char *peer_url = &argv[1]->s; | |||
| DMESSAGE( "Got hello from %s", peer_name ); | |||
| if ( ! ep->find_peer_by_name( peer_name ) ) | |||
| Peer *p = find_peer_by_name( peer_name ); | |||
| if ( ! p ) | |||
| { | |||
| scan_peer( peer_name, peer_url ); | |||
| } | |||
| else | |||
| { | |||
| ep->scan_peer( peer_name, peer_url ); | |||
| /* maybe the peer has a new URL */ | |||
| /* update address */ | |||
| lo_address addr = lo_address_new_from_url( peer_url ); | |||
| if ( ep->name() ) | |||
| { | |||
| ep->hello( peer_url ); | |||
| } | |||
| else | |||
| if ( address_matches( addr, p->addr ) ) | |||
| { | |||
| DMESSAGE( "Not sending hello because we don't have a name yet!" ); | |||
| free( addr ); | |||
| return; | |||
| } | |||
| if ( p->addr ) | |||
| free( p->addr ); | |||
| p->addr = addr; | |||
| /* scan it while we're at it */ | |||
| p->_scanning = true; | |||
| DMESSAGE( "Scanning peer %s", peer_name ); | |||
| send( p->addr, "/signal/list" ); | |||
| } | |||
| if ( name() ) | |||
| { | |||
| hello( peer_url ); | |||
| } | |||
| else | |||
| { | |||
| DMESSAGE( "Not sending hello because we don't have a name yet!" ); | |||
| } | |||
| } | |||
| int | |||
| Endpoint::osc_sig_hello ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
| { | |||
| Endpoint *ep = (Endpoint*)user_data; | |||
| const char *peer_name = &argv[0]->s; | |||
| const char *peer_url = &argv[1]->s; | |||
| ep->handle_hello( peer_name, peer_url ); | |||
| return 0; | |||
| } | |||
| @@ -374,13 +411,24 @@ namespace OSC | |||
| Signal *ps = ep->find_peer_signal_by_id( p, their_id ); | |||
| /* if ( ! ps ) */ | |||
| /* { */ | |||
| /* WARNING( "Unknown source signal" ); */ | |||
| /* WARNIN */ | |||
| /* return 0; */ | |||
| /* } */ | |||
| if ( ! ps ) | |||
| { | |||
| WARNING( "Unknown source signal" ); | |||
| /* we don't know about this signal yet */ | |||
| /* just add a stub signal and fill in the blanks later */ | |||
| ps = new Signal( NULL, Signal::Output); | |||
| ps->_id = their_id; | |||
| ps->_peer = p; | |||
| return 0; | |||
| p->_signals.push_back( ps ); | |||
| } | |||
| Signal *s = ep->find_signal_by_id( our_id ); | |||
| if ( ! s ) | |||
| @@ -427,27 +475,44 @@ namespace OSC | |||
| if ( ! o ) | |||
| { | |||
| WARNING( "Unknown signal id %i", id ); | |||
| WARNING( "Unknown signal ID %i", id ); | |||
| return 0; | |||
| } | |||
| DMESSAGE( "Signal %s:%s was removed", o->_peer->name, o->path() ); | |||
| /* disconnect it */ | |||
| for ( std::list<Signal*>::iterator i = o->_outgoing.begin(); | |||
| i != o->_outgoing.end(); | |||
| ++i ) | |||
| if ( o->_outgoing.size() ) | |||
| { | |||
| ep->disconnect_signal( o, *i ); | |||
| for ( std::list<Signal*>::iterator i = o->_outgoing.begin(); | |||
| i != o->_outgoing.end(); | |||
| ) | |||
| { | |||
| Signal *s = *i; | |||
| /* avoid messing up iterator */ | |||
| ++i; | |||
| ep->disconnect_signal( o, s ); | |||
| } | |||
| } | |||
| for ( std::list<Signal*>::iterator i = o->_incoming.begin(); | |||
| i != o->_incoming.end(); | |||
| ++i ) | |||
| if ( o->_incoming.size() ) | |||
| { | |||
| ep->disconnect_signal( *i, o ); | |||
| for ( std::list<Signal*>::iterator i = o->_incoming.begin(); | |||
| i != o->_incoming.end(); | |||
| ) | |||
| { | |||
| Signal *s = *i; | |||
| /* avoid messing up iterator */ | |||
| ++i; | |||
| ep->disconnect_signal( s, o ); | |||
| } | |||
| } | |||
| if ( ep->_peer_signal_notification_callback ) | |||
| ep->_peer_signal_notification_callback( o, Signal::Removed, ep->_peer_signal_notification_userdata ); | |||
| p->_signals.remove( o ); | |||
| delete o; | |||
| @@ -459,14 +524,6 @@ namespace OSC | |||
| Endpoint::osc_sig_created ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
| { | |||
| Endpoint *ep = (Endpoint*)user_data; | |||
| Peer *p = ep->find_peer_by_address( lo_message_get_source( msg ) ); | |||
| if ( ! p ) | |||
| { | |||
| WARNING( "Got signal creation from unknown peer." ); | |||
| return 0; | |||
| } | |||
| const char *name = &argv[0]->s; | |||
| const char *direction = &argv[1]->s; | |||
| @@ -475,9 +532,14 @@ namespace OSC | |||
| const float max = argv[4]->f; | |||
| const float default_value = argv[5]->f; | |||
| DMESSAGE( "Peer %s has created signal %s with id %i (%s %f %f %f)", p->name, | |||
| name, id, direction, min, max, default_value ); | |||
| Peer *p = ep->find_peer_by_address( lo_message_get_source( msg ) ); | |||
| if ( ! p ) | |||
| { | |||
| WARNING( "Got signal creation notification from unknown peer" ); | |||
| return 0; | |||
| } | |||
| Signal::Direction dir = Signal::Input; | |||
| if ( !strcmp( direction, "in" ) ) | |||
| @@ -492,6 +554,12 @@ namespace OSC | |||
| s->parameter_limits( min, max, default_value ); | |||
| p->_signals.push_back( s ); | |||
| DMESSAGE( "Peer %s has created signal %s with id %i (%s %f %f %f)", p->name, | |||
| name, id, direction, min, max, default_value ); | |||
| if ( ep->_peer_signal_notification_callback ) | |||
| ep->_peer_signal_notification_callback( s, Signal::Created, ep->_peer_signal_notification_userdata ); | |||
| return 0; | |||
| } | |||
| @@ -652,6 +720,8 @@ namespace OSC | |||
| Endpoint::osc_signal_lister ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||
| { | |||
| // OSC_DMSG(); | |||
| DMESSAGE( "Listing signals." ); | |||
| const char *prefix = NULL; | |||
| @@ -700,7 +770,7 @@ namespace OSC | |||
| void | |||
| Endpoint::list_peer_signals ( void (*callback) (const char *, const OSC::Signal *, void * ), void *v ) | |||
| Endpoint::list_peer_signals ( void *v ) | |||
| { | |||
| for ( std::list<Peer*>::iterator i = _peers.begin(); | |||
| i != _peers.end(); | |||
| @@ -711,7 +781,8 @@ namespace OSC | |||
| ++j ) | |||
| { | |||
| // DMESSAGE( "Running callback" ); | |||
| callback( (*i)->name, *j, v ); | |||
| if ( _peer_signal_notification_callback ) | |||
| _peer_signal_notification_callback( *j, OSC::Signal::Created, v ); | |||
| } | |||
| } | |||
| } | |||
| @@ -764,15 +835,22 @@ namespace OSC | |||
| { | |||
| if ( ! s->is_connected_to( d ) ) | |||
| return false; | |||
| MESSAGE( "Disconnecting signal output \"%s\" to %s:%i", s->path(), d->_peer->name, d->_id ); | |||
| send( d->_peer->addr, "/signal/disconnect", | |||
| s->_id, /* our signal id */ | |||
| d->_id /* their signal id */ ); | |||
| if ( d->_peer ) | |||
| { | |||
| MESSAGE( "Disconnecting signal output \"%s\" from %s:%s", s->path(), d->_peer->name, d->_path ); | |||
| send( d->_peer->addr, "/signal/disconnect", | |||
| s->_id, /* our signal id */ | |||
| d->_id /* their signal id */ ); | |||
| } | |||
| else | |||
| { | |||
| MESSAGE( "Disconnecting signal output \"%s\" to (unknown):%i", s->path(), d->_id ); | |||
| } | |||
| s->_outgoing.remove( d ); | |||
| s->_incoming.remove( d ); | |||
| d->_incoming.remove( s ); | |||
| return true; | |||
| } | |||
| @@ -801,6 +879,9 @@ namespace OSC | |||
| return false; | |||
| } | |||
| /** Connect to name signal. If the destination doesn't currently * | |||
| exist, but appears at some later point, the connection will be made | |||
| then */ | |||
| bool | |||
| Endpoint::connect_signal( OSC::Signal *s, const char *peer_and_path ) | |||
| { | |||
| @@ -930,13 +1011,28 @@ namespace OSC | |||
| else if ( !strcmp( &argv[2]->s, "out" ) ) | |||
| dir = Signal::Output; | |||
| Signal *s = new Signal( &argv[1]->s, (Signal::Direction)dir ); | |||
| Signal *s = ep->find_peer_signal_by_id( p, argv[3]->i ); | |||
| if ( s && s->id() == argv[3]->i ) | |||
| { | |||
| /* found a stub signal, fill in the blanks */ | |||
| s->_path = strdup(&argv[1]->s); | |||
| s->parameter_limits( argv[4]->f, argv[5]->f, argv[6]->f ); | |||
| } | |||
| else | |||
| { | |||
| s = new Signal( &argv[1]->s, (Signal::Direction)dir ); | |||
| s->_peer = p; | |||
| s->_id = argv[3]->i; | |||
| s->parameter_limits( argv[4]->f, argv[5]->f, argv[6]->f ); | |||
| p->_signals.push_back( s ); | |||
| } | |||
| if ( ep->_peer_signal_notification_callback ) | |||
| ep->_peer_signal_notification_callback( s, Signal::Created, ep->_peer_signal_notification_userdata ); | |||
| } | |||
| return 0; | |||
| @@ -985,7 +1081,6 @@ namespace OSC | |||
| lo_server_add_method( _server, path, NULL, osc_sig_handler, o ); | |||
| } | |||
| o->parameter_limits( min, max, default_value ); | |||
| /* tell our peers about it */ | |||
| @@ -994,7 +1089,7 @@ namespace OSC | |||
| ++i ) | |||
| { | |||
| send( (*i)->addr, | |||
| "/signal/created", | |||
| "/signal/created", | |||
| o->path(), | |||
| o->_direction == Signal::Input ? "in" : "out", | |||
| o->id(), | |||
| @@ -1074,24 +1169,66 @@ namespace OSC | |||
| o->id() ); | |||
| } | |||
| Endpoint *ep = this; | |||
| /* disconnect it */ | |||
| if ( o->_outgoing.size() ) | |||
| { | |||
| for ( std::list<Signal*>::iterator i = o->_outgoing.begin(); | |||
| i != o->_outgoing.end(); | |||
| ) | |||
| { | |||
| Signal *s = *i; | |||
| /* avoid messing up iterator */ | |||
| ++i; | |||
| ep->disconnect_signal( o, s ); | |||
| } | |||
| } | |||
| if ( o->_incoming.size() ) | |||
| { | |||
| for ( std::list<Signal*>::iterator i = o->_incoming.begin(); | |||
| i != o->_incoming.end(); | |||
| ) | |||
| { | |||
| Signal *s = *i; | |||
| /* avoid messing up iterator */ | |||
| ++i; | |||
| ep->disconnect_signal( s, o ); | |||
| } | |||
| } | |||
| /* FIXME: clear loopback connections first! */ | |||
| // delete o; | |||
| _signals.remove( o ); | |||
| } | |||
| void | |||
| Endpoint::scan_peer ( const char *name, const char *url ) | |||
| Peer * | |||
| Endpoint::add_peer ( const char *name, const char *url ) | |||
| { | |||
| Peer *p = new Peer; | |||
| DMESSAGE( "Scanning peer %s @ %s...", name, url ); | |||
| DMESSAGE( "Adding peer %s @ %s...", name, url ); | |||
| p->name = strdup( name ); | |||
| p->addr = lo_address_new_from_url( url ); | |||
| _peers.push_back( p ); | |||
| return p; | |||
| } | |||
| void | |||
| Endpoint::scan_peer ( const char *name, const char *url ) | |||
| { | |||
| Peer *p = add_peer(name,url); | |||
| p->_scanning = true; | |||
| _peers.push_back( p ); | |||
| DMESSAGE( "Scanning peer %s", name ); | |||
| send( p->addr, "/signal/list" ); | |||
| } | |||
| @@ -1184,15 +1321,15 @@ namespace OSC | |||
| switch ( ov->type() ) | |||
| { | |||
| case 'f': | |||
| DMESSAGE( "Adding float %f", ((OSC_Float*)ov)->value() ); | |||
| // DMESSAGE( "Adding float %f", ((OSC_Float*)ov)->value() ); | |||
| lo_message_add_float( m, ((OSC_Float*)ov)->value() ); | |||
| break; | |||
| case 'i': | |||
| DMESSAGE( "Adding int %i", ((OSC_Int*)ov)->value() ); | |||
| // DMESSAGE( "Adding int %i", ((OSC_Int*)ov)->value() ); | |||
| lo_message_add_int32( m, ((OSC_Int*)ov)->value() ); | |||
| break; | |||
| case 's': | |||
| DMESSAGE( "Adding string %s", ((OSC_String*)ov)->value() ); | |||
| // DMESSAGE( "Adding string %s", ((OSC_String*)ov)->value() ); | |||
| lo_message_add_string( m, ((OSC_String*)ov)->value() ); | |||
| break; | |||
| default: | |||
| @@ -1201,7 +1338,7 @@ namespace OSC | |||
| } | |||
| } | |||
| DMESSAGE( "Path: %s", path ); | |||
| // DMESSAGE( "Path: %s", path ); | |||
| lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE ); | |||
| @@ -133,6 +133,11 @@ namespace OSC | |||
| public: | |||
| enum State { | |||
| Created = 0, | |||
| Removed = 1 | |||
| }; | |||
| enum Direction { | |||
| Input, | |||
| Output, | |||
| @@ -166,6 +171,10 @@ namespace OSC | |||
| public: | |||
| const char * peer_name ( void ) const { | |||
| return _peer->name; | |||
| } | |||
| Signal ( const char *path, Direction dir ); | |||
| ~Signal ( ); | |||
| @@ -259,6 +268,8 @@ namespace OSC | |||
| static int osc_sig_connect ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | |||
| static int osc_sig_hello ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | |||
| Peer * add_peer ( const char *name, const char *url ); | |||
| void scan_peer ( const char *name, const char *url ); | |||
| private: | |||
| @@ -279,12 +290,22 @@ namespace OSC | |||
| void del_signal ( Signal *signal ); | |||
| void send_signal_rename_notifications( Signal *s ); | |||
| public: | |||
| void (*_peer_signal_notification_callback)( OSC::Signal *, OSC::Signal::State, void*); | |||
| void *_peer_signal_notification_userdata; | |||
| public: | |||
| void peer_signal_notification_callback ( void (*cb)(OSC::Signal *, OSC::Signal::State, void*), void *userdata ) | |||
| { | |||
| _peer_signal_notification_callback = cb; | |||
| _peer_signal_notification_userdata = userdata; | |||
| } | |||
| // can be used to point back to owning object. | |||
| void *owner; | |||
| void list_peer_signals ( void (*callback) (const char *, const OSC::Signal *, void * ), void *v ); | |||
| void list_peer_signals ( void *v ); | |||
| int init ( int proto, const char *port = 0 ); | |||
| @@ -299,7 +320,6 @@ namespace OSC | |||
| bool connect_signal ( OSC::Signal *s, const char *peer_name, int signal_id ); | |||
| bool connect_signal ( OSC::Signal *s, const char *peer_and_path ); | |||
| Signal * add_signal ( const char *path, Signal::Direction dir, float min, float max, float default_value, signal_handler handler, void *user_data ); | |||
| Method *add_method ( const char *path, const char *typespec, lo_method_handler handler, void *user_data, const char *argument_description ); | |||
| void del_method ( const char *path, const char *typespec ); | |||
| @@ -317,6 +337,7 @@ namespace OSC | |||
| const char *name ( void ) { return _name; } | |||
| void hello ( const char *url ); | |||
| void handle_hello ( const char *peer_name, const char *peer_url ); | |||
| int send ( lo_address to, const char *path, std::list< OSC_Value > values ); | |||
| @@ -66,10 +66,10 @@ Control_Sequence::Control_Sequence ( Track *track, const char *name ) : Sequence | |||
| _track = track; | |||
| mode( OSC ); | |||
| this->name( name ); | |||
| mode( OSC ); | |||
| if ( track ) | |||
| track->add( this ); | |||
| @@ -198,6 +198,8 @@ Control_Sequence::cb_button ( Fl_Widget *w ) | |||
| void | |||
| Control_Sequence::init ( void ) | |||
| { | |||
| timeline->osc->peer_signal_notification_callback( &Control_Sequence::peer_callback, NULL ); | |||
| labeltype( FL_NO_LABEL ); | |||
| { | |||
| Control_Sequence_Header *o = new Control_Sequence_Header( x(), y(), Track::width(), 52 ); | |||
| @@ -332,7 +334,7 @@ Control_Sequence::mode ( Mode m ) | |||
| { | |||
| /* FIXME: use name here... */ | |||
| char *path; | |||
| asprintf( &path, "/track/%s/control/%i", track()->name(), track()->ncontrols() ); | |||
| asprintf( &path, "/track/%s/%s", track()->name(), name() ); | |||
| char *s = escape_url( path ); | |||
| @@ -348,8 +350,6 @@ Control_Sequence::mode ( Mode m ) | |||
| DMESSAGE( "osc_output: %p", _osc_output() ); | |||
| connect_osc(); | |||
| header()->outputs_indicator->label( "osc" ); | |||
| } | |||
| @@ -589,6 +589,8 @@ Control_Sequence::menu_cb ( const Fl_Menu_ *m ) | |||
| void | |||
| Control_Sequence::connect_osc ( void ) | |||
| { | |||
| timeline->osc_thread->lock(); | |||
| if ( _persistent_osc_connections.size() ) | |||
| { | |||
| for ( std::list<char*>::iterator i = _persistent_osc_connections.begin(); | |||
| @@ -597,7 +599,7 @@ Control_Sequence::connect_osc ( void ) | |||
| { | |||
| if ( ! timeline->osc->connect_signal( _osc_output(), *i ) ) | |||
| { | |||
| // MESSAGE( "Failed to connect output %s to ", _osc_output->path(), *i ); | |||
| /* WARNING( "Failed to connect output %s to %s", _osc_output()->path(), *i ); */ | |||
| } | |||
| else | |||
| { | |||
| @@ -606,6 +608,10 @@ Control_Sequence::connect_osc ( void ) | |||
| } | |||
| } | |||
| } | |||
| header()->outputs_indicator->value( _osc_output() && _osc_output()->connected() ); | |||
| timeline->osc_thread->unlock(); | |||
| } | |||
| void | |||
| @@ -614,28 +620,26 @@ Control_Sequence::process_osc ( void ) | |||
| if ( mode() != OSC ) | |||
| return; | |||
| header()->outputs_indicator->value( _osc_output() && _osc_output()->connected() ); | |||
| if ( _osc_output() && _osc_output()->connected() ) | |||
| { | |||
| sample_t buf[1]; | |||
| play( buf, (nframes_t)transport->frame, (nframes_t) 1 ); | |||
| _osc_output()->value( (float)buf[0] ); | |||
| } | |||
| } | |||
| static Fl_Menu_Button *peer_menu; | |||
| static const char *peer_prefix; | |||
| void | |||
| Control_Sequence::peer_callback( const char *name, const OSC::Signal *sig, void *v ) | |||
| Control_Sequence::update_osc_connection_state ( void ) | |||
| { | |||
| ((Control_Sequence*)v)->peer_callback( name, sig ); | |||
| header()->outputs_indicator->value( _osc_output() && _osc_output()->connected() ); | |||
| } | |||
| static Fl_Menu_Button *peer_menu; | |||
| static const char *peer_prefix; | |||
| void | |||
| Control_Sequence::peer_callback( const char *name, const OSC::Signal *sig ) | |||
| Control_Sequence::peer_callback( OSC::Signal *sig, OSC::Signal::State state, void *v ) | |||
| { | |||
| char *s; | |||
| @@ -647,34 +651,44 @@ Control_Sequence::peer_callback( const char *name, const OSC::Signal *sig ) | |||
| if ( ! ( sig->parameter_limits().min == 0.0 && | |||
| sig->parameter_limits().max == 1.0 ) ) | |||
| return; | |||
| assert( sig->path() ); | |||
| char *path = strdup( sig->path() ); | |||
| unescape_url( path ); | |||
| if ( ! v ) | |||
| { | |||
| if( state == OSC::Signal::Created ) | |||
| timeline->connect_osc(); | |||
| else | |||
| timeline->update_osc_connection_state(); | |||
| } | |||
| else | |||
| { | |||
| /* building menu */ | |||
| const char *name = sig->peer_name(); | |||
| assert( sig->path() ); | |||
| asprintf( &s, "%s/%s%s", peer_prefix, name, path ); | |||
| char *path = strdup( sig->path() ); | |||
| peer_menu->add( s, 0, NULL, (void*)( sig ), | |||
| FL_MENU_TOGGLE | | |||
| ( _osc_output()->is_connected_to( sig ) ? FL_MENU_VALUE : 0 ) ); | |||
| unescape_url( path ); | |||
| free( path ); | |||
| asprintf( &s, "%s/%s%s", peer_prefix, name, path ); | |||
| free( s ); | |||
| peer_menu->add( s, 0, NULL, (void*)( sig ), | |||
| FL_MENU_TOGGLE | | |||
| ( ((Control_Sequence*)v)->_osc_output()->is_connected_to( sig ) ? FL_MENU_VALUE : 0 ) ); | |||
| free( path ); | |||
| connect_osc(); | |||
| free( s ); | |||
| } | |||
| } | |||
| void | |||
| Control_Sequence::add_osc_peers_to_menu ( Fl_Menu_Button *m, const char *prefix ) | |||
| { | |||
| peer_menu = m; | |||
| peer_menu = m; | |||
| peer_prefix = prefix; | |||
| timeline->osc->list_peer_signals( &Control_Sequence::peer_callback, this ); | |||
| timeline->osc->list_peer_signals( this ); | |||
| } | |||
| Fl_Menu_Button & | |||
| @@ -71,8 +71,8 @@ private: | |||
| } | |||
| static void peer_callback( const char *name, const OSC::Signal *sig, void *v ); | |||
| void peer_callback( const char *name, const OSC::Signal *sig ); | |||
| static void peer_callback( OSC::Signal *sig, OSC::Signal::State state, void *v ); | |||
| void peer_callback( OSC::Signal *sig, OSC::Signal::State state ); | |||
| void add_osc_peers_to_menu ( Fl_Menu_Button *m, const char *prefix ); | |||
| static Fl_Widget *_highlighted; | |||
| @@ -116,6 +116,7 @@ public: | |||
| void process_osc ( void ); | |||
| void connect_osc ( void ); | |||
| void update_osc_connection_state ( void ); | |||
| static bool draw_with_polygon; | |||
| static bool draw_with_grid; | |||
| @@ -56,7 +56,7 @@ command_open ( const char *name, const char *display_name, const char *client_id | |||
| instance_name = strdup( client_id ); | |||
| timeline->osc->name( client_id ); | |||
| int r = 0; | |||
| if ( Project::validate( name ) ) | |||
| @@ -79,8 +79,10 @@ command_open ( const char *name, const char *display_name, const char *client_id | |||
| r = ERR_GENERAL; | |||
| } | |||
| } | |||
| timeline->say_hello(); | |||
| timeline->discover_peers(); | |||
| // timeline->connect_osc(); | |||
| return r; | |||
| } | |||
| @@ -89,8 +91,6 @@ static void | |||
| command_session_is_loaded ( void *userdata ) | |||
| { | |||
| MESSAGE( "NSM says session is loaded." ); | |||
| timeline->discover_peers(); | |||
| } | |||
| static int | |||
| @@ -101,7 +101,7 @@ command_broadcast ( const char *path, lo_message msg, void *userdata ) | |||
| if ( !strcmp( path, "/non/hello" ) ) | |||
| { | |||
| timeline->reply_to_finger( msg ); | |||
| timeline->handle_hello( msg ); | |||
| return 0; | |||
| } | |||
| else | |||
| @@ -26,6 +26,8 @@ | |||
| #include "debug.h" | |||
| #include "OSC/Endpoint.H" | |||
| extern Timeline *timeline; | |||
| OSC_Thread::OSC_Thread ( ) | |||
| @@ -61,14 +63,17 @@ OSC_Thread::process ( void ) | |||
| _thread.name( "OSC" ); | |||
| DMESSAGE( "OSC Thread starting" ); | |||
| while ( !_shutdown ) | |||
| { | |||
| if ( trylock() ) | |||
| { | |||
| timeline->osc->check(); | |||
| timeline->process_osc(); | |||
| unlock(); | |||
| } | |||
| usleep( 100 * 1000 ); | |||
| /* lock(); */ | |||
| timeline->process_osc(); | |||
| /* unlock(); */ | |||
| } | |||
| DMESSAGE( "OSC Thread stopping." ); | |||
| @@ -2082,15 +2082,6 @@ Timeline::session_manager_name ( void ) | |||
| /* OSC */ | |||
| /*******/ | |||
| const double OSC_INTERVAL = 0.2f; | |||
| void | |||
| Timeline::check_osc ( void * v ) | |||
| { | |||
| ((Timeline*)v)->osc->check(); | |||
| Fl::repeat_timeout( OSC_INTERVAL, &Timeline::check_osc, v ); | |||
| } | |||
| int | |||
| Timeline::init_osc ( const char *osc_port ) | |||
| { | |||
| @@ -2107,11 +2098,6 @@ Timeline::init_osc ( const char *osc_port ) | |||
| // osc->start(); | |||
| /* poll so we can keep OSC handlers running in the GUI thread and avoid extra sync */ | |||
| Fl::add_timeout( OSC_INTERVAL, &Timeline::check_osc, this ); | |||
| osc->peer_scan_complete_callback( &Timeline::handle_peer_scan_complete, this ); | |||
| if ( ! osc_thread ) | |||
| { | |||
| osc_thread = new OSC_Thread(); | |||
| @@ -2123,9 +2109,19 @@ Timeline::init_osc ( const char *osc_port ) | |||
| } | |||
| int | |||
| Timeline::osc_non_hello ( const char *path, const char *, lo_arg **argv, int argc, lo_message, void * ) | |||
| Timeline::osc_non_hello ( const char *, const char *, lo_arg **, int , lo_message msg, void * ) | |||
| { | |||
| OSC_DMSG(); | |||
| THREAD_ASSERT( OSC ); | |||
| timeline->handle_hello(msg); | |||
| return 0; | |||
| } | |||
| void | |||
| Timeline::handle_hello ( lo_message msg ) | |||
| { | |||
| int argc = lo_message_get_argc( msg ); | |||
| lo_arg **argv = lo_message_get_argv( msg ); | |||
| if ( argc >= 4 ) | |||
| { | |||
| @@ -2134,88 +2130,60 @@ Timeline::osc_non_hello ( const char *path, const char *, lo_arg **argv, int arg | |||
| const char *version = &argv[2]->s; | |||
| const char *id = &argv[3]->s; | |||
| MESSAGE( "Discovered NON peer %s (%s) @ %s with ID \"%s\"", name, version, url, id ); | |||
| MESSAGE( "Registering Signals" ); | |||
| timeline->osc->hello( url ); | |||
| MESSAGE( "Got hello from NON peer %s (%s) @ %s with ID \"%s\"", name, version, url, id ); | |||
| return 0; | |||
| osc->handle_hello( &argv[3]->s, &argv[0]->s ); | |||
| } | |||
| return -1; | |||
| } | |||
| void | |||
| Timeline::reply_to_finger ( lo_message msg ) | |||
| { | |||
| int argc = lo_message_get_argc( msg ); | |||
| lo_arg **argv = lo_message_get_argv( msg ); | |||
| if ( argc < 1 ) | |||
| return; | |||
| lo_address reply = lo_address_new_from_url( &argv[0]->s ); | |||
| osc->send( reply, | |||
| "/non/hello", | |||
| osc->url(), | |||
| APP_NAME, | |||
| VERSION, | |||
| instance_name ); | |||
| osc->hello( &argv[0]->s ); | |||
| lo_address_free( reply ); | |||
| } | |||
| void | |||
| Timeline::handle_peer_scan_complete ( void *o ) | |||
| Timeline::say_hello ( void ) | |||
| { | |||
| ((Timeline*)o)->connect_osc(); | |||
| if ( nsm_is_active( nsm ) ) | |||
| { | |||
| lo_message m = lo_message_new(); | |||
| lo_message_add( m, "sssss", | |||
| "/non/hello", | |||
| osc->url(), | |||
| APP_NAME, | |||
| VERSION, | |||
| instance_name ); | |||
| nsm_send_broadcast( nsm, m ); | |||
| } | |||
| } | |||
| void | |||
| Timeline::connect_osc ( void ) | |||
| { | |||
| // rdlock(); | |||
| /* try to (re)connect OSC signals */ | |||
| /* reconnect OSC signals */ | |||
| for ( int i = tracks->children(); i-- ; ) | |||
| { | |||
| Track *t = (Track*)tracks->child( i ); | |||
| t->connect_osc(); | |||
| } | |||
| // unlock(); | |||
| } | |||
| void | |||
| Timeline::discover_peers ( void ) | |||
| Timeline::update_osc_connection_state ( void ) | |||
| { | |||
| if ( nsm_is_active( nsm ) ) | |||
| /* reconnect OSC signals */ | |||
| for ( int i = tracks->children(); i-- ; ) | |||
| { | |||
| lo_message m = lo_message_new(); | |||
| lo_message_add( m, "sssss", | |||
| "/non/hello", | |||
| osc->url(), | |||
| APP_NAME, | |||
| VERSION, | |||
| instance_name ); | |||
| Track *t = (Track*)tracks->child( i ); | |||
| nsm_send_broadcast( nsm, m ); | |||
| t->update_osc_connection_state(); | |||
| } | |||
| } | |||
| /* runs in the OSC thread... */ | |||
| void | |||
| Timeline::process_osc ( void ) | |||
| { | |||
| THREAD_ASSERT( OSC ); | |||
| rdlock(); | |||
| /* rdlock(); */ | |||
| /* reconnect OSC signals */ | |||
| for ( int i = tracks->children(); i-- ; ) | |||
| @@ -2225,6 +2193,6 @@ Timeline::process_osc ( void ) | |||
| t->process_osc(); | |||
| } | |||
| unlock(); | |||
| /* unlock(); */ | |||
| } | |||
| @@ -294,7 +294,9 @@ public: | |||
| void connect_osc ( void ); | |||
| void discover_peers ( void ); | |||
| void update_osc_connection_state ( void ); | |||
| void say_hello ( void ); | |||
| static void check_osc ( void * v ); | |||
| @@ -304,7 +306,7 @@ public: | |||
| static int osc_non_hello ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | |||
| void reply_to_finger ( lo_message msg ); | |||
| void handle_hello ( lo_message msg ); | |||
| void add_cursor ( Cursor_Region *o ); | |||
| void add_cursor ( Cursor_Point *o ); | |||
| @@ -1095,6 +1095,16 @@ Track::connect_osc ( void ) | |||
| } | |||
| } | |||
| void | |||
| Track::update_osc_connection_state ( void ) | |||
| { | |||
| for ( int j = control->children(); j--; ) | |||
| { | |||
| Control_Sequence *c = (Control_Sequence*)control->child( j ); | |||
| c->update_osc_connection_state(); | |||
| } | |||
| } | |||
| void | |||
| Track::process_osc ( void ) | |||
| { | |||
| @@ -242,6 +242,7 @@ public: | |||
| void process_osc ( void ); | |||
| void connect_osc ( void ); | |||
| void update_osc_connection_state ( void ); | |||
| /* Engine */ | |||
| const Audio_Region *capture_region ( void ) const; | |||