diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2006-05-18 02:19:27 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2006-05-18 02:19:27 +0000 |
commit | 60fbeedb5f819b42fdca1f8175319aa2a9bca4c1 (patch) | |
tree | 53f2768aff3fa2d94d03b6a4c953f67b5141a0c2 /libs | |
parent | b3b383faa5ca4e2a101314612d69b05184edc422 (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.h | 14 | ||||
-rw-r--r-- | libs/ardour/ardour/control_protocol.h | 41 | ||||
-rw-r--r-- | libs/ardour/basic_ui.cc | 2 | ||||
-rw-r--r-- | libs/ardour/control_protocol.cc | 269 | ||||
-rw-r--r-- | libs/surfaces/osc/SConscript | 52 | ||||
-rw-r--r-- | libs/surfaces/osc/i18n.h | 16 | ||||
-rw-r--r-- | libs/surfaces/osc/interface.cc | 44 | ||||
-rw-r--r-- | libs/surfaces/osc/osc_server.cc | 392 | ||||
-rw-r--r-- | libs/surfaces/osc/osc_server.h | 102 | ||||
-rw-r--r-- | libs/surfaces/tranzport/tranzport_control_protocol.cc | 136 | ||||
-rw-r--r-- | libs/surfaces/tranzport/tranzport_control_protocol.h | 1 |
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; |