Mixer: Implement two way mapping for OSC learning.
This commit is contained in:
parent
d7d711807d
commit
37d5dd87b9
2
lib/ntk
2
lib/ntk
|
@ -1 +1 @@
|
||||||
Subproject commit 02768c459a81592abaa50c6095b3a60b1049b4fc
|
Subproject commit 8ee564bef320b3561e204d17c1aa054311b2ce47
|
|
@ -45,6 +45,8 @@
|
||||||
// needed for mixer->endpoint
|
// needed for mixer->endpoint
|
||||||
#include "Mixer.H"
|
#include "Mixer.H"
|
||||||
|
|
||||||
|
bool Controller_Module::_learn_mode = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Controller_Module::Controller_Module ( bool is_default ) : Module( is_default, 50, 100, name() )
|
Controller_Module::Controller_Module ( bool is_default ) : Module( is_default, 50, 100, name() )
|
||||||
|
@ -517,6 +519,19 @@ Controller_Module::menu ( void )
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Controller_Module::draw ( void )
|
||||||
|
{
|
||||||
|
draw_box(x(),y(),w(),h());
|
||||||
|
Fl_Group::draw();
|
||||||
|
|
||||||
|
|
||||||
|
if ( learn_mode() )
|
||||||
|
{
|
||||||
|
fl_rectf( x(),y(),w(),h(), fl_color_add_alpha( FL_MAGENTA, 50 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Controller_Module::handle ( int m )
|
Controller_Module::handle ( int m )
|
||||||
{
|
{
|
||||||
|
@ -525,7 +540,24 @@ Controller_Module::handle ( int m )
|
||||||
{
|
{
|
||||||
case FL_PUSH:
|
case FL_PUSH:
|
||||||
{
|
{
|
||||||
if ( test_press( FL_BUTTON3 ) )
|
if ( learn_mode() )
|
||||||
|
{
|
||||||
|
tooltip( "Now learning control. Move the desired control on your controller" );
|
||||||
|
|
||||||
|
//connect_to( &module->control_input[port] );
|
||||||
|
Port *p = control_output[0].connected_port();
|
||||||
|
|
||||||
|
if ( p )
|
||||||
|
{
|
||||||
|
DMESSAGE( "Will learn %s", p->osc_path() );
|
||||||
|
|
||||||
|
mixer->osc_endpoint->learn( p->osc_path() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Fl::event_button3() )
|
||||||
{
|
{
|
||||||
/* context menu */
|
/* context menu */
|
||||||
if ( type() != SPATIALIZATION )
|
if ( type() != SPATIALIZATION )
|
||||||
|
|
|
@ -40,11 +40,13 @@ class Controller_Module : public Module
|
||||||
static void menu_cb ( Fl_Widget *w, void *v );
|
static void menu_cb ( Fl_Widget *w, void *v );
|
||||||
void menu_cb ( const Fl_Menu_ *m );
|
void menu_cb ( const Fl_Menu_ *m );
|
||||||
|
|
||||||
char *_osc_path;
|
|
||||||
char *_osc_path_cv;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
static bool _learn_mode;
|
||||||
|
|
||||||
|
static bool learn_mode ( void ) { return _learn_mode; }
|
||||||
|
static void learn_mode ( bool b ) { _learn_mode = b; }
|
||||||
|
|
||||||
enum Mode { GUI, CV, OSC, MIDI };
|
enum Mode { GUI, CV, OSC, MIDI };
|
||||||
|
|
||||||
enum Type { KNOB,
|
enum Type { KNOB,
|
||||||
|
@ -88,11 +90,7 @@ public:
|
||||||
|
|
||||||
void process ( nframes_t nframes );
|
void process ( nframes_t nframes );
|
||||||
|
|
||||||
void draw ( void )
|
void draw ( void );
|
||||||
{
|
|
||||||
draw_box(x(),y(),w(),h());
|
|
||||||
Fl_Group::draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
int handle ( int m );
|
int handle ( int m );
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,8 @@
|
||||||
#include "OSC/Endpoint.H"
|
#include "OSC/Endpoint.H"
|
||||||
#include <lo/lo.h>
|
#include <lo/lo.h>
|
||||||
|
|
||||||
|
#include "Controller_Module.H"
|
||||||
|
|
||||||
extern char *user_config_dir;
|
extern char *user_config_dir;
|
||||||
extern char *instance_name;
|
extern char *instance_name;
|
||||||
|
|
||||||
|
@ -55,11 +57,25 @@ extern char *instance_name;
|
||||||
#include "string_util.h"
|
#include "string_util.h"
|
||||||
|
|
||||||
#include "NSM.H"
|
#include "NSM.H"
|
||||||
|
#include <FL/Fl_Tooltip.H>
|
||||||
|
|
||||||
extern NSM_Client *nsm;
|
extern NSM_Client *nsm;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
mixer_show_tooltip ( const char *s )
|
||||||
|
{
|
||||||
|
mixer->status( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mixer_hide_tooltip ( void )
|
||||||
|
{
|
||||||
|
mixer->status( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************/
|
/************************/
|
||||||
/* OSC Message Handlers */
|
/* OSC Message Handlers */
|
||||||
/************************/
|
/************************/
|
||||||
|
@ -262,6 +278,18 @@ void Mixer::cb_menu(Fl_Widget* o) {
|
||||||
fl_alert( "%s", "Failed to import strip!" );
|
fl_alert( "%s", "Failed to import strip!" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ( ! strcmp( picked, "&Mixer/Start Learning" ) )
|
||||||
|
{
|
||||||
|
Controller_Module::learn_mode( true );
|
||||||
|
status( "Now in learn mode. Click on a highlighted control to teach it something." );
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
else if ( ! strcmp( picked, "&Mixer/Stop Learning" ) )
|
||||||
|
{
|
||||||
|
Controller_Module::learn_mode( false );
|
||||||
|
status( "Learning complete" );
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
else if ( !strcmp( picked, "&Mixer/Paste" ) )
|
else if ( !strcmp( picked, "&Mixer/Paste" ) )
|
||||||
{
|
{
|
||||||
Fl::paste(*this);
|
Fl::paste(*this);
|
||||||
|
@ -286,18 +314,6 @@ void Mixer::cb_menu(Fl_Widget* o) {
|
||||||
{
|
{
|
||||||
fl_theme_chooser();
|
fl_theme_chooser();
|
||||||
}
|
}
|
||||||
else if (! strcmp( picked, "&Options/&Display/Update Frequency/15 Hz" ) )
|
|
||||||
{
|
|
||||||
update_frequency( 15.0f );
|
|
||||||
}
|
|
||||||
else if (! strcmp( picked, "&Options/&Display/Update Frequency/30 Hz" ) )
|
|
||||||
{
|
|
||||||
update_frequency( 30.0f );
|
|
||||||
}
|
|
||||||
else if (! strcmp( picked, "&Options/&Display/Update Frequency/60 Hz" ) )
|
|
||||||
{
|
|
||||||
update_frequency( 60.0f );
|
|
||||||
}
|
|
||||||
else if ( ! strcmp( picked, "&Help/&About" ) )
|
else if ( ! strcmp( picked, "&Help/&About" ) )
|
||||||
{
|
{
|
||||||
About_Dialog ab( PIXMAP_PATH "/non-mixer/icon-256x256.png" );
|
About_Dialog ab( PIXMAP_PATH "/non-mixer/icon-256x256.png" );
|
||||||
|
@ -422,7 +438,7 @@ Mixer::load_project_settings ( void )
|
||||||
{
|
{
|
||||||
reset_project_settings();
|
reset_project_settings();
|
||||||
|
|
||||||
// if ( Project::open() )
|
if ( Project::open() )
|
||||||
((Fl_Menu_Settings*)menubar)->load( menubar->find_item( "&Project/Se&ttings" ), "options" );
|
((Fl_Menu_Settings*)menubar)->load( menubar->find_item( "&Project/Se&ttings" ), "options" );
|
||||||
|
|
||||||
update_menu();
|
update_menu();
|
||||||
|
@ -434,6 +450,15 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) :
|
||||||
Loggable::dirty_callback( &Mixer::handle_dirty, this );
|
Loggable::dirty_callback( &Mixer::handle_dirty, this );
|
||||||
Loggable::progress_callback( progress_cb, NULL );
|
Loggable::progress_callback( progress_cb, NULL );
|
||||||
|
|
||||||
|
Fl_Tooltip::hoverdelay( 0 );
|
||||||
|
Fl_Tooltip::delay( 0 );
|
||||||
|
fl_show_tooltip = mixer_show_tooltip;
|
||||||
|
fl_hide_tooltip = mixer_hide_tooltip;
|
||||||
|
/* Fl_Tooltip::size( 11 ); */
|
||||||
|
/* Fl_Tooltip::textcolor( FL_FOREGROUND_COLOR ); */
|
||||||
|
/* Fl_Tooltip::color( fl_color_add_alpha( FL_DARK1, 0 ) ); */
|
||||||
|
// fl_tooltip_docked = 1;
|
||||||
|
|
||||||
_rows = 1;
|
_rows = 1;
|
||||||
box( FL_FLAT_BOX );
|
box( FL_FLAT_BOX );
|
||||||
labelsize( 96 );
|
labelsize( 96 );
|
||||||
|
@ -452,6 +477,8 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) :
|
||||||
o->add( "&Mixer/Add &N Strips" );
|
o->add( "&Mixer/Add &N Strips" );
|
||||||
o->add( "&Mixer/&Import Strip" );
|
o->add( "&Mixer/&Import Strip" );
|
||||||
o->add( "&Mixer/Paste", FL_CTRL + 'v', 0, 0 );
|
o->add( "&Mixer/Paste", FL_CTRL + 'v', 0, 0 );
|
||||||
|
o->add( "&Mixer/Start Learning", FL_F + 9, 0, 0 );
|
||||||
|
o->add( "&Mixer/Stop Learning", FL_F + 10, 0, 0 );
|
||||||
o->add( "&View/&Theme", 0, 0, 0 );
|
o->add( "&View/&Theme", 0, 0, 0 );
|
||||||
/* o->add( "&Options/&Display/Update Frequency/60 Hz", 0, 0, 0, FL_MENU_RADIO ); */
|
/* o->add( "&Options/&Display/Update Frequency/60 Hz", 0, 0, 0, FL_MENU_RADIO ); */
|
||||||
/* o->add( "&Options/&Display/Update Frequency/30 Hz", 0, 0, 0, FL_MENU_RADIO); */
|
/* o->add( "&Options/&Display/Update Frequency/30 Hz", 0, 0, 0, FL_MENU_RADIO); */
|
||||||
|
@ -483,18 +510,17 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) :
|
||||||
} // Fl_Blink_Button* sm_blinker
|
} // Fl_Blink_Button* sm_blinker
|
||||||
o->end();
|
o->end();
|
||||||
}
|
}
|
||||||
{ Fl_Scroll *o = scroll = new Fl_Scroll( X, Y + 24, W, H - 24 );
|
{ Fl_Scroll *o = scroll = new Fl_Scroll( X, Y + 24, W, H - ( 24 + 18 ) );
|
||||||
o->box( FL_FLAT_BOX );
|
o->box( FL_FLAT_BOX );
|
||||||
// o->type( Fl_Scroll::HORIZONTAL_ALWAYS );
|
// o->type( Fl_Scroll::HORIZONTAL_ALWAYS );
|
||||||
// o->box( Fl_Scroll::BOTH );
|
// o->box( Fl_Scroll::BOTH );
|
||||||
{
|
{
|
||||||
Fl_Flowpack *o = mixer_strips = new Fl_Flowpack( X, Y + 24, W, H - 18 - 24 );
|
Fl_Flowpack *o = mixer_strips = new Fl_Flowpack( X, Y + 24, W, H - ( 18*2 + 24 ));
|
||||||
// label( "Non-Mixer" );
|
// label( "Non-Mixer" );
|
||||||
align( (Fl_Align)(FL_ALIGN_CENTER | FL_ALIGN_INSIDE) );
|
align( (Fl_Align)(FL_ALIGN_CENTER | FL_ALIGN_INSIDE) );
|
||||||
o->flow( false );
|
|
||||||
o->box( FL_FLAT_BOX );
|
o->box( FL_FLAT_BOX );
|
||||||
o->type( Fl_Pack::HORIZONTAL );
|
o->type( Fl_Pack::HORIZONTAL );
|
||||||
o->hspacing( 2 );
|
o->hspacing( 2 );
|
||||||
o->vspacing( 2 );
|
o->vspacing( 2 );
|
||||||
o->end();
|
o->end();
|
||||||
Fl_Group::current()->resizable( o );
|
Fl_Group::current()->resizable( o );
|
||||||
|
@ -502,7 +528,12 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) :
|
||||||
o->end();
|
o->end();
|
||||||
Fl_Group::current()->resizable( o );
|
Fl_Group::current()->resizable( o );
|
||||||
}
|
}
|
||||||
|
{ Fl_Box *o = _status = new Fl_Box( X, Y + H - 18, W, 18 );
|
||||||
|
o->align( FL_ALIGN_LEFT | FL_ALIGN_INSIDE );
|
||||||
|
o->labelsize( 10 );
|
||||||
|
o->box( FL_FLAT_BOX );
|
||||||
|
o->color( FL_DARK1 );
|
||||||
|
}
|
||||||
end();
|
end();
|
||||||
|
|
||||||
update_frequency( 15 );
|
update_frequency( 15 );
|
||||||
|
@ -512,6 +543,45 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) :
|
||||||
load_options();
|
load_options();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* translate message addressed to strip number to appropriate strip */
|
||||||
|
int
|
||||||
|
Mixer::osc_strip_by_number ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char *rem;
|
||||||
|
|
||||||
|
OSC::Endpoint *ep = (OSC::Endpoint*)user_data;
|
||||||
|
|
||||||
|
DMESSAGE( "%s", path );
|
||||||
|
|
||||||
|
if ( 2 != sscanf( path, "/strip#/%d/%a[^\n]", &n, &rem ) )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
DMESSAGE( "%s", rem );
|
||||||
|
|
||||||
|
Mixer_Strip *o = mixer->track_by_number( n );
|
||||||
|
|
||||||
|
if ( ! o )
|
||||||
|
{
|
||||||
|
DMESSAGE( "No strip by number %i", n );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *new_path;
|
||||||
|
|
||||||
|
asprintf( &new_path, "/strip/%s/%s", o->name(), rem );
|
||||||
|
|
||||||
|
free( rem );
|
||||||
|
|
||||||
|
DMESSAGE( "Sending %s", new_path );
|
||||||
|
|
||||||
|
lo_send_message( ep->address(), new_path, msg );
|
||||||
|
|
||||||
|
free( new_path );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Mixer::init_osc ( const char *osc_port )
|
Mixer::init_osc ( const char *osc_port )
|
||||||
{
|
{
|
||||||
|
@ -569,6 +639,11 @@ void Mixer::add ( Mixer_Strip *ms )
|
||||||
ms->take_focus();
|
ms->take_focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Mixer::find_strip ( const Mixer_Strip *m ) const
|
||||||
|
{
|
||||||
|
return mixer_strips->find( m );
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Mixer::quit ( void )
|
Mixer::quit ( void )
|
||||||
|
@ -584,8 +659,6 @@ Mixer::insert ( Mixer_Strip *ms, Mixer_Strip *before )
|
||||||
{
|
{
|
||||||
// mixer_strips->remove( ms );
|
// mixer_strips->remove( ms );
|
||||||
mixer_strips->insert( *ms, before );
|
mixer_strips->insert( *ms, before );
|
||||||
|
|
||||||
// scroll->redraw();
|
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
Mixer::insert ( Mixer_Strip *ms, int i )
|
Mixer::insert ( Mixer_Strip *ms, int i )
|
||||||
|
@ -646,23 +719,26 @@ Mixer::rows ( int ideal_rows )
|
||||||
{
|
{
|
||||||
int sh;
|
int sh;
|
||||||
|
|
||||||
int actual_rows;
|
int actual_rows = 1;
|
||||||
|
|
||||||
/* calculate how many rows will actually fit */
|
if ( ideal_rows > 1 )
|
||||||
int can_fit = scroll->h() / ( Mixer_Strip::min_h() );
|
|
||||||
|
|
||||||
actual_rows = can_fit > 0 ? can_fit : 1;
|
|
||||||
|
|
||||||
if ( actual_rows > ideal_rows )
|
|
||||||
actual_rows = ideal_rows;
|
|
||||||
|
|
||||||
/* calculate strip height */
|
|
||||||
if ( actual_rows > 1 )
|
|
||||||
{
|
{
|
||||||
sh = ( scroll->h() / (float)actual_rows ) - ( mixer_strips->vspacing() * ( actual_rows - 2 ));
|
sh = (scroll->h() / ideal_rows ) - (mixer_strips->vspacing() * (ideal_rows - 1));
|
||||||
mixer_strips->flow(true);
|
mixer_strips->flow( true );
|
||||||
|
|
||||||
|
if ( sh < Mixer_Strip::min_h() )
|
||||||
|
{
|
||||||
|
int can_fit = ( scroll->h() - 18 ) / Mixer_Strip::min_h();
|
||||||
|
|
||||||
|
actual_rows = can_fit > 0 ? can_fit : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
actual_rows = ideal_rows;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
actual_rows = 1;
|
||||||
|
|
||||||
|
if ( 1 == actual_rows )
|
||||||
{
|
{
|
||||||
sh = (scroll->h() - 18);
|
sh = (scroll->h() - 18);
|
||||||
mixer_strips->flow(false);
|
mixer_strips->flow(false);
|
||||||
|
@ -707,6 +783,15 @@ Mixer::track_by_name ( const char *name )
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
/** retrun a pointer to the track named /name/, or NULL if no track is named /name/ */
|
||||||
|
Mixer_Strip *
|
||||||
|
Mixer::track_by_number ( int n )
|
||||||
|
{
|
||||||
|
if ( n < 0 || n >= mixer_strips->children() )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return (Mixer_Strip*)mixer_strips->child(n);
|
||||||
|
}
|
||||||
|
|
||||||
/** return a malloc'd string representing a unique name for a new track */
|
/** return a malloc'd string representing a unique name for a new track */
|
||||||
char *
|
char *
|
||||||
|
|
|
@ -52,6 +52,7 @@ private:
|
||||||
Fl_Color system_colors[3];
|
Fl_Color system_colors[3];
|
||||||
|
|
||||||
Mixer_Strip* track_by_name ( const char *name );
|
Mixer_Strip* track_by_name ( const char *name );
|
||||||
|
Mixer_Strip* track_by_number ( int n );
|
||||||
|
|
||||||
void snapshot ( void );
|
void snapshot ( void );
|
||||||
static void snapshot ( void *v ) { ((Mixer*)v)->snapshot(); }
|
static void snapshot ( void *v ) { ((Mixer*)v)->snapshot(); }
|
||||||
|
@ -63,6 +64,7 @@ private:
|
||||||
Fl_Scroll *scroll;
|
Fl_Scroll *scroll;
|
||||||
Fl_Pack *pack;
|
Fl_Pack *pack;
|
||||||
Fl_Box *project_name;
|
Fl_Box *project_name;
|
||||||
|
Fl_Box *_status;
|
||||||
|
|
||||||
Fl_Flowpack *mixer_strips;
|
Fl_Flowpack *mixer_strips;
|
||||||
|
|
||||||
|
@ -75,6 +77,7 @@ private:
|
||||||
static void handle_dirty ( int, void *v );
|
static void handle_dirty ( int, void *v );
|
||||||
|
|
||||||
static int osc_non_hello ( const char *, const char *, lo_arg **, int , lo_message msg, void * );
|
static int osc_non_hello ( const char *, const char *, lo_arg **, int , lo_message msg, void * );
|
||||||
|
static int osc_strip_by_number ( const char *, const char *, lo_arg **, int , lo_message msg, void * );
|
||||||
|
|
||||||
static void update_cb ( void * );
|
static void update_cb ( void * );
|
||||||
void update_cb ( void );
|
void update_cb ( void );
|
||||||
|
@ -83,6 +86,11 @@ public:
|
||||||
|
|
||||||
void update_frequency ( float f );
|
void update_frequency ( float f );
|
||||||
|
|
||||||
|
void status ( const char *s ) {
|
||||||
|
if ( s ) _status->copy_label( s );
|
||||||
|
else _status->label(0);
|
||||||
|
_status->redraw(); }
|
||||||
|
|
||||||
virtual int handle ( int m );
|
virtual int handle ( int m );
|
||||||
|
|
||||||
char * get_unique_track_name ( const char *name );
|
char * get_unique_track_name ( const char *name );
|
||||||
|
@ -102,6 +110,7 @@ public:
|
||||||
void insert ( Mixer_Strip *ms, int i );
|
void insert ( Mixer_Strip *ms, int i );
|
||||||
bool contains ( Mixer_Strip *ms );
|
bool contains ( Mixer_Strip *ms );
|
||||||
Mixer_Strip * event_inside ( void );
|
Mixer_Strip * event_inside ( void );
|
||||||
|
int find_strip ( const Mixer_Strip *m ) const;
|
||||||
|
|
||||||
bool save ( void );
|
bool save ( void );
|
||||||
void quit ( void );
|
void quit ( void );
|
||||||
|
|
|
@ -389,6 +389,7 @@ Mixer_Strip::init ( )
|
||||||
|
|
||||||
{ Fl_Box *o = color_box = new Fl_Box( 0,0, 25, 10 );
|
{ Fl_Box *o = color_box = new Fl_Box( 0,0, 25, 10 );
|
||||||
o->box(FL_FLAT_BOX);
|
o->box(FL_FLAT_BOX);
|
||||||
|
o->tooltip( "Drag and drop to move strip" );
|
||||||
}
|
}
|
||||||
|
|
||||||
{ Fl_Pack *o = new Fl_Pack( 2, 2, 114, 100 );
|
{ Fl_Pack *o = new Fl_Pack( 2, 2, 114, 100 );
|
||||||
|
@ -727,8 +728,9 @@ Mixer_Strip::handle ( int m )
|
||||||
}
|
}
|
||||||
case FL_PUSH:
|
case FL_PUSH:
|
||||||
if ( Fl::event_button1() && Fl::event_inside( color_box ) )
|
if ( Fl::event_button1() && Fl::event_inside( color_box ) )
|
||||||
{
|
dragging = this;
|
||||||
}
|
else
|
||||||
|
dragging = NULL;
|
||||||
|
|
||||||
_button = Fl::event_button();
|
_button = Fl::event_button();
|
||||||
|
|
||||||
|
@ -737,18 +739,17 @@ Mixer_Strip::handle ( int m )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FL_DRAG:
|
case FL_DRAG:
|
||||||
if ( Fl::event_is_click() )
|
return 1;
|
||||||
return 1;
|
|
||||||
|
|
||||||
dragging = this;
|
|
||||||
break;
|
break;
|
||||||
case FL_RELEASE:
|
case FL_RELEASE:
|
||||||
if ( dragging == this )
|
if ( dragging == this && ! Fl::event_is_click() )
|
||||||
{
|
{
|
||||||
mixer->insert( this, mixer->event_inside() );
|
mixer->insert( this, mixer->event_inside() );
|
||||||
dragging = NULL;
|
dragging = NULL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dragging = NULL;
|
||||||
|
|
||||||
int b = _button;
|
int b = _button;
|
||||||
_button = 0;
|
_button = 0;
|
||||||
|
@ -769,6 +770,11 @@ Mixer_Strip::handle ( int m )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Mixer_Strip::number ( void ) const
|
||||||
|
{
|
||||||
|
return mixer->find_strip( this );
|
||||||
|
}
|
||||||
|
|
||||||
/************/
|
/************/
|
||||||
/* Commands */
|
/* Commands */
|
||||||
|
|
|
@ -141,6 +141,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
int number ( void ) const;
|
||||||
static bool import_strip ( const char *filename );
|
static bool import_strip ( const char *filename );
|
||||||
|
|
||||||
void command_move_left ( void );
|
void command_move_left ( void );
|
||||||
|
|
|
@ -226,12 +226,42 @@ Module::paste_before ( void )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Module::Port::send_feedback ( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( _scaled_signal )
|
||||||
|
{
|
||||||
|
/* send feedback for by_name signal */
|
||||||
|
mixer->osc_endpoint->send_feedback( _scaled_signal->path(), control_value() );
|
||||||
|
|
||||||
|
/* send feedback for by number signal */
|
||||||
|
{
|
||||||
|
int n = _module->chain()->strip()->number();
|
||||||
|
|
||||||
|
char *s = strdup( _scaled_signal->path() );
|
||||||
|
|
||||||
|
char *suffix = index( s, '/' );
|
||||||
|
suffix = index( suffix, '/' );
|
||||||
|
suffix = index( suffix, '/' );
|
||||||
|
|
||||||
|
char *path;
|
||||||
|
asprintf( &path, "/strip#/%i%s", suffix );
|
||||||
|
|
||||||
|
mixer->osc_endpoint->send_feedback( path, control_value() );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Module::handle_control_changed ( Port *p )
|
Module::handle_control_changed ( Port *p )
|
||||||
{
|
{
|
||||||
if ( _editor )
|
if ( _editor )
|
||||||
_editor->handle_control_changed ( p );
|
_editor->handle_control_changed ( p );
|
||||||
|
|
||||||
|
p->send_feedback();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -239,6 +239,8 @@ public:
|
||||||
update_connected_port_buffer();
|
update_connected_port_buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void send_feedback ( void );
|
||||||
|
|
||||||
void disconnect ( void )
|
void disconnect ( void )
|
||||||
{
|
{
|
||||||
if ( _connected && _connected != (void*)0x01 )
|
if ( _connected && _connected != (void*)0x01 )
|
||||||
|
|
|
@ -180,6 +180,7 @@ namespace OSC
|
||||||
|
|
||||||
Endpoint::Endpoint ( )
|
Endpoint::Endpoint ( )
|
||||||
{
|
{
|
||||||
|
_learning_path = NULL;
|
||||||
_peer_signal_notification_callback = 0;
|
_peer_signal_notification_callback = 0;
|
||||||
_peer_signal_notification_userdata = 0;
|
_peer_signal_notification_userdata = 0;
|
||||||
_peer_scan_complete_callback = 0;
|
_peer_scan_complete_callback = 0;
|
||||||
|
@ -196,6 +197,10 @@ namespace OSC
|
||||||
|
|
||||||
_server = lo_server_new_with_proto( port, proto, error_handler );
|
_server = lo_server_new_with_proto( port, proto, error_handler );
|
||||||
|
|
||||||
|
char *url = lo_server_get_url( _server );
|
||||||
|
_addr = lo_address_new_from_url( url );
|
||||||
|
free( url );
|
||||||
|
|
||||||
if ( ! _server )
|
if ( ! _server )
|
||||||
{
|
{
|
||||||
WARNING( "Error creating OSC server" );
|
WARNING( "Error creating OSC server" );
|
||||||
|
@ -210,8 +215,8 @@ namespace OSC
|
||||||
add_method( "/signal/created", "ssifff", &Endpoint::osc_sig_created, this, "" );
|
add_method( "/signal/created", "ssifff", &Endpoint::osc_sig_created, this, "" );
|
||||||
add_method( "/signal/change", "iif", &Endpoint::osc_sig_handler, this, "" );
|
add_method( "/signal/change", "iif", &Endpoint::osc_sig_handler, this, "" );
|
||||||
add_method( "/signal/list", NULL, &Endpoint::osc_signal_lister, this, "" );
|
add_method( "/signal/list", NULL, &Endpoint::osc_signal_lister, this, "" );
|
||||||
add_method( NULL, "", &Endpoint::osc_generic, this, "" );
|
|
||||||
add_method( "/reply", NULL, &Endpoint::osc_reply, this, "" );
|
add_method( "/reply", NULL, &Endpoint::osc_reply, this, "" );
|
||||||
|
add_method( NULL, NULL, &Endpoint::osc_generic, this, "" );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -694,16 +699,46 @@ namespace OSC
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Endpoint::add_translation ( const char *a, const char *b )
|
||||||
|
{
|
||||||
|
_translations[a].path = b;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Endpoint::osc_generic ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
|
Endpoint::osc_generic ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
|
||||||
{
|
{
|
||||||
// OSC_DMSG();
|
// OSC_DMSG();
|
||||||
|
Endpoint *ep = (Endpoint*)user_data;
|
||||||
|
|
||||||
|
if ( ep->_learning_path )
|
||||||
|
{
|
||||||
|
ep->add_translation( path, ep->_learning_path );
|
||||||
|
|
||||||
|
DMESSAGE( "Learned translation \"%s\" -> \"%s\"", path, ep->_learning_path );
|
||||||
|
|
||||||
|
free(ep->_learning_path);
|
||||||
|
ep->_learning_path = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::map<std::string,TranslationDestination>::const_iterator i = ep->_translations.find( path );
|
||||||
|
|
||||||
|
if ( i != ep->_translations.end() )
|
||||||
|
{
|
||||||
|
const char *dpath = i->second.path.c_str();
|
||||||
|
|
||||||
|
DMESSAGE( "Translating message \"%s\" to \"%s\"", path, dpath );
|
||||||
|
lo_send_message(ep->_addr, dpath, msg );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( argc || path[ strlen(path) - 1 ] != '/' )
|
if ( argc || path[ strlen(path) - 1 ] != '/' )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
Endpoint *ep = (Endpoint*)user_data;
|
|
||||||
|
|
||||||
for ( std::list<Method*>::const_iterator i = ep->_methods.begin(); i != ep->_methods.end(); ++i )
|
for ( std::list<Method*>::const_iterator i = ep->_methods.begin(); i != ep->_methods.end(); ++i )
|
||||||
{
|
{
|
||||||
if ( ! (*i)->path() )
|
if ( ! (*i)->path() )
|
||||||
|
@ -1212,6 +1247,51 @@ namespace OSC
|
||||||
_signals.remove( o );
|
_signals.remove( o );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* prepare to learn a translation for /path/. The next unhandled message to come through will be mapped to /path/ */
|
||||||
|
void
|
||||||
|
Endpoint::learn ( const char *path )
|
||||||
|
{
|
||||||
|
if ( _learning_path )
|
||||||
|
free( _learning_path );
|
||||||
|
|
||||||
|
_learning_path = NULL;
|
||||||
|
|
||||||
|
if ( path )
|
||||||
|
_learning_path = strdup( path );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** if there's a translation with a destination of 'path', then send feedback for it */
|
||||||
|
void
|
||||||
|
Endpoint::send_feedback ( const char *path, float v )
|
||||||
|
{
|
||||||
|
for ( std::map<std::string,TranslationDestination>::iterator i = _translations.begin();
|
||||||
|
i != _translations.end();
|
||||||
|
i++ )
|
||||||
|
{
|
||||||
|
if ( ! strcmp( i->second.path.c_str(), path ) )
|
||||||
|
{
|
||||||
|
/* found it */
|
||||||
|
if ( i->second.current_value != v )
|
||||||
|
{
|
||||||
|
const char *spath = i->first.c_str();
|
||||||
|
|
||||||
|
DMESSAGE( "Sending feedback to \"%s\": %f", spath, v );
|
||||||
|
|
||||||
|
/* send to all peers */
|
||||||
|
for ( std::list<Peer*>::iterator p = _peers.begin();
|
||||||
|
p != _peers.end();
|
||||||
|
++p )
|
||||||
|
{
|
||||||
|
send( (*p)->addr, spath, v );
|
||||||
|
}
|
||||||
|
|
||||||
|
i->second.current_value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Peer *
|
Peer *
|
||||||
Endpoint::add_peer ( const char *name, const char *url )
|
Endpoint::add_peer ( const char *name, const char *url )
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,8 +22,10 @@
|
||||||
#include <lo/lo.h>
|
#include <lo/lo.h>
|
||||||
#include "Thread.H"
|
#include "Thread.H"
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <string>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
namespace OSC
|
namespace OSC
|
||||||
{
|
{
|
||||||
|
@ -244,11 +246,23 @@ namespace OSC
|
||||||
|
|
||||||
// lo_server_thread _st;
|
// lo_server_thread _st;
|
||||||
lo_server _server;
|
lo_server _server;
|
||||||
|
lo_address _addr;
|
||||||
|
|
||||||
std::list<Peer*> _peers;
|
std::list<Peer*> _peers;
|
||||||
std::list<Signal*> _signals;
|
std::list<Signal*> _signals;
|
||||||
std::list<Method*> _methods;
|
std::list<Method*> _methods;
|
||||||
|
|
||||||
|
char *_learning_path;
|
||||||
|
|
||||||
|
class TranslationDestination {
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string path;
|
||||||
|
float current_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::string,TranslationDestination> _translations;
|
||||||
|
|
||||||
void (*_peer_scan_complete_callback)(void*);
|
void (*_peer_scan_complete_callback)(void*);
|
||||||
void *_peer_scan_complete_userdata;
|
void *_peer_scan_complete_userdata;
|
||||||
|
|
||||||
|
@ -296,6 +310,16 @@ namespace OSC
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
void send_feedback ( const char *path, float v );
|
||||||
|
void learn ( const char *path );
|
||||||
|
|
||||||
|
lo_address address ( void )
|
||||||
|
{
|
||||||
|
return _addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_translation ( const char *a, const char *b );
|
||||||
|
|
||||||
void peer_signal_notification_callback ( void (*cb)(OSC::Signal *, OSC::Signal::State, void*), void *userdata )
|
void peer_signal_notification_callback ( void (*cb)(OSC::Signal *, OSC::Signal::State, void*), void *userdata )
|
||||||
{
|
{
|
||||||
_peer_signal_notification_callback = cb;
|
_peer_signal_notification_callback = cb;
|
||||||
|
|
Loading…
Reference in New Issue