summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2006-05-18 02:19:27 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2006-05-18 02:19:27 +0000
commit60fbeedb5f819b42fdca1f8175319aa2a9bca4c1 (patch)
tree53f2768aff3fa2d94d03b6a4c953f67b5141a0c2 /libs
parentb3b383faa5ca4e2a101314612d69b05184edc422 (diff)
a) basic prototype of OSC control
b) various changes to ControlProtocol model/implementation c) more attempts to get autoscroll to work nicely (unfinished) d) move editor item types into their own header git-svn-id: svn://localhost/trunk/ardour2@506 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/basic_ui.h14
-rw-r--r--libs/ardour/ardour/control_protocol.h41
-rw-r--r--libs/ardour/basic_ui.cc2
-rw-r--r--libs/ardour/control_protocol.cc269
-rw-r--r--libs/surfaces/osc/SConscript52
-rw-r--r--libs/surfaces/osc/i18n.h16
-rw-r--r--libs/surfaces/osc/interface.cc44
-rw-r--r--libs/surfaces/osc/osc_server.cc392
-rw-r--r--libs/surfaces/osc/osc_server.h102
-rw-r--r--libs/surfaces/tranzport/tranzport_control_protocol.cc136
-rw-r--r--libs/surfaces/tranzport/tranzport_control_protocol.h1
11 files changed, 957 insertions, 112 deletions
diff --git a/libs/ardour/ardour/basic_ui.h b/libs/ardour/ardour/basic_ui.h
index ddfe0c5a01..a2395f8f59 100644
--- a/libs/ardour/ardour/basic_ui.h
+++ b/libs/ardour/ardour/basic_ui.h
@@ -10,25 +10,31 @@ class BasicUI {
BasicUI (ARDOUR::Session&);
virtual ~BasicUI ();
+ void add_marker ();
+
+ /* transport control */
+
void loop_toggle ();
void goto_start ();
void goto_end ();
- void add_marker ();
void rewind ();
void ffwd ();
void transport_stop ();
void transport_play ();
- void rec_enable_toggle ();
+ void set_transport_speed (float speed);
+ float get_transport_speed (float speed);
+
void save_state ();
void prev_marker ();
void next_marker ();
- void move_at (float speed);
void undo ();
void redo ();
- void toggle_all_rec_enables ();
void toggle_punch_in ();
void toggle_punch_out ();
+ void rec_enable_toggle ();
+ void toggle_all_rec_enables ();
+
protected:
ARDOUR::Session& session;
};
diff --git a/libs/ardour/ardour/control_protocol.h b/libs/ardour/ardour/control_protocol.h
index 70c7d2dc0d..9a9c14021c 100644
--- a/libs/ardour/ardour/control_protocol.h
+++ b/libs/ardour/ardour/control_protocol.h
@@ -2,6 +2,7 @@
#define ardour_control_protocols_h
#include <string>
+#include <vector>
#include <list>
#include <sigc++/sigc++.h>
@@ -35,9 +36,49 @@ class ControlProtocol : public sigc::trackable, public BasicUI {
static sigc::signal<void> Enter;
static sigc::signal<void,float> ScrollTimeline;
+ /* the model here is as follows:
+
+ we imagine most control surfaces being able to control
+ from 1 to N tracks at a time, with a session that may
+ contain 1 to M tracks, where M may be smaller, larger or
+ equal to N.
+
+ the control surface has a fixed set of physical controllers
+ which can potentially be mapped onto different tracks/busses
+ via some mechanism.
+
+ therefore, the control protocol object maintains
+ a table that reflects the current mapping between
+ the controls and route object.
+ */
+
+ void set_route_table_size (uint32_t size);
+ void set_route_table (uint32_t table_index, ARDOUR::Route*);
+
+ void route_set_rec_enable (uint32_t table_index, bool yn);
+ bool route_get_rec_enable (uint32_t table_index);
+
+ float route_get_gain (uint32_t table_index);
+ void route_set_gain (uint32_t table_index, float);
+ float route_get_effective_gain (uint32_t table_index);
+
+ float route_get_peak_input_power (uint32_t table_index, uint32_t which_input);
+
+ bool route_get_muted (uint32_t table_index);
+ void route_set_muted (uint32_t table_index, bool);
+
+ bool route_get_soloed (uint32_t table_index);
+ void route_set_soloed (uint32_t table_index, bool);
+
+ std::string route_get_name (uint32_t table_index);
+
protected:
+ std::vector<ARDOUR::Route*> route_table;
std::string _name;
bool _active;
+
+ void next_track (uint32_t initial_id);
+ void prev_track (uint32_t initial_id);
};
extern "C" {
diff --git a/libs/ardour/basic_ui.cc b/libs/ardour/basic_ui.cc
index cfed836eab..02e45ac84a 100644
--- a/libs/ardour/basic_ui.cc
+++ b/libs/ardour/basic_ui.cc
@@ -157,7 +157,7 @@ BasicUI::next_marker ()
}
void
-BasicUI::move_at (float speed)
+BasicUI::set_transport_speed (float speed)
{
session.request_transport_speed (speed);
}
diff --git a/libs/ardour/control_protocol.cc b/libs/ardour/control_protocol.cc
index b7004a0ffa..222ecbf279 100644
--- a/libs/ardour/control_protocol.cc
+++ b/libs/ardour/control_protocol.cc
@@ -19,6 +19,9 @@
*/
#include <ardour/control_protocol.h>
+#include <ardour/session.h>
+#include <ardour/route.h>
+#include <ardour/audio_track.h>
using namespace ARDOUR;
using namespace std;
@@ -40,3 +43,269 @@ ControlProtocol::~ControlProtocol ()
{
}
+void
+ControlProtocol::next_track (uint32_t initial_id)
+{
+ uint32_t limit = session.nroutes();
+ Route* cr = route_table[0];
+ uint32_t id;
+
+ if (cr) {
+ id = cr->remote_control_id ();
+ } else {
+ id = 0;
+ }
+
+ if (id == limit) {
+ id = 0;
+ } else {
+ id++;
+ }
+
+ while (id < limit) {
+ if ((cr = session.route_by_remote_id (id)) != 0) {
+ break;
+ }
+ id++;
+ }
+
+ if (id == limit) {
+ id = 0;
+ while (id != initial_id) {
+ if ((cr = session.route_by_remote_id (id)) != 0) {
+ break;
+ }
+ id++;
+ }
+ }
+
+ route_table[0] = cr;
+}
+
+void
+ControlProtocol::prev_track (uint32_t initial_id)
+{
+ uint32_t limit = session.nroutes() - 1;
+ Route* cr = route_table[0];
+ uint32_t id;
+
+ if (cr) {
+ id = cr->remote_control_id ();
+ } else {
+ id = 0;
+ }
+
+ if (id == 0) {
+ id = session.nroutes() - 1;
+ } else {
+ id--;
+ }
+
+ while (id >= 0) {
+ if ((cr = session.route_by_remote_id (id)) != 0) {
+ break;
+ }
+ id--;
+ }
+
+ if (id < 0) {
+ id = limit;
+ while (id > initial_id) {
+ if ((cr = session.route_by_remote_id (id)) != 0) {
+ break;
+ }
+ id--;
+ }
+ }
+
+ route_table[0] = cr;
+}
+
+
+void
+ControlProtocol::set_route_table_size (uint32_t size)
+{
+ while (route_table.size() < size) {
+ route_table.push_back (0);
+ }
+}
+
+void
+ControlProtocol::set_route_table (uint32_t table_index, ARDOUR::Route*)
+{
+}
+
+void
+ControlProtocol::route_set_rec_enable (uint32_t table_index, bool yn)
+{
+ if (table_index > route_table.size()) {
+ return;
+ }
+
+ Route* r = route_table[table_index];
+
+ AudioTrack* at = dynamic_cast<AudioTrack*>(r);
+
+ if (at) {
+ at->set_record_enable (yn, this);
+ }
+}
+
+bool
+ControlProtocol::route_get_rec_enable (uint32_t table_index)
+{
+ if (table_index > route_table.size()) {
+ return false;
+ }
+
+ Route* r = route_table[table_index];
+
+ AudioTrack* at = dynamic_cast<AudioTrack*>(r);
+
+ if (at) {
+ at->record_enabled ();
+ }
+}
+
+
+float
+ControlProtocol::route_get_gain (uint32_t table_index)
+{
+ if (table_index > route_table.size()) {
+ return 0.0f;
+ }
+
+ Route* r = route_table[table_index];
+
+ if (r == 0) {
+ return 0.0f;
+ }
+
+ return r->gain ();
+}
+
+void
+ControlProtocol::route_set_gain (uint32_t table_index, float gain)
+{
+ if (table_index > route_table.size()) {
+ return;
+ }
+
+ Route* r = route_table[table_index];
+
+ if (r != 0) {
+ r->set_gain (gain, this);
+ }
+}
+
+float
+ControlProtocol::route_get_effective_gain (uint32_t table_index)
+{
+ if (table_index > route_table.size()) {
+ return 0.0f;
+ }
+
+ Route* r = route_table[table_index];
+
+ if (r == 0) {
+ return 0.0f;
+ }
+
+ return r->effective_gain ();
+}
+
+
+float
+ControlProtocol::route_get_peak_input_power (uint32_t table_index, uint32_t which_input)
+{
+ if (table_index > route_table.size()) {
+ return 0.0f;
+ }
+
+ Route* r = route_table[table_index];
+
+ if (r == 0) {
+ return 0.0f;
+ }
+
+ return r->peak_input_power (which_input);
+}
+
+
+bool
+ControlProtocol::route_get_muted (uint32_t table_index)
+{
+ if (table_index > route_table.size()) {
+ return false;
+ }
+
+ Route* r = route_table[table_index];
+
+ if (r == 0) {
+ return false;
+ }
+
+ return r->muted ();
+}
+
+void
+ControlProtocol::route_set_muted (uint32_t table_index, bool yn)
+{
+ if (table_index > route_table.size()) {
+ return;
+ }
+
+ Route* r = route_table[table_index];
+
+ if (r != 0) {
+ r->set_mute (yn, this);
+ }
+}
+
+
+bool
+ControlProtocol::route_get_soloed (uint32_t table_index)
+{
+ if (table_index > route_table.size()) {
+ return false;
+ }
+
+ Route* r = route_table[table_index];
+
+ if (r == 0) {
+ return false;
+ }
+
+ return r->soloed ();
+}
+
+void
+ControlProtocol::route_set_soloed (uint32_t table_index, bool yn)
+{
+ if (table_index > route_table.size()) {
+ return;
+ }
+
+ Route* r = route_table[table_index];
+
+ if (r != 0) {
+ r->set_solo (yn, this);
+ }
+}
+
+string
+ControlProtocol:: route_get_name (uint32_t table_index)
+{
+ if (table_index > route_table.size()) {
+ return "";
+ }
+
+ Route* r = route_table[table_index];
+
+ if (r == 0) {
+ return "";
+ }
+
+ return r->name();
+}
+
diff --git a/libs/surfaces/osc/SConscript b/libs/surfaces/osc/SConscript
new file mode 100644
index 0000000000..c01fe88edf
--- /dev/null
+++ b/libs/surfaces/osc/SConscript
@@ -0,0 +1,52 @@
+# -*- python -*-
+
+import os
+import os.path
+import glob
+
+Import('env final_prefix install_prefix final_config_prefix libraries i18n')
+
+osc = env.Copy()
+
+#
+# this defines the version number 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("""
+interface.cc
+osc_server.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.Merge ([
+ libraries['ardour'],
+ libraries['sigc2'],
+ libraries['pbd3'],
+ libraries['lo']
+])
+
+libardour_osc = osc.SharedLibrary('ardour_osc', osc_files)
+
+Default(libardour_osc)
+
+if env['NLS']:
+ i18n (osc, osc_files, env)
+
+env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2/surfaces'), libardour_osc))
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript', 'i18n.h', 'gettext.h' ] +
+ osc_files +
+ glob.glob('po/*.po') + glob.glob('*.h')))
diff --git a/libs/surfaces/osc/i18n.h b/libs/surfaces/osc/i18n.h
new file mode 100644
index 0000000000..3ace250419
--- /dev/null
+++ b/libs/surfaces/osc/i18n.h
@@ -0,0 +1,16 @@
+#ifndef __i18n_h__
+#define __i18n_h__
+
+#include <pbd/compose.h>
+#include "gettext.h"
+
+#include <vector>
+#include <string>
+
+std::vector<std::string> internationalize (const char **);
+
+#define _(Text) dgettext (PACKAGE,Text)
+#define N_(Text) gettext_noop (Text)
+#define X_(Text) Text
+
+#endif // __i18n_h__
diff --git a/libs/surfaces/osc/interface.cc b/libs/surfaces/osc/interface.cc
new file mode 100644
index 0000000000..3ec5a6571f
--- /dev/null
+++ b/libs/surfaces/osc/interface.cc
@@ -0,0 +1,44 @@
+#include <ardour/control_protocol.h>
+
+#include "osc_server.h"
+
+using namespace ARDOUR;
+
+ControlProtocol*
+new_osc_protocol (ControlProtocolDescriptor* descriptor, Session* s)
+{
+ ControlOSC* osc = new ControlOSC (*s, 3891);
+
+ if (osc->set_active (true)) {
+ delete osc;
+ return 0;
+ }
+
+ return osc;
+
+}
+
+void
+delete_osc_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
+{
+ delete cp;
+}
+
+static ControlProtocolDescriptor osc_descriptor = {
+ name : "OSC",
+ id : "uri://ardour.org/surfaces/osc:0",
+ ptr : 0,
+ module : 0,
+ initialize : new_osc_protocol,
+ destroy : delete_osc_protocol
+
+};
+
+
+extern "C" {
+ControlProtocolDescriptor*
+protocol_descriptor () {
+ return &osc_descriptor;
+}
+}
+
diff --git a/libs/surfaces/osc/osc_server.cc b/libs/surfaces/osc/osc_server.cc
new file mode 100644
index 0000000000..5d0a2daa4d
--- /dev/null
+++ b/libs/surfaces/osc/osc_server.cc
@@ -0,0 +1,392 @@
+/*
+** Copyright (C) 2004 Jesse Chappell <jesse@essej.net>
+**
+** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+
+#include <iostream>
+#include <cstdio>
+#include <cstdlib>
+#include <cerrno>
+#include <algorithm>
+
+#include <sys/poll.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sigc++/sigc++.h>
+
+#include <lo/lo.h>
+
+#include "osc_server.h"
+
+#include "i18n.h"
+
+using namespace sigc;
+using namespace std;
+
+#include <pbd/abstract_ui.cc>
+
+static void error_callback(int num, const char *m, const char *path)
+{
+#ifdef DEBUG
+ fprintf(stderr, "liblo server error %d in path %s: %s\n", num, path, m);
+#endif
+}
+
+ControlOSC::ControlOSC (ARDOUR::Session& s, uint32_t port)
+ : ControlProtocol(s, X_("OSC")),
+ AbstractUI<OSCRequest> (X_("OSC"), false),
+ _port(port)
+{
+ _shutdown = false;
+ _osc_server = 0;
+ _osc_unix_server = 0;
+ _osc_thread = 0;
+}
+
+int
+ControlOSC::set_active (bool yn)
+{
+ if (yn) {
+
+ char tmpstr[255];
+
+ for (int j=0; j < 20; ++j) {
+ snprintf(tmpstr, sizeof(tmpstr), "%d", _port);
+
+ if ((_osc_server = lo_server_new (tmpstr, error_callback))) {
+ break;
+ }
+#ifdef DEBUG
+ cerr << "can't get osc at port: " << _port << endl;
+#endif
+ _port++;
+ continue;
+ }
+
+#ifdef ARDOUR_OSC_UNIX_SERVER
+
+ // APPEARS sluggish for now
+
+ // attempt to create unix socket server too
+
+ snprintf(tmpstr, sizeof(tmpstr), "/tmp/sooperlooper_XXXXXX");
+ int fd = mkstemp(tmpstr);
+
+ if (fd >= 0 ) {
+ unlink (tmpstr);
+ close (fd);
+
+ _osc_unix_server = lo_server_new (tmpstr, error_callback);
+
+ if (_osc_unix_server) {
+ _osc_unix_socket_path = tmpstr;
+ }
+ }
+#endif
+
+ register_callbacks();
+
+ on_session_load ();
+
+ // lo_server_thread_add_method(_sthread, NULL, NULL, ControlOSC::_dummy_handler, this);
+
+ if (!init_osc_thread()) {
+ return -1;
+ }
+
+ } else {
+
+ /* need to stop the OSC UDP server */
+
+ if (!_osc_unix_socket_path.empty()) {
+ // unlink it
+ unlink(_osc_unix_socket_path.c_str());
+ }
+
+ // stop server thread
+ terminate_osc_thread();
+ }
+
+ return 0;
+}
+
+bool
+ControlOSC::caller_is_ui_thread ()
+{
+ return false;
+}
+
+ControlOSC::~ControlOSC()
+{
+ set_active (false);
+}
+
+void
+ControlOSC::register_callbacks()
+{
+ lo_server srvs[2];
+ lo_server serv;
+
+ srvs[0] = _osc_server;
+ srvs[1] = _osc_unix_server;
+
+ for (size_t i = 0; i < 2; ++i) {
+
+ if (!srvs[i]) {
+ continue;
+ }
+
+ serv = srvs[i];
+
+#define REGISTER_CALLBACK(serv,path,types, function) lo_server_add_method (serv, path, types, ControlOSC::_ ## function, this)
+
+ REGISTER_CALLBACK (serv, "/session/add_marker", "", add_marker);
+ REGISTER_CALLBACK (serv, "/session/loop_toggle", "", loop_toggle);
+ REGISTER_CALLBACK (serv, "/session/goto_start", "", goto_start);
+ REGISTER_CALLBACK (serv, "/session/goto_end", "", goto_end);
+ REGISTER_CALLBACK (serv, "/session/rewind", "", rewind);
+ REGISTER_CALLBACK (serv, "/session/ffwd", "", ffwd);
+ REGISTER_CALLBACK (serv, "/session/transport_stop", "", transport_stop);
+ REGISTER_CALLBACK (serv, "/session/transport_play", "", transport_play);
+ REGISTER_CALLBACK (serv, "/session/set_transport_speed", "f", set_transport_speed);
+ REGISTER_CALLBACK (serv, "/session/save_state", "", save_state);
+ REGISTER_CALLBACK (serv, "/session/prev_marker", "", prev_marker);
+ REGISTER_CALLBACK (serv, "/session/next_marker", "", next_marker);
+ REGISTER_CALLBACK (serv, "/session/undo", "", undo);
+ REGISTER_CALLBACK (serv, "/session/redo", "", redo);
+ REGISTER_CALLBACK (serv, "/session/toggle_punch_in", "", toggle_punch_in);
+ REGISTER_CALLBACK (serv, "/session/toggle_punch_out", "", toggle_punch_out);
+ REGISTER_CALLBACK (serv, "/session/rec_enable_toggle", "", rec_enable_toggle);
+ REGISTER_CALLBACK (serv, "/session/toggle_all_rec_enables", "", toggle_all_rec_enables);
+
+#if 0
+
+ lo_server_add_method(serv, "/session/set", "ss", ControlOSC::global_set_handler, this);
+ lo_server_add_method(serv, "/session/get", "ss", ControlOSC::global_get_handler, this);
+
+ // un/register_update args= s:ctrl s:returl s:retpath
+ lo_server_add_method(serv, "/register_update", "sss", ControlOSC::global_register_update_handler, this);
+ lo_server_add_method(serv, "/unregister_update", "sss", ControlOSC::global_unregister_update_handler, this);
+ lo_server_add_method(serv, "/register_auto_update", "siss", ControlOSC::global_register_auto_update_handler, this);
+ lo_server_add_method(serv, "/unregister_auto_update", "sss", ControlOSC::_global_unregister_auto_update_handler, this);
+#endif
+ }
+}
+
+bool
+ControlOSC::init_osc_thread ()
+{
+ // create new thread to run server
+ if (pipe (_request_pipe)) {
+ cerr << "Cannot create osc request signal pipe" << strerror (errno) << endl;
+ return false;
+ }
+
+ if (fcntl (_request_pipe[0], F_SETFL, O_NONBLOCK)) {
+ cerr << "osc: cannot set O_NONBLOCK on signal read pipe " << strerror (errno) << endl;
+ return false;
+ }
+
+ if (fcntl (_request_pipe[1], F_SETFL, O_NONBLOCK)) {
+ cerr << "osc: cannot set O_NONBLOCK on signal write pipe " << strerror (errno) << endl;
+ return false;
+ }
+
+ pthread_create (&_osc_thread, NULL, &ControlOSC::_osc_receiver, this);
+ if (!_osc_thread) {
+ return false;
+ }
+
+ //pthread_detach (_osc_thread);
+ return true;
+}
+
+void
+ControlOSC::terminate_osc_thread ()
+{
+ void* status;
+
+ _shutdown = true;
+
+ poke_osc_thread ();
+
+ pthread_join (_osc_thread, &status);
+}
+
+void
+ControlOSC::poke_osc_thread ()
+{
+ char c;
+
+ if (write (_request_pipe[1], &c, 1) != 1) {
+ cerr << "cannot send signal to osc thread! " << strerror (errno) << endl;
+ }
+}
+
+void
+ControlOSC::on_session_load ()
+{
+}
+
+void
+ControlOSC::on_session_unload ()
+{
+ // will be called from main event loop
+}
+
+
+std::string
+ControlOSC::get_server_url()
+{
+ string url;
+ char * urlstr;
+
+ if (_osc_server) {
+ urlstr = lo_server_get_url (_osc_server);
+ url = urlstr;
+ free (urlstr);
+ }
+
+ return url;
+}
+
+std::string
+ControlOSC::get_unix_server_url()
+{
+ string url;
+ char * urlstr;
+
+ if (_osc_unix_server) {
+ urlstr = lo_server_get_url (_osc_unix_server);
+ url = urlstr;
+ free (urlstr);
+ }
+
+ return url;
+}
+
+
+/* server thread */
+
+void *
+ControlOSC::_osc_receiver(void * arg)
+{
+ static_cast<ControlOSC*> (arg)->osc_receiver();
+ return 0;
+}
+
+void
+ControlOSC::osc_receiver()
+{
+ struct pollfd pfd[3];
+ int fds[3];
+ lo_server srvs[3];
+ int nfds = 0;
+ int timeout = -1;
+ int ret;
+
+ fds[0] = _request_pipe[0];
+ nfds++;
+
+ if (_osc_server && lo_server_get_socket_fd(_osc_server) >= 0) {
+ fds[nfds] = lo_server_get_socket_fd(_osc_server);
+ srvs[nfds] = _osc_server;
+ nfds++;
+ }
+
+ if (_osc_unix_server && lo_server_get_socket_fd(_osc_unix_server) >= 0) {
+ fds[nfds] = lo_server_get_socket_fd(_osc_unix_server);
+ srvs[nfds] = _osc_unix_server;
+ nfds++;
+ }
+
+
+ while (!_shutdown) {
+
+ for (int i=0; i < nfds; ++i) {
+ pfd[i].fd = fds[i];
+ pfd[i].events = POLLIN|POLLPRI|POLLHUP|POLLERR;
+ pfd[i].revents = 0;
+ }
+
+ again:
+ //cerr << "poll on " << nfds << " for " << timeout << endl;
+ if ((ret = poll (pfd, nfds, timeout)) < 0) {
+ if (errno == EINTR) {
+ /* gdb at work, perhaps */
+ cerr << "EINTR hit " << endl;
+ goto again;
+ }
+
+ cerr << "OSC thread poll failed: " << strerror (errno) << endl;
+
+ break;
+ }
+
+ //cerr << "poll returned " << ret << " pfd[0].revents = " << pfd[0].revents << " pfd[1].revents = " << pfd[1].revents << endl;
+
+ if (_shutdown) {
+ break;
+ }
+
+ if ((pfd[0].revents & ~POLLIN)) {
+ cerr << "OSC: error polling extra port" << endl;
+ break;
+ }
+
+ for (int i=1; i < nfds; ++i) {
+ if (pfd[i].revents & POLLIN)
+ {
+ // this invokes callbacks
+ //cerr << "invoking recv on " << pfd[i].fd << endl;
+ lo_server_recv(srvs[i]);
+ }
+ }
+
+ }
+
+ //cerr << "SL engine shutdown" << endl;
+
+ if (_osc_server) {
+ int fd = lo_server_get_socket_fd(_osc_server);
+ if (fd >=0) {
+ // hack around
+ close(fd);
+ }
+ lo_server_free (_osc_server);
+ _osc_server = 0;
+ }
+
+ if (_osc_unix_server) {
+ cerr << "freeing unix server" << endl;
+ lo_server_free (_osc_unix_server);
+ _osc_unix_server = 0;
+ }
+
+ close(_request_pipe[0]);
+ close(_request_pipe[1]);
+}
+
+void
+ControlOSC::do_request (OSCRequest* req)
+{
+}
+
+/* path callbacks */
+
+
diff --git a/libs/surfaces/osc/osc_server.h b/libs/surfaces/osc/osc_server.h
new file mode 100644
index 0000000000..d3d4516d4d
--- /dev/null
+++ b/libs/surfaces/osc/osc_server.h
@@ -0,0 +1,102 @@
+#ifndef ardour_osc_control_protocol_h
+#define ardour_osc_control_protocol_h
+
+#include <string>
+
+#include <sys/time.h>
+#include <pthread.h>
+
+#include <lo/lo.h>
+
+#include <pbd/lockmonitor.h>
+#include <ardour/control_protocol.h>
+#include <ardour/types.h>
+
+#include <pbd/abstract_ui.h>
+
+struct OSCRequest : public BaseUI::BaseRequestObject {
+ /* nothing yet */
+};
+
+class ControlOSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCRequest>
+{
+ public:
+ ControlOSC (ARDOUR::Session&, uint32_t port);
+ virtual ~ControlOSC();
+
+ int set_active (bool yn);
+
+ bool caller_is_ui_thread();
+
+ private:
+ uint32_t _port;
+ volatile bool _ok;
+ volatile bool _shutdown;
+ lo_server _osc_server;
+ lo_server _osc_unix_server;
+ std::string _osc_unix_socket_path;
+ pthread_t _osc_thread;
+ int _request_pipe[2];
+
+ static void * _osc_receiver(void * arg);
+ void osc_receiver();
+
+ bool init_osc_thread ();
+ void terminate_osc_thread ();
+ void poke_osc_thread ();
+
+ void register_callbacks ();
+
+ void on_session_load ();
+ void on_session_unload ();
+
+ std::string get_server_url ();
+ std::string get_unix_server_url ();
+
+ void do_request (OSCRequest* req);
+
+#define PATH_CALLBACK(name) \
+ static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
+ return static_cast<ControlOSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
+ } \
+ int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
+ name (); \
+ return 0; \
+ }
+
+
+ PATH_CALLBACK(add_marker);
+ PATH_CALLBACK(loop_toggle);
+ PATH_CALLBACK(goto_start);
+ PATH_CALLBACK(goto_end);
+ PATH_CALLBACK(rewind);
+ PATH_CALLBACK(ffwd);
+ PATH_CALLBACK(transport_stop);
+ PATH_CALLBACK(transport_play);
+ PATH_CALLBACK(save_state);
+ PATH_CALLBACK(prev_marker);
+ PATH_CALLBACK(next_marker);
+ PATH_CALLBACK(undo);
+ PATH_CALLBACK(redo);
+ PATH_CALLBACK(toggle_punch_in);
+ PATH_CALLBACK(toggle_punch_out);
+ PATH_CALLBACK(rec_enable_toggle);
+ PATH_CALLBACK(toggle_all_rec_enables);
+
+#define PATH_CALLBACK1(name,type) \
+ static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
+ return static_cast<ControlOSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
+ } \
+ int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
+ if (argc > 0) { \
+ name (argv[0]->type); \
+ }\
+ return 0; \
+ }
+
+
+ PATH_CALLBACK1(set_transport_speed,f);
+};
+
+
+#endif // ardour_osc_control_protocol_h
diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.cc b/libs/surfaces/tranzport/tranzport_control_protocol.cc
index 30ca270593..7857744b17 100644
--- a/libs/surfaces/tranzport/tranzport_control_protocol.cc
+++ b/libs/surfaces/tranzport/tranzport_control_protocol.cc
@@ -70,12 +70,15 @@ TranzportControlProtocol::TranzportControlProtocol (Session& s)
AbstractUI<TranzportRequest> (X_("Tranzport"), false)
{
+ /* tranzport controls one track at a time */
+
+ set_route_table_size (1);
+
timeout = 60000;
buttonmask = 0;
_datawheel = 0;
_device_status = STATUS_OFFLINE;
udev = 0;
- current_route = 0;
current_track_id = 0;
last_where = max_frames;
wheel_mode = WheelTimeline;
@@ -139,11 +142,11 @@ TranzportControlProtocol::set_active (bool yn)
void
TranzportControlProtocol::show_track_gain ()
{
- if (current_route) {
- gain_t g = current_route->gain();
+ if (route_table[0]) {
+ gain_t g = route_get_gain (0);
if (g != last_track_gain) {
char buf[16];
- snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (current_route->effective_gain()));
+ snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (route_get_effective_gain (0)));
print (0, 9, buf);
last_track_gain = g;
}
@@ -234,11 +237,11 @@ log_meter (float db)
void
TranzportControlProtocol::show_meter ()
{
- if (current_route == 0) {
+ if (route_table[0] == 0) {
return;
}
- float level = current_route->peak_input_power (0);
+ float level = route_get_peak_input_power (0, 0);
float fraction = log_meter (level);
/* we draw using a choice of a sort of double colon-like character ("::") or a single, left-aligned ":".
@@ -579,10 +582,6 @@ TranzportControlProtocol::monitor_work ()
val = usb_interrupt_read (udev, READ_ENDPOINT, (char*) buf, 8, 10);
pthread_testcancel();
- /* any requests to handle? */
-
- handle_ui_requests ();
-
if (val == 8) {
process (buf);
}
@@ -673,19 +672,19 @@ TranzportControlProtocol::update_state ()
/* per track */
- if (current_route) {
- AudioTrack* at = dynamic_cast<AudioTrack*> (current_route);
+ if (route_table[0]) {
+ AudioTrack* at = dynamic_cast<AudioTrack*> (route_table[0]);
if (at && at->record_enabled()) {
pending_lights[LightTrackrec] = true;
} else {
pending_lights[LightTrackrec] = false;
}
- if (current_route->muted()) {
+ if (route_get_muted (0)) {
pending_lights[LightTrackmute] = true;
} else {
pending_lights[LightTrackmute] = false;
}
- if (current_route->soloed()) {
+ if (route_get_soloed (0)) {
pending_lights[LightTracksolo] = true;
} else {
pending_lights[LightTracksolo] = false;
@@ -954,10 +953,10 @@ TranzportControlProtocol::process (uint8_t* buf)
void
TranzportControlProtocol::show_current_track ()
{
- if (current_route == 0) {
+ if (route_table[0] == 0) {
print (0, 0, "--------");
} else {
- print (0, 0, current_route->name().substr (0, 8).c_str());
+ print (0, 0, route_get_name (0).substr (0, 8).c_str());
}
}
@@ -1009,10 +1008,7 @@ TranzportControlProtocol::button_event_trackrec_press (bool shifted)
if (shifted) {
toggle_all_rec_enables ();
} else {
- if (current_route) {
- AudioTrack* at = dynamic_cast<AudioTrack*>(current_route);
- at->set_record_enable (!at->record_enabled(), this);
- }
+ route_set_rec_enable (0, !route_get_rec_enable (0));
}
}
@@ -1024,9 +1020,7 @@ TranzportControlProtocol::button_event_trackrec_release (bool shifted)
void
TranzportControlProtocol::button_event_trackmute_press (bool shifted)
{
- if (current_route) {
- current_route->set_mute (!current_route->muted(), this);
- }
+ route_set_muted (0, !route_get_muted (0));
}
void
@@ -1045,9 +1039,7 @@ TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
if (shifted) {
session.set_all_solo (!session.soloing());
} else {
- if (current_route) {
- current_route->set_solo (!current_route->soloed(), this);
- }
+ route_set_soloed (0, !route_get_soloed (0));
}
}
@@ -1267,7 +1259,7 @@ TranzportControlProtocol::datawheel ()
/* parameter control */
- if (current_route) {
+ if (route_table[0]) {
switch (wheel_shift_mode) {
case WheelShiftGain:
if (_datawheel < WheelDirectionThreshold) {
@@ -1358,7 +1350,7 @@ TranzportControlProtocol::scrub ()
last_wheel_motion = now;
last_wheel_dir = dir;
- move_at (speed * dir);
+ set_transport_speed (speed * dir);
}
void
@@ -1392,7 +1384,7 @@ TranzportControlProtocol::step_gain_up ()
gain_fraction = 2.0;
}
- current_route->set_gain (slider_position_to_gain (gain_fraction), this);
+ route_set_gain (0, slider_position_to_gain (gain_fraction));
}
void
@@ -1408,7 +1400,7 @@ TranzportControlProtocol::step_gain_down ()
gain_fraction = 0.0;
}
- current_route->set_gain (slider_position_to_gain (gain_fraction), this);
+ route_set_gain (0, slider_position_to_gain (gain_fraction));
}
void
@@ -1458,83 +1450,15 @@ TranzportControlProtocol::next_wheel_mode ()
void
TranzportControlProtocol::next_track ()
{
- uint32_t limit = session.nroutes();
- uint32_t start = current_track_id;
- Route* cr = current_route;
-
- if (current_track_id == limit) {
- current_track_id = 0;
- } else {
- current_track_id++;
- }
-
- while (current_track_id < limit) {
- if ((cr = session.route_by_remote_id (current_track_id)) != 0) {
- break;
- }
- current_track_id++;
- }
-
- if (current_track_id == limit) {
- current_track_id = 0;
- while (current_track_id != start) {
- if ((cr = session.route_by_remote_id (current_track_id)) != 0) {
- break;
- }
- current_track_id++;
- }
- }
-
- current_route = cr;
- gain_fraction = gain_to_slider_position (current_route->effective_gain());
+ ControlProtocol::next_track (current_track_id);
+ gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
}
void
TranzportControlProtocol::prev_track ()
{
- uint32_t limit = session.nroutes() - 1;
- uint32_t start = current_track_id;
- Route* cr = current_route;
-
- if (current_track_id == 0) {
- current_track_id = session.nroutes() - 1;
- } else {
- current_track_id--;
- }
-
- while (current_track_id >= 0) {
- if ((cr = session.route_by_remote_id (current_track_id)) != 0) {
- break;
- }
- current_track_id--;
- }
-
- if (current_track_id < 0) {
- current_track_id = limit;
- while (current_track_id > start) {
- if ((cr = session.route_by_remote_id (current_track_id)) != 0) {
- break;
- }
- current_track_id--;
- }
- }
-
- current_route = cr;
- gain_fraction = gain_to_slider_position (current_route->effective_gain());
-}
-
-void
-TranzportControlProtocol::set_current_track (Route* r)
-{
- TranzportRequest* req = get_request (SetCurrentTrack);
-
- if (req == 0) {
- return;
- }
-
- req->track = r;
-
- send_request (req);
+ ControlProtocol::prev_track (current_track_id);
+ gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
}
void
@@ -1640,8 +1564,8 @@ void
TranzportControlProtocol::do_request (TranzportRequest* req)
{
if (req->type == SetCurrentTrack) {
- current_route = req->track;
- }
-
- return;
+ route_table[0] = req->track;
+ }
+
+ return;
}
diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.h b/libs/surfaces/tranzport/tranzport_control_protocol.h
index 69812cb5ec..b24a94577a 100644
--- a/libs/surfaces/tranzport/tranzport_control_protocol.h
+++ b/libs/surfaces/tranzport/tranzport_control_protocol.h
@@ -101,7 +101,6 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol, public Abstract
uint8_t _device_status;
usb_dev_handle* udev;
- ARDOUR::Route* current_route;
uint32_t current_track_id;
WheelMode wheel_mode;
WheelShiftMode wheel_shift_mode;