summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2009-01-15 22:09:23 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2009-01-15 22:09:23 +0000
commit16556bb182b19e6baae34543768668b5eeb3cd45 (patch)
treed7b584921af2ccb1b28269a5ae8aed7c521572a8 /libs
parent13e40db5e5587499cf7a388c12b519a51f55cc81 (diff)
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
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/SConscript8
-rw-r--r--libs/ardour/globals.cc33
-rw-r--r--libs/ardour/session.cc13
-rw-r--r--libs/surfaces/generic_midi/SConscript2
-rw-r--r--libs/surfaces/osc/SConscript63
-rw-r--r--libs/surfaces/osc/interface.cc66
-rw-r--r--libs/surfaces/osc/osc.cc (renamed from libs/ardour/osc.cc)374
-rw-r--r--libs/surfaces/osc/osc.h (renamed from libs/ardour/ardour/osc.h)70
-rw-r--r--libs/surfaces/osc/osc_controllable.cc54
-rw-r--r--libs/surfaces/osc/osc_controllable.h46
10 files changed, 632 insertions, 97 deletions
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 <ardour/audioengine.h>
#include <ardour/filesystem_paths.h>
-#ifdef HAVE_LIBLO
-#include <ardour/osc.h>
-#endif
-
#include <ardour/mix.h>
#include <ardour/runtime_functions.h>
@@ -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<void,std::string> 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 <ardour/analyser.h>
#include <ardour/bundle.h>
-#ifdef HAVE_LIBLO
-#include <ardour/osc.h>
-#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 <control_protocol/control_protocol.h>
+#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
index ffd2df63be..4503993360 100644
--- a/libs/ardour/osc.cc
+++ b/libs/surfaces/osc/osc.cc
@@ -33,20 +33,23 @@
#include <pbd/pthread_utils.h>
#include <pbd/file_utils.h>
#include <pbd/filesystem.h>
+#include <pbd/failed_constructor.h>
-#include <ardour/osc.h>
#include <ardour/session.h>
#include <ardour/route.h>
#include <ardour/audio_track.h>
+#include <ardour/midi_track.h>
#include <ardour/dB.h>
#include <ardour/filesystem_paths.h>
+#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<Session::RouteList> 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<Route> 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<AudioTrack>(r)) {
+ lo_message_add_string (reply, "AT");
+ } else if (boost::dynamic_pointer_cast<MidiTrack>(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 /<path> */
+
+ 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<Route> 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<Route> 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
index 33759feb91..b2417474fc 100644
--- a/libs/ardour/ardour/osc.h
+++ b/libs/surfaces/osc/osc.h
@@ -30,20 +30,32 @@
#include <sigc++/sigc++.h>
#include <ardour/types.h>
-
-#include <control_protocol/basic_ui.h>
+#include <ardour/session.h>
+#include <control_protocol/control_protocol.h>
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<sigc::connection> connections;
+
+ Listener (Route* r, lo_address a) : route (r), addr (a) {}
+ };
+
+ typedef std::pair<Route*, lo_address> ListenerPair;
+ typedef std::list<Listener*> 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 <cstdio> /* for sprintf, sigh */
+#include <climits>
+#include <pbd/error.h>
+#include <pbd/xml++.h>
+
+#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 <string>
+
+#include <sigc++/sigc++.h>
+#include <lo/lo.h>
+
+#include <pbd/controllable.h>
+#include <pbd/stateful.h>
+#include <ardour/types.h>
+
+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__ */