diff --git a/.gitignore b/.gitignore index e6c8671..3177794 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ *.o tongseng -*.swp -TongsengApp/build -TongsengApp/TongsengApp.xcodeproj/iang.* +build +project.xcworkspace +xcuserdata diff --git a/Makefile b/Makefile index 389d6bd..53d6383 100644 --- a/Makefile +++ b/Makefile @@ -6,11 +6,13 @@ SRC=main.cpp \ TUIO/TuioManager.cpp \ TUIO/TuioObject.cpp \ TUIO/TuioCursor.cpp \ + TUIO/TuioBlob.cpp \ TUIO/TuioContainer.cpp \ TUIO/TuioPoint.cpp \ TUIO/TuioBlob.cpp \ TUIO/TuioDispatcher.cpp \ TUIO/UdpSender.cpp \ + TUIO/OneEuroFilter.cpp \ oscpack/ip/posix/NetworkingUtils.cpp \ oscpack/ip/posix/UdpSocket.cpp \ oscpack/osc/OscOutboundPacketStream.cpp \ @@ -18,13 +20,13 @@ SRC=main.cpp \ OBJS=$(SRC:.cpp=.o) CPPFLAGS=-ITUIO -Ioscpack -LIBS=-F/System/Library/PrivateFrameworks -framework MultitouchSupport +LIBS=-F/System/Library/PrivateFrameworks -framework MultitouchSupport -framework CoreFoundation BIN=tongseng all : $(BIN) .cpp.o : - g++ -c $(CPPFLAGS) $< -o $@ + g++ $(CPPFLAGS) -c $< -o $@ $(BIN) : $(OBJS) g++ -o $@ $(LIBS) $^ diff --git a/TUIO/FlashSender.cpp b/TUIO/FlashSender.cpp deleted file mode 100644 index c14071f..0000000 --- a/TUIO/FlashSender.cpp +++ /dev/null @@ -1,648 +0,0 @@ -#include "FlashSender.h" - -// Copyright (C) 2009 Georg Kaindl -// This file is part of Touché. -// -// Touché is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of -// the License, or (at your option) any later version. -// -// Touché 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 Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with Touché. If not, see . -// - -#include -#include -#include -#include - -#if !defined(WIN32) -#include -#include -#include -#include - -#if defined(__APPLE__) -#include -#include -#else -#include -#endif - -#endif - -#define FLASHLC_SHM_SIZE (64528) // This is what Flash always uses as size -#define FLASHLC_SHM_LISTENERS_OFFSET (40976) // Another "magic number" -#define MAX_LISTENER_NAME_LEN (64) -#define MAX_LISTENER_METHOD_NAME (64) - -#define PROTOCOL_NAME ("localhost") - -#define WIN32_SEMAPHORE_NAME ("MacromediaMutexOmega") -#define WIN32_SHMEM_NAME ("MacromediaFMOmega") -#define POSIX_SEMAPHORE_NAME ("MacromediaSemaphoreDig") -#define POSIX_SEMAPHORE_INITIAL_VALUE (10) - -#define AMF_TYPE_STRING (0x02) -#define AMF_TYPE_AMF3OBJ (0x11) -#define AMF3_TYPE_BYTEARRAY (0x0C) - -#define AMF_ENVELOPE_LEN (16) -#define AMF_ENVELOPE_TIMESTAMP_POS (8) -#define AMF_ENVELOPE_SIZE_POS (12) - -void _TFLCSLockSemaphore(TFLCSLocalConnection_t* connection); -void _TFLCSUnlockSemaphore(TFLCSLocalConnection_t* connection); - -// returns non-zero if the given connection is in a usable state, zero otherwise -int _TFLCSConnectionStructureIsValidForUse(TFLCSLocalConnection_t* connection); - -// On WIN32, we cannot create the shared memory and semaphore ourselves, because -// we don't know the exact parameters. Therefore, if Flash is not running when we -// try to connect, we'll try again whenever we should send data, until we finally -// manage to connect. -int _TFLCSDelayedConnect(TFLCSLocalConnection_t* connection); - -#define ENSURE_CONNECTION_UP(c, rv) do { if (!(c)->open && !_TFLCSDelayedConnect((c))) return (rv); } while (0) - -u_int32_t _TFLCSKnownDarwinKeys[] = { 0x53414e44, 0 }; - -TFLCSError_t TFLCSErrno = TFLCSErrorSuccess; - -TFLCSLocalConnection_t* TFLCSConnect(const char* listenerName, - const char* listenerMethod, - void* shmemKey, - void* semaphoreKey) -{ - TFLCSLocalConnection_t* connection = NULL; - - if (NULL == listenerName || NULL == listenerMethod || - strlen(listenerName) > TFLCS_LISTENER_NAME_MAX_LEN || - strlen(listenerMethod) > TFLCS_LISTENER_METHOD_MAX_LEN) { - TFLCSErrno = TFLCSErrorInvalidArgument; - return NULL; - } - - connection = (TFLCSLocalConnection_t*)malloc(sizeof(TFLCSLocalConnection_t)); - if (NULL == connection) { - TFLCSErrno = TFLCSErrorOutOfMemory; - goto errorReturn; - } - - connection->open = 0; - -#if defined(WIN32) - // initialize the structure - connection->semaphore = NULL; - connection->mapFile = NULL; - connection->mapAddress = NULL; - connection->data = NULL; - - _TFLCSDelayedConnect(connection); -#else - // initialize the structure - connection->semaphore = (sem_t*)SEM_FAILED; - connection->shmid = -1; - connection->data = (char*)-1; - - // we don't need a delayed connect on MacOS X, so let's just connect now! - key_t key; - char* semName; - - if (NULL != shmemKey) - key = *(key_t*)shmemKey; - else { - key_t* guessedKey = (key_t*)TFLCSGuessShmemKey(); - if (NULL != guessedKey) - key = *(key_t*)guessedKey; - else { - TFLCSErrno = TFLCSErrorShmemKeyNotFound; - goto errorReturn; - } - } - - if (NULL != semaphoreKey) - semName = (char*)semaphoreKey; - else - semName = (char*)POSIX_SEMAPHORE_NAME; - - connection->semaphore = sem_open(semName, - O_CREAT, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, - POSIX_SEMAPHORE_INITIAL_VALUE); - if ((sem_t*)SEM_FAILED == connection->semaphore) { - TFLCSErrno = TFLCSErrorSemaphoreCreationFailed; - goto errorReturn; - } - - if (-1 == (connection->shmid = shmget(key, FLASHLC_SHM_SIZE, 0666 | IPC_CREAT))) { - TFLCSErrno = TFLCSErrorShmemIDNotFound; - goto errorReturn; - } - - connection->data = (char*)shmat(connection->shmid, NULL, 0); - if ((char*)-1 == connection->data) { - TFLCSErrno = TFLCSErrorShmemOpeningFailed; - goto errorReturn; - } - - connection->open = 1; - - // initialize the memory region the way Flash likes it :-) - connection->data[0] = 1; - connection->data[4] = 1; -#endif - - strncpy(connection->listenerName, listenerName, TFLCS_LISTENER_NAME_MAX_LEN); - strncpy(connection->listenerMethod, listenerMethod, TFLCS_LISTENER_METHOD_MAX_LEN); - - return connection; - -errorReturn: - TFLCSDisconnect(connection); - - return NULL; -} - -void TFLCSDisconnect(TFLCSLocalConnection_t* connection) -{ - if (NULL != connection) { -#if defined(WIN32) - if (NULL != connection->semaphore) - CloseHandle(connection->semaphore); - - if (NULL != connection->mapAddress) - UnmapViewOfFile(connection->mapAddress); - - if (NULL != connection->mapFile) - CloseHandle(connection->mapFile); -#else - if ((sem_t*)SEM_FAILED != connection->semaphore) - sem_close(connection->semaphore); - - if ((char*)-1 != connection->data) - (void)shmdt(connection->data); -#endif - free(connection); - } -} - -void TFLCSChangeListenerName(TFLCSLocalConnection_t* connection, const char* newListenerName) -{ - if (NULL != connection && NULL != newListenerName) - strncpy(connection->listenerName, newListenerName, TFLCS_LISTENER_NAME_MAX_LEN); -} - -void TFLCSChangeMethodName(TFLCSLocalConnection_t* connection, const char* newMethodName) -{ - if (NULL != connection && NULL != newMethodName) - strncpy(connection->listenerMethod, newMethodName, TFLCS_LISTENER_METHOD_MAX_LEN); -} - -int TFLCSConnectionHasConnectedClient(TFLCSLocalConnection_t* connection) -{ - ENSURE_CONNECTION_UP(connection, 0); - - int retval = 0; - - if (_TFLCSConnectionStructureIsValidForUse(connection)) { - _TFLCSLockSemaphore(connection); - - int c, l = strlen(connection->listenerName); - char* p = &connection->data[FLASHLC_SHM_LISTENERS_OFFSET]; - - while (!retval && (char)0 != *p) { - c = strlen(p) + 1; - if (0 == strncmp(p, connection->listenerName, l)) - retval = 1; - - p += c; - } - - _TFLCSUnlockSemaphore(connection); - } - - return retval; -} - -int TFLCSGetConnectedConnectionNames(TFLCSLocalConnection_t* connection, char* dest, int destLen) -{ - ENSURE_CONNECTION_UP(connection, 0); - - int retval = 0; - - if (NULL != dest && 0 < destLen && _TFLCSConnectionStructureIsValidForUse(connection)) { - _TFLCSLockSemaphore(connection); - - int c, i=0; - char* p = &connection->data[FLASHLC_SHM_LISTENERS_OFFSET]; - - while ((char)0 != *p && destLen > 0) { - c = strlen(p) + 1; - if (0 == (i % 3)) { - strncpy(dest, p, destLen < c ? destLen : c); - destLen -= c; - dest += c; - } - - p += c; - i++; - } - - retval = i/3; - - _TFLCSUnlockSemaphore(connection); - } - - return retval; -} - -void* TFLCSGuessShmemKey() -{ -#if defined(WIN32) - return (void*)WIN32_SHMEM_NAME; -#else - static int found = 0; - static key_t key; - - // first, try our known keys - int i = 0; - while(!found && _TFLCSKnownDarwinKeys[i]) { - if (-1 != shmget(_TFLCSKnownDarwinKeys[i], FLASHLC_SHM_SIZE, 0)) { - found = 1; - key = _TFLCSKnownDarwinKeys[i]; - } - - i++; - } - - /* // magic numbers for MacOS X 10.5, probably later and earlier versions too, dunno... - int minid = 0xffff; - int maxid = 0x500000; - struct shmid_ds shm_info; - for (i=minid; !found && i<=maxid; i++) { - if (shmctl(i, IPC_STAT, &shm_info) < 0) - continue; - - if (FLASHLC_SHM_SIZE == shm_info.shm_segsz) { - found = 1; - key = shm_info.shm_perm._key; - } - } */ - - // if we didn't find anything, set the key to a reasonable guess - // this is necessary because the shared segment might not exist yet. - if (!found) { - key = _TFLCSKnownDarwinKeys[0]; - found = 1; - } - - return &key; -#endif -} - -u_int32_t TFLCSGetTickCount() -{ -#if defined(WIN32) - return (u_int32_t)GetTickCount(); -#elif defined(__APPLE__) - static mach_timebase_info_data_t timeBase; - - u_int64_t nanos = mach_absolute_time(); - - if (0 == timeBase.denom) { - (void)mach_timebase_info(&timeBase); - } - return (u_int32_t)((nanos * (u_int64_t)timeBase.numer / (u_int64_t)timeBase.denom) / (u_int64_t)1000000); -#else - static struct timeval bt; - static int initialized = 0; - - if (!initialized) { - struct utmpx* ut; - while (NULL != (ut = getutxent())) { - if (BOOT_TIME == ut->ut_type) { - memcpy(&bt, &ut->ut_tv, sizeof(struct timeval)); - break; - } - } - initialized = 1; - } - - struct timeval nt, btc; - (void)gettimeofday(&nt, NULL); - memcpy(&btc, &bt, sizeof(struct timeval)); - - if (nt.tv_usec < btc.tv_usec) { - u_int64_t n = (btc.tv_usec - nt.tv_usec) / 1000000 + 1; - btc.tv_usec -= 1000000 * n; - btc.tv_sec += n; - } - if (nt.tv_usec - btc.tv_usec > 1000000) { - u_int64_t n = (btc.tv_usec - nt.tv_usec) / 1000000; - btc.tv_usec += 1000000 * n; - btc.tv_sec -= n; - } - - nt.tv_usec = nt.tv_usec - btc.tv_usec; - nt.tv_sec = nt.tv_sec - btc.tv_sec; - - return (u_int32_t)((nt.tv_sec * 1000) + (nt.tv_usec / 1000)); -#endif -} - -int TFLCSWriteAMF3Integer(char* buffer, int value, int pos) -{ - if (value < 0) { - buffer[pos++] = (0x80 | ((value >> 22) & 0xff)); - buffer[pos++] = (0x80 | ((value >> 15) & 0x7f)); - buffer[pos++] = (0x80 | ((value >> 8) & 0x7f)); - buffer[pos++] = (value & 0xff); - } else if (value <= 0x7f) { - buffer[pos++] = value; - } else if (value <= 0x3fff) { - buffer[pos++] = (0x80 | ((value >> 7) & 0x7f)); - buffer[pos++] = (value & 0x7f); - } else if (value <= 0x1fffff) { - buffer[pos++] = (0x80 | ((value >> 14) & 0x7f)); - buffer[pos++] = (0x80 | ((value >> 7) & 0x7f)); - buffer[pos++] = (value & 0x7f); - } else { - buffer[pos++] = (0x80 | ((value >> 22) & 0xff)); - buffer[pos++] = (0x80 | ((value >> 15) & 0x7f)); - buffer[pos++] = (0x80 | ((value >> 8) & 0x7f)); - buffer[pos++] = (value & 0xff); - } - - return pos; -} - -int TFLCSWriteAMFString(char* buffer, const char * str, int pos) -{ - int len = strlen(str); - - buffer[pos++] = AMF_TYPE_STRING; - buffer[pos++] = 0; // TODO: string length is badly encoded here! - buffer[pos++] = (char)(len & 0xff); - - strcpy((char*)&buffer[pos], str); - - pos += len; - return pos; -} - -int TFLCSWriteAMF3ByteArray(char* buffer, const char* bytes, int pos, int len) -{ - // buffer[pos++] = AMF_TYPE_AMF3OBJ; - buffer[pos++] = AMF3_TYPE_BYTEARRAY; // AMF3_TYPE_BYTE_ARRAY - - pos = TFLCSWriteAMF3Integer(buffer, ((len << 1) | 1), pos); - - int i=0; - for(i=0; idata[AMF_ENVELOPE_TIMESTAMP_POS]; - - int pos = AMF_ENVELOPE_LEN; - // check timestamp and size - - memset(connection->data, 0, AMF_ENVELOPE_LEN); - - connection->data[0] = 1; - connection->data[4] = 1; - - *timestamp = TFLCSGetTickCount(); - - // write connection name - pos = TFLCSWriteAMFString(connection->data, connection->listenerName, pos); - // write protocol - pos = TFLCSWriteAMFString(connection->data, PROTOCOL_NAME, pos); - - // I have no idea what this is, but we apparently need it... - char weirdBytes[] = { - 0x01, 0x01, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0x40, 0x24, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x08, 0, 0, - 0, 0, 0, 0}; - int i; - for (i=0; i<31; i++) - connection->data[pos++] = weirdBytes[i]; - - // write method name - pos = TFLCSWriteAMFString(connection->data, connection->listenerMethod, pos); - - return pos; -} - -int TFLCSWriteLCAMFEnvelopeTrailer(TFLCSLocalConnection_t* connection, int pos) -{ - if (NULL == connection) - return pos; - - u_int32_t* size = (u_int32_t*)&connection->data[AMF_ENVELOPE_SIZE_POS]; - - //pos = writeAMF3ByteArray(buffer, msg, pos, strlen(msg)); - *size = pos-16; - - return pos; -} - -int TFLCSSendByteArray(TFLCSLocalConnection_t* connection, const char* bytes, int len) -{ - ENSURE_CONNECTION_UP(connection, 0); - - if (NULL == bytes || 0 == len || !_TFLCSConnectionStructureIsValidForUse(connection)) { - TFLCSErrno = TFLCSErrorInvalidArgument; - return 0; - } - - _TFLCSLockSemaphore(connection); - - int pos = TFLCSWriteLCAMFEnvelopeHeader(connection); - pos = TFLCSWriteAMF3ByteArray(connection->data, bytes, pos, len); - (void)TFLCSWriteLCAMFEnvelopeTrailer(connection, pos); - - _TFLCSUnlockSemaphore(connection); - - return 1; -} - -void TFLCSDumpMemory(char* buffer, int offset, int size) -{ - int i = 0; - int c = 0; - char b; - - while (i < size) { - while ((c < 16) && (i+c < size)) { - b = buffer[offset+i+c]; - printf("%X%X ", b/16 & 0x0f, b & 0x0f ); - c++; - } - - while (c++ < 16) - printf(" "); - - c = 0; - - while ((c < 16) && (i+c < size)) { - b = buffer[offset+i+c]; - if (b > 31) - printf("%c", (char)b); - else - printf("."); - c++; - } - - i += 16; - c = 0; - printf("\n"); - } -} - -void _TFLCSLockSemaphore(TFLCSLocalConnection_t* connection) -{ - if (NULL != connection) { -#if defined(WIN32) - if (NULL != connection->semaphore) - WaitForSingleObject(connection->semaphore, INFINITE); -#else - if ((sem_t*)SEM_FAILED != connection->semaphore) - sem_wait(connection->semaphore); -#endif - } -} - -void _TFLCSUnlockSemaphore(TFLCSLocalConnection_t* connection) -{ - if (NULL != connection) { -#if defined(WIN32) - if (NULL != connection->semaphore) - ReleaseMutex(connection->semaphore); -#else - if ((sem_t*)SEM_FAILED != connection->semaphore) - sem_post(connection->semaphore); -#endif - } -} - -int _TFLCSConnectionStructureIsValidForUse(TFLCSLocalConnection_t* connection) -{ - return (NULL != connection - && 0 != connection->open -#if defined(WIN32) - && NULL != connection->semaphore - && NULL != connection->mapFile - && NULL != connection->mapAddress - && NULL != connection->data -#else - && (sem_t*)SEM_FAILED != connection->semaphore - && (char*)-1 != connection->data -#endif - ); -} - -int _TFLCSDelayedConnect(TFLCSLocalConnection_t* connection) -{ -#if defined(WIN32) - if (NULL == connection) - return 0; - if (connection->open) - return 1; - - if (NULL == (connection->semaphore = OpenMutex(MUTEX_ALL_ACCESS, - FALSE, - WIN32_SEMAPHORE_NAME))) { - TFLCSErrno = TFLCSErrorSemaphoreCreationFailed; - goto errorReturn; - } - - if (NULL == (connection->mapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, - FALSE, - WIN32_SHMEM_NAME))) { - TFLCSErrno = TFLCSErrorShmemIDNotFound; - goto errorReturn; - } - - if (NULL == (connection->mapAddress = MapViewOfFile(connection->mapFile, - FILE_MAP_ALL_ACCESS, - 0, - 0, - 0))) { - TFLCSErrno = TFLCSErrorShmemOpeningFailed; - goto errorReturn; - } - - connection->data = (char*)connection->mapAddress; - connection->open = 1; - -errorReturn: -#endif - - return connection->open; -} - - -/* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (c) 2005-2009 Martin Kaltenbrunner - - 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 - */ - -using namespace TUIO; - -FlashSender::FlashSender() { - local = true; - buffer_size = MAX_FLASH_SIZE; - lcConnection = TFLCSConnect(DEFAULT_LC_CONN_NAME,DEFAULT_LC_METH_NAME,NULL,NULL); -} - -FlashSender::FlashSender(const char *conn_name, const char *meth_name) { - local = true; - buffer_size = MAX_FLASH_SIZE; - lcConnection = TFLCSConnect(conn_name,meth_name,NULL,NULL); -} - -FlashSender::~FlashSender() { - TFLCSDisconnect(lcConnection); -} - -bool FlashSender::isConnected() { - return TFLCSConnectionHasConnectedClient(lcConnection); -} - -bool FlashSender::sendOscPacket (osc::OutboundPacketStream *bundle) { - if (!TFLCSConnectionHasConnectedClient(lcConnection))return false; - if ( bundle->Size() > buffer_size ) return false; - TFLCSSendByteArray(lcConnection, bundle->Data(), bundle->Size()); - return true; -} diff --git a/TUIO/FlashSender.h b/TUIO/FlashSender.h index 51335d1..7dd4684 100644 --- a/TUIO/FlashSender.h +++ b/TUIO/FlashSender.h @@ -20,7 +20,7 @@ // // You should have received a copy of the GNU Lesser General Public // License along with Touché. If not, see . -// + #if !defined(__TFFlashLCSHMEM_H__) #define __TFFlashLCSHMEM_H__ 1 @@ -32,10 +32,7 @@ extern "C" #ifdef WIN32 #include - - typedef DWORD u_int32_t; - - +typedef DWORD u_int32_t; #else #include #include @@ -140,25 +137,22 @@ extern "C" #endif //__TFFlashLCSHMEM_H__ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (c) 2005-2009 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - 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 library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_FLASHSENDER_H #define INCLUDED_FLASHSENDER_H @@ -175,7 +169,7 @@ namespace TUIO { * The FlashSender implements the Flash LocalConnection transport method for OSC * * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL FlashSender : public OscSender { @@ -194,7 +188,7 @@ namespace TUIO { /** * The destructor closes the connection. */ - ~FlashSender(); + virtual ~FlashSender(); /** * This method delivers the provided OSC data @@ -212,6 +206,8 @@ namespace TUIO { */ bool isConnected (); + const char* tuio_type() { return "TUIO/FLC"; } + private: TFLCSLocalConnection_t* lcConnection; }; diff --git a/TUIO/OneEuroFilter.cpp b/TUIO/OneEuroFilter.cpp new file mode 100644 index 0000000..213f317 --- /dev/null +++ b/TUIO/OneEuroFilter.cpp @@ -0,0 +1,65 @@ +/* reacTIVision tangible interaction framework + Copyright (C) 2005-2016 Martin Kaltenbrunner + Based on an example by Nicolas Roussel + + 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 "OneEuroFilter.h" + +using namespace TUIO; + +double LowPassFilter::filter(double value, double alpha) { + + if (alpha<=0.0 || alpha>1.0) + throw std::range_error("alpha should be in (0.0., 1.0]"); + + double result; + if (initialized) + result = alpha*value + (1.0-alpha)*lastResult; + else { + result = value; + initialized = true; + } + + lastRawValue = value; + lastResult = result; + return result; +} + +// ----------------------------------------------------------------- + +double OneEuroFilter::alpha(double cutoff) { + double te = 1.0 / freq; + double tau = 1.0 / (2*M_PI*cutoff); + return 1.0 / (1.0 + tau/te); +} + +double OneEuroFilter::filter(double value, TimeStamp timestamp) { + // update the sampling frequency based on timestamps + if (lasttime!=UndefinedTime && timestamp!=UndefinedTime) + freq = 1.0 / (timestamp-lasttime); + lasttime = timestamp; + // estimate the current variation per second + double dvalue = x->initialized ? (value - x->lastRawValue)*freq : value; + + double edvalue; + try { edvalue = dx->filter(dvalue, alpha(dcutoff)); + } catch (std::range_error e) { return value; } + // use it to update the cutoff frequency + double cutoff = mincutoff + beta*fabs(edvalue); + // filter the given value + return x->filter(value, alpha(cutoff)); +} \ No newline at end of file diff --git a/TUIO/OneEuroFilter.h b/TUIO/OneEuroFilter.h new file mode 100644 index 0000000..7fc4ee1 --- /dev/null +++ b/TUIO/OneEuroFilter.h @@ -0,0 +1,90 @@ +/* reacTIVision tangible interaction framework + Copyright (C) 2005-2016 Martin Kaltenbrunner + Based on an example by Nicolas Roussel + + 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 + */ + +#ifndef ONEEUROFILTER +#define ONEEUROFILTER + +#include +#include + +typedef double TimeStamp; // in seconds +static const TimeStamp UndefinedTime = -1.0; + +namespace TUIO { + + class LowPassFilter { + + public: + + bool initialized; + double lastRawValue,lastResult; + + LowPassFilter(double initval=0.0) { + + lastRawValue = lastResult = initval; + initialized = false; + } + + double filter(double value, double alpha); + }; + + // ----------------------------------------------------------------- + + class OneEuroFilter { + + double freq; + double mincutoff; + double beta; + double dcutoff; + LowPassFilter *x; + LowPassFilter *dx; + TimeStamp lasttime; + + double alpha(double cutoff); + + public: + + OneEuroFilter(double f, double mc=1.0, double b=0.0, double dc=1.0) { + + if (f<=0) throw std::range_error("freq should be >0"); + else freq = f; + if (mc<=0) throw std::range_error("mincutoff should be >0"); + else mincutoff = mc; + if (b<=0) throw std::range_error("beta should be >0"); + else beta = b; + if (dc<=0) throw std::range_error("dcutoff should be >0"); + else dcutoff = dc; + + x = new LowPassFilter(alpha(mincutoff)); + dx = new LowPassFilter(alpha(dcutoff)); + lasttime = UndefinedTime; + } + + ~OneEuroFilter(void) { + delete x; + delete dx; + } + + double filter(double value, TimeStamp timestamp=UndefinedTime); + + }; + +} + +#endif diff --git a/TUIO/OscReceiver.cpp b/TUIO/OscReceiver.cpp deleted file mode 100644 index 08059c4..0000000 --- a/TUIO/OscReceiver.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (c) 2005-2009 Martin Kaltenbrunner - - 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 "OscReceiver.h" - -using namespace TUIO; -using namespace osc; - -void OscReceiver::ProcessMessage( const ReceivedMessage& msg, const IpEndpointName& remoteEndpoint) { - for (std::list::iterator client=clientList.begin(); client!= clientList.end(); client++) - (*client)->processOSC(msg); -} -void OscReceiver::ProcessBundle( const ReceivedBundle& b, const IpEndpointName& remoteEndpoint) { - - try { - for( ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){ - if( i->IsBundle() ) - ProcessBundle( ReceivedBundle(*i), remoteEndpoint); - else - ProcessMessage( ReceivedMessage(*i), remoteEndpoint); - } - } catch (MalformedBundleException& e) { - std::cerr << "malformed OSC bundle: " << e.what() << std::endl; - } - -} - -void OscReceiver::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) { - try { - ReceivedPacket p( data, size ); - if(p.IsBundle()) ProcessBundle( ReceivedBundle(p), remoteEndpoint); - else ProcessMessage( ReceivedMessage(p), remoteEndpoint); - } catch (MalformedBundleException& e) { - std::cerr << "malformed OSC bundle: " << e.what() << std::endl; - } -} - -bool OscReceiver::isConnected() { - return connected; -} - -void OscReceiver::addTuioClient(TuioClient *client) { - clientList.push_back(client); -} - diff --git a/TUIO/OscReceiver.h b/TUIO/OscReceiver.h deleted file mode 100644 index e43bf93..0000000 --- a/TUIO/OscReceiver.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (c) 2005-2009 Martin Kaltenbrunner - - 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 - */ - -#ifndef INCLUDED_OSCRECEIVER_H -#define INCLUDED_OSCRECEIVER_H - -#include "LibExport.h" -#include "TuioClient.h" - -#include "osc/OscReceivedElements.h" -#include "ip/PacketListener.h" - -namespace TUIO { - - class TuioClient; // Forward declaration - - /** - * The OscReceiver is the base class for the various OSC transport methods such as UDP, TCP ... - * - * @author Martin Kaltenbrunner - * @version 1.5 - */ - class LIBDECL OscReceiver: public PacketListener { - - public: - - /** - * The constructor is doing nothing in particular. - */ - OscReceiver() : connected(false) {}; - - /** - * The destructor is doing nothing in particular. - */ - virtual ~OscReceiver() {}; - - /** - * The OscReceiver connects and starts receiving TUIO messages via OSC - * - * @param lock running in the background if set to false (default) - */ - virtual void connect(bool lock=false) = 0; - - /** - * The OscReceiver disconnects and stops receiving TUIO messages via OSC - */ - virtual void disconnect() = 0; - - /** - * Returns true if this OscReceiver is currently connected. - * @return true if this OscReceiver is currently connected - */ - bool isConnected(); - - /** - * Attaches the provided TuioClient to this OscReceiver - * - * @param client a pointer to the TuioClient to attach - */ - void addTuioClient(TuioClient *client); - - /** - * The OSC callback method where the incoming OSC data is received - * - * @param data the received OSC data - * @param size the size of the received OSC data - * @param remoteEndpoint the origin of the received OSC data - */ - void ProcessPacket( const char *data, int size, const IpEndpointName &remoteEndpoint ); - - protected: - void ProcessBundle( const osc::ReceivedBundle& b, const IpEndpointName& remoteEndpoint); - - void ProcessMessage( const osc::ReceivedMessage& message, const IpEndpointName& remoteEndpoint); - - std::list clientList; - bool connected; - }; -}; -#endif /* INCLUDED_OSCRECEIVER_H */ diff --git a/TUIO/OscSender.cpp b/TUIO/OscSender.cpp deleted file mode 100644 index 5339991..0000000 --- a/TUIO/OscSender.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (c) 2005-2009 Martin Kaltenbrunner - - 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 - */ - -#ifndef INCLUDED_OSCSENDER_H -#define INCLUDED_OSCSENDER_H - -#include "LibExport.h" -#include "osc/OscOutboundPacketStream.h" -#include "ip/NetworkingUtils.h" -#include -#include - -namespace TUIO { - - /** - * The OscSender class is the base class for the various OSC transport methods such as UDP, TCP ... - * - * @author Martin Kaltenbrunner - * @version 1.5 - */ - class LIBDECL OscSender { - - public: - - /** - * The constructor is doing nothing in particular. - */ - OscSender (): local(true) {}; - - /** - * The destructor is doing nothing in particular. - */ - virtual ~OscSender() {} - - /** - * This method delivers the provided OSC data - * - * @param *bundle the OSC stream to deliver - * @return true if the data was delivered successfully - */ - virtual bool sendOscPacket (osc::OutboundPacketStream *bundle) = 0; - - /** - * This method returns the connection state - * - * @return true if the connection is alive - */ - virtual bool isConnected () = 0; - - /** - * This method returns if this OscSender delivers locally - * - * @return true if this OscSender delivers locally - */ - bool isLocal () { return local; }; - - /** - * This method returns the maximum bundle size in bytes - * - * @return the maximum bundle size in bytes - */ - int getBufferSize () { return buffer_size; }; - - protected: - unsigned int buffer_size; - bool local; - }; -} -#endif /* INCLUDED_OSCSENDER_H */ diff --git a/TUIO/OscSender.h b/TUIO/OscSender.h index 5339991..b2693fd 100644 --- a/TUIO/OscSender.h +++ b/TUIO/OscSender.h @@ -1,29 +1,27 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_OSCSENDER_H #define INCLUDED_OSCSENDER_H #include "LibExport.h" #include "osc/OscOutboundPacketStream.h" +#include "osc/OscHostEndianness.h" #include "ip/NetworkingUtils.h" #include #include @@ -34,7 +32,7 @@ namespace TUIO { * The OscSender class is the base class for the various OSC transport methods such as UDP, TCP ... * * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL OscSender { @@ -47,7 +45,7 @@ namespace TUIO { /** * The destructor is doing nothing in particular. - */ + */ virtual ~OscSender() {} /** @@ -78,10 +76,15 @@ namespace TUIO { * @return the maximum bundle size in bytes */ int getBufferSize () { return buffer_size; }; + + virtual const char* tuio_type() = 0; protected: unsigned int buffer_size; bool local; }; } + + #endif /* INCLUDED_OSCSENDER_H */ + diff --git a/TUIO/TcpSender.cpp b/TUIO/TcpSender.cpp deleted file mode 100644 index dc5f957..0000000 --- a/TUIO/TcpSender.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (c) 2005-2009 Martin Kaltenbrunner - - 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 "TcpSender.h" - -#ifdef WIN32 -#ifndef int32_t -typedef DWORD int32_t; -#endif -#endif - -using namespace TUIO; - -#ifndef WIN32 -static void* ServerThreadFunc( void* obj ) -#else -static DWORD WINAPI ServerThreadFunc( LPVOID obj ) -#endif -{ - TcpSender *sender = static_cast(obj); - struct sockaddr_in tcp_client; - socklen_t len = sizeof(tcp_client); - char buf[16]; - - while (sender->tcp_socket) { - sender->tcp_client_connection = accept(sender->tcp_socket, (struct sockaddr*)&tcp_client, &len); - sender->connected=true; - - // test if connection is still alive - int connected = 1; - while (connected) { - connected = recv(sender->tcp_client_connection, buf, sizeof(buf),0); - } - sender->connected=false; - } - - return 0; -}; - -TcpSender::TcpSender() - :connected (false) -{ - local = true; - - tcp_socket = socket( AF_INET, SOCK_STREAM, 0 ); - if (tcp_socket < 0) std::cerr << "could not create socket" << std::endl; - - struct sockaddr_in tcp_server; - memset( &tcp_server, 0, sizeof (tcp_server)); - unsigned long addr = inet_addr("127.0.0.1"); - memcpy( (char *)&tcp_server.sin_addr, &addr, sizeof(addr)); - - tcp_server.sin_family = AF_INET; - tcp_server.sin_port = htons(3333); - - int ret = connect(tcp_client_connection,(struct sockaddr*)&tcp_server,sizeof(tcp_server)); - if (ret<0) std::cerr << "could not connect to server" << std::endl; - - buffer_size = MAX_TCP_SIZE; -} - -TcpSender::TcpSender(const char *host, int port) - :connected (false) -{ - if ((strcmp(host,"127.0.0.1")==0) || (strcmp(host,"localhost")==0)) { - local = true; - } else local = false; - - tcp_socket = socket( AF_INET, SOCK_STREAM, 0 ); - if (tcp_socket < 0) std::cerr << "could not create socket" << std::endl; - - struct sockaddr_in tcp_server; - memset( &tcp_server, 0, sizeof (tcp_server)); - unsigned long addr = inet_addr(host); - if (addr != INADDR_NONE) { - memcpy( (char *)&tcp_server.sin_addr, &addr, sizeof(addr)); - } else { - struct hostent *host_info = gethostbyname(host); - if (host_info == NULL) std::cerr << "unknown host name" << std::endl; - memcpy( (char *)&tcp_server.sin_addr, host_info->h_addr, host_info->h_length ); - } - - tcp_server.sin_family = AF_INET; - tcp_server.sin_port = htons(port); - - int ret = connect(tcp_client_connection,(struct sockaddr*)&tcp_server,sizeof(tcp_server)); - if (ret<0) std::cerr << "could not connect to server" << std::endl; - - buffer_size = MAX_TCP_SIZE; -} - -TcpSender::TcpSender(int port) - :connected (false) -{ - local = false; - - tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (tcp_socket < 0) std::cerr << "could not create socket" << std::endl; - - int optval = 1; - #ifdef WIN32 - int ret = setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR, (const char *)&optval, sizeof(int)); - #else - int ret = setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR, (const void *)&optval, sizeof(int)); - #endif - if (ret < 0) std::cerr << "could not reuse socket address" << std::endl; - - struct sockaddr_in tcp_server; - memset( &tcp_server, 0, sizeof (tcp_server)); - - tcp_server.sin_family = AF_INET; - tcp_server.sin_addr.s_addr = htonl(INADDR_ANY); - tcp_server.sin_port = htons(port); - - socklen_t len = sizeof(tcp_server); - ret = bind(tcp_socket,(struct sockaddr*)&tcp_server,len); - if (ret < 0) std::cerr << "could not bind to socket" << std::endl; - - ret = listen(tcp_socket, 1); - if (ret < 0) std::cerr << "could not listen to socket" << std::endl; - -#ifndef WIN32 - pthread_create(&server_thread , NULL, ServerThreadFunc, this); -#else - DWORD threadId; - server_thread = CreateThread( 0, 0, ServerThreadFunc, this, 0, &threadId ); -#endif - - buffer_size = MAX_TCP_SIZE; -} - -TcpSender::~TcpSender() { -#ifdef WIN32 - closesocket(tcp_client_connection); - closesocket(tcp_socket); - if( server_thread ) CloseHandle( server_thread ); -#else - close(tcp_client_connection); - close(tcp_socket); - server_thread = 0; -#endif -} - - -bool TcpSender::isConnected() { - return connected; -} - -bool TcpSender::sendOscPacket (osc::OutboundPacketStream *bundle) { - if (!connected) return false; - if ( bundle->Size() > buffer_size ) return false; - -#ifdef OSC_HOST_LITTLE_ENDIAN - data_size[0] = bundle->Size()>>24; - data_size[1] = (bundle->Size()>>16) & 255; - data_size[2] = (bundle->Size()>>8) & 255; - data_size[3] = (bundle->Size()) & 255; -#else - *((int32_t*)data_size) = bundle->Size(); -#endif - - send(tcp_client_connection,data_size, 4,0); - send(tcp_client_connection, bundle->Data(), bundle->Size(),0); - - return true; -} diff --git a/TUIO/TcpSender.h b/TUIO/TcpSender.h index f390163..acef5ab 100644 --- a/TUIO/TcpSender.h +++ b/TUIO/TcpSender.h @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TCPSENDER_H #define INCLUDED_TCPSENDER_H @@ -37,6 +34,7 @@ typedef int socklen_t; #include #endif +#include #define MAX_TCP_SIZE 65536 namespace TUIO { @@ -45,7 +43,7 @@ namespace TUIO { * The TcpSender implements the TCP transport method for OSC * * @author Martin Kaltenbrunner - * @version 1.5 + * @version 2.0.a0 */ class LIBDECL TcpSender : public OscSender { @@ -67,14 +65,14 @@ namespace TUIO { /** * This constructor creates a TcpSender that listens to the provided port * - * @param port the incoming TUIO TCP port number + * @param port the incoming TUIO TCP port number */ TcpSender(int port); /** * The destructor closes the socket. */ - ~TcpSender(); + virtual ~TcpSender(); /** * This method delivers the provided OSC data @@ -92,20 +90,33 @@ namespace TUIO { */ bool isConnected (); + /** + * This method is called whenever a new client connects + * + * @param tcp_client the socket handle of the new client + */ + virtual void newClient( int tcp_client ); + + int port_no; #ifdef WIN32 - SOCKET tcp_socket, tcp_client_connection; + SOCKET tcp_socket; + std::list tcp_client_list; #else - int tcp_socket, tcp_client_connection; + int tcp_socket; + std::list tcp_client_list; #endif - bool connected; - private: + const char* tuio_type() { return "TUIO/TCP"; } + + protected: char data_size[4]; + char data_buffer[MAX_TCP_SIZE+4]; #ifdef WIN32 HANDLE server_thread; + DWORD ServerThreadId; #else pthread_t server_thread; #endif diff --git a/TUIO/TuioBlob.cpp b/TUIO/TuioBlob.cpp index ccad812..124603f 100644 --- a/TUIO/TuioBlob.cpp +++ b/TUIO/TuioBlob.cpp @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #include "TuioBlob.h" using namespace TUIO; @@ -25,40 +22,66 @@ using namespace TUIO; TuioBlob::TuioBlob (TuioTime ttime, long si, int bi, float xp, float yp, float a, float w, float h, float f):TuioContainer(ttime, si, xp, yp) { blob_id = bi; angle = a; + angle_sum = a; width = w; height = h; area = f; rotation_speed = 0.0f; rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; + widthFilter = NULL; + heightFilter = NULL; + sizeThreshold = 0.0f; } TuioBlob::TuioBlob (long si, int bi, float xp, float yp, float a, float w, float h, float f):TuioContainer(si, xp, yp) { blob_id = bi; angle = a; + angle_sum = a; width = w; height = h; area = f; rotation_speed = 0.0f; rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; + widthFilter = NULL; + heightFilter = NULL; + sizeThreshold = 0.0f; } TuioBlob::TuioBlob (TuioBlob *tblb):TuioContainer(tblb) { blob_id = tblb->getBlobID(); angle = tblb->getAngle(); + angle_sum = tblb->getAngleSum(); width = tblb->getWidth(); height = tblb->getHeight(); area = tblb->getArea(); rotation_speed = 0.0f; rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; + widthFilter = NULL; + heightFilter = NULL; + sizeThreshold = 0.0f; } int TuioBlob::getBlobID() const{ return blob_id; } +void TuioBlob::setBlobID(long b_id) { + blob_id = b_id; +} + void TuioBlob::update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra) { TuioContainer::update(ttime,xp,yp,xs,ys,ma); angle = a; + angle_sum = a; width = w; height = h; area = f; @@ -70,6 +93,7 @@ void TuioBlob::update (TuioTime ttime, float xp, float yp, float a, float w, flo void TuioBlob::update (float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra) { TuioContainer::update(xp,yp,xs,ys,ma); angle = a; + angle_sum = a; width = w; height = h; area = f; @@ -84,16 +108,36 @@ void TuioBlob::update (TuioTime ttime, float xp, float yp, float a, float w, flo TuioTime diffTime = currentTime - lastPoint.getTuioTime(); float dt = diffTime.getTotalMilliseconds()/1000.0f; - float last_angle = angle; float last_rotation_speed = rotation_speed; - angle = a; - double da = (angle-last_angle)/(2*M_PI); + float prev_angle = angle_sum; + float da = a-angle; + if (da > M_PI/2.0f) angle_sum += (da-2*M_PI); + else if (da < M_PI/-2.0f) angle_sum += (da+2*M_PI); + else angle_sum += da; + + if (angleFilter) angle_sum = angleFilter->filter(angle_sum,dt); + if (fabs(angle_sum-prev_angle) 0.75f) da-=1.0f; else if (da < -0.75f) da+=1.0f; - width = w; - height = h; + if (widthFilter && heightFilter) { + w = widthFilter->filter(w,dt); + h = heightFilter->filter(h,dt); + } + + float dw = fabs(width - w); + float dh = fabs(height - h); + if ((dw>sizeThreshold) || (dh>sizeThreshold)) { + width = w; + height = h; + } + area = f; rotation_speed = (float)da/dt; @@ -109,6 +153,7 @@ void TuioBlob::stop (TuioTime ttime) { void TuioBlob::update (TuioBlob *tblb) { TuioContainer::update(tblb); angle = tblb->getAngle(); + angle = tblb->getAngleSum(); width = tblb->getWidth(); height = tblb->getHeight(); area = tblb->getArea(); @@ -141,6 +186,10 @@ float TuioBlob::getAngle() const{ return angle; } +float TuioBlob::getAngleSum() const{ + return angle_sum; +} + float TuioBlob::getAngleDegrees() const{ return (float)(angle/M_PI*180); } @@ -157,3 +206,48 @@ bool TuioBlob::isMoving() const{ if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING) || (state==TUIO_ROTATING)) return true; else return false; } + +void TuioBlob::addAngleThreshold(float thresh) { + angleThreshold = thresh; +} + +void TuioBlob::removeAngleThreshold() { + angleThreshold = 0.0f; +} + +void TuioBlob::addAngleFilter(float mcut, float beta) { + + if (angleFilter) delete angleFilter; + angleFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); +} + +void TuioBlob::removeAngleFilter() { + + if (angleFilter) delete angleFilter; + angleFilter = NULL; +} + +void TuioBlob::addSizeThreshold(float thresh) { + sizeThreshold = thresh; +} + +void TuioBlob::removeSizeThreshold() { + sizeThreshold = 0.0f; +} + +void TuioBlob::addSizeFilter(float mcut, float beta) { + + if (widthFilter) delete widthFilter; + widthFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); + if (heightFilter) delete heightFilter; + heightFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); +} + +void TuioBlob::removeSizeFilter() { + + if (widthFilter) delete widthFilter; + widthFilter = NULL; + if (heightFilter) delete heightFilter; + heightFilter = NULL; +} + diff --git a/TUIO/TuioBlob.h b/TUIO/TuioBlob.h index af88451..3301e8c 100644 --- a/TUIO/TuioBlob.h +++ b/TUIO/TuioBlob.h @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TUIOBLOB_H #define INCLUDED_TUIOBLOB_H @@ -30,7 +27,7 @@ namespace TUIO { * The TuioBlob class encapsulates /tuio/2Dblb TUIO objects. * * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL TuioBlob: public TuioContainer { @@ -43,6 +40,10 @@ namespace TUIO { * The rotation angle value. */ float angle; + /** + * The accumulated angle value. + */ + float angle_sum; /** * The width value. */ @@ -64,9 +65,15 @@ namespace TUIO { */ float rotation_accel; + float angleThreshold; + OneEuroFilter *angleFilter; + float sizeThreshold; + OneEuroFilter *widthFilter; + OneEuroFilter *heightFilter; + public: using TuioContainer::update; - + /** * This constructor takes a TuioTime argument and assigns it along with the provided * Session ID, X and Y coordinate, width, height and angle to the newly created TuioBlob. @@ -107,7 +114,11 @@ namespace TUIO { /** * The destructor is doing nothing in particular. */ - ~TuioBlob() {}; + virtual ~TuioBlob() { + if (widthFilter) delete widthFilter; + if (heightFilter) delete heightFilter; + if (angleFilter) delete angleFilter; + }; /** * Returns the Blob ID of this TuioBlob. @@ -115,6 +126,12 @@ namespace TUIO { */ int getBlobID() const; + /** + * Sets the Blob ID of this TuioBlob. + * @param b_id the new Blob ID for this TuioBlob + */ + void setBlobID(long b_id); + /** * Takes a TuioTime argument and assigns it along with the provided * X and Y coordinate, angle, X and Y velocity, motion acceleration, @@ -220,6 +237,12 @@ namespace TUIO { */ float getAngle() const; + /** + * Returns the accumulated rotation angle of this TuioBlob. + * @return the accumulated rotation angle of this TuioBlob + */ + float getAngleSum() const; + /** * Returns the rotation angle in degrees of this TuioBlob. * @return the rotation angle in degrees of this TuioBlob @@ -243,6 +266,22 @@ namespace TUIO { * @return true of this TuioBlob is moving */ bool isMoving() const; + + void addAngleThreshold(float thresh); + + void removeAngleThreshold(); + + void addAngleFilter(float mcut, float beta); + + void removeAngleFilter(); + + void addSizeThreshold(float thresh); + + void removeSizeThreshold(); + + void addSizeFilter(float mcut, float beta); + + void removeSizeFilter(); }; } #endif diff --git a/TUIO/TuioClient.cpp b/TUIO/TuioClient.cpp deleted file mode 100644 index 48ad7af..0000000 --- a/TUIO/TuioClient.cpp +++ /dev/null @@ -1,852 +0,0 @@ -/* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (c) 2005-2009 Martin Kaltenbrunner - - 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 "TuioClient.h" -#include "UdpReceiver.h" - -using namespace TUIO; -using namespace osc; - - -TuioClient::TuioClient() -: currentFrame (-1) -, source_id (0) -, source_name (NULL) -, source_addr (NULL) -, local_receiver(true) -{ - receiver = new UdpReceiver(); - initialize(); -} - -TuioClient::TuioClient(int port) -: currentFrame (-1) -, source_id (0) -, source_name (NULL) -, source_addr (NULL) -, local_receiver(true) -{ - receiver = new UdpReceiver(port); - initialize(); -} - -TuioClient::TuioClient(OscReceiver *osc) -: currentFrame (-1) -, source_id (0) -, source_name (NULL) -, source_addr (NULL) -, receiver (osc) -, local_receiver(false) -{ - initialize(); -} - -void TuioClient::initialize() { - receiver->addTuioClient(this); - maxCursorID[source_id] = -1; - maxBlobID[source_id] = -1; -} - -TuioClient::~TuioClient() { - if (local_receiver) delete receiver; -} - -void TuioClient::processOSC( const ReceivedMessage& msg ) { - try { - ReceivedMessageArgumentStream args = msg.ArgumentStream(); - ReceivedMessage::const_iterator arg = msg.ArgumentsBegin(); - - if( strcmp( msg.AddressPattern(), "/tuio/2Dobj" ) == 0 ){ - - const char* cmd; - args >> cmd; - - if (strcmp(cmd,"source")==0) { - const char* src; - args >> src; - - source_name = strtok((char*)src, "@"); - char *addr = strtok(NULL, "@"); - - if (addr!=NULL) source_addr = addr; - else source_addr = (char*)"localhost"; - - // check if we know that source - std::string source_str(src); - std::map::iterator iter = sourceList.find(source_str); - - // add a new source - if (iter==sourceList.end()) { - source_id = sourceList.size(); - sourceList[source_str] = source_id; - } else { - // use the found source_id - source_id = sourceList[source_str]; - } - - } else if (strcmp(cmd,"set")==0) { - int32 s_id, c_id; - float xpos, ypos, angle, xspeed, yspeed, rspeed, maccel, raccel; - args >> s_id >> c_id >> xpos >> ypos >> angle >> xspeed >> yspeed >> rspeed >> maccel >> raccel; - - lockObjectList(); - std::list::iterator tobj; - for (tobj=objectList.begin(); tobj!= objectList.end(); tobj++) - if((*tobj)->getSessionID()==(long)s_id) break; - - if (tobj == objectList.end()) { - - TuioObject *addObject = new TuioObject((long)s_id,(int)c_id,xpos,ypos,angle); - frameObjects.push_back(addObject); - - } else if ( ((*tobj)->getX()!=xpos) || ((*tobj)->getY()!=ypos) || ((*tobj)->getAngle()!=angle) || ((*tobj)->getXSpeed()!=xspeed) || ((*tobj)->getYSpeed()!=yspeed) || ((*tobj)->getRotationSpeed()!=rspeed) || ((*tobj)->getMotionAccel()!=maccel) || ((*tobj)->getRotationAccel()!=raccel) ) { - - TuioObject *updateObject = new TuioObject((long)s_id,(*tobj)->getSymbolID(),xpos,ypos,angle); - updateObject->update(xpos,ypos,angle,xspeed,yspeed,rspeed,maccel,raccel); - frameObjects.push_back(updateObject); - - } - unlockObjectList(); - - } else if (strcmp(cmd,"alive")==0) { - - int32 s_id; - aliveObjectList.clear(); - while(!args.Eos()) { - args >> s_id; - aliveObjectList.push_back((long)s_id); - } - - } else if (strcmp(cmd,"fseq")==0) { - - int32 fseq; - args >> fseq; - bool lateFrame = false; - if (fseq>0) { - if (fseq>currentFrame) currentTime = TuioTime::getSessionTime(); - if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq; - else lateFrame = true; - } else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) { - currentTime = TuioTime::getSessionTime(); - } - - if (!lateFrame) { - - lockObjectList(); - //find the removed objects first - for (std::list::iterator tobj=objectList.begin(); tobj != objectList.end(); tobj++) { - if ((*tobj)->getTuioSourceID()==source_id) { - std::list::iterator iter = find(aliveObjectList.begin(), aliveObjectList.end(), (*tobj)->getSessionID()); - if (iter == aliveObjectList.end()) { - (*tobj)->remove(currentTime); - frameObjects.push_back(*tobj); - } - } - } - unlockObjectList(); - - for (std::list::iterator iter=frameObjects.begin(); iter != frameObjects.end(); iter++) { - TuioObject *tobj = (*iter); - - TuioObject *frameObject = NULL; - switch (tobj->getTuioState()) { - case TUIO_REMOVED: - - frameObject = tobj; - frameObject->remove(currentTime); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->removeTuioObject(frameObject); - - lockObjectList(); - for (std::list::iterator delobj=objectList.begin(); delobj!=objectList.end(); delobj++) { - if((*delobj)->getSessionID()==frameObject->getSessionID()) { - objectList.erase(delobj); - break; - } - } - unlockObjectList(); - break; - case TUIO_ADDED: - - lockObjectList(); - frameObject = new TuioObject(currentTime,tobj->getSessionID(),tobj->getSymbolID(),tobj->getX(),tobj->getY(),tobj->getAngle()); - if (source_name) frameObject->setTuioSource(source_id,source_name,source_addr); - objectList.push_back(frameObject); - unlockObjectList(); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->addTuioObject(frameObject); - - break; - default: - - lockObjectList(); - std::list::iterator iter; - for (iter=objectList.begin(); iter != objectList.end(); iter++) { - if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getSessionID()==tobj->getSessionID())) { - frameObject = (*iter); - break; - } - } - - if (iter==objectList.end()) { - unlockObjectList(); - break; - } - - if ( (tobj->getX()!=frameObject->getX() && tobj->getXSpeed()==0) || (tobj->getY()!=frameObject->getY() && tobj->getYSpeed()==0) ) - frameObject->update(currentTime,tobj->getX(),tobj->getY(),tobj->getAngle()); - else - frameObject->update(currentTime,tobj->getX(),tobj->getY(),tobj->getAngle(),tobj->getXSpeed(),tobj->getYSpeed(),tobj->getRotationSpeed(),tobj->getMotionAccel(),tobj->getRotationAccel()); - - unlockObjectList(); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->updateTuioObject(frameObject); - } - delete tobj; - } - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->refresh(currentTime); - - } else { - for (std::list::iterator iter=frameObjects.begin(); iter != frameObjects.end(); iter++) { - TuioObject *tobj = (*iter); - delete tobj; - } - } - - frameObjects.clear(); - } - } else if( strcmp( msg.AddressPattern(), "/tuio/2Dcur" ) == 0 ) { - const char* cmd; - args >> cmd; - - if (strcmp(cmd,"source")==0) { - const char* src; - args >> src; - - source_name = strtok((char*)src, "@"); - char *addr = strtok(NULL, "@"); - - if (addr!=NULL) source_addr = addr; - else source_addr = (char*)"localhost"; - - // check if we know that source - std::string source_str(src); - std::map::iterator iter = sourceList.find(source_str); - - // add a new source - if (iter==sourceList.end()) { - source_id = sourceList.size(); - sourceList[source_str] = source_id; - maxCursorID[source_id] = -1; - } else { - // use the found source_id - source_id = sourceList[source_str]; - } - - } else if (strcmp(cmd,"set")==0) { - - int32 s_id; - float xpos, ypos, xspeed, yspeed, maccel; - args >> s_id >> xpos >> ypos >> xspeed >> yspeed >> maccel; - - lockCursorList(); - std::list::iterator tcur; - for (tcur=cursorList.begin(); tcur!= cursorList.end(); tcur++) - if (((*tcur)->getSessionID()==(long)s_id) && ((*tcur)->getTuioSourceID()==source_id)) break; - - if (tcur==cursorList.end()) { - - TuioCursor *addCursor = new TuioCursor((long)s_id,-1,xpos,ypos); - frameCursors.push_back(addCursor); - - } else if ( ((*tcur)->getX()!=xpos) || ((*tcur)->getY()!=ypos) || ((*tcur)->getXSpeed()!=xspeed) || ((*tcur)->getYSpeed()!=yspeed) || ((*tcur)->getMotionAccel()!=maccel) ) { - - TuioCursor *updateCursor = new TuioCursor((long)s_id,(*tcur)->getCursorID(),xpos,ypos); - updateCursor->update(xpos,ypos,xspeed,yspeed,maccel); - frameCursors.push_back(updateCursor); - - } - unlockCursorList(); - - } else if (strcmp(cmd,"alive")==0) { - - int32 s_id; - aliveCursorList.clear(); - while(!args.Eos()) { - args >> s_id; - aliveCursorList.push_back((long)s_id); - } - - } else if( strcmp( cmd, "fseq" ) == 0 ) { - int32 fseq; - args >> fseq; - bool lateFrame = false; - if (fseq>0) { - if (fseq>currentFrame) currentTime = TuioTime::getSessionTime(); - if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq; - else lateFrame = true; - } else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) { - currentTime = TuioTime::getSessionTime(); - } - - if (!lateFrame) { - - lockCursorList(); - // find the removed cursors first - for (std::list::iterator tcur=cursorList.begin(); tcur != cursorList.end(); tcur++) { - if ((*tcur)->getTuioSourceID()==source_id) { - std::list::iterator iter = find(aliveCursorList.begin(), aliveCursorList.end(), (*tcur)->getSessionID()); - - if (iter == aliveCursorList.end()) { - (*tcur)->remove(currentTime); - frameCursors.push_back(*tcur); - } - } - } - unlockCursorList(); - - for (std::list::iterator iter=frameCursors.begin(); iter != frameCursors.end(); iter++) { - TuioCursor *tcur = (*iter); - - int c_id = 0; - int free_size = 0; - TuioCursor *frameCursor = NULL; - switch (tcur->getTuioState()) { - case TUIO_REMOVED: - - frameCursor = tcur; - frameCursor->remove(currentTime); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->removeTuioCursor(frameCursor); - - lockCursorList(); - for (std::list::iterator delcur=cursorList.begin(); delcur!=cursorList.end(); delcur++) { - if(((*delcur)->getTuioSourceID()==source_id) && ((*delcur)->getSessionID()==frameCursor->getSessionID())) { - cursorList.erase(delcur); - break; - } - } - - if (frameCursor->getCursorID()==maxCursorID[source_id]) { - maxCursorID[source_id] = -1; - delete frameCursor; - - if (cursorList.size()>0) { - std::list::iterator clist; - for (clist=cursorList.begin(); clist != cursorList.end(); clist++) { - if ((*clist)->getTuioSourceID()==source_id) { - c_id = (*clist)->getCursorID(); - if (c_id>maxCursorID[source_id]) maxCursorID[source_id]=c_id; - } - } - - freeCursorBuffer.clear(); - for (std::list::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) { - TuioCursor *freeCursor = (*flist); - if (freeCursor->getTuioSourceID()==source_id) { - if (freeCursor->getCursorID()>maxCursorID[source_id]) delete freeCursor; - else freeCursorBuffer.push_back(freeCursor); - } else freeCursorBuffer.push_back(freeCursor); - } - freeCursorList = freeCursorBuffer; - - } else { - freeCursorBuffer.clear(); - for (std::list::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) { - TuioCursor *freeCursor = (*flist); - if (freeCursor->getTuioSourceID()==source_id) delete freeCursor; - else freeCursorBuffer.push_back(freeCursor); - } - freeCursorList = freeCursorBuffer; - - } - } else if (frameCursor->getCursorID()::iterator iter = cursorList.begin();iter!= cursorList.end(); iter++) - if ((*iter)->getTuioSourceID()==source_id) c_id++; - - for(std::list::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) - if ((*iter)->getTuioSourceID()==source_id) free_size++; - - if ((free_size<=maxCursorID[source_id]) && (free_size>0)) { - std::list::iterator closestCursor = freeCursorList.begin(); - - for(std::list::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) { - if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getDistance(tcur)<(*closestCursor)->getDistance(tcur))) closestCursor = iter; - } - - if (closestCursor!=freeCursorList.end()) { - TuioCursor *freeCursor = (*closestCursor); - c_id = freeCursor->getCursorID(); - freeCursorList.erase(closestCursor); - delete freeCursor; - } - } else maxCursorID[source_id] = c_id; - - frameCursor = new TuioCursor(currentTime,tcur->getSessionID(),c_id,tcur->getX(),tcur->getY()); - if (source_name) frameCursor->setTuioSource(source_id,source_name,source_addr); - cursorList.push_back(frameCursor); - - delete tcur; - unlockCursorList(); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->addTuioCursor(frameCursor); - - break; - default: - - lockCursorList(); - std::list::iterator iter; - for (iter=cursorList.begin(); iter != cursorList.end(); iter++) { - if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getSessionID()==tcur->getSessionID())) { - frameCursor = (*iter); - break; - } - } - - if (iter==cursorList.end()) { - unlockCursorList(); - break; - } - - if ( (tcur->getX()!=frameCursor->getX() && tcur->getXSpeed()==0) || (tcur->getY()!=frameCursor->getY() && tcur->getYSpeed()==0) ) - frameCursor->update(currentTime,tcur->getX(),tcur->getY()); - else - frameCursor->update(currentTime,tcur->getX(),tcur->getY(),tcur->getXSpeed(),tcur->getYSpeed(),tcur->getMotionAccel()); - - delete tcur; - unlockCursorList(); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->updateTuioCursor(frameCursor); - - } - } - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->refresh(currentTime); - - } else { - for (std::list::iterator iter=frameCursors.begin(); iter != frameCursors.end(); iter++) { - TuioCursor *tcur = (*iter); - delete tcur; - } - } - - frameCursors.clear(); - } - } else if( strcmp( msg.AddressPattern(), "/tuio/2Dblb" ) == 0 ){ - const char* cmd; - args >> cmd; - - if (strcmp(cmd,"source")==0) { - const char* src; - args >> src; - - source_name = strtok((char*)src, "@"); - char *addr = strtok(NULL, "@"); - - if (addr!=NULL) source_addr = addr; - else source_addr = (char*)"localhost"; - - // check if we know that source - std::string source_str(src); - std::map::iterator iter = sourceList.find(source_str); - - // add a new source - if (iter==sourceList.end()) { - source_id = sourceList.size(); - sourceList[source_str] = source_id; - maxBlobID[source_id] = -1; - } else { - // use the found source_id - source_id = sourceList[source_str]; - } - - } else if (strcmp(cmd,"set")==0) { - - int32 s_id; - float xpos, ypos, angle, width, height, area, xspeed, yspeed, rspeed, maccel, raccel; - args >> s_id >> xpos >> ypos >> angle >> width >> height >> area >> xspeed >> yspeed >> rspeed >> maccel >> raccel; - - lockBlobList(); - std::list::iterator tblb; - for (tblb=blobList.begin(); tblb!= blobList.end(); tblb++) - if((*tblb)->getSessionID()==(long)s_id) break; - - if (tblb==blobList.end()) { - - TuioBlob *addBlob = new TuioBlob((long)s_id,-1,xpos,ypos,angle,width,height,area); - frameBlobs.push_back(addBlob); - - } else if ( ((*tblb)->getX()!=xpos) || ((*tblb)->getY()!=ypos) || ((*tblb)->getAngle()!=angle) || ((*tblb)->getWidth()!=width) || ((*tblb)->getHeight()!=height) || ((*tblb)->getArea()!=area) || ((*tblb)->getXSpeed()!=xspeed) || ((*tblb)->getYSpeed()!=yspeed) || ((*tblb)->getMotionAccel()!=maccel) ) { - - TuioBlob *updateBlob = new TuioBlob((long)s_id,(*tblb)->getBlobID(),xpos,ypos,angle,width,height,area); - updateBlob->update(xpos,ypos,angle,width,height,area,xspeed,yspeed,rspeed,maccel,raccel); - frameBlobs.push_back(updateBlob); - } - unlockBlobList(); - - } else if (strcmp(cmd,"alive")==0) { - - int32 s_id; - aliveBlobList.clear(); - while(!args.Eos()) { - args >> s_id; - aliveBlobList.push_back((long)s_id); - } - - } else if( strcmp( cmd, "fseq" ) == 0 ) { - - int32 fseq; - args >> fseq; - bool lateFrame = false; - if (fseq>0) { - if (fseq>currentFrame) currentTime = TuioTime::getSessionTime(); - if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq; - else lateFrame = true; - } else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) { - currentTime = TuioTime::getSessionTime(); - } - - if (!lateFrame) { - - lockBlobList(); - // find the removed blobs first - for (std::list::iterator tblb=blobList.begin(); tblb != blobList.end(); tblb++) { - if ((*tblb)->getTuioSourceID()==source_id) { - std::list::iterator iter = find(aliveBlobList.begin(), aliveBlobList.end(), (*tblb)->getSessionID()); - - if (iter == aliveBlobList.end()) { - (*tblb)->remove(currentTime); - frameBlobs.push_back(*tblb); - } - } - } - unlockBlobList(); - - for (std::list::iterator iter=frameBlobs.begin(); iter != frameBlobs.end(); iter++) { - TuioBlob *tblb = (*iter); - - int b_id = 0; - int free_size = 0; - TuioBlob *frameBlob = NULL; - switch (tblb->getTuioState()) { - case TUIO_REMOVED: - frameBlob = tblb; - frameBlob->remove(currentTime); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->removeTuioBlob(frameBlob); - - lockBlobList(); - for (std::list::iterator delblb=blobList.begin(); delblb!=blobList.end(); delblb++) { - if(((*delblb)->getTuioSourceID()==source_id) && ((*delblb)->getSessionID()==frameBlob->getSessionID())) { - blobList.erase(delblb); - break; - } - } - - if (frameBlob->getBlobID()==maxBlobID[source_id]) { - maxBlobID[source_id] = -1; - delete frameBlob; - - if (blobList.size()>0) { - std::list::iterator clist; - for (clist=blobList.begin(); clist != blobList.end(); clist++) { - if ((*clist)->getTuioSourceID()==source_id) { - b_id = (*clist)->getBlobID(); - if (b_id>maxBlobID[source_id]) maxBlobID[source_id]=b_id; - } - } - - freeBlobBuffer.clear(); - for (std::list::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) { - TuioBlob *freeBlob = (*flist); - if (freeBlob->getTuioSourceID()==source_id) { - if (freeBlob->getBlobID()>maxBlobID[source_id]) delete freeBlob; - else freeBlobBuffer.push_back(freeBlob); - } else freeBlobBuffer.push_back(freeBlob); - } - freeBlobList = freeBlobBuffer; - - } else { - freeBlobBuffer.clear(); - for (std::list::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) { - TuioBlob *freeBlob = (*flist); - if (freeBlob->getTuioSourceID()==source_id) delete freeBlob; - else freeBlobBuffer.push_back(freeBlob); - } - freeBlobList = freeBlobBuffer; - - } - } else if (frameBlob->getBlobID()::iterator iter = blobList.begin();iter!= blobList.end(); iter++) - if ((*iter)->getTuioSourceID()==source_id) b_id++; - - for(std::list::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) - if ((*iter)->getTuioSourceID()==source_id) free_size++; - - if ((free_size<=maxBlobID[source_id]) && (free_size>0)) { - std::list::iterator closestBlob = freeBlobList.begin(); - - for(std::list::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) { - if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getDistance(tblb)<(*closestBlob)->getDistance(tblb))) closestBlob = iter; - } - - if (closestBlob!=freeBlobList.end()) { - TuioBlob *freeBlob = (*closestBlob); - b_id = freeBlob->getBlobID(); - freeBlobList.erase(closestBlob); - delete freeBlob; - } - } else maxBlobID[source_id] = b_id; - - frameBlob = new TuioBlob(currentTime,tblb->getSessionID(),b_id,tblb->getX(),tblb->getY(),tblb->getAngle(),tblb->getWidth(),tblb->getHeight(),tblb->getArea()); - if (source_name) frameBlob->setTuioSource(source_id,source_name,source_addr); - blobList.push_back(frameBlob); - - delete tblb; - unlockBlobList(); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->addTuioBlob(frameBlob); - - break; - default: - - lockBlobList(); - std::list::iterator iter; - for (iter=blobList.begin(); iter != blobList.end(); iter++) { - if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getSessionID()==tblb->getSessionID())) { - frameBlob = (*iter); - break; - } - } - - if (iter==blobList.end()) { - unlockBlobList(); - break; - } - - if ( (tblb->getX()!=frameBlob->getX() && tblb->getXSpeed()==0) || (tblb->getY()!=frameBlob->getY() && tblb->getYSpeed()==0) || (tblb->getAngle()!=frameBlob->getAngle() && tblb->getRotationSpeed()==0) ) - frameBlob->update(currentTime,tblb->getX(),tblb->getY(),tblb->getAngle(),tblb->getWidth(),tblb->getHeight(),tblb->getArea()); - else - frameBlob->update(currentTime,tblb->getX(),tblb->getY(),tblb->getAngle(),tblb->getWidth(),tblb->getHeight(),tblb->getArea(),tblb->getXSpeed(),tblb->getYSpeed(),tblb->getRotationSpeed(),tblb->getMotionAccel(),tblb->getRotationAccel()); - - delete tblb; - unlockBlobList(); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->updateTuioBlob(frameBlob); - } - } - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->refresh(currentTime); - - } else { - for (std::list::iterator iter=frameBlobs.begin(); iter != frameBlobs.end(); iter++) { - TuioBlob *tblb = (*iter); - delete tblb; - } - } - - frameBlobs.clear(); - } - } - } catch( Exception& e ){ - std::cerr << "error parsing TUIO message: "<< msg.AddressPattern() << " - " << e.what() << std::endl; - } -} - -bool TuioClient::isConnected() { - return receiver->isConnected(); -} - -void TuioClient::connect(bool lock) { - - TuioTime::initSession(); - currentTime.reset(); - - receiver->connect(lock); - - unlockCursorList(); - unlockObjectList(); - unlockBlobList(); -} - -void TuioClient::disconnect() { - - receiver->disconnect(); - - aliveObjectList.clear(); - aliveCursorList.clear(); - aliveBlobList.clear(); - - for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) - delete (*iter); - objectList.clear(); - - for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) - delete (*iter); - cursorList.clear(); - - for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) - delete (*iter); - blobList.clear(); - - for (std::list::iterator iter=freeCursorList.begin(); iter != freeCursorList.end(); iter++) - delete(*iter); - freeCursorList.clear(); - - for (std::list::iterator iter=freeBlobList.begin(); iter != freeBlobList.end(); iter++) - delete(*iter); - freeBlobList.clear(); -} - - -TuioObject* TuioClient::getTuioObject(int src_id, long s_id) { - lockObjectList(); - for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { - if (((*iter)->getTuioSourceID()==src_id) && ((*iter)->getSessionID()==s_id)) { - unlockObjectList(); - return (*iter); - } - } - unlockObjectList(); - return NULL; -} - -TuioCursor* TuioClient::getTuioCursor(int src_id, long s_id) { - lockCursorList(); - for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { - if (((*iter)->getTuioSourceID()==src_id) && ((*iter)->getSessionID()==s_id)) { - unlockCursorList(); - return (*iter); - } - } - unlockCursorList(); - return NULL; -} - -TuioBlob* TuioClient::getTuioBlob(int src_id, long s_id) { - lockBlobList(); - for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { - if (((*iter)->getTuioSourceID()==src_id) && ((*iter)->getSessionID()==s_id)) { - unlockBlobList(); - return (*iter); - } - } - unlockBlobList(); - return NULL; -} - - -std::list TuioClient::getTuioObjects(int source_id) { - lockObjectList(); - std::list listBuffer; - for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { - TuioObject *tobj = (*iter); - if (tobj->getTuioSourceID()==source_id) listBuffer.push_back(tobj); - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioClient::getTuioCursors(int source_id) { - lockCursorList(); - std::list listBuffer; - for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { - TuioCursor *tcur = (*iter); - if (tcur->getTuioSourceID()==source_id) listBuffer.push_back(tcur); - } - unlockCursorList(); - return listBuffer; -} - -std::list TuioClient::getTuioBlobs(int source_id) { - lockBlobList(); - std::list listBuffer; - for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { - TuioBlob *tblb = (*iter); - if (tblb->getTuioSourceID()==source_id) listBuffer.push_back(tblb); - } - unlockBlobList(); - return listBuffer; -} - - -std::list TuioClient::copyTuioObjects(int source_id) { - lockObjectList(); - std::list listBuffer; - for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { - TuioObject *tobj = (*iter); - if (tobj->getTuioSourceID()==source_id) listBuffer.push_back(*tobj); - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioClient::copyTuioCursors(int source_id) { - lockCursorList(); - std::list listBuffer; - for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { - TuioCursor *tcur = (*iter); - if (tcur->getTuioSourceID()==source_id) listBuffer.push_back(*tcur); - } - unlockCursorList(); - return listBuffer; -} - -std::list TuioClient::copyTuioBlobs(int source_id) { - lockBlobList(); - std::list listBuffer; - for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { - TuioBlob *tblb = (*iter); - if (tblb->getTuioSourceID()==source_id) listBuffer.push_back(*tblb); - } - unlockBlobList(); - return listBuffer; -} - diff --git a/TUIO/TuioClient.h b/TUIO/TuioClient.h deleted file mode 100644 index d2fd7db..0000000 --- a/TUIO/TuioClient.h +++ /dev/null @@ -1,304 +0,0 @@ -/* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (c) 2005-2009 Martin Kaltenbrunner - - 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 - */ - -#ifndef INCLUDED_TUIOCLIENT_H -#define INCLUDED_TUIOCLIENT_H - -#include "TuioDispatcher.h" -#include "OscReceiver.h" -#include "osc/OscReceivedElements.h" - -#include -#include -#include -#include -#include -#include - -namespace TUIO { - - class OscReceiver; // Forward declaration - - /** - *

