/*---------------------------------------------------------------------------- ChucK Concurrent, On-the-fly Audio Programming Language Compiler and Virtual Machine Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved. http://chuck.stanford.edu/ http://chuck.cs.princeton.edu/ 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 U.S.A.-----------------------------------------------------------------------------*/ //-----------------------------------------------------------------------------// file: ulib_opsc.cpp// desc: class library for open sound control//// author: Philip L. Davidson (philipd@alumni.princeton.edu)// Ge Wang (gewang@cs.princeton.edu)// Perry R. Cook (prc@cs.princeton.edu)// date: Spring 2005//----------------------------------------------------------------------------- // lo.h ----> lo_osc_types.h needs to import <cstdint> before running itself,// but ONLY when compiling this file, and NOT when compiling liblo .c files// so, set a flag | REFACTOR-2017#ifdef __PLATFORM_WIN32__#define ULIB_OPSC_CPP#endif #ifdef __UNITY_FLAT__#include "lo.h"#else#include "lo/lo.h"#endif #include "ulib_opsc.h"#include "chuck_type.h"#include "chuck_vm.h"#include "chuck_compile.h"#include "chuck_dl.h"#include "util_opsc.h"#include "chuck_instr.h"#include "util_thread.h"#include "util_buffers.h"#include "util_string.h" #if _MSC_VER#define snprintf _snprintf#endif const std::string CK_OSC_TYPETAG_CHARS = "ifs"; struct OscMsg{ std::string path; std::string type; struct OscArg { OscArg() : i(0), f(0), s() { } OscArg(int _i) : i(_i), f(0), s() { } OscArg(float _f) : i(0), f(_f), s() { } OscArg(const std::string &_s) : i(0), f(0), s(_s) { } int i; float f; std::string s; }; std::vector<OscArg> args;}; // TODO: use this to cache ck objects to not leak memory so rampantlystruct CkOscMsg{ OscMsg msg; Chuck_String *path; Chuck_String *type; std::vector<Chuck_Object> args;}; class OscIn; class OscInServer{public: static OscInServer *forPort(int port) { if(s_oscIn.count(port) == 0) { s_oscIn[port] = new OscInServer(port); } return s_oscIn[port]; } static void shutdownAll() { } void addMethod(const std::string &method, OscIn * obj) { OscInMsg msg; msg.msg_type = OscInMsg::ADD_METHOD; methodToPathAndType(method, msg.path, msg.nopath, msg.type, msg.notype); msg.obj = obj; m_inMsgBuffer.put(msg); } void removeMethod(const std::string &method, OscIn * obj) { OscInMsg msg; msg.msg_type = OscInMsg::REMOVE_METHOD; methodToPathAndType(method, msg.path, msg.nopath, msg.type, msg.notype); msg.obj = obj; m_inMsgBuffer.put(msg); } void removeAllMethods(OscIn * obj) { OscInMsg msg; msg.msg_type = OscInMsg::REMOVEALL_METHODS; msg.obj = obj; m_inMsgBuffer.put(msg); } int port() { return m_assignedPort; } private: static std::map<int, OscInServer *> s_oscIn; #ifdef WIN32 static unsigned int __stdcall s_server_cb(void *data)#else static void *s_server_cb(void *data)#endif // WIN32 { OscInServer * _this = (OscInServer *) data; #ifdef WIN32 return (t_CKINT)_this->server_cb();#else return _this->server_cb();#endif } static void s_err_handler(int num, const char *msg, const char *where) { if(msg) EM_error3("OscIn: error: %s", msg); else EM_error3("OscIn: unknown error"); } static void methodToPathAndType(const std::string &method, std::string &path, t_CKBOOL &nopath, std::string &type, t_CKBOOL ¬ype) { t_CKINT comma_pos = method.find(','); if(comma_pos != method.npos) { path = ltrim(rtrim(method.substr(0, comma_pos))); nopath = FALSE; std::string dirty_type = method.substr(comma_pos+1); type.clear(); for(int i = 0; i < dirty_type.size(); i++) if(CK_OSC_TYPETAG_CHARS.find(dirty_type[i]) != std::string::npos) type.push_back(dirty_type[i]); notype = FALSE; } else { path = ltrim(rtrim(method)); nopath = (path.size() == 0); notype = TRUE; } } struct OscInMsg { enum Type { NO_METHOD, ADD_METHOD, REMOVE_METHOD, REMOVEALL_METHODS, }; Type msg_type; std::string path; t_CKBOOL nopath; std::string type; t_CKBOOL notype; OscIn * obj; // 1.4.1.0 (ge) added OscInMsg() : msg_type(NO_METHOD), nopath(FALSE), notype(FALSE), obj(NULL) { } }; OscInServer(int port) : m_port(port), m_inMsgBuffer(CircularBuffer<OscInMsg>(1024)), m_thread(XThread()), m_quit(false), m_assignedPort(-1) { m_thread.start(s_server_cb, this); } void *server_cb(); XThread m_thread; bool m_quit; const int m_port; int m_assignedPort; CircularBuffer<OscInMsg> m_inMsgBuffer; struct Method { std::string path; t_CKBOOL nopath; std::string type; t_CKBOOL notype; bool operator==(const Method &m) const { return path == m.path && nopath == m.nopath && type == m.type && notype == m.notype; } }; std::map<OscIn *, std::list<Method> > m_methods;}; std::map<int, OscInServer *> OscInServer::s_oscIn; class OscIn{public: OscIn(Chuck_Event * event, Chuck_VM * vm) : m_event(event), m_vm(vm), m_port(-1), m_oscMsgBuffer(CircularBuffer<OscMsg>(1024)) { m_eventBuffer = m_vm->create_event_buffer(); } ~OscIn() { removeAllMethods(); CBufferSimple * t_eventBuffer = m_eventBuffer; m_eventBuffer = NULL; m_vm->destroy_event_buffer(t_eventBuffer); m_vm = NULL; m_event = NULL; } void addMethod(const std::string &method) { OscInServer::forPort(m_port)->addMethod(method, this); } void removeMethod(const std::string &method) { OscInServer::forPort(m_port)->removeMethod(method, this); } void removeAllMethods() { OscInServer::forPort(m_port)->removeAllMethods(this); } t_CKBOOL get(OscMsg &msg) { return m_oscMsgBuffer.get(msg); } static int s_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data) { OscIn * _this = (OscIn *) user_data; return _this->handler(path, types, argv, argc, msg); } int port(int port) { m_port = port; return m_port; } int port() { // 1.5.0.0 (ge) simply return the current m_port return m_port; // previously (which returns an assigned port is always set) // return OscInServer::forPort(m_port)->port(); } private: Chuck_VM * m_vm; Chuck_Event * m_event; int m_port; CBufferSimple * m_eventBuffer; CircularBuffer<OscMsg> m_oscMsgBuffer; int handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message _msg) { OscMsg msg; msg.path = path; msg.type = types; for(int i = 0; i < argc; i++) { OscMsg::OscArg arg; switch(types[i]) { case 'i': arg.i = argv[i]->i; break; case 'f': arg.f = argv[i]->f; break; case 's': arg.s = &(argv[i]->s); break; default: EM_error3("OscIn: error: unhandled OSC type '%c'", types[i]); } msg.args.push_back(arg); } m_oscMsgBuffer.put(msg); m_vm->queue_event(m_event, 1, m_eventBuffer); return -1; }}; void *OscInServer::server_cb(){ lo_server m_server = NULL; if(m_port > 0) { char portStr[32]; snprintf(portStr, 32, "%d", m_port); m_server = lo_server_new(portStr, s_err_handler); } else { m_server = lo_server_new(NULL, s_err_handler); } if(m_server == NULL) { EM_error3("OscIn: error: unable to create server instance"); return NULL; } m_assignedPort = lo_server_get_port(m_server); EM_log(CK_LOG_INFO, "OscIn: starting OSC server at port '%d'", m_port); while(!m_quit) { OscInMsg msg; while(m_inMsgBuffer.get(msg)) { switch(msg.msg_type) { case OscInMsg::NO_METHOD: // 1.4.1.0 (ge) added { // just skip continue; } break; case OscInMsg::ADD_METHOD: { if(lo_server_add_method(m_server, msg.nopath ? NULL : msg.path.c_str(), msg.notype ? NULL : msg.type.c_str(), OscIn::s_handler, msg.obj)) { if(!m_methods.count(msg.obj)) m_methods[msg.obj] = std::list<Method>(); Method m; m.path = msg.path; m.nopath = msg.nopath; m.type = msg.type; m.notype = msg.notype; m_methods[msg.obj].push_back(m); } else { EM_error3("OscIn: error: add_method failed for %s, %s", msg.path.c_str(), msg.type.c_str()); } } break; case OscInMsg::REMOVE_METHOD: { lo_server_del_method(m_server, msg.nopath ? NULL : msg.path.c_str(), msg.notype ? NULL : msg.type.c_str()); if(m_methods.count(msg.obj)) { Method m; m.path = msg.path; m.nopath = msg.nopath; m.type = msg.type; m.notype = msg.notype; m_methods[msg.obj].remove(m); } } break; case OscInMsg::REMOVEALL_METHODS: { if(m_methods.count(msg.obj)) { for(std::list<Method>::iterator i = m_methods[msg.obj].begin(); i != m_methods[msg.obj].end(); i++) { lo_server_del_method(m_server, i->nopath ? NULL : i->path.c_str(), i->notype ? NULL : i->type.c_str()); } m_methods[msg.obj].clear(); m_methods.erase(msg.obj); } } break; } } lo_server_recv_noblock(m_server, 2); } lo_server_free(m_server); EM_log(CK_LOG_INFO, "OscIn: shutting down OSC server", m_port); return NULL;} class OscOut{public: OscOut() { m_address = NULL; m_message = NULL; // 1.4.1.1 (ge) added m_port = 0; } ~OscOut() { if(m_address != NULL) { lo_address_free(m_address); m_address = NULL; } if(m_message != NULL) { lo_message_free(m_message); m_message = NULL; } } t_CKBOOL setDestination(const std::string &host, int port) { if( m_address != NULL ) { lo_address_free(m_address);Lines 1–500 of 1743. Load more
/*---------------------------------------------------------------------------- ChucK Concurrent, On-the-fly Audio Programming Language Compiler and Virtual Machine Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved. http://chuck.stanford.edu/ http://chuck.cs.princeton.edu/ 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 U.S.A. -----------------------------------------------------------------------------*/ //----------------------------------------------------------------------------- // file: ulib_opsc.cpp // desc: class library for open sound control // // author: Philip L. Davidson (philipd@alumni.princeton.edu) // Ge Wang (gewang@cs.princeton.edu) // Perry R. Cook (prc@cs.princeton.edu) // date: Spring 2005 //----------------------------------------------------------------------------- // lo.h ----> lo_osc_types.h needs to import <cstdint> before running itself, // but ONLY when compiling this file, and NOT when compiling liblo .c files // so, set a flag | REFACTOR-2017 #ifdef __PLATFORM_WIN32__ #define ULIB_OPSC_CPP #endif #ifdef __UNITY_FLAT__ #include "lo.h" #else #include "lo/lo.h" #endif #include "ulib_opsc.h" #include "chuck_type.h" #include "chuck_vm.h" #include "chuck_compile.h" #include "chuck_dl.h" #include "util_opsc.h" #include "chuck_instr.h" #include "util_thread.h" #include "util_buffers.h" #include "util_string.h" #if _MSC_VER #define snprintf _snprintf #endif const std::string CK_OSC_TYPETAG_CHARS = "ifs"; struct OscMsg { std::string path; std::string type; struct OscArg { OscArg() : i(0), f(0), s() { } OscArg(int _i) : i(_i), f(0), s() { } OscArg(float _f) : i(0), f(_f), s() { } OscArg(const std::string &_s) : i(0), f(0), s(_s) { } int i; float f; std::string s; }; std::vector<OscArg> args; }; // TODO: use this to cache ck objects to not leak memory so rampantly struct CkOscMsg { OscMsg msg; Chuck_String *path; Chuck_String *type; std::vector<Chuck_Object> args; }; class OscIn; class OscInServer { public: static OscInServer *forPort(int port) { if(s_oscIn.count(port) == 0) { s_oscIn[port] = new OscInServer(port); } return s_oscIn[port]; } static void shutdownAll() { } void addMethod(const std::string &method, OscIn * obj) { OscInMsg msg; msg.msg_type = OscInMsg::ADD_METHOD; methodToPathAndType(method, msg.path, msg.nopath, msg.type, msg.notype); msg.obj = obj; m_inMsgBuffer.put(msg); } void removeMethod(const std::string &method, OscIn * obj) { OscInMsg msg; msg.msg_type = OscInMsg::REMOVE_METHOD; methodToPathAndType(method, msg.path, msg.nopath, msg.type, msg.notype); msg.obj = obj; m_inMsgBuffer.put(msg); } void removeAllMethods(OscIn * obj) { OscInMsg msg; msg.msg_type = OscInMsg::REMOVEALL_METHODS; msg.obj = obj; m_inMsgBuffer.put(msg); } int port() { return m_assignedPort; } private: static std::map<int, OscInServer *> s_oscIn; #ifdef WIN32 static unsigned int __stdcall s_server_cb(void *data) #else static void *s_server_cb(void *data) #endif // WIN32 { OscInServer * _this = (OscInServer *) data; #ifdef WIN32 return (t_CKINT)_this->server_cb(); #else return _this->server_cb(); #endif } static void s_err_handler(int num, const char *msg, const char *where) { if(msg) EM_error3("OscIn: error: %s", msg); else EM_error3("OscIn: unknown error"); } static void methodToPathAndType(const std::string &method, std::string &path, t_CKBOOL &nopath, std::string &type, t_CKBOOL ¬ype) { t_CKINT comma_pos = method.find(','); if(comma_pos != method.npos) { path = ltrim(rtrim(method.substr(0, comma_pos))); nopath = FALSE; std::string dirty_type = method.substr(comma_pos+1); type.clear(); for(int i = 0; i < dirty_type.size(); i++) if(CK_OSC_TYPETAG_CHARS.find(dirty_type[i]) != std::string::npos) type.push_back(dirty_type[i]); notype = FALSE; } else { path = ltrim(rtrim(method)); nopath = (path.size() == 0); notype = TRUE; } } struct OscInMsg { enum Type { NO_METHOD, ADD_METHOD, REMOVE_METHOD, REMOVEALL_METHODS, }; Type msg_type; std::string path; t_CKBOOL nopath; std::string type; t_CKBOOL notype; OscIn * obj; // 1.4.1.0 (ge) added OscInMsg() : msg_type(NO_METHOD), nopath(FALSE), notype(FALSE), obj(NULL) { } }; OscInServer(int port) : m_port(port), m_inMsgBuffer(CircularBuffer<OscInMsg>(1024)), m_thread(XThread()), m_quit(false), m_assignedPort(-1) { m_thread.start(s_server_cb, this); } void *server_cb(); XThread m_thread; bool m_quit; const int m_port; int m_assignedPort; CircularBuffer<OscInMsg> m_inMsgBuffer; struct Method { std::string path; t_CKBOOL nopath; std::string type; t_CKBOOL notype; bool operator==(const Method &m) const { return path == m.path && nopath == m.nopath && type == m.type && notype == m.notype; } }; std::map<OscIn *, std::list<Method> > m_methods; }; std::map<int, OscInServer *> OscInServer::s_oscIn; class OscIn { public: OscIn(Chuck_Event * event, Chuck_VM * vm) : m_event(event), m_vm(vm), m_port(-1), m_oscMsgBuffer(CircularBuffer<OscMsg>(1024)) { m_eventBuffer = m_vm->create_event_buffer(); } ~OscIn() { removeAllMethods(); CBufferSimple * t_eventBuffer = m_eventBuffer; m_eventBuffer = NULL; m_vm->destroy_event_buffer(t_eventBuffer); m_vm = NULL; m_event = NULL; } void addMethod(const std::string &method) { OscInServer::forPort(m_port)->addMethod(method, this); } void removeMethod(const std::string &method) { OscInServer::forPort(m_port)->removeMethod(method, this); } void removeAllMethods() { OscInServer::forPort(m_port)->removeAllMethods(this); } t_CKBOOL get(OscMsg &msg) { return m_oscMsgBuffer.get(msg); } static int s_handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data) { OscIn * _this = (OscIn *) user_data; return _this->handler(path, types, argv, argc, msg); } int port(int port) { m_port = port; return m_port; } int port() { // 1.5.0.0 (ge) simply return the current m_port return m_port; // previously (which returns an assigned port is always set) // return OscInServer::forPort(m_port)->port(); } private: Chuck_VM * m_vm; Chuck_Event * m_event; int m_port; CBufferSimple * m_eventBuffer; CircularBuffer<OscMsg> m_oscMsgBuffer; int handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message _msg) { OscMsg msg; msg.path = path; msg.type = types; for(int i = 0; i < argc; i++) { OscMsg::OscArg arg; switch(types[i]) { case 'i': arg.i = argv[i]->i; break; case 'f': arg.f = argv[i]->f; break; case 's': arg.s = &(argv[i]->s); break; default: EM_error3("OscIn: error: unhandled OSC type '%c'", types[i]); } msg.args.push_back(arg); } m_oscMsgBuffer.put(msg); m_vm->queue_event(m_event, 1, m_eventBuffer); return -1; } }; void *OscInServer::server_cb() { lo_server m_server = NULL; if(m_port > 0) { char portStr[32]; snprintf(portStr, 32, "%d", m_port); m_server = lo_server_new(portStr, s_err_handler); } else { m_server = lo_server_new(NULL, s_err_handler); } if(m_server == NULL) { EM_error3("OscIn: error: unable to create server instance"); return NULL; } m_assignedPort = lo_server_get_port(m_server); EM_log(CK_LOG_INFO, "OscIn: starting OSC server at port '%d'", m_port); while(!m_quit) { OscInMsg msg; while(m_inMsgBuffer.get(msg)) { switch(msg.msg_type) { case OscInMsg::NO_METHOD: // 1.4.1.0 (ge) added { // just skip continue; } break; case OscInMsg::ADD_METHOD: { if(lo_server_add_method(m_server, msg.nopath ? NULL : msg.path.c_str(), msg.notype ? NULL : msg.type.c_str(), OscIn::s_handler, msg.obj)) { if(!m_methods.count(msg.obj)) m_methods[msg.obj] = std::list<Method>(); Method m; m.path = msg.path; m.nopath = msg.nopath; m.type = msg.type; m.notype = msg.notype; m_methods[msg.obj].push_back(m); } else { EM_error3("OscIn: error: add_method failed for %s, %s", msg.path.c_str(), msg.type.c_str()); } } break; case OscInMsg::REMOVE_METHOD: { lo_server_del_method(m_server, msg.nopath ? NULL : msg.path.c_str(), msg.notype ? NULL : msg.type.c_str()); if(m_methods.count(msg.obj)) { Method m; m.path = msg.path; m.nopath = msg.nopath; m.type = msg.type; m.notype = msg.notype; m_methods[msg.obj].remove(m); } } break; case OscInMsg::REMOVEALL_METHODS: { if(m_methods.count(msg.obj)) { for(std::list<Method>::iterator i = m_methods[msg.obj].begin(); i != m_methods[msg.obj].end(); i++) { lo_server_del_method(m_server, i->nopath ? NULL : i->path.c_str(), i->notype ? NULL : i->type.c_str()); } m_methods[msg.obj].clear(); m_methods.erase(msg.obj); } } break; } } lo_server_recv_noblock(m_server, 2); } lo_server_free(m_server); EM_log(CK_LOG_INFO, "OscIn: shutting down OSC server", m_port); return NULL; } class OscOut { public: OscOut() { m_address = NULL; m_message = NULL; // 1.4.1.1 (ge) added m_port = 0; } ~OscOut() { if(m_address != NULL) { lo_address_free(m_address); m_address = NULL; } if(m_message != NULL) { lo_message_free(m_message); m_message = NULL; } } t_CKBOOL setDestination(const std::string &host, int port) { if( m_address != NULL ) { lo_address_free(m_address);