From 16556bb182b19e6baae34543768668b5eeb3cd45 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 15 Jan 2009 22:09:23 +0000 Subject: [PATCH] OSC becomes a control protocol object; make ardev_common.sh(.in) look for surfaces in the right place(s) git-svn-id: svn://localhost/ardour2/branches/3.0@4411 d708f5d6-7413-0410-9779-e7cbd77b26cf --- SConstruct | 29 +- gtk2_ardour/ardev_common.sh.in | 1 + libs/ardour/SConscript | 8 - libs/ardour/globals.cc | 33 -- libs/ardour/session.cc | 13 - libs/surfaces/generic_midi/SConscript | 2 +- libs/surfaces/osc/SConscript | 63 ++++ libs/surfaces/osc/interface.cc | 66 ++++ libs/{ardour => surfaces/osc}/osc.cc | 374 +++++++++++++++++++-- libs/{ardour/ardour => surfaces/osc}/osc.h | 70 +++- libs/surfaces/osc/osc_controllable.cc | 54 +++ libs/surfaces/osc/osc_controllable.h | 46 +++ 12 files changed, 646 insertions(+), 113 deletions(-) create mode 100644 libs/surfaces/osc/SConscript create mode 100644 libs/surfaces/osc/interface.cc rename libs/{ardour => surfaces/osc}/osc.cc (62%) rename libs/{ardour/ardour => surfaces/osc}/osc.h (70%) create mode 100644 libs/surfaces/osc/osc_controllable.cc create mode 100644 libs/surfaces/osc/osc_controllable.h diff --git a/SConstruct b/SConstruct index e603a0e305..1744090bd4 100644 --- a/SConstruct +++ b/SConstruct @@ -45,7 +45,6 @@ opts.AddOptions( BoolOption('EXTRA_WARN', 'Compile with -Wextra, -ansi, and -pedantic. Might break compilation. For pedants', 0), BoolOption('FREESOUND', 'Include Freesound database lookup', 0), BoolOption('FPU_OPTIMIZATION', 'Build runtime checked assembler code', 1), - BoolOption('LIBLO', 'Compile with support for liblo library', 1), BoolOption('NLS', 'Set to turn on i18n support', 1), PathOption('PREFIX', 'Set the install "prefix"', '/usr/local'), BoolOption('SURFACES', 'Build support for control surfaces', 1), @@ -867,10 +866,6 @@ if env['EXTRA_WARN']: env.Append(CXXFLAGS="-ansi") # env.Append(CFLAGS="-iso") -if env['LIBLO']: - env.Append(CCFLAGS="-DHAVE_LIBLO") - - # # fix scons nitpickiness on APPLE # @@ -998,16 +993,17 @@ libraries['boost'] = conf.Finish () # # Check for liblo -if env['LIBLO']: - libraries['lo'] = LibraryInfo () - prep_libcheck(env, libraries['lo']) +libraries['lo'] = LibraryInfo () +prep_libcheck(env, libraries['lo']) - conf = Configure (libraries['lo']) - if conf.CheckLib ('lo', 'lo_server_new') == False: - print "liblo does not appear to be installed." - sys.exit (1) - - libraries['lo'] = conf.Finish () +conf = Configure (libraries['lo']) +if conf.CheckLib ('lo', 'lo_server_new') == False: + print "liblo does not appear to be installed." + env['HAVE_LIBLO'] = False +else: + env['HAVE_LIBLO'] = True + +libraries['lo'] = conf.Finish () # # Check for dmalloc @@ -1270,7 +1266,7 @@ else: # # * always build the LGPL control protocol lib, since we link against it from libardour -# * ditto for generic MIDI +# * ditto for generic MIDI and OSC # * tranzport & wiimote check whether they should build internally, but we need them here # so that they are included in the tarball # @@ -1280,7 +1276,8 @@ surface_subdirs = [ 'libs/surfaces/control_protocol', 'libs/surfaces/tranzport', 'libs/surfaces/mackie', 'libs/surfaces/powermate', - 'libs/surfaces/wiimote' + 'libs/surfaces/wiimote', + 'libs/surfaces/osc' ] if env['SURFACES']: diff --git a/gtk2_ardour/ardev_common.sh.in b/gtk2_ardour/ardev_common.sh.in index 28eaad39c7..1af6c77062 100644 --- a/gtk2_ardour/ardev_common.sh.in +++ b/gtk2_ardour/ardev_common.sh.in @@ -3,6 +3,7 @@ cd `dirname "$0"`/.. #export G_DEBUG=fatal_criticals export ARDOUR_PATH=gtk2_ardour/icons:gtk2_ardour/pixmaps:gtk2_ardour:. +export ARDOUR_SURFACES_PATH=libs/surfaces/osc:libs/surfaces/generic_midi:libs/surfaces/tranzport:libs/surfaces/powermate export ARDOUR_DATA_PATH=gtk2_ardour:. if test -d $HOME/gtk/inst ; then echo USING NEW CLEARLOOKS diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 58db70c6a6..f21b623ed2 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -178,7 +178,6 @@ version.cc arch_specific_objects = [ ] -osc_files = [ 'osc.cc' ] vst_files = [ 'vst_plugin.cc', 'session_vst.cc' ] lv2_files = [ 'lv2_plugin.cc' ] audiounit_files = [ 'audio_unit.cc' ] @@ -194,9 +193,6 @@ if ardour['LV2']: extra_sources += lv2_files ardour.Append(CCFLAGS="-DHAVE_SLV2") -if ardour['LIBLO']: - extra_sources += osc_files - ardour.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE") ardour.Append(CXXFLAGS="-DDATA_DIR=\\\"" + os.path.join (final_prefix, 'share') + "\\\"") ardour.Append(CXXFLAGS="-DMODULE_DIR=\\\"" + os.path.join (final_prefix, env['LIBDIR']) + "\\\"") @@ -362,9 +358,6 @@ else: if ardour['LV2']: ardour.Merge ([ libraries['slv2'] ]) -if ardour['LIBLO']: - ardour.Merge ([ libraries['lo'] ]) - if ardour['COREAUDIO'] or ardour['AUDIOUNITS']: ardour.Merge ([ libraries['appleutility'] ]) @@ -418,7 +411,6 @@ env.Alias('tarball', env.Distribute (env['DISTTREE'], [ 'sse_functions_xmm.cc', 'sse_functions.s', 'sse_functions_64bit.s' ] + [ 'rb_effect.cc', 'st_stretch.cc', 'st_pitch.cc' ] + ardour_files + - osc_files + vst_files + coreaudio_files + audiounit_files + diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 8be2e3b8b6..c6c56f99a4 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -67,10 +67,6 @@ #include #include -#ifdef HAVE_LIBLO -#include -#endif - #include #include @@ -84,10 +80,6 @@ ARDOUR::Configuration* ARDOUR::Config = 0; ARDOUR::RuntimeProfile* ARDOUR::Profile = 0; ARDOUR::AudioLibrary* ARDOUR::Library = 0; -#ifdef HAVE_LIBLO -ARDOUR::OSC* ARDOUR::osc = 0; -#endif - using namespace ARDOUR; using namespace std; using namespace PBD; @@ -111,26 +103,6 @@ mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0; sigc::signal ARDOUR::BootMessage; -#ifdef HAVE_LIBLO -static int -setup_osc () -{ - /* no real cost to creating this object, and it avoids - conditionals anywhere that uses it - */ - - osc = new OSC (Config->get_osc_port()); - - if (Config->get_use_osc ()) { - BootMessage (_("Starting OSC")); - return osc->start (); - } else { - return 0; - } -} - -#endif - int ARDOUR::setup_midi () { @@ -341,11 +313,6 @@ ARDOUR::init (bool use_vst, bool try_optimization) Profile = new RuntimeProfile; -#ifdef HAVE_LIBLO - if (setup_osc ()) { - return -1; - } -#endif #ifdef VST_SUPPORT if (Config->get_use_vst() && fst_init ()) { diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 67ea01b8bf..c020509924 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -83,10 +83,6 @@ #include #include -#ifdef HAVE_LIBLO -#include -#endif - #include "i18n.h" using namespace std; @@ -728,15 +724,6 @@ Session::when_engine_running () BootMessage (_("Connect to engine")); _engine.set_session (this); - -#ifdef HAVE_LIBLO - /* and to OSC */ - - BootMessage (_("OSC startup")); - - osc->set_session (*this); -#endif - } void diff --git a/libs/surfaces/generic_midi/SConscript b/libs/surfaces/generic_midi/SConscript index d4c9e92214..86d879cdcd 100644 --- a/libs/surfaces/generic_midi/SConscript +++ b/libs/surfaces/generic_midi/SConscript @@ -9,7 +9,7 @@ Import('env final_prefix install_prefix final_config_prefix libraries i18n') genericmidi = env.Clone() # -# this defines the version number of libardour_genericmidi +# this defines the translation domain of libardour_genericmidi # domain = 'ardour_genericmidi' diff --git a/libs/surfaces/osc/SConscript b/libs/surfaces/osc/SConscript new file mode 100644 index 0000000000..2e1b0c7ac7 --- /dev/null +++ b/libs/surfaces/osc/SConscript @@ -0,0 +1,63 @@ +# -*- python -*- + +import os +import os.path +import glob + +Import('env final_prefix install_prefix final_config_prefix libraries i18n') + +osc = env.Clone() + +# +# this defines the translation domain of libardour_osc +# + +domain = 'ardour_osc' + +osc.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0) +osc.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"") +osc.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED") +osc.Append(PACKAGE = domain) +osc.Append(POTFILE = domain + '.pot') + +osc_files=Split(""" +osc.cc +osc_controllable.cc +interface.cc +""") + +osc.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE") +osc.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"") +osc.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"") +osc.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"") +osc.Append(CPPPATH = libraries['jack'].get('CPPPATH', [])) + +osc.Merge ([ + libraries['lo'], + libraries['midi++2'], + libraries['evoral'], + libraries['ardour'], + libraries['ardour_cp'], + libraries['pbd'], + libraries['sigc2'], + libraries['xml'], + libraries['glib2'], + libraries['glibmm2'] + ]) + +libardour_osc = osc.SharedLibrary('ardour_osc', osc_files) + +if osc['HAVE_LIBLO']: + Default(libardour_osc) + if env['NLS']: + i18n (osc, osc_files, env) + env.Alias('install', env.Install(os.path.join(install_prefix, + env['LIBDIR'], + 'ardour3', + 'surfaces'), + libardour_osc)) + +env.Alias('tarball', env.Distribute (env['DISTTREE'], + [ 'SConscript' ] + + osc_files + + glob.glob('po/*.po') + glob.glob('*.h'))) diff --git a/libs/surfaces/osc/interface.cc b/libs/surfaces/osc/interface.cc new file mode 100644 index 0000000000..042dac1ded --- /dev/null +++ b/libs/surfaces/osc/interface.cc @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2006 Paul Davis + * Copyright (C) 2007 Michael Taht + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * */ + +#include +#include "osc.h" + +using namespace ARDOUR; + +ControlProtocol* +new_osc_protocol (ControlProtocolDescriptor* descriptor, Session* s) +{ + OSC* osc = new OSC (*s, Config->get_osc_port()); + + osc->set_active (true); + + return osc; +} + +void +delete_osc_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp) +{ + delete cp; +} + +bool +probe_osc_protocol (ControlProtocolDescriptor* descriptor) +{ + return true; // we can always do OSC +} + +static ControlProtocolDescriptor osc_descriptor = { + name : "Open Sound Control (OSC)", + id : "uri://ardour.org/surfaces/osc:0", + ptr : 0, + module : 0, + mandatory : 1, + supports_feedback : true, + probe : probe_osc_protocol, + initialize : new_osc_protocol, + destroy : delete_osc_protocol +}; + +extern "C" { +ControlProtocolDescriptor* +protocol_descriptor () { + return &osc_descriptor; +} +} + diff --git a/libs/ardour/osc.cc b/libs/surfaces/osc/osc.cc similarity index 62% rename from libs/ardour/osc.cc rename to libs/surfaces/osc/osc.cc index ffd2df63be..4503993360 100644 --- a/libs/ardour/osc.cc +++ b/libs/surfaces/osc/osc.cc @@ -33,20 +33,23 @@ #include #include #include +#include -#include #include #include #include +#include #include #include +#include "osc.h" #include "i18n.h" using namespace ARDOUR; using namespace sigc; using namespace std; + static void error_callback(int num, const char *m, const char *path) { #ifdef DEBUG @@ -54,13 +57,61 @@ static void error_callback(int num, const char *m, const char *path) #endif } -OSC::OSC (uint32_t port) - : _port(port) +OSC::OSC (Session& s, uint32_t port) + : ControlProtocol (s, "OSC") + , _port(port) { _shutdown = false; _osc_server = 0; _osc_unix_server = 0; _osc_thread = 0; + _namespace_root = "/ardour"; + _send_route_changes = true; + + // "Application Hooks" + session_loaded (s); + session->Exported.connect( mem_fun( *this, &OSC::session_exported ) ); + + /* catch up with existing routes */ + + boost::shared_ptr rl = session->get_routes (); + route_added (*(rl.get())); + + // session->RouteAdded.connect (mem_fun (*this, &OSC::route_added)); +} + +OSC::~OSC() +{ + stop (); +} + +int +OSC::set_active (bool yn) +{ + if (yn) { + return start (); + } else { + return stop (); + } +} + +bool +OSC::get_active () const +{ + return _osc_server != 0; +} + +int +OSC::set_feedback (bool yn) +{ + _send_route_changes = yn; + return 0; +} + +bool +OSC::get_feedback () const +{ + return _send_route_changes; } int @@ -162,11 +213,6 @@ OSC::stop () return 0; } -OSC::~OSC() -{ - stop (); -} - void OSC::register_callbacks() { @@ -183,6 +229,10 @@ OSC::register_callbacks() } serv = srvs[i]; + + /* this is a special catchall handler */ + + lo_server_add_method (serv, 0, 0, _catchall, this); #define REGISTER_CALLBACK(serv,path,types, function) lo_server_add_method (serv, path, types, OSC::_ ## function, this) @@ -416,20 +466,217 @@ OSC::osc_receiver() } void -OSC::set_session (Session& s) +OSC::current_value_query (const char* path, size_t len, lo_arg **argv, int argc, lo_message msg) { - session = &s; - session->GoingAway.connect (mem_fun (*this, &OSC::session_going_away)); + char* subpath; + + subpath = (char*) malloc (len-15+1); + memcpy (subpath, path, len-15); + subpath[len-15] = '\0'; + + send_current_value (subpath, argv, argc, msg); + + free (subpath); +} - // "Application Hooks" - session_loaded( s ); - session->Exported.connect( mem_fun( *this, &OSC::session_exported ) ); +void +OSC::send_current_value (const char* path, lo_arg** argv, int argc, lo_message msg) +{ + if (!session) { + return; + } + + lo_message reply = lo_message_new (); + boost::shared_ptr r; + int id; + + lo_message_add_string (reply, path); + + if (argc == 0) { + lo_message_add_string (reply, "bad syntax"); + } else { + id = argv[0]->i; + r = session->route_by_remote_id (id); + + if (!r) { + lo_message_add_string (reply, "not found"); + } else { + + if (strcmp (path, "/routes/state") == 0) { + + if (boost::dynamic_pointer_cast(r)) { + lo_message_add_string (reply, "AT"); + } else if (boost::dynamic_pointer_cast(r)) { + lo_message_add_string (reply, "MT"); + } else { + lo_message_add_string (reply, "B"); + } + + lo_message_add_string (reply, r->name().c_str()); + lo_message_add_int32 (reply, r->n_inputs().n_audio()); + lo_message_add_int32 (reply, r->n_outputs().n_audio()); + lo_message_add_int32 (reply, r->muted()); + lo_message_add_int32 (reply, r->soloed()); + + } else if (strcmp (path, "/routes/mute") == 0) { + + lo_message_add_int32 (reply, (float) r->muted()); + + } else if (strcmp (path, "/routes/solo") == 0) { + + lo_message_add_int32 (reply, r->soloed()); + } + } + } + + lo_send_message (lo_message_get_source (msg), "#reply", reply); + lo_message_free (reply); +} + +int +OSC::_catchall (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) +{ + return ((OSC*)user_data)->catchall (path, types, argv, argc, data); +} + +int +OSC::catchall (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg) +{ + size_t len; + int ret = 1; /* unhandled */ + + cerr << "Received a message, path = " << path << " types = \"" + << (types ? types : "NULL") << '"' << endl; + + /* 15 for /#current_value plus 2 for / */ + + len = strlen (path); + + if (len >= 17 && !strcmp (&path[len-15], "/#current_value")) { + current_value_query (path, len, argv, argc, msg); + ret = 0; + + } else if (strcmp (path, "/routes/listen") == 0) { + + cerr << "set up listener\n"; + + lo_message reply = lo_message_new (); + + if (argc > 0) { + int id = argv[0]->i; + boost::shared_ptr r = session->route_by_remote_id (id); + + if (!r) { + lo_message_add_string (reply, "not found"); + cerr << "no such route\n"; + } else { + + ListenerPair listener; + + listener.first = r.get(); + listener.second = lo_message_get_source (msg); + + cerr << "add listener\n"; + + listen_to_route (listener); + + lo_message_add_string (reply, "0"); + } + + } else { + lo_message_add_string (reply, "syntax error"); + } + + lo_send_message (lo_message_get_source (msg), "#reply", reply); + lo_message_free (reply); + + } else if (strcmp (path, "/routes/ignore") == 0) { + + if (argc > 0) { + int id = argv[0]->i; + boost::shared_ptr r = session->route_by_remote_id (id); + + if (r) { + ListenerPair listener; + + listener.first = r.get(); + listener.second = lo_message_get_source (msg); + + drop_listener_pair (listener); + } + } + } + + return ret; } void -OSC::session_going_away () +OSC::route_added (Session::RouteList& rl) { - session = 0; +} + +void +OSC::listen_to_route (const ListenerPair& lp) +{ + Listeners::iterator x; + bool route_exists = false; + + cerr << "listen to route\n"; + + /* check existing listener pairs to avoid duplicate listens */ + + for (x = listeners.begin(); x != listeners.end(); ++x) { + + if ((*x)->route == lp.first) { + route_exists = true; + + if ((*x)->addr == lp.second ) { + return; + } + } + } + + Listener* l = new Listener (lp.first, lp.second); + + cerr << "listener binding to signals\n"; + + l->connections.push_back (lp.first->solo_changed.connect (bind (mem_fun (*this, &OSC::route_changed), RouteSolo, lp.first, lp.second))); + l->connections.push_back (lp.first->mute_changed.connect (bind (mem_fun (*this, &OSC::route_changed), RouteMute, lp.first, lp.second))); + l->connections.push_back (lp.first->gain_control()->Changed.connect (bind (mem_fun (*this, &OSC::route_changed_deux), RouteGain, lp.first, lp.second))); + + if (!route_exists) { + l->route->GoingAway.connect (bind (mem_fun (*this, &OSC::drop_listeners_by_route), l->route)); + } + + listeners.push_back (l); +} + +void +OSC::drop_listeners_by_route (Route* r) +{ + Listeners::iterator x; + + for (x = listeners.begin(); x != listeners.end();) { + if ((*x)->route == r) { + delete *x; + x = listeners.erase (x); + } else { + ++x; + } + } +} + +void +OSC::drop_listener_pair (const ListenerPair& lp) +{ + Listeners::iterator x; + + for (x = listeners.begin(); x != listeners.end(); ++x) { + if ((*x)->route == lp.first && (*x)->addr == lp.second) { + listeners.erase (x); + return; + } + } } // "Application Hook" Handlers // @@ -445,6 +692,61 @@ OSC::session_exported( std::string path, std::string name ) { lo_send( listener, "/session/exported", "ss", path.c_str(), name.c_str() ); } +void +OSC::set_send_route_changes (bool yn) +{ + _send_route_changes = yn; +} + +void +OSC::route_changed (void* src, RouteChangeType what, Route* r, lo_address addr) +{ + route_changed_deux (what, r, addr); +} + +void +OSC::route_changed_deux (RouteChangeType what, Route* r, lo_address addr) +{ + if (!_send_route_changes) { + return; + } + + string prefix = _namespace_root; + int ret; + + switch (what) { + + case OSC::RouteSolo: + prefix += "/changed/route/solo"; + ret = lo_send (addr, prefix.c_str(), "ii", r->remote_control_id(), (int) r->soloed()); + break; + + case OSC::RouteMute: + prefix += "/changed/route/mute"; + ret = lo_send (addr, prefix.c_str(), "ii", r->remote_control_id(), (int) r->muted()); + break; + + case OSC::RouteGain: + prefix += "/changed/route/gain"; + ret = lo_send (addr, prefix.c_str(), "if", r->remote_control_id(), r->effective_gain()); + + default: + error << "OSC: unhandled route change\n"; + return; + } + + if (ret < 0) { + ListenerPair lp; + + lp.first = r; + lp.second = addr; + + cerr << "Error sending to listener ... dropping\n"; + drop_listener_pair (lp); + } + +} + // end "Application Hook" Handlers // /* path callbacks */ @@ -465,38 +767,38 @@ OSC::current_value (const char *path, const char *types, lo_arg **argv, int argc const char *retpath = argv[2]->s; - if (strcmp (argv[0]->s, "transport_frame")) { + if (strcmp (argv[0]->s, "transport_frame") == 0) { if (session) { lo_send (addr, retpath, "i", session->transport_frame()); } - } else if (strcmp (argv[0]->s, "transport_speed")) { - + } else if (strcmp (argv[0]->s, "transport_speed") == 0) { + if (session) { lo_send (addr, retpath, "i", session->transport_frame()); } - - } else if (strcmp (argv[0]->s, "transport_locked")) { - + + } else if (strcmp (argv[0]->s, "transport_locked") == 0) { + if (session) { lo_send (addr, retpath, "i", session->transport_frame()); } - - } else if (strcmp (argv[0]->s, "punch_in") { - + + } else if (strcmp (argv[0]->s, "punch_in") == 0) { + if (session) { lo_send (addr, retpath, "i", session->transport_frame()); } - - } else if (strcmp (argv[0]->s, "punch_out") { + + } else if (strcmp (argv[0]->s, "punch_out") == 0) { if (session) { lo_send (addr, retpath, "i", session->transport_frame()); } - - } else if (strcmp (argv[0]->s, "rec_enable") { - + + } else if (strcmp (argv[0]->s, "rec_enable") == 0) { + if (session) { lo_send (addr, retpath, "i", session->transport_frame()); } @@ -572,6 +874,18 @@ OSC::route_set_gain_dB (int rid, float dB) if (r) { r->set_gain (dB_to_coefficient (dB), this); } + + return 0; +} +XMLNode& +OSC::get_state () +{ + return *(new XMLNode ("OSC")); +} + +int +OSC::set_state (const XMLNode&) +{ return 0; } diff --git a/libs/ardour/ardour/osc.h b/libs/surfaces/osc/osc.h similarity index 70% rename from libs/ardour/ardour/osc.h rename to libs/surfaces/osc/osc.h index 33759feb91..b2417474fc 100644 --- a/libs/ardour/ardour/osc.h +++ b/libs/surfaces/osc/osc.h @@ -30,20 +30,32 @@ #include #include - -#include +#include +#include namespace ARDOUR { - class Session; - class Route; -class OSC : public BasicUI, public sigc::trackable +class Session; +class Route; + +class OSC : public ControlProtocol { public: - OSC (uint32_t port); + OSC (Session&, uint32_t port); virtual ~OSC(); - - void set_session (ARDOUR::Session&); + + XMLNode& get_state (); + int set_state (const XMLNode&); + + int set_active (bool yn); + bool get_active () const; + int set_feedback (bool yn); + bool get_feedback () const; + + void set_namespace_root (std::string); + bool send_route_changes () const { return _send_route_changes; } + void set_send_route_changes (bool yn); + int start (); int stop (); @@ -55,6 +67,8 @@ class OSC : public BasicUI, public sigc::trackable lo_server _osc_unix_server; std::string _osc_unix_socket_path; std::string _osc_url_file; + std::string _namespace_root; + bool _send_route_changes; pthread_t _osc_thread; int _request_pipe[2]; @@ -68,16 +82,31 @@ class OSC : public BasicUI, public sigc::trackable void register_callbacks (); - void session_going_away (); - + void route_added (ARDOUR::Session::RouteList&); + // Handlers for "Application Hook" signals - void session_loaded( ARDOUR::Session& ); - void session_exported( std::string, std::string ); + void session_loaded (ARDOUR::Session&); + void session_exported (std::string, std::string); + + enum RouteChangeType { + RouteSolo, + RouteMute, + RouteGain + }; + + void route_changed (void* ignored, RouteChangeType, ARDOUR::Route*, lo_address); + void route_changed_deux (RouteChangeType, ARDOUR::Route*, lo_address); + // end "Application Hook" handles std::string get_server_url (); std::string get_unix_server_url (); + void send_current_value (const char* path, lo_arg** argv, int argc, lo_message msg); + void current_value_query (const char* path, size_t len, lo_arg **argv, int argc, lo_message msg); + int catchall (const char *path, const char *types, lo_arg **argv, int argc, void *data); + static int _catchall (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); + int current_value (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data); #define PATH_CALLBACK(name) \ @@ -143,6 +172,23 @@ class OSC : public BasicUI, public sigc::trackable int route_recenable (int rid, int yn); int route_set_gain_abs (int rid, float level); int route_set_gain_dB (int rid, float dB); + + struct Listener { + Route* route; + lo_address addr; + std::vector connections; + + Listener (Route* r, lo_address a) : route (r), addr (a) {} + }; + + typedef std::pair ListenerPair; + typedef std::list Listeners; + + Listeners listeners; + + void listen_to_route (const ListenerPair&); + void drop_listener_pair (const ListenerPair&); + void drop_listeners_by_route (Route*); }; } diff --git a/libs/surfaces/osc/osc_controllable.cc b/libs/surfaces/osc/osc_controllable.cc new file mode 100644 index 0000000000..12959652b8 --- /dev/null +++ b/libs/surfaces/osc/osc_controllable.cc @@ -0,0 +1,54 @@ +/* + Copyright (C) 2009 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include /* for sprintf, sigh */ +#include +#include +#include + +#include "osc_controllable.h" + +using namespace sigc; +using namespace PBD; +using namespace ARDOUR; + +OSCControllable::OSCControllable (lo_address a, Controllable& c) + : controllable (c) + , addr (a) +{ +} + +OSCControllable::~OSCControllable () +{ + lo_address_free (addr); +} + +XMLNode& +OSCControllable::get_state () +{ + XMLNode& root (controllable.get_state()); + return root; +} + +int +OSCControllable::set_state (const XMLNode& node) +{ + return 0; +} + diff --git a/libs/surfaces/osc/osc_controllable.h b/libs/surfaces/osc/osc_controllable.h new file mode 100644 index 0000000000..48183138ec --- /dev/null +++ b/libs/surfaces/osc/osc_controllable.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 1998-2006 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __osc_osccontrollable_h__ +#define __osc_osccontrollable_h__ + +#include + +#include +#include + +#include +#include +#include + +class OSCControllable : public PBD::Stateful +{ + public: + OSCControllable (lo_address addr, PBD::Controllable&); + virtual ~OSCControllable (); + + XMLNode& get_state (); + int set_state (const XMLNode& node); + + private: + PBD::Controllable& controllable; + lo_address addr; +}; + +#endif /* __osc_osccontrollable_h__ */ -- 2.30.2