diff --git a/mixer/src/Mixer.C b/mixer/src/Mixer.C index 7bc1632..df7b498 100644 --- a/mixer/src/Mixer.C +++ b/mixer/src/Mixer.C @@ -50,7 +50,7 @@ const double STATUS_UPDATE_FREQ = 0.2f; -const double OSC_INTERVAL = 0.2f; +const double OSC_INTERVAL = 1.0 / 20.0; /* 20 hz */ extern char *user_config_dir; extern char *instance_name; @@ -98,14 +98,13 @@ Mixer::reply_to_finger ( lo_message msg ) int argc = lo_message_get_argc( msg ); lo_arg **argv = lo_message_get_argv( msg ); - if ( argc < 2 ) + if ( argc < 1 ) return; - lo_address to = lo_address_new_from_url( &argv[1]->s ); + lo_address to = lo_address_new_from_url( &argv[0]->s ); osc_endpoint->send( to, - "/reply", - "/non/finger", + "/non/hello", osc_endpoint->url(), APP_NAME, VERSION, @@ -114,6 +113,24 @@ Mixer::reply_to_finger ( lo_message msg ) lo_address_free( to ); } +void +Mixer::say_hello ( void ) +{ + lo_message m = lo_message_new(); + + lo_message_add( m, "sssss", + "/non/hello", + osc_endpoint->url(), + APP_NAME, + VERSION, + instance_name ); + + nsm->broadcast( m ); + + lo_message_free( m ); +} + + static diff --git a/mixer/src/Mixer.H b/mixer/src/Mixer.H index 9289dbc..e8eeb8f 100644 --- a/mixer/src/Mixer.H +++ b/mixer/src/Mixer.H @@ -103,6 +103,8 @@ public: void sm_active ( bool b ); + void say_hello ( void ); + public: bool command_save ( void ); diff --git a/mixer/src/Module.C b/mixer/src/Module.C index adf35f5..41e38eb 100644 --- a/mixer/src/Module.C +++ b/mixer/src/Module.C @@ -218,14 +218,14 @@ Module::Port::generate_osc_path () char *path = NULL; - // /mixer/strip/STRIPNAME/control/MODULENAME/CONTROLNAME + // /mixer/STRIPNAME/MODULENAME/CONTROLNAME int n = module()->chain()->get_module_instance_number( module() ); if ( n > 0 ) - asprintf( &path, "/non/mixer/strip/%s/control/%s.%i/%s", module()->chain()->name(), p->module()->label(), n, p->name() ); + asprintf( &path, "/mixer/%s/%s.%i/%s", module()->chain()->name(), p->module()->label(), n, p->name() ); else - asprintf( &path, "/non/mixer/strip/%s/control/%s/%s", module()->chain()->name(), p->module()->label(), p->name() ); + asprintf( &path, "/mixer/%s/%s/%s", module()->chain()->name(), p->module()->label(), p->name() ); // Hack to keep spaces out of OSC URL... Probably need to handle other special characters similarly. for ( int i = strlen( path ); i--; ) @@ -240,36 +240,34 @@ Module::Port::generate_osc_path () void Module::Port::change_osc_path ( char *path ) { - if ( _osc_path ) + if ( _scaled_signal && _unscaled_signal ) { - mixer->osc_endpoint->del_method( _osc_path, "f" ); - mixer->osc_endpoint->del_method( _osc_path_unscaled, "f" ); - - free( _osc_path ); - free( _osc_path_unscaled ); - - _osc_path = NULL; - _osc_path_unscaled = NULL; + mixer->osc_endpoint->del_signal( _scaled_signal ); + mixer->osc_endpoint->del_signal( _unscaled_signal ); + + _scaled_signal = _unscaled_signal = NULL; } if ( path ) { - _osc_path_unscaled = NULL; - _osc_path = path; + char *scaled_path = path; + char *unscaled_path = NULL; + + asprintf( &unscaled_path, "%s/unscaled", path ); - asprintf( &_osc_path_unscaled, "%s/unscaled", path ); + _scaled_signal = mixer->osc_endpoint->add_signal( scaled_path, OSC::Signal::Input, &Module::Port::osc_control_change_cv, this ); - mixer->osc_endpoint->add_method( _osc_path, "f", &Module::Port::osc_control_change_cv, this, "value" ); + _unscaled_signal = mixer->osc_endpoint->add_signal( unscaled_path, OSC::Signal::Input, &Module::Port::osc_control_change_exact, this ); - mixer->osc_endpoint->add_method( _osc_path_unscaled, "f", &Module::Port::osc_control_change_exact, this, "value" ); + free( unscaled_path ); + free( scaled_path ); if ( hints.ranged ) { - mixer->osc_endpoint->set_parameter_limits( _osc_path_unscaled, "f", 0, - hints.minimum, - hints.maximum, - hints.default_value ); - + _unscaled_signal->parameter_limits( + hints.minimum, + hints.maximum, + hints.default_value ); } float scaled_default = 0.5f; @@ -277,25 +275,25 @@ Module::Port::change_osc_path ( char *path ) if ( hints.ranged ) { float scale = hints.maximum - hints.minimum; -// float offset = hints.minimum; + float offset = hints.minimum; - scaled_default = ( hints.default_value / scale ); + scaled_default = ( hints.default_value - offset ) / scale; } - mixer->osc_endpoint->set_parameter_limits( _osc_path, "f", 0, - 0.0f, - 1.0f, - scaled_default ); + _scaled_signal->parameter_limits( + 0.0f, + 1.0f, + scaled_default ); } } int -Module::Port::osc_control_change_exact ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +Module::Port::osc_control_change_exact ( float v, void *user_data ) { Module::Port *p = (Module::Port*)user_data; - float f = argv[0]->f; + float f = v; if ( p->hints.ranged ) { @@ -307,17 +305,17 @@ Module::Port::osc_control_change_exact ( const char *path, const char *types, lo p->control_value( f ); - mixer->osc_endpoint->send( lo_message_get_source( msg ), "/reply", path, f ); +// mixer->osc_endpoint->send( lo_message_get_source( msg ), "/reply", path, f ); return 0; } int -Module::Port::osc_control_change_cv ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +Module::Port::osc_control_change_cv ( float v, void *user_data ) { Module::Port *p = (Module::Port*)user_data; - float f = argv[0]->f; + float f = v; // clamp value to control voltage range. if ( f > 1.0 ) @@ -337,7 +335,7 @@ Module::Port::osc_control_change_cv ( const char *path, const char *types, lo_ar p->control_value( f ); - mixer->osc_endpoint->send( lo_message_get_source( msg ), "/reply", path, f ); +// mixer->osc_endpoint->send( lo_message_get_source( msg ), "/reply", path, f ); return 0; } diff --git a/mixer/src/Module.H b/mixer/src/Module.H index eb79c38..66e66a6 100644 --- a/mixer/src/Module.H +++ b/mixer/src/Module.H @@ -110,8 +110,8 @@ public: } }; - static int osc_control_change_exact ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); - static int osc_control_change_cv ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); + static int osc_control_change_exact ( float v, void *user_data ); + static int osc_control_change_cv ( float v, void *user_data ); Hints hints; @@ -124,8 +124,8 @@ public: _nframes = 0; _connected = 0; _module = module; - _osc_path = 0; - _osc_path_unscaled = 0; + _scaled_signal = 0; + _unscaled_signal = 0; } Port ( const Port& p ) @@ -138,8 +138,8 @@ public: _connected = p._connected; _module = p._module; hints = p.hints; - _osc_path = p._osc_path; - _osc_path_unscaled = p._osc_path_unscaled; + _scaled_signal = p._scaled_signal; + _unscaled_signal = p._unscaled_signal; } virtual ~Port ( ) @@ -160,7 +160,7 @@ public: const char *osc_path ( ) { - return _osc_path; + return _scaled_signal->path(); } void update_osc_port ( ) @@ -246,8 +246,8 @@ public: nframes_t _nframes; Module *_module; - char *_osc_path; - char *_osc_path_unscaled; + OSC::Signal *_scaled_signal; + OSC::Signal *_unscaled_signal; }; void bbox ( int &X, int &Y, int &W, int &H ) diff --git a/mixer/src/NSM.C b/mixer/src/NSM.C index 733d2df..41ac9d0 100644 --- a/mixer/src/NSM.C +++ b/mixer/src/NSM.C @@ -36,12 +36,12 @@ int command_open ( const char *name, const char *display_name, const char *clien int command_save ( char **out_msg ); int -NSM_Client::command_broadcast ( lo_message msg ) +NSM_Client::command_broadcast ( const char *path, lo_message msg ) { int argc = lo_message_get_argc( msg ); lo_arg **argv = lo_message_get_argv( msg ); - if ( argc > 1 && !strcmp( &argv[0]->s, "/non/finger" ) ) + if ( argc == 1 && !strcmp( path, "/non/finger" ) ) { mixer->reply_to_finger( msg ); return 0; diff --git a/mixer/src/NSM.H b/mixer/src/NSM.H index 45942fa..b289c00 100644 --- a/mixer/src/NSM.H +++ b/mixer/src/NSM.H @@ -36,5 +36,5 @@ protected: void command_active ( bool active ); - int command_broadcast ( lo_message msg ); + int command_broadcast ( const char *path, lo_message msg ); }; diff --git a/nonlib/NSM/Client.C b/nonlib/NSM/Client.C index 449b01a..88ac1df 100644 --- a/nonlib/NSM/Client.C +++ b/nonlib/NSM/Client.C @@ -123,11 +123,11 @@ namespace NSM void - Client::broadcast ( const char *path, const char *v1 ) + Client::broadcast ( lo_message msg ) { if ( nsm_is_active ) { - lo_send_from( nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/server/broadcast", "ss", path, v1 ); + lo_send_message_from( nsm_addr, _server, "/nsm/server/broadcast", msg ); } } @@ -164,7 +164,7 @@ namespace NSM lo_server_add_method( _server, "/nsm/client/open", "sss", &Client::osc_open, this ); lo_server_add_method( _server, "/nsm/client/save", "", &Client::osc_save, this ); lo_server_add_method( _server, "/nsm/client/session_is_loaded", "", &Client::osc_session_is_loaded, this ); - lo_server_add_method( _server, "/nsm/client/broadcast", NULL, &Client::osc_broadcast, this ); + lo_server_add_method( _server, NULL, NULL, &Client::osc_broadcast, this ); return 0; } @@ -183,7 +183,7 @@ namespace NSM lo_server_thread_add_method( _st, "/nsm/client/open", "sss", &Client::osc_open, this ); lo_server_thread_add_method( _st, "/nsm/client/save", "", &Client::osc_save, this ); lo_server_thread_add_method( _st, "/nsm/client/session_is_loaded", "", &Client::osc_session_is_loaded, this ); - lo_server_thread_add_method( _st, "/nsm/client/broadcast", NULL, &Client::osc_broadcast, this ); + lo_server_thread_add_method( _st, NULL, NULL, &Client::osc_broadcast, this ); return 0; } @@ -195,7 +195,7 @@ namespace NSM int Client::osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) { - return ((NSM::Client*)user_data)->command_broadcast( msg ); + return ((NSM::Client*)user_data)->command_broadcast( path, msg ); } int diff --git a/nonlib/NSM/Client.H b/nonlib/NSM/Client.H index 299a9d6..7e211c5 100644 --- a/nonlib/NSM/Client.H +++ b/nonlib/NSM/Client.H @@ -66,7 +66,7 @@ namespace NSM void message( int priority, const char *msg ); void announce ( const char *nsm_url, const char *appliction_name, const char *capabilities, const char *process_name ); - void broadcast ( const char *path, const char *v1 ); + void broadcast ( lo_message msg ); /* init without threading */ int init ( void ); @@ -91,7 +91,7 @@ namespace NSM virtual void command_session_is_loaded ( void ) { } /* invoked when an unrecognized message is received. Should return 0 if you handled it, -1 otherwise. */ - virtual int command_broadcast ( lo_message msg ) { return -1; } + virtual int command_broadcast ( const char *path, lo_message msg ) { return -1; } private: diff --git a/nonlib/OSC/Endpoint.C b/nonlib/OSC/Endpoint.C index 5c60d31..1bfdfe7 100644 --- a/nonlib/OSC/Endpoint.C +++ b/nonlib/OSC/Endpoint.C @@ -31,7 +31,51 @@ namespace OSC { + /**********/ + /* Method */ + /**********/ + Method::Method ( ) + { + _path = _typespec = _documentation = 0; + } + + Method::~Method ( ) + { + if ( _path ) + free( _path ); + if ( _typespec ) + free( _typespec ); + } + + /**********/ + /* Signal */ + /**********/ + + int Signal::next_id = 0; + + void + Signal::value ( float f ) + { + for ( std::list::const_iterator i = _outgoing.begin(); + i != _outgoing.end(); + ++i ) + { +// DMESSAGE( "Sending signal value %i %f", (*i)->signal_id, f ); + + if ( (*i)->value != f ) + { + (*i)->value = f; + + _endpoint->send( (*i)->peer->addr, + "/signal/change", + (*i)->signal_id, + f ); + } + } + } + + void Endpoint::error_handler(int num, const char *msg, const char *path) { @@ -55,13 +99,10 @@ namespace OSC return -1; } - // char *url = lo_server_get_url(_server); - // printf("OSC: %s\n",url); - // free(url); - - // add generic handler for path reporting. - add_method( "/osc/query/parameters", "s", osc_query_parameters, this, "" ); + add_method( "/signal/change", "if", &Endpoint::osc_sig_handler, this, "" ); add_method( NULL, "", &Endpoint::osc_generic, this, "" ); + add_method( NULL, NULL, &Endpoint::osc_signal_lister, this, "" ); + add_method( "/reply", NULL, &Endpoint::osc_reply, this, "" ); return 0; } @@ -73,62 +114,97 @@ namespace OSC lo_server_free( _server ); } - int - Endpoint::osc_query_parameters ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) + OSC::Target * + Endpoint::find_target_by_peer_address ( std::list *l, lo_address addr ) { - OSC_DMSG(); - - Endpoint *ep = (Endpoint*)user_data; - - const char *qpath = &argv[0]->s; - - Method_Data *md = NULL; - for ( std::list::iterator i = ep->_methods.begin(); i != ep->_methods.end(); ++i ) + for ( std::list::iterator i = l->begin(); + i != l->end(); + ++i ) { - if ( ! (*i)->path ) - continue; - - if ( ! strcmp( qpath, (*i)->path ) && (*i)->typespec ) + if ( address_matches( addr, (*i)->peer->addr ) ) { - md = *i; - - /* FIXME: what about the fact that there could be multiple messages with the same path but - different typespecs ? */ - break; + return *i; } } - if ( ! md ) + return NULL; + } + + OSC::Signal * + Endpoint::find_signal_by_id ( int id ) + { + for ( std::list::iterator i = _signals.begin(); + i != _signals.end(); + ++i ) { - ep->send( lo_message_get_source( msg ), "/error", path, - "Could not find specified path" ); + if ( (*i)->id() == id ) + return *i; + } + } - return 0; + int + Endpoint::osc_sig_handler ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) + { + Signal *o; + float f = 0.0; + + if ( !strcmp( path, "/signal/change" ) && !strcmp( types, "if" ) ) + { + /* accept a value for numbered signal */ + int id = argv[0]->i; + f = argv[1]->f; + o = ((Endpoint*)user_data)->find_signal_by_id( id ); + if ( ! o ) + { + WARNING( "Unknown signal id %i", id ); + return 0; + } + } + else if ( ! strcmp( types, "f" ) ) + { + /* accept a value for signal named in path */ + o = (Signal*)user_data; + f = argv[0]->f; + } + else if ( ! types || 0 == types[0] ) + { + /* reply with current value */ + o = (Signal*)user_data; + o->_endpoint->send( lo_message_get_source( msg ), "/reply", path, o->value() ); + } + else + { + return -1; } - char *r = (char*) malloc( 256 ); - r[0] = 0; + Target *t = NULL; - for ( int i = 0; i < strlen( md->typespec ); ++i ) + if ( 0 == o->_incoming.size() || + ! ( t = find_target_by_peer_address( &o->_incoming, lo_message_get_source( msg ) ) ) ) + { + /* message came from an unconnected peer, just set the value exactly */ + } + else { - char desc[50]; + /* message is from a connected source, do mixing. */ - snprintf( desc, sizeof(desc), "f:%f:%f:%f\n", - md->parameter_limits[i].min, - md->parameter_limits[i].max, - md->parameter_limits[i].default_value ); + t->value = f; - r = (char*)realloc( r, strlen( r ) + strlen( desc ) + 2 ); + f = 0.0; - strcat( r, desc ); - strcat( r, "\n" ); + for ( std::list::const_iterator i = o->_incoming.begin(); + i != o->_incoming.end(); + ++i ) + { + f += (*i)->value; + } } - ep->send( lo_message_get_source( msg ), "/reply", path, - qpath, - r ); + o->_value = f; + o->_handler( f, o->_user_data ); + return 0; } @@ -140,93 +216,269 @@ namespace OSC if ( path[ strlen(path) - 1 ] != '/' ) return -1; - char *paths = ((Endpoint*)user_data)->get_paths( path ); + Endpoint *ep = (Endpoint*)user_data; - ((Endpoint*)user_data)->send( lo_message_get_source( msg ), "/reply", path, paths ); + for ( std::list::const_iterator i = ep->_methods.begin(); i != ep->_methods.end(); ++i ) + { + if ( ! (*i)->path() ) + continue; - free(paths); + if (! strncmp( (*i)->path(), path, strlen(path) ) ) + { + /* asprintf( &stored_path, "%s (%s); %s", path, typespec, argument_description ); */ + + ((Endpoint*)user_data)->send( lo_message_get_source( msg ), "/reply", path, (*i)->path() ); + } + } + + ((Endpoint*)user_data)->send( lo_message_get_source( msg ), "/reply", path ); return 0; } - // returns a malloc()'d string containing path names beginning with /prefix/, newline separated - char * - Endpoint::get_paths ( const char *prefix ) + int + Endpoint::osc_signal_lister ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) { - char *r = (char*)malloc( 1024 ); - r[0] = 0; - - for ( std::list::const_iterator i = _methods.begin(); i != _methods.end(); ++i ) +// OSC_DMSG(); + + Signal::Direction dir; + + if ( ! strcmp( path, "/signal/list_inputs" ) ) { - if ( ! (*i)->path ) - continue; + dir = Signal::Input; + } + else if ( ! strcmp( path, "/signal/list_outputs" ) ) + { + dir = Signal::Output; + } + else + return -1; + + const char *prefix = NULL; + + if ( argc ) + prefix = &argv[0]->s; - if (! strncmp( (*i)->path, prefix, strlen(prefix) ) ) + Endpoint *ep = (Endpoint*)user_data; + + for ( std::list::const_iterator i = ep->_signals.begin(); i != ep->_signals.end(); ++i ) + { + Signal *o = *i; + + if ( dir == Signal::Bidirectional || + dir == o->_direction ) { - r = (char*)realloc( r, strlen( r ) + strlen( (*i)->path ) + 2 ); + if ( ! prefix || ! strncmp( o->path(), prefix, strlen(prefix) ) ) + { + ep->send( lo_message_get_source( msg ), + "/reply", + path, + o->path(), + o->id(), + o->parameter_limits().min, + o->parameter_limits().max, + o->parameter_limits().default_value + ); + } + } + } - /* asprintf( &stored_path, "%s (%s); %s", path, typespec, argument_description ); */ + ep->send( lo_message_get_source( msg ), "/reply", path ); + + return 0; + } + + bool + Endpoint::address_matches ( lo_address addr1, lo_address addr2 ) + { + char *purl = strdup( lo_address_get_port( addr1 ) ); + char *url = strdup( lo_address_get_port( addr2 ) ); + + bool r = !strcmp( purl, url ); + + free( purl ); + free( url ); - strcat( r, (*i)->path ); - strcat( r, "\n" ); + return r; + } + + + void + Endpoint::list_peers ( void (*callback) (const char *, const char *, int, void * ), void *v ) + { + for ( std::list::iterator i = _peers.begin(); + i != _peers.end(); + ++i ) + { + for ( std::list::iterator j = (*i)->_signals.begin(); + j != (*i)->_signals.end(); + ++j ) + { +// DMESSAGE( "Running callback" ); + callback( (*i)->name, (*j)->path(), (*j)->id(), v ); } } + } - return r; + Peer * + Endpoint::find_peer_by_address ( lo_address addr ) + { + char *url = strdup( lo_address_get_port( addr ) ); + + Peer *p = NULL; + + for ( std::list::iterator i = _peers.begin(); + i != _peers.end(); + ++i ) + { + char *purl = strdup( lo_address_get_port( (*i)->addr ) ); + + if ( !strcmp( purl, url ) ) + { + free( purl ); + p = *i; + break; + } + free(purl); + } + + free( url ); + + return p; } - void - Endpoint::set_parameter_limits ( const char *path, const char *typespec, - int index, - float min, float max, float default_value ) + Peer * + Endpoint::find_peer_by_name ( const char *name ) { - assert( typespec ); + for ( std::list::iterator i = _peers.begin(); + i != _peers.end(); + ++i ) + { + if ( !strcmp( name, (*i)->name ) ) + { + return *i; + } + } - assert( index < strlen( typespec ) ); + return NULL; + } - for ( std::list::iterator i = _methods.begin(); i != _methods.end(); ++i ) + /* First part of 'to' is a peer name */ + bool + Endpoint::connect_signal( OSC::Signal *s, const char *peer_name, int signal_id ) + { + if ( s->_direction == Signal::Output ) { - if ( ! (*i)->path ) - continue; + Peer *p = find_peer_by_name( peer_name ); - if ( ! strcmp( path, (*i)->path ) && - ! strcmp( typespec, (*i)->typespec ) ) + MESSAGE( "Connecting signal output \"%s\" to %s:%i", s->path(), peer_name, signal_id ); + + if ( p ) { - (*i)->parameter_limits[index].min = min; - (*i)->parameter_limits[index].max = max; - (*i)->parameter_limits[index].default_value = default_value; + Target *t = new Target(); + + t->peer = p; + t->signal_id = signal_id; + + s->_outgoing.push_back( t ); + + send( p->addr, "/signal/connect", + 0, /* FIXME: our signal id */ + 0 /* FIXME: their signal id */ ); + + return true; + } + } + + return false; + } - break; + + int + Endpoint::osc_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) + + { + Endpoint *ep = (Endpoint*)user_data; + + if ( argc && !strcmp( &argv[0]->s, "/signal/list_inputs" ) ) + { + Peer *p = ep->find_peer_by_address( lo_message_get_source( msg ) ); + + if ( ! p ) + { + WARNING( "Got input list reply from unknown peer." ); + return 0; + } + + if ( argc == 1 ) + { + p->_scanning = false; + DMESSAGE( "Done scanning %s", p->name ); } + else if ( p->_scanning ) + { + DMESSAGE( "Peer %s has signal %s", p->name, &argv[1]->s ); + + Signal *s = new Signal( &argv[1]->s, Signal::Input ); + + s->_id = argv[2]->i; + s->parameter_limits().min = argv[3]->f; + s->parameter_limits().max = argv[4]->f; + s->parameter_limits().default_value = argv[4]->f; + + p->_signals.push_back( s ); + } + + return 0; } + else + return -1; } - method_handle + Method * Endpoint::add_method ( const char *path, const char *typespec, lo_method_handler handler, void *user_data, const char *argument_description ) { // DMESSAGE( "Added OSC method %s (%s)", path, typespec ); lo_server_add_method( _server, path, typespec, handler, user_data ); - Method_Data *md = new Method_Data; + Method *md = new Method; if ( path ) - md->path = strdup( path ); + md->_path = strdup( path ); if ( typespec ) - md->typespec = strdup( typespec ); + md->_typespec = strdup( typespec ); if ( argument_description ) - md->documentation = strdup( argument_description ); + md->_documentation = strdup( argument_description ); if ( typespec ) - md->parameter_limits = new Parameter_Limits[strlen(typespec)]; + md->_parameter_limits = new Parameter_Limits[strlen(typespec)]; _methods.push_back( md ); return md; - - /* asprintf( &stored_path, "%s (%s); %s", path, typespec, argument_description ); */ + } + + Signal * + Endpoint::add_signal ( const char *path, Signal::Direction dir, signal_handler handler, void *user_data ) + { + Signal *md = new Signal( path, dir ); - /* _path_names.push_back( stored_path ); */ + if ( path ) + md->_path = strdup( path ); + + md->_handler = handler; + md->_user_data = user_data; + md->_endpoint = this; + + _signals.push_back( md ); + + if ( dir == Signal::Input ) + { + lo_server_add_method( _server, path, NULL, osc_sig_handler, md ); + } + + return md; } void @@ -236,13 +488,13 @@ namespace OSC lo_server_del_method( _server, path, typespec ); - for ( std::list::iterator i = _methods.begin(); i != _methods.end(); ++i ) + for ( std::list::iterator i = _methods.begin(); i != _methods.end(); ++i ) { - if ( ! (*i)->path ) + if ( ! (*i)->path() ) continue; - if ( ! strcmp( path, (*i)->path ) && - ! strcmp( typespec, (*i)->typespec ) ) + if ( ! strcmp( path, (*i)->path() ) && + ! strcmp( typespec, (*i)->typespec() ) ) { delete *i; i = _methods.erase( i ); @@ -253,36 +505,42 @@ namespace OSC } void - Endpoint::del_method ( const method_handle mh ) + Endpoint::del_method ( Method *meth ) { // DMESSAGE( "Deleted OSC method %s (%s)", path, typespec ); - Method_Data *meth = const_cast( (const Method_Data*)mh ); - - lo_server_del_method( _server, meth->path, meth->typespec ); + lo_server_del_method( _server, meth->path(), meth->typespec() ); delete meth; _methods.remove( meth ); + } + void + Endpoint::del_signal ( Signal *o ) + { +// DMESSAGE( "Deleted OSC method %s (%s)", path, typespec ); - /* for ( std::list::iterator i = _methods.begin(); i != _methods.end(); ++i ) */ - /* { */ - /* if ( ! (*i)->path ) */ - /* continue; */ + lo_server_del_method( _server, o->path(), "f" ); - /* if ( ! strcmp( path, (*i)->path ) && */ - /* ! strcmp( typespec, (*i)->typespec ) ) */ - /* { */ - /* delete *i; */ - /* i = _methods.erase( i ); */ + delete o; - /* break; */ - /* } */ - /* } */ + _signals.remove( o ); } + void + Endpoint::scan_peer ( const char *name, const char *url ) + { + Peer *p = new Peer; + + p->name = strdup( name ); + p->addr = lo_address_new_from_url( url ); + p->_scanning = true; + + _peers.push_back( p ); + send( p->addr, "/signal/list_inputs" ); + } void * Endpoint::osc_thread ( void * arg ) @@ -342,7 +600,7 @@ namespace OSC /** Process any waiting events and return after timeout */ void Endpoint::wait ( int timeout ) const - { + { if ( lo_server_wait( _server, timeout ) ) while ( lo_server_recv_noblock( _server, 0 ) ) { } } @@ -372,15 +630,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: @@ -389,7 +647,7 @@ namespace OSC } } -// DMESSAGE( "Path: %s", path ); + DMESSAGE( "Path: %s", path ); lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE ); @@ -460,7 +718,7 @@ namespace OSC int Endpoint::send ( lo_address to, const char *path, const char *v1, const char *v2, int v3, int v4, int v5 ) - { + { return lo_send_from( to, _server, LO_TT_IMMEDIATE, path, "ssiii", v1, v2, v3, v4, v5 ); } @@ -519,4 +777,27 @@ namespace OSC return lo_send_message_from( to, _server, path, msg ); } + int + Endpoint::send ( lo_address to, const char *path, const char *v1, const char *v2, int v3, float v4, float v5, float v6 ) + { + return lo_send_from( to, _server, LO_TT_IMMEDIATE, path, "ssifff", v1, v2, v3, v4, v5, v6 ); + } + + int + Endpoint::send ( lo_address to, const char *path, const char *v1, int v2, int v3 ) + { + return lo_send_from( to, _server, LO_TT_IMMEDIATE, path, "sii", v1, v2, v3 ); + } + + int + Endpoint::send ( lo_address to, const char *path, int v1, int v2 ) + { + return lo_send_from( to, _server, LO_TT_IMMEDIATE, path, "ii", v1, v2 ); + } + + int + Endpoint::send ( lo_address to, const char *path, int v1, float v2 ) + { + return lo_send_from( to, _server, LO_TT_IMMEDIATE, path, "if", v1, v2 ); + } } diff --git a/nonlib/OSC/Endpoint.H b/nonlib/OSC/Endpoint.H index cb9f38a..42a10b9 100644 --- a/nonlib/OSC/Endpoint.H +++ b/nonlib/OSC/Endpoint.H @@ -23,11 +23,10 @@ #include "Thread.H" #include #include +#include namespace OSC { - typedef void * method_handle; - class OSC_Value { @@ -107,83 +106,189 @@ namespace OSC } }; + struct Parameter_Limits + { + float min; + float max; + float default_value; + }; + + class Endpoint; + class Signal; + struct Peer + { + + bool _scanning; + + char *name; + lo_address addr; + + std::list _signals; + }; + + struct Target + { + Peer *peer; +// char *path; + int signal_id; + float value; + }; + + typedef int (*signal_handler) ( float value, void *user_data ); + + class Signal + { + static int next_id; + + public: + + enum Direction { + Input, + Output, + Bidirectional + }; + + private: + + Endpoint *_endpoint; + + int _id; + + char *_path; + char *_documentation; + + float _value; + + std::list _outgoing; + + Direction _direction; + + /* FIXME: + In order to support signal mixing, the receiver must track + each connected signal channel separately, and add the + values together before invoking the handler. + */ + std::list _incoming; + + signal_handler _handler; + void *_user_data; + + public: + + Parameter_Limits _parameter_limits; + + Signal ( const char *path, Direction dir ) + { + _direction = dir; + _path = strdup( path ); + _id = ++next_id; + _value = 0.0f; + } + + ~Signal ( ) + { + free( _path ); + } + + bool connected ( void ) { return _outgoing.size() + _incoming.size(); } + + int id ( void ) { return _id; } + + Direction direction ( void ) { return _direction; } + + void parameter_limits ( float min, float max, float default_value ) + { + _parameter_limits.min = min; + _parameter_limits.max = max; + _parameter_limits.default_value = default_value; + _value = default_value; + } + + Parameter_Limits& parameter_limits ( void ) { return _parameter_limits; } + + const char *path ( void ) { return _path; } + + /* publishes value to targets */ + void value ( float v ); + /* get current value */ + float value ( void ) { return _value; } + + friend class Endpoint; + }; + + class Method + { + char *_path; + char *_typespec; + char *_documentation; + struct Parameter_Limits *_parameter_limits; + + public: + + const char *path ( void ) { return _path; } + const char *typespec ( void ) { return _typespec; } + + Method ( ); + ~Method ( ); + + friend class Endpoint; + }; + + class Endpoint { static void error_handler(int num, const char *msg, const char *path); + static int osc_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); + + static int osc_signal_lister ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); static int osc_generic ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); - static int osc_query_parameters ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); + static int osc_sig_handler ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); Thread _thread; // lo_server_thread _st; lo_server _server; - - struct Parameter_Limits - { - float min; - float max; - float default_value; - }; - - struct Method_Data - { - char *path; - char *typespec; - char *documentation; - struct Parameter_Limits *parameter_limits; - std::list subscribers; - - Method_Data ( ) - { - path = typespec = documentation = 0; - parameter_limits = 0; - } - - ~Method_Data ( ) - { - if ( path ) - free( path ); - if ( typespec ) - free( typespec ); - if ( parameter_limits ) - free( parameter_limits ); - - for ( std::list::iterator i = subscribers.begin(); - i != subscribers.end(); - ++i ) - { - lo_address_free( *i ); - } - - subscribers.clear(); - } - }; - - std::list _methods; + std::list _peers; + std::list _signals; + std::list _methods; static void *osc_thread ( void *arg ); void osc_thread ( void ); + OSC::Signal *find_signal_by_id ( int id ); + + Peer *find_peer_by_name ( const char *name ); + Peer *find_peer_by_address ( lo_address addr ); + static bool address_matches ( lo_address addr1, lo_address addr2 ); + + static Target *find_target_by_peer_address ( std::list *l, lo_address addr ); + public: + void list_peers ( void (*callback) (const char *, const char *, int, void * ), void *v ); + int init ( const char *port = 0 ); Endpoint ( ); ~Endpoint ( ); - char *get_paths ( const char *prefix ); - method_handle add_method ( const char *path, const char *typespec, lo_method_handler handler, void *user_data, const char *argument_description ); + bool connect_signal( OSC::Signal *s, const char *peer_name, int signal_id ); + + + Signal *add_signal ( const char *path, Signal::Direction dir, 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 ); - void del_method ( const method_handle ); + void del_method ( Method* method ); + void del_signal ( Signal *signal ); void start ( void ); void stop ( void ); int port ( void ) const; char * url ( void ) const; - void set_parameter_limits ( const char *path, const char *typespec, int index, float min, float max, float default_value ); + void scan_peer ( const char *name, const char *url ); void check ( void ) const; void wait ( int timeout ) const; @@ -197,8 +302,11 @@ namespace OSC int send ( lo_address to, const char *path, double v ); int send ( lo_address to, const char *path, int v ); int send ( lo_address to, const char *path, long v ); - int send ( lo_address to, const char *path, const char * v1, float v2 ); + int send ( lo_address to, const char *path, int v1, int v2 ); + int send ( lo_address to, const char *path, int v1, float v2 ); int send ( lo_address to, const char *path, const char *v ); + int send ( lo_address to, const char *path, const char *v1, float v2 ); + int send ( lo_address to, const char *path, const char *v1, int v2, int v3 ); int send ( lo_address to, const char *path, const char *v1, const char *v2 ); int send ( lo_address to, const char *path, const char *v1, const char *v2, const char *v3 ); int send ( lo_address to, const char *path, const char *v1, int v2, int v3, int v4 ); @@ -216,6 +324,8 @@ namespace OSC int send ( lo_address to, const char *path, lo_message msg ); + int send ( lo_address to, const char *path, const char *v1, const char *v2, int v3, float v4, float v5, float v6 ); + // can be used to point back to owning object. void *owner; }; diff --git a/session/src/nsmd.C b/session/src/nsmd.C index c6b2709..c64225c 100644 --- a/session/src/nsmd.C +++ b/session/src/nsmd.C @@ -349,8 +349,11 @@ set_name ( const char *name ) bool address_matches ( lo_address addr1, lo_address addr2 ) { - char *url1 = lo_address_get_url( addr1 ); - char *url2 = lo_address_get_url( addr2 ); + /* char *url1 = lo_address_get_url( addr1 ); */ + /* char *url2 = lo_address_get_url( addr2 ); */ + + char *url1 = strdup( lo_address_get_port( addr1 ) ); + char *url2 = strdup(lo_address_get_port( addr2 ) ); bool r = !strcmp( url1, url2 ); @@ -1464,7 +1467,7 @@ OSC_HANDLER( broadcast ) if ( strcmp( sender_url, url ) ) { - osc_server->send( (*i)->addr, "/nsm/client/broadcast", new_args ); + osc_server->send( (*i)->addr, to_path, new_args ); } free( url ); diff --git a/timeline/src/Control_Sequence.C b/timeline/src/Control_Sequence.C index 6dcc17f..451fdd9 100644 --- a/timeline/src/Control_Sequence.C +++ b/timeline/src/Control_Sequence.C @@ -30,6 +30,8 @@ #include using std::list; +#include "Transport.H" + bool Control_Sequence::draw_with_gradient = true; @@ -38,6 +40,8 @@ bool Control_Sequence::draw_with_grid = true; +const double OSC_INTERVAL = 1.0f / 20.0f; + Control_Sequence::Control_Sequence ( Track *track ) : Sequence( 0 ) { init(); @@ -51,10 +55,20 @@ Control_Sequence::Control_Sequence ( Track *track ) : Sequence( 0 ) FATAL( "could not create JACK port" ); } + { + char *path; + asprintf( &path, "/non/daw/%s/control/%i", track->name(), track->ncontrols() ); + + _osc_output = timeline->osc->add_signal( path, OSC::Signal::Output, NULL, NULL ); + + free( path ); + } + if ( track ) track->add( this ); log_create(); + } @@ -88,8 +102,10 @@ Control_Sequence::init ( void ) _track = NULL; _highlighted = false; _output = NULL; - + _osc_output = NULL; color( fl_darker( FL_YELLOW ) ); + + Fl::add_timeout( OSC_INTERVAL, &Control_Sequence::process_osc, this ); } @@ -282,6 +298,69 @@ Control_Sequence::draw ( void ) fl_pop_clip(); } +#include "FL/menu_popup.H" + +void +Control_Sequence::menu_cb ( Fl_Widget *w, void *v ) +{ + ((Control_Sequence*)v)->menu_cb( (const Fl_Menu_*)w ); +} + +void +Control_Sequence::menu_cb ( const Fl_Menu_ *m ) +{ + char picked[1024]; + + if ( ! m->mvalue() ) // || m->mvalue()->flags & FL_SUBMENU_POINTER || m->mvalue()->flags & FL_SUBMENU ) + return; + + m->item_pathname( picked, sizeof( picked ), m->mvalue() ); + + // DMESSAGE( "Picked: %s (%s)", picked, m->mvalue()->label() ); + + + if ( ! _osc_output ) + { + char *path; + asprintf( &path, "/non/daw/%s/control/%i", track()->name(), track()->ncontrols() ); + + _osc_output = timeline->osc->add_signal( path, OSC::Signal::Output, NULL, NULL ); + + free( path ); + } + + /* FIXME: somebody has to free these unsigned longs */ + unsigned long id = *(unsigned long*)m->mvalue()->user_data(); + + char *peer_name = index( picked, '/' ) + 1; + + *index( peer_name, '/' ) = 0; + + timeline->osc->connect_signal( _osc_output, peer_name, id ); +} + + +void +Control_Sequence::process_osc ( void *v ) +{ + ((Control_Sequence*)v)->process_osc(); +} + +void +Control_Sequence::process_osc ( void ) +{ + Fl::add_timeout( OSC_INTERVAL, &Control_Sequence::process_osc, this ); + + 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] ); + } +} + int Control_Sequence::handle ( int m ) { @@ -319,33 +398,55 @@ Control_Sequence::handle ( int m ) } else if ( Fl::event_button3() && ! ( Fl::event_state() & ( FL_ALT | FL_SHIFT | FL_CTRL ) ) ) { + timeline->discover_peers(); - Fl_Menu_Item menu[] = - { - { "Rename" }, - { "Remove" }, - { 0 } - }; + Fl_Menu_Button menu( 0, 0, 0, 0, "Control Sequence" ); - const Fl_Menu_Item *r = menu->popup( Fl::event_x(), Fl::event_y(), "Control Sequence" ); + /* Fl_Menu_Button *con = new Fl_Menu_Button( 0, 0, 0, 0 ); */ - if ( r ) - { - if ( r == &menu[ 0 ] ) - { - const char *s = fl_input( "Input new name for control sequence:", name() ); +// con->callback( &Control_Sequence::menu_cb, (void*)this ); - if ( s ) - name( s ); + menu.clear(); - redraw(); - } - else if ( r == &menu[ 1 ] ) - { - Fl::delete_widget( this ); - } + timeline->add_osc_peers_to_menu( &menu, "Connect To" ); + + /* menu.add( "Connect To", 0, 0, 0); */ + /* menu.add( "Connect To", 0, 0, const_cast< Fl_Menu_Item *>( con->menu() ), FL_SUBMENU_POINTER ); */ + menu.add( "Rename", 0, 0, 0 ); + menu.add( "Remove", 0, 0, 0 ); - } + + menu.callback( &Control_Sequence::menu_cb, (void*)this); + /* Fl_Menu_Item menu[] = */ + /* { */ + /* { "Rename" }, */ + /* { "Remove" }, */ + /* { "Connect To" }, */ + + /* { 0 } */ + /* }; */ + + menu_popup( &menu, x(), y() ); + +// const Fl_Menu_Item *r = menu.popup( Fl::event_x(), Fl::event_y(), "Control Sequence" ); + + /* if ( r ) */ + /* { */ + /* if ( r == &menu[ 0 ] ) */ + /* { */ + /* const char *s = fl_input( "Input new name for control sequence:", name() ); */ + + /* if ( s ) */ + /* name( s ); */ + + /* redraw(); */ + /* } */ + /* else if ( r == &menu[ 1 ] ) */ + /* { */ + /* Fl::delete_widget( this ); */ + /* } */ + + /* } */ return 1; } diff --git a/timeline/src/Control_Sequence.H b/timeline/src/Control_Sequence.H index 368a773..f4cc110 100644 --- a/timeline/src/Control_Sequence.H +++ b/timeline/src/Control_Sequence.H @@ -26,6 +26,7 @@ #include "JACK/Port.H" // class JACK::Port; +#include "OSC/Endpoint.H" class Control_Sequence : public Sequence { @@ -41,6 +42,8 @@ private: JACK::Port *_output; + OSC::Signal *_osc_output; + bool _highlighted; curve_type_e _type; @@ -49,6 +52,13 @@ private: void draw_curve ( bool flip, bool filled ); + static void menu_cb ( Fl_Widget *w, void *v ); + void menu_cb ( const Fl_Menu_ *m ); + + static void process_osc ( void *v ); + void process_osc ( void ); + + protected: diff --git a/timeline/src/Engine/Control_Sequence.C b/timeline/src/Engine/Control_Sequence.C index e77ea6f..e88419e 100644 --- a/timeline/src/Engine/Control_Sequence.C +++ b/timeline/src/Engine/Control_Sequence.C @@ -54,7 +54,7 @@ sigmoid_interpolate ( float y1, float y2, float mu ) nframes_t Control_Sequence::play ( sample_t *buf, nframes_t frame, nframes_t nframes ) { - THREAD_ASSERT( RT ); + // THREAD_ASSERT( RT ); Control_Point *p2, *p1 = (Control_Point*)&_widgets.front(); diff --git a/timeline/src/NSM.C b/timeline/src/NSM.C index 937a595..3fd2e26 100644 --- a/timeline/src/NSM.C +++ b/timeline/src/NSM.C @@ -91,12 +91,12 @@ NSM_Client::command_session_is_loaded ( void ) } int -NSM_Client::command_broadcast ( lo_message msg ) +NSM_Client::command_broadcast ( const char *path, lo_message msg ) { int argc = lo_message_get_argc( msg ); lo_arg **argv = lo_message_get_argv( msg ); - if ( argc > 1 && !strcmp( &argv[0]->s, "/non/finger" ) ) + if ( argc == 1 && !strcmp( path, "/non/finger" ) ) { timeline->reply_to_finger( msg ); return 0; diff --git a/timeline/src/NSM.H b/timeline/src/NSM.H index deb4ab8..bab3d61 100644 --- a/timeline/src/NSM.H +++ b/timeline/src/NSM.H @@ -35,5 +35,5 @@ protected: int command_save ( char **out_msg ); void command_session_is_loaded ( void ); - int command_broadcast ( lo_message msg ); + int command_broadcast ( const char *path, lo_message msg ); }; diff --git a/timeline/src/Timeline.C b/timeline/src/Timeline.C index 0a27811..11c5ae4 100644 --- a/timeline/src/Timeline.C +++ b/timeline/src/Timeline.C @@ -1517,6 +1517,8 @@ Timeline::command_load ( const char *name, const char *display_name ) Project::set_name ( display_name ? display_name : name ); + discover_peers(); + return true; } @@ -1539,6 +1541,9 @@ Timeline::command_new ( const char *name, const char *display_name ) /* tle->update_menu(); */ /* tle->main_window->redraw(); */ + + discover_peers(); + } const char * @@ -1573,7 +1578,7 @@ Timeline::init_osc ( const char *osc_port ) printf( "OSC=%s\n", osc->url() ); - osc->add_method( "/reply", NULL, &Timeline::osc_reply, osc, "" ); + osc->add_method( "/non/hello", "ssss", &Timeline::osc_non_hello, osc, "" ); // osc->start(); @@ -1584,19 +1589,23 @@ Timeline::init_osc ( const char *osc_port ) } int -Timeline::osc_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) +Timeline::osc_non_hello ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) { OSC_DMSG(); - if ( argc >= 5 && !strcmp( &argv[0]->s, "/non/finger" ) ) + if ( argc >= 4 ) { - const char *url = &argv[1]->s; - const char *name = &argv[2]->s; - const char *version = &argv[3]->s; - const char *id = &argv[4]->s; + 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 OSC peer %s (%s) @ %s with ID \"%s\"", name, version, url, id ); + MESSAGE( "Scanning..." ); + + timeline->osc->scan_peer( id, url ); + return 0; } @@ -1609,14 +1618,13 @@ Timeline::reply_to_finger ( lo_message msg ) int argc = lo_message_get_argc( msg ); lo_arg **argv = lo_message_get_argv( msg ); - if ( argc < 2 ) + if ( argc < 1 ) return; - lo_address reply = lo_address_new_from_url( &argv[1]->s ); + lo_address reply = lo_address_new_from_url( &argv[0]->s ); osc->send( reply, - "/reply", - "/non/finger", + "/non/hello", osc->url(), APP_NAME, VERSION, @@ -1625,10 +1633,49 @@ Timeline::reply_to_finger ( lo_message msg ) lo_address_free( reply ); } - void Timeline::discover_peers ( void ) { - nsm->broadcast( "/non/finger", osc->url() ); + lo_message m = lo_message_new(); + + lo_message_add_string( m, "/non/finger" ); + lo_message_add_string( m, osc->url() ); + + nsm->broadcast( m ); + + lo_message_free( m ); +} + +void +Timeline::peer_callback( const char *name, const char *path, int id, void *v ) +{ + ((Timeline*)v)->peer_callback2( name, path, id ); +} + +static Fl_Menu_Button *peer_menu; +static const char *peer_prefix; + +void +Timeline::peer_callback2( const char *name, const char *path, int id ) +{ + char *s; + + asprintf( &s, "%s/%s/%s", peer_prefix, name, path ); + + /* FIXME: Somebody has to free these unsigned longs! */ + peer_menu->add( s, 0, NULL, new unsigned long( id ) ); + + free( s ); +} + +void +Timeline::add_osc_peers_to_menu ( Fl_Menu_Button *m, const char *prefix ) +{ + peer_menu = m; + peer_prefix = prefix; + + osc->list_peers( &Timeline::peer_callback, this ); } + + diff --git a/timeline/src/Timeline.H b/timeline/src/Timeline.H index baf1ed0..a7196a8 100644 --- a/timeline/src/Timeline.H +++ b/timeline/src/Timeline.H @@ -87,8 +87,7 @@ class Timeline : public Fl_Single_Window, public RWLock { static void draw_clip ( void * v, int X, int Y, int W, int H ); - OSC::Endpoint *osc; - + int _old_xposition; int _old_yposition; @@ -120,6 +119,8 @@ class Timeline : public Fl_Single_Window, public RWLock public: + OSC::Endpoint *osc; + #undef Bars #undef Beats #undef None @@ -232,6 +233,12 @@ public: /* OSC */ + static void peer_callback( const char *name, const char *path, int id, void *v ); + void peer_callback2( const char *name, const char *path, int id ); + + + void add_osc_peers_to_menu ( Fl_Menu_Button *m, const char *prefix ); + void discover_peers ( void ); static void check_osc ( void * v ); @@ -239,7 +246,9 @@ public: int init_osc ( const char *osc_port ); static int osc_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); + 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 ); private: