From 1ad3de7c7b7246aa2943ccab952fd1439c128f45 Mon Sep 17 00:00:00 2001 From: ISHII Tsuubito Date: Mon, 11 May 2015 22:09:28 +0900 Subject: [PATCH] add ofxOscPublisher --- README.md | 32 ++++- src/ofxOscPublisher.h | 275 ++++++++++++++++++++++++++++++++++++++++++ src/ofxPubSubOsc.h | 11 ++ 3 files changed, 314 insertions(+), 4 deletions(-) create mode 100644 src/ofxOscPublisher.h create mode 100644 src/ofxPubSubOsc.h diff --git a/README.md b/README.md index c71a03a..8df753f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ -# ofxOscSubscriber +# ofxPubSubOsc -subscribe OSC message. +publish/subscribe OSC message. -## How to use? +## API -* template \ ofxSubscribeOSC(int _port_, const string &_address_, T &value); +### ofxSubscribeOsc + +* template \ ofxSubscribeOsc(int _port_, const string &_address_, T &value); bind value to OSC message has _address_ incoming from _port_. @@ -17,8 +19,30 @@ unbind OSC message has _address_ incoming from _port_. unbind all OSC messages incoming from _port_. +### ofxPublishOsc + +* template \ ofxPublishOsc(const string &_ip_, int _port_, const string &_address_, T &_value_); +* template \ ofxPublishOsc(const string &_ip_, int _port_, const string &_address_, T (*_getter_)()); +* template \ ofxPublishOsc(const string &_ip_, int _port_, const string &_address_, U \*_that_, T (U::*_getter_)()); + +publish _value_ / _getter()_ / _that.*getter()_ to OSC message has _address_ to _ip:port_. + + +* ofxUnpublishOSC(int _port_, const string &_address_); + +unpublish OSC message has _address_ is send to _ip:port_. + +* ofxUnpublishOSC(int _port_); + +unpublish all OSC messages is send to _ip:port_. + ## Update history +### 2015/05/11 ver 0.02 release + +* rename from ofxOscSubscriber +* add ofxOscPublisher + ### 2015/05/09 ver 0.01 release ## License diff --git a/src/ofxOscPublisher.h b/src/ofxOscPublisher.h new file mode 100644 index 0000000..4e7c94b --- /dev/null +++ b/src/ofxOscPublisher.h @@ -0,0 +1,275 @@ +// +// ofxOscPublisher.h +// +// Created by ISHII 2bit on 2015/05/11. +// +// + +#pragma once + +#include "ofMain.h" +#include "ofxOsc.h" + +namespace ofx { + namespace { + template + struct add_reference_if_non_arithmetic { + typedef T& type; + }; + +#define define_add_reference_if_non_arithmetic(T) \ +template <> \ +struct add_reference_if_non_arithmetic { \ +typedef T type; \ +}; + define_add_reference_if_non_arithmetic(bool); + define_add_reference_if_non_arithmetic(short); + define_add_reference_if_non_arithmetic(unsigned short); + define_add_reference_if_non_arithmetic(int); + define_add_reference_if_non_arithmetic(unsigned int); + define_add_reference_if_non_arithmetic(long); + define_add_reference_if_non_arithmetic(unsigned long); + define_add_reference_if_non_arithmetic(float); + define_add_reference_if_non_arithmetic(double); +#undef define_add_reference_if_non_arithmetic +#define TypeRef(T) typename add_reference_if_non_arithmetic::type + } + class OscPublisher { + struct AbstractParameter { + virtual void send(ofxOscSender &sender, const string &address) {} + }; + + struct SetImplementation { + protected: +#define define_set_int(type) inline void set(ofxOscMessage &m, type v) const { m.addIntArg(v); } + define_set_int(bool); + define_set_int(short); + define_set_int(unsigned short); + define_set_int(int); + define_set_int(unsigned int); +#undef define_set_int +#define define_set_int64(type) inline void set(ofxOscMessage &m, type v) const { m.addInt64Arg(v); } + define_set_int64(long); + define_set_int64(unsigned long); +#undef define_set_int64 +#define define_set_float(type) inline void set(ofxOscMessage &m, type v) const { m.addFloatArg(v); } + define_set_float(float); + define_set_float(double); +#undef define_set_float + inline void set(ofxOscMessage &m, const string &v) const { m.addStringArg(v); } + template + inline void set(ofxOscMessage &m, const ofColor_ &v) const { setVec<4>(m, v); } + inline void set(ofxOscMessage &m, const ofVec2f &v) const { setVec<2>(m, v); } + inline void set(ofxOscMessage &m, const ofVec3f &v) const { setVec<3>(m, v); } + inline void set(ofxOscMessage &m, const ofVec4f &v) const { setVec<4>(m, v); } + + template + inline void setVec(ofxOscMessage &m, const T &v) const { + for(int i = 0; i < n; i++) { set(m, v[i]); } + } + + inline void set(ofxOscMessage &m, const ofRectangle &v) const { + set(m, v.x); + set(m, v.y); + set(m, v.width); + set(m, v.height); + } + + template + inline void set(ofxOscMessage &m, const U v[size]) const { + for(int i = 0; i < size; i++) { set(m, v[i]); } + } + + template + inline void set(ofxOscMessage &m, const vector &v) const { + for(int i = 0; i < v.size(); i++) { set(m, v[i]); } + } + }; + + template + struct Parameter : AbstractParameter, SetImplementation { + Parameter(T &t) : t(t) {} + virtual void send(ofxOscSender &sender, const string &address) { + ofxOscMessage m; + m.setAddress(address); + set(m, get()); + sender.sendMessage(m); + } + + protected: + virtual TypeRef(T) get() { return t; } + T &t; + }; + + template + struct Parameter : AbstractParameter, SetImplementation { + Parameter(T &t) : t(t), old(t) {} + virtual void send(ofxOscSender &sender, const string &address) { + if(!isChanged()) return; + ofxOscMessage m; + m.setAddress(address); + set(m, get()); + sender.sendMessage(m); + } + + protected: + inline bool isChanged() { + if(old != get()) { + old = get(); + return true; + } else { + return false; + } + } + + virtual TypeRef(T) get() { return t; } + protected: + T &t; + T old; + }; + + template + struct GetterFunctionParameter : Parameter { + typedef T (*GetterFunction)(); + GetterFunctionParameter(GetterFunction getter) : Parameter(dummy), getter(getter) {} + + protected: + virtual TypeRef(T) get() { return getter(); } + private: + GetterFunction getter; + T dummy; + }; + + template + struct GetterParameter : Parameter { + typedef T (U::*Getter)(); + GetterParameter(U *that, Getter getter) : getter(getter), that(*that) {} + GetterParameter(U &that, Getter getter) : getter(getter), that(that) {} + + protected: + virtual TypeRef(T) get() { return that.*getter(); } + private: + Getter getter; + U &that; + }; + + typedef shared_ptr ParameterRef; + typedef shared_ptr OscSenderRef; + typedef pair SenderKey; + typedef map Targets; + typedef map > TargetsMap; + + public: + static OscPublisher &getSharedInstance() { + return *(sharedInstance ?: sharedInstance = new OscPublisher); + } + + inline void publish(const string &ip, int port, const string &address, ParameterRef ref) { + SenderKey key(ip, port); + if(!isPublished(key)) { + ofxOscSender *sender = new ofxOscSender; + sender->setup(ip, port); + targetsMap.insert(make_pair(key, make_pair(OscSenderRef(sender), Targets()))); + } + targetsMap[key].second.insert(make_pair(address, ref)); + } + + template + void publish(const string &ip, int port, const string &address, const T &value, bool whenValueIsChanged = false) { + ParameterRef p; + if(whenValueIsChanged) p = ParameterRef(new Parameter(value)); + else p = ParameterRef(new Parameter(value)); + publish(ip, port, address, p); + } + + template + void publish(const string &ip, int port, const string &address, T (*getter)(), bool whenValueIsChanged = false) { + ParameterRef p; + if(whenValueIsChanged) p = ParameterRef(new GetterFunctionParameter(getter)); + else p = ParameterRef(new GetterFunctionParameter(getter)); + publish(ip, port, address, p); + } + + template + void publish(const string &ip, int port, const string &address, U *that, T (U::*getter)(), bool whenValueIsChanged = false) { + ParameterRef p; + if(whenValueIsChanged) p = ParameterRef(new GetterParameter(that, getter)); + else p = ParameterRef(new GetterParameter(that, getter)); + publish(ip, port, address, p); + } + + template + void publish(const string &ip, int port, const string &address, U &that, T (U::*getter)(), bool whenValueIsChanged = false) { + ParameterRef p; + if(whenValueIsChanged) p = ParameterRef(new GetterParameter(that, getter)); + else p = ParameterRef(new GetterParameter(that, getter)); + publish(ip, port, address, p); + } + + void unsubscribe(const string &ip, int port, const string &address) { + SenderKey key(ip, port); + if(targetsMap.find(key) == targetsMap.end()) return; + targetsMap[key].second.erase(address); + } + + void unsubscribe(const string &ip, int port) { + SenderKey key(ip, port); + targetsMap.erase(key); + } + + inline bool isPublished(const string &ip, int port) const { + return isPublished(SenderKey(ip, port)); + } + + inline bool isPublished(const SenderKey &key) const { + return targetsMap.find(key) != targetsMap.end(); + } + + inline bool isPublished(const string &ip, int port, const string &address) const { + SenderKey key(ip, port); + return isPublished(key) && (targetsMap.at(key).second.find(address) != targetsMap.at(key).second.end()); + } + + private: + void update(ofEventArgs &args) { + for(TargetsMap::iterator _ = targetsMap.begin(); _ != targetsMap.end(); _++) { + Targets &targets = _->second.second; + ofxOscSender *sender = _->second.first.get(); + for(Targets::iterator it = targets.begin(); it != targets.end(); it++) { + it->second->send(*sender, it->first); + } + } + } + OscPublisher() { + ofAddListener(ofEvents().update, this, &OscPublisher::update, OF_EVENT_ORDER_BEFORE_APP); + } + virtual ~OscPublisher() { + ofRemoveListener(ofEvents().update, this, &OscPublisher::update, OF_EVENT_ORDER_BEFORE_APP); + } + TargetsMap targetsMap; + static OscPublisher *sharedInstance; + }; + OscPublisher *OscPublisher::sharedInstance = NULL; +}; + +typedef ofx::OscPublisher ofxOscPublisher; + +template +void ofxPublishOsc(const string &ip, int port, const string &address, const T &value, bool whenValueIsChanged = false) { + ofxOscPublisher::getSharedInstance().publish(ip, port, address, value, whenValueIsChanged); +} + +template +void ofxPublishOsc(const string &ip, int port, const string &address, T (*getter)(), bool whenValueIsChanged = false) { + ofxOscPublisher::getSharedInstance().publish(ip, port, address, getter, whenValueIsChanged); +} + +template +void ofxPublishOsc(const string &ip, int port, const string &address, U *that, T (U::*getter)(), bool whenValueIsChanged = false) { + ofxOscPublisher::getSharedInstance().publish(ip, port, address, that, getter, whenValueIsChanged); +} + +template +void ofxPublishOsc(const string &ip, int port, const string &address, U &that, T (U::*getter)(), bool whenValueIsChanged = false) { + ofxOscPublisher::getSharedInstance().publish(ip, port, address, that, getter, whenValueIsChanged); +} diff --git a/src/ofxPubSubOsc.h b/src/ofxPubSubOsc.h new file mode 100644 index 0000000..3121b25 --- /dev/null +++ b/src/ofxPubSubOsc.h @@ -0,0 +1,11 @@ +// +// ofxPubSubOsc.h +// +// Created by ISHII 2bit on 2015/05/11. +// +// + +#pragma once + +#include "ofxOscPublisher.h" +#include "ofxOscSubscriber.h" \ No newline at end of file