@@ -41,7 +41,6 @@ | |||||
#include "Engine/Engine.H" | #include "Engine/Engine.H" | ||||
#include "Chain.H" | #include "Chain.H" | ||||
#include "OSC/Endpoint.H" | #include "OSC/Endpoint.H" | ||||
// needed for mixer->endpoint | // needed for mixer->endpoint | ||||
@@ -65,7 +64,6 @@ Controller_Module::Controller_Module ( bool is_default ) : Module( is_default, 5 | |||||
add_port( Port( this, Port::OUTPUT, Port::CONTROL ) ); | add_port( Port( this, Port::OUTPUT, Port::CONTROL ) ); | ||||
_mode = GUI; | _mode = GUI; | ||||
_osc_path = NULL; | |||||
// mode( GUI ); | // mode( GUI ); | ||||
// mode( CV ); | // mode( CV ); | ||||
@@ -86,69 +84,12 @@ Controller_Module::~Controller_Module ( ) | |||||
/* shutdown JACK port, if we have one */ | /* shutdown JACK port, if we have one */ | ||||
mode( GUI ); | mode( GUI ); | ||||
change_osc_path( NULL ); | |||||
} | } | ||||
void | void | ||||
Controller_Module::handle_chain_name_changed() | Controller_Module::handle_chain_name_changed() | ||||
{ | { | ||||
change_osc_path( generate_osc_path() ); | |||||
} | |||||
char * | |||||
Controller_Module::generate_osc_path () | |||||
{ | |||||
const Port *p = control_output[0].connected_port(); | |||||
if ( !p ) | |||||
return NULL; | |||||
char *path; | |||||
// /mixer/strip/STRIPNAME/control/MODULENAME/CONTROLNAME | |||||
asprintf( &path, "/mixer/strip/%s/control/%s/%s", 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--; ) | |||||
{ | |||||
if ( path[i] == ' ' ) | |||||
path[i] = '_'; | |||||
} | |||||
return path; | |||||
} | |||||
void | |||||
Controller_Module::change_osc_path ( char *path ) | |||||
{ | |||||
if ( _osc_path ) | |||||
{ | |||||
mixer->osc_endpoint->del_method( _osc_path, "f" ); | |||||
free( _osc_path ); | |||||
free( _osc_path_cv ); | |||||
_osc_path = NULL; | |||||
_osc_path_cv = NULL; | |||||
} | |||||
if ( path ) | |||||
{ | |||||
_osc_path_cv = (char*)malloc( strlen( path ) + 4 ); | |||||
_osc_path_cv[0] = 0; | |||||
strcpy( _osc_path_cv, path ); | |||||
strcat( _osc_path_cv, "/cv" ); | |||||
mixer->osc_endpoint->add_method( path, "f", &Controller_Module::osc_control_change_exact, this, "value" ); | |||||
mixer->osc_endpoint->add_method( _osc_path_cv, "f", &Controller_Module::osc_control_change_cv, this, "value" ); | |||||
_osc_path = path; | |||||
tooltip( _osc_path ); | |||||
} | |||||
// change_osc_path( generate_osc_path() ); | |||||
} | } | ||||
@@ -463,8 +404,6 @@ Controller_Module::connect_to ( Port *p ) | |||||
} | } | ||||
// create OSC port | // create OSC port | ||||
change_osc_path( generate_osc_path() ); | |||||
} | } | ||||
void | void | ||||
@@ -550,7 +489,7 @@ Controller_Module::menu ( void ) | |||||
{ "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 ) }, | { "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 ) }, | { "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 ) }, | |||||
// { "Open Sound Control (OSC)", 0, 0, 0, FL_MENU_RADIO | ( mode() == OSC ? FL_MENU_VALUE : 0 ) }, | |||||
{ 0 }, | { 0 }, | ||||
{ 0 }, | { 0 }, | ||||
}; | }; | ||||
@@ -587,14 +526,20 @@ Controller_Module::handle ( int m ) | |||||
} | } | ||||
void | void | ||||
Controller_Module::handle_control_changed ( Port * ) | |||||
Controller_Module::handle_control_changed ( Port *p ) | |||||
{ | { | ||||
/* ignore changes initiated while mouse is over widget */ | /* ignore changes initiated while mouse is over widget */ | ||||
if ( contains( Fl::pushed() ) ) | if ( contains( Fl::pushed() ) ) | ||||
return; | return; | ||||
if ( p ) | |||||
control_value = p->control_value(); | |||||
if ( control->value() != control_value ) | if ( control->value() != control_value ) | ||||
{ | |||||
redraw(); | redraw(); | ||||
DMESSAGE( "handle_control_changed" ); | |||||
} | |||||
if ( type() == SPATIALIZATION ) | if ( type() == SPATIALIZATION ) | ||||
{ | { | ||||
@@ -652,64 +597,3 @@ Controller_Module::process ( nframes_t nframes ) | |||||
control_value = f; | control_value = f; | ||||
} | } | ||||
} | } | ||||
int | |||||
Controller_Module::osc_control_change_exact ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||||
{ | |||||
Controller_Module *c = (Controller_Module*)user_data; | |||||
if ( c->mode() != OSC ) | |||||
return 0; | |||||
OSC_DMSG(); | |||||
const Port *p = c->control_output[0].connected_port(); | |||||
float f = argv[0]->f; | |||||
if ( p->hints.ranged ) | |||||
{ | |||||
if ( f > p->hints.maximum ) | |||||
f = p->hints.maximum; | |||||
else if ( f < p->hints.minimum ) | |||||
f = p->hints.minimum; | |||||
} | |||||
c->control_value = f; | |||||
mixer->osc_endpoint->send( lo_message_get_source( msg ), "/reply", path, "ok" ); | |||||
return 0; | |||||
} | |||||
int | |||||
Controller_Module::osc_control_change_cv ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||||
{ | |||||
Controller_Module *c = (Controller_Module*)user_data; | |||||
if ( c->mode() != OSC ) | |||||
return 0; | |||||
OSC_DMSG(); | |||||
const Port *p = c->control_output[0].connected_port(); | |||||
float f = argv[0]->f; | |||||
if (p->hints.ranged ) | |||||
{ | |||||
// scale value to range. | |||||
// we assume that CV values are between 0 and 1 | |||||
float scale = p->hints.maximum - p->hints.minimum; | |||||
float offset = p->hints.minimum; | |||||
f = ( f * scale ) + offset; | |||||
} | |||||
c->control_value = f; | |||||
mixer->osc_endpoint->send( lo_message_get_source( msg ), "/reply", path, "ok" ); | |||||
return 0; | |||||
} |
@@ -106,9 +106,6 @@ private: | |||||
char *generate_osc_path ( void ); | char *generate_osc_path ( void ); | ||||
void change_osc_path ( char *path ); | void change_osc_path ( char *path ); | ||||
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 ); | |||||
std::vector<JACK::Port> jack_input; | std::vector<JACK::Port> jack_input; | ||||
Mode _mode; | Mode _mode; | ||||
Type _type; | Type _type; | ||||
@@ -37,6 +37,7 @@ | |||||
#include <FL/Fl_Menu_Button.H> | #include <FL/Fl_Menu_Button.H> | ||||
#include "FL/test_press.H" | #include "FL/test_press.H" | ||||
#include "FL/menu_popup.H" | #include "FL/menu_popup.H" | ||||
#include "Mixer.H" | |||||
@@ -65,7 +66,6 @@ Module::Module ( ) : Fl_Group( 0, 0, 50, 50, "Unnamed" ) | |||||
{ | { | ||||
init(); | init(); | ||||
log_create(); | log_create(); | ||||
} | } | ||||
@@ -83,12 +83,16 @@ Module::~Module ( ) | |||||
for ( unsigned int i = 0; i < audio_output.size(); ++i ) | for ( unsigned int i = 0; i < audio_output.size(); ++i ) | ||||
audio_output[i].disconnect(); | audio_output[i].disconnect(); | ||||
for ( unsigned int i = 0; i < control_input.size(); ++i ) | for ( unsigned int i = 0; i < control_input.size(); ++i ) | ||||
{ | |||||
control_input[i].disconnect(); | control_input[i].disconnect(); | ||||
control_input[i].destroy_osc_port(); | |||||
} | |||||
for ( unsigned int i = 0; i < control_output.size(); ++i ) | for ( unsigned int i = 0; i < control_output.size(); ++i ) | ||||
control_output[i].disconnect(); | control_output[i].disconnect(); | ||||
audio_input.clear(); | audio_input.clear(); | ||||
audio_output.clear(); | audio_output.clear(); | ||||
control_input.clear(); | control_input.clear(); | ||||
control_output.clear(); | control_output.clear(); | ||||
} | } | ||||
@@ -187,6 +191,118 @@ Module::paste_before ( void ) | |||||
m->copy(); | m->copy(); | ||||
} | } | ||||
char * | |||||
Module::Port::generate_osc_path () | |||||
{ | |||||
const Port *p = this; | |||||
char *path; | |||||
// /mixer/strip/STRIPNAME/control/MODULENAME/CONTROLNAME | |||||
asprintf( &path, "/mixer/strip/%s/control/%s/%s", module()->chain()->name(), p->module()->label(), p->name() ); | |||||
// asprintf( &path, "/mixer/strip/control/%s/%s", 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--; ) | |||||
{ | |||||
if ( path[i] == ' ' ) | |||||
path[i] = '_'; | |||||
} | |||||
return path; | |||||
} | |||||
void | |||||
Module::Port::change_osc_path ( char *path ) | |||||
{ | |||||
if ( _osc_path ) | |||||
{ | |||||
mixer->osc_endpoint->del_method( _osc_path, "f" ); | |||||
free( _osc_path ); | |||||
free( _osc_path_cv ); | |||||
_osc_path = NULL; | |||||
_osc_path_cv = NULL; | |||||
} | |||||
if ( path ) | |||||
{ | |||||
_osc_path_cv = (char*)malloc( strlen( path ) + 4 ); | |||||
_osc_path_cv[0] = 0; | |||||
strcpy( _osc_path_cv, path ); | |||||
strcat( _osc_path_cv, "/cv" ); | |||||
mixer->osc_endpoint->add_method( path, "f", &Module::Port::osc_control_change_exact, this, "value" ); | |||||
mixer->osc_endpoint->add_method( _osc_path_cv, "f", &Module::Port::osc_control_change_cv, this, "value" ); | |||||
_osc_path = path; | |||||
// tooltip( _osc_path ); | |||||
} | |||||
} | |||||
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 *p = (Module::Port*)user_data; | |||||
OSC_DMSG(); | |||||
// const Port *p = c->control_output[0].connected_port(); | |||||
float f = argv[0]->f; | |||||
if ( p->hints.ranged ) | |||||
{ | |||||
if ( f > p->hints.maximum ) | |||||
f = p->hints.maximum; | |||||
else if ( f < p->hints.minimum ) | |||||
f = p->hints.minimum; | |||||
} | |||||
p->control_value( f ); | |||||
mixer->osc_endpoint->send( lo_message_get_source( msg ), "/reply", path, "ok" ); | |||||
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 *p = (Module::Port*)user_data; | |||||
// const Port *p = c->control_output[0].connected_port(); | |||||
float f = argv[0]->f; | |||||
if (p->hints.ranged ) | |||||
{ | |||||
// scale value to range. | |||||
// we assume that CV values are between 0 and 1 | |||||
float scale = p->hints.maximum - p->hints.minimum; | |||||
float offset = p->hints.minimum; | |||||
f = ( f * scale ) + offset; | |||||
} | |||||
p->control_value( f ); | |||||
// c->control_value = f; | |||||
mixer->osc_endpoint->send( lo_message_get_source( msg ), "/reply", path, "ok" ); | |||||
return 0; | |||||
} | |||||
void | void | ||||
Module::set ( Log_Entry &e ) | Module::set ( Log_Entry &e ) | ||||
{ | { | ||||
@@ -30,6 +30,7 @@ | |||||
#include "Loggable.H" | #include "Loggable.H" | ||||
#include "JACK/Port.H" | #include "JACK/Port.H" | ||||
#include "OSC/Endpoint.H" | |||||
class Chain; | class Chain; | ||||
class Module_Parameter_Editor; | class Module_Parameter_Editor; | ||||
@@ -97,7 +98,7 @@ public: | |||||
float maximum; | float maximum; | ||||
float default_value; | float default_value; | ||||
int dimensions; | int dimensions; | ||||
Hints ( ) | Hints ( ) | ||||
{ | { | ||||
type = LINEAR; | type = LINEAR; | ||||
@@ -109,6 +110,9 @@ 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 ); | |||||
Hints hints; | Hints hints; | ||||
Port ( Module *module, Direction direction, Type type, const char *name = 0 ) | Port ( Module *module, Direction direction, Type type, const char *name = 0 ) | ||||
@@ -120,6 +124,8 @@ public: | |||||
_nframes = 0; | _nframes = 0; | ||||
_connected = 0; | _connected = 0; | ||||
_module = module; | _module = module; | ||||
_osc_path = 0; | |||||
_osc_path_cv = 0; | |||||
} | } | ||||
Port ( const Port& p ) | Port ( const Port& p ) | ||||
@@ -132,10 +138,13 @@ public: | |||||
_connected = p._connected; | _connected = p._connected; | ||||
_module = p._module; | _module = p._module; | ||||
hints = p.hints; | hints = p.hints; | ||||
_osc_path = p._osc_path; | |||||
_osc_path_cv = p._osc_path; | |||||
} | } | ||||
virtual ~Port ( ) | virtual ~Port ( ) | ||||
{ | { | ||||
// change_osc_path( NULL ); | |||||
// disconnect(); | // disconnect(); | ||||
} | } | ||||
@@ -149,6 +158,17 @@ public: | |||||
void buffer ( void *buf, nframes_t nframes ) { _buf = buf; _nframes = nframes; }; | void buffer ( void *buf, nframes_t nframes ) { _buf = buf; _nframes = nframes; }; | ||||
void *buffer ( void ) const { return _buf; } | void *buffer ( void ) const { return _buf; } | ||||
void update_osc_port ( ) | |||||
{ | |||||
if ( INPUT == _direction ) | |||||
change_osc_path( generate_osc_path() ); | |||||
} | |||||
void destroy_osc_port ( ) | |||||
{ | |||||
change_osc_path( NULL ); | |||||
} | |||||
void control_value_no_callback ( float f ) | void control_value_no_callback ( float f ) | ||||
{ | { | ||||
THREAD_ASSERT( UI ); | THREAD_ASSERT( UI ); | ||||
@@ -163,6 +183,8 @@ public: | |||||
{ | { | ||||
control_value_no_callback( f ); | control_value_no_callback( f ); | ||||
_module->handle_control_changed( this ); | _module->handle_control_changed( this ); | ||||
if ( connected() ) | |||||
connected_port()->_module->handle_control_changed( connected_port() ); | |||||
} | } | ||||
float control_value ( ) const | float control_value ( ) const | ||||
@@ -208,6 +230,9 @@ public: | |||||
private: | private: | ||||
char *generate_osc_path ( void ); | |||||
void change_osc_path ( char *path ); | |||||
Port *_connected; | Port *_connected; | ||||
Type _type; | Type _type; | ||||
Direction _direction; | Direction _direction; | ||||
@@ -215,6 +240,9 @@ public: | |||||
void *_buf; | void *_buf; | ||||
nframes_t _nframes; | nframes_t _nframes; | ||||
Module *_module; | Module *_module; | ||||
char *_osc_path; | |||||
char *_osc_path_cv; | |||||
}; | }; | ||||
void bbox ( int &X, int &Y, int &W, int &H ) | void bbox ( int &X, int &Y, int &W, int &H ) | ||||
@@ -317,7 +345,15 @@ public: | |||||
} | } | ||||
Chain *chain ( void ) const { return _chain; } | Chain *chain ( void ) const { return _chain; } | ||||
void chain ( Chain * v ) { _chain = v; } | |||||
void chain ( Chain * v ) | |||||
{ | |||||
_chain = v; | |||||
for ( int i = 0; i < ncontrol_inputs(); ++i ) | |||||
{ | |||||
control_input[i].update_osc_port(); | |||||
} | |||||
} | |||||
char *get_parameters ( void ) const; | char *get_parameters ( void ) const; | ||||
void set_parameters ( const char * ); | void set_parameters ( const char * ); | ||||