| @@ -485,12 +485,10 @@ Controller_Module::menu_cb ( const Fl_Menu_ *m ) | |||||
| Logger log( this ); | Logger log( this ); | ||||
| if ( ! strcmp( picked, "Mode/Manual" ) ) | |||||
| if ( ! strcmp( picked, "Mode/GUI + OSC" ) ) | |||||
| mode( GUI ); | mode( GUI ); | ||||
| else if ( ! strcmp( picked, "Mode/Control Voltage" ) ) | |||||
| else if ( ! strcmp( picked, "Mode/Control Voltage (JACK)" ) ) | |||||
| mode( CV ); | mode( CV ); | ||||
| else if ( ! strcmp( picked, "Mode/Open Sound Control (OSC)" ) ) | |||||
| mode( OSC ); | |||||
| } | } | ||||
| /** build the context menu for this control */ | /** build the context menu for this control */ | ||||
| @@ -502,9 +500,8 @@ Controller_Module::menu ( void ) | |||||
| Fl_Menu_Item items[] = | Fl_Menu_Item items[] = | ||||
| { | { | ||||
| { "Mode", 0, 0, 0, FL_SUBMENU }, | { "Mode", 0, 0, 0, FL_SUBMENU }, | ||||
| { "Manual", 0, 0, 0, FL_MENU_RADIO | ( mode() == GUI ? FL_MENU_VALUE : 0 ) }, | |||||
| { "Control Voltage", 0, 0, 0, FL_MENU_RADIO | ( mode() == CV ? FL_MENU_VALUE : 0 ) }, | |||||
| // { "Open Sound Control (OSC)", 0, 0, 0, FL_MENU_RADIO | ( mode() == OSC ? FL_MENU_VALUE : 0 ) }, | |||||
| { "GUI + OSC", 0, 0, 0, FL_MENU_RADIO | ( mode() == GUI ? FL_MENU_VALUE : 0 ) }, | |||||
| { "Control Voltage (JACK)", 0, 0, 0, FL_MENU_RADIO | ( mode() == CV ? FL_MENU_VALUE : 0 ) }, | |||||
| { 0 }, | { 0 }, | ||||
| { 0 }, | { 0 }, | ||||
| }; | }; | ||||
| @@ -75,6 +75,16 @@ namespace OSC | |||||
| } | } | ||||
| } | } | ||||
| void | |||||
| Signal::get_connected_peer_name_and_path ( char **peer_name, char **path ) | |||||
| { | |||||
| Target *t = _outgoing.back(); | |||||
| Signal *s = get_peer_signal_by_id( t->peer, t->signal_id ); | |||||
| *peer_name = strdup( t->peer->name ); | |||||
| *path = strdup( s->path() ); | |||||
| } | |||||
| void | void | ||||
| Endpoint::error_handler(int num, const char *msg, const char *path) | Endpoint::error_handler(int num, const char *msg, const char *path) | ||||
| @@ -141,6 +151,22 @@ namespace OSC | |||||
| if ( (*i)->id() == id ) | if ( (*i)->id() == id ) | ||||
| return *i; | return *i; | ||||
| } | } | ||||
| return NULL; | |||||
| } | |||||
| OSC::Signal * | |||||
| Endpoint::find_peer_signal_by_path ( Peer *p, const char *path ) | |||||
| { | |||||
| for ( std::list<Signal*>::iterator i = p->_signals.begin(); | |||||
| i != p->_signals.end(); | |||||
| ++i ) | |||||
| { | |||||
| if ( !strcmp( (*i)->path(), path ) ) | |||||
| return *i; | |||||
| } | |||||
| return NULL; | |||||
| } | } | ||||
| int | int | ||||
| @@ -213,7 +239,7 @@ namespace OSC | |||||
| { | { | ||||
| // OSC_DMSG(); | // OSC_DMSG(); | ||||
| if ( path[ strlen(path) - 1 ] != '/' ) | |||||
| if ( argc || path[ strlen(path) - 1 ] != '/' ) | |||||
| return -1; | return -1; | ||||
| Endpoint *ep = (Endpoint*)user_data; | Endpoint *ep = (Endpoint*)user_data; | ||||
| @@ -363,13 +389,52 @@ namespace OSC | |||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* First part of 'to' is a peer name */ | |||||
| bool | |||||
| Endpoint::connect_signal( OSC::Signal *s, const char *peer_name, const char *signal_path ) | |||||
| { | |||||
| if ( s->_direction == Signal::Output ) | |||||
| { | |||||
| Peer *p = find_peer_by_name( peer_name ); | |||||
| if ( ! p ) | |||||
| return false; | |||||
| Signal *ps = find_peer_signal_by_path( p, signal_path ); | |||||
| if ( ! ps ) | |||||
| return false; | |||||
| MESSAGE( "Connecting signal output \"%s\" to %s:%i", s->path(), peer_name, s->_id ); | |||||
| if ( p ) | |||||
| { | |||||
| Target *t = new Target(); | |||||
| t->peer = p; | |||||
| t->signal_id = ps->_id; | |||||
| s->_outgoing.push_back( t ); | |||||
| send( p->addr, "/signal/connect", | |||||
| s->_id, /* our signal id */ | |||||
| t->signal_id /* their signal id */ ); | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| bool | bool | ||||
| Endpoint::connect_signal( OSC::Signal *s, const char *peer_name, int signal_id ) | Endpoint::connect_signal( OSC::Signal *s, const char *peer_name, int signal_id ) | ||||
| { | { | ||||
| if ( s->_direction == Signal::Output ) | if ( s->_direction == Signal::Output ) | ||||
| { | { | ||||
| Peer *p = find_peer_by_name( peer_name ); | Peer *p = find_peer_by_name( peer_name ); | ||||
| if ( !p ) | |||||
| return false; | |||||
| MESSAGE( "Connecting signal output \"%s\" to %s:%i", s->path(), peer_name, signal_id ); | MESSAGE( "Connecting signal output \"%s\" to %s:%i", s->path(), peer_name, signal_id ); | ||||
| @@ -383,8 +448,8 @@ namespace OSC | |||||
| s->_outgoing.push_back( t ); | s->_outgoing.push_back( t ); | ||||
| send( p->addr, "/signal/connect", | send( p->addr, "/signal/connect", | ||||
| 0, /* FIXME: our signal id */ | |||||
| 0 /* FIXME: their signal id */ ); | |||||
| s->_id, /* our signal id */ | |||||
| t->signal_id /* their signal id */ ); | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -393,6 +458,19 @@ namespace OSC | |||||
| return false; | return false; | ||||
| } | } | ||||
| Signal * | |||||
| Signal::get_peer_signal_by_id ( Peer *p, int signal_id ) | |||||
| { | |||||
| for ( std::list<Signal *>::iterator i = p->_signals.begin(); | |||||
| i != p->_signals.end(); | |||||
| ++i ) | |||||
| { | |||||
| if ( (*i)->_id == signal_id ) | |||||
| return *i; | |||||
| } | |||||
| return NULL; | |||||
| } | |||||
| int | int | ||||
| Endpoint::osc_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | Endpoint::osc_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | ||||
| @@ -117,7 +117,6 @@ namespace OSC | |||||
| class Signal; | class Signal; | ||||
| struct Peer | struct Peer | ||||
| { | { | ||||
| bool _scanning; | bool _scanning; | ||||
| char *name; | char *name; | ||||
| @@ -129,7 +128,6 @@ namespace OSC | |||||
| struct Target | struct Target | ||||
| { | { | ||||
| Peer *peer; | Peer *peer; | ||||
| // char *path; | |||||
| int signal_id; | int signal_id; | ||||
| float value; | float value; | ||||
| }; | }; | ||||
| @@ -190,8 +188,10 @@ namespace OSC | |||||
| free( _path ); | free( _path ); | ||||
| } | } | ||||
| static Signal *get_peer_signal_by_id ( Peer *p, int signal_id ); | |||||
| bool connected ( void ) { return _outgoing.size() + _incoming.size(); } | bool connected ( void ) { return _outgoing.size() + _incoming.size(); } | ||||
| void get_connected_peer_name_and_path ( char **peer_name, char **path ); | |||||
| int id ( void ) { return _id; } | int id ( void ) { return _id; } | ||||
| Direction direction ( void ) { return _direction; } | Direction direction ( void ) { return _direction; } | ||||
| @@ -260,6 +260,8 @@ namespace OSC | |||||
| OSC::Signal *find_signal_by_id ( int id ); | OSC::Signal *find_signal_by_id ( int id ); | ||||
| OSC::Signal *find_peer_signal_by_path ( Peer *p, const char *path ); | |||||
| Peer *find_peer_by_name ( const char *name ); | Peer *find_peer_by_name ( const char *name ); | ||||
| Peer *find_peer_by_address ( lo_address addr ); | Peer *find_peer_by_address ( lo_address addr ); | ||||
| static bool address_matches ( lo_address addr1, lo_address addr2 ); | static bool address_matches ( lo_address addr1, lo_address addr2 ); | ||||
| @@ -275,6 +277,8 @@ namespace OSC | |||||
| ~Endpoint ( ); | ~Endpoint ( ); | ||||
| bool connect_signal( OSC::Signal *s, const char *peer_name, const char *signal_path ); | |||||
| bool connect_signal( OSC::Signal *s, const char *peer_name, int signal_id ); | bool connect_signal( OSC::Signal *s, const char *peer_name, int signal_id ); | ||||
| @@ -916,8 +916,8 @@ main (int argc, char **argv ) | |||||
| Daemon *d = new Daemon; | Daemon *d = new Daemon; | ||||
| d->url = optarg; | |||||
| d->addr = lo_address_new_from_url( optarg ); | |||||
| d->url = nsm_url; | |||||
| d->addr = lo_address_new_from_url( nsm_url ); | |||||
| daemon_list.push_back( d ); | daemon_list.push_back( d ); | ||||
| } | } | ||||
| @@ -40,12 +40,12 @@ 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(); | ||||
| _osc_connected_peer = _osc_connected_path = 0; | |||||
| _track = track; | _track = track; | ||||
| _output = new JACK::Port( engine, JACK::Port::Output, track->name(), track->ncontrols(), "cv" ); | _output = new JACK::Port( engine, JACK::Port::Output, track->name(), track->ncontrols(), "cv" ); | ||||
| @@ -55,20 +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() ); | |||||
| /* { */ | |||||
| /* 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 ); | |||||
| /* _osc_output = timeline->osc->add_signal( path, OSC::Signal::Output, NULL, NULL ); */ | |||||
| free( path ); | |||||
| } | |||||
| /* free( path ); */ | |||||
| /* } */ | |||||
| _osc_output = 0; | |||||
| if ( track ) | if ( track ) | ||||
| track->add( this ); | track->add( this ); | ||||
| interpolation( Linear ); | |||||
| log_create(); | log_create(); | ||||
| } | } | ||||
| @@ -108,7 +108,10 @@ Control_Sequence::init ( void ) | |||||
| _osc_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 ); | |||||
| interpolation( Linear ); | |||||
| frequency( 10 ); | |||||
| Fl::add_timeout( _interval, &Control_Sequence::process_osc, this ); | |||||
| } | } | ||||
| @@ -124,6 +127,20 @@ void | |||||
| Control_Sequence::get_unjournaled ( Log_Entry &e ) const | Control_Sequence::get_unjournaled ( Log_Entry &e ) const | ||||
| { | { | ||||
| e.add( ":interpolation", _interpolation ); | e.add( ":interpolation", _interpolation ); | ||||
| if ( _osc_output->connected() ) | |||||
| { | |||||
| char *path; | |||||
| char *peer; | |||||
| _osc_output->get_connected_peer_name_and_path( &peer, &path ); | |||||
| e.add( ":osc_peer", peer ); | |||||
| e.add( ":osc_path", path ); | |||||
| free( path ); | |||||
| free( peer ); | |||||
| } | |||||
| e.add( ":frequency", frequency() ); | |||||
| } | } | ||||
| void | void | ||||
| @@ -156,7 +173,16 @@ Control_Sequence::set ( Log_Entry &e ) | |||||
| name( v ); | name( v ); | ||||
| else if ( ! strcmp( ":interpolation", s ) ) | else if ( ! strcmp( ":interpolation", s ) ) | ||||
| interpolation( (curve_type_e)atoi( v ) ); | interpolation( (curve_type_e)atoi( v ) ); | ||||
| else if ( ! strcmp( ":frequency", s ) ) | |||||
| frequency( atoi( v ) ); | |||||
| else if ( ! strcmp( ":osc_peer", s ) ) | |||||
| { | |||||
| _osc_connected_peer = strdup( v ); | |||||
| } | |||||
| else if ( !strcmp( ":osc_path", s ) ) | |||||
| { | |||||
| _osc_connected_path = strdup( v ); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -354,6 +380,19 @@ Control_Sequence::menu_cb ( const Fl_Menu_ *m ) | |||||
| interpolation( Linear ); | interpolation( Linear ); | ||||
| else if ( ! strcmp( picked, "Interpolation/None" ) ) | else if ( ! strcmp( picked, "Interpolation/None" ) ) | ||||
| interpolation( None ); | interpolation( None ); | ||||
| else if ( ! strcmp( picked, "Frequency/1Hz" ) ) | |||||
| frequency( 1 ); | |||||
| else if ( ! strcmp( picked, "Frequency/5Hz" ) ) | |||||
| frequency( 5 ); | |||||
| else if ( ! strcmp( picked, "Frequency/10Hz" ) ) | |||||
| frequency( 10 ); | |||||
| else if ( ! strcmp( picked, "Frequency/20Hz" ) ) | |||||
| frequency( 20 ); | |||||
| else if ( ! strcmp( picked, "Frequency/30Hz" ) ) | |||||
| frequency( 30 ); | |||||
| else if ( ! strcmp( picked, "Frequency/60Hz" ) ) | |||||
| frequency( 60 ); | |||||
| else if ( ! strcmp( picked, "/Rename" ) ) | else if ( ! strcmp( picked, "/Rename" ) ) | ||||
| { | { | ||||
| const char *s = fl_input( "Input new name for control sequence:", name() ); | const char *s = fl_input( "Input new name for control sequence:", name() ); | ||||
| @@ -369,6 +408,23 @@ Control_Sequence::menu_cb ( const Fl_Menu_ *m ) | |||||
| } | } | ||||
| } | } | ||||
| void | |||||
| Control_Sequence::connect_osc ( void ) | |||||
| { | |||||
| 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 ); | |||||
| } | |||||
| if ( _osc_connected_peer && _osc_connected_path ) | |||||
| timeline->osc->connect_signal( _osc_output, _osc_connected_peer, _osc_connected_path ); | |||||
| } | |||||
| void | void | ||||
| Control_Sequence::process_osc ( void *v ) | Control_Sequence::process_osc ( void *v ) | ||||
| @@ -379,7 +435,7 @@ Control_Sequence::process_osc ( void *v ) | |||||
| void | void | ||||
| Control_Sequence::process_osc ( void ) | Control_Sequence::process_osc ( void ) | ||||
| { | { | ||||
| Fl::add_timeout( OSC_INTERVAL, &Control_Sequence::process_osc, this ); | |||||
| Fl::repeat_timeout( _interval, &Control_Sequence::process_osc, this ); | |||||
| if ( _osc_output && _osc_output->connected() ) | if ( _osc_output && _osc_output->connected() ) | ||||
| { | { | ||||
| @@ -443,6 +499,15 @@ Control_Sequence::handle ( int m ) | |||||
| /* menu.add( "Connect To", 0, 0, const_cast< Fl_Menu_Item *>( con->menu() ), FL_SUBMENU_POINTER ); */ | /* menu.add( "Connect To", 0, 0, const_cast< Fl_Menu_Item *>( con->menu() ), FL_SUBMENU_POINTER ); */ | ||||
| menu.add( "Interpolation/None", 0, 0, 0, FL_MENU_RADIO | ( interpolation() == None ? FL_MENU_VALUE : 0 ) ); | menu.add( "Interpolation/None", 0, 0, 0, FL_MENU_RADIO | ( interpolation() == None ? FL_MENU_VALUE : 0 ) ); | ||||
| menu.add( "Interpolation/Linear", 0, 0, 0, FL_MENU_RADIO | ( interpolation() == Linear ? FL_MENU_VALUE : 0 ) ); | menu.add( "Interpolation/Linear", 0, 0, 0, FL_MENU_RADIO | ( interpolation() == Linear ? FL_MENU_VALUE : 0 ) ); | ||||
| menu.add( "Frequency/1Hz", 0, 0, 0, FL_MENU_RADIO | ( frequency() == 1 ? FL_MENU_VALUE : 0 ) ); | |||||
| menu.add( "Frequency/5Hz", 0, 0, 0, FL_MENU_RADIO | ( frequency() == 5 ? FL_MENU_VALUE : 0 ) ); | |||||
| menu.add( "Frequency/10Hz", 0, 0, 0, FL_MENU_RADIO | ( frequency() == 10 ? FL_MENU_VALUE : 0 ) ); | |||||
| menu.add( "Frequency/20Hz", 0, 0, 0, FL_MENU_RADIO | ( frequency() == 20 ? FL_MENU_VALUE : 0 ) ); | |||||
| menu.add( "Frequency/30Hz", 0, 0, 0, FL_MENU_RADIO | ( frequency() == 30 ? FL_MENU_VALUE : 0 ) ); | |||||
| menu.add( "Frequency/60Hz", 0, 0, 0, FL_MENU_RADIO | ( frequency() == 60 ? FL_MENU_VALUE : 0 ) ); | |||||
| menu.add( "Rename", 0, 0, 0 ); | menu.add( "Rename", 0, 0, 0 ); | ||||
| menu.add( "Remove", 0, 0, 0 ); | menu.add( "Remove", 0, 0, 0 ); | ||||
| @@ -42,11 +42,18 @@ private: | |||||
| JACK::Port *_output; | JACK::Port *_output; | ||||
| /* these are used to cache the saved osc connection until the | |||||
| * session is loaded, at which time we will reconnect */ | |||||
| char *_osc_connected_peer; | |||||
| char *_osc_connected_path; | |||||
| /* osc output port */ | |||||
| OSC::Signal *_osc_output; | OSC::Signal *_osc_output; | ||||
| bool _highlighted; | bool _highlighted; | ||||
| curve_type_e _interpolation; | curve_type_e _interpolation; | ||||
| int _frequency; | |||||
| float _interval; | |||||
| void init ( void ); | void init ( void ); | ||||
| @@ -78,6 +85,8 @@ protected: | |||||
| public: | public: | ||||
| void connect_osc ( void ); | |||||
| static bool draw_with_gradient; | static bool draw_with_gradient; | ||||
| static bool draw_with_polygon; | static bool draw_with_polygon; | ||||
| static bool draw_with_grid; | static bool draw_with_grid; | ||||
| @@ -91,6 +100,8 @@ public: | |||||
| curve_type_e interpolation ( void ) const { return _interpolation; } | curve_type_e interpolation ( void ) const { return _interpolation; } | ||||
| void interpolation ( curve_type_e v ) { _interpolation = v; } | void interpolation ( curve_type_e v ) { _interpolation = v; } | ||||
| int frequency ( void ) const { return _frequency; } | |||||
| void frequency ( int v ) { _frequency = v; _interval = ( 1.0f / (float)v ) / 2; } | |||||
| /* Engine */ | /* Engine */ | ||||
| void output ( JACK::Port *p ) { _output = p; } | void output ( JACK::Port *p ) { _output = p; } | ||||
| @@ -1644,6 +1644,26 @@ Timeline::discover_peers ( void ) | |||||
| nsm->broadcast( m ); | nsm->broadcast( m ); | ||||
| lo_message_free( m ); | lo_message_free( m ); | ||||
| /* wait for responses and then autoconnect outputs */ | |||||
| MESSAGE( "Waiting for OSC peers..." ); | |||||
| osc->wait( 1000 ); | |||||
| MESSAGE( "Reconnecting signals." ); | |||||
| /* reconnect OSC signals */ | |||||
| for ( int i = tracks->children(); i-- ; ) | |||||
| { | |||||
| Track *t = (Track*)tracks->child( i ); | |||||
| for ( int j = t->control->children(); j--; ) | |||||
| { | |||||
| Control_Sequence *c = (Control_Sequence*)t->control->child( j ); | |||||
| c->connect_osc(); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| void | void | ||||