The TuioClient class is the central TUIO protocol decoder component. It provides a simple callback infrastructure using the {@link TuioListener} interface. - * In order to receive and decode TUIO messages an instance of TuioClient needs to be created. The TuioClient instance then generates TUIO events - * which are broadcasted to all registered classes that implement the {@link TuioListener} interface.

- *

- * TuioClient *client = new TuioClient();
- * client->addTuioListener(myTuioListener);
- * client->connect();
- *

- * - * @author Martin Kaltenbrunner - * @version 1.5 - */ - class LIBDECL TuioClient : public TuioDispatcher { - - public: - /** - * This constructor creates a TuioClient that uses an internal UdpReceiver listening to the default UDP port 3333 - * - */ - TuioClient(); - - /** - * This constructor creates a TuioClient that uses an internal UdpReceiver listening to the provided UDP port - * - * @param port the UDP port the internal UdpReceiver is listening to - */ - TuioClient(int port); - - /** - * This constructor creates a TuioClient that uses the provided OscReceiver for the incoming OSC data - * - * @param oscreceiver the OscReceiver implementation for the chosen transport method (UDP, TCP ...) - */ - TuioClient(OscReceiver *oscreceiver); - - /** - * The destructor is doing nothing in particular. - */ - ~TuioClient(); - - /** - * The TuioClient connects and starts receiving TUIO messages from its associated OscReceiver - * - * @param lock running in the background if set to false (default) - */ - void connect(bool lock=false); - - /** - * The TuioClient disconnects and stops receiving TUIO messages from its associated OscReceiver - */ - void disconnect(); - - /** - * Returns true if this TuioClient is currently connected. - * @return true if this TuioClient is currently connected - */ - bool isConnected(); - - /** - * Returns a List of all currently active TuioObjects - * - * @return a List of TuioObjects - */ - std::list getTuioObjects() { - return TuioDispatcher::getTuioObjects(); - } - - /** - * Returns a List of all currently active TuioObjects - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List of TuioObjects - */ - std::list getTuioObjects(int source_id); - - /** - * Returns a List with a copy of all currently active TuioObjects - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List with a copy of TuioObjects - */ - std::list copyTuioObjects(int source_id); - - - /** - * Returns a List with a copy of all currently active TuioObjects - * - * @return a List with a copy of TuioObjects - */ - std::list copyTuioObjects() { - return TuioDispatcher::copyTuioObjects(); - } - - /** - * Returns the TuioObject corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioObject - * - * @param s_id the session ID of the corresponding TuioObject - * @return an active TuioObject corresponding to the provided Session ID or NULL - */ - TuioObject* getTuioObject(long s_id) { - return getTuioObject(0,s_id); - }; - - /** - * Returns the TuioObject corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioObject - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioObject - * @return an active TuioObject corresponding to the provided Session ID or NULL - */ - TuioObject* getTuioObject(int src_id, long s_id); - - /** - * Returns a List of all currently active TuioCursors - * - * @return a List of TuioCursors - */ - std::list getTuioCursors() { - return TuioDispatcher::getTuioCursors(); - } - - /** - * Returns a List of all currently active TuioCursors - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List of TuioCursors - */ - std::list getTuioCursors(int source_id); - - /** - * Returns a List with a copy of all currently active TuioCursors - * - * @return a List with a copy of TuioCursors - */ - std::list copyTuioCursors() { - return TuioDispatcher::copyTuioCursors(); - } - - /** - * Returns a List with a copy of all currently active TuioCursors - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List with a copy of TuioCursors - */ - std::list copyTuioCursors(int source_id); - - /** - * Returns the TuioCursor corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioCursor - * - * @param s_id the session ID of the corresponding TuioCursor - * @return an active TuioCursor corresponding to the provided Session ID or NULL - */ - TuioCursor* getTuioCursor(long s_id) { - return getTuioCursor(0,s_id); - }; - - /** - * Returns the TuioCursor corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioCursor - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioCursor - * @return an active TuioCursor corresponding to the provided Session ID or NULL - */ - TuioCursor* getTuioCursor(int src_id, long s_id); - - /** - * Returns a List of all currently active TuioBlobs - * - * @return a List of TuioBlobs - */ - std::list getTuioBlobs() { - return TuioDispatcher::getTuioBlobs(); - } - - /** - * Returns a List of all currently active TuioBlobs - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List of TuioBlobs - */ - std::list getTuioBlobs(int source_id); - - /** - * Returns a List with a copy of all currently active TuioBlobs - * - * @return a List with a copy of TuioBlobs - */ - std::list copyTuioBlobs() { - return TuioDispatcher::copyTuioBlobs(); - } - - /** - * Returns a List with a copy of all currently active TuioBlobs - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List with a copy of TuioBlobs - */ - std::list copyTuioBlobs(int source_id); - - /** - * Returns the TuioBlob corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioBlob - * - * @param s_id the session ID of the corresponding TuioBlob - * @return an active TuioBlob corresponding to the provided Session ID or NULL - */ - TuioBlob* getTuioBlob(long s_id) { - return getTuioBlob(0,s_id); - }; - - /** - * Returns the TuioBlob corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioBlob - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioBlob - * @return an active TuioBlob corresponding to the provided Session ID or NULL - */ - TuioBlob* getTuioBlob(int src_id, long s_id); - - void processOSC( const osc::ReceivedMessage& message); - - private: - void initialize(); - - std::list frameObjects; - std::list aliveObjectList; - std::list frameCursors; - std::list aliveCursorList; - std::list frameBlobs; - std::list aliveBlobList; - - osc::int32 currentFrame; - TuioTime currentTime; - - std::list freeCursorList, freeCursorBuffer; - std::map maxCursorID; - - std::list freeBlobList, freeBlobBuffer; - std::map maxBlobID; - - std::map sourceList; - int source_id; - char *source_name; - char *source_addr; - - OscReceiver *receiver; - bool local_receiver; - }; -}; -#endif /* INCLUDED_TUIOCLIENT_H */ diff --git a/TUIO/TuioContainer.cpp b/TUIO/TuioContainer.cpp index 83aef7a..ba85fb6 100644 --- a/TUIO/TuioContainer.cpp +++ b/TUIO/TuioContainer.cpp @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #include "TuioContainer.h" using namespace TUIO; @@ -32,40 +29,49 @@ TuioContainer::TuioContainer (TuioTime ttime, long si, float xp, float yp):TuioP x_speed = 0.0f; y_speed = 0.0f; motion_speed = 0.0f; - motion_accel = 0.0f; + motion_accel = 0.0f; + x_accel = 0.0f; + y_accel = 0.0f; TuioPoint p(currentTime,xpos,ypos); path.push_back(p); - + lastPoint = &path.back(); } TuioContainer::TuioContainer (long si, float xp, float yp):TuioPoint(xp,yp) ,state(TUIO_ADDED) ,source_id(0) ,source_name("undefined") -,source_addr("localhost") +,source_addr("localhost") { session_id = si; x_speed = 0.0f; y_speed = 0.0f; motion_speed = 0.0f; - motion_accel = 0.0f; + motion_accel = 0.0f; + x_accel = 0.0f; + y_accel = 0.0f; TuioPoint p(currentTime,xpos,ypos); path.push_back(p); + lastPoint = &path.back(); } TuioContainer::TuioContainer (TuioContainer *tcon):TuioPoint(tcon) ,state(TUIO_ADDED) ,source_id(0) ,source_name("undefined") -,source_addr("localhost") +,source_addr("localhost") { session_id = tcon->getSessionID(); x_speed = 0.0f; y_speed = 0.0f; motion_speed = 0.0f; motion_accel = 0.0f; + x_accel = 0.0f; + y_accel = 0.0f; + TuioPoint p(currentTime,xpos,ypos); path.push_back(p); + lastPoint = &path.back(); } void TuioContainer::setTuioSource(int src_id, const char *src_name, const char *src_addr) { @@ -87,31 +93,37 @@ int TuioContainer::getTuioSourceID() const{ } void TuioContainer::update (TuioTime ttime, float xp, float yp) { - TuioPoint lastPoint = path.back(); + lastPoint = &path.back(); TuioPoint::update(ttime,xp, yp); - - TuioTime diffTime = currentTime - lastPoint.getTuioTime(); + + TuioTime diffTime = currentTime - lastPoint->getTuioTime(); float dt = diffTime.getTotalMilliseconds()/1000.0f; - float dx = xpos - lastPoint.getX(); - float dy = ypos - lastPoint.getY(); + float dx = xpos - lastPoint->getX(); + float dy = ypos - lastPoint->getY(); float dist = sqrt(dx*dx+dy*dy); float last_motion_speed = motion_speed; - + float last_x_speed = x_speed; + float last_y_speed = y_speed; + x_speed = dx/dt; y_speed = dy/dt; motion_speed = dist/dt; motion_accel = (motion_speed - last_motion_speed)/dt; - + x_accel = (x_speed - last_x_speed)/dt; + y_accel = (y_speed - last_y_speed)/dt; + TuioPoint p(currentTime,xpos,ypos); path.push_back(p); - + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + if (motion_accel>0) state = TUIO_ACCELERATING; else if (motion_accel<0) state = TUIO_DECELERATING; else state = TUIO_STOPPED; } void TuioContainer::stop(TuioTime ttime) { - update(ttime,xpos,ypos); + if ( state==TUIO_IDLE )update(ttime,xpos,ypos); + else state=TUIO_IDLE; } void TuioContainer::update (TuioTime ttime, float xp, float yp, float xs, float ys, float ma) { @@ -120,10 +132,14 @@ void TuioContainer::update (TuioTime ttime, float xp, float yp, float xs, float y_speed = ys; motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed); motion_accel = ma; - + x_accel = ma; + y_accel = ma; + + lastPoint = &path.back(); TuioPoint p(currentTime,xpos,ypos); path.push_back(p); - + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + if (motion_accel>0) state = TUIO_ACCELERATING; else if (motion_accel<0) state = TUIO_DECELERATING; else state = TUIO_STOPPED; @@ -135,11 +151,14 @@ void TuioContainer::update (float xp, float yp, float xs, float ys, float ma) { y_speed = ys; motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed); motion_accel = ma; - - path.pop_back(); + x_accel = ma; + y_accel = ma; + + lastPoint = &path.back(); TuioPoint p(currentTime,xpos,ypos); path.push_back(p); - + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + if (motion_accel>0) state = TUIO_ACCELERATING; else if (motion_accel<0) state = TUIO_DECELERATING; else state = TUIO_STOPPED; @@ -151,10 +170,14 @@ void TuioContainer::update (TuioContainer *tcon) { y_speed = tcon->getYSpeed(); motion_speed = tcon->getMotionSpeed(); motion_accel = tcon->getMotionAccel(); - + x_accel = motion_accel; + y_accel = motion_accel; + + lastPoint = &path.back(); TuioPoint p(tcon->getTuioTime(),xpos,ypos); path.push_back(p); - + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + if (motion_accel>0) state = TUIO_ACCELERATING; else if (motion_accel<0) state = TUIO_DECELERATING; else state = TUIO_STOPPED; @@ -165,19 +188,19 @@ void TuioContainer::remove(TuioTime ttime) { state = TUIO_REMOVED; } -long TuioContainer::getSessionID() const{ +long TuioContainer::getSessionID() const{ return session_id; } -void TuioContainer::setSessionID(long s_id) { +void TuioContainer::setSessionID(long s_id) { session_id = s_id; } -float TuioContainer::getXSpeed() const{ +float TuioContainer::getXSpeed() const{ return x_speed; } -float TuioContainer::getYSpeed() const{ +float TuioContainer::getYSpeed() const{ return y_speed; } @@ -198,12 +221,57 @@ float TuioContainer::getMotionAccel() const{ return motion_accel; } -int TuioContainer::getTuioState() const{ +int TuioContainer::getTuioState() const{ return state; -} +} -bool TuioContainer::isMoving() const{ +bool TuioContainer::isMoving() const{ if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING)) return true; else return false; } +TuioPoint TuioContainer::predictPosition() { + /*if (path.size()>1) { + std::list::iterator iter = path.end(); + std::advance(iter, -2); + + TuioTime diffTime = currentTime - (*iter).getTuioTime(); + float dt = diffTime.getTotalMilliseconds()/1000.0f; + + float tx = x_speed * dt; + float ty = y_speed * dt; + + float nx = xpos+tx-tx*x_accel*dt; + float ny = ypos+ty-ty*y_accel*dt; + + //if (xposFilter && yposFilter) { + // nx = xposFilter->filter(nx,dt); + // ny = yposFilter->filter(ny,dt); + // //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl; + //} + + //std::cout << nx << " " << ny << std::endl; + return TuioPoint(nx,ny); + } else return TuioPoint(xpos,ypos);*/ + + TuioTime diffTime = currentTime - lastPoint->getTuioTime(); + float dt = diffTime.getTotalMilliseconds()/1000.0f; + + float tx = x_speed * dt; + float ty = y_speed * dt; + + float nx = xpos+tx-tx*x_accel*dt; + float ny = ypos+ty-ty*y_accel*dt; + + //if (xposFilter && yposFilter) { + // nx = xposFilter->filter(nx,dt); + // ny = yposFilter->filter(ny,dt); + // //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl; + //} + + //std::cout << nx << " " << ny << std::endl; + return TuioPoint(nx,ny); + + +} + diff --git a/TUIO/TuioContainer.h b/TUIO/TuioContainer.h index 6a23595..c25a0b2 100644 --- a/TUIO/TuioContainer.h +++ b/TUIO/TuioContainer.h @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TUIOCONTAINER_H #define INCLUDED_TUIOCONTAINER_H @@ -34,16 +31,23 @@ #define TUIO_STOPPED 5 #define TUIO_REMOVED 6 +#define MAX_PATH_SIZE 128 + namespace TUIO { /** * The abstract TuioContainer class defines common attributes that apply to both subclasses {@link TuioObject} and {@link TuioCursor}. * * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL TuioContainer: public TuioPoint { + + private: + + TuioPoint *lastPoint; + protected: /** * The unique session ID number that is assigned to each TUIO object or cursor. @@ -65,6 +69,8 @@ namespace TUIO { * The motion acceleration value. */ float motion_accel; + float x_accel; + float y_accel; /** * A List of TuioPoints containing all the previous positions of the TUIO component. */ @@ -266,6 +272,8 @@ namespace TUIO { * @return true of this TuioContainer is moving */ virtual bool isMoving() const; + + virtual TuioPoint predictPosition(); }; } #endif diff --git a/TUIO/TuioCursor.cpp b/TUIO/TuioCursor.cpp index 4d5fdb4..4df31cd 100644 --- a/TUIO/TuioCursor.cpp +++ b/TUIO/TuioCursor.cpp @@ -1,29 +1,25 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #include "TuioCursor.h" using namespace TUIO; - TuioCursor::TuioCursor (TuioTime ttime, long si, int ci, float xp, float yp):TuioContainer(ttime,si,xp,yp) { cursor_id = ci; } @@ -36,7 +32,6 @@ TuioCursor::TuioCursor (TuioCursor *tcur):TuioContainer(tcur) { cursor_id = tcur->getCursorID(); } - int TuioCursor::getCursorID() const{ return cursor_id; }; diff --git a/TUIO/TuioCursor.h b/TUIO/TuioCursor.h index 9e8ce48..43d345d 100644 --- a/TUIO/TuioCursor.h +++ b/TUIO/TuioCursor.h @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TUIOCURSOR_H #define INCLUDED_TUIOCURSOR_H @@ -30,7 +27,7 @@ namespace TUIO { * The TuioCursor class encapsulates /tuio/2Dcur TUIO cursors. * * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL TuioCursor: public TuioContainer { @@ -77,7 +74,7 @@ namespace TUIO { /** * The destructor is doing nothing in particular. */ - ~TuioCursor(){}; + virtual ~TuioCursor(){}; /** * Returns the Cursor ID of this TuioCursor. diff --git a/TUIO/TuioDispatcher.cpp b/TUIO/TuioDispatcher.cpp index a1b4274..c36d59e 100644 --- a/TUIO/TuioDispatcher.cpp +++ b/TUIO/TuioDispatcher.cpp @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (C) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #include "TuioDispatcher.h" @@ -34,9 +31,9 @@ TuioDispatcher::TuioDispatcher() { pthread_mutex_init(&objectMutex,NULL); pthread_mutex_init(&blobMutex,NULL); #else - cursorMutex = CreateMutex(NULL,FALSE,"cursorMutex"); - objectMutex = CreateMutex(NULL,FALSE,"objectMutex"); - blobMutex = CreateMutex(NULL,FALSE,"blobMutex"); + cursorMutex = CreateMutex(NULL,FALSE,TEXT("cursorMutex")); + objectMutex = CreateMutex(NULL,FALSE,TEXT("objectMutex")); + blobMutex = CreateMutex(NULL,FALSE,TEXT("blobMutex")); #endif } @@ -151,21 +148,27 @@ TuioBlob* TuioDispatcher::getTuioBlob(long s_id) { std::list TuioDispatcher::getTuioObjects() { lockObjectList(); - std::list listBuffer = objectList; + std::list listBuffer; + listBuffer.insert(listBuffer.end(), objectList.begin(), objectList.end()); + //std::list listBuffer = objectList; unlockObjectList(); return listBuffer; } std::list TuioDispatcher::getTuioCursors() { lockCursorList(); - std::list listBuffer = cursorList; + std::list listBuffer; + listBuffer.insert(listBuffer.end(), cursorList.begin(), cursorList.end()); + //std::list listBuffer = cursorList; unlockCursorList(); return listBuffer; } std::list TuioDispatcher::getTuioBlobs() { lockBlobList(); - std::list listBuffer = blobList; + std::list listBuffer; + listBuffer.insert(listBuffer.end(), blobList.begin(), blobList.end()); + //std::list listBuffer = blobList; unlockBlobList(); return listBuffer; } diff --git a/TUIO/TuioDispatcher.h b/TUIO/TuioDispatcher.h index 8553c03..0b8fc79 100644 --- a/TUIO/TuioDispatcher.h +++ b/TUIO/TuioDispatcher.h @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (C) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TUIODISPATCHER_H #define INCLUDED_TUIODISPATCHER_H @@ -37,7 +34,7 @@ namespace TUIO { * registered classes that implement the {@link TuioListener} interface.

* * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL TuioDispatcher { diff --git a/TUIO/TuioListener.h b/TUIO/TuioListener.h index d70592d..099f880 100644 --- a/TUIO/TuioListener.h +++ b/TUIO/TuioListener.h @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TUIOLISTENER_H #define INCLUDED_TUIOLISTENER_H @@ -43,7 +40,7 @@ namespace TUIO { *

* * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL TuioListener { diff --git a/TUIO/TuioManager.cpp b/TUIO/TuioManager.cpp index 9053c08..db16a61 100644 --- a/TUIO/TuioManager.cpp +++ b/TUIO/TuioManager.cpp @@ -1,22 +1,19 @@ /* - TUIO Server Component - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (C) 2005-2009 Martin Kaltenbrunner - - 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 + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. */ #include "TuioManager.h" @@ -61,6 +58,7 @@ TuioObject* TuioManager::addTuioObject(int f_id, float x, float y, float a) { void TuioManager::addExternalTuioObject(TuioObject *tobj) { if (tobj==NULL) return; + tobj->setSessionID(sessionID++); objectList.push_back(tobj); updateObject = true; @@ -103,15 +101,16 @@ void TuioManager::updateExternalTuioObject(TuioObject *tobj) { void TuioManager::removeTuioObject(TuioObject *tobj) { if (tobj==NULL) return; - objectList.remove(tobj); - delete tobj; - updateObject = true; for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) (*listener)->removeTuioObject(tobj); if (verbose) std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ")" << std::endl; + + objectList.remove(tobj); + delete tobj; + updateObject = true; } void TuioManager::removeExternalTuioObject(TuioObject *tobj) { @@ -158,6 +157,7 @@ TuioCursor* TuioManager::addTuioCursor(float x, float y) { void TuioManager::addExternalTuioCursor(TuioCursor *tcur) { if (tcur==NULL) return; + tcur->setSessionID(sessionID++); cursorList.push_back(tcur); updateCursor = true; @@ -170,7 +170,7 @@ void TuioManager::addExternalTuioCursor(TuioCursor *tcur) { void TuioManager::updateTuioCursor(TuioCursor *tcur,float x, float y) { if (tcur==NULL) return; - if (tcur->getTuioTime()==currentFrameTime) return; + //if (tcur->getTuioTime()==currentFrameTime) return; tcur->update(currentFrameTime,x,y); updateCursor = true; @@ -280,13 +280,31 @@ TuioBlob* TuioManager::addTuioBlob(float x, float y, float a, float w, float h, (*listener)->addTuioBlob(tblb); if (verbose) - std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << tblb->getAngle() << " " << tblb->getWidth() << tblb->getHeight() << " " << tblb->getArea() << std::endl; + std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl; return tblb; } void TuioManager::addExternalTuioBlob(TuioBlob *tblb) { if (tblb==NULL) return; + + int blobID = (int)blobList.size(); + if (blobID <= maxBlobID) { + std::list::iterator closestBlob = freeBlobList.begin(); + + for(std::list::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) { + if((*iter)->getDistance(tblb->getX(),tblb->getY())<(*closestBlob)->getDistance(tblb->getX(),tblb->getY())) closestBlob = iter; + } + + TuioBlob *freeBlob = (*closestBlob); + blobID = (*closestBlob)->getBlobID(); + freeBlobList.erase(closestBlob); + delete freeBlob; + } else maxBlobID = blobID; + + tblb->setSessionID(sessionID++); + tblb->setBlobID(blobID); + blobList.push_back(tblb); updateBlob = true; @@ -294,7 +312,7 @@ void TuioManager::addExternalTuioBlob(TuioBlob *tblb) { (*listener)->addTuioBlob(tblb); if (verbose) - std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << tblb->getAngle() << " " << tblb->getWidth() << tblb->getHeight() << " " << tblb->getArea() << std::endl; + std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl; } void TuioManager::updateTuioBlob(TuioBlob *tblb,float x, float y, float a, float w, float h, float f) { @@ -569,8 +587,8 @@ void TuioManager::stopUntouchedMovingBlobs() { tblb->stop(currentFrameTime); updateBlob = true; if (verbose) - std::cout << "set blb " << tblb->getSessionID() << tblb->getX() << " " << tblb->getY() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getAngle() - << " " << tblb->getXSpeed() << " " << tblb->getYSpeed()<< " " << tblb->getMotionAccel() << " " << std::endl; + std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() + << " " << tblb->getXSpeed() << " " << tblb->getYSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel()<< " " << tblb->getRotationAccel() << " " << std::endl; } } } diff --git a/TUIO/TuioManager.h b/TUIO/TuioManager.h index 10fe477..3eabbde 100644 --- a/TUIO/TuioManager.h +++ b/TUIO/TuioManager.h @@ -1,23 +1,20 @@ /* - TUIO Server Component - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (C) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TUIOMANAGER_H #define INCLUDED_TUIOMANAGER_H @@ -60,7 +57,7 @@ namespace TUIO { *

* * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL TuioManager : public TuioDispatcher { @@ -348,6 +345,7 @@ namespace TUIO { * @param verbose print verbose messages if set to true */ void setVerbose(bool verbose) { this->verbose=verbose; } + bool isVerbose() { return verbose; } void setInversion(bool ix, bool iy, bool ia) { invert_x = ix; diff --git a/TUIO/TuioObject.cpp b/TUIO/TuioObject.cpp index de9090a..9c818ca 100644 --- a/TUIO/TuioObject.cpp +++ b/TUIO/TuioObject.cpp @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #include "TuioObject.h" @@ -26,27 +23,40 @@ using namespace TUIO; TuioObject::TuioObject (TuioTime ttime, long si, int sym, float xp, float yp, float a):TuioContainer(ttime, si, xp, yp) { symbol_id = sym; angle = a; + angle_sum = a; rotation_speed = 0.0f; rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; } TuioObject::TuioObject (long si, int sym, float xp, float yp, float a):TuioContainer(si, xp, yp) { symbol_id = sym; angle = a; + angle_sum = a; rotation_speed = 0.0f; rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; } TuioObject::TuioObject (TuioObject *tobj):TuioContainer(tobj) { symbol_id = tobj->getSymbolID(); angle = tobj->getAngle(); + angle_sum = tobj->getAngleSum(); rotation_speed = 0.0f; rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; } void TuioObject::update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) { TuioContainer::update(ttime,xp,yp,xs,ys,ma); angle = a; + angle_sum = a; rotation_speed = rs; rotation_accel = ra; if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; @@ -56,6 +66,7 @@ void TuioObject::update (TuioTime ttime, float xp, float yp, float a, float xs, void TuioObject::update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) { TuioContainer::update(xp,yp,xs,ys,ma); angle = a; + angle_sum = a; rotation_speed = rs; rotation_accel = ra; if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; @@ -67,11 +78,21 @@ void TuioObject::update (TuioTime ttime, float xp, float yp, float a) { TuioTime diffTime = currentTime - lastPoint.getTuioTime(); float dt = diffTime.getTotalMilliseconds()/1000.0f; - float last_angle = angle; float last_rotation_speed = rotation_speed; - angle = a; - double da = (angle-last_angle)/(2*M_PI); + float prev_angle = angle_sum; + float da = a-angle; + if (da > M_PI/2.0f) angle_sum += (da-2*M_PI); + else if (da < M_PI/-2.0f) angle_sum += (da+2*M_PI); + else angle_sum += da; + + if (angleFilter) angle_sum = angleFilter->filter(angle_sum,dt); + if (fabs(angle_sum-prev_angle) 0.75f) da-=1.0f; else if (da < -0.75f) da+=1.0f; @@ -88,6 +109,7 @@ void TuioObject::stop (TuioTime ttime) { void TuioObject::update (TuioObject *tobj) { TuioContainer::update(tobj); angle = tobj->getAngle(); + angle_sum = tobj->getAngleSum(); rotation_speed = tobj->getRotationSpeed(); rotation_accel = tobj->getRotationAccel(); if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; @@ -101,6 +123,10 @@ float TuioObject::getAngle() const{ return angle; } +float TuioObject::getAngleSum() const{ + return angle_sum; +} + float TuioObject::getAngleDegrees() const{ return (float)(angle/M_PI*180); } @@ -117,3 +143,23 @@ bool TuioObject::isMoving() const{ if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING) || (state==TUIO_ROTATING)) return true; else return false; } + +void TuioObject::addAngleThreshold(float thresh) { + angleThreshold = thresh; +} + +void TuioObject::removeAngleThreshold() { + angleThreshold = 0.0f; +} + +void TuioObject::addAngleFilter(float mcut, float beta) { + + if (angleFilter) delete angleFilter; + angleFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); +} + +void TuioObject::removeAngleFilter() { + + if (angleFilter) delete angleFilter; + angleFilter = NULL; +} diff --git a/TUIO/TuioObject.h b/TUIO/TuioObject.h index 183c6f2..b027c79 100644 --- a/TUIO/TuioObject.h +++ b/TUIO/TuioObject.h @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TUIOOBJECT_H #define INCLUDED_TUIOOBJECT_H @@ -30,7 +27,7 @@ namespace TUIO { * The TuioObject class encapsulates /tuio/2Dobj TUIO objects. * * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL TuioObject: public TuioContainer { @@ -43,6 +40,10 @@ namespace TUIO { * The rotation angle value. */ float angle; + /** + * The accumulated angle value. + */ + float angle_sum; /** * The rotation speed value. */ @@ -52,6 +53,9 @@ namespace TUIO { */ float rotation_accel; + float angleThreshold; + OneEuroFilter *angleFilter; + public: using TuioContainer::update; @@ -91,7 +95,9 @@ namespace TUIO { /** * The destructor is doing nothing in particular. */ - ~TuioObject() {}; + virtual ~TuioObject() { + if (angleFilter) delete angleFilter; + }; /** * Takes a TuioTime argument and assigns it along with the provided @@ -165,6 +171,12 @@ namespace TUIO { */ float getAngle() const; + /** + * Returns the accumulated rotation angle of this TuioObject. + * @return the accumulated rotation angle of this TuioObject + */ + float getAngleSum() const; + /** * Returns the rotation angle in degrees of this TuioObject. * @return the rotation angle in degrees of this TuioObject @@ -188,6 +200,14 @@ namespace TUIO { * @return true of this TuioObject is moving */ bool isMoving() const; + + void addAngleThreshold(float thresh); + + void removeAngleThreshold(); + + void addAngleFilter(float mcut, float beta); + + void removeAngleFilter(); }; } #endif diff --git a/TUIO/TuioPoint.cpp b/TUIO/TuioPoint.cpp index 42f58a8..0b0761c 100644 --- a/TUIO/TuioPoint.cpp +++ b/TUIO/TuioPoint.cpp @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #include "TuioPoint.h" @@ -28,6 +25,11 @@ TuioPoint::TuioPoint (float xp, float yp) { ypos = yp; currentTime = TuioTime::getSessionTime(); startTime = currentTime; + + xposFilter = NULL; + yposFilter = NULL; + + posThreshold = 0.0f; } TuioPoint::TuioPoint (TuioTime ttime, float xp, float yp) { @@ -35,6 +37,11 @@ TuioPoint::TuioPoint (TuioTime ttime, float xp, float yp) { ypos = yp; currentTime = ttime; startTime = currentTime; + + xposFilter = NULL; + yposFilter = NULL; + + posThreshold = 0.0f; } TuioPoint::TuioPoint (TuioPoint *tpoint) { @@ -42,6 +49,11 @@ TuioPoint::TuioPoint (TuioPoint *tpoint) { ypos = tpoint->getY(); currentTime = TuioTime::getSessionTime(); startTime = currentTime; + + xposFilter = NULL; + yposFilter = NULL; + + posThreshold = 0.0f; } void TuioPoint::update (TuioPoint *tpoint) { @@ -52,16 +64,30 @@ void TuioPoint::update (TuioPoint *tpoint) { void TuioPoint::update (float xp, float yp) { xpos = xp; ypos = yp; -} +} void TuioPoint::update (TuioTime ttime, float xp, float yp) { - xpos = xp; - ypos = yp; + + if (xposFilter && yposFilter) { + TuioTime diffTime = ttime - startTime; + float dt = diffTime.getTotalMilliseconds()/1000.0f; + xp = xposFilter->filter(xp,dt); + yp = yposFilter->filter(yp,dt); + //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl; + } + + float dx = fabs(xpos - xp); + float dy = fabs(ypos - yp); + if ((dx>posThreshold) || (dy>posThreshold)) { + xpos = xp; + ypos = yp; + } + currentTime = ttime; } -float TuioPoint::getX() const{ +float TuioPoint::getX() const{ return xpos; } @@ -90,10 +116,10 @@ float TuioPoint::getAngle(float xp, float yp) const{ float side = xpos-xp; float height = ypos-yp; float distance = getDistance(xp,yp); - + float angle = (float)(asin(side/distance)+M_PI/2); if (height<0) angle = 2.0f*(float)M_PI-angle; - + return angle; } @@ -109,7 +135,7 @@ float TuioPoint::getAngleDegrees(TuioPoint *tpoint) const{ return ((getAngle(tpoint)/(float)M_PI)*180.0f); } -int TuioPoint::getScreenX(int width) const{ +int TuioPoint::getScreenX(int width) const{ return (int)floor(xpos*width+0.5f); } @@ -117,7 +143,7 @@ int TuioPoint::getScreenY(int height) const{ return (int)floor(ypos*height+0.5f); } -TuioTime TuioPoint::getTuioTime() const{ +TuioTime TuioPoint::getTuioTime() const{ return currentTime; } @@ -125,3 +151,26 @@ TuioTime TuioPoint::getStartTime() const{ return startTime; } +void TuioPoint::addPositionThreshold(float thresh) { + posThreshold = thresh; +} + +void TuioPoint::removePositionThreshold() { + posThreshold = 0.0f; +} + +void TuioPoint::addPositionFilter(float mcut, float beta) { + + if (xposFilter) delete xposFilter; + xposFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); + if (yposFilter) delete yposFilter; + yposFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); +} + +void TuioPoint::removePositionFilter() { + + if (xposFilter) delete xposFilter; + xposFilter = NULL; + if (yposFilter) delete yposFilter; + yposFilter = NULL; +} diff --git a/TUIO/TuioPoint.h b/TUIO/TuioPoint.h index 9a5ec93..3415f07 100644 --- a/TUIO/TuioPoint.h +++ b/TUIO/TuioPoint.h @@ -1,28 +1,26 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TUIOPOINT_H #define INCLUDED_TUIOPOINT_H #include "TuioTime.h" +#include "OneEuroFilter.h" #include #ifndef M_PI @@ -30,16 +28,16 @@ #endif namespace TUIO { - + /** * The TuioPoint class on the one hand is a simple container and utility class to handle TUIO positions in general, * on the other hand the TuioPoint is the base class for the TuioCursor and TuioObject classes. * * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL TuioPoint { - + protected: /** * X coordinate, representated as a floating point value in a range of 0..1 @@ -57,16 +55,20 @@ namespace TUIO { * The creation time of this TuioPoint represented as TuioTime (time since session start) */ TuioTime startTime; - + + OneEuroFilter *xposFilter; + OneEuroFilter *yposFilter; + float posThreshold; + public: /** - * The default constructor takes no arguments and sets + * The default constructor takes no arguments and sets * its coordinate attributes to zero and its time stamp to the current session time. */ TuioPoint (float xp, float yp); - + /** - * This constructor takes a TuioTime object and two floating point coordinate arguments and sets + * This constructor takes a TuioTime object and two floating point coordinate arguments and sets * its coordinate attributes to these values and its time stamp to the provided TUIO time object. * * @param ttime the TuioTime to assign @@ -74,37 +76,40 @@ namespace TUIO { * @param yp the Y coordinate to assign */ TuioPoint (TuioTime ttime, float xp, float yp); - + /** - * This constructor takes a TuioPoint argument and sets its coordinate attributes + * This constructor takes a TuioPoint argument and sets its coordinate attributes * to the coordinates of the provided TuioPoint and its time stamp to the current session time. * * @param tpoint the TuioPoint to assign */ TuioPoint (TuioPoint *tpoint); - + /** - * The destructor is doing nothing in particular. + * The destructor is doing nothing in particular. */ - ~TuioPoint(){}; - + virtual ~TuioPoint(){ + if (xposFilter) delete xposFilter; + if (yposFilter) delete yposFilter; + }; + /** - * Takes a TuioPoint argument and updates its coordinate attributes + * Takes a TuioPoint argument and updates its coordinate attributes * to the coordinates of the provided TuioPoint and leaves its time stamp unchanged. * * @param tpoint the TuioPoint to assign */ void update (TuioPoint *tpoint); - + /** * Takes two floating point coordinate arguments and updates its coordinate attributes * to the coordinates of the provided TuioPoint and leaves its time stamp unchanged. * * @param xp the X coordinate to assign * @param yp the Y coordinate to assign - */ - void update (float xp, float yp); - + */ + void update (float xp, float yp); + /** * Takes a TuioTime object and two floating point coordinate arguments and updates its coordinate attributes * to the coordinates of the provided TuioPoint and its time stamp to the provided TUIO time object. @@ -208,6 +213,14 @@ namespace TUIO { * @return the start time of this TuioPoint as TuioTime */ TuioTime getStartTime() const; + + void addPositionThreshold(float thresh); + + void removePositionThreshold(); + + void addPositionFilter(float mcut, float beta); + + void removePositionFilter(); }; } #endif diff --git a/TUIO/TuioServer.cpp b/TUIO/TuioServer.cpp index 4220237..c157e7d 100644 --- a/TUIO/TuioServer.cpp +++ b/TUIO/TuioServer.cpp @@ -1,22 +1,19 @@ /* - TUIO Server Component - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (C) 2005-2009 Martin Kaltenbrunner - - 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 + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. */ #include "TuioServer.h" @@ -26,48 +23,44 @@ using namespace TUIO; using namespace osc; TuioServer::TuioServer() - :local_sender (true) - ,full_update (false) + :full_update (false) ,periodic_update (false) ,objectProfileEnabled (true) ,cursorProfileEnabled (true) ,blobProfileEnabled (true) ,source_name (NULL) { - primary_sender = new UdpSender(); - initialize(); + OscSender *oscsend = new UdpSender(); + initialize(oscsend); } TuioServer::TuioServer(const char *host, int port) -:local_sender (true) -,full_update (false) +:full_update (false) ,periodic_update (false) ,objectProfileEnabled (true) ,cursorProfileEnabled (true) ,blobProfileEnabled (true) ,source_name (NULL) { - primary_sender = new UdpSender(host,port); - initialize(); + OscSender *oscsend = new UdpSender(host,port); + initialize(oscsend); } TuioServer::TuioServer(OscSender *oscsend) - :primary_sender (oscsend) - ,local_sender (false) - ,full_update (false) + :full_update (false) ,periodic_update (false) ,objectProfileEnabled (true) ,cursorProfileEnabled (true) ,blobProfileEnabled (true) ,source_name (NULL) { - initialize(); + initialize(oscsend); } -void TuioServer::initialize() { +void TuioServer::initialize(OscSender *oscsend) { - senderList.push_back(primary_sender); - int size = primary_sender->getBufferSize(); + senderList.push_back(oscsend); + int size = oscsend->getBufferSize(); oscBuffer = new char[size]; oscPacket = new osc::OutboundPacketStream(oscBuffer,size); fullBuffer = new char[size]; @@ -77,9 +70,9 @@ void TuioServer::initialize() { cursorUpdateTime = TuioTime(currentFrameTime); blobUpdateTime = TuioTime(currentFrameTime); - sendEmptyCursorBundle(); - sendEmptyObjectBundle(); - sendEmptyBlobBundle(); + if (cursorProfileEnabled) sendEmptyCursorBundle(); + if (objectProfileEnabled) sendEmptyObjectBundle(); + if (blobProfileEnabled) sendEmptyBlobBundle(); invert_x = false; invert_y = false; @@ -98,17 +91,18 @@ TuioServer::~TuioServer() { removeUntouchedStoppedObjects(); removeUntouchedStoppedBlobs(); - sendEmptyCursorBundle(); - sendEmptyObjectBundle(); - sendEmptyBlobBundle(); - + if (cursorProfileEnabled) sendEmptyCursorBundle(); + if (objectProfileEnabled) sendEmptyObjectBundle(); + if (blobProfileEnabled) sendEmptyBlobBundle(); + delete []oscBuffer; delete oscPacket; delete []fullBuffer; delete fullPacket; if (source_name) delete[] source_name; - if( local_sender) delete primary_sender; + for (unsigned int i=0;isendOscPacket(packet); } +void TuioServer::setSourceName(const char *name, const char *ip) { + if (!source_name) source_name = new char[256]; + sprintf(source_name,"%s@%s",name,ip); +} + + void TuioServer::setSourceName(const char *src) { if (!source_name) source_name = new char[256]; - if (primary_sender->isLocal()) { + /*if (senderList[0]->isLocal()) { sprintf(source_name,"%s",src); - } else { + } else {*/ char hostname[64]; char *source_addr = NULL; struct hostent *hp = NULL; @@ -174,9 +174,9 @@ void TuioServer::setSourceName(const char *src) { source_addr = inet_ntoa(*addr); } sprintf(source_name,"%s@%s",src,source_addr); - } + //} - //std::cout << "source: " << source_name << std::endl; + std::cout << "tuio/src " << source_name << std::endl; } void TuioServer::commitFrame() { @@ -302,12 +302,14 @@ void TuioServer::startCursorBundle() { if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive"; for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { - (*oscPacket) << (int32)((*tuioCursor)->getSessionID()); + if ((*tuioCursor)->getTuioState()!=TUIO_ADDED) (*oscPacket) << (int32)((*tuioCursor)->getSessionID()); } (*oscPacket) << osc::EndMessage; } void TuioServer::addCursorMessage(TuioCursor *tcur) { + + if (tcur->getTuioState()==TUIO_ADDED) return; float xpos = tcur->getX(); float xvel = tcur->getXSpeed(); @@ -405,13 +407,15 @@ void TuioServer::startBlobBundle() { if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive"; for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { - (*oscPacket) << (int32)((*tuioBlob)->getSessionID()); + if ((*tuioBlob)->getTuioState()!=TUIO_ADDED) (*oscPacket) << (int32)((*tuioBlob)->getSessionID()); } (*oscPacket) << osc::EndMessage; } void TuioServer::addBlobMessage(TuioBlob *tblb) { + if (tblb->getTuioState()==TUIO_ADDED) return; + float xpos = tblb->getX(); float xvel = tblb->getXSpeed(); if (invert_x) { diff --git a/TUIO/TuioServer.h b/TUIO/TuioServer.h index 5fc5a73..66ad0a5 100644 --- a/TUIO/TuioServer.h +++ b/TUIO/TuioServer.h @@ -1,29 +1,29 @@ /* - TUIO Server Component - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (C) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TuioServer_H #define INCLUDED_TuioServer_H #include "TuioManager.h" #include "UdpSender.h" +#include "TcpSender.h" +#include "WebSockSender.h" +#include "FlashSender.h" #include #include #include @@ -66,7 +66,7 @@ namespace TUIO { *

* * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL TuioServer : public TuioManager { @@ -172,9 +172,21 @@ namespace TUIO { /** * Defines the name of this TUIO source, which is transmitted within the /tuio/[profile] source message. * - * @param src the desired name of this TUIO source + * @param name the desired name of this TUIO source */ - void setSourceName(const char *src); + void setSourceName(const char *name); + + + /** + * Defines the name and IP address of this TUIO source, which is transmitted within the /tuio/[profile] source message. + * + * @param name the desired name of this TUIO source + * @param ip the local IP address + */ + void setSourceName(const char *name, const char *ip); + + + void addOscSender(OscSender *sender); void enableObjectProfile(bool flag) { objectProfileEnabled = flag; }; @@ -183,10 +195,7 @@ namespace TUIO { private: - void initialize(); - - OscSender *primary_sender; - bool local_sender; + void initialize(OscSender *oscsend); std::vector senderList; void deliverOscPacket(osc::OutboundPacketStream *packet); diff --git a/TUIO/TuioTime.cpp b/TUIO/TuioTime.cpp index 09f5941..f169c14 100644 --- a/TUIO/TuioTime.cpp +++ b/TUIO/TuioTime.cpp @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #include "TuioTime.h" using namespace TUIO; diff --git a/TUIO/TuioTime.h b/TUIO/TuioTime.h index b9cc3f9..567c443 100644 --- a/TUIO/TuioTime.h +++ b/TUIO/TuioTime.h @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_TUIOTIME_H #define INCLUDED_TUIOTIME_H @@ -46,7 +43,7 @@ namespace TUIO { * The class also provides various addtional convience method, which allow some simple time arithmetics. * * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL TuioTime { diff --git a/TUIO/UdpReceiver.cpp b/TUIO/UdpReceiver.cpp deleted file mode 100644 index bbd7460..0000000 --- a/TUIO/UdpReceiver.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (c) 2005-2009 Martin Kaltenbrunner - - 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 "UdpReceiver.h" - -using namespace TUIO; -using namespace osc; - -#ifndef WIN32 -static void* ClientThreadFunc( void* obj ) -#else -static DWORD WINAPI ClientThreadFunc( LPVOID obj ) -#endif -{ - static_cast(obj)->socket->Run(); - return 0; -}; - -UdpReceiver::UdpReceiver(int port) -: socket (NULL) -, thread (NULL) -, locked (false) -{ - try { - socket = new UdpListeningReceiveSocket(IpEndpointName( IpEndpointName::ANY_ADDRESS, port ), this ); - } catch (std::exception &e) { - std::cerr << "could not bind to UDP port " << port << std::endl; - socket = NULL; - } - - if (socket!=NULL) { - if (!socket->IsBound()) { - delete socket; - socket = NULL; - } else std::cout << "listening to TUIO messages on UDP port " << port << std::endl; - } -} - -UdpReceiver::~UdpReceiver() { - delete socket; -} - -void UdpReceiver::connect(bool lk) { - - if (connected) return; - if (socket==NULL) return; - - locked = lk; - if (!locked) { -#ifndef WIN32 - pthread_create(&thread , NULL, ClientThreadFunc, this); -#else - DWORD threadId; - thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &threadId ); -#endif - } else socket->Run(); - - connected = true; -} - -void UdpReceiver::disconnect() { - - if (!connected) return; - if (socket==NULL) { - connected = false; - return; - } - socket->Break(); - - if (!locked) { -#ifdef WIN32 - if( thread ) CloseHandle( thread ); -#endif - thread = 0; - locked = false; - } - - connected = false; -} - - diff --git a/TUIO/UdpReceiver.h b/TUIO/UdpReceiver.h deleted file mode 100644 index 4f0da51..0000000 --- a/TUIO/UdpReceiver.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ - - Copyright (c) 2005-2009 Martin Kaltenbrunner - - 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 - */ - -#ifndef INCLUDED_UDPRECEIVER_H -#define INCLUDED_UDPRECEIVER_H - -#include "OscReceiver.h" -#include "ip/UdpSocket.h" - -namespace TUIO { - - /** - * The UdpReceiver provides the OscReceiver finctionality for the UDP transport method - * - * @author Martin Kaltenbrunner - * @version 1.5 - */ - class LIBDECL UdpReceiver: public OscReceiver { - - public: - - /** - * The UDP socket is only public to be accessible from the thread function - */ - UdpListeningReceiveSocket *socket; - - /** - * This constructor creates a UdpReceiver instance listening to the provided UDP port - * - * @param port the number of the UDP port to listen to, defaults to 3333 - */ - UdpReceiver (int port=3333); - - /** - * The destructor is doing nothing in particular. - */ - virtual ~UdpReceiver(); - - /** - * The UdpReceiver connects and starts receiving TUIO messages via UDP - * - * @param lock running in the background if set to false (default) - */ - void connect(bool lock=false); - - /** - * The UdpReceiver disconnects and stops receiving TUIO messages via UDP - */ - void disconnect(); - - private: - -#ifndef WIN32 - pthread_t thread; -#else - HANDLE thread; -#endif - - bool locked; - }; -}; -#endif /* INCLUDED_UDPRECEIVER_H */ diff --git a/TUIO/UdpSender.cpp b/TUIO/UdpSender.cpp index d1b3e88..c4f8c10 100644 --- a/TUIO/UdpSender.cpp +++ b/TUIO/UdpSender.cpp @@ -1,24 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ - + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #include "UdpSender.h" @@ -30,9 +26,11 @@ UdpSender::UdpSender() { long unsigned int ip = GetHostByName("localhost"); socket = new UdpTransmitSocket(IpEndpointName(ip, 3333)); buffer_size = MAX_UDP_SIZE; + std::cout << "TUIO/UDP messages to " << "127.0.0.1@3333" << std::endl; } catch (std::exception &e) { std::cout << "could not create UDP socket" << std::endl; socket = NULL; + throw std::exception(); } } @@ -47,9 +45,11 @@ UdpSender::UdpSender(const char *host, int port) { } long unsigned int ip = GetHostByName(host); socket = new UdpTransmitSocket(IpEndpointName(ip, port)); + std::cout << "TUIO/UDP messages to " << host << "@" << port << std::endl; } catch (std::exception &e) { std::cout << "could not create UDP socket" << std::endl; socket = NULL; + throw std::exception(); } } @@ -62,9 +62,11 @@ UdpSender::UdpSender(const char *host, int port, int size) { socket = new UdpTransmitSocket(IpEndpointName(ip, port)); if (buffer_size>MAX_UDP_SIZE) buffer_size = MAX_UDP_SIZE; else if (buffer_sizeSize() > buffer_size ) return false; + if ( bundle->Size() == 0 ) return false; + socket->Send( bundle->Data(), bundle->Size() ); return true; } diff --git a/TUIO/UdpSender.h b/TUIO/UdpSender.h index 88bcb42..357f0f7 100644 --- a/TUIO/UdpSender.h +++ b/TUIO/UdpSender.h @@ -1,23 +1,20 @@ /* - TUIO C++ Library - part of the reacTIVision project - http://reactivision.sourceforge.net/ + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner - Copyright (c) 2005-2009 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. - 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, + This library 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. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser 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 - */ + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ #ifndef INCLUDED_UDPSENDER_H #define INCLUDED_UDPSENDER_H @@ -35,7 +32,7 @@ namespace TUIO { * The UdpSender implements the UDP transport method for OSC * * @author Martin Kaltenbrunner - * @version 1.5 + * @version 1.1.6 */ class LIBDECL UdpSender : public OscSender { @@ -69,7 +66,7 @@ namespace TUIO { /** * The destructor closes the socket. */ - ~UdpSender(); + virtual ~UdpSender(); /** * This method delivers the provided OSC data @@ -87,6 +84,8 @@ namespace TUIO { */ bool isConnected (); + const char* tuio_type() { return "TUIO/UDP"; } + private: UdpTransmitSocket *socket; }; diff --git a/TUIO/WebSockSender.h b/TUIO/WebSockSender.h new file mode 100644 index 0000000..66c8589 --- /dev/null +++ b/TUIO/WebSockSender.h @@ -0,0 +1,121 @@ +/* + TUIO C++ Library + Copyright (c) 2009-2016 Martin Kaltenbrunner + WebSockSender (c) 2015 Florian Echtler + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_WEBSOCKSENDER_H +#define INCLUDED_WEBSOCKSENDER_H + +#if defined(_MSC_VER) && _MSC_VER < 1900 +#include +#include +#define snprintf c99_snprintf +#define vsnprintf c99_vsnprintf + +__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + + return count; +} + +#endif + + +/* All of these macros assume use on a 32-bit variable. + Additionally, SWAP assumes we're little-endian. */ +#define SWAP(a) ((((a) >> 24) & 0x000000ff) | (((a) >> 8) & 0x0000ff00) | \ +(((a) << 8) & 0x00ff0000) | (((a) << 24) & 0xff000000)) +#define ROL(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) +#define ROR(a, b) ROL((a), (32 - (b))) +#define SHA1_HASH_SIZE (160/8) + +#include "TcpSender.h" +#include +#include +#include +#include + +namespace TUIO { + + /** + * The WebSockSender implements the WebSocket transport method for OSC + * + * @author Florian Echtler + * @version 2.0.a0 + */ + class LIBDECL WebSockSender : public TcpSender { + + public: + + /** + * The default constructor creates a WebSockSender that listens to the default HTTP-alt port 8080 on localhost + */ + WebSockSender(); + + /** + * This constructor creates a WebSockSender that listens to the provided port + * + * @param port the listening WebSocket port number + */ + WebSockSender(int port); + + /** + * The destructor closes the socket. + */ + virtual ~WebSockSender() {} + + /** + * This method delivers the provided OSC data + * + * @param *bundle the OSC stream to deliver + * @return true if the data was delivered successfully + */ + bool sendOscPacket (osc::OutboundPacketStream *bundle); + + /** + * This method is called whenever a new client connects + * + * @param tcp_client the socket handle of the new client + */ + void newClient( int tcp_client ); + + const char* tuio_type() { return "TUIO/WEB"; } + private: + + void sha1( uint8_t digest[SHA1_HASH_SIZE], const uint8_t* inbuf, size_t length ); + std::string base64( uint8_t* buffer, size_t size ); + }; +} +#endif /* INCLUDED_WEBSOCKSENDER_H */ diff --git a/TongsengApp/English.lproj/InfoPlist.strings b/TongsengApp/English.lproj/InfoPlist.strings deleted file mode 100644 index 5e45963..0000000 Binary files a/TongsengApp/English.lproj/InfoPlist.strings and /dev/null differ diff --git a/TongsengApp/English.lproj/MainMenu.xib b/TongsengApp/English.lproj/MainMenu.xib index 08bd409..2b292b6 100644 --- a/TongsengApp/English.lproj/MainMenu.xib +++ b/TongsengApp/English.lproj/MainMenu.xib @@ -1,849 +1,170 @@ - - - - 1050 - 9L30 - 677 - 949.54 - 353.00 - - YES - - - - - YES - com.apple.InterfaceBuilderKit - com.apple.InterfaceBuilder.CocoaPlugin - - - YES - - YES - - - YES - - - - YES - - NSApplication - - - FirstResponder - - - NSApplication - - - AMainMenu - - YES - - - Tongseng - - 1048576 - 2147483647 - - NSImage - NSMenuCheckmark - - - NSImage - NSMenuMixedState - - submenuAction: - - TongsengApp - - YES - - - About Tongseng - - 2147483647 - - - - - - YES - YES - - - 2147483647 - - - - - - Hide Tongseng - h - 1048576 - 2147483647 - - - - - - Hide Others - h - 1572864 - 2147483647 - - - - - - Show All - - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Quit Tongseng - q - 1048576 - 2147483647 - - - - - _NSAppleMenu - - - - _NSMainMenu - - - 7 - 2 - {{529, 292}, {269, 190}} - 1954021376 - Tongseng - NSWindow - - {3.40282e+38, 3.40282e+38} - - - 256 - - YES - - - 12 - - YES - - - 256 - - YES - - - 268 - {{15, 57}, {72, 17}} - - YES - - 68288064 - 71304192 - Hostname: - - LucidaGrande - 1.300000e+01 - 1044 - - - - 6 - System - controlColor - - 3 - MC42NjY2NjY2OQA - - - - 6 - System - controlTextColor - - 3 - MAA - - - - - - - 268 - {{15, 25}, {72, 17}} - - YES - - 68288064 - 71304192 - UDP port: - - - - - - - - - 268 - {{92, 55}, {119, 22}} - - YES - - -1804468671 - 272630784 - localhost - - - YES - - 6 - System - textBackgroundColor - - 3 - MQA - - - - 6 - System - textColor - - - - - - - 268 - {{92, 23}, {119, 22}} - - YES - - -1804468671 - 272630784 - 3333 - - - YES - - - - - - {{1, 1}, {233, 98}} - - - - {{17, 16}, {235, 114}} - - {0, 0} - - 67239424 - 0 - Configuration - - LucidaGrande - 1.100000e+01 - 3100 - - - - 3 - MCAwLjgwMDAwMDAxAA - - - - 1 - 0 - 2 - NO - - - - 268 - {{14, 142}, {90, 32}} - - YES - - 67239424 - 134217728 - Start - - - -2038284033 - 129 - - - 200 - 25 - - - - - 268 - {{109, 152}, {143, 17}} - - YES - - 68288064 - 4195328 - Tongseng is stopped - - - - - - - - {269, 190} - - - {{0, 0}, {1280, 778}} - {3.40282e+38, 3.40282e+38} - - - NSFontManager - - - TongsengController - - - - - YES - - - hide: - - - - 367 - - - - hideOtherApplications: - - - - 368 - - - - unhideAllApplications: - - - - 370 - - - - terminate: - - - - 449 - - - - startstop: - - - - 464 - - - - _hostname - - - - 465 - - - - _port - - - - 466 - - - - _button - - - - 467 - - - - _info - - - - 472 - - - - delegate - - - - 481 - - - - orderFrontStandardAboutPanel: - - - - 501 - - - - - YES - - 0 - - YES - - - - - - -2 - - - RmlsZSdzIE93bmVyA - - - -1 - - - First Responder - - - -3 - - - Application - - - 29 - - - YES - - - - MainMenu - - - 56 - - - YES - - - - - - 57 - - - YES - - - - - - - - - - - - 134 - - - - - 150 - - - - - 136 - - - 1111 - - - 149 - - - - - 145 - - - - - 371 - - - YES - - - - Window (Window) - - - 372 - - - YES - - - - - - - - 420 - - - - - 458 - - - YES - - - - - - 459 - - - - - 463 - - - - - 469 - - - YES - - - - - - 470 - - - - - 486 - - - YES - - - - - - - - - 450 - - - YES - - - - - - 451 - - - - - 452 - - - YES - - - - - - 453 - - - - - 454 - - - YES - - - - - - 455 - - - - - 456 - - - YES - - - - - - 457 - - - - - 498 - - - - - 499 - - - - - - - YES - - YES - -1.IBPluginDependency - -2.IBPluginDependency - -3.IBPluginDependency - 134.IBPluginDependency - 134.ImportedFromIB2 - 136.IBPluginDependency - 136.ImportedFromIB2 - 145.IBPluginDependency - 145.ImportedFromIB2 - 149.IBPluginDependency - 149.ImportedFromIB2 - 150.IBPluginDependency - 150.ImportedFromIB2 - 29.IBEditorWindowLastContentRect - 29.IBPluginDependency - 29.ImportedFromIB2 - 29.WindowOrigin - 29.editorWindowContentRectSynchronizationRect - 371.IBEditorWindowLastContentRect - 371.IBWindowTemplateEditedContentRect - 371.NSWindowTemplate.visibleAtLaunch - 371.editorWindowContentRectSynchronizationRect - 371.windowTemplate.maxSize - 372.IBPluginDependency - 420.IBPluginDependency - 450.IBPluginDependency - 451.IBPluginDependency - 452.IBPluginDependency - 453.IBPluginDependency - 454.IBPluginDependency - 455.IBPluginDependency - 456.IBPluginDependency - 457.IBPluginDependency - 458.IBPluginDependency - 459.IBPluginDependency - 463.IBPluginDependency - 469.IBPluginDependency - 470.IBPluginDependency - 486.IBPluginDependency - 498.IBPluginDependency - 499.IBPluginDependency - 56.IBPluginDependency - 56.ImportedFromIB2 - 57.IBEditorWindowLastContentRect - 57.IBPluginDependency - 57.ImportedFromIB2 - 57.editorWindowContentRectSynchronizationRect - - - YES - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilderKit - com.apple.InterfaceBuilderKit - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin - - {{88, 622}, {114, 20}} - com.apple.InterfaceBuilder.CocoaPlugin - - {74, 862} - {{6, 978}, {478, 20}} - {{355, 419}, {269, 190}} - {{355, 419}, {269, 190}} - - {{33, 99}, {480, 360}} - {3.40282e+38, 3.40282e+38} - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - {{100, 499}, {206, 123}} - com.apple.InterfaceBuilder.CocoaPlugin - - {{23, 794}, {245, 183}} - - - - YES - - YES - - - YES - - - - - YES - - YES - - - YES - - - - 501 - - - - YES - - NSObject - - startstop: - id - - - IBUserSource - - - - - TongsengController - NSObject - - YES - - YES - start: - startstop: - stop: - - - YES - id - id - id - - - - YES - - YES - _button - _hostname - _info - _port - - - YES - NSButton - NSTextField - NSTextField - NSTextField - - - - IBProjectSource - TongsengController.h - - - - TongsengController - NSObject - - IBUserSource - - - - - - 0 - ../TongsengApp.xcodeproj - 3 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TongsengApp/Info.plist b/TongsengApp/Info.plist index ce57a49..f5fa2ee 100644 --- a/TongsengApp/Info.plist +++ b/TongsengApp/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile - + TUIO CFBundleIdentifier id.web.fajran.${PRODUCT_NAME:identifier} CFBundleInfoDictionaryVersion @@ -19,7 +19,7 @@ CFBundleSignature ???? CFBundleVersion - 0.4 + 0.5 NSMainNibFile MainMenu NSPrincipalClass diff --git a/TongsengApp/TUIO.icns b/TongsengApp/TUIO.icns new file mode 100644 index 0000000..b1a9064 Binary files /dev/null and b/TongsengApp/TUIO.icns differ diff --git a/TongsengApp/TongsengApp.xcodeproj/TemplateIcon.icns b/TongsengApp/TongsengApp.xcodeproj/TemplateIcon.icns deleted file mode 100644 index 62cb701..0000000 Binary files a/TongsengApp/TongsengApp.xcodeproj/TemplateIcon.icns and /dev/null differ diff --git a/TongsengApp/TongsengApp.xcodeproj/project.pbxproj b/TongsengApp/TongsengApp.xcodeproj/project.pbxproj index d650e70..69d7c33 100644 --- a/TongsengApp/TongsengApp.xcodeproj/project.pbxproj +++ b/TongsengApp/TongsengApp.xcodeproj/project.pbxproj @@ -3,16 +3,14 @@ archiveVersion = 1; classes = { }; - objectVersion = 45; + objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; }; - 3F45D5AA10A0FEEB00139241 /* TuioBlob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F45D5A410A0FEEB00139241 /* TuioBlob.cpp */; }; 3F45D5AB10A0FEEB00139241 /* TuioContainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F45D5A510A0FEEB00139241 /* TuioContainer.cpp */; }; 3F45D5AC10A0FEEB00139241 /* TuioCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F45D5A610A0FEEB00139241 /* TuioCursor.cpp */; }; 3F45D5AD10A0FEEB00139241 /* TuioDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F45D5A710A0FEEB00139241 /* TuioDispatcher.cpp */; }; - 3F45D5AE10A0FEEB00139241 /* TuioObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F45D5A810A0FEEB00139241 /* TuioObject.cpp */; }; 3F45D5AF10A0FEEB00139241 /* TuioPoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F45D5A910A0FEEB00139241 /* TuioPoint.cpp */; }; 3F6CB36A10374F0C00CFF31E /* tongseng.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F6CB36810374F0C00CFF31E /* tongseng.cpp */; }; 3F6CB3C010374FB900CFF31E /* NetworkingUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F6CB39010374FB900CFF31E /* NetworkingUtils.cpp */; }; @@ -25,29 +23,26 @@ 3F6CB43A10375A6000CFF31E /* TongsengController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F6CB43810375A6000CFF31E /* TongsengController.m */; }; 3FAF0802103963CD006DF045 /* TuioManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FAF0800103963CD006DF045 /* TuioManager.cpp */; }; 3FAF0803103963CD006DF045 /* UdpSender.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3FAF0801103963CD006DF045 /* UdpSender.cpp */; }; - 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + B26C5F031D12EDF500354F09 /* OneEuroFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B26C5F021D12EDF500354F09 /* OneEuroFilter.cpp */; }; + B26C5F051D12EF5300354F09 /* TuioObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B26C5F041D12EF5300354F09 /* TuioObject.cpp */; }; + B26C5F071D12EF5A00354F09 /* TuioBlob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B26C5F061D12EF5A00354F09 /* TuioBlob.cpp */; }; + B26C5F091D12F2E000354F09 /* TUIO.icns in Resources */ = {isa = PBXBuildFile; fileRef = B26C5F081D12F2E000354F09 /* TUIO.icns */; }; + B2A01DF71D1C1D5900EF381B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2A01DF61D1C1D5900EF381B /* CoreFoundation.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; - 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; 1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; - 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; - 32CA4F630368D1EE00C91783 /* TongsengApp_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TongsengApp_Prefix.pch; sourceTree = ""; }; - 3F45D5A410A0FEEB00139241 /* TuioBlob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TuioBlob.cpp; sourceTree = ""; }; 3F45D5A510A0FEEB00139241 /* TuioContainer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TuioContainer.cpp; sourceTree = ""; }; 3F45D5A610A0FEEB00139241 /* TuioCursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TuioCursor.cpp; sourceTree = ""; }; 3F45D5A710A0FEEB00139241 /* TuioDispatcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TuioDispatcher.cpp; sourceTree = ""; }; - 3F45D5A810A0FEEB00139241 /* TuioObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TuioObject.cpp; sourceTree = ""; }; 3F45D5A910A0FEEB00139241 /* TuioPoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TuioPoint.cpp; sourceTree = ""; }; - 3F6CB36810374F0C00CFF31E /* tongseng.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tongseng.cpp; path = ../tongseng.cpp; sourceTree = SOURCE_ROOT; }; + 3F6CB36810374F0C00CFF31E /* tongseng.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp.preprocessed; fileEncoding = 4; name = tongseng.cpp; path = ../tongseng.cpp; sourceTree = SOURCE_ROOT; }; 3F6CB36910374F0C00CFF31E /* tongseng.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tongseng.h; path = ../tongseng.h; sourceTree = SOURCE_ROOT; }; - 3F6CB36B10374F1600CFF31E /* mt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mt.h; path = ../mt.h; sourceTree = SOURCE_ROOT; }; + 3F6CB36B10374F1600CFF31E /* multitouch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = multitouch.h; path = ../multitouch.h; sourceTree = SOURCE_ROOT; }; 3F6CB39010374FB900CFF31E /* NetworkingUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkingUtils.cpp; sourceTree = ""; }; 3F6CB39210374FB900CFF31E /* UdpSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UdpSocket.cpp; sourceTree = ""; }; 3F6CB39E10374FB900CFF31E /* OscOutboundPacketStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OscOutboundPacketStream.cpp; sourceTree = ""; }; @@ -61,6 +56,11 @@ 3FAF0801103963CD006DF045 /* UdpSender.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UdpSender.cpp; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* Tongseng.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Tongseng.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B26C5F021D12EDF500354F09 /* OneEuroFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OneEuroFilter.cpp; sourceTree = ""; }; + B26C5F041D12EF5300354F09 /* TuioObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TuioObject.cpp; sourceTree = ""; }; + B26C5F061D12EF5A00354F09 /* TuioBlob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TuioBlob.cpp; sourceTree = ""; }; + B26C5F081D12F2E000354F09 /* TUIO.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = TUIO.icns; sourceTree = ""; }; + B2A01DF61D1C1D5900EF381B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -70,6 +70,7 @@ files = ( 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 3F6CB41F103754BC00CFF31E /* MultitouchSupport.framework in Frameworks */, + B2A01DF71D1C1D5900EF381B /* CoreFoundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -88,22 +89,13 @@ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( + B2A01DF61D1C1D5900EF381B /* CoreFoundation.framework */, + 3F6CB41E103754BC00CFF31E /* MultitouchSupport.framework */, 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; - 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { - isa = PBXGroup; - children = ( - 3F6CB41E103754BC00CFF31E /* MultitouchSupport.framework */, - 29B97324FDCFA39411CA2CEA /* AppKit.framework */, - 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, - 29B97325FDCFA39411CA2CEA /* Foundation.framework */, - ); - name = "Other Frameworks"; - sourceTree = ""; - }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( @@ -129,10 +121,9 @@ children = ( 3F6CB3F31037541700CFF31E /* TUIO */, 3F6CB38710374FB900CFF31E /* oscpack */, - 3F6CB36B10374F1600CFF31E /* mt.h */, + 3F6CB36B10374F1600CFF31E /* multitouch.h */, 3F6CB36810374F0C00CFF31E /* tongseng.cpp */, 3F6CB36910374F0C00CFF31E /* tongseng.h */, - 32CA4F630368D1EE00C91783 /* TongsengApp_Prefix.pch */, 29B97316FDCFA39411CA2CEA /* main.m */, ); name = "Other Sources"; @@ -141,8 +132,8 @@ 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( + B26C5F081D12F2E000354F09 /* TUIO.icns */, 8D1107310486CEB800E47090 /* Info.plist */, - 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, 1DDD58140DA1D0A300B32029 /* MainMenu.xib */, ); name = Resources; @@ -152,7 +143,6 @@ isa = PBXGroup; children = ( 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, - 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; @@ -196,11 +186,12 @@ 3F6CB3F31037541700CFF31E /* TUIO */ = { isa = PBXGroup; children = ( - 3F45D5A410A0FEEB00139241 /* TuioBlob.cpp */, + B26C5F061D12EF5A00354F09 /* TuioBlob.cpp */, + B26C5F041D12EF5300354F09 /* TuioObject.cpp */, + B26C5F021D12EDF500354F09 /* OneEuroFilter.cpp */, 3F45D5A510A0FEEB00139241 /* TuioContainer.cpp */, 3F45D5A610A0FEEB00139241 /* TuioCursor.cpp */, 3F45D5A710A0FEEB00139241 /* TuioDispatcher.cpp */, - 3F45D5A810A0FEEB00139241 /* TuioObject.cpp */, 3F45D5A910A0FEEB00139241 /* TuioPoint.cpp */, 3FAF0800103963CD006DF045 /* TuioManager.cpp */, 3FAF0801103963CD006DF045 /* UdpSender.cpp */, @@ -237,9 +228,16 @@ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; + attributes = { + LastUpgradeCheck = 0730; + }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "TongsengApp" */; - compatibilityVersion = "Xcode 3.1"; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; hasScannedForEncodings = 1; + knownRegions = ( + en, + ); mainGroup = 29B97314FDCFA39411CA2CEA /* TongsengApp */; projectDirPath = ""; projectRoot = ""; @@ -254,7 +252,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, + B26C5F091D12F2E000354F09 /* TUIO.icns in Resources */, 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -271,32 +269,25 @@ 3F6CB3C010374FB900CFF31E /* NetworkingUtils.cpp in Sources */, 3F6CB3C210374FB900CFF31E /* UdpSocket.cpp in Sources */, 3F6CB3C710374FB900CFF31E /* OscOutboundPacketStream.cpp in Sources */, + B26C5F031D12EDF500354F09 /* OneEuroFilter.cpp in Sources */, 3F6CB3CD10374FB900CFF31E /* OscTypes.cpp in Sources */, 3F6CB4061037541700CFF31E /* TuioServer.cpp in Sources */, 3F6CB4081037541700CFF31E /* TuioTime.cpp in Sources */, 3F6CB43A10375A6000CFF31E /* TongsengController.m in Sources */, 3FAF0802103963CD006DF045 /* TuioManager.cpp in Sources */, 3FAF0803103963CD006DF045 /* UdpSender.cpp in Sources */, - 3F45D5AA10A0FEEB00139241 /* TuioBlob.cpp in Sources */, + B26C5F051D12EF5300354F09 /* TuioObject.cpp in Sources */, 3F45D5AB10A0FEEB00139241 /* TuioContainer.cpp in Sources */, 3F45D5AC10A0FEEB00139241 /* TuioCursor.cpp in Sources */, 3F45D5AD10A0FEEB00139241 /* TuioDispatcher.cpp in Sources */, - 3F45D5AE10A0FEEB00139241 /* TuioObject.cpp in Sources */, 3F45D5AF10A0FEEB00139241 /* TuioPoint.cpp in Sources */, + B26C5F071D12EF5A00354F09 /* TuioBlob.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ - 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 089C165DFE840E0CC02AAC07 /* English */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; 1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( @@ -321,8 +312,7 @@ GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = TongsengApp_Prefix.pch; + GCC_PRECOMPILE_PREFIX_HEADER = NO; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; PRODUCT_NAME = Tongseng; @@ -339,8 +329,7 @@ "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", ); GCC_MODEL_TUNING = G5; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = TongsengApp_Prefix.pch; + GCC_PRECOMPILE_PREFIX_HEADER = NO; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; PRODUCT_NAME = Tongseng; @@ -350,40 +339,37 @@ C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - GCC_C_LANGUAGE_STANDARD = c99; + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + GCC_C_LANGUAGE_STANDARD = "compiler-default"; GCC_OPTIMIZATION_LEVEL = 0; - GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_ABOUT_RETURN_TYPE = NO; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( ../oscpack, ../TUIO, ); - ONLY_ACTIVE_ARCH = NO; - PREBINDING = NO; - SDKROOT = ""; - VALID_ARCHS = i386; + MACOSX_DEPLOYMENT_TARGET = 10.6; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + VALID_ARCHS = "i386 x86_64"; }; name = Debug; }; C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = ( - i386, - x86_64, - ); - GCC_C_LANGUAGE_STANDARD = c99; - GCC_WARN_ABOUT_RETURN_TYPE = YES; + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = "compiler-default"; + GCC_WARN_ABOUT_RETURN_TYPE = NO; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( ../oscpack, ../TUIO, ); + MACOSX_DEPLOYMENT_TARGET = 10.6; ONLY_ACTIVE_ARCH = NO; - PREBINDING = NO; - SDKROOT = macosx10.5; - VALID_ARCHS = "x86_64 i386"; + SDKROOT = macosx; + VALID_ARCHS = "i386 x86_64"; }; name = Release; }; diff --git a/TongsengApp/TongsengApp_Prefix.pch b/TongsengApp/TongsengApp_Prefix.pch deleted file mode 100644 index 8988ad2..0000000 --- a/TongsengApp/TongsengApp_Prefix.pch +++ /dev/null @@ -1,7 +0,0 @@ -// -// Prefix header for all source files of the 'TongsengApp' target in the 'TongsengApp' project -// - -#ifdef __OBJC__ - #import -#endif diff --git a/TongsengApp/TongsengController.h b/TongsengApp/TongsengController.h index f818a2b..0a599b6 100644 --- a/TongsengApp/TongsengController.h +++ b/TongsengApp/TongsengController.h @@ -4,6 +4,7 @@ IBOutlet NSTextField *_hostname; IBOutlet NSTextField *_port; IBOutlet NSTextField *_info; + IBOutlet NSPopUpButton *_device; IBOutlet NSButton *_button; bool _running; } diff --git a/TongsengApp/TongsengController.m b/TongsengApp/TongsengController.m index 68806a0..9ef9f0b 100644 --- a/TongsengApp/TongsengController.m +++ b/TongsengApp/TongsengController.m @@ -1,4 +1,5 @@ #import "TongsengController.h" +#import "multitouch.h" #import "tongseng.h" #import @@ -10,6 +11,26 @@ - (id) init { return self; } +- (void)awakeFromNib +{ + + CFArrayRef devList = MTDeviceCreateList(); + CFIndex dev_count = (CFIndex)CFArrayGetCount(devList); + + if(dev_count > 1) { + for (int i=1;i<=dev_count;i++) + [_device addItemWithTitle:@"External"]; + } else if(dev_count == 0) { + [_device removeAllItems]; + [_device addItemWithTitle:@"None"]; + [_button setEnabled:false]; + [_hostname setEnabled:false]; + [_port setEnabled:false]; + [_device setEnabled:false]; + [_info setStringValue:@"Tongseng is disabled"]; + } +} + - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app { [self stop:app]; @@ -25,12 +46,15 @@ - (IBAction)start:(id)sender { const char *hostname = [[_hostname stringValue] UTF8String]; const char *strPort = [[_port stringValue] UTF8String]; const int port = atoi(strPort); - + const int device = [_device indexOfSelectedItem]; + tongseng_set_hostname_and_port(hostname, port); + tongseng_set_device(device); tongseng_start(); [_hostname setEnabled:false]; [_port setEnabled:false]; + [_device setEnabled:false]; [_info setStringValue:@"Tongseng is running"]; [_button setTitle:@"Stop"]; @@ -42,6 +66,7 @@ - (IBAction)stop:(id)sender { [_hostname setEnabled:true]; [_port setEnabled:true]; + [_device setEnabled:true]; [_info setStringValue:@"Tongseng is stopped"]; [_button setTitle:@"Start"]; diff --git a/main.cpp b/main.cpp index 0022303..4317dbb 100644 --- a/main.cpp +++ b/main.cpp @@ -7,12 +7,14 @@ static bool running = false; static bool verbose = false; static std::string host("localhost"); static int port = 3333; +static int device = 0; static void show_help() { - std::cout << "Usage: tongseng [options] [host] [port]" << std::endl; - std::cout << " -v verbose" << std::endl; - std::cout << " -h show help" << std::endl; + std::cout << "Usage: tongseng -n [host] -p [port] -d [device]" << std::endl; + std::cout << " -l list devices" << std::endl; + std::cout << " -v verbose output" << std::endl; + std::cout << " -h show this help" << std::endl; } static void stop(int param) @@ -22,40 +24,42 @@ static void stop(int param) static void init(int argc, char** argv) { - int aflag = 0; - int bflag = 0; - char *cvalue = NULL; - int index; - int c; + char c; - opterr = 0; - - while ((c = getopt(argc, argv, "v")) != -1) { + while ((c = getopt(argc, argv, "n:p:d:lvh")) != -1) { switch (c) { + case 'n': + host = std::string(optarg); + break; + case 'p': + port = atoi(optarg); + break; + case 'd': + device = atoi(optarg); + break; case 'v': verbose = true; break; + case 'l': + tongseng_list_devices(); + exit(0); case 'h': show_help(); exit(0); + /*case '?': + if (optopt == 'n') + fprintf (stderr, "Option -n requires a host name.\n"); + if (optopt == 'p') + fprintf (stderr, "Option -p requires a port number.\n"); + if (optopt == 'd') + fprintf (stderr, "Option -d requires a device number.\n"); + else if (isprint (optopt)) fprintf (stderr, "Unknown option '-%c'.\n", optopt); + else fprintf (stderr, "Unknown option character '\\x%x'.\n", optopt);*/ default: show_help(); exit(1); } } - - for (index=optind, c=0; index < argc; index++, c++) { - switch (c) { - case 0: - host = argv[index]; - break; - case 1: - port = atoi(argv[index]); - break; - default: - break; - } - } } int main(int argc, char** argv) @@ -63,6 +67,7 @@ int main(int argc, char** argv) init(argc, argv); std::cout << "Host: " << host << std::endl; std::cout << "Port: " << port << std::endl; + std::cout << "Device: " << device << std::endl; std::cout << "Verbose: " << verbose << std::endl; std::cout << "Press Ctrl+C to end this program." << std::endl; @@ -73,8 +78,10 @@ int main(int argc, char** argv) tongseng_set_hostname_and_port(host.c_str(), port); tongseng_set_verbose(verbose); + tongseng_set_device(device); tongseng_start(); + // Loop until the program is stopped. running = true; while (running) { diff --git a/mt.h b/mt.h deleted file mode 100644 index 7a5437d..0000000 --- a/mt.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2009 Fajran Iman Rusadi - -// 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., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -// Based on multitouch code from http://www.steike.com/code/multitouch/ - -#ifndef MT_H_ -#define MT_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { float x,y; } mtPoint; -typedef struct { mtPoint pos,vel; } mtReadout; - -typedef struct { - int frame; - double timestamp; - int identifier, state, foo3, foo4; - mtReadout normalized; - float size; - int zero1; - float angle, majorAxis, minorAxis; // ellipsoid - mtReadout mm; - int zero2[2]; - float unk2; -} Finger; - -typedef void* MTDeviceRef; -typedef int (*MTContactCallbackFunction)(int,Finger*,int,double,int); - -MTDeviceRef MTDeviceCreateDefault(); -void MTRegisterContactFrameCallback(MTDeviceRef, MTContactCallbackFunction); -void MTUnregisterContactFrameCallback(MTDeviceRef, MTContactCallbackFunction); -void MTDeviceStart(MTDeviceRef, int); -void MTDeviceStop(MTDeviceRef); -void MTDeviceRelease(MTDeviceRef); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/multitouch.h b/multitouch.h new file mode 100644 index 0000000..af325b9 --- /dev/null +++ b/multitouch.h @@ -0,0 +1,145 @@ +// Copyright (C) 2009 Fajran Iman Rusadi + +// 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#ifndef MULTITOUCH_H +#define MULTITOUCH_H + +#ifdef __OBJC__ +#include +#endif +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct { + float x; + float y; + } MTPoint; + + typedef struct { + MTPoint position; + MTPoint velocity; + } MTVector; + + enum { + MTTouchStateNotTracking = 0, + MTTouchStateStartInRange = 1, + MTTouchStateHoverInRange = 2, + MTTouchStateMakeTouch = 3, + MTTouchStateTouching = 4, + MTTouchStateBreakTouch = 5, + MTTouchStateLingerInRange = 6, + MTTouchStateOutOfRange = 7 + }; + typedef uint32_t MTTouchState; + + typedef struct { + int32_t frame; + double timestamp; + int32_t pathIndex; // "P" (~transducerIndex) + MTTouchState state; + int32_t fingerID; // "F" (~identity) + int32_t handID; // "H" (always 1) + MTVector normalizedVector; + float zTotal; // "ZTot" (~quality, multiple of 1/8 between 0 and 1) + int32_t field9; // always 0 + float angle; + float majorAxis; + float minorAxis; + MTVector absoluteVector; // "mm" + int32_t field14; // always 0 + int32_t field15; // always 0 + float zDensity; // "ZDen" (~density) + } MTTouch; + + typedef void* MTDeviceRef; + + double MTAbsoluteTimeGetCurrent(); + bool MTDeviceIsAvailable(); // true if can create default device + + CFArrayRef MTDeviceCreateList(); // creates for driver types 0, 1, 4, 2, 3 + MTDeviceRef MTDeviceCreateDefault(); + MTDeviceRef MTDeviceCreateFromDeviceID(int64_t); + MTDeviceRef MTDeviceCreateFromService(io_service_t); + MTDeviceRef MTDeviceCreateFromGUID(uuid_t); // GUID's compared by pointer, not value! + void MTDeviceRelease(MTDeviceRef); + + CFRunLoopSourceRef MTDeviceCreateMultitouchRunLoopSource(MTDeviceRef); + OSStatus MTDeviceScheduleOnRunLoop(MTDeviceRef, CFRunLoopRef, CFStringRef); + + OSStatus MTDeviceStart(MTDeviceRef, int); + OSStatus MTDeviceStop(MTDeviceRef); + bool MTDeviceIsRunning(MTDeviceRef); + + bool MTDeviceIsValid(MTDeviceRef); + bool MTDeviceIsBuiltIn(MTDeviceRef) __attribute__ ((weak_import)); // no 10.5 + bool MTDeviceIsOpaqueSurface(MTDeviceRef); + io_service_t MTDeviceGetService(MTDeviceRef); + OSStatus MTDeviceGetSensorSurfaceDimensions(MTDeviceRef, int*, int*); + OSStatus MTDeviceGetFamilyID(MTDeviceRef, int*); + OSStatus MTDeviceGetDeviceID(MTDeviceRef, uint64_t*) __attribute__ ((weak_import)); // no 10.5 + OSStatus MTDeviceGetDriverType(MTDeviceRef, int*); + OSStatus MTDeviceGetActualType(MTDeviceRef, int*); + OSStatus MTDeviceGetGUID(MTDeviceRef, uuid_t*); + + typedef void (*MTFrameCallbackFunction)(MTDeviceRef device, + MTTouch touches[], size_t numTouches, + double timestamp, size_t frame); + void MTRegisterContactFrameCallback(MTDeviceRef, MTFrameCallbackFunction); + void MTUnregisterContactFrameCallback(MTDeviceRef, MTFrameCallbackFunction); + + typedef void (*MTPathCallbackFunction)(MTDeviceRef device, long pathID, long state, MTTouch* touch); + MTPathCallbackFunction MTPathPrintCallback; + void MTRegisterPathCallback(MTDeviceRef, MTPathCallbackFunction); + void MTUnregisterPathCallback(MTDeviceRef, MTPathCallbackFunction); + + /* + // callbacks never called (need different flags?) + typedef void (*MTImageCallbackFunction)(MTDeviceRef, void*, void*); + MTImageCallbackFunction MTImagePrintCallback; + void MTRegisterMultitouchImageCallback(MTDeviceRef, MTImageCallbackFunction); + */ + + /* + // these log error + void MTVibratorRunForDuration(MTDeviceRef,long); + void MTVibratorStop(MTDeviceRef); + */ + + inline const char* + MTTouchStateName(MTTouchState ps) { + switch (ps) { + case MTTouchStateNotTracking: return "NotTracking" ; + case MTTouchStateStartInRange: return "StartInRange" ; + case MTTouchStateHoverInRange: return "HoverInRange" ; + case MTTouchStateMakeTouch: return "MakeTouch" ; + case MTTouchStateTouching: return "Touching" ; + case MTTouchStateBreakTouch: return "BreakTouch" ; + case MTTouchStateLingerInRange: return "LingerInRange" ; + case MTTouchStateOutOfRange: return "OutOfRange" ; + default: return "Unknown" ; + } + } + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/oscpack/changes b/oscpack/changes index 804df95..046c6b6 100644 --- a/oscpack/changes +++ b/oscpack/changes @@ -1,3 +1,94 @@ +April 9, 2013 +------------- + +Changes for the 1.1.0 release (vs 1.0.2) are listed below. Unless +otherwise indicated these changes have been made since +January 2013. The focus has been on general clean-up, fixing bugs, +compiler errors and warnings, and fixing issues on 64 bit platforms. +A few improvements such as support for OSC arrays, functions +for setting broadcast and reuse socket options have been added. +This update merges changes from the openFrameworks version +of oscpack. + + - Added support for arrays in messages (see OscUnitTests.cpp + for example usage). (patch thanks to Tim Blechmann) + + - Fixed bugs relating to 64 bit usage (e.g. crashes in 64 bit + builds on OS X). + + - Some member functions that previously used the "int" or + "unsigned long" type for parameters or return values now use + std::size_t (platform-defined) or + osc_bundle_element_size_t (a.k.a. int32). + This change was made to better support 64 bit platforms. + See SVN revision 70 for details. + + - The previous point introduces a breaking change on Linux/x86_64 + for callers of AsBlob() and AsBlobUnchecked(): + The type of the second argument (the "size" argument) to + ReceivedMessageArgument::AsBlob() and + ReceivedMessageArgument::AsBlobUnchecked() has changed + from unsigned long & to osc_bundle_element_size_t (an int32). + You should declare your size argument variables as + osc_bundle_element_size_t to avoid incompatibilities between + 32 and 64 bit builds. + + - Note that oscpack does not support packets larger than + 0x7FFFFFFC (see comments in class ReceivedPacket for + details). + + - Oscpack defines an osc::Nil value used for sending the nil + message argument value. This conflicts with Objective-C. + Therefore osc::Nil is no longer defined in Obj-C++ code. + There is now an osc::OscNil value, which should be preferred. + osc::Nil is still available when writing C++. + (fix thanks to openFrameworks) + + - Added UdpSocket::SetEnableBroadcast(). This needs to + be called to enable sending to the broadcast address on some + platforms (e.g. Mac OS X). (thanks to openFrameworks) + + - Added UdpSocket::SetAllowReuse(). This is useful for + sharing sockets on some platforms (Mac?), and not so useful + on other platforms. (thanks to openFrameworks) + + - Added IpEndpointName::IsMulticastAddress() (2010) + + - Cleaned up C++ header usage and std:: namespace usage + to be more standards compliant (fixes issues on recent compilers + such as clang and gcc4.6). + + - Improved host endianness detection. Should auto-detect + endianness on most platforms now. + (thanks to Tim Blechmann for help with this) + + - Fixed two memory leaks: (1) in OscPrintReceivedElements.cpp + when printing time tag message arguments (thanks to Gwydion ap Dafydd). + (2) in the posix SocketReceiveMultiplexer::Run() method if an exception + was thrown while listening. + + - Fixed bug in posix SocketReceiveMultiplexer::Run() that would cause + packets to stop being received if select() returned EINTR. + (thanks to Björn Wöldecke) + + - Updated and improved Makefile to avoid redundant re-linking + (thanks to Douglas Mandell) + + - Added CMakeLists.txt CMake build file (2010, thanks to David Doria) + + - Switched license to plain MIT license with non binding request + for contribution of improvements (same as current PortAudio + boilerplate). See LICENSE file. + +Thanks to Tim Blechmann, Rob Canning, Gwydion ap Dafydd, David Doria, +Christopher Delaney, Jon McCormack, Douglas Mandell, Björn Wöldecke, +all the guys at openFrameworks, and everyone who reported bugs, +submitted patches and helped out with testing this release. + +Thanks to Syneme at the University of Calgary for providing financial +support for the 1.1.0 update. + + September 28, 2005 ------------------ @@ -11,14 +102,14 @@ spawn your own threads in a more complex application. The list below summarises the changes if you are porting code from the previous release. - - there are no longer any threads in oscpack. if you need to + - There are no longer any threads in oscpack. if you need to set up an asynchronous listener you can create your own thread and call Run on an instance of SocketReceiveMultiplexer or UdpListeningReceiveSocket (see ip/UdpSocket.h) yourself. - - host byte order is now used for network (IP) addresses + - Host byte order is now used for network (IP) addresses - - functions which used to take two parameters + - Functions which used to take two parameters now take an instance of IpEndpointName (see ip/IpEndpointName.h) this class has a number of convenient constructors for converting numbers and strings to internet diff --git a/oscpack/ip/IpEndpointName.cpp b/oscpack/ip/IpEndpointName.cpp index 33fdd98..556da3a 100644 --- a/oscpack/ip/IpEndpointName.cpp +++ b/oscpack/ip/IpEndpointName.cpp @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,9 +23,20 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ #include "IpEndpointName.h" -#include +#include #include "NetworkingUtils.h" @@ -43,9 +50,9 @@ unsigned long IpEndpointName::GetHostByName( const char *s ) void IpEndpointName::AddressAsString( char *s ) const { if( address == ANY_ADDRESS ){ - sprintf( s, "" ); + std::sprintf( s, "" ); }else{ - sprintf( s, "%d.%d.%d.%d", + std::sprintf( s, "%d.%d.%d.%d", (int)((address >> 24) & 0xFF), (int)((address >> 16) & 0xFF), (int)((address >> 8) & 0xFF), @@ -58,9 +65,9 @@ void IpEndpointName::AddressAndPortAsString( char *s ) const { if( port == ANY_PORT ){ if( address == ANY_ADDRESS ){ - sprintf( s, ":" ); + std::sprintf( s, ":" ); }else{ - sprintf( s, "%d.%d.%d.%d:", + std::sprintf( s, "%d.%d.%d.%d:", (int)((address >> 24) & 0xFF), (int)((address >> 16) & 0xFF), (int)((address >> 8) & 0xFF), @@ -68,9 +75,9 @@ void IpEndpointName::AddressAndPortAsString( char *s ) const } }else{ if( address == ANY_ADDRESS ){ - sprintf( s, ":%d", port ); + std::sprintf( s, ":%d", port ); }else{ - sprintf( s, "%d.%d.%d.%d:%d", + std::sprintf( s, "%d.%d.%d.%d:%d", (int)((address >> 24) & 0xFF), (int)((address >> 16) & 0xFF), (int)((address >> 8) & 0xFF), diff --git a/oscpack/ip/IpEndpointName.h b/oscpack/ip/IpEndpointName.h index c7b078e..4b3159a 100644 --- a/oscpack/ip/IpEndpointName.h +++ b/oscpack/ip/IpEndpointName.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,8 +23,19 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_IPENDPOINTNAME_H -#define INCLUDED_IPENDPOINTNAME_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_IPENDPOINTNAME_H +#define INCLUDED_OSCPACK_IPENDPOINTNAME_H class IpEndpointName{ @@ -54,6 +61,8 @@ class IpEndpointName{ unsigned long address; int port; + bool IsMulticastAddress() const { return ((address >> 24) & 0xFF) >= 224 && ((address >> 24) & 0xFF) <= 239; } + enum { ADDRESS_STRING_LENGTH=17 }; void AddressAsString( char *s ) const; @@ -71,4 +80,4 @@ inline bool operator!=( const IpEndpointName& lhs, const IpEndpointName& rhs ) return !(lhs == rhs); } -#endif /* INCLUDED_IPENDPOINTNAME_H */ +#endif /* INCLUDED_OSCPACK_IPENDPOINTNAME_H */ diff --git a/oscpack/ip/NetworkingUtils.h b/oscpack/ip/NetworkingUtils.h index 0d6901c..516e9d2 100644 --- a/oscpack/ip/NetworkingUtils.h +++ b/oscpack/ip/NetworkingUtils.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,8 +23,19 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_NETWORKINGUTILS_H -#define INCLUDED_NETWORKINGUTILS_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_NETWORKINGUTILS_H +#define INCLUDED_OSCPACK_NETWORKINGUTILS_H // in general NetworkInitializer is only used internally, but if you're @@ -46,4 +53,4 @@ class NetworkInitializer{ unsigned long GetHostByName( const char *name ); -#endif /* INCLUDED_NETWORKINGUTILS_H */ +#endif /* INCLUDED_OSCPACK_NETWORKINGUTILS_H */ diff --git a/oscpack/ip/PacketListener.h b/oscpack/ip/PacketListener.h index 6647209..2a8cf63 100644 --- a/oscpack/ip/PacketListener.h +++ b/oscpack/ip/PacketListener.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,8 +23,19 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_PACKETLISTENER_H -#define INCLUDED_PACKETLISTENER_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_PACKETLISTENER_H +#define INCLUDED_OSCPACK_PACKETLISTENER_H class IpEndpointName; @@ -40,4 +47,4 @@ class PacketListener{ const IpEndpointName& remoteEndpoint ) = 0; }; -#endif /* INCLUDED_PACKETLISTENER_H */ +#endif /* INCLUDED_OSCPACK_PACKETLISTENER_H */ diff --git a/oscpack/ip/TimerListener.h b/oscpack/ip/TimerListener.h index 82b1181..61e262b 100644 --- a/oscpack/ip/TimerListener.h +++ b/oscpack/ip/TimerListener.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,8 +23,19 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_TIMERLISTENER_H -#define INCLUDED_TIMERLISTENER_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_TIMERLISTENER_H +#define INCLUDED_OSCPACK_TIMERLISTENER_H class TimerListener{ @@ -37,4 +44,4 @@ class TimerListener{ virtual void TimerExpired() = 0; }; -#endif /* INCLUDED_TIMERLISTENER_H */ +#endif /* INCLUDED_OSCPACK_TIMERLISTENER_H */ diff --git a/oscpack/ip/UdpSocket.h b/oscpack/ip/UdpSocket.h index 6d9c26d..8bebb27 100644 --- a/oscpack/ip/UdpSocket.h +++ b/oscpack/ip/UdpSocket.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,16 +23,24 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_UDPSOCKET_H -#define INCLUDED_UDPSOCKET_H -#ifndef INCLUDED_NETWORKINGUTILITIES_H -#include "NetworkingUtils.h" -#endif /* INCLUDED_NETWORKINGUTILITIES_H */ +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_UDPSOCKET_H +#define INCLUDED_OSCPACK_UDPSOCKET_H -#ifndef INCLUDED_IPENDPOINTNAME_H +#include // size_t + +#include "NetworkingUtils.h" #include "IpEndpointName.h" -#endif /* INCLUDED_IPENDPOINTNAME_H */ class PacketListener; @@ -80,26 +84,40 @@ class UdpSocket{ public: - // ctor throws std::runtime_error if there's a problem + // Ctor throws std::runtime_error if there's a problem // initializing the socket. UdpSocket(); virtual ~UdpSocket(); - // the socket is created in an unbound, unconnected state + // Enable broadcast addresses (e.g. x.x.x.255) + // Sets SO_BROADCAST socket option. + void SetEnableBroadcast( bool enableBroadcast ); + + // Enable multiple listeners for a single port on same + // network interface* + // Sets SO_REUSEADDR (also SO_REUSEPORT on OS X). + // [*] The exact behavior of SO_REUSEADDR and + // SO_REUSEPORT is undefined for some common cases + // and may have drastically different behavior on different + // operating systems. + void SetAllowReuse( bool allowReuse ); + + + // The socket is created in an unbound, unconnected state // such a socket can only be used to send to an arbitrary // address using SendTo(). To use Send() you need to first // connect to a remote endpoint using Connect(). To use // ReceiveFrom you need to first bind to a local endpoint // using Bind(). - // retrieve the local endpoint name when sending to 'to' - IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const; + // Retrieve the local endpoint name when sending to 'to' + IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const; // Connect to a remote endpoint which is used as the target // for calls to Send() void Connect( const IpEndpointName& remoteEndpoint ); - void Send( const char *data, int size ); - void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size ); + void Send( const char *data, std::size_t size ); + void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ); // Bind a local endpoint to receive incoming data. Endpoint @@ -107,7 +125,7 @@ class UdpSocket{ void Bind( const IpEndpointName& localEndpoint ); bool IsBound() const; - int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ); + std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ); }; @@ -155,4 +173,4 @@ class UdpListeningReceiveSocket : public UdpSocket{ }; -#endif /* INCLUDED_UDPSOCKET_H */ +#endif /* INCLUDED_OSCPACK_UDPSOCKET_H */ diff --git a/oscpack/ip/posix/NetworkingUtils.cpp b/oscpack/ip/posix/NetworkingUtils.cpp index 3b1da79..51daca3 100644 --- a/oscpack/ip/posix/NetworkingUtils.cpp +++ b/oscpack/ip/posix/NetworkingUtils.cpp @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,13 +23,24 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ #include "ip/NetworkingUtils.h" #include #include #include -#include -#include + +#include @@ -49,7 +56,7 @@ unsigned long GetHostByName( const char *name ) struct hostent *h = gethostbyname( name ); if( h ){ struct in_addr a; - memcpy( &a, h->h_addr_list[0], h->h_length ); + std::memcpy( &a, h->h_addr_list[0], h->h_length ); result = ntohl(a.s_addr); } diff --git a/oscpack/ip/posix/UdpSocket.cpp b/oscpack/ip/posix/UdpSocket.cpp index f5feb00..4fa6204 100644 --- a/oscpack/ip/posix/UdpSocket.cpp +++ b/oscpack/ip/posix/UdpSocket.cpp @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,16 +23,18 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "ip/UdpSocket.h" -#include -#include -#include -#include -#include -#include -#include -#include // for memset +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "ip/UdpSocket.h" #include #include @@ -48,19 +46,30 @@ #include #include // for sockaddr_in +#include +#include +#include +#include + +#include +#include +#include // for memset +#include +#include + #include "ip/PacketListener.h" #include "ip/TimerListener.h" #if defined(__APPLE__) && !defined(_SOCKLEN_T) -// pre system 10.3 didn have socklen_t +// pre system 10.3 didn't have socklen_t typedef ssize_t socklen_t; #endif static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) { - memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); + std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = @@ -107,9 +116,7 @@ class UdpSocket::Implementation{ throw std::runtime_error("unable to create udp socket\n"); } - int on=1; - setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on)); - memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); + std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); sendToAddr_.sin_family = AF_INET; } @@ -118,6 +125,24 @@ class UdpSocket::Implementation{ if (socket_ != -1) close(socket_); } + void SetEnableBroadcast( bool enableBroadcast ) + { + int broadcast = (enableBroadcast) ? 1 : 0; // int on posix + setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); + } + + void SetAllowReuse( bool allowReuse ) + { + int reuseAddr = (allowReuse) ? 1 : 0; // int on posix + setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)); + +#ifdef __APPLE__ + // needed also for OS X - enable multiple listeners for a single port on same network interface + int reusePort = (allowReuse) ? 1 : 0; // int on posix + setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort)); +#endif + } + IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const { assert( isBound_ ); @@ -134,7 +159,7 @@ class UdpSocket::Implementation{ // get the address struct sockaddr_in sockAddr; - memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); + std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); socklen_t length = sizeof(sockAddr); if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) { throw std::runtime_error("unable to getsockname\n"); @@ -151,7 +176,7 @@ class UdpSocket::Implementation{ // unconnect from the remote address struct sockaddr_in unconnectSockAddr; - memset( (char *)&unconnectSockAddr, 0, sizeof(unconnectSockAddr ) ); + std::memset( (char *)&unconnectSockAddr, 0, sizeof(unconnectSockAddr ) ); unconnectSockAddr.sin_family = AF_UNSPEC; // address fields are zero int connectResult = connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)); @@ -174,14 +199,14 @@ class UdpSocket::Implementation{ isConnected_ = true; } - void Send( const char *data, int size ) + void Send( const char *data, std::size_t size ) { assert( isConnected_ ); send( socket_, data, size, 0 ); } - void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size ) + void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) { sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address ); sendToAddr_.sin_port = htons( remoteEndpoint.port ); @@ -203,14 +228,14 @@ class UdpSocket::Implementation{ bool IsBound() const { return isBound_; } - int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ) + std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) { assert( isBound_ ); struct sockaddr_in fromAddr; socklen_t fromAddrLen = sizeof(fromAddr); - int result = recvfrom(socket_, data, size, 0, + ssize_t result = recvfrom(socket_, data, size, 0, (struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen); if( result < 0 ) return 0; @@ -218,7 +243,7 @@ class UdpSocket::Implementation{ remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr); remoteEndpoint.port = ntohs(fromAddr.sin_port); - return result; + return (std::size_t)result; } int Socket() { return socket_; } @@ -234,6 +259,16 @@ UdpSocket::~UdpSocket() delete impl_; } +void UdpSocket::SetEnableBroadcast( bool enableBroadcast ) +{ + impl_->SetEnableBroadcast( enableBroadcast ); +} + +void UdpSocket::SetAllowReuse( bool allowReuse ) +{ + impl_->SetAllowReuse( allowReuse ); +} + IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const { return impl_->LocalEndpointFor( remoteEndpoint ); @@ -244,12 +279,12 @@ void UdpSocket::Connect( const IpEndpointName& remoteEndpoint ) impl_->Connect( remoteEndpoint ); } -void UdpSocket::Send( const char *data, int size ) +void UdpSocket::Send( const char *data, std::size_t size ) { impl_->Send( data, size ); } -void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size ) +void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) { impl_->SendTo( remoteEndpoint, data, size ); } @@ -264,7 +299,7 @@ bool UdpSocket::IsBound() const return impl_->IsBound(); } -int UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ) +std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) { return impl_->ReceiveFrom( remoteEndpoint, data, size ); } @@ -370,106 +405,123 @@ class SocketReceiveMultiplexer::Implementation{ void Run() { break_ = false; - - // configure the master fd_set for select() - - fd_set masterfds, tempfds; - FD_ZERO( &masterfds ); - FD_ZERO( &tempfds ); - - // in addition to listening to the inbound sockets we - // also listen to the asynchronous break pipe, so that AsynchronousBreak() - // can break us out of select() from another thread. - FD_SET( breakPipe_[0], &masterfds ); - int fdmax = breakPipe_[0]; - - for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); - i != socketListeners_.end(); ++i ){ - - if( fdmax < i->second->impl_->Socket() ) - fdmax = i->second->impl_->Socket(); - FD_SET( i->second->impl_->Socket(), &masterfds ); - } - - - // configure the timer queue - double currentTimeMs = GetCurrentTimeMs(); - - // expiry time ms, listener - std::vector< std::pair< double, AttachedTimerListener > > timerQueue_; - for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); - i != timerListeners_.end(); ++i ) - timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) ); - std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); - - const int MAX_BUFFER_SIZE = 4098; - char *data = new char[ MAX_BUFFER_SIZE ]; - IpEndpointName remoteEndpoint; - - struct timeval timeout; - - while( !break_ ){ - tempfds = masterfds; - - struct timeval *timeoutPtr = 0; - if( !timerQueue_.empty() ){ - double timeoutMs = timerQueue_.front().first - GetCurrentTimeMs(); - if( timeoutMs < 0 ) - timeoutMs = 0; - - // 1000000 microseconds in a second - timeout.tv_sec = (long)(timeoutMs * .001); - timeout.tv_usec = (long)((timeoutMs - (timeout.tv_sec * 1000)) * 1000); - timeoutPtr = &timeout; - } - - if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 && errno != EINTR ){ - if (!break_) throw std::runtime_error("select failed\n"); - else break; - } - - if ( FD_ISSET( breakPipe_[0], &tempfds ) ){ - // clear pending data from the asynchronous break pipe - char c; - ssize_t ret; - ret = read( breakPipe_[0], &c, 1 ); - } - - if( break_ ) - break; - - for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); - i != socketListeners_.end(); ++i ){ - - if( FD_ISSET( i->second->impl_->Socket(), &tempfds ) ){ - - int size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); - if( size > 0 ){ - i->first->ProcessPacket( data, size, remoteEndpoint ); - if( break_ ) - break; - } - } - } - - // execute any expired timers - currentTimeMs = GetCurrentTimeMs(); - bool resort = false; - for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin(); - i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){ - - i->second.listener->TimerExpired(); - if( break_ ) - break; - - i->first += i->second.periodMs; - resort = true; - } - if( resort ) - std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); - } - - delete [] data; + char *data = 0; + + try{ + + // configure the master fd_set for select() + + fd_set masterfds, tempfds; + FD_ZERO( &masterfds ); + FD_ZERO( &tempfds ); + + // in addition to listening to the inbound sockets we + // also listen to the asynchronous break pipe, so that AsynchronousBreak() + // can break us out of select() from another thread. + FD_SET( breakPipe_[0], &masterfds ); + int fdmax = breakPipe_[0]; + + for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); + i != socketListeners_.end(); ++i ){ + + if( fdmax < i->second->impl_->Socket() ) + fdmax = i->second->impl_->Socket(); + FD_SET( i->second->impl_->Socket(), &masterfds ); + } + + + // configure the timer queue + double currentTimeMs = GetCurrentTimeMs(); + + // expiry time ms, listener + std::vector< std::pair< double, AttachedTimerListener > > timerQueue_; + for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); + i != timerListeners_.end(); ++i ) + timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) ); + std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); + + const int MAX_BUFFER_SIZE = 4098; + data = new char[ MAX_BUFFER_SIZE ]; + IpEndpointName remoteEndpoint; + + struct timeval timeout; + + while( !break_ ){ + tempfds = masterfds; + + struct timeval *timeoutPtr = 0; + if( !timerQueue_.empty() ){ + double timeoutMs = timerQueue_.front().first - GetCurrentTimeMs(); + if( timeoutMs < 0 ) + timeoutMs = 0; + + long timoutSecondsPart = (long)(timeoutMs * .001); + timeout.tv_sec = (time_t)timoutSecondsPart; + // 1000000 microseconds in a second + timeout.tv_usec = (suseconds_t)((timeoutMs - (timoutSecondsPart * 1000)) * 1000); + timeoutPtr = &timeout; + } + + if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 ){ + if( break_ ){ + break; + }else if( errno == EINTR ){ + // on returning an error, select() doesn't clear tempfds. + // so tempfds would remain all set, which would cause read( breakPipe_[0]... + // below to block indefinitely. therefore if select returns EINTR we restart + // the while() loop instead of continuing on to below. + continue; + }else{ + throw std::runtime_error("select failed\n"); + } + } + + if( FD_ISSET( breakPipe_[0], &tempfds ) ){ + // clear pending data from the asynchronous break pipe + char c; + read( breakPipe_[0], &c, 1 ); + } + + if( break_ ) + break; + + for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); + i != socketListeners_.end(); ++i ){ + + if( FD_ISSET( i->second->impl_->Socket(), &tempfds ) ){ + + std::size_t size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); + if( size > 0 ){ + i->first->ProcessPacket( data, (int)size, remoteEndpoint ); + if( break_ ) + break; + } + } + } + + // execute any expired timers + currentTimeMs = GetCurrentTimeMs(); + bool resort = false; + for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin(); + i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){ + + i->second.listener->TimerExpired(); + if( break_ ) + break; + + i->first += i->second.periodMs; + resort = true; + } + if( resort ) + std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); + } + + delete [] data; + }catch(...){ + if( data ) + delete [] data; + throw; + } } void Break() @@ -482,8 +534,7 @@ class SocketReceiveMultiplexer::Implementation{ break_ = true; // Send a termination message to the asynchronous break pipe, so select() will return - ssize_t ret; - ret = write( breakPipe_[1], "!", 1 ); + write( breakPipe_[1], "!", 1 ); } }; diff --git a/oscpack/ip/win32/NetworkingUtils.cpp b/oscpack/ip/win32/NetworkingUtils.cpp index 071a758..ded5305 100644 --- a/oscpack/ip/win32/NetworkingUtils.cpp +++ b/oscpack/ip/win32/NetworkingUtils.cpp @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,12 +23,23 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ #include "ip/NetworkingUtils.h" #include // this must come first to prevent errors with MSVC7 #include -#include -#include + +#include static LONG initCount_ = 0; @@ -80,7 +87,7 @@ unsigned long GetHostByName( const char *name ) struct hostent *h = gethostbyname( name ); if( h ){ struct in_addr a; - memcpy( &a, h->h_addr_list[0], h->h_length ); + std::memcpy( &a, h->h_addr_list[0], h->h_length ); result = ntohl(a.s_addr); } diff --git a/oscpack/ip/win32/UdpSocket.cpp b/oscpack/ip/win32/UdpSocket.cpp index 6f59bef..f4543fb 100644 --- a/oscpack/ip/win32/UdpSocket.cpp +++ b/oscpack/ip/win32/UdpSocket.cpp @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,17 +23,35 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "ip/UdpSocket.h" + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ #include // this must come first to prevent errors with MSVC7 #include #include // for timeGetTime() -#include +#ifndef WINCE +#include +#endif + #include +#include +#include // for memset #include -#include -#include +#include + +#include "ip/UdpSocket.h" // usually I'd include the module header first + // but this is causing conflicts with BCB4 due to + // std::size_t usage. #include "ip/NetworkingUtils.h" #include "ip/PacketListener.h" @@ -49,7 +63,7 @@ typedef int socklen_t; static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) { - memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); + std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = @@ -98,9 +112,7 @@ class UdpSocket::Implementation{ throw std::runtime_error("unable to create udp socket\n"); } - int on=1; - setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on)); - memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); + std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); sendToAddr_.sin_family = AF_INET; } @@ -109,6 +121,22 @@ class UdpSocket::Implementation{ if (socket_ != INVALID_SOCKET) closesocket(socket_); } + void SetEnableBroadcast( bool enableBroadcast ) + { + char broadcast = (char)((enableBroadcast) ? 1 : 0); // char on win32 + setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); + } + + void SetAllowReuse( bool allowReuse ) + { + // Note: SO_REUSEADDR is non-deterministic for listening sockets on Win32. See MSDN article: + // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" + // http://msdn.microsoft.com/en-us/library/ms740621%28VS.85%29.aspx + + char reuseAddr = (char)((allowReuse) ? 1 : 0); // char on win32 + setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)); + } + IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const { assert( isBound_ ); @@ -125,7 +153,7 @@ class UdpSocket::Implementation{ // get the address struct sockaddr_in sockAddr; - memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); + std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); socklen_t length = sizeof(sockAddr); if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) { throw std::runtime_error("unable to getsockname\n"); @@ -164,19 +192,19 @@ class UdpSocket::Implementation{ isConnected_ = true; } - void Send( const char *data, int size ) + void Send( const char *data, std::size_t size ) { assert( isConnected_ ); - send( socket_, data, size, 0 ); + send( socket_, data, (int)size, 0 ); } - void SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size ) + void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) { sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address ); sendToAddr_.sin_port = htons( (short)remoteEndpoint.port ); - sendto( socket_, data, size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) ); + sendto( socket_, data, (int)size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) ); } void Bind( const IpEndpointName& localEndpoint ) @@ -193,14 +221,14 @@ class UdpSocket::Implementation{ bool IsBound() const { return isBound_; } - int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ) + std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) { assert( isBound_ ); struct sockaddr_in fromAddr; socklen_t fromAddrLen = sizeof(fromAddr); - int result = recvfrom(socket_, data, size, 0, + int result = recvfrom(socket_, data, (int)size, 0, (struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen); if( result < 0 ) return 0; @@ -224,6 +252,16 @@ UdpSocket::~UdpSocket() delete impl_; } +void UdpSocket::SetEnableBroadcast( bool enableBroadcast ) +{ + impl_->SetEnableBroadcast( enableBroadcast ); +} + +void UdpSocket::SetAllowReuse( bool allowReuse ) +{ + impl_->SetAllowReuse( allowReuse ); +} + IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const { return impl_->LocalEndpointFor( remoteEndpoint ); @@ -234,12 +272,12 @@ void UdpSocket::Connect( const IpEndpointName& remoteEndpoint ) impl_->Connect( remoteEndpoint ); } -void UdpSocket::Send( const char *data, int size ) +void UdpSocket::Send( const char *data, std::size_t size ) { impl_->Send( data, size ); } -void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, int size ) +void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) { impl_->SendTo( remoteEndpoint, data, size ); } @@ -254,7 +292,7 @@ bool UdpSocket::IsBound() const return impl_->IsBound(); } -int UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ) +std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) { return impl_->ReceiveFrom( remoteEndpoint, data, size ); } @@ -284,7 +322,9 @@ extern "C" /*static*/ void InterruptSignalHandler( int ); /*static*/ void InterruptSignalHandler( int ) { multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak(); - signal( SIGINT, SIG_DFL ); +#ifndef WINCE + signal( SIGINT, SIG_DFL ); +#endif } @@ -299,8 +339,12 @@ class SocketReceiveMultiplexer::Implementation{ double GetCurrentTimeMs() const { +#ifndef WINCE return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days - } +#else + return 0; +#endif + } public: Implementation() @@ -407,9 +451,9 @@ class SocketReceiveMultiplexer::Implementation{ if( waitResult != WAIT_TIMEOUT ){ for( int i = waitResult - WAIT_OBJECT_0; i < (int)socketListeners_.size(); ++i ){ - int size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); + std::size_t size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); if( size > 0 ){ - socketListeners_[i].first->ProcessPacket( data, size, remoteEndpoint ); + socketListeners_[i].first->ProcessPacket( data, (int)size, remoteEndpoint ); if( break_ ) break; } @@ -505,9 +549,13 @@ void SocketReceiveMultiplexer::RunUntilSigInt() { assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */ multiplexerInstanceToAbortWithSigInt_ = this; - signal( SIGINT, InterruptSignalHandler ); +#ifndef WINCE + signal( SIGINT, InterruptSignalHandler ); +#endif impl_->Run(); +#ifndef WINCE signal( SIGINT, SIG_DFL ); +#endif multiplexerInstanceToAbortWithSigInt_ = 0; } diff --git a/oscpack/license b/oscpack/license index 23c9609..7b11e28 100644 --- a/oscpack/license +++ b/oscpack/license @@ -1,7 +1,7 @@ -oscpack -- Open Sound Control packet manipulation library -http://www.audiomulch.com/~rossb/code/oscpack +oscpack -- Open Sound Control (OSC) packet manipulation library +http://www.rossbencina.com/code/oscpack -Copyright (c) 2004 Ross Bencina +Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -14,10 +14,6 @@ subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -Any person wishing to distribute modifications to the Software is -requested to send the modifications to the original developer so that -they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -26,3 +22,13 @@ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +### + +The text above constitutes the entire oscpack license; however, +the oscpack developer(s) also make the following non-binding requests: + +Any person wishing to distribute modifications to the Software is +requested to send the modifications to the original developer so that +they can be incorporated into the canonical version. It is also +requested that these non-binding requests be included whenever the +above license is reproduced. \ No newline at end of file diff --git a/oscpack/osc/MessageMappingOscPacketListener.h b/oscpack/osc/MessageMappingOscPacketListener.h index 017bf05..fc7f75a 100644 --- a/oscpack/osc/MessageMappingOscPacketListener.h +++ b/oscpack/osc/MessageMappingOscPacketListener.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,10 +23,21 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H -#define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H -#include +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H +#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H + +#include #include #include "OscPacketListener.h" @@ -61,7 +68,7 @@ class MessageMappingOscPacketListener : public OscPacketListener{ private: struct cstr_compare{ bool operator()( const char *lhs, const char *rhs ) const - { return strcmp( lhs, rhs ) < 0; } + { return std::strcmp( lhs, rhs ) < 0; } }; typedef std::map function_map_type; @@ -70,4 +77,4 @@ class MessageMappingOscPacketListener : public OscPacketListener{ } // namespace osc -#endif /* INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H */ \ No newline at end of file +#endif /* INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H */ \ No newline at end of file diff --git a/oscpack/osc/OscException.h b/oscpack/osc/OscException.h index cd8d567..5742762 100644 --- a/oscpack/osc/OscException.h +++ b/oscpack/osc/OscException.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,8 +23,19 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_OSC_EXCEPTION_H -#define INCLUDED_OSC_EXCEPTION_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCEXCEPTION_H +#define INCLUDED_OSCPACK_OSCEXCEPTION_H #include @@ -40,7 +47,8 @@ class Exception : public std::exception { public: Exception() throw() {} Exception( const Exception& src ) throw() - : what_( src.what_ ) {} + : std::exception( src ) + , what_( src.what_ ) {} Exception( const char *w ) throw() : what_( w ) {} Exception& operator=( const Exception& src ) throw() @@ -51,4 +59,4 @@ class Exception : public std::exception { } // namespace osc -#endif /* INCLUDED_OSC_EXCEPTION_H */ +#endif /* INCLUDED_OSCPACK_OSCEXCEPTION_H */ diff --git a/oscpack/osc/OscHostEndianness.h b/oscpack/osc/OscHostEndianness.h index 48a4f5f..3bcc376 100644 --- a/oscpack/osc/OscHostEndianness.h +++ b/oscpack/osc/OscHostEndianness.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,22 +23,36 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef OSC_HOSTENDIANNESS_H -#define OSC_HOSTENDIANNESS_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H +#define INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H /* Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined - If you know a way to enhance the detection below for Linux and/or MacOSX - please let me know! I've tried a few things which don't work. + We try to use preprocessor symbols to deduce the host endianness. + + Alternatively you can define one of the above symbols from the command line. + Usually you do this with the -D flag to the compiler. e.g.: + + $ g++ -DOSC_HOST_LITTLE_ENDIAN ... */ #if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN) -// you can define one of the above symbols from the command line -// then you don't have to edit this file. +// endianness defined on the command line. nothing to do here. -#elif defined(__WIN32__) || defined(WIN32) +#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE) // assume that __WIN32__ is only defined on little endian systems @@ -52,18 +62,66 @@ #elif defined(__APPLE__) #if defined(__LITTLE_ENDIAN__) + #define OSC_HOST_LITTLE_ENDIAN 1 #undef OSC_HOST_BIG_ENDIAN -#else + +#elif defined(__BIG_ENDIAN__) + #define OSC_HOST_BIG_ENDIAN 1 #undef OSC_HOST_LITTLE_ENDIAN + +#endif + +#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) + +// should cover gcc and clang + +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + +#define OSC_HOST_LITTLE_ENDIAN 1 +#undef OSC_HOST_BIG_ENDIAN + +#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + +#define OSC_HOST_BIG_ENDIAN 1 +#undef OSC_HOST_LITTLE_ENDIAN + #endif #else -#error please edit OSCHostEndianness.h to configure endianness +// gcc defines __LITTLE_ENDIAN__ and __BIG_ENDIAN__ +// for others used here see http://sourceforge.net/p/predef/wiki/Endianness/ +#if (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \ + || (defined(__ARMEL__) && !defined(__ARMEB__)) \ + || (defined(__AARCH64EL__) && !defined(__AARCH64EB__)) \ + || (defined(_MIPSEL) && !defined(_MIPSEB)) \ + || (defined(__MIPSEL) && !defined(__MIPSEB)) \ + || (defined(__MIPSEL__) && !defined(__MIPSEB__)) + +#define OSC_HOST_LITTLE_ENDIAN 1 +#undef OSC_HOST_BIG_ENDIAN + +#elif (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \ + || (defined(__ARMEB__) && !defined(__ARMEL__)) \ + || (defined(__AARCH64EB__) && !defined(__AARCH64EL__)) \ + || (defined(_MIPSEB) && !defined(_MIPSEL)) \ + || (defined(__MIPSEB) && !defined(__MIPSEL)) \ + || (defined(__MIPSEB__) && !defined(__MIPSEL__)) + +#define OSC_HOST_BIG_ENDIAN 1 +#undef OSC_HOST_LITTLE_ENDIAN + +#endif + +#endif + +#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN) + +#error please edit OSCHostEndianness.h or define one of {OSC_HOST_LITTLE_ENDIAN, OSC_HOST_BIG_ENDIAN} to configure endianness #endif -#endif /* OSC_HOSTENDIANNESS_H */ +#endif /* INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H */ diff --git a/oscpack/osc/OscOutboundPacketStream.cpp b/oscpack/osc/OscOutboundPacketStream.cpp index 75b1800..e54cbd3 100644 --- a/oscpack/osc/OscOutboundPacketStream.cpp +++ b/oscpack/osc/OscOutboundPacketStream.cpp @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,18 +23,37 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "OscOutboundPacketStream.h" -#include -#include -#include +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: -#if defined(__WIN32__) || defined(WIN32) + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "OscOutboundPacketStream.h" + +#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) #include // for alloca +#else +//#include // alloca on Linux (also OSX) +#include // alloca on OSX and FreeBSD (and Linux?) #endif +#include +#include // memcpy, memmove, strcpy, strlen +#include // ptrdiff_t + #include "OscHostEndianness.h" +#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug +namespace std { +using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. +} +#endif namespace osc{ @@ -130,13 +145,14 @@ static void FromUInt64( char *p, uint64 x ) } -static inline long RoundUp4( long x ) +// round up to the next highest multiple of 4. unless x is already a multiple of 4 +static inline std::size_t RoundUp4( std::size_t x ) { - return ((x-1) & (~0x03L)) + 4; + return (x + 3) & ~((std::size_t)0x03); } -OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity ) +OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity ) : data_( buffer ) , end_( data_ + capacity ) , typeTagsCurrent_( end_ ) @@ -145,7 +161,12 @@ OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity , elementSizePtr_( 0 ) , messageIsInProgress_( false ) { - + // sanity check integer types declared in OscTypes.h + // you'll need to fix OscTypes.h if any of these asserts fail + assert( sizeof(osc::int32) == 4 ); + assert( sizeof(osc::uint32) == 4 ); + assert( sizeof(osc::int64) == 8 ); + assert( sizeof(osc::uint64) == 8 ); } @@ -189,12 +210,15 @@ void OutboundPacketStream::EndElement( char *endPtr ) // size slot is stored in the elements size slot (or a ptr to data_ // if there is no containing element). We retrieve that here uint32 *previousElementSizePtr = - (uint32*)(data_ + *reinterpret_cast(elementSizePtr_)); + reinterpret_cast(data_ + *elementSizePtr_); - // then we store the element size in the slot, note that the element + // then we store the element size in the slot. note that the element // size does not include the size slot, hence the - 4 below. - uint32 elementSize = - (endPtr - reinterpret_cast(elementSizePtr_)) - 4; + + std::ptrdiff_t d = endPtr - reinterpret_cast(elementSizePtr_); + // assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb + + uint32 elementSize = static_cast(d - 4); FromUInt32( reinterpret_cast(elementSizePtr_), elementSize ); // finally, we reset the element size ptr to the containing element @@ -211,7 +235,7 @@ bool OutboundPacketStream::ElementSizeSlotRequired() const void OutboundPacketStream::CheckForAvailableBundleSpace() { - unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + 16; + std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16; if( required > Capacity() ) throw OutOfBufferMemoryException(); @@ -221,18 +245,18 @@ void OutboundPacketStream::CheckForAvailableBundleSpace() void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern ) { // plus 4 for at least four bytes of type tag - unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) - + RoundUp4(strlen(addressPattern) + 1) + 4; + std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + + RoundUp4(std::strlen(addressPattern) + 1) + 4; if( required > Capacity() ) throw OutOfBufferMemoryException(); } -void OutboundPacketStream::CheckForAvailableArgumentSpace( long argumentLength ) +void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength ) { // plus three for extra type tag, comma and null terminator - unsigned long required = (argumentCurrent_ - data_) + argumentLength + std::size_t required = (argumentCurrent_ - data_) + argumentLength + RoundUp4( (end_ - typeTagsCurrent_) + 3 ); if( required > Capacity() ) @@ -250,15 +274,15 @@ void OutboundPacketStream::Clear() } -unsigned int OutboundPacketStream::Capacity() const +std::size_t OutboundPacketStream::Capacity() const { return end_ - data_; } -unsigned int OutboundPacketStream::Size() const +std::size_t OutboundPacketStream::Size() const { - unsigned int result = argumentCurrent_ - data_; + std::size_t result = argumentCurrent_ - data_; if( IsMessageInProgress() ){ // account for the length of the type tag string. the total type tag // includes an initial comma, plus at least one terminating \0 @@ -302,7 +326,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& r messageCursor_ = BeginElement( messageCursor_ ); - memcpy( messageCursor_, "#bundle\0", 8 ); + std::memcpy( messageCursor_, "#bundle\0", 8 ); FromUInt64( messageCursor_ + 8, rhs.timeTag ); messageCursor_ += 16; @@ -336,12 +360,12 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs messageCursor_ = BeginElement( messageCursor_ ); - strcpy( messageCursor_, rhs.addressPattern ); - unsigned long rhsLength = strlen(rhs.addressPattern); + std::strcpy( messageCursor_, rhs.addressPattern ); + std::size_t rhsLength = std::strlen(rhs.addressPattern); messageCursor_ += rhsLength + 1; // zero pad to 4-byte boundary - unsigned long i = rhsLength + 1; + std::size_t i = rhsLength + 1; while( i & 0x3 ){ *messageCursor_++ = '\0'; ++i; @@ -363,27 +387,27 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& if( !IsMessageInProgress() ) throw MessageNotInProgressException(); - int typeTagsCount = end_ - typeTagsCurrent_; + std::size_t typeTagsCount = end_ - typeTagsCurrent_; if( typeTagsCount ){ char *tempTypeTags = (char*)alloca(typeTagsCount); - memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount ); + std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount ); // slot size includes comma and null terminator - int typeTagSlotSize = RoundUp4( typeTagsCount + 2 ); + std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 ); - uint32 argumentsSize = argumentCurrent_ - messageCursor_; + std::size_t argumentsSize = argumentCurrent_ - messageCursor_; - memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize ); + std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize ); messageCursor_[0] = ','; // copy type tags in reverse (really forward) order - for( int i=0; i < typeTagsCount; ++i ) + for( std::size_t i=0; i < typeTagsCount; ++i ) messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ]; char *p = messageCursor_ + 1 + typeTagsCount; - for( int i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i ) + for( std::size_t i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i ) *p++ = '\0'; typeTagsCurrent_ = end_; @@ -393,7 +417,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& }else{ // send an empty type tags string - memcpy( messageCursor_, ",\0\0\0", 4 ); + std::memcpy( messageCursor_, ",\0\0\0", 4 ); // advance messageCursor_ for next message messageCursor_ += 4; @@ -575,15 +599,15 @@ OutboundPacketStream& OutboundPacketStream::operator<<( double rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) { - CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) ); + CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); *(--typeTagsCurrent_) = STRING_TYPE_TAG; - strcpy( argumentCurrent_, rhs ); - unsigned long rhsLength = strlen(rhs); + std::strcpy( argumentCurrent_, rhs ); + std::size_t rhsLength = std::strlen(rhs); argumentCurrent_ += rhsLength + 1; // zero pad to 4-byte boundary - unsigned long i = rhsLength + 1; + std::size_t i = rhsLength + 1; while( i & 0x3 ){ *argumentCurrent_++ = '\0'; ++i; @@ -595,15 +619,15 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs ) { - CheckForAvailableArgumentSpace( RoundUp4(strlen(rhs) + 1) ); + CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG; - strcpy( argumentCurrent_, rhs ); - unsigned long rhsLength = strlen(rhs); + std::strcpy( argumentCurrent_, rhs ); + std::size_t rhsLength = std::strlen(rhs); argumentCurrent_ += rhsLength + 1; // zero pad to 4-byte boundary - unsigned long i = rhsLength + 1; + std::size_t i = rhsLength + 1; while( i & 0x3 ){ *argumentCurrent_++ = '\0'; ++i; @@ -621,7 +645,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs ) FromUInt32( argumentCurrent_, rhs.size ); argumentCurrent_ += 4; - memcpy( argumentCurrent_, rhs.data, rhs.size ); + std::memcpy( argumentCurrent_, rhs.data, rhs.size ); argumentCurrent_ += rhs.size; // zero pad to 4-byte boundary @@ -634,6 +658,26 @@ OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs ) return *this; } +OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs ) +{ + (void) rhs; + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG; + + return *this; +} + +OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs ) +{ + (void) rhs; + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG; + + return *this; +} + } // namespace osc diff --git a/oscpack/osc/OscOutboundPacketStream.h b/oscpack/osc/OscOutboundPacketStream.h index e5f3726..97aabf5 100644 --- a/oscpack/osc/OscOutboundPacketStream.h +++ b/oscpack/osc/OscOutboundPacketStream.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,8 +23,21 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_OSCOUTBOUNDPACKET_H -#define INCLUDED_OSCOUTBOUNDPACKET_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H +#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H + +#include // size_t #include "OscTypes.h" #include "OscException.h" @@ -66,15 +75,15 @@ class MessageNotInProgressException : public Exception{ class OutboundPacketStream{ public: - OutboundPacketStream( char *buffer, unsigned long capacity ); + OutboundPacketStream( char *buffer, std::size_t capacity ); ~OutboundPacketStream(); void Clear(); - unsigned int Capacity() const; + std::size_t Capacity() const; // invariant: size() is valid even while building a message. - unsigned int Size() const; + std::size_t Size() const; const char *Data() const; @@ -96,7 +105,7 @@ class OutboundPacketStream{ OutboundPacketStream& operator<<( const InfinitumType& rhs ); OutboundPacketStream& operator<<( int32 rhs ); -#ifndef __x86_64__ +#if !(defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)) OutboundPacketStream& operator<<( int rhs ) { *this << (int32)rhs; return *this; } #endif @@ -112,6 +121,9 @@ class OutboundPacketStream{ OutboundPacketStream& operator<<( const Symbol& rhs ); OutboundPacketStream& operator<<( const Blob& rhs ); + OutboundPacketStream& operator<<( const ArrayInitiator& rhs ); + OutboundPacketStream& operator<<( const ArrayTerminator& rhs ); + private: char *BeginElement( char *beginPtr ); @@ -120,7 +132,7 @@ class OutboundPacketStream{ bool ElementSizeSlotRequired() const; void CheckForAvailableBundleSpace(); void CheckForAvailableMessageSpace( const char *addressPattern ); - void CheckForAvailableArgumentSpace( long argumentLength ); + void CheckForAvailableArgumentSpace( std::size_t argumentLength ); char *data_; char *end_; @@ -139,4 +151,4 @@ class OutboundPacketStream{ } // namespace osc -#endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */ +#endif /* INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H */ diff --git a/oscpack/osc/OscPacketListener.h b/oscpack/osc/OscPacketListener.h index bc322b7..c77e924 100644 --- a/oscpack/osc/OscPacketListener.h +++ b/oscpack/osc/OscPacketListener.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,8 +23,19 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_OSCPACKETLISTENER_H -#define INCLUDED_OSCPACKETLISTENER_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCPACKETLISTENER_H +#define INCLUDED_OSCPACK_OSCPACKETLISTENER_H #include "OscReceivedElements.h" #include "../ip/PacketListener.h" @@ -69,4 +76,4 @@ class OscPacketListener : public PacketListener{ } // namespace osc -#endif /* INCLUDED_OSCPACKETLISTENER_H */ +#endif /* INCLUDED_OSCPACK_OSCPACKETLISTENER_H */ diff --git a/oscpack/osc/OscPrintReceivedElements.cpp b/oscpack/osc/OscPrintReceivedElements.cpp index 467c213..72e0bc5 100644 --- a/oscpack/osc/OscPrintReceivedElements.cpp +++ b/oscpack/osc/OscPrintReceivedElements.cpp @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,12 +23,29 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ #include "OscPrintReceivedElements.h" +#include +#include #include #include -#include +#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug +namespace std { +using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. +} +#endif namespace osc{ @@ -108,20 +121,17 @@ std::ostream& operator<<( std::ostream & os, case TIME_TAG_TYPE_TAG: { - os << "OSC-timetag:" << arg.AsTimeTagUnchecked(); + os << "OSC-timetag:" << arg.AsTimeTagUnchecked() << " "; std::time_t t = (unsigned long)( arg.AsTimeTagUnchecked() >> 32 ); - // strip trailing newline from string returned by ctime const char *timeString = std::ctime( &t ); - size_t len = strlen( timeString ); - char *s = new char[ len + 1 ]; - strcpy( s, timeString ); - if( len ) - s[ len - 1 ] = '\0'; - - os << " " << s; + size_t len = std::strlen( timeString ); + + // -1 to omit trailing newline from string returned by ctime() + if( len > 1 ) + os.write( timeString, len - 1 ); } break; @@ -139,12 +149,12 @@ std::ostream& operator<<( std::ostream & os, case BLOB_TYPE_TAG: { - unsigned long size; const void *data; + osc_bundle_element_size_t size; arg.AsBlobUnchecked( data, size ); os << "OSC-blob:<<" << std::hex << std::setfill('0'); unsigned char *p = (unsigned char*)data; - for( unsigned long i = 0; i < size; ++i ){ + for( osc_bundle_element_size_t i = 0; i < size; ++i ){ os << "0x" << std::setw(2) << int(p[i]); if( i != size-1 ) os << ' '; @@ -154,6 +164,14 @@ std::ostream& operator<<( std::ostream & os, } break; + case ARRAY_BEGIN_TYPE_TAG: + os << "["; + break; + + case ARRAY_END_TYPE_TAG: + os << "]"; + break; + default: os << "unknown"; } @@ -164,10 +182,13 @@ std::ostream& operator<<( std::ostream & os, std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ) { - - os << "[" << m.AddressPattern(); + os << "["; + if( m.AddressPatternIsUInt32() ) + os << m.AddressPatternAsUInt32(); + else + os << m.AddressPattern(); + bool first = true; - for( ReceivedMessage::const_iterator i = m.ArgumentsBegin(); i != m.ArgumentsEnd(); ++i ){ if( first ){ diff --git a/oscpack/osc/OscPrintReceivedElements.h b/oscpack/osc/OscPrintReceivedElements.h index 6adbd32..7561c01 100644 --- a/oscpack/osc/OscPrintReceivedElements.h +++ b/oscpack/osc/OscPrintReceivedElements.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,15 +23,23 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H -#define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H +#define INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H #include -#include -#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H #include "OscReceivedElements.h" -#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */ namespace osc{ @@ -47,4 +51,4 @@ std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ); } // namespace osc -#endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */ +#endif /* INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H */ diff --git a/oscpack/osc/OscReceivedElements.cpp b/oscpack/osc/OscReceivedElements.cpp index e3e3572..4dfa787 100644 --- a/oscpack/osc/OscReceivedElements.cpp +++ b/oscpack/osc/OscReceivedElements.cpp @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,12 +23,22 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "OscReceivedElements.h" -#include +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "OscReceivedElements.h" #include "OscHostEndianness.h" +#include // ptrdiff_t namespace osc{ @@ -77,13 +83,10 @@ static inline const char* FindStr4End( const char *p, const char *end ) } -static inline unsigned long RoundUp4( unsigned long x ) +// round up to the next highest multiple of 4. unless x is already a multiple of 4 +static inline uint32 RoundUp4( uint32 x ) { - unsigned long remainder = x & 0x3UL; - if( remainder ) - return x + (4 - remainder); - else - return x; + return (x + 3) & ~((uint32)0x03); } @@ -127,7 +130,7 @@ static inline uint32 ToUInt32( const char *p ) } -int64 ToInt64( const char *p ) +static inline int64 ToInt64( const char *p ) { #ifdef OSC_HOST_LITTLE_ENDIAN union{ @@ -151,7 +154,7 @@ int64 ToInt64( const char *p ) } -uint64 ToUInt64( const char *p ) +static inline uint64 ToUInt64( const char *p ) { #ifdef OSC_HOST_LITTLE_ENDIAN union{ @@ -189,20 +192,20 @@ bool ReceivedBundleElement::IsBundle() const } -int32 ReceivedBundleElement::Size() const +osc_bundle_element_size_t ReceivedBundleElement::Size() const { - return ToUInt32( size_ ); + return ToInt32( sizePtr_ ); } //------------------------------------------------------------------------------ bool ReceivedMessageArgument::AsBool() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == TRUE_TYPE_TAG ) + else if( *typeTagPtr_ == TRUE_TYPE_TAG ) return true; - else if( *typeTag_ == FALSE_TYPE_TAG ) + else if( *typeTagPtr_ == FALSE_TYPE_TAG ) return false; else throw WrongArgumentTypeException(); @@ -211,9 +214,9 @@ bool ReceivedMessageArgument::AsBool() const bool ReceivedMessageArgument::AsBoolUnchecked() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == TRUE_TYPE_TAG ) + else if( *typeTagPtr_ == TRUE_TYPE_TAG ) return true; else return false; @@ -222,9 +225,9 @@ bool ReceivedMessageArgument::AsBoolUnchecked() const int32 ReceivedMessageArgument::AsInt32() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == INT32_TYPE_TAG ) + else if( *typeTagPtr_ == INT32_TYPE_TAG ) return AsInt32Unchecked(); else throw WrongArgumentTypeException(); @@ -239,23 +242,23 @@ int32 ReceivedMessageArgument::AsInt32Unchecked() const char c[4]; } u; - u.c[0] = argument_[3]; - u.c[1] = argument_[2]; - u.c[2] = argument_[1]; - u.c[3] = argument_[0]; + u.c[0] = argumentPtr_[3]; + u.c[1] = argumentPtr_[2]; + u.c[2] = argumentPtr_[1]; + u.c[3] = argumentPtr_[0]; return u.i; #else - return *(int32*)argument_; + return *(int32*)argumentPtr_; #endif } float ReceivedMessageArgument::AsFloat() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == FLOAT_TYPE_TAG ) + else if( *typeTagPtr_ == FLOAT_TYPE_TAG ) return AsFloatUnchecked(); else throw WrongArgumentTypeException(); @@ -270,23 +273,23 @@ float ReceivedMessageArgument::AsFloatUnchecked() const char c[4]; } u; - u.c[0] = argument_[3]; - u.c[1] = argument_[2]; - u.c[2] = argument_[1]; - u.c[3] = argument_[0]; + u.c[0] = argumentPtr_[3]; + u.c[1] = argumentPtr_[2]; + u.c[2] = argumentPtr_[1]; + u.c[3] = argumentPtr_[0]; return u.f; #else - return *(float*)argument_; + return *(float*)argumentPtr_; #endif } char ReceivedMessageArgument::AsChar() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == CHAR_TYPE_TAG ) + else if( *typeTagPtr_ == CHAR_TYPE_TAG ) return AsCharUnchecked(); else throw WrongArgumentTypeException(); @@ -295,15 +298,15 @@ char ReceivedMessageArgument::AsChar() const char ReceivedMessageArgument::AsCharUnchecked() const { - return (char)ToInt32( argument_ ); + return (char)ToInt32( argumentPtr_ ); } uint32 ReceivedMessageArgument::AsRgbaColor() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == RGBA_COLOR_TYPE_TAG ) + else if( *typeTagPtr_ == RGBA_COLOR_TYPE_TAG ) return AsRgbaColorUnchecked(); else throw WrongArgumentTypeException(); @@ -312,15 +315,15 @@ uint32 ReceivedMessageArgument::AsRgbaColor() const uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const { - return ToUInt32( argument_ ); + return ToUInt32( argumentPtr_ ); } uint32 ReceivedMessageArgument::AsMidiMessage() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG ) + else if( *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG ) return AsMidiMessageUnchecked(); else throw WrongArgumentTypeException(); @@ -329,15 +332,15 @@ uint32 ReceivedMessageArgument::AsMidiMessage() const uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const { - return ToUInt32( argument_ ); + return ToUInt32( argumentPtr_ ); } int64 ReceivedMessageArgument::AsInt64() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == INT64_TYPE_TAG ) + else if( *typeTagPtr_ == INT64_TYPE_TAG ) return AsInt64Unchecked(); else throw WrongArgumentTypeException(); @@ -346,15 +349,15 @@ int64 ReceivedMessageArgument::AsInt64() const int64 ReceivedMessageArgument::AsInt64Unchecked() const { - return ToInt64( argument_ ); + return ToInt64( argumentPtr_ ); } uint64 ReceivedMessageArgument::AsTimeTag() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == TIME_TAG_TYPE_TAG ) + else if( *typeTagPtr_ == TIME_TAG_TYPE_TAG ) return AsTimeTagUnchecked(); else throw WrongArgumentTypeException(); @@ -363,15 +366,15 @@ uint64 ReceivedMessageArgument::AsTimeTag() const uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const { - return ToUInt64( argument_ ); + return ToUInt64( argumentPtr_ ); } double ReceivedMessageArgument::AsDouble() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == DOUBLE_TYPE_TAG ) + else if( *typeTagPtr_ == DOUBLE_TYPE_TAG ) return AsDoubleUnchecked(); else throw WrongArgumentTypeException(); @@ -386,28 +389,28 @@ double ReceivedMessageArgument::AsDoubleUnchecked() const char c[8]; } u; - u.c[0] = argument_[7]; - u.c[1] = argument_[6]; - u.c[2] = argument_[5]; - u.c[3] = argument_[4]; - u.c[4] = argument_[3]; - u.c[5] = argument_[2]; - u.c[6] = argument_[1]; - u.c[7] = argument_[0]; + u.c[0] = argumentPtr_[7]; + u.c[1] = argumentPtr_[6]; + u.c[2] = argumentPtr_[5]; + u.c[3] = argumentPtr_[4]; + u.c[4] = argumentPtr_[3]; + u.c[5] = argumentPtr_[2]; + u.c[6] = argumentPtr_[1]; + u.c[7] = argumentPtr_[0]; return u.d; #else - return *(double*)argument_; + return *(double*)argumentPtr_; #endif } const char* ReceivedMessageArgument::AsString() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == STRING_TYPE_TAG ) - return argument_; + else if( *typeTagPtr_ == STRING_TYPE_TAG ) + return argumentPtr_; else throw WrongArgumentTypeException(); } @@ -415,50 +418,88 @@ const char* ReceivedMessageArgument::AsString() const const char* ReceivedMessageArgument::AsSymbol() const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == SYMBOL_TYPE_TAG ) - return argument_; + else if( *typeTagPtr_ == SYMBOL_TYPE_TAG ) + return argumentPtr_; else throw WrongArgumentTypeException(); } -void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const +void ReceivedMessageArgument::AsBlob( const void*& data, osc_bundle_element_size_t& size ) const { - if( !typeTag_ ) + if( !typeTagPtr_ ) throw MissingArgumentException(); - else if( *typeTag_ == BLOB_TYPE_TAG ) + else if( *typeTagPtr_ == BLOB_TYPE_TAG ) AsBlobUnchecked( data, size ); else throw WrongArgumentTypeException(); } -void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const +void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const +{ + // read blob size as an unsigned int then validate + osc_bundle_element_size_t sizeResult = (osc_bundle_element_size_t)ToUInt32( argumentPtr_ ); + if( !IsValidElementSizeValue(sizeResult) ) + throw MalformedMessageException("invalid blob size"); + + size = sizeResult; + data = (void*)(argumentPtr_+ osc::OSC_SIZEOF_INT32); +} + +std::size_t ReceivedMessageArgument::ComputeArrayItemCount() const { - size = ToUInt32( argument_ ); - data = (void*)(argument_+4); + // it is only valid to call ComputeArrayItemCount when the argument is the array start marker + if( !IsArrayBegin() ) + throw WrongArgumentTypeException(); + + std::size_t result = 0; + unsigned int level = 0; + const char *typeTag = typeTagPtr_ + 1; + + // iterate through all type tags. note that ReceivedMessage::Init + // has already checked that the message is well formed. + while( *typeTag ) { + switch( *typeTag++ ) { + case ARRAY_BEGIN_TYPE_TAG: + level += 1; + break; + + case ARRAY_END_TYPE_TAG: + if(level == 0) + return result; + level -= 1; + break; + + default: + if( level == 0 ) // only count items at level 0 + ++result; + } + } + + return result; } //------------------------------------------------------------------------------ void ReceivedMessageArgumentIterator::Advance() { - if( !value_.typeTag_ ) + if( !value_.typeTagPtr_ ) return; - switch( *value_.typeTag_++ ){ + switch( *value_.typeTagPtr_++ ){ case '\0': // don't advance past end - --value_.typeTag_; + --value_.typeTagPtr_; break; case TRUE_TYPE_TAG: case FALSE_TYPE_TAG: case NIL_TYPE_TAG: case INFINITUM_TYPE_TAG: - + // zero length break; @@ -468,14 +509,14 @@ void ReceivedMessageArgumentIterator::Advance() case RGBA_COLOR_TYPE_TAG: case MIDI_MESSAGE_TYPE_TAG: - value_.argument_ += 4; + value_.argumentPtr_ += 4; break; case INT64_TYPE_TAG: case TIME_TAG_TYPE_TAG: case DOUBLE_TYPE_TAG: - value_.argument_ += 8; + value_.argumentPtr_ += 8; break; case STRING_TYPE_TAG: @@ -485,26 +526,31 @@ void ReceivedMessageArgumentIterator::Advance() // the arguments have already been validated in // ReceivedMessage::Init() below. - value_.argument_ = FindStr4End( value_.argument_ ); + value_.argumentPtr_ = FindStr4End( value_.argumentPtr_ ); break; case BLOB_TYPE_TAG: { - uint32 blobSize = ToUInt32( value_.argument_ ); - value_.argument_ = value_.argument_ + 4 + RoundUp4( blobSize ); + // treat blob size as an unsigned int for the purposes of this calculation + uint32 blobSize = ToUInt32( value_.argumentPtr_ ); + value_.argumentPtr_ = value_.argumentPtr_ + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize ); } break; + case ARRAY_BEGIN_TYPE_TAG: + case ARRAY_END_TYPE_TAG: + + // [ Indicates the beginning of an array. The tags following are for + // data in the Array until a close brace tag is reached. + // ] Indicates the end of an array. + + // zero length, don't advance argument ptr + break; + default: // unknown type tag // don't advance - --value_.typeTag_; + --value_.typeTagPtr_; break; - - - // not handled: - // [ Indicates the beginning of an array. The tags following are for - // data in the Array until a close brace tag is reached. - // ] Indicates the end of an array. } } @@ -536,12 +582,15 @@ uint32 ReceivedMessage::AddressPatternAsUInt32() const } -void ReceivedMessage::Init( const char *message, unsigned long size ) +void ReceivedMessage::Init( const char *message, osc_bundle_element_size_t size ) { + if( !IsValidElementSizeValue(size) ) + throw MalformedMessageException( "invalid message size" ); + if( size == 0 ) throw MalformedMessageException( "zero length messages not permitted" ); - if( (size & 0x03L) != 0 ) + if( !IsMultipleOf4(size) ) throw MalformedMessageException( "message size must be multiple of four" ); const char *end = message + size; @@ -580,6 +629,7 @@ void ReceivedMessage::Init( const char *message, unsigned long size ) const char *typeTag = typeTagsBegin_; const char *argument = arguments_; + unsigned int arrayLevel = 0; do{ switch( *typeTag ){ @@ -587,10 +637,22 @@ void ReceivedMessage::Init( const char *message, unsigned long size ) case FALSE_TYPE_TAG: case NIL_TYPE_TAG: case INFINITUM_TYPE_TAG: - // zero length break; + // [ Indicates the beginning of an array. The tags following are for + // data in the Array until a close brace tag is reached. + // ] Indicates the end of an array. + case ARRAY_BEGIN_TYPE_TAG: + ++arrayLevel; + // (zero length argument data) + break; + + case ARRAY_END_TYPE_TAG: + --arrayLevel; + // (zero length argument data) + break; + case INT32_TYPE_TAG: case FLOAT_TYPE_TAG: case CHAR_TYPE_TAG: @@ -627,11 +689,12 @@ void ReceivedMessage::Init( const char *message, unsigned long size ) case BLOB_TYPE_TAG: { - if( argument + 4 > end ) + if( argument + osc::OSC_SIZEOF_INT32 > end ) MalformedMessageException( "arguments exceed message size" ); + // treat blob size as an unsigned int for the purposes of this calculation uint32 blobSize = ToUInt32( argument ); - argument = argument + 4 + RoundUp4( blobSize ); + argument = argument + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize ); if( argument > end ) MalformedMessageException( "arguments exceed message size" ); } @@ -639,16 +702,22 @@ void ReceivedMessage::Init( const char *message, unsigned long size ) default: throw MalformedMessageException( "unknown type tag" ); - - // not handled: - // [ Indicates the beginning of an array. The tags following are for - // data in the Array until a close brace tag is reached. - // ] Indicates the end of an array. } }while( *++typeTag != '\0' ); typeTagsEnd_ = typeTag; + + if( arrayLevel != 0 ) + throw MalformedMessageException( "array was not terminated before end of message (expected ']' end of array tag)" ); } + + // These invariants should be guaranteed by the above code. + // we depend on them in the implementation of ArgumentCount() +#ifndef NDEBUG + std::ptrdiff_t argumentCount = typeTagsEnd_ - typeTagsBegin_; + assert( argumentCount >= 0 ); + assert( argumentCount <= OSC_INT32_MAX ); +#endif } } @@ -668,12 +737,16 @@ ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement ) } -void ReceivedBundle::Init( const char *bundle, unsigned long size ) +void ReceivedBundle::Init( const char *bundle, osc_bundle_element_size_t size ) { + + if( !IsValidElementSizeValue(size) ) + throw MalformedBundleException( "invalid bundle size" ); + if( size < 16 ) throw MalformedBundleException( "packet too short for bundle" ); - if( (size & 0x03L) != 0 ) + if( !IsMultipleOf4(size) ) throw MalformedBundleException( "bundle size must be multiple of four" ); if( bundle[0] != '#' @@ -693,14 +766,15 @@ void ReceivedBundle::Init( const char *bundle, unsigned long size ) const char *p = timeTag_ + 8; while( p < end_ ){ - if( p + 4 > end_ ) + if( p + osc::OSC_SIZEOF_INT32 > end_ ) throw MalformedBundleException( "packet too short for elementSize" ); + // treat element size as an unsigned int for the purposes of this calculation uint32 elementSize = ToUInt32( p ); - if( (elementSize & 0x03L) != 0 ) + if( (elementSize & ((uint32)0x03)) != 0 ) throw MalformedBundleException( "bundle element size must be multiple of four" ); - p += 4 + elementSize; + p += osc::OSC_SIZEOF_INT32 + elementSize; if( p > end_ ) throw MalformedBundleException( "packet too short for bundle element" ); diff --git a/oscpack/osc/OscReceivedElements.h b/oscpack/osc/OscReceivedElements.h index f438757..6cfc2d9 100644 --- a/oscpack/osc/OscReceivedElements.h +++ b/oscpack/osc/OscReceivedElements.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,8 +23,23 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H -#define INCLUDED_OSCRECEIVEDELEMENTS_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H +#define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H + +#include +#include +#include // size_t #include "OscTypes.h" #include "OscException.h" @@ -37,6 +48,12 @@ namespace osc{ +class MalformedPacketException : public Exception{ +public: + MalformedPacketException( const char *w="malformed packet" ) + : Exception( w ) {} +}; + class MalformedMessageException : public Exception{ public: MalformedMessageException( const char *w="malformed message" ) @@ -70,37 +87,73 @@ class ExcessArgumentException : public Exception{ class ReceivedPacket{ public: - ReceivedPacket( const char *contents, int32 size ) + // Although the OSC spec is not entirely clear on this, we only support + // packets up to 0x7FFFFFFC bytes long (the maximum 4-byte aligned value + // representable by an int32). An exception will be raised if you pass a + // larger value to the ReceivedPacket() constructor. + + ReceivedPacket( const char *contents, osc_bundle_element_size_t size ) + : contents_( contents ) + , size_( ValidateSize(size) ) {} + + ReceivedPacket( const char *contents, std::size_t size ) : contents_( contents ) - , size_( size ) {} + , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} + +#if !(defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)) + ReceivedPacket( const char *contents, int size ) + : contents_( contents ) + , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} +#endif bool IsMessage() const { return !IsBundle(); } bool IsBundle() const; - int32 Size() const { return size_; } + osc_bundle_element_size_t Size() const { return size_; } const char *Contents() const { return contents_; } private: const char *contents_; - int32 size_; + osc_bundle_element_size_t size_; + + static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size ) + { + // sanity check integer types declared in OscTypes.h + // you'll need to fix OscTypes.h if any of these asserts fail + assert( sizeof(osc::int32) == 4 ); + assert( sizeof(osc::uint32) == 4 ); + assert( sizeof(osc::int64) == 8 ); + assert( sizeof(osc::uint64) == 8 ); + + if( !IsValidElementSizeValue(size) ) + throw MalformedPacketException( "invalid packet size" ); + + if( size == 0 ) + throw MalformedPacketException( "zero length elements not permitted" ); + + if( !IsMultipleOf4(size) ) + throw MalformedPacketException( "element size must be multiple of four" ); + + return size; + } }; class ReceivedBundleElement{ public: - ReceivedBundleElement( const char *size ) - : size_( size ) {} + ReceivedBundleElement( const char *sizePtr ) + : sizePtr_( sizePtr ) {} friend class ReceivedBundleElementIterator; bool IsMessage() const { return !IsBundle(); } bool IsBundle() const; - int32 Size() const; - const char *Contents() const { return size_ + 4; } + osc_bundle_element_size_t Size() const; + const char *Contents() const { return sizePtr_ + osc::OSC_SIZEOF_INT32; } private: - const char *size_; + const char *sizePtr_; }; @@ -132,11 +185,11 @@ class ReceivedBundleElementIterator{ private: ReceivedBundleElement value_; - void Advance() { value_.size_ = value_.Contents() + value_.Size(); } + void Advance() { value_.sizePtr_ = value_.Contents() + value_.Size(); } bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const { - return value_.size_ == rhs.value_.size_; + return value_.sizePtr_ == rhs.value_.sizePtr_; } }; @@ -155,73 +208,79 @@ inline bool operator!=(const ReceivedBundleElementIterator& lhs, class ReceivedMessageArgument{ public: - ReceivedMessageArgument( const char *typeTag, const char *argument ) - : typeTag_( typeTag ) - , argument_( argument ) {} + ReceivedMessageArgument( const char *typeTagPtr, const char *argumentPtr ) + : typeTagPtr_( typeTagPtr ) + , argumentPtr_( argumentPtr ) {} friend class ReceivedMessageArgumentIterator; - const char TypeTag() const { return *typeTag_; } + char TypeTag() const { return *typeTagPtr_; } // the unchecked methods below don't check whether the argument actually // is of the specified type. they should only be used if you've already // checked the type tag or the associated IsType() method. bool IsBool() const - { return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; } + { return *typeTagPtr_ == TRUE_TYPE_TAG || *typeTagPtr_ == FALSE_TYPE_TAG; } bool AsBool() const; bool AsBoolUnchecked() const; - bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; } - bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; } + bool IsNil() const { return *typeTagPtr_ == NIL_TYPE_TAG; } + bool IsInfinitum() const { return *typeTagPtr_ == INFINITUM_TYPE_TAG; } - bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; } + bool IsInt32() const { return *typeTagPtr_ == INT32_TYPE_TAG; } int32 AsInt32() const; int32 AsInt32Unchecked() const; - bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; } + bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; } float AsFloat() const; float AsFloatUnchecked() const; - bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; } + bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; } char AsChar() const; char AsCharUnchecked() const; - bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; } + bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; } uint32 AsRgbaColor() const; uint32 AsRgbaColorUnchecked() const; - bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; } + bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; } uint32 AsMidiMessage() const; uint32 AsMidiMessageUnchecked() const; - bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; } + bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; } int64 AsInt64() const; int64 AsInt64Unchecked() const; - bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; } + bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; } uint64 AsTimeTag() const; uint64 AsTimeTagUnchecked() const; - bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; } + bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; } double AsDouble() const; double AsDoubleUnchecked() const; - bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; } + bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; } const char* AsString() const; - const char* AsStringUnchecked() const { return argument_; } + const char* AsStringUnchecked() const { return argumentPtr_; } - bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; } + bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; } const char* AsSymbol() const; - const char* AsSymbolUnchecked() const { return argument_; } + const char* AsSymbolUnchecked() const { return argumentPtr_; } - bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; } - void AsBlob( const void*& data, unsigned long& size ) const; - void AsBlobUnchecked( const void*& data, unsigned long& size ) const; + bool IsBlob() const { return *typeTagPtr_ == BLOB_TYPE_TAG; } + void AsBlob( const void*& data, osc_bundle_element_size_t& size ) const; + void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const; + bool IsArrayBegin() const { return *typeTagPtr_ == ARRAY_BEGIN_TYPE_TAG; } + bool IsArrayEnd() const { return *typeTagPtr_ == ARRAY_END_TYPE_TAG; } + // Calculate the number of top-level items in the array. Nested arrays count as one item. + // Only valid at array start. Will throw an exception if IsArrayStart() == false. + std::size_t ComputeArrayItemCount() const; + private: - const char *typeTag_; - const char *argument_; + const char *typeTagPtr_; + const char *argumentPtr_; }; @@ -257,7 +316,7 @@ class ReceivedMessageArgumentIterator{ bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const { - return value_.typeTag_ == rhs.value_.typeTag_; + return value_.typeTagPtr_ == rhs.value_.typeTagPtr_; } }; @@ -299,6 +358,7 @@ class ReceivedMessageArgumentStream{ // not sure if it would be useful to stream Nil and Infinitum // for now it's not possible + // same goes for array boundaries ReceivedMessageArgumentStream& operator>>( int32& rhs ) { @@ -401,6 +461,8 @@ class ReceivedMessageArgumentStream{ ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) { + (void) rhs; // suppress unused parameter warning + if( !Eos() ) throw ExcessArgumentException(); @@ -410,18 +472,18 @@ class ReceivedMessageArgumentStream{ class ReceivedMessage{ - void Init( const char *bundle, unsigned long size ); + void Init( const char *bundle, osc_bundle_element_size_t size ); public: explicit ReceivedMessage( const ReceivedPacket& packet ); explicit ReceivedMessage( const ReceivedBundleElement& bundleElement ); const char *AddressPattern() const { return addressPattern_; } - // Support for non-standad SuperCollider integer address patterns: + // Support for non-standard SuperCollider integer address patterns: bool AddressPatternIsUInt32() const; uint32 AddressPatternAsUInt32() const; - unsigned long ArgumentCount() const { return static_cast(typeTagsEnd_ - typeTagsBegin_); } + uint32 ArgumentCount() const { return static_cast(typeTagsEnd_ - typeTagsBegin_); } const char *TypeTags() const { return typeTagsBegin_; } @@ -452,14 +514,14 @@ class ReceivedMessage{ class ReceivedBundle{ - void Init( const char *message, unsigned long size ); + void Init( const char *message, osc_bundle_element_size_t size ); public: explicit ReceivedBundle( const ReceivedPacket& packet ); explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); uint64 TimeTag() const; - unsigned long ElementCount() const { return elementCount_; } + uint32 ElementCount() const { return elementCount_; } typedef ReceivedBundleElementIterator const_iterator; @@ -476,11 +538,11 @@ class ReceivedBundle{ private: const char *timeTag_; const char *end_; - unsigned long elementCount_; + uint32 elementCount_; }; } // namespace osc -#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */ +#endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */ diff --git a/oscpack/osc/OscTypes.cpp b/oscpack/osc/OscTypes.cpp index 889ab43..51616d5 100644 --- a/oscpack/osc/OscTypes.cpp +++ b/oscpack/osc/OscTypes.cpp @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,6 +23,17 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ #include "OscTypes.h" namespace osc{ @@ -34,7 +41,12 @@ namespace osc{ BundleInitiator BeginBundleImmediate(1); BundleTerminator EndBundle; MessageTerminator EndMessage; -NilType Nil; +NilType OscNil; +#ifndef _OBJC_OBJC_H_ +NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead +#endif InfinitumType Infinitum; +ArrayInitiator BeginArray; +ArrayTerminator EndArray; } // namespace osc diff --git a/oscpack/osc/OscTypes.h b/oscpack/osc/OscTypes.h index 4c5814e..9b43214 100644 --- a/oscpack/osc/OscTypes.h +++ b/oscpack/osc/OscTypes.h @@ -1,8 +1,8 @@ /* - oscpack -- Open Sound Control packet manipulation library - http://www.audiomulch.com/~rossb/oscpack + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack - Copyright (c) 2004-2005 Ross Bencina + Copyright (c) 2004-2013 Ross Bencina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files @@ -15,10 +15,6 @@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. @@ -27,8 +23,19 @@ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDED_OSCTYPES_H -#define INCLUDED_OSCTYPES_H + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCTYPES_H +#define INCLUDED_OSCPACK_OSCTYPES_H namespace osc{ @@ -40,6 +47,11 @@ namespace osc{ typedef __int64 int64; typedef unsigned __int64 uint64; +#elif defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) + +typedef long int64; +typedef unsigned long uint64; + #else typedef long long int64; @@ -49,7 +61,7 @@ typedef unsigned long long uint64; -#ifdef __x86_64__ +#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) typedef signed int int32; typedef unsigned int uint32; @@ -62,6 +74,41 @@ typedef unsigned long uint32; #endif +enum ValueTypeSizes{ + OSC_SIZEOF_INT32 = 4, + OSC_SIZEOF_UINT32 = 4, + OSC_SIZEOF_INT64 = 8, + OSC_SIZEOF_UINT64 = 8, +}; + + +// osc_bundle_element_size_t is used for the size of bundle elements and blobs +// the OSC spec specifies these as int32 (signed) but we ensure that they +// are always positive since negative field sizes make no sense. + +typedef int32 osc_bundle_element_size_t; + +enum { + OSC_INT32_MAX = 0x7FFFFFFF, + + // Element sizes are specified to be int32, and are always rounded up to nearest + // multiple of 4. Therefore their values can't be greater than 0x7FFFFFFC. + OSC_BUNDLE_ELEMENT_SIZE_MAX = 0x7FFFFFFC +}; + + +inline bool IsValidElementSizeValue( osc_bundle_element_size_t x ) +{ + // sizes may not be negative or exceed OSC_BUNDLE_ELEMENT_SIZE_MAX + return x >= 0 && x <= OSC_BUNDLE_ELEMENT_SIZE_MAX; +} + + +inline bool IsMultipleOf4( osc_bundle_element_size_t x ) +{ + return (x & ((osc_bundle_element_size_t)0x03)) == 0; +} + enum TypeTagValues { TRUE_TYPE_TAG = 'T', @@ -78,7 +125,9 @@ enum TypeTagValues { DOUBLE_TYPE_TAG = 'd', STRING_TYPE_TAG = 's', SYMBOL_TYPE_TAG = 'S', - BLOB_TYPE_TAG = 'b' + BLOB_TYPE_TAG = 'b', + ARRAY_BEGIN_TYPE_TAG = '[', + ARRAY_END_TYPE_TAG = ']' }; @@ -120,9 +169,12 @@ extern MessageTerminator EndMessage; struct NilType{ }; -//extern NilType Nil; +extern NilType OscNil; + +#ifndef _OBJC_OBJC_H_ +extern NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead +#endif - struct InfinitumType{ }; @@ -166,13 +218,23 @@ struct Symbol{ struct Blob{ Blob() {} - explicit Blob( const void* data_, unsigned long size_ ) + explicit Blob( const void* data_, osc_bundle_element_size_t size_ ) : data( data_ ), size( size_ ) {} const void* data; - unsigned long size; + osc_bundle_element_size_t size; +}; + +struct ArrayInitiator{ }; +extern ArrayInitiator BeginArray; + +struct ArrayTerminator{ +}; + +extern ArrayTerminator EndArray; + } // namespace osc -#endif /* INCLUDED_OSCTYPES_H */ +#endif /* INCLUDED_OSCPACK_OSCTYPES_H */ diff --git a/oscpack/readme b/oscpack/readme index 61964ce..4382775 100644 --- a/oscpack/readme +++ b/oscpack/readme @@ -1,69 +1,134 @@ oscpack -- Open Sound Control packet manipulation library -http://www.audiomulch.com/~rossb/code/oscpack - -Copyright (c) 2004-2005 Ross Bencina - A simple C++ library for packing and unpacking OSC packets. +http://www.rossbencina.com/code/oscpack + +Copyright (c) 2004-2013 Ross Bencina Oscpack is simply a set of C++ classes for packing and unpacking OSC packets. -Oscpack includes a minimal set of UDP networking classes for windows and posix -which are sufficient for writing many OSC applications and servers, but you are -encouraged to use another networking framework if it better suits your needs. -Oscpack is not an OSC application framework, it doesn't include infrastructure for +Oscpack includes a minimal set of UDP networking classes for Windows and POSIX. +The networking classes are sufficient for writing many OSC applications and servers, +but you are encouraged to use another networking framework if it better suits your needs. +Oscpack is not an OSC application framework. It doesn't include infrastructure for constructing or routing OSC namespaces, just classes for easily constructing, sending, receiving and parsing OSC packets. The library should also be easy to use -for other transport methods (eg serial). +for other transport methods (e.g. serial). The key goals of the oscpack library are: - - to be a simple and complete implementation of OSC - - to be portable to a wide variety of platforms - - to allow easy development of robust OSC applications - (for example it should be impossible to crash a server - by sending it malformed packets, and difficult to - create malformed packets.) + - Be a simple and complete implementation of OSC + - Be portable to a wide variety of platforms + - Allow easy development of robust OSC applications + (for example it should be impossible to crash a server + by sending it malformed packets, and difficult to create + malformed packets.) -Here's a summary of the key files: +Here's a quick run down of the key files: osc/OscReceivedElements -- classes for parsing a packet osc/OscPrintRecievedElements -- iostream << operators for printing packet elements -osc/OscOutboundPacket -- a class for packing messages into a packet +osc/OscOutboundPacketStream -- a class for packing messages into a packet osc/OscPacketListener -- base class for listening to OSC packets on a UdpSocket +ip/IpEndpointName -- class that represents an IP address and port number +ip/UdpSocket -- classes for UDP transmission and listening sockets tests/OscUnitTests -- unit test program for the OSC modules tests/OscSendTests -- examples of how to send messages tests/OscReceiveTest -- example of how to receive the messages sent by OSCSendTests examples/OscDump -- a program that prints received OSC packets +examples/SimpleSend -- a minimal program to send an OSC message +examples/SimpleReceive -- a minimal program to receive an OSC message +osc/ contains all of the OSC related classes +ip/ contains the networking classes + +ip/windows contains the Windows implementation of the networking classes +ip/posix contains the POSIX implementation of the networking classes Building -------- -In general the idea is that you will embed this source code in your projects as you +The idea is that you will embed this source code in your projects as you see fit. The Makefile has an install rule for building a shared library and -installing headers in usr/local. +installing headers in usr/local. It can also build a static library. +There is a CMakeLists.txt for building with cmake. + +Makefile builds +............... + +The Makefile works for Linux and Max OS X. It should also work on other platforms +that have make. Just run: + +$ make + +You can run "make install" if you like. + + +Cmake builds +............ + +There is a CMakeLists.txt file which has been tested with cmake on +Windows and Linux. It should work on other platforms too. +For example, to generate a Visual Studio 10 project, run cmake +like this: + +> cmake -G "Visual Studio 10" + +Run cmake without any parameters to get a list of available generators. + + +Mingw build batch file +...................... + +For Windows there is a batch file for doing a simple test build with +MinGW gcc called make.MinGW32.bat. This will build the test executables +and oscdump in ./bin and run the unit tests. + + +Note: -The Makefile works for Linux and MaxOS X except that if you are on a big endian -machine such as PowerPC Macintosh you need to edit the line which sets the -endianness to OSC_HOST_BIG_ENDIAN (see the makefile comment for details) or it won't -work. If you want to build and install liboscpack as a library on OS X you also need -to edit the $(LIBFILENAME) rule by commenting out the Linux case and uncommenting -the OS X case since OS X uses different gcc flags for shared libraries. +In some rare instances you may need to edit the Makefile or +osc/OscHostEndianness.h to configure oscpack for the endianness of your +processor (see the comments at the top of the Makefile for details). + + + +Verification test +----------------- + +To run the unit tests: + +$ ./bin/OscUnitTests + +To run the send and receive tests. Open two terminals. In one run: + +$ ./bin/OscReceiveTest + +Then in the other terminal run: + +$./bin/OscSendTests + + +You should see an indication that the messages were received +in the first terminal. + +Note that OscSendTests intentionally sends some unexpected +message parameters to test exception handling in the receiver. +You will see some "error while parsing message" messages printed. + +You can use ./bin/OscDump to print out OSC messages received +from any program, including the test programs. -On Windows there is a batch file for doing a simple test build with MinGW gcc called -make.MinGW32.bat. This will build the test executables and oscdump in ./bin and run -the unit tests. -- -If you fix anything or write a set of TCP send/recieve classes -please consider sending me a patch. Thanks :) +If you fix anything or write a set of TCP send/receive classes +please consider sending me a patch. My email address is +rossb@audiomulch.com. Thanks :) For more information about Open Sound Control, see: -http://www.cnmat.berkeley.edu/OpenSoundControl/ - +http://opensoundcontrol.org/ Thanks to Till Bovermann for helping with POSIX networking code and Mac compatibility, and to Martin Kaltenbrunner and the rest of the @@ -73,8 +138,13 @@ for additional help with Linux builds and POSIX implementation details. Portions developed at the Music Technology Group, Audiovisual Institute, University Pompeu Fabra, Barcelona, during my stay as a visiting -researcher, November 2004 - September 2005. +researcher, November 2004 - September 2005. -See the file LICENSE for information about distributing and using this code. +Thanks to Syneme at the University of Calgary for providing financial +support for the 1.1.0 update, December 2012 - March 2013. +See the file CHANGES for information about recent updates. + +See the file LICENSE for information about distributing and using this code. +### diff --git a/oscpack/todo b/oscpack/todo index 309ae68..a9e99fc 100644 --- a/oscpack/todo +++ b/oscpack/todo @@ -14,9 +14,6 @@ TODO: void Stop(); }; - - provide some kind of automatic endianness configuration (hopefully there - are gcc symbols for this) - - work out a way to make the parsing classes totally safe. at a minimum this means adding functions to test for invalid float/doublevalues, making sure the iterators never pass the end of the message, ... diff --git a/tongseng.cpp b/tongseng.cpp index 65edbb2..39c58a4 100644 --- a/tongseng.cpp +++ b/tongseng.cpp @@ -16,8 +16,8 @@ // Based on multitouch code from http://www.steike.com/code/multitouch/ +#include "multitouch.h" #include "tongseng.h" -#include "mt.h" #include #include #include @@ -41,6 +41,7 @@ static bool running = false; static bool verbose = false; static std::string host("localhost"); static int port = 3333; +static int dev_id = 0; // Sensitivity #define MIN_DISTANCE 0.00001f @@ -148,11 +149,14 @@ static void tuio_frame_end() server->commitFrame(); } +typedef void (*MTPathCallbackFunction)(MTDeviceRef device, long pathID, long state, MTTouch* touch); + + // Process incoming events -static int callback(int device, Finger *data, int nFingers, double timestamp, int frame) -{ +static void callback(MTDeviceRef device, MTTouch touches[], size_t numTouches, double timestamp, size_t frame) { + if (!running || !sampling_interval_passed()) { - return 0; + return; } tuio_frame_begin(); @@ -161,12 +165,12 @@ static int callback(int device, Finger *data, int nFingers, double timestamp, in // Process incoming events int i; - for (i=0; iidentifier; + for (i=0; ipathIndex; - float x = f->normalized.pos.x; - float y = 1.0f - f->normalized.pos.y; // reverse y axis + float x = f->normalizedVector.position.x; + float y = 1.0f - f->normalizedVector.position.y; // reverse y axis if (EXISTS(currentFingers, id)) { // update @@ -194,8 +198,6 @@ static int callback(int device, Finger *data, int nFingers, double timestamp, in currentFingers.insert(fingers.begin(), fingers.end()); tuio_frame_end(); - - return 0; } // Start TUIO server @@ -228,13 +230,17 @@ static void tuio_stop() { release_all_fingers(); delete server; - delete oscSender; } // Start handling multitouch events static void mt_start() { - dev = MTDeviceCreateDefault(); + CFArrayRef devList = MTDeviceCreateList(); + if((CFIndex)CFArrayGetCount(devList) - 1 < dev_id) { + std::cout << "Could not find external trackpad, defaulting to internal!" << std::endl; + dev_id = 0; + } + dev = (MTDeviceRef)CFArrayGetValueAtIndex(devList, dev_id); MTRegisterContactFrameCallback(dev, callback); MTDeviceStart(dev, 0); } @@ -260,6 +266,12 @@ void tongseng_set_verbose(int _verbose) verbose = _verbose != 0; } +// Set TUIO server verbosity +void tongseng_set_device(int _id) +{ + dev_id = _id; +} + // Start Tongseng void tongseng_start() { @@ -278,3 +290,17 @@ void tongseng_stop() } } +// List devices +void tongseng_list_devices() +{ + CFArrayRef devList = MTDeviceCreateList(); + CFIndex dev_count = (CFIndex)CFArrayGetCount(devList); + + if (dev_count == 0) std::cout << "no devices found" << std::endl; + else std::cout << "0: default" << std::endl; + + if(dev_count > 1) { + for (int i=1;i<=dev_count;i++) + std::cout << i << ": external" << std::endl; + } +} diff --git a/tongseng.h b/tongseng.h index d4eca01..1a90506 100644 --- a/tongseng.h +++ b/tongseng.h @@ -4,11 +4,13 @@ #ifdef __cplusplus extern "C" { #endif - + void tongseng_set_hostname_and_port(const char*, int); +void tongseng_set_device(int); void tongseng_set_verbose(int); void tongseng_start(); void tongseng_stop(); +void tongseng_list_devices(); #ifdef __cplusplus }