1743 lines · 51.2 KB · C++
RawDownload
/*----------------------------------------------------------------------------  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 &notype)    {        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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t