Mercurial > hg > touchkeys
view Source/TouchKeys/Osc.h @ 31:88287c1c2c92
Added an auxiliary MIDI input control, and moved the logging out of the window into the menu to make space in the GUI. Also updated the main window to be rescalable vertically for showing more mappings.
author | Andrew McPherson <andrewm@eecs.qmul.ac.uk> |
---|---|
date | Thu, 20 Mar 2014 00:14:00 +0000 |
parents | 48e3f67b5fe0 |
children | 90ce403d0dc5 |
line wrap: on
line source
/* TouchKeys: multi-touch musical keyboard control software Copyright (c) 2013 Andrew McPherson 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 3 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, see <http://www.gnu.org/licenses/>. ===================================================================== Osc.h: classes for handling reception and transmission of OSC messages, using the liblo library. */ #ifndef OSC_H #define OSC_H //#include <cstdint> #include <iostream> #include <iomanip> #include <fstream> #include <set> #include <map> #include <string> #include <vector> #include <set> #include "lo/lo.h" #include "../JuceLibraryCode/JuceHeader.h" using namespace std; class OscMessageSource; // This is an abstract base class implementing a single function oscHandlerMethod(). Objects that // want to register to receive OSC messages should inherit from OscHandler. Notice that all listener // add/remove methods are private or protected. The subclass of OscHandler should add any relevant // listeners, or optionally expose a public interface to add listeners. (Never call the methods in // OscMessageSource externally.) class OscHandler { public: OscHandler() : oscController_(NULL) {} // The OSC controller will call this method when it gets a matching message that's been registered virtual bool oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data) = 0; void setOscController(OscMessageSource *c) { oscController_ = c; } virtual ~OscHandler(); // In the destructor, remove all OSC listeners protected: bool addOscListener(const string& path); bool removeOscListener(const string& path); bool removeAllOscListeners(); OscMessageSource *oscController_; set<string> oscListenerPaths_; }; // Base class for anything that acts as a source of OSC messages. Could be // received externally or internally generated. class OscMessageSource { friend class OscHandler; public: OscMessageSource() {} protected: bool addListener(const string& path, OscHandler *object, bool matchSubpath = false); // Add a listener object for a specific path bool removeListener(const string& path, OscHandler *object); // Remove a listener object from a specific path bool removeListener(OscHandler *object); // Remove a listener object from all paths void updateListeners(); // Propagate changes to the listeners to the main object //ReadWriteLock oscListenerMutex_; // This mutex protects the OSC listener table from being modified mid-message CriticalSection oscListenerMutex_; // This mutex protects the OSC listener table from being modified mid-message CriticalSection oscUpdaterMutex_; // This mutex controls the insertion of objects in add/removeListener multimap<string, OscHandler*> noteListeners_; // Map from OSC path name to handler (possibly multiple handlers per object) multimap<string, OscHandler*> noteListenersToAdd_; // Collection of listeners to add on the next cycle multimap<string, OscHandler*> noteListenersToRemove_; // Collection of listeners to remove on the next cycle set<OscHandler*> noteListenersForBlanketRemoval_; // Collection of listeners to remove from all paths }; // This class specifically implements OSC messages coming from external sources class OscReceiver : public OscMessageSource { public: OscReceiver(const int port, const char *prefix) { globalPrefix_.assign(prefix); useThru_ = false; // Only start the server if the port is positive if(port > 0) { char portStr[16]; #ifdef _MSC_VER _snprintf_s(portStr, 16, _TRUNCATE, "%d", port); #else snprintf(portStr, 16, "%d", port); #endif oscServerThread_ = lo_server_thread_new(portStr, staticErrorHandler); if(oscServerThread_ != 0) { lo_server_thread_add_method(oscServerThread_, NULL, NULL, OscReceiver::staticHandler, (void *)this); lo_server_thread_start(oscServerThread_); } } else oscServerThread_ = 0; } void setThruAddress(lo_address thruAddr, const char *prefix) { thruAddress_ = thruAddr; thruPrefix_.assign(prefix); useThru_ = true; } // Check whether the server is operating bool running() { return (oscServerThread_ != 0); } // Get or set the current port. Setting the port requires restarting the server. // setPort() returns true on success; false if an error occurred (which will leave the server not running). const int port() { if(oscServerThread_ == 0) return 0; return lo_server_get_port(oscServerThread_); } bool setPort(const int port); // staticHandler() is called by liblo with new OSC messages. Its only function is to pass control // to the object-specific handler method, which has access to all internal variables. int handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *data); static int staticHandler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *userData) { return ((OscReceiver *)userData)->handler(path, types, argv, argc, msg, userData); } // staticErrorHandler() is called by liblo when an error occurs. For now, ignore errors. static void staticErrorHandler(int num, const char *msg, const char *path) {} ~OscReceiver() { if(oscServerThread_ != 0) { lo_server_thread_del_method(oscServerThread_, NULL, NULL); lo_server_thread_stop(oscServerThread_); lo_server_thread_free(oscServerThread_); } } private: lo_server_thread oscServerThread_; // Thread that handles received OSC messages // OSC thru bool useThru_; // Whether or not we retransmit any messages lo_address thruAddress_; // Address to which we retransmit string thruPrefix_; // Prefix that must be matched to be retransmitted // State variables string globalPrefix_; // Prefix for all OSC paths }; class OscTransmitter { public: OscTransmitter() : enabled_(true), debugMessages_(false) {} // Enable or disable transmission void setEnabled(bool enable) { enabled_ = enable; } bool enabled() { return enabled_; } // Add and remove addresses to send to int addAddress(const char * host, const char * port, int proto = LO_UDP); void removeAddress(int index); void clearAddresses(); vector<lo_address> addresses() { return addresses_; } void sendMessage(const char * path, const char * type, ...); void sendMessage(const char * path, const char * type, const lo_message& message); void sendByteArray(const char * path, const unsigned char * data, int length); void setDebugMessages(bool debug) { debugMessages_ = debug; } ~OscTransmitter(); private: vector<lo_address> addresses_; bool enabled_; bool debugMessages_; }; #endif // OSC_H