"Initial commit"

This commit is contained in:
gauthiier 2022-03-20 11:57:12 +01:00
commit efb3bfd43b
8 changed files with 3201 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,924 @@
/*
Copyright (c) 2015, The Cinder Project, All rights reserved.
This code is intended for use with the Cinder C++ library: http://libcinder.org
Redistribution and use in source and binary forms, with or without modification, are permitted provided that
the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Toshiro Yamada
Portions Copyright (c) 2011
Distributed under the BSD-License.
https://github.com/toshiroyamada/tnyosc
*/
#pragma once
#if ! defined( ASIO_STANDALONE )
#define ASIO_STANDALONE 1
#endif
#include "asio/asio.hpp"
#include <set>
#include <mutex>
#include "cinder/Buffer.h"
#include "cinder/app/App.h"
#if ! defined( _MSC_VER ) || _MSC_VER >= 1900
#define NOEXCEPT noexcept
#else
#define NOEXCEPT
#endif
namespace cinder {
namespace osc {
//! Argument types suported by the Message class
enum class ArgType : char { INTEGER_32 = 'i', FLOAT = 'f', DOUBLE = 'd', STRING = 's', BLOB = 'b', MIDI = 'm', TIME_TAG = 't', INTEGER_64 = 'h', BOOL_T = 'T', BOOL_F = 'F', CHAR = 'c', NULL_T = 'N', IMPULSE = 'I', NONE = NULL_T };
// Forward declarations
using UdpSocketRef = std::shared_ptr<asio::ip::udp::socket>;
using TcpSocketRef = std::shared_ptr<asio::ip::tcp::socket>;
using AcceptorRef = std::shared_ptr<asio::ip::tcp::acceptor>;
template<size_t size>
using ByteArray = std::array<uint8_t, size>;
using ByteBuffer = std::vector<uint8_t>;
using ByteBufferRef = std::shared_ptr<ByteBuffer>;
/// This class represents an Open Sound Control message. It supports Open Sound
/// Control 1.0 and 1.1 specifications and extra non-standard arguments listed
/// in http://opensoundcontrol.org/spec-1_0.
class Message {
public:
Message();
//! Create an OSC message.
explicit Message( const std::string& address );
Message( const Message & );
Message& operator=( const Message & );
Message( Message && ) NOEXCEPT;
Message& operator=( Message && ) NOEXCEPT;
~Message() = default;
// Functions for appending OSC 1.0 types
//! Appends an int32 to the back of the message.
void append( int32_t v );
//! Appends a float to the back of the message.
void append( float v );
//! Appends a string to the back of the message.
void append( const std::string& v );
//! Appends a null-terminated c-string to the back of message.
void append( const char v[] );
//! Appends an osc blob to the back of the message.
void appendBlob( void* blob, uint32_t size );
//! Appends an osc blob to the back of the message.
void append( const ci::Buffer &buffer );
// Functions for appending OSC 1.1 types
//! Appends an OSC-timetag (NTP format) to the back of the message.
void appendTimeTag( uint64_t v );
//! Appends the current UTP timestamp to the back of the message.
void appendCurrentTime();
//! Appends a 'T'(True) or 'F'(False) to the back of the message.
void append( bool v );
//! Appends a Null (or nil) to the back of the message.
void appendNull() { mIsCached = false; mDataViews.emplace_back( this, ArgType::NULL_T, -1, 0 ); }
//! Appends an Impulse (or IMPULSE) to the back of the message
void appendImpulse() { mIsCached = false; mDataViews.emplace_back( this, ArgType::IMPULSE, -1, 0 ); }
// Functions for appending nonstandard types
//! Appends an int64_t to the back of the message.
void append( int64_t v );
//! Appends a float64 (or double) to the back of the message.
void append( double v );
//! Appends an ascii character to the back of the message.
void append( char v );
//! Appends a midi value to the back of the message.
void appendMidi( uint8_t port, uint8_t status, uint8_t data1, uint8_t data2 );
//! Appends \a arg to the back of the message. Static asserts if Message doesn't know how to
//! convert the type.
template<typename T>
Message& operator<<( T&& arg )
{
appendArg( std::forward<T>(arg) );
return *this;
}
//! Returns the type \a T located at \a index. If index is out of bounds, throws ExcIndexOutOfBounds.
//! If argument isn't convertible to this type, throws ExcNonConvertible
template <typename T>
T getArg( uint32_t index );
//! Returns the int32_t located at \a index. If index is out of bounds, throws ExcIndexOutOfBounds.
//! If argument isn't convertible to this type, throws ExcNonConvertible
int32_t getArgInt32( uint32_t index ) const;
//! Returns the float located at \a index. If index is out of bounds, throws ExcIndexOutOfBounds.
//! If argument isn't convertible to this type, throws ExcNonConvertible
float getArgFloat( uint32_t index ) const;
//! Returns the string located at \a index. If index is out of bounds, throws ExcIndexOutOfBounds.
//! If argument isn't convertible to this type, throws ExcNonConvertible
std::string getArgString( uint32_t index ) const;
//! Supplies the string data located at \a index to the \a dataPtr and \a size. Note: Doesn't copy.
//! If index is out of bounds, throws ExcIndexOutOfBounds. If argument isn't convertible to this type,
//! throws ExcNonConvertible
void getArgStringData( uint32_t index, const char **dataPtr, uint32_t *size ) const;
//! Returns the time_tag located at \a index. If index is out of bounds, throws ExcIndexOutOfBounds.
//! If argument isn't convertible to this type, throws ExcNonConvertible
int64_t getArgTime( uint32_t index ) const;
//! Returns the time_tag located at \a index. If index is out of bounds, throws ExcIndexOutOfBounds.
//! If argument isn't convertible to this type, throws ExcNonConvertible
int64_t getArgInt64( uint32_t index ) const;
//! Returns the double located at \a index. If index is out of bounds, throws ExcIndexOutOfBounds.
//! If argument isn't convertible to this type, throws ExcNonConvertible
double getArgDouble( uint32_t index ) const;
//! Returns the bool located at \a index. If index is out of bounds, throws ExcIndexOutOfBounds.
//! If argument isn't convertible to this type, throws ExcNonConvertible
bool getArgBool( uint32_t index ) const;
//! Returns the char located at \a index. If index is out of bounds, throws ExcIndexOutOfBounds.
//! If argument isn't convertible to this type, throws ExcNonConvertible
char getArgChar( uint32_t index ) const;
//! Supplies values for the four arguments in the midi format located at \a index. If index is out
//! of bounds, throws ExcIndexOutOfBounds. If argument isn't convertible to this type, throws
//! ExcNonConvertible
void getArgMidi( uint32_t index, uint8_t *port, uint8_t *status, uint8_t *data1, uint8_t *data2 ) const;
//! Returns the blob, as a ci::Buffer, located at \a index. If index is out of bounds, throws
//! ExcIndexOutOfBounds. If argument isn't convertible to this type, throws ExcNonConvertible
ci::Buffer getArgBlob( uint32_t index ) const;
//! Supplies the blob data located at \a index to the \a dataPtr and \a size. Note: Doesn't copy.
//! If index is out of bounds, throws ExcIndexOutOfBounds. If argument isn't convertible to this type,
//! throws ExcNonConvertible
void getArgBlobData( uint32_t index, const void **dataPtr, size_t *size ) const;
//! Returns the argument type located at \a index.
ArgType getArgType( uint32_t index ) const;
//! Returns the number of arguments contained.
size_t getNumArgs() const { return mDataViews.size(); }
//! Returns a string in spec format of the contained arguments for validation purposes.
std::string getTypeTagString() const;
//! Sets the OSC address of this message.
void setAddress( const std::string& address );
//! Returns the OSC address of this message.
const std::string& getAddress() const { return mAddress; }
//! Returns the size of this OSC message as a complete packet.
//! Performs a complete cache operation.
size_t getPacketSize() const;
/// Clears the message, specifically any cache, dataViews, and address.
void clear();
class Argument {
public:
Argument();
Argument( Message *owner, ArgType type, int32_t offset, uint32_t size, bool needsSwap = false );
Argument( const Argument &arg );
Argument& operator=( const Argument &arg );
Argument( Argument &&arg ) NOEXCEPT;
Argument& operator=( Argument &&arg ) NOEXCEPT;
~Argument() = default;
//! Returns the arguments type as an ArgType
ArgType getType() const { return mType; }
//! Returns the arguments size, without trailing zeros or size int's taken into account.
uint32_t getSize() const { return mSize; }
//! Returns the offset into the dataBuffer, where this Argument starts.
int32_t getOffset() const { return mOffset; }
//! returns the underlying argument as an int32. If argument isn't convertible to this type,
//! throws ExcNonConvertible
int32_t int32() const;
//! returns the underlying argument as an int64. If argument isn't convertible to this type,
//! throws ExcNonConvertible
int64_t int64() const;
//! returns the underlying argument as a float. If argument isn't convertible to this type,
//! throws ExcNonConvertible
float flt() const;
//! returns the underlying argument as a double. If argument isn't convertible to this type,
//! throws ExcNonConvertible
double dbl() const;
//! returns the underlying argument as a boolean. If argument isn't convertible to this type,
//! throws ExcNonConvertible
bool boolean() const;
//! Supplies values for the four arguments in the midi format located at \a index. If argument
//! isn't convertible to this type, throws ExcNonConvertible.
//! ExcNonConvertible
void midi( uint8_t *port, uint8_t *status, uint8_t *data1, uint8_t *data2 ) const;
//! Returns the underlying argument as a "deep-copied" ci::Buffer. If argument isn't convertible
//! to this type, throws ExcNonConvertible
ci::Buffer blob() const;
//! Supplies the blob data to the \a dataPtr and \a size. Note: Doesn't copy.
//! If argument isn't convertible to this type, throws ExcNonConvertible
void blobData( const void **dataPtr, size_t *size ) const;
//! Returns the underlying argument as a char. If argument isn't convertible to this type,
//! throws ExcNonConvertible
char character() const;
//! Returns the underlying argument as a string. If argument isn't convertible to this type,
//! throws ExcNonConvertible
std::string string() const;
//! Supplies the string data to the \a dataPtr and \a size. Note: Doesn't copy.
//! If argument isn't convertible to this type, throws ExcNonConvertible
void stringData( const char **dataPtr, uint32_t *size ) const;
//! Evaluates the equality of this with \a other
bool operator==( const Argument &other ) const;
//! Converts ArgType \a type to c-string for debug purposes.
static const char* argTypeToString( ArgType type );
//! Helper function to translate from ArgType to the spec's representation of that type.
static char translateArgTypeToCharType( ArgType type );
//! Helper function to translate from the spec's character representation to the ArgType.
static ArgType translateCharTypeToArgType( char type );
private:
//! Simple helper to stream a message's contents to the console.
void outputValueToStream( std::ostream &ostream ) const;
//! Returns true, if before transporting this message, this argument needs a big endian swap
bool needsEndianSwapForTransmit() const { return mNeedsEndianSwapForTransmit; }
//! Implements the swap for all types needing a swap.
void swapEndianForTransmit( uint8_t* buffer ) const;
//! Helper to check if the underlying type is able to be converted to the provided template
//! type \a T.
template<typename T>
bool convertible() const;
Message* mOwner;
ArgType mType;
int32_t mOffset;
uint32_t mSize;
bool mNeedsEndianSwapForTransmit;
friend class Message;
friend std::ostream& operator<<( std::ostream &os, const Message &rhs );
friend std::ostream& operator<<( std::ostream &os, const Message::Argument &rhs );
};
//! Subscript operator returns a const Argument& based on \a index. If index is out of
//! bounds, throws ExcIndexOutOfBounds.
const Argument& operator[]( uint32_t index ) const;
//! Evaluates the equality of this with \a other
bool operator==( const Message &other ) const;
//! Evaluates the inequality of this with \a other
bool operator!=( const Message &other ) const;
//! Returns a const reference of the Sender's (originator) Ip Address. Note: Will only
//! be set by the receiver when the message is received.
const asio::ip::address& getSenderIpAddress() const { return mSenderIpAddress; }
//! Returns the Sender's (originator) Port. Note: Will only
//! be set by the receiver when the message is received.
uint16_t getSenderPort() const { return mSenderPort; }
private:
//! Helper to calculate how many zeros to buffer to create a 4 byte
static uint8_t getTrailingZeros( size_t bufferSize ) { return 4 - ( bufferSize % 4 ); }
//! Helper to get current offset into the buffer.
int32_t getCurrentOffset() {
CI_ASSERT_MSG( mDataBuffer.size() <= std::numeric_limits<int32_t>::max(),
"Argument offset must fit in int32_t" );
return static_cast<int32_t>( mDataBuffer.size() );
}
//! Helper to retrieve the data view of an Argument. Checks the type provided and
//! throws ExcNonConvertible if data view cannot convert the type.
template<typename T>
const Argument& getDataView( uint32_t index ) const;
//! Helper type trait definition of a c-string.
template<class T>
struct is_c_str
: std::integral_constant<
bool,
std::is_same<char const *, typename std::decay<T>::type>::value ||
std::is_same<char *, typename std::decay<T>::type>::value ||
std::is_same<char[], typename std::decay<T>::type>::value
> {};
//! Appends \a t to the back of a message. Checks the type against acceptable types
//! and static_asserts if the type is acceptable.
template <typename T>
void appendArg(T&& t)
{
static_assert(std::is_same<T, int32_t>::value ||
std::is_same<T, int64_t>::value ||
std::is_same<T, std::string>::value ||
std::is_same<T, float>::value ||
std::is_same<T, double>::value ||
std::is_same<T, ci::Buffer>::value ||
std::is_same<T, char>::value ||
std::is_same<T, bool>::value ||
is_c_str<T>::value,
"Unsupported Type in operator<< statement" );
append(std::forward<T>(t));
}
//! Helper to to insert data starting at \a begin for \a with resize/fill in the amount
//! of \a trailingZeros
void appendDataBuffer( const void *begin, size_t size, uint32_t trailingZeros = 0 );
//! Returns a complete byte array of this OSC message as a ByteBufferRef type.
//! The byte buffer is constructed lazily and is cached until the cache is
//! obsolete. Call to |data| and |size| perform the same caching.
ByteBufferRef getSharedBuffer() const;
std::string mAddress;
ByteBuffer mDataBuffer;
std::vector<Argument> mDataViews;
mutable bool mIsCached;
mutable ByteBufferRef mCache;
asio::ip::address mSenderIpAddress;
uint16_t mSenderPort;
//! Create the OSC message and store it in cache.
void createCache() const;
//! Used by receiver to create the inner message.
bool bufferCache( uint8_t *data, size_t size );
friend class Bundle;
friend class SenderBase;
friend class SenderUdp;
friend class ReceiverBase;
friend std::ostream& operator<<( std::ostream &os, const Message &rhs );
public:
class ExcIndexOutOfBounds : public ci::Exception {
public:
ExcIndexOutOfBounds( const std::string &address, uint32_t index )
: Exception( std::string( std::to_string( index ) + " out of bounds from address, " + address ) )
{}
};
class ExcNonConvertible : public ci::Exception {
public:
ExcNonConvertible( const std::string &address, ArgType actualType, ArgType convertToType )
: Exception( address + ": expected type: " +
Argument::argTypeToString( convertToType ) +
", actual type: " +
Argument::argTypeToString( actualType ) )
{}
};
};
template<> inline int32_t Message::getArg( uint32_t index ) { return getArgInt32( index ); }
template<> inline float Message::getArg( uint32_t index ) { return getArgFloat( index ); }
template<> inline std::string Message::getArg( uint32_t index ) { return getArgString( index ); }
template<> inline ci::Buffer Message::getArg( uint32_t index ) { return getArgBlob( index ); }
template<> inline int64_t Message::getArg( uint32_t index ) { return getArgInt64( index ); }
template<> inline double Message::getArg( uint32_t index ) { return getArgDouble( index ); }
template<> inline char Message::getArg( uint32_t index ) { return getArgChar( index ); }
template<> inline bool Message::getArg( uint32_t index ) { return getArgBool( index ); }
//! Convenient stream operator for Message
std::ostream& operator<<( std::ostream &os, const Message &rhs );
std::ostream& operator<<( std::ostream &os, const Message::Argument &rhs );
//! Represents an Open Sound Control bundle message. A bundle can contains any number
//! of Messages and Bundles.
class Bundle {
public:
//! Creates an OSC bundle with timestamp set to immediate. Call set_timetag to
//! set a custom timestamp. Note: The current Receiver's below disregard timestamp
//! and dispatch the contents immediately.
Bundle();
~Bundle() = default;
//! Appends an OSC message to this bundle. The message's byte buffer is immediately
//! copied into this bundle and any changes to the message after the call to this
//! function does not affect this bundle.
void append( const Message &message ) { appendData( message.getSharedBuffer() ); }
//! Appends an OSC bundle to this bundle. The bundle's contents are immediately copied
//! into this bundle and any changes to the message after the call to this
//! function does not affect this bundle.
void append( const Bundle &bundle ) { appendData( bundle.getSharedBuffer() ); }
/// Sets timestamp of the bundle.
void setTimetag( uint64_t ntp_time );
//! Returns the size of this OSC bundle as a complete packet.
size_t getPacketSize() const { return mDataBuffer->size(); }
//! Clears the bundle.
void clear() { initializeBuffer(); }
private:
ByteBufferRef mDataBuffer;
/// Returns a pointer to the byte array of this OSC bundle. This call is
/// convenient for actually sending this OSC bundle.
ByteBufferRef getSharedBuffer() const;
void initializeBuffer();
//! Appends /a data to the internal byte buffer
void appendData( const ByteBufferRef& data );
friend class SenderBase;
friend class SenderUdp;
};
using PacketFramingRef = std::shared_ptr<class PacketFraming>;
class PacketFraming {
public:
virtual ~PacketFraming() = default;
//! Abstract signature to implement the encode process.
virtual ByteBufferRef encode( ByteBufferRef bufferToEncode ) = 0;
//! Abstract signature to implement the decode process.
virtual ByteBufferRef decode( ByteBufferRef bufferToDecode ) = 0;
//! Alias representing the iterator type passed the message complete function.
using iterator = asio::buffers_iterator<asio::streambuf::const_buffers_type>;
//! Abstract signature used to implement the read_until message match_condition. For more info on
//! the use of this function read about match_condition here...
//! http://think-async.com/Asio/asio-1.10.6/doc/asio/reference/async_read_until/overload4.html
virtual std::pair<iterator, bool> messageComplete( iterator begin, iterator end ) = 0;
protected:
PacketFraming() = default;
};
//! Represents an OSC Sender (called a \a server in the OSC spec) and implements a unified
//! interface without implementing any of the networking layer.
class SenderBase {
public:
virtual ~SenderBase() = default;
//! Alias for the send OnErrorFn.
using OnErrorFn = std::function<void( asio::error_code )>;
//! Alias for the send OnCompleteFn.
using OnCompleteFn = std::function<void()>;
//! Binds the underlying network socket. Should be called before trying any communication operations.
//! If an error occurs with either the underlying open or bind operations on the socket, throws
//! osc::Exception with asio::error_code information.
void bind() { bindImpl(); }
//! Sends \a message to the destination endpoint. Takes optional /a onErrorFn and /a onCompleteFn.
//! If error occurs, and an error callback is provided, it will be called with error_code information.
//! If send operation completes and /a onCompleteFn included, it will be called.
void send( const Message &message, OnErrorFn onErrorFn = nullptr, OnCompleteFn onCompleteFn = nullptr );
//! Sends \a bundle to the destination endpoint. Takes optional /a onErrorFn and /a onCompleteFn.
//! If error occurs, and an error callback is provided, it will be called with error_code information.
//! If send operation completes and /a onCompleteFn included, it will be called.
void send( const Bundle &bundle, OnErrorFn onErrorFn = nullptr, OnCompleteFn onCompleteFn = nullptr );
//! Closes the underlying connection to the socket. If an error occurs with either the underlying
//! close operations on the socket, throws osc::Exception with asio::error_code information.
void close() { closeImpl(); }
protected:
SenderBase() = default;
SenderBase( const SenderBase &other ) = delete;
SenderBase& operator=( const SenderBase &other ) = delete;
SenderBase( SenderBase &&other ) = delete;
SenderBase& operator=( SenderBase &&other ) = delete;
//! Abstract send function implemented by the network layer.
virtual void sendImpl( const ByteBufferRef &byteBuffer, OnErrorFn onErrorFn, OnCompleteFn onCompleteFn ) = 0;
//! Helper function to extract the address of an osc message if present.
static std::string extractOscAddress( const ByteBufferRef &transportData );
//! Abstract bind function implemented by the network layer
virtual void bindImpl() = 0;
//! Abstract close function implemented by the network layer
virtual void closeImpl() = 0;
};
//! Represents an OSC Sender (called a \a server in the OSC spec) and implements the UDP
//! transport networking layer.
class SenderUdp : public SenderBase {
public:
//! Alias protocol for cleaner interfaces
using protocol = asio::ip::udp;
//! Constructs a Sender (called a \a server in the OSC spec) using UDP as transport, whose local endpoint is
//! defined by \a localPort and \a protocol, which defaults to v4, and remote endpoint is defined by
//! \a destinationHost and \a destinationPort. Takes an optional io_context, used to construct the socket from.
SenderUdp( uint16_t localPort,
const std::string &destinationHost,
uint16_t destinationPort,
const protocol &protocol = protocol::v4(),
asio::io_context &service = ci::app::App::get()->io_context() );
//! Constructs a Sender (called a \a server in the OSC spec) using UDP as transport, whose local endpoint is
//! defined by \a localPort and \a protocol, which defaults to v4, and remote endpoint is defined by \a
//! destination. Takes an optional io_context, used to construct the socket from.
SenderUdp( uint16_t localPort,
const protocol::endpoint &destination,
const protocol &protocol = protocol::v4(),
asio::io_context &service = ci::app::App::get()->io_context() );
//! Constructs a Sender (called a \a server in the OSC spec) using UDP for transport, with an already created
//! udp::socket shared_ptr \a socket and remote endpoint \a destination. This constructor is good for using
//! already constructed sockets for more indepth configuration. Expects the local endpoint to be constructed.
SenderUdp( const UdpSocketRef &socket, const protocol::endpoint &destination );
//! Default virtual constructor
virtual ~SenderUdp() = default;
//! Returns the local address of the endpoint associated with this socket.
protocol::endpoint getLocalAddress() const { return mSocket->local_endpoint(); }
//! Returns the remote address of the endpoint associated with this transport.
const protocol::endpoint& getRemoteAddress() const { return mRemoteEndpoint; }
protected:
//! Opens and Binds the underlying UDP socket to the protocol and localEndpoint respectively. If an
//! error occurs, throws osc::Exception.
void bindImpl() override;
//! Sends the byte buffer /a data to the remote endpoint using the UDP socket, asynchronously. Takes
//! optional /a options. If error occurs, and SenderOptions provides an error callback, it will be
//! called with information. If /a options includes a completeFn, it will be called.
void sendImpl( const ByteBufferRef &data, OnErrorFn onErrorFn, OnCompleteFn onCompleteFn ) override;
//! Closes the underlying UDP socket. If an error occurs, If an error occurs, throws osc::Exception.
void closeImpl() override;
UdpSocketRef mSocket;
protocol::endpoint mLocalEndpoint, mRemoteEndpoint;
public:
//! Non-copyable.
SenderUdp( const SenderUdp &other ) = delete;
//! Non-copyable.
SenderUdp& operator=( const SenderUdp &other ) = delete;
//! Non-Moveable.
SenderUdp( SenderUdp &&other ) = delete;
//! Non-Moveable.
SenderUdp& operator=( SenderUdp &&other ) = delete;
};
//! Represents an OSC Sender (called a \a server in the OSC spec) and implements the TCP
//! transport networking layer. Implements an optional PacketFraming interface used at
//! construction to define the framing of messages to the endpoint. See PacketFraming above.
class SenderTcp : public SenderBase {
public:
//! Alias protocol for cleaner interfaces
using protocol = asio::ip::tcp;
//! Alias function representing an on connect callback, receiving an error_code and the bound and connected
//! underlying shared_ptr tcp::socket.
using OnConnectFn = std::function<void( asio::error_code )>;
//! Constructs a Sender (called a \a server in the OSC spec) using TCP as transport, whose local endpoint is
//! defined by \a localPort and \a protocol, which defaults to v4, and remote endpoint is defined by \a
//! destinationHost and \a destinationPort and PacketFraming shared_ptr \a packetFraming, which defaults to
//! null. Takes an optional io_context to construct the socket from.
SenderTcp( uint16_t localPort,
const std::string &destinationHost,
uint16_t destinationPort,
const protocol &protocol = protocol::v4(),
asio::io_context &service = ci::app::App::get()->io_context(),
PacketFramingRef packetFraming = nullptr );
//! Constructs a Sender (called a \a server in the OSC spec) using TCP as transport, whose local endpoint is
//! defined by \a localPort and \a protocol, which defaults to v4, and remote endpoint is defined by \a
//! destination and PacketFraming shared_ptr \a packetFraming, which defaults to null. Takes an optional
//! io_context to construct the socket from.
SenderTcp( uint16_t localPort,
const protocol::endpoint &destination,
const protocol &protocol = protocol::v4(),
asio::io_context &service = ci::app::App::get()->io_context(),
PacketFramingRef packetFraming = nullptr );
//! Constructs a Sender (called a \a server in the OSC spec) using TCP as transport, with an already created
//! tcp::socket shared_ptr \a socket, and remote endpoint is defined by \a destination and PacketFraming
//! shared_ptr \a packetFraming, which defaults to null. This constructor is good for using already constructed
//! sockets for more indepth configuration. Expects the local endpoint is already constructed.
SenderTcp( const TcpSocketRef &socket,
const protocol::endpoint &destination,
PacketFramingRef packetFraming = nullptr );
virtual ~SenderTcp();
//! Connects to the remote endpoint using the underlying socket. Has to be called before attempting to
//! send anything. /a onConnectFn called after asynchronous operation finishes, with any errors in the
//! error_code argument
void connect( OnConnectFn onConnectFn );
//! Shuts down the underlying socket. Use this function prior to close to clean up the connection and
//! end socket linger. If an error occurs with the underlying operation on the socket, throws
//! osc::Exception with asio::error_code information.
void shutdown( asio::socket_base::shutdown_type shutdownType = asio::socket_base::shutdown_both );
//! Returns the local address of the endpoint associated with this socket.
protocol::endpoint getLocalEndpoint() const { return mSocket->local_endpoint(); }
//! Returns the remote address of the endpoint associated with this transport.
const protocol::endpoint& getRemoteEndpoint() const { return mRemoteEndpoint; }
protected:
//! Opens and Binds the underlying TCP socket to the protocol and localEndpoint respectively. If an
//! error occurs, throws osc::Exception.
void bindImpl() override;
//! Sends the byte buffer /a data to the remote endpoint using the TCP socket, asynchronously. Takes
//! optional /a options. If error occurs, and SenderOptions provides an error callback, it will be
//! called with information. If /a options includes a completeFn, it will be called.
void sendImpl( const ByteBufferRef &data, OnErrorFn onErrorFn, OnCompleteFn onCompleteFn ) override;
//! Closes the underlying TCP socket. If error occurs, throws osc::Exception.
void closeImpl() override;
TcpSocketRef mSocket;
PacketFramingRef mPacketFraming;
asio::ip::tcp::endpoint mLocalEndpoint, mRemoteEndpoint;
public:
//! Non-copyable.
SenderTcp( const SenderTcp &other ) = delete;
//! Non-copyable.
SenderTcp& operator=( const SenderTcp &other ) = delete;
//! Non-Moveable.
SenderTcp( SenderTcp &&other ) = delete;
//! Non-Moveable.
SenderTcp& operator=( SenderTcp &&other ) = delete;
};
//! Represents an OSC Receiver(called a \a client in the OSC spec) and implements a unified
//! interface without implementing any of the networking layer.
class ReceiverBase {
public:
virtual ~ReceiverBase() = default;
//! Alias function representing a message callback.
using ListenerFn = std::function<void( const Message &message )>;
//! Alias container for callbacks.
using Listeners = std::vector<std::pair<std::string, ListenerFn>>;
//! Binds the underlying network socket. Should be called before executing communication operations.
void bind() { bindImpl(); }
//! Closes the underlying network socket. Should be called on most errors to reset the socket.
void close() { closeImpl(); }
//! Sets a callback, \a listener, to be called when receiving a message with \a address. If a ListenerFn
//! does not exist for a specific address, any messages with that address will be disregarded. If a ListenerFn
//! already exists for this address, \a listener will replace it.
void setListener( const std::string &address, ListenerFn listener );
//! Removes the listener associated with \a address.
void removeListener( const std::string &address );
protected:
ReceiverBase() = default;
//! Non-copyable.
ReceiverBase( const ReceiverBase &other ) = delete;
//! Non-copyable.
ReceiverBase& operator=( const ReceiverBase &other ) = delete;
//! Non-Moveable.
ReceiverBase( ReceiverBase &&other ) = delete;
//! Non-Moveable.
ReceiverBase& operator=( ReceiverBase &&other ) = delete;
//! Decodes and routes messages from the networking layer stream. Dispatches all messages with
//! an address that has an associated listener.
void dispatchMethods( uint8_t *data, uint32_t size, const asio::ip::address &senderIpAddress, uint16_t senderPort );
//! Decodes a complete OSC Packet into it's individual parts. \a timetag is ignored within the
//! below implementations.
bool decodeData( uint8_t *data, uint32_t size, std::vector<Message> &messages, uint64_t timetag = 0 ) const;
//! Decodes an individual message. \a timetag is ignored within the below implementations.
bool decodeMessage( uint8_t *data, uint32_t size, std::vector<Message> &messages, uint64_t timetag = 0 ) const;
//! Matches the addresses of messages based on the OSC spec.
bool patternMatch( const std::string &lhs, const std::string &rhs ) const;
//! Abstract bind implementation function.
virtual void bindImpl() = 0;
//! Abstract close implementation function.
virtual void closeImpl() = 0;
Listeners mListeners;
std::mutex mListenerMutex;
std::set<std::string> mDisregardedAddresses;
};
//! Represents an OSC Receiver(called a \a client in the OSC spec) and implements the UDP transport
//! networking layer.
class ReceiverUdp : public ReceiverBase {
public:
//! Alias protocol for cleaner interfaces
using protocol = asio::ip::udp;
//! Alias function that represents a general error callback for the socket, with an error_code and
//! orginating endpoint if present. To see more about asio's error_codes, look at "asio/error.hpp".
using OnSocketErrorFn = std::function<bool( asio::error_code /*error*/, protocol::endpoint /*originator*/)>;
//! Constructs a Receiver (called a \a client in the OSC spec) using UDP for transport, whose local endpoint
//! is defined by \a localPort and \a protocol, which defaults to v4. Takes an optional io_context to
//! construct the socket from.
ReceiverUdp( uint16_t port,
const protocol &protocol = protocol::v4(),
asio::io_context &io = ci::app::App::get()->io_context() );
//! Constructs a Receiver (called a \a client in the OSC spec) using UDP for transport, whose local endpoint
//! is defined by \a localEndpoint. Takes an optional io_context to construct the socket from.
ReceiverUdp( const protocol::endpoint &localEndpoint,
asio::io_context &io = ci::app::App::get()->io_context() );
//! Constructs a Receiver (called a \a client in the OSC spec) using UDP for transport, from the already
//! constructed udp::socket shared_ptr \a socket. Use this for extra configuration and or sharing sockets
//! between sender and receiver.
ReceiverUdp( UdpSocketRef socket );
virtual ~ReceiverUdp() = default;
//! Commits the socket to asynchronously listen and begin to receive from outside connections.
//! /a onSocketErrorFn will be called in the case that any socket error is propagated.
void listen( OnSocketErrorFn onSocketErrorFn );
//! Sets the amount of bytes to reserve for the datagrams being received.
void setAmountToReceive( uint32_t amountToReceive );
//! Returns the local udp::endpoint of the underlying socket.
asio::ip::udp::endpoint getLocalEndpoint() { return mSocket->local_endpoint(); }
protected:
//! Opens and Binds the underlying UDP socket to the protocol and localEndpoint respectively. If an error occurs,
//! the SocketTranportErrorFn will be called with a default constructed endpoint.
void bindImpl() override;
//! Closes the underlying UDP socket. If an error occurs, the SocketTranportErrorFn will be called with a
//! default constructed endpoint.
void closeImpl() override;
UdpSocketRef mSocket;
asio::ip::udp::endpoint mLocalEndpoint;
asio::streambuf mBuffer;
std::atomic<uint32_t> mAmountToReceive;
public:
//! Non-copyable.
ReceiverUdp( const ReceiverUdp &other ) = delete;
//! Non-copyable.
ReceiverUdp& operator=( const ReceiverUdp &other ) = delete;
//! Non-Moveable.
ReceiverUdp( ReceiverUdp &&other ) = delete;
//! Non-Moveable.
ReceiverUdp& operator=( ReceiverUdp &&other ) = delete;
};
//! Represents an OSC Receiver(called a \a client in the OSC spec) and implements the TCP
//! transport networking layer.
class ReceiverTcp : public ReceiverBase {
public:
//! Alias protocol for cleaner interfaces
using protocol = asio::ip::tcp;
//! Alias function that represents a general error callback for the socket, arguments include
//! the error_code and the connectionIdentifier. To see more about asio's error_codes, look
//! at "asio/error.hpp". The connectionIdentifier can be used to close the underlying socket
//! and notify the rest of your system.
using ConnectionErrorFn = std::function<void( asio::error_code /*error*/, uint64_t /*connectionId*/ )>;
//! Alias function that represents an on accept callback with the constructed tcp::socket and the
//! connectionIdentifier. The connectionIdentifier is useful to target closing the underlying
//! socket at a later time. Function should return whether the Receiver should or should not cache
//! the connection.
using OnAcceptFn = std::function<bool( TcpSocketRef /*accepted socket*/, uint64_t /*connectionId*/)>;
//! Alias function that represents a general error callback for the underlying tcp::acceptor,
//! arguments include the error_code and possible remote endpoint. Function should return whether or
//! not the acceptor should continue to accept. To see more about asio's error_codes,
//! look at "asio/error.hpp"
using OnAcceptErrorFn = std::function<bool( asio::error_code /*error*/,
protocol::endpoint /*remote endpoint*/ )>;
//! Constructs a Receiver (called a \a client in the OSC spec) using TCP for transport, whose
//! local endpoint is defined by \a localPort and \a protocol, which defaults to v4, and
//! PacketFraming shared_ptr \a packetFraming, which defaults to null. Takes an optional io_context
//! to construct the socket from.
ReceiverTcp( uint16_t port,
const protocol &protocol = protocol::v4(),
asio::io_context &service = ci::app::App::get()->io_context(),
PacketFramingRef packetFraming = nullptr );
//! Constructs a Receiver (called a \a client in the OSC spec) using TCP for transport, whose local endpoint
//! is defined by \a localEndpoint and PacketFraming shared_ptr \a packetFraming, which defaults to null. Takes
//! an optional io_context to construct the socket from.
ReceiverTcp( const protocol::endpoint &localEndpoint,
asio::io_context &service = ci::app::App::get()->io_context(),
PacketFramingRef packetFraming = nullptr );
//! Constructs a Receiver (called a \a client in the OSC spec) using TCP for transport, from the already
//! constructed tcp::acceptor shared_ptr \a acceptor and PacketFraming shared_ptr \a packetFraming, which
//! defaults to null. Use this for extra configuration.
ReceiverTcp( AcceptorRef acceptor,
PacketFramingRef packetFraming = nullptr );
//! Constructs a Receiver (called a \a client in the OSC spec) using TCP for transport, from the already
//! constructed tcp::socket shared_ptr \a connection and PacketFraming shared_ptr \a packetFraming, which
//! defaults to null. Advanced use only. Does not instantiate an acceptor.
ReceiverTcp( TcpSocketRef connection,
PacketFramingRef packetFraming = nullptr );
virtual ~ReceiverTcp();
//! Launches acceptor to asynchronously accept connections. If an error occurs, the /a onAcceptErrorFn
//! will be called. When a connection is accepted, /a onAcceptFn will be called.
void accept( OnAcceptErrorFn onAcceptErrorFn, OnAcceptFn onAcceptFn );
//! Sets the underlying SocketTransportErrorFn, called on any errors happening on the underlying sockets.
void setConnectionErrorFn( ConnectionErrorFn errorFn );
//! Closes the underlying acceptor. Must rebind to listen again after calling this function.
void closeAcceptor();
//! Closes the Connection associated with the connectionIdentifier. \a connectionIdentifier is the handle
//! to the socket, received in the OnAccept method. \a shutdownType sets the shutdown method for the underlying
//! socket before closing it. See OnAcceptFn and SocketTransportErrorFn for more.
asio::error_code closeConnection( uint64_t connectionIdentifier, asio::socket_base::shutdown_type shutdownType = asio::socket_base::shutdown_both );
protected:
//! Handles reading from the socket.
struct Connection {
//! Constructs a Connection with \a socket,\a transport, and \a identifier.
Connection( TcpSocketRef socket, ReceiverTcp* transport, uint64_t identifier );
~Connection();
//! Implements asynchronous read on the underlying socket. Handles the async receive completion operations.
void read();
asio::error_code shutdown( asio::socket_base::shutdown_type shutdownType );
//! Simple alias for asio buffer iterator type.
using iterator = asio::buffers_iterator<asio::streambuf::const_buffers_type>;
//! Static method which is used to read the stream as it's coming in and notate each packet. Implementation
//! based on the OSC 1.0 spec.
static std::pair<iterator, bool> readMatchCondition( iterator begin, iterator end );
TcpSocketRef mSocket;
ReceiverTcp* mReceiver;
asio::streambuf mBuffer;
std::atomic<bool> mIsConnected;
const uint64_t mIdentifier;
//! Non-copyable.
Connection( const Connection &other ) = delete;
//! Non-copyable.
Connection& operator=( const Connection &other ) = delete;
//! Non-moveable.
Connection( Connection &&other ) = delete;
//! Non-moveable.
Connection& operator=( Connection &&other ) = delete;
friend class ReceiverTcp;
};
//! Opens and Binds the underlying TCP acceptor to the protocol and localEndpoint respectively. If an error occurs,
//! the AccpetorErrorFn will be called.
void bindImpl() override;
//! Implements the close operation for the underlying sockets and acceptor. For the underlying socket, shutdown is
//! called on the prior to close. If an error occurs, the AcceptorErrorFn or the SocketErrorFn will be called
//! respectively.
void closeImpl() override;
AcceptorRef mAcceptor;
PacketFramingRef mPacketFraming;
protocol::endpoint mLocalEndpoint;
ConnectionErrorFn mConnectionErrorFn;
std::mutex mConnectionMutex, mConnectionErrorFnMutex;
//! Alias representing each connection.
using UniqueConnection = std::unique_ptr<Connection>;
std::vector<UniqueConnection> mConnections;
uint64_t mConnectionIdentifiers;
std::atomic<bool> mIsShuttingDown;
friend struct Connection;
public:
//! Non-copyable.
ReceiverTcp( const ReceiverTcp &other ) = delete;
//! Non-copyable.
ReceiverTcp& operator=( const ReceiverTcp &other ) = delete;
//! Non-Moveable.
ReceiverTcp( ReceiverTcp &&other ) = delete;
//! Non-Moveable.
ReceiverTcp& operator=( ReceiverTcp &&other ) = delete;
};
//! Implements the SLIP encode and decode process for Stream Packet Framing. This is the recommended
//! standard for the OSC 1.1 specification. Code contribution from https://github.com/pizthewiz/Cinder-Encoding.
class SLIPPacketFraming : public PacketFraming {
public:
SLIPPacketFraming() = default;
virtual ~SLIPPacketFraming() = default;
//! SLIP encodes \a bufferToEncode returning the encoded ByteBufferRef.
ByteBufferRef encode( ByteBufferRef bufferToEncode ) override;
//! SLIP decodes \a bufferToDecode returning the decoded ByteBufferRef.
ByteBufferRef decode( ByteBufferRef bufferToDecode ) override;
//! Message Match condition for SLIP encoding.
std::pair<iterator, bool> messageComplete( iterator begin, iterator end ) override;
//! Const values used in the SLIP encoding/decoding process.
static const uint8_t SLIP_END = 0xC0;
static const uint8_t SLIP_ESC = 0xDB;
static const uint8_t SLIP_ESC_END = 0xDC;
static const uint8_t SLIP_ESC_ESC = 0xDD;
protected:
//! Implements the encoding process.
size_t encode( const uint8_t* data, size_t size, uint8_t* encodedData );
//! Implements the decoding process.
size_t decode( const uint8_t* data, size_t size, uint8_t* decodedData );
};
class Exception : public ci::Exception {
public:
Exception( asio::error_code error ) : ci::Exception( error.message() ), mError( error ) {}
//! Returns system level value of the error for reference online. Very helpful information
//! can be found using this number.
int32_t value() const { return mError.value(); }
private:
asio::error_code mError;
};
namespace time {
using milliseconds = std::chrono::milliseconds;
//! Returns system clock time.
uint64_t get_current_ntp_time( milliseconds offsetMillis = milliseconds( 0 ) );
//! Returns the current presentation time as NTP time, which may include an offset to the system clock.
uint64_t getFutureClockWithOffset( milliseconds offsetFuture = milliseconds( 0 ), int64_t localOffsetSecs = 0, int64_t localOffsetUSecs = 0 );
//! Returns the current presentation time as a string.
std::string getClockString( uint64_t ntpTime, bool includeDate = false );
//! Sets the current presentation time as NTP time, from which an offset to the system clock is calculated.
void calcOffsetFromSystem( uint64_t ntpTime, int64_t *localOffsetSecs, int64_t *localOffsetUSecs );
} // namespace time
} // namespace osc
} // namespace cinder

8
include/Resources.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include "cinder/CinderResources.h"
//#define RES_MY_RES CINDER_RESOURCE( ../resources/, image_name.png, 128, IMAGE )

BIN
resources/CinderApp.icns Normal file

Binary file not shown.

34
src/voicemachineApp.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
using namespace ci;
using namespace ci::app;
using namespace std;
class voicemachineApp : public App {
public:
void setup() override;
void mouseDown( MouseEvent event ) override;
void update() override;
void draw() override;
};
void voicemachineApp::setup()
{
}
void voicemachineApp::mouseDown( MouseEvent event )
{
}
void voicemachineApp::update()
{
}
void voicemachineApp::draw()
{
gl::clear( Color( 0, 0, 0 ) );
}
CINDER_APP( voicemachineApp, RendererGl )

34
xcode/Info.plist Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string>CinderApp.icns</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 __MyCompanyName__. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@ -0,0 +1,386 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
006D720419952D00008149E2 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 006D720219952D00008149E2 /* AVFoundation.framework */; };
006D720519952D00008149E2 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 006D720319952D00008149E2 /* CoreMedia.framework */; };
0091D8F90E81B9330029341E /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0091D8F80E81B9330029341E /* OpenGL.framework */; };
00B784B30FF439BC000DE1D7 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B784AF0FF439BC000DE1D7 /* Accelerate.framework */; };
00B784B40FF439BC000DE1D7 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B784B00FF439BC000DE1D7 /* AudioToolbox.framework */; };
00B784B50FF439BC000DE1D7 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B784B10FF439BC000DE1D7 /* AudioUnit.framework */; };
00B784B60FF439BC000DE1D7 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B784B20FF439BC000DE1D7 /* CoreAudio.framework */; };
00B9955A1B128DF400A5C623 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B995581B128DF400A5C623 /* IOKit.framework */; };
00B9955B1B128DF400A5C623 /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B995591B128DF400A5C623 /* IOSurface.framework */; };
5323E6B20EAFCA74003A9687 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5323E6B10EAFCA74003A9687 /* CoreVideo.framework */; };
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
4C873AE62C144407A9725762 /* Osc.h in Headers */ = {isa = PBXBuildFile; fileRef = A43DE166BACA4EFFBF60EEAD /* Osc.h */; };
61BC22F18F324E6E8815BD34 /* Osc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EEED49B18AF14821BF61F719 /* Osc.cpp */; };
9694A235FF1F47B6B3C80AEC /* voicemachine_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = BA89722D261F445CBA3D8E1C /* voicemachine_Prefix.pch */; };
7CFBE1F4D6B14DE585A12E16 /* CinderApp.icns in Resources */ = {isa = PBXBuildFile; fileRef = AE451D503FF042C9AE08908C /* CinderApp.icns */; };
A6850AE63D214AEDA0375FB5 /* Resources.h in Headers */ = {isa = PBXBuildFile; fileRef = D36537B11C304E7DAA1E9FDD /* Resources.h */; };
14BED3D2B12E45A98475E9EA /* voicemachineApp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B0C0230F695948E8B2D6A7B3 /* voicemachineApp.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
006D720219952D00008149E2 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
006D720319952D00008149E2 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
0091D8F80E81B9330029341E /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
00B784AF0FF439BC000DE1D7 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
00B784B00FF439BC000DE1D7 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
00B784B10FF439BC000DE1D7 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
00B784B20FF439BC000DE1D7 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
00B995581B128DF400A5C623 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
00B995591B128DF400A5C623 /* IOSurface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOSurface.framework; path = System/Library/Frameworks/IOSurface.framework; sourceTree = SDKROOT; };
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
5323E6B10EAFCA74003A9687 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = /System/Library/Frameworks/CoreVideo.framework; sourceTree = "<absolute>"; };
8D1107320486CEB800E47090 /* voicemachine.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = voicemachine.app; sourceTree = BUILT_PRODUCTS_DIR; };
B0C0230F695948E8B2D6A7B3 /* voicemachineApp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.cpp; path = ../src/voicemachineApp.cpp; sourceTree = "<group>"; name = voicemachineApp.cpp; };
D36537B11C304E7DAA1E9FDD /* Resources.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ../include/Resources.h; sourceTree = "<group>"; name = Resources.h; };
AE451D503FF042C9AE08908C /* CinderApp.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = ../resources/CinderApp.icns; sourceTree = "<group>"; name = CinderApp.icns; };
16410EF0C18C4B3D9B23B091 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; name = Info.plist; };
BA89722D261F445CBA3D8E1C /* voicemachine_Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = "\"\""; path = voicemachine_Prefix.pch; sourceTree = "<group>"; name = voicemachine_Prefix.pch; };
EEED49B18AF14821BF61F719 /* Osc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.cpp; path = ../blocks/OSC/src/cinder/osc/Osc.cpp; sourceTree = "<group>"; name = Osc.cpp; };
A43DE166BACA4EFFBF60EEAD /* Osc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ../blocks/OSC/src/cinder/osc/Osc.h; sourceTree = "<group>"; name = Osc.h; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8D11072E0486CEB800E47090 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
006D720419952D00008149E2 /* AVFoundation.framework in Frameworks */,
006D720519952D00008149E2 /* CoreMedia.framework in Frameworks */,
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
0091D8F90E81B9330029341E /* OpenGL.framework in Frameworks */,
5323E6B20EAFCA74003A9687 /* CoreVideo.framework in Frameworks */,
00B784B30FF439BC000DE1D7 /* Accelerate.framework in Frameworks */,
00B784B40FF439BC000DE1D7 /* AudioToolbox.framework in Frameworks */,
00B784B50FF439BC000DE1D7 /* AudioUnit.framework in Frameworks */,
00B784B60FF439BC000DE1D7 /* CoreAudio.framework in Frameworks */,
00B9955A1B128DF400A5C623 /* IOKit.framework in Frameworks */,
00B9955B1B128DF400A5C623 /* IOSurface.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
080E96DDFE201D6D7F000001 /* Source */ = {
isa = PBXGroup;
children = (
B0C0230F695948E8B2D6A7B3 /* voicemachineApp.cpp */,
);
name = Source;
sourceTree = "<group>";
};
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
isa = PBXGroup;
children = (
006D720219952D00008149E2 /* AVFoundation.framework */,
006D720319952D00008149E2 /* CoreMedia.framework */,
00B784AF0FF439BC000DE1D7 /* Accelerate.framework */,
00B784B00FF439BC000DE1D7 /* AudioToolbox.framework */,
00B784B10FF439BC000DE1D7 /* AudioUnit.framework */,
00B784B20FF439BC000DE1D7 /* CoreAudio.framework */,
5323E6B10EAFCA74003A9687 /* CoreVideo.framework */,
0091D8F80E81B9330029341E /* OpenGL.framework */,
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
00B995581B128DF400A5C623 /* IOKit.framework */,
00B995591B128DF400A5C623 /* IOSurface.framework */,
);
name = "Linked Frameworks";
sourceTree = "<group>";
};
1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
isa = PBXGroup;
children = (
29B97324FDCFA39411CA2CEA /* AppKit.framework */,
29B97325FDCFA39411CA2CEA /* Foundation.framework */,
);
name = "Other Frameworks";
sourceTree = "<group>";
};
19C28FACFE9D520D11CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
8D1107320486CEB800E47090 /* voicemachine.app */,
);
name = Products;
sourceTree = "<group>";
};
29B97314FDCFA39411CA2CEA /* voicemachine */ = {
isa = PBXGroup;
children = (
01B97315FEAEA392516A2CEA /* Blocks */,
29B97315FDCFA39411CA2CEA /* Headers */,
080E96DDFE201D6D7F000001 /* Source */,
29B97317FDCFA39411CA2CEA /* Resources */,
29B97323FDCFA39411CA2CEA /* Frameworks */,
19C28FACFE9D520D11CA2CBB /* Products */,
);
name = voicemachine;
sourceTree = "<group>";
};
A844FD97CE404410A8F0EE52 /* osc */ = {
isa = PBXGroup;
children = (
EEED49B18AF14821BF61F719 /* Osc.cpp */,
A43DE166BACA4EFFBF60EEAD /* Osc.h */,
);
name = osc;
sourceTree = "<group>";
};
62DA978992674AE3A1DE794A /* cinder */ = {
isa = PBXGroup;
children = (
A844FD97CE404410A8F0EE52 /* osc */,
);
name = cinder;
sourceTree = "<group>";
};
945EEA54632045E092AADDB7 /* src */ = {
isa = PBXGroup;
children = (
62DA978992674AE3A1DE794A /* cinder */,
);
name = src;
sourceTree = "<group>";
};
674D71528C1B4016B5E8F7A8 /* OSC */ = {
isa = PBXGroup;
children = (
945EEA54632045E092AADDB7 /* src */,
);
name = OSC;
sourceTree = "<group>";
};
01B97315FEAEA392516A2CEA /* Blocks */ = {
isa = PBXGroup;
children = (
674D71528C1B4016B5E8F7A8 /* OSC */,
);
name = Blocks;
sourceTree = "<group>";
};
29B97315FDCFA39411CA2CEA /* Headers */ = {
isa = PBXGroup;
children = (
D36537B11C304E7DAA1E9FDD /* Resources.h */,
BA89722D261F445CBA3D8E1C /* voicemachine_Prefix.pch */,
);
name = Headers;
sourceTree = "<group>";
};
29B97317FDCFA39411CA2CEA /* Resources */ = {
isa = PBXGroup;
children = (
AE451D503FF042C9AE08908C /* CinderApp.icns */,
16410EF0C18C4B3D9B23B091 /* Info.plist */,
);
name = Resources;
sourceTree = "<group>";
};
29B97323FDCFA39411CA2CEA /* Frameworks */ = {
isa = PBXGroup;
children = (
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8D1107260486CEB800E47090 /* voicemachine */ = {
isa = PBXNativeTarget;
buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "voicemachine" */;
buildPhases = (
8D1107290486CEB800E47090 /* Resources */,
8D11072C0486CEB800E47090 /* Sources */,
8D11072E0486CEB800E47090 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = voicemachine;
productInstallPath = "$(HOME)/Applications";
productName = voicemachine;
productReference = 8D1107320486CEB800E47090 /* voicemachine.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "voicemachine" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
Japanese,
French,
German,
);
mainGroup = 29B97314FDCFA39411CA2CEA /* voicemachine */;
projectDirPath = "";
projectRoot = "";
targets = (
8D1107260486CEB800E47090 /* voicemachine */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
8D1107290486CEB800E47090 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7CFBE1F4D6B14DE585A12E16 /* CinderApp.icns in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8D11072C0486CEB800E47090 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14BED3D2B12E45A98475E9EA /* voicemachineApp.cpp in Sources */,
61BC22F18F324E6E8815BD34 /* Osc.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = voicemachine_Prefix.pch;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
OTHER_LDFLAGS = "\"$(CINDER_PATH)/lib/macosx/$(CONFIGURATION)/libcinder.a\"";
PRODUCT_BUNDLE_IDENTIFIER = "org.libcinder.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = voicemachine;
SYMROOT = ./build;
WRAPPER_EXTENSION = app;
};
name = Debug;
};
C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_FAST_MATH = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_OPTIMIZATION_LEVEL = 3;
GCC_PREPROCESSOR_DEFINITIONS = (
"NDEBUG=1",
"$(inherited)",
);
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = voicemachine_Prefix.pch;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Applications";
OTHER_LDFLAGS = "\"$(CINDER_PATH)/lib/macosx/$(CONFIGURATION)/libcinder.a\"";
PRODUCT_BUNDLE_IDENTIFIER = "org.libcinder.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = voicemachine;
STRIP_INSTALLED_PRODUCT = YES;
SYMROOT = ./build;
WRAPPER_EXTENSION = app;
};
name = Release;
};
C01FCF4F08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CINDER_PATH = "../../../../../../../../D/___systems/Cinder";
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
ENABLE_TESTABILITY = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "\"$(CINDER_PATH)/include\"";
MACOSX_DEPLOYMENT_TARGET = 10.13;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
USER_HEADER_SEARCH_PATHS = (
"\"$(CINDER_PATH)/include\" ../include",
../blocks/OSC/src,
);
};
name = Debug;
};
C01FCF5008A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CINDER_PATH = "../../../../../../../../D/___systems/Cinder";
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "\"$(CINDER_PATH)/include\"";
MACOSX_DEPLOYMENT_TARGET = 10.13;
SDKROOT = macosx;
USER_HEADER_SEARCH_PATHS = (
"\"$(CINDER_PATH)/include\" ../include",
../blocks/OSC/src,
);
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "voicemachine" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C01FCF4B08A954540054247B /* Debug */,
C01FCF4C08A954540054247B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C01FCF4E08A954540054247B /* Build configuration list for PBXProject "voicemachine" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C01FCF4F08A954540054247B /* Debug */,
C01FCF5008A954540054247B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
}

View File

@ -0,0 +1,12 @@
#if defined( __cplusplus )
#include "cinder/Cinder.h"
#include "cinder/app/App.h"
#include "cinder/gl/gl.h"
#include "cinder/CinderMath.h"
#include "cinder/Matrix.h"
#include "cinder/Vector.h"
#include "cinder/Quaternion.h"
#endif