OSC: Implement generic signal model with path auto discovery through NSM.
This commit is contained in:
parent
dca72cb455
commit
7cfa1ec38a
|
@ -50,7 +50,7 @@
|
||||||
|
|
||||||
const double STATUS_UPDATE_FREQ = 0.2f;
|
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 *user_config_dir;
|
||||||
extern char *instance_name;
|
extern char *instance_name;
|
||||||
|
@ -98,14 +98,13 @@ Mixer::reply_to_finger ( lo_message msg )
|
||||||
int argc = lo_message_get_argc( msg );
|
int argc = lo_message_get_argc( msg );
|
||||||
lo_arg **argv = lo_message_get_argv( msg );
|
lo_arg **argv = lo_message_get_argv( msg );
|
||||||
|
|
||||||
if ( argc < 2 )
|
if ( argc < 1 )
|
||||||
return;
|
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,
|
osc_endpoint->send( to,
|
||||||
"/reply",
|
"/non/hello",
|
||||||
"/non/finger",
|
|
||||||
osc_endpoint->url(),
|
osc_endpoint->url(),
|
||||||
APP_NAME,
|
APP_NAME,
|
||||||
VERSION,
|
VERSION,
|
||||||
|
@ -114,6 +113,24 @@ Mixer::reply_to_finger ( lo_message msg )
|
||||||
lo_address_free( to );
|
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
|
static
|
||||||
|
|
|
@ -103,6 +103,8 @@ public:
|
||||||
|
|
||||||
void sm_active ( bool b );
|
void sm_active ( bool b );
|
||||||
|
|
||||||
|
void say_hello ( void );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool command_save ( void );
|
bool command_save ( void );
|
||||||
|
|
|
@ -218,14 +218,14 @@ Module::Port::generate_osc_path ()
|
||||||
|
|
||||||
char *path = NULL;
|
char *path = NULL;
|
||||||
|
|
||||||
// /mixer/strip/STRIPNAME/control/MODULENAME/CONTROLNAME
|
// /mixer/STRIPNAME/MODULENAME/CONTROLNAME
|
||||||
|
|
||||||
int n = module()->chain()->get_module_instance_number( module() );
|
int n = module()->chain()->get_module_instance_number( module() );
|
||||||
|
|
||||||
if ( n > 0 )
|
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
|
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.
|
// Hack to keep spaces out of OSC URL... Probably need to handle other special characters similarly.
|
||||||
for ( int i = strlen( path ); i--; )
|
for ( int i = strlen( path ); i--; )
|
||||||
|
@ -240,36 +240,34 @@ Module::Port::generate_osc_path ()
|
||||||
void
|
void
|
||||||
Module::Port::change_osc_path ( char *path )
|
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_signal( _scaled_signal );
|
||||||
mixer->osc_endpoint->del_method( _osc_path_unscaled, "f" );
|
mixer->osc_endpoint->del_signal( _unscaled_signal );
|
||||||
|
|
||||||
free( _osc_path );
|
_scaled_signal = _unscaled_signal = NULL;
|
||||||
free( _osc_path_unscaled );
|
|
||||||
|
|
||||||
_osc_path = NULL;
|
|
||||||
_osc_path_unscaled = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( path )
|
if ( path )
|
||||||
{
|
{
|
||||||
_osc_path_unscaled = NULL;
|
char *scaled_path = path;
|
||||||
_osc_path = path;
|
char *unscaled_path = NULL;
|
||||||
|
|
||||||
asprintf( &_osc_path_unscaled, "%s/unscaled", path );
|
asprintf( &unscaled_path, "%s/unscaled", path );
|
||||||
|
|
||||||
mixer->osc_endpoint->add_method( _osc_path, "f", &Module::Port::osc_control_change_cv, this, "value" );
|
_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_unscaled, "f", &Module::Port::osc_control_change_exact, this, "value" );
|
_unscaled_signal = mixer->osc_endpoint->add_signal( unscaled_path, OSC::Signal::Input, &Module::Port::osc_control_change_exact, this );
|
||||||
|
|
||||||
|
free( unscaled_path );
|
||||||
|
free( scaled_path );
|
||||||
|
|
||||||
if ( hints.ranged )
|
if ( hints.ranged )
|
||||||
{
|
{
|
||||||
mixer->osc_endpoint->set_parameter_limits( _osc_path_unscaled, "f", 0,
|
_unscaled_signal->parameter_limits(
|
||||||
hints.minimum,
|
hints.minimum,
|
||||||
hints.maximum,
|
hints.maximum,
|
||||||
hints.default_value );
|
hints.default_value );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float scaled_default = 0.5f;
|
float scaled_default = 0.5f;
|
||||||
|
@ -277,25 +275,25 @@ Module::Port::change_osc_path ( char *path )
|
||||||
if ( hints.ranged )
|
if ( hints.ranged )
|
||||||
{
|
{
|
||||||
float scale = hints.maximum - hints.minimum;
|
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,
|
_scaled_signal->parameter_limits(
|
||||||
0.0f,
|
0.0f,
|
||||||
1.0f,
|
1.0f,
|
||||||
scaled_default );
|
scaled_default );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
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;
|
Module::Port *p = (Module::Port*)user_data;
|
||||||
|
|
||||||
float f = argv[0]->f;
|
float f = v;
|
||||||
|
|
||||||
if ( p->hints.ranged )
|
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 );
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
Module::Port *p = (Module::Port*)user_data;
|
||||||
|
|
||||||
float f = argv[0]->f;
|
float f = v;
|
||||||
|
|
||||||
// clamp value to control voltage range.
|
// clamp value to control voltage range.
|
||||||
if ( f > 1.0 )
|
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 );
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_exact ( float v, 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_cv ( float v, void *user_data );
|
||||||
|
|
||||||
Hints hints;
|
Hints hints;
|
||||||
|
|
||||||
|
@ -124,8 +124,8 @@ public:
|
||||||
_nframes = 0;
|
_nframes = 0;
|
||||||
_connected = 0;
|
_connected = 0;
|
||||||
_module = module;
|
_module = module;
|
||||||
_osc_path = 0;
|
_scaled_signal = 0;
|
||||||
_osc_path_unscaled = 0;
|
_unscaled_signal = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Port ( const Port& p )
|
Port ( const Port& p )
|
||||||
|
@ -138,8 +138,8 @@ public:
|
||||||
_connected = p._connected;
|
_connected = p._connected;
|
||||||
_module = p._module;
|
_module = p._module;
|
||||||
hints = p.hints;
|
hints = p.hints;
|
||||||
_osc_path = p._osc_path;
|
_scaled_signal = p._scaled_signal;
|
||||||
_osc_path_unscaled = p._osc_path_unscaled;
|
_unscaled_signal = p._unscaled_signal;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Port ( )
|
virtual ~Port ( )
|
||||||
|
@ -160,7 +160,7 @@ public:
|
||||||
|
|
||||||
const char *osc_path ( )
|
const char *osc_path ( )
|
||||||
{
|
{
|
||||||
return _osc_path;
|
return _scaled_signal->path();
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_osc_port ( )
|
void update_osc_port ( )
|
||||||
|
@ -246,8 +246,8 @@ public:
|
||||||
nframes_t _nframes;
|
nframes_t _nframes;
|
||||||
Module *_module;
|
Module *_module;
|
||||||
|
|
||||||
char *_osc_path;
|
OSC::Signal *_scaled_signal;
|
||||||
char *_osc_path_unscaled;
|
OSC::Signal *_unscaled_signal;
|
||||||
};
|
};
|
||||||
|
|
||||||
void bbox ( int &X, int &Y, int &W, int &H )
|
void bbox ( int &X, int &Y, int &W, int &H )
|
||||||
|
|
|
@ -36,12 +36,12 @@ int command_open ( const char *name, const char *display_name, const char *clien
|
||||||
int command_save ( char **out_msg );
|
int command_save ( char **out_msg );
|
||||||
|
|
||||||
int
|
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 );
|
int argc = lo_message_get_argc( msg );
|
||||||
lo_arg **argv = lo_message_get_argv( 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 );
|
mixer->reply_to_finger( msg );
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -36,5 +36,5 @@ protected:
|
||||||
|
|
||||||
void command_active ( bool active );
|
void command_active ( bool active );
|
||||||
|
|
||||||
int command_broadcast ( lo_message msg );
|
int command_broadcast ( const char *path, lo_message msg );
|
||||||
};
|
};
|
||||||
|
|
|
@ -123,11 +123,11 @@ namespace NSM
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Client::broadcast ( const char *path, const char *v1 )
|
Client::broadcast ( lo_message msg )
|
||||||
{
|
{
|
||||||
if ( nsm_is_active )
|
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/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/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/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;
|
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/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/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/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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@ namespace NSM
|
||||||
int
|
int
|
||||||
Client::osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
|
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
|
int
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace NSM
|
||||||
void message( int priority, const char *msg );
|
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 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 */
|
/* init without threading */
|
||||||
int init ( void );
|
int init ( void );
|
||||||
|
@ -91,7 +91,7 @@ namespace NSM
|
||||||
virtual void command_session_is_loaded ( void ) { }
|
virtual void command_session_is_loaded ( void ) { }
|
||||||
|
|
||||||
/* invoked when an unrecognized message is received. Should return 0 if you handled it, -1 otherwise. */
|
/* 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:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,51 @@
|
||||||
namespace OSC
|
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<Target*>::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
|
void
|
||||||
Endpoint::error_handler(int num, const char *msg, const char *path)
|
Endpoint::error_handler(int num, const char *msg, const char *path)
|
||||||
{
|
{
|
||||||
|
@ -55,13 +99,10 @@ namespace OSC
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// char *url = lo_server_get_url(_server);
|
add_method( "/signal/change", "if", &Endpoint::osc_sig_handler, this, "" );
|
||||||
// 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( NULL, "", &Endpoint::osc_generic, 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -73,62 +114,97 @@ namespace OSC
|
||||||
lo_server_free( _server );
|
lo_server_free( _server );
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
OSC::Target *
|
||||||
Endpoint::osc_query_parameters ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
|
Endpoint::find_target_by_peer_address ( std::list<Target*> *l, lo_address addr )
|
||||||
{
|
{
|
||||||
OSC_DMSG();
|
|
||||||
|
|
||||||
Endpoint *ep = (Endpoint*)user_data;
|
|
||||||
|
|
||||||
const char *qpath = &argv[0]->s;
|
for ( std::list<Target*>::iterator i = l->begin();
|
||||||
|
i != l->end();
|
||||||
Method_Data *md = NULL;
|
++i )
|
||||||
|
|
||||||
for ( std::list<Method_Data *>::iterator i = ep->_methods.begin(); i != ep->_methods.end(); ++i )
|
|
||||||
{
|
{
|
||||||
if ( ! (*i)->path )
|
if ( address_matches( addr, (*i)->peer->addr ) )
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( ! strcmp( qpath, (*i)->path ) && (*i)->typespec )
|
|
||||||
{
|
{
|
||||||
md = *i;
|
return *i;
|
||||||
|
|
||||||
/* FIXME: what about the fact that there could be multiple messages with the same path but
|
|
||||||
different typespecs ? */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! md )
|
return NULL;
|
||||||
{
|
}
|
||||||
ep->send( lo_message_get_source( msg ), "/error", path,
|
|
||||||
"Could not find specified path" );
|
|
||||||
|
|
||||||
return 0;
|
OSC::Signal *
|
||||||
|
Endpoint::find_signal_by_id ( int id )
|
||||||
|
{
|
||||||
|
for ( std::list<Signal*>::iterator i = _signals.begin();
|
||||||
|
i != _signals.end();
|
||||||
|
++i )
|
||||||
|
{
|
||||||
|
if ( (*i)->id() == id )
|
||||||
|
return *i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
Target *t = NULL;
|
||||||
r[0] = 0;
|
|
||||||
|
|
||||||
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 ) ) ) )
|
||||||
{
|
{
|
||||||
char desc[50];
|
/* message came from an unconnected peer, just set the value exactly */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* message is from a connected source, do mixing. */
|
||||||
|
|
||||||
snprintf( desc, sizeof(desc), "f:%f:%f:%f\n",
|
t->value = f;
|
||||||
md->parameter_limits[i].min,
|
|
||||||
md->parameter_limits[i].max,
|
|
||||||
md->parameter_limits[i].default_value );
|
|
||||||
|
|
||||||
r = (char*)realloc( r, strlen( r ) + strlen( desc ) + 2 );
|
f = 0.0;
|
||||||
|
|
||||||
strcat( r, desc );
|
for ( std::list<Target*>::const_iterator i = o->_incoming.begin();
|
||||||
strcat( r, "\n" );
|
i != o->_incoming.end();
|
||||||
|
++i )
|
||||||
|
{
|
||||||
|
f += (*i)->value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ep->send( lo_message_get_source( msg ), "/reply", path,
|
o->_value = f;
|
||||||
qpath,
|
|
||||||
r );
|
|
||||||
|
|
||||||
|
o->_handler( f, o->_user_data );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,93 +216,269 @@ namespace OSC
|
||||||
if ( path[ strlen(path) - 1 ] != '/' )
|
if ( path[ strlen(path) - 1 ] != '/' )
|
||||||
return -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<Method*>::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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns a malloc()'d string containing path names beginning with /prefix/, newline separated
|
int
|
||||||
char *
|
Endpoint::osc_signal_lister ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
|
||||||
Endpoint::get_paths ( const char *prefix )
|
|
||||||
{
|
{
|
||||||
char *r = (char*)malloc( 1024 );
|
// OSC_DMSG();
|
||||||
r[0] = 0;
|
|
||||||
|
Signal::Direction dir;
|
||||||
for ( std::list<Method_Data*>::const_iterator i = _methods.begin(); i != _methods.end(); ++i )
|
|
||||||
|
if ( ! strcmp( path, "/signal/list_inputs" ) )
|
||||||
{
|
{
|
||||||
if ( ! (*i)->path )
|
dir = Signal::Input;
|
||||||
continue;
|
}
|
||||||
|
else if ( ! strcmp( path, "/signal/list_outputs" ) )
|
||||||
|
{
|
||||||
|
dir = Signal::Output;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (! strncmp( (*i)->path, prefix, strlen(prefix) ) )
|
const char *prefix = NULL;
|
||||||
|
|
||||||
|
if ( argc )
|
||||||
|
prefix = &argv[0]->s;
|
||||||
|
|
||||||
|
Endpoint *ep = (Endpoint*)user_data;
|
||||||
|
|
||||||
|
for ( std::list<Signal*>::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) ) )
|
||||||
|
{
|
||||||
/* asprintf( &stored_path, "%s (%s); %s", path, typespec, argument_description ); */
|
ep->send( lo_message_get_source( msg ),
|
||||||
|
"/reply",
|
||||||
strcat( r, (*i)->path );
|
path,
|
||||||
strcat( r, "\n" );
|
o->path(),
|
||||||
|
o->id(),
|
||||||
|
o->parameter_limits().min,
|
||||||
|
o->parameter_limits().max,
|
||||||
|
o->parameter_limits().default_value
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Endpoint::set_parameter_limits ( const char *path, const char *typespec,
|
void
|
||||||
int index,
|
Endpoint::list_peers ( void (*callback) (const char *, const char *, int, void * ), void *v )
|
||||||
float min, float max, float default_value )
|
|
||||||
{
|
{
|
||||||
assert( typespec );
|
for ( std::list<Peer*>::iterator i = _peers.begin();
|
||||||
|
i != _peers.end();
|
||||||
assert( index < strlen( typespec ) );
|
++i )
|
||||||
|
|
||||||
for ( std::list<Method_Data *>::iterator i = _methods.begin(); i != _methods.end(); ++i )
|
|
||||||
{
|
{
|
||||||
if ( ! (*i)->path )
|
for ( std::list<Signal*>::iterator j = (*i)->_signals.begin();
|
||||||
continue;
|
j != (*i)->_signals.end();
|
||||||
|
++j )
|
||||||
if ( ! strcmp( path, (*i)->path ) &&
|
|
||||||
! strcmp( typespec, (*i)->typespec ) )
|
|
||||||
{
|
{
|
||||||
(*i)->parameter_limits[index].min = min;
|
// DMESSAGE( "Running callback" );
|
||||||
(*i)->parameter_limits[index].max = max;
|
callback( (*i)->name, (*j)->path(), (*j)->id(), v );
|
||||||
(*i)->parameter_limits[index].default_value = default_value;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
method_handle
|
Peer *
|
||||||
|
Endpoint::find_peer_by_address ( lo_address addr )
|
||||||
|
{
|
||||||
|
char *url = strdup( lo_address_get_port( addr ) );
|
||||||
|
|
||||||
|
Peer *p = NULL;
|
||||||
|
|
||||||
|
for ( std::list<Peer*>::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Peer *
|
||||||
|
Endpoint::find_peer_by_name ( const char *name )
|
||||||
|
{
|
||||||
|
for ( std::list<Peer*>::iterator i = _peers.begin();
|
||||||
|
i != _peers.end();
|
||||||
|
++i )
|
||||||
|
{
|
||||||
|
if ( !strcmp( name, (*i)->name ) )
|
||||||
|
{
|
||||||
|
return *i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 )
|
||||||
|
{
|
||||||
|
Peer *p = find_peer_by_name( peer_name );
|
||||||
|
|
||||||
|
MESSAGE( "Connecting signal output \"%s\" to %s:%i", s->path(), peer_name, signal_id );
|
||||||
|
|
||||||
|
if ( p )
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 *
|
||||||
Endpoint::add_method ( const char *path, const char *typespec, lo_method_handler handler, void *user_data, const char *argument_description )
|
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 );
|
// DMESSAGE( "Added OSC method %s (%s)", path, typespec );
|
||||||
|
|
||||||
lo_server_add_method( _server, path, typespec, handler, user_data );
|
lo_server_add_method( _server, path, typespec, handler, user_data );
|
||||||
|
|
||||||
Method_Data *md = new Method_Data;
|
Method *md = new Method;
|
||||||
|
|
||||||
if ( path )
|
if ( path )
|
||||||
md->path = strdup( path );
|
md->_path = strdup( path );
|
||||||
if ( typespec )
|
if ( typespec )
|
||||||
md->typespec = strdup( typespec );
|
md->_typespec = strdup( typespec );
|
||||||
if ( argument_description )
|
if ( argument_description )
|
||||||
md->documentation = strdup( argument_description );
|
md->_documentation = strdup( argument_description );
|
||||||
|
|
||||||
if ( typespec )
|
if ( typespec )
|
||||||
md->parameter_limits = new Parameter_Limits[strlen(typespec)];
|
md->_parameter_limits = new Parameter_Limits[strlen(typespec)];
|
||||||
|
|
||||||
_methods.push_back( md );
|
_methods.push_back( md );
|
||||||
|
|
||||||
return 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
|
void
|
||||||
|
@ -236,13 +488,13 @@ namespace OSC
|
||||||
|
|
||||||
lo_server_del_method( _server, path, typespec );
|
lo_server_del_method( _server, path, typespec );
|
||||||
|
|
||||||
for ( std::list<Method_Data *>::iterator i = _methods.begin(); i != _methods.end(); ++i )
|
for ( std::list<Method *>::iterator i = _methods.begin(); i != _methods.end(); ++i )
|
||||||
{
|
{
|
||||||
if ( ! (*i)->path )
|
if ( ! (*i)->path() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( ! strcmp( path, (*i)->path ) &&
|
if ( ! strcmp( path, (*i)->path() ) &&
|
||||||
! strcmp( typespec, (*i)->typespec ) )
|
! strcmp( typespec, (*i)->typespec() ) )
|
||||||
{
|
{
|
||||||
delete *i;
|
delete *i;
|
||||||
i = _methods.erase( i );
|
i = _methods.erase( i );
|
||||||
|
@ -253,36 +505,42 @@ namespace OSC
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Endpoint::del_method ( const method_handle mh )
|
Endpoint::del_method ( Method *meth )
|
||||||
{
|
{
|
||||||
// DMESSAGE( "Deleted OSC method %s (%s)", path, typespec );
|
// DMESSAGE( "Deleted OSC method %s (%s)", path, typespec );
|
||||||
|
|
||||||
Method_Data *meth = const_cast<Method_Data*>( (const Method_Data*)mh );
|
lo_server_del_method( _server, meth->path(), meth->typespec() );
|
||||||
|
|
||||||
lo_server_del_method( _server, meth->path, meth->typespec );
|
|
||||||
|
|
||||||
delete meth;
|
delete meth;
|
||||||
|
|
||||||
_methods.remove( meth );
|
_methods.remove( meth );
|
||||||
|
|
||||||
|
|
||||||
/* for ( std::list<Method_Data *>::iterator i = _methods.begin(); i != _methods.end(); ++i ) */
|
|
||||||
/* { */
|
|
||||||
/* if ( ! (*i)->path ) */
|
|
||||||
/* continue; */
|
|
||||||
|
|
||||||
/* if ( ! strcmp( path, (*i)->path ) && */
|
|
||||||
/* ! strcmp( typespec, (*i)->typespec ) ) */
|
|
||||||
/* { */
|
|
||||||
/* delete *i; */
|
|
||||||
/* i = _methods.erase( i ); */
|
|
||||||
|
|
||||||
/* break; */
|
|
||||||
/* } */
|
|
||||||
/* } */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Endpoint::del_signal ( Signal *o )
|
||||||
|
{
|
||||||
|
// DMESSAGE( "Deleted OSC method %s (%s)", path, typespec );
|
||||||
|
|
||||||
|
lo_server_del_method( _server, o->path(), "f" );
|
||||||
|
|
||||||
|
delete o;
|
||||||
|
|
||||||
|
_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 *
|
void *
|
||||||
Endpoint::osc_thread ( void * arg )
|
Endpoint::osc_thread ( void * arg )
|
||||||
|
@ -342,7 +600,7 @@ namespace OSC
|
||||||
/** Process any waiting events and return after timeout */
|
/** Process any waiting events and return after timeout */
|
||||||
void
|
void
|
||||||
Endpoint::wait ( int timeout ) const
|
Endpoint::wait ( int timeout ) const
|
||||||
{
|
{
|
||||||
if ( lo_server_wait( _server, timeout ) )
|
if ( lo_server_wait( _server, timeout ) )
|
||||||
while ( lo_server_recv_noblock( _server, 0 ) ) { }
|
while ( lo_server_recv_noblock( _server, 0 ) ) { }
|
||||||
}
|
}
|
||||||
|
@ -372,15 +630,15 @@ namespace OSC
|
||||||
switch ( ov->type() )
|
switch ( ov->type() )
|
||||||
{
|
{
|
||||||
case 'f':
|
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() );
|
lo_message_add_float( m, ((OSC_Float*)ov)->value() );
|
||||||
break;
|
break;
|
||||||
case 'i':
|
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() );
|
lo_message_add_int32( m, ((OSC_Int*)ov)->value() );
|
||||||
break;
|
break;
|
||||||
case 's':
|
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() );
|
lo_message_add_string( m, ((OSC_String*)ov)->value() );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -389,7 +647,7 @@ namespace OSC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DMESSAGE( "Path: %s", path );
|
DMESSAGE( "Path: %s", path );
|
||||||
|
|
||||||
lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE );
|
lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE );
|
||||||
|
|
||||||
|
@ -460,7 +718,7 @@ namespace OSC
|
||||||
|
|
||||||
int
|
int
|
||||||
Endpoint::send ( lo_address to, const char *path, const char *v1, const char *v2, int v3, int v4, int v5 )
|
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 );
|
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 );
|
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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,10 @@
|
||||||
#include "Thread.H"
|
#include "Thread.H"
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
namespace OSC
|
namespace OSC
|
||||||
{
|
{
|
||||||
typedef void * method_handle;
|
|
||||||
|
|
||||||
class OSC_Value
|
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<Signal*> _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<Target*> _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<Target*> _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
|
class Endpoint
|
||||||
{
|
{
|
||||||
static void error_handler(int num, const char *msg, const char *path);
|
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_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;
|
Thread _thread;
|
||||||
|
|
||||||
// lo_server_thread _st;
|
// lo_server_thread _st;
|
||||||
lo_server _server;
|
lo_server _server;
|
||||||
|
|
||||||
|
std::list<Peer*> _peers;
|
||||||
struct Parameter_Limits
|
std::list<Signal*> _signals;
|
||||||
{
|
std::list<Method*> _methods;
|
||||||
float min;
|
|
||||||
float max;
|
|
||||||
float default_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Method_Data
|
|
||||||
{
|
|
||||||
char *path;
|
|
||||||
char *typespec;
|
|
||||||
char *documentation;
|
|
||||||
struct Parameter_Limits *parameter_limits;
|
|
||||||
std::list<lo_address> 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<lo_address>::iterator i = subscribers.begin();
|
|
||||||
i != subscribers.end();
|
|
||||||
++i )
|
|
||||||
{
|
|
||||||
lo_address_free( *i );
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribers.clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::list<Method_Data*> _methods;
|
|
||||||
|
|
||||||
static void *osc_thread ( void *arg );
|
static void *osc_thread ( void *arg );
|
||||||
void osc_thread ( void );
|
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<Target*> *l, lo_address addr );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
void list_peers ( void (*callback) (const char *, const char *, int, void * ), void *v );
|
||||||
|
|
||||||
int init ( const char *port = 0 );
|
int init ( const char *port = 0 );
|
||||||
Endpoint ( );
|
Endpoint ( );
|
||||||
|
|
||||||
~Endpoint ( );
|
~Endpoint ( );
|
||||||
|
|
||||||
char *get_paths ( const char *prefix );
|
bool connect_signal( OSC::Signal *s, const char *peer_name, int signal_id );
|
||||||
method_handle add_method ( const char *path, const char *typespec, lo_method_handler handler, void *user_data, const char *argument_description );
|
|
||||||
|
|
||||||
|
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 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 start ( void );
|
||||||
void stop ( void );
|
void stop ( void );
|
||||||
int port ( void ) const;
|
int port ( void ) const;
|
||||||
char * url ( 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 check ( void ) const;
|
||||||
void wait ( int timeout ) 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, double v );
|
||||||
int send ( lo_address to, const char *path, int 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, 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 *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 );
|
||||||
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, const char *v2, const char *v3 );
|
||||||
int send ( lo_address to, const char *path, const char *v1, int v2, int v3, int v4 );
|
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, 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.
|
// can be used to point back to owning object.
|
||||||
void *owner;
|
void *owner;
|
||||||
};
|
};
|
||||||
|
|
|
@ -349,8 +349,11 @@ set_name ( const char *name )
|
||||||
bool
|
bool
|
||||||
address_matches ( lo_address addr1, lo_address addr2 )
|
address_matches ( lo_address addr1, lo_address addr2 )
|
||||||
{
|
{
|
||||||
char *url1 = lo_address_get_url( addr1 );
|
/* char *url1 = lo_address_get_url( addr1 ); */
|
||||||
char *url2 = lo_address_get_url( addr2 );
|
/* 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 );
|
bool r = !strcmp( url1, url2 );
|
||||||
|
|
||||||
|
@ -1464,7 +1467,7 @@ OSC_HANDLER( broadcast )
|
||||||
|
|
||||||
if ( strcmp( sender_url, url ) )
|
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 );
|
free( url );
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
using std::list;
|
using std::list;
|
||||||
|
|
||||||
|
#include "Transport.H"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool Control_Sequence::draw_with_gradient = true;
|
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 )
|
Control_Sequence::Control_Sequence ( Track *track ) : Sequence( 0 )
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
@ -51,10 +55,20 @@ Control_Sequence::Control_Sequence ( Track *track ) : Sequence( 0 )
|
||||||
FATAL( "could not create JACK port" );
|
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 )
|
if ( track )
|
||||||
track->add( this );
|
track->add( this );
|
||||||
|
|
||||||
log_create();
|
log_create();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,8 +102,10 @@ Control_Sequence::init ( void )
|
||||||
_track = NULL;
|
_track = NULL;
|
||||||
_highlighted = false;
|
_highlighted = false;
|
||||||
_output = NULL;
|
_output = NULL;
|
||||||
|
_osc_output = NULL;
|
||||||
color( fl_darker( FL_YELLOW ) );
|
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();
|
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
|
int
|
||||||
Control_Sequence::handle ( int m )
|
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 ) ) )
|
else if ( Fl::event_button3() && ! ( Fl::event_state() & ( FL_ALT | FL_SHIFT | FL_CTRL ) ) )
|
||||||
{
|
{
|
||||||
|
timeline->discover_peers();
|
||||||
|
|
||||||
Fl_Menu_Item menu[] =
|
Fl_Menu_Button menu( 0, 0, 0, 0, "Control Sequence" );
|
||||||
{
|
|
||||||
{ "Rename" },
|
|
||||||
{ "Remove" },
|
|
||||||
{ 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
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 )
|
// con->callback( &Control_Sequence::menu_cb, (void*)this );
|
||||||
{
|
|
||||||
if ( r == &menu[ 0 ] )
|
|
||||||
{
|
|
||||||
const char *s = fl_input( "Input new name for control sequence:", name() );
|
|
||||||
|
|
||||||
if ( s )
|
menu.clear();
|
||||||
name( s );
|
|
||||||
|
|
||||||
redraw();
|
timeline->add_osc_peers_to_menu( &menu, "Connect To" );
|
||||||
}
|
|
||||||
else if ( r == &menu[ 1 ] )
|
/* menu.add( "Connect To", 0, 0, 0); */
|
||||||
{
|
/* menu.add( "Connect To", 0, 0, const_cast< Fl_Menu_Item *>( con->menu() ), FL_SUBMENU_POINTER ); */
|
||||||
Fl::delete_widget( this );
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "JACK/Port.H"
|
#include "JACK/Port.H"
|
||||||
|
|
||||||
// class JACK::Port;
|
// class JACK::Port;
|
||||||
|
#include "OSC/Endpoint.H"
|
||||||
|
|
||||||
class Control_Sequence : public Sequence
|
class Control_Sequence : public Sequence
|
||||||
{
|
{
|
||||||
|
@ -41,6 +42,8 @@ private:
|
||||||
|
|
||||||
JACK::Port *_output;
|
JACK::Port *_output;
|
||||||
|
|
||||||
|
OSC::Signal *_osc_output;
|
||||||
|
|
||||||
bool _highlighted;
|
bool _highlighted;
|
||||||
|
|
||||||
curve_type_e _type;
|
curve_type_e _type;
|
||||||
|
@ -49,6 +52,13 @@ private:
|
||||||
|
|
||||||
void draw_curve ( bool flip, bool filled );
|
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:
|
protected:
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ sigmoid_interpolate ( float y1, float y2, float mu )
|
||||||
nframes_t
|
nframes_t
|
||||||
Control_Sequence::play ( sample_t *buf, nframes_t frame, nframes_t nframes )
|
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();
|
Control_Point *p2, *p1 = (Control_Point*)&_widgets.front();
|
||||||
|
|
||||||
|
|
|
@ -91,12 +91,12 @@ NSM_Client::command_session_is_loaded ( void )
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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 );
|
int argc = lo_message_get_argc( msg );
|
||||||
lo_arg **argv = lo_message_get_argv( 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 );
|
timeline->reply_to_finger( msg );
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -35,5 +35,5 @@ protected:
|
||||||
int command_save ( char **out_msg );
|
int command_save ( char **out_msg );
|
||||||
void command_session_is_loaded ( void );
|
void command_session_is_loaded ( void );
|
||||||
|
|
||||||
int command_broadcast ( lo_message msg );
|
int command_broadcast ( const char *path, lo_message msg );
|
||||||
};
|
};
|
||||||
|
|
|
@ -1517,6 +1517,8 @@ Timeline::command_load ( const char *name, const char *display_name )
|
||||||
|
|
||||||
Project::set_name ( display_name ? display_name : name );
|
Project::set_name ( display_name ? display_name : name );
|
||||||
|
|
||||||
|
discover_peers();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1539,6 +1541,9 @@ Timeline::command_new ( const char *name, const char *display_name )
|
||||||
/* tle->update_menu(); */
|
/* tle->update_menu(); */
|
||||||
|
|
||||||
/* tle->main_window->redraw(); */
|
/* tle->main_window->redraw(); */
|
||||||
|
|
||||||
|
discover_peers();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
|
@ -1573,7 +1578,7 @@ Timeline::init_osc ( const char *osc_port )
|
||||||
|
|
||||||
printf( "OSC=%s\n", osc->url() );
|
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();
|
// osc->start();
|
||||||
|
|
||||||
|
@ -1584,19 +1589,23 @@ Timeline::init_osc ( const char *osc_port )
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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();
|
OSC_DMSG();
|
||||||
|
|
||||||
if ( argc >= 5 && !strcmp( &argv[0]->s, "/non/finger" ) )
|
if ( argc >= 4 )
|
||||||
{
|
{
|
||||||
const char *url = &argv[1]->s;
|
const char *url = &argv[0]->s;
|
||||||
const char *name = &argv[2]->s;
|
const char *name = &argv[1]->s;
|
||||||
const char *version = &argv[3]->s;
|
const char *version = &argv[2]->s;
|
||||||
const char *id = &argv[4]->s;
|
const char *id = &argv[3]->s;
|
||||||
|
|
||||||
MESSAGE( "Discovered OSC peer %s (%s) @ %s with ID \"%s\"", name, version, url, id );
|
MESSAGE( "Discovered OSC peer %s (%s) @ %s with ID \"%s\"", name, version, url, id );
|
||||||
|
|
||||||
|
MESSAGE( "Scanning..." );
|
||||||
|
|
||||||
|
timeline->osc->scan_peer( id, url );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1609,14 +1618,13 @@ Timeline::reply_to_finger ( lo_message msg )
|
||||||
int argc = lo_message_get_argc( msg );
|
int argc = lo_message_get_argc( msg );
|
||||||
lo_arg **argv = lo_message_get_argv( msg );
|
lo_arg **argv = lo_message_get_argv( msg );
|
||||||
|
|
||||||
if ( argc < 2 )
|
if ( argc < 1 )
|
||||||
return;
|
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,
|
osc->send( reply,
|
||||||
"/reply",
|
"/non/hello",
|
||||||
"/non/finger",
|
|
||||||
osc->url(),
|
osc->url(),
|
||||||
APP_NAME,
|
APP_NAME,
|
||||||
VERSION,
|
VERSION,
|
||||||
|
@ -1625,10 +1633,49 @@ Timeline::reply_to_finger ( lo_message msg )
|
||||||
lo_address_free( reply );
|
lo_address_free( reply );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Timeline::discover_peers ( 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
static void draw_clip ( void * v, int X, int Y, int W, int H );
|
||||||
|
|
||||||
OSC::Endpoint *osc;
|
|
||||||
|
|
||||||
int _old_xposition;
|
int _old_xposition;
|
||||||
int _old_yposition;
|
int _old_yposition;
|
||||||
|
|
||||||
|
@ -120,6 +119,8 @@ class Timeline : public Fl_Single_Window, public RWLock
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
OSC::Endpoint *osc;
|
||||||
|
|
||||||
#undef Bars
|
#undef Bars
|
||||||
#undef Beats
|
#undef Beats
|
||||||
#undef None
|
#undef None
|
||||||
|
@ -232,6 +233,12 @@ public:
|
||||||
|
|
||||||
/* OSC */
|
/* 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 );
|
void discover_peers ( void );
|
||||||
|
|
||||||
static void check_osc ( void * v );
|
static void check_osc ( void * v );
|
||||||
|
@ -239,7 +246,9 @@ public:
|
||||||
int init_osc ( const char *osc_port );
|
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_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 );
|
void reply_to_finger ( lo_message msg );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in New Issue