Mercurial > hg > midi-score-follower
changeset 0:b299a65a3ad0
start project
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxFileDialogOSX/src/ofxFileDialogOSX.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,147 @@ +/* + * ofxFileDialogOSX.cpp + * + * Created by timknapen on 07/05/10. + * www.wereldderindianen.be + * code stolen from 'mantissa' over here: + * http://www.openframeworks.cc/forum/viewtopic.php?p=5028#p5028 + * + */ + +#include "ofxFileDialogOSX.h" + + +//--------------------------------------------------------------------------------- +int ofxFileDialogOSX::saveFile(string& URL, string& fileURL){ + + short fRefNumOut; + FSRef output_file; + OSStatus err; + + NavDialogCreationOptions options; + NavGetDefaultDialogCreationOptions( &options ); + options.modality = kWindowModalityAppModal; + + NavDialogRef dialog; + err = NavCreatePutFileDialog(&options, '.mov', 'Moov', NULL, NULL, &dialog); + err = NavDialogRun(dialog); + + NavUserAction action; + action = NavDialogGetUserAction( dialog ); + if (action == kNavUserActionNone || action == kNavUserActionCancel) return 0; + + NavReplyRecord reply; + err = NavDialogGetReply(dialog, &reply); + if ( err != noErr ) return 0; + + if ( reply.replacing ) + { + printf("need to replace\n"); + } + + AEKeyword keyword; + DescType actual_type; + Size actual_size; + FSRef output_dir; + err = AEGetNthPtr(&(reply.selection), 1, typeFSRef, &keyword, &actual_type, + &output_dir, sizeof(output_file), &actual_size); + + + + CFURLRef cfUrl = CFURLCreateFromFSRef( kCFAllocatorDefault, &output_dir ); + CFStringRef cfString = NULL; + if ( cfUrl != NULL ) + { + cfString = CFURLCopyFileSystemPath( cfUrl, kCFURLPOSIXPathStyle ); // LEAK? + CFRelease( cfUrl ); + } + + // copy from a CFString into a local c string (http://www.carbondev.com/site/?page=CStrings+) + const int kBufferSize = 255; + + char folderURL[kBufferSize]; + Boolean bool1 = CFStringGetCString(cfString,folderURL,kBufferSize,kCFStringEncodingMacRoman); + + char fileName[kBufferSize]; + Boolean bool2 = CFStringGetCString(reply.saveFileName,fileName,kBufferSize,kCFStringEncodingMacRoman); + + URL = folderURL; + fileURL = fileName; + // cleanup dialog + NavDialogDispose(dialog); + // dispose of reply: + NavDisposeReply(&reply); + // dispose of cfString + CFRelease( cfString ); + + + return 1; +} + + +//--------------------------------------------------------------------------------- +int ofxFileDialogOSX::openFile(string& URL){ + + short fRefNumOut; + FSRef output_file; + OSStatus err; + + NavDialogCreationOptions options; + NavGetDefaultDialogCreationOptions( &options ); + options.modality = kWindowModalityAppModal; + // adding a banner + // options.message = CFStringCreateWithCString(kCFAllocatorDefault, "hello world", kCFStringEncodingMacRoman); + NavDialogRef dialog; + + err = NavCreateGetFileDialog(&options, NULL, NULL ,NULL, NULL, NULL, &dialog); + err = NavDialogRun(dialog); + + NavUserAction action; + action = NavDialogGetUserAction( dialog ); + + if (action == kNavUserActionNone || action == kNavUserActionCancel) { + cout << "no action or action cancel" << endl; + return 0; + } + + // get dialog reply + NavReplyRecord reply; + err = NavDialogGetReply(dialog, &reply); + if ( err != noErr ){ + cout << "error getting DialogReply" << endl; + return 0; + } + if ( reply.replacing ) + { + cout << (" need to replace\n ") << endl; + } + + AEKeyword keyword; + DescType actual_type; + Size actual_size; + FSRef output_dir; + err = AEGetNthPtr(&(reply.selection), 1, typeFSRef, &keyword, &actual_type, + &output_dir, sizeof(output_file), &actual_size); + + CFURLRef cfUrl = CFURLCreateFromFSRef( kCFAllocatorDefault, &output_dir ); + CFStringRef cfString = NULL; + if ( cfUrl != NULL ) + { + cfString = CFURLCopyFileSystemPath( cfUrl, kCFURLPOSIXPathStyle ); + CFRelease( cfUrl ); + } + + // copy from a CFString into a local c string (http://www.carbondev.com/site/?page=CStrings+) + const int kBufferSize = 255; + + char fileURL[kBufferSize]; + Boolean bool1 = CFStringGetCString(cfString,fileURL,kBufferSize,kCFStringEncodingMacRoman); + URL = fileURL; + // cleanup dialog + NavDialogDispose(dialog); + // dispose of reply: + NavDisposeReply(&reply); + // dispose of cfString + CFRelease( cfString ); + return 1; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxFileDialogOSX/src/ofxFileDialogOSX.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,26 @@ +/* + * ofxFileDialogOSX.h + * + * Created by timknapen on 07/05/10. + * www.wereldderindianen.be + * code stolen from 'mantissa' over here: + * http://www.openframeworks.cc/forum/viewtopic.php?p=5028#p5028 + * + */ + + +#ifndef _OFX_FILE_DIALOG_OSX_ +#define _OFX_FILE_DIALOG_OSX_ + +#include "ofMain.h" + +class ofxFileDialogOSX { +public: + static int openFile(string& URL); + static int saveFile(string& URL, string& fileURL); +private: + + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/install.xml Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,45 @@ +<install> + <name>ofxOsc</name> + <version>0.04</version> + <author>damian stewart</author> + <url>http://frey.co.nz/ofxosc</url> + + <add> + <!-- ===================================================================== --> + <!-- ========================== add per project using this addon ========= --> + <!-- ===================================================================== --> + + <src> + <folder name="addons/ofxOsc/src"> + <file>../../../addons/ofxOsc/src/ofxOsc.h</file> + <file>../../../addons/ofxOsc/src/ofxOscArg.h</file> + <file>../../../addons/ofxOsc/src/ofxOscBundle.cpp</file> + <file>../../../addons/ofxOsc/src/ofxOscBundle.h</file> + <file>../../../addons/ofxOsc/src/ofxOscMessage.h</file> + <file>../../../addons/ofxOsc/src/ofxOscMessage.cpp</file> + <file>../../../addons/ofxOsc/src/ofxOscReceiver.h</file> + <file>../../../addons/ofxOsc/src/ofxOscReceiver.cpp</file> + <file>../../../addons/ofxOsc/src/ofxOscSender.cpp</file> + <file>../../../addons/ofxOsc/src/ofxOscSender.h</file> + </folder> + </src> + + <include> + <path>../../../addons/ofxOsc/src</path> + <path>../../../addons/ofxOsc/libs/oscpack/include/ip</path> + <path>../../../addons/ofxOsc/libs/oscpack/include/osc</path> + </include> + + <link> + <lib os="win_cb" compiler="codeblocks">../../../addons/ofxOsc/libs/oscpack/lib/win32/oscpack.a</lib> + <lib os="win_vs2008" compiler="visualstudio">../../../addons/ofxOsc/libs/oscpack/lib/win32/oscpack.lib</lib> + <lib os="linux" compiler="codeblocks, makefile">../../../addons/ofxOsc/libs/oscpack/lib/linux/liboscpack.a</lib> + <lib os="linux64" compiler="codeblocks, makefile">../../../addons/ofxOsc/libs/oscpack/lib/linux64/liboscpack.a</lib> + <lib os="mac" compiler="xcode">../../../addons/ofxOsc/libs/oscpack/lib/mac/libOsc.a</lib> + </link> + + </add> + + +</install> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/ip/IpEndpointName.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,74 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef INCLUDED_IPENDPOINTNAME_H +#define INCLUDED_IPENDPOINTNAME_H + + +class IpEndpointName{ + static unsigned long GetHostByName( const char *s ); +public: + static const unsigned long ANY_ADDRESS = 0xFFFFFFFF; + static const int ANY_PORT = -1; + + IpEndpointName() + : address( ANY_ADDRESS ), port( ANY_PORT ) {} + IpEndpointName( int port_ ) + : address( ANY_ADDRESS ), port( port_ ) {} + IpEndpointName( unsigned long ipAddress_, int port_ ) + : address( ipAddress_ ), port( port_ ) {} + IpEndpointName( const char *addressName, int port_=ANY_PORT ) + : address( GetHostByName( addressName ) ) + , port( port_ ) {} + IpEndpointName( int addressA, int addressB, int addressC, int addressD, int port_=ANY_PORT ) + : address( ( (addressA << 24) | (addressB << 16) | (addressC << 8) | addressD ) ) + , port( port_ ) {} + + // address and port are maintained in host byte order here + unsigned long address; + int port; + + enum { ADDRESS_STRING_LENGTH=17 }; + void AddressAsString( char *s ) const; + + enum { ADDRESS_AND_PORT_STRING_LENGTH=23}; + void AddressAndPortAsString( char *s ) const; +}; + +inline bool operator==( const IpEndpointName& lhs, const IpEndpointName& rhs ) +{ + return (lhs.address == rhs.address && lhs.port == rhs.port ); +} + +inline bool operator!=( const IpEndpointName& lhs, const IpEndpointName& rhs ) +{ + return !(lhs == rhs); +} + +#endif /* INCLUDED_IPENDPOINTNAME_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/ip/NetworkingUtils.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,49 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef INCLUDED_NETWORKINGUTILS_H +#define INCLUDED_NETWORKINGUTILS_H + + +// in general NetworkInitializer is only used internally, but if you're +// application creates multiple sockets from different threads at runtime you +// should instantiate one of these in main just to make sure the networking +// layer is initialized. +class NetworkInitializer{ +public: + NetworkInitializer(); + ~NetworkInitializer(); +}; + + +// return ip address of host name in host byte order +unsigned long GetHostByName( const char *name ); + + +#endif /* INCLUDED_NETWORKINGUTILS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/ip/PacketListener.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,43 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef INCLUDED_PACKETLISTENER_H +#define INCLUDED_PACKETLISTENER_H + + +class IpEndpointName; + +class PacketListener{ +public: + virtual ~PacketListener() {} + virtual void ProcessPacket( const char *data, int size, + const IpEndpointName& remoteEndpoint ) = 0; +}; + +#endif /* INCLUDED_PACKETLISTENER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/ip/TimerListener.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,40 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef INCLUDED_TIMERLISTENER_H +#define INCLUDED_TIMERLISTENER_H + + +class TimerListener{ +public: + virtual ~TimerListener() {} + virtual void TimerExpired() = 0; +}; + +#endif /* INCLUDED_TIMERLISTENER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/ip/UdpSocket.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,158 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef INCLUDED_UDPSOCKET_H +#define INCLUDED_UDPSOCKET_H + +#ifndef INCLUDED_NETWORKINGUTILITIES_H +#include "NetworkingUtils.h" +#endif /* INCLUDED_NETWORKINGUTILITIES_H */ + +#ifndef INCLUDED_IPENDPOINTNAME_H +#include "IpEndpointName.h" +#endif /* INCLUDED_IPENDPOINTNAME_H */ + + +class PacketListener; +class TimerListener; + +class UdpSocket; + +class SocketReceiveMultiplexer{ + class Implementation; + Implementation *impl_; + + friend class UdpSocket; + +public: + SocketReceiveMultiplexer(); + ~SocketReceiveMultiplexer(); + + // only call the attach/detach methods _before_ calling Run + + // only one listener per socket, each socket at most once + void AttachSocketListener( UdpSocket *socket, PacketListener *listener ); + void DetachSocketListener( UdpSocket *socket, PacketListener *listener ); + + void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ); + void AttachPeriodicTimerListener( + int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ); + void DetachPeriodicTimerListener( TimerListener *listener ); + + void Run(); // loop and block processing messages indefinitely + void RunUntilSigInt(); + void Break(); // call this from a listener to exit once the listener returns + void AsynchronousBreak(); // call this from another thread or signal handler to exit the Run() state +}; + + +class UdpSocket{ + class Implementation; + Implementation *impl_; + + friend class SocketReceiveMultiplexer::Implementation; + +public: + + // 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 + // 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; + + // 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 ); + + + // Bind a local endpoint to receive incoming data. Endpoint + // can be 'any' for the system to choose an endpoint + void Bind( const IpEndpointName& localEndpoint ); + bool IsBound() const; + + int ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, int size ); +}; + + +// convenience classes for transmitting and receiving +// they just call Connect and/or Bind in the ctor. +// note that you can still use a receive socket +// for transmitting etc + +class UdpTransmitSocket : public UdpSocket{ +public: + UdpTransmitSocket( const IpEndpointName& remoteEndpoint ) + { Connect( remoteEndpoint ); } +}; + + +class UdpReceiveSocket : public UdpSocket{ +public: + UdpReceiveSocket( const IpEndpointName& localEndpoint ) + { Bind( localEndpoint ); } +}; + + +// UdpListeningReceiveSocket provides a simple way to bind one listener +// to a single socket without having to manually set up a SocketReceiveMultiplexer + +class UdpListeningReceiveSocket : public UdpSocket{ + SocketReceiveMultiplexer mux_; + PacketListener *listener_; +public: + UdpListeningReceiveSocket( const IpEndpointName& localEndpoint, PacketListener *listener ) + : listener_( listener ) + { + Bind( localEndpoint ); + mux_.AttachSocketListener( this, listener_ ); + } + + ~UdpListeningReceiveSocket() + { mux_.DetachSocketListener( this, listener_ ); } + + // see SocketReceiveMultiplexer above for the behaviour of these methods... + void Run() { mux_.Run(); } + void RunUntilSigInt() { mux_.RunUntilSigInt(); } + void Break() { mux_.Break(); } + void AsynchronousBreak() { mux_.AsynchronousBreak(); } +}; + + +#endif /* INCLUDED_UDPSOCKET_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/osc/MessageMappingOscPacketListener.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,73 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H +#define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H + +#include <string.h> +#include <map> + +#include "OscPacketListener.h" + + + +namespace osc{ + +template< class T > +class MessageMappingOscPacketListener : public OscPacketListener{ +public: + typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&); + +protected: + void RegisterMessageFunction( const char *addressPattern, function_type f ) + { + functions_.insert( std::make_pair( addressPattern, f ) ); + } + + virtual void ProcessMessage( const osc::ReceivedMessage& m, + const IpEndpointName& remoteEndpoint ) + { + typename function_map_type::iterator i = functions_.find( m.AddressPattern() ); + if( i != functions_.end() ) + (dynamic_cast<T*>(this)->*(i->second))( m, remoteEndpoint ); + } + +private: + struct cstr_compare{ + bool operator()( const char *lhs, const char *rhs ) const + { return strcmp( lhs, rhs ) < 0; } + }; + + typedef std::map<const char*, function_type, cstr_compare> function_map_type; + function_map_type functions_; +}; + +} // namespace osc + +#endif /* INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H */ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/osc/OscException.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,54 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef INCLUDED_OSC_EXCEPTION_H +#define INCLUDED_OSC_EXCEPTION_H + +#include <exception> + +namespace osc{ + +class Exception : public std::exception { + const char *what_; + +public: + Exception() throw() {} + Exception( const Exception& src ) throw() + : what_( src.what_ ) {} + Exception( const char *w ) throw() + : what_( w ) {} + Exception& operator=( const Exception& src ) throw() + { what_ = src.what_; return *this; } + virtual ~Exception() throw() {} + virtual const char* what() const throw() { return what_; } +}; + +} // namespace osc + +#endif /* INCLUDED_OSC_EXCEPTION_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/osc/OscHostEndianness.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,69 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef OSC_HOSTENDIANNESS_H +#define OSC_HOSTENDIANNESS_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. +*/ + +#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. + +#elif defined(__WIN32__) || defined(WIN32) + +// assume that __WIN32__ is only defined on little endian systems + +#define OSC_HOST_LITTLE_ENDIAN 1 +#undef OSC_HOST_BIG_ENDIAN + +#elif defined(__APPLE__) + +#if defined(__LITTLE_ENDIAN__) +#define OSC_HOST_LITTLE_ENDIAN 1 +#undef OSC_HOST_BIG_ENDIAN +#else +#define OSC_HOST_BIG_ENDIAN 1 +#undef OSC_HOST_LITTLE_ENDIAN +#endif + +#else + +#error please edit OSCHostEndianness.h to configure endianness + +#endif + +#endif /* OSC_HOSTENDIANNESS_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/osc/OscOutboundPacketStream.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,284 @@ +/* + + oscpack -- Open Sound Control packet manipulation library + + http://www.audiomulch.com/~rossb/oscpack + + + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + + + Permission is hereby granted, free of charge, to any person obtaining + + a copy of this software and associated documentation files + + (the "Software"), to deal in the Software without restriction, + + including without limitation the rights to use, copy, modify, merge, + + publish, distribute, sublicense, and/or sell copies of the Software, + + and to permit persons to whom the Software is furnished to do so, + + 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. + + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + + 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. + +*/ + +#ifndef INCLUDED_OSCOUTBOUNDPACKET_H + +#define INCLUDED_OSCOUTBOUNDPACKET_H + + + +#include "OscTypes.h" + +#include "OscException.h" + + + + + +namespace osc{ + + + +class OutOfBufferMemoryException : public Exception{ + +public: + + OutOfBufferMemoryException( const char *w="out of buffer memory" ) + + : Exception( w ) {} + +}; + + + +class BundleNotInProgressException : public Exception{ + +public: + + BundleNotInProgressException( + + const char *w="call to EndBundle when bundle is not in progress" ) + + : Exception( w ) {} + +}; + + + +class MessageInProgressException : public Exception{ + +public: + + MessageInProgressException( + + const char *w="opening or closing bundle or message while message is in progress" ) + + : Exception( w ) {} + +}; + + + +class MessageNotInProgressException : public Exception{ + +public: + + MessageNotInProgressException( + + const char *w="call to EndMessage when message is not in progress" ) + + : Exception( w ) {} + +}; + + + + + +class OutboundPacketStream{ + +public: + + OutboundPacketStream( char *buffer, unsigned long capacity ); + + ~OutboundPacketStream(); + + + + void Clear(); + + + + unsigned int Capacity() const; + + + + // invariant: size() is valid even while building a message. + + unsigned int Size() const; + + + + const char *Data() const; + + + + // indicates that all messages have been closed with a matching EndMessage + + // and all bundles have been closed with a matching EndBundle + + bool IsReady() const; + + + + bool IsMessageInProgress() const; + + bool IsBundleInProgress() const; + + + + OutboundPacketStream& operator<<( const BundleInitiator& rhs ); + + OutboundPacketStream& operator<<( const BundleTerminator& rhs ); + + + + OutboundPacketStream& operator<<( const BeginMessage& rhs ); + + OutboundPacketStream& operator<<( const MessageTerminator& rhs ); + + + + OutboundPacketStream& operator<<( bool rhs ); + + OutboundPacketStream& operator<<( const NilType& rhs ); + + OutboundPacketStream& operator<<( const InfinitumType& rhs ); + + OutboundPacketStream& operator<<( int32 rhs ); + + + +#ifndef __x86_64__ + + OutboundPacketStream& operator<<( int rhs ) + + { *this << (int32)rhs; return *this; } + +#endif + + + + OutboundPacketStream& operator<<( float rhs ); + + OutboundPacketStream& operator<<( char rhs ); + + OutboundPacketStream& operator<<( const RgbaColor& rhs ); + + OutboundPacketStream& operator<<( const MidiMessage& rhs ); + + OutboundPacketStream& operator<<( int64 rhs ); + + OutboundPacketStream& operator<<( const TimeTag& rhs ); + + OutboundPacketStream& operator<<( double rhs ); + + OutboundPacketStream& operator<<( const char* rhs ); + + OutboundPacketStream& operator<<( const Symbol& rhs ); + + OutboundPacketStream& operator<<( const Blob& rhs ); + + + +private: + + + + char *BeginElement( char *beginPtr ); + + void EndElement( char *endPtr ); + + + + bool ElementSizeSlotRequired() const; + + void CheckForAvailableBundleSpace(); + + void CheckForAvailableMessageSpace( const char *addressPattern ); + + void CheckForAvailableArgumentSpace( long argumentLength ); + + + + char *data_; + + char *end_; + + + + char *typeTagsCurrent_; // stored in reverse order + + char *messageCursor_; + + char *argumentCurrent_; + + + + // elementSizePtr_ has two special values: 0 indicates that a bundle + + // isn't open, and elementSizePtr_==data_ indicates that a bundle is + + // open but that it doesn't have a size slot (ie the outermost bundle) + + uint32 *elementSizePtr_; + + + + bool messageIsInProgress_; + +}; + + + +} // namespace osc + + + +#endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/osc/OscPacketListener.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,72 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef INCLUDED_OSCPACKETLISTENER_H +#define INCLUDED_OSCPACKETLISTENER_H + +#include "OscReceivedElements.h" +#include "../ip/PacketListener.h" + + +namespace osc{ + +class OscPacketListener : public PacketListener{ +protected: + virtual void ProcessBundle( const osc::ReceivedBundle& b, + const IpEndpointName& remoteEndpoint ) + { + // ignore bundle time tag for now + + for( ReceivedBundle::const_iterator i = b.ElementsBegin(); + i != b.ElementsEnd(); ++i ){ + if( i->IsBundle() ) + ProcessBundle( ReceivedBundle(*i), remoteEndpoint ); + else + ProcessMessage( ReceivedMessage(*i), remoteEndpoint ); + } + } + + virtual void ProcessMessage( const osc::ReceivedMessage& m, + const IpEndpointName& remoteEndpoint ) = 0; + +public: + virtual void ProcessPacket( const char *data, int size, + const IpEndpointName& remoteEndpoint ) + { + osc::ReceivedPacket p( data, size ); + if( p.IsBundle() ) + ProcessBundle( ReceivedBundle(p), remoteEndpoint ); + else + ProcessMessage( ReceivedMessage(p), remoteEndpoint ); + } +}; + +} // namespace osc + +#endif /* INCLUDED_OSCPACKETLISTENER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/osc/OscPrintReceivedElements.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,49 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H +#define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H + +#include <iosfwd> + +#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H +#include "OscReceivedElements.h" +#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */ + + +namespace osc{ + +std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p ); +std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg ); +std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ); +std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ); + +} // namespace osc + +#endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/osc/OscReceivedElements.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,486 @@ +/* + oscpack -- Open Sound Control packet manipulation library + http://www.audiomulch.com/~rossb/oscpack + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + 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. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + 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. +*/ +#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H +#define INCLUDED_OSCRECEIVEDELEMENTS_H + +#include "OscTypes.h" +#include "OscException.h" + + +namespace osc{ + + +class MalformedMessageException : public Exception{ +public: + MalformedMessageException( const char *w="malformed message" ) + : Exception( w ) {} +}; + +class MalformedBundleException : public Exception{ +public: + MalformedBundleException( const char *w="malformed bundle" ) + : Exception( w ) {} +}; + +class WrongArgumentTypeException : public Exception{ +public: + WrongArgumentTypeException( const char *w="wrong argument type" ) + : Exception( w ) {} +}; + +class MissingArgumentException : public Exception{ +public: + MissingArgumentException( const char *w="missing argument" ) + : Exception( w ) {} +}; + +class ExcessArgumentException : public Exception{ +public: + ExcessArgumentException( const char *w="too many arguments" ) + : Exception( w ) {} +}; + + +class ReceivedPacket{ +public: + ReceivedPacket( const char *contents, int32 size ) + : contents_( contents ) + , size_( size ) {} + + bool IsMessage() const { return !IsBundle(); } + bool IsBundle() const; + + int32 Size() const { return size_; } + const char *Contents() const { return contents_; } + +private: + const char *contents_; + int32 size_; +}; + + +class ReceivedBundleElement{ +public: + ReceivedBundleElement( const char *size ) + : size_( size ) {} + + friend class ReceivedBundleElementIterator; + + bool IsMessage() const { return !IsBundle(); } + bool IsBundle() const; + + int32 Size() const; + const char *Contents() const { return size_ + 4; } + +private: + const char *size_; +}; + + +class ReceivedBundleElementIterator{ +public: + ReceivedBundleElementIterator( const char *sizePtr ) + : value_( sizePtr ) {} + + ReceivedBundleElementIterator operator++() + { + Advance(); + return *this; + } + + ReceivedBundleElementIterator operator++(int) + { + ReceivedBundleElementIterator old( *this ); + Advance(); + return old; + } + + const ReceivedBundleElement& operator*() const { return value_; } + + const ReceivedBundleElement* operator->() const { return &value_; } + + friend bool operator==(const ReceivedBundleElementIterator& lhs, + const ReceivedBundleElementIterator& rhs ); + +private: + ReceivedBundleElement value_; + + void Advance() { value_.size_ = value_.Contents() + value_.Size(); } + + bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const + { + return value_.size_ == rhs.value_.size_; + } +}; + +inline bool operator==(const ReceivedBundleElementIterator& lhs, + const ReceivedBundleElementIterator& rhs ) +{ + return lhs.IsEqualTo( rhs ); +} + +inline bool operator!=(const ReceivedBundleElementIterator& lhs, + const ReceivedBundleElementIterator& rhs ) +{ + return !( lhs == rhs ); +} + + +class ReceivedMessageArgument{ +public: + ReceivedMessageArgument( const char *typeTag, const char *argument ) + : typeTag_( typeTag ) + , argument_( argument ) {} + + friend class ReceivedMessageArgumentIterator; + + const char TypeTag() const { return *typeTag_; } + + // 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; } + bool AsBool() const; + bool AsBoolUnchecked() const; + + bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; } + bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; } + + bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; } + int32 AsInt32() const; + int32 AsInt32Unchecked() const; + + bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; } + float AsFloat() const; + float AsFloatUnchecked() const; + + bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; } + char AsChar() const; + char AsCharUnchecked() const; + + bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; } + uint32 AsRgbaColor() const; + uint32 AsRgbaColorUnchecked() const; + + bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; } + uint32 AsMidiMessage() const; + uint32 AsMidiMessageUnchecked() const; + + bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; } + int64 AsInt64() const; + int64 AsInt64Unchecked() const; + + bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; } + uint64 AsTimeTag() const; + uint64 AsTimeTagUnchecked() const; + + bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; } + double AsDouble() const; + double AsDoubleUnchecked() const; + + bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; } + const char* AsString() const; + const char* AsStringUnchecked() const { return argument_; } + + bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; } + const char* AsSymbol() const; + const char* AsSymbolUnchecked() const { return argument_; } + + 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; + +private: + const char *typeTag_; + const char *argument_; +}; + + +class ReceivedMessageArgumentIterator{ +public: + ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments ) + : value_( typeTags, arguments ) {} + + ReceivedMessageArgumentIterator operator++() + { + Advance(); + return *this; + } + + ReceivedMessageArgumentIterator operator++(int) + { + ReceivedMessageArgumentIterator old( *this ); + Advance(); + return old; + } + + const ReceivedMessageArgument& operator*() const { return value_; } + + const ReceivedMessageArgument* operator->() const { return &value_; } + + friend bool operator==(const ReceivedMessageArgumentIterator& lhs, + const ReceivedMessageArgumentIterator& rhs ); + +private: + ReceivedMessageArgument value_; + + void Advance(); + + bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const + { + return value_.typeTag_ == rhs.value_.typeTag_; + } +}; + +inline bool operator==(const ReceivedMessageArgumentIterator& lhs, + const ReceivedMessageArgumentIterator& rhs ) +{ + return lhs.IsEqualTo( rhs ); +} + +inline bool operator!=(const ReceivedMessageArgumentIterator& lhs, + const ReceivedMessageArgumentIterator& rhs ) +{ + return !( lhs == rhs ); +} + + +class ReceivedMessageArgumentStream{ + friend class ReceivedMessage; + ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin, + const ReceivedMessageArgumentIterator& end ) + : p_( begin ) + , end_( end ) {} + + ReceivedMessageArgumentIterator p_, end_; + +public: + + // end of stream + bool Eos() const { return p_ == end_; } + + ReceivedMessageArgumentStream& operator>>( bool& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsBool(); + return *this; + } + + // not sure if it would be useful to stream Nil and Infinitum + // for now it's not possible + + ReceivedMessageArgumentStream& operator>>( int32& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsInt32(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( float& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsFloat(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( char& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsChar(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsRgbaColor(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsMidiMessage(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( int64& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsInt64(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( TimeTag& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsTimeTag(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( double& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsDouble(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( Blob& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + (*p_++).AsBlob( rhs.data, rhs.size ); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( const char*& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsString(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( Symbol& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsSymbol(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) + { + if( !Eos() ) + throw ExcessArgumentException(); + + return *this; + } +}; + + +class ReceivedMessage{ + void Init( const char *bundle, unsigned long 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: + bool AddressPatternIsUInt32() const; + uint32 AddressPatternAsUInt32() const; + + unsigned long ArgumentCount() const { return static_cast<unsigned long>(typeTagsEnd_ - typeTagsBegin_); } + + const char *TypeTags() const { return typeTagsBegin_; } + + + typedef ReceivedMessageArgumentIterator const_iterator; + + ReceivedMessageArgumentIterator ArgumentsBegin() const + { + return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ ); + } + + ReceivedMessageArgumentIterator ArgumentsEnd() const + { + return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 ); + } + + ReceivedMessageArgumentStream ArgumentStream() const + { + return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() ); + } + +private: + const char *addressPattern_; + const char *typeTagsBegin_; + const char *typeTagsEnd_; + const char *arguments_; +}; + + +class ReceivedBundle{ + void Init( const char *message, unsigned long size ); +public: + explicit ReceivedBundle( const ReceivedPacket& packet ); + explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); + + uint64 TimeTag() const; + + unsigned long ElementCount() const { return elementCount_; } + + typedef ReceivedBundleElementIterator const_iterator; + + ReceivedBundleElementIterator ElementsBegin() const + { + return ReceivedBundleElementIterator( timeTag_ + 8 ); + } + + ReceivedBundleElementIterator ElementsEnd() const + { + return ReceivedBundleElementIterator( end_ ); + } + +private: + const char *timeTag_; + const char *end_; + unsigned long elementCount_; +}; + + +} // namespace osc + + +#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/libs/oscpack/include/osc/OscTypes.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,356 @@ +/* + + oscpack -- Open Sound Control packet manipulation library + + http://www.audiomulch.com/~rossb/oscpack + + + + Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com> + + + + Permission is hereby granted, free of charge, to any person obtaining + + a copy of this software and associated documentation files + + (the "Software"), to deal in the Software without restriction, + + including without limitation the rights to use, copy, modify, merge, + + publish, distribute, sublicense, and/or sell copies of the Software, + + and to permit persons to whom the Software is furnished to do so, + + 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. + + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + + 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. + +*/ + +#ifndef INCLUDED_OSCTYPES_H + +#define INCLUDED_OSCTYPES_H + + + + + +namespace osc{ + + + +// basic types + + + +#if defined(__BORLANDC__) || defined(_MSC_VER) + + + +typedef __int64 int64; + +typedef unsigned __int64 uint64; + + + +#else + + + +typedef long long int64; + +typedef unsigned long long uint64; + + + +#endif + + + + + + + +#ifdef __x86_64__ + + + +typedef signed int int32; + +typedef unsigned int uint32; + + + +#else + + + +typedef signed long int32; + +typedef unsigned long uint32; + + + +#endif + + + + + + + +enum TypeTagValues { + + TRUE_TYPE_TAG = 'T', + + FALSE_TYPE_TAG = 'F', + + NIL_TYPE_TAG = 'N', + + INFINITUM_TYPE_TAG = 'I', + + INT32_TYPE_TAG = 'i', + + FLOAT_TYPE_TAG = 'f', + + CHAR_TYPE_TAG = 'c', + + RGBA_COLOR_TYPE_TAG = 'r', + + MIDI_MESSAGE_TYPE_TAG = 'm', + + INT64_TYPE_TAG = 'h', + + TIME_TAG_TYPE_TAG = 't', + + DOUBLE_TYPE_TAG = 'd', + + STRING_TYPE_TAG = 's', + + SYMBOL_TYPE_TAG = 'S', + + BLOB_TYPE_TAG = 'b' + +}; + + + + + + + +// i/o manipulators used for streaming interfaces + + + +struct BundleInitiator{ + + explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {} + + uint64 timeTag; + +}; + + + +extern BundleInitiator BeginBundleImmediate; + + + +inline BundleInitiator BeginBundle( uint64 timeTag=1 ) + +{ + + return BundleInitiator(timeTag); + +} + + + + + +struct BundleTerminator{ + +}; + + + +extern BundleTerminator EndBundle; + + + +struct BeginMessage{ + + explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {} + + const char *addressPattern; + +}; + + + +struct MessageTerminator{ + +}; + + + +extern MessageTerminator EndMessage; + + + + + +// osc specific types. they are defined as structs so they can be used + +// as separately identifiable types with the streaming operators. + + + +struct NilType{ + +}; + + + +extern NilType Nil; + + + + + +struct InfinitumType{ + +}; + + + +extern InfinitumType Infinitum; + + + +struct RgbaColor{ + + RgbaColor() {} + + explicit RgbaColor( uint32 value_ ) : value( value_ ) {} + + uint32 value; + + + + operator uint32() const { return value; } + +}; + + + + + +struct MidiMessage{ + + MidiMessage() {} + + explicit MidiMessage( uint32 value_ ) : value( value_ ) {} + + uint32 value; + + + + operator uint32() const { return value; } + +}; + + + + + +struct TimeTag{ + + TimeTag() {} + + explicit TimeTag( uint64 value_ ) : value( value_ ) {} + + uint64 value; + + + + operator uint64() const { return value; } + +}; + + + + + +struct Symbol{ + + Symbol() {} + + explicit Symbol( const char* value_ ) : value( value_ ) {} + + const char* value; + + + + operator const char *() const { return value; } + +}; + + + + + +struct Blob{ + + Blob() {} + + explicit Blob( const void* data_, unsigned long size_ ) + + : data( data_ ), size( size_ ) {} + + const void* data; + + unsigned long size; + +}; + + + +} // namespace osc + + + + + +#endif /* INCLUDED_OSCTYPES_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/src/ofxOsc.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,37 @@ +/* + + Copyright (c) 2007-2009, Damian Stewart + All rights reserved. + + 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. + * Neither the name of the developer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''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 DAMIAN STEWART 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. + */ + +#ifndef _OFXOSC_H +#define _OFXOSC_H + +#include "ofxOscArg.h" +#include "ofxOscMessage.h" +#include "ofxOscSender.h" +#include "ofxOscReceiver.h" + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/src/ofxOscArg.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,135 @@ +/* + + Copyright (c) 2007-2009, Damian Stewart + All rights reserved. + + 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. + * Neither the name of the developer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''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 DAMIAN STEWART 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. + */ + +#ifndef _OFXOSCARG_H +#define _OFXOSCARG_H + +#include "ofConstants.h" +#include <string> + +typedef enum _ofxOscArgType +{ + OFXOSC_TYPE_NONE, + OFXOSC_TYPE_INT32, + OFXOSC_TYPE_FLOAT, + OFXOSC_TYPE_STRING, + OFXOSC_TYPE_BLOB, + OFXOSC_TYPE_BUNDLE, + OFXOSC_TYPE_INDEXOUTOFBOUNDS +} ofxOscArgType; + +/* + +ofxOscArg + +base class for arguments + +*/ + +class ofxOscArg +{ +public: + ofxOscArg() {}; + virtual ~ofxOscArg() {}; + + virtual ofxOscArgType getType() { return OFXOSC_TYPE_NONE; } + virtual string getTypeName() { return "none"; } + +private: +}; + + +/* + +subclasses for each possible argument type + +*/ + +#if defined TARGET_WIN32 && defined _MSC_VER +// required because MSVC isn't ANSI-C compliant +typedef long int32_t; +#endif + +class ofxOscArgInt32 : public ofxOscArg +{ +public: + ofxOscArgInt32( int32_t _value ) { value = _value; } + ~ofxOscArgInt32() {}; + + /// return the type of this argument + ofxOscArgType getType() { return OFXOSC_TYPE_INT32; } + string getTypeName() { return "int32"; } + + /// return value + int32_t get() const { return value; } + /// set value + void set( int32_t _value ) { value = _value; } + +private: + int32_t value; +}; + +class ofxOscArgFloat : public ofxOscArg +{ +public: + ofxOscArgFloat( float _value ) { value = _value; } + ~ofxOscArgFloat() {}; + + /// return the type of this argument + ofxOscArgType getType() { return OFXOSC_TYPE_FLOAT; } + string getTypeName() { return "float"; } + + /// return value + float get() const { return value; } + /// set value + void set( float _value ) { value = _value; } + +private: + float value; +}; + +class ofxOscArgString : public ofxOscArg +{ +public: + ofxOscArgString( string _value ) { value = _value; } + ~ofxOscArgString() {}; + + /// return the type of this argument + ofxOscArgType getType() { return OFXOSC_TYPE_STRING; } + string getTypeName() { return "string"; } + + /// return value + string get() const { return value; } + /// set value + void set( const char* _value ) { value = _value; } + +private: + std::string value; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/src/ofxOscBundle.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,64 @@ +/* + + Copyright (c) 2007-2009, Damian Stewart + All rights reserved. + + 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. + * Neither the name of the developer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''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 DAMIAN STEWART 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. + */ + +#include "ofxOscBundle.h" + + +ofxOscBundle::ofxOscBundle() +{ +} + +ofxOscBundle::~ofxOscBundle() +{ +} + +ofxOscBundle& ofxOscBundle::copy( const ofxOscBundle& other ) +{ + for ( int i=0; i<other.bundles.size(); i++ ) + { + bundles.push_back( other.bundles[i] ); + } + for ( int i=0; i<other.messages.size(); i++ ) + { + messages.push_back( other.messages[i] ); + } + return *this; +} + + + +void ofxOscBundle::addBundle( const ofxOscBundle& bundle ) +{ + bundles.push_back( bundle ); +} + +void ofxOscBundle::addMessage( const ofxOscMessage& message ) +{ + messages.push_back( message ); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/src/ofxOscBundle.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,67 @@ +/* + + Copyright (c) 2007-2009, Damian Stewart + All rights reserved. + + 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. + * Neither the name of the developer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''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 DAMIAN STEWART 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. + */ + +#ifndef _OFXOSCBUNDLE_H +#define _OFXOSCBUNDLE_H + +#include <vector> +#include "ofxOscMessage.h" + +class ofxOscBundle +{ +public: + ofxOscBundle(); + ~ofxOscBundle(); + ofxOscBundle( const ofxOscBundle& other ) { copy ( other ); } + ofxOscBundle& operator= ( const ofxOscBundle& other ) { return copy( other ); } + /// for operator= and copy constructor + ofxOscBundle& copy( const ofxOscBundle& other ); + + /// erase contents + void clear() { messages.clear(); bundles.clear(); } + + /// add bundle elements + void addBundle( const ofxOscBundle& element ); + void addMessage( const ofxOscMessage& message ); + + /// get bundle elements + int getBundleCount() const { return bundles.size(); } + int getMessageCount() const { return messages.size(); } + /// return the bundle or message at the given index + ofxOscBundle& getBundleAt( int i ) { return bundles[i]; } + ofxOscMessage& getMessageAt( int i ) { return messages[i]; } + +private: + + std::vector< ofxOscMessage > messages; + std::vector< ofxOscBundle > bundles; +}; + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/src/ofxOscMessage.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,210 @@ +/* + + Copyright (c) 2007-2009, Damian Stewart + All rights reserved. + + 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. + * Neither the name of the developer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''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 DAMIAN STEWART 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. + */ + +#include "ofxOscMessage.h" +#include <iostream> +#include <assert.h> + +ofxOscMessage::ofxOscMessage() + +{ +} + +ofxOscMessage::~ofxOscMessage() +{ + clear(); +} + +void ofxOscMessage::clear() +{ + for ( unsigned int i=0; i<args.size(); ++i ) + delete args[i]; + args.clear(); + address = ""; +} + +/* + +get methods + +*/ + +int ofxOscMessage::getNumArgs() const +{ + return (int)args.size(); +} + +ofxOscArgType ofxOscMessage::getArgType( int index ) const +{ + if ( index >= (int)args.size() ) + { + fprintf(stderr,"ofxOscMessage::getArgType: index %d out of bounds\n", index ); + return OFXOSC_TYPE_INDEXOUTOFBOUNDS; + } + else + return args[index]->getType(); +} + +string ofxOscMessage::getArgTypeName( int index ) const +{ + if ( index >= (int)args.size() ) + { + fprintf(stderr,"ofxOscMessage::getArgTypeName: index %d out of bounds\n", index ); + return "INDEX OUT OF BOUNDS"; + } + else + return args[index]->getTypeName(); +} + + +int32_t ofxOscMessage::getArgAsInt32( int index ) const +{ + if ( getArgType(index) != OFXOSC_TYPE_INT32 ) + { + if ( getArgType( index ) == OFXOSC_TYPE_FLOAT ) + { + fprintf(stderr, "ofxOscMessage:getArgAsInt32: warning: converting int32 to float for argument %i\n", index ); + return ((ofxOscArgFloat*)args[index])->get(); + } + else + { + fprintf(stderr, "ofxOscMessage:getArgAsInt32: error: argument %i is not a number\n", index ); + return 0; + } + } + else + return ((ofxOscArgInt32*)args[index])->get(); +} + + +float ofxOscMessage::getArgAsFloat( int index ) const +{ + if ( getArgType(index) != OFXOSC_TYPE_FLOAT ) + { + if ( getArgType( index ) == OFXOSC_TYPE_INT32 ) + { + fprintf(stderr, "ofxOscMessage:getArgAsFloat: warning: converting float to int32 for argument %i\n", index ); + return ((ofxOscArgInt32*)args[index])->get(); + } + else + { + fprintf(stderr, "ofxOscMessage:getArgAsFloat: error: argument %i is not a number\n", index ); + return 0; + } + } + else + return ((ofxOscArgFloat*)args[index])->get(); +} + + +string ofxOscMessage::getArgAsString( int index ) const +{ + if ( getArgType(index) != OFXOSC_TYPE_STRING ) + { + if ( getArgType( index ) == OFXOSC_TYPE_FLOAT ) + { + char buf[1024]; + sprintf(buf,"%f",((ofxOscArgFloat*)args[index])->get() ); + fprintf(stderr, "ofxOscMessage:getArgAsString: warning: converting float to string for argument %i\n", index ); + return buf; + } + else if ( getArgType( index ) == OFXOSC_TYPE_INT32 ) + { + char buf[1024]; + sprintf(buf,"%i",((ofxOscArgInt32*)args[index])->get() ); + fprintf(stderr, "ofxOscMessage:getArgAsString: warning: converting int32 to string for argument %i\n", index ); + return buf; + } + else + { + fprintf(stderr, "ofxOscMessage:getArgAsString: error: argument %i is not a string\n", index ); + return ""; + } + } + else + return ((ofxOscArgString*)args[index])->get(); +} + + + +/* + +set methods + +*/ + + +void ofxOscMessage::addIntArg( int32_t argument ) +{ + + args.push_back( new ofxOscArgInt32( argument ) ); +} + +void ofxOscMessage::addFloatArg( float argument ) +{ + args.push_back( new ofxOscArgFloat( argument ) ); +} + +void ofxOscMessage::addStringArg( string argument ) +{ + args.push_back( new ofxOscArgString( argument ) ); +} + + +/* + + housekeeping + + */ + +ofxOscMessage& ofxOscMessage::copy( const ofxOscMessage& other ) +{ + // copy address + address = other.address; + + remote_host = other.remote_host; + remote_port = other.remote_port; + + // copy arguments + for ( int i=0; i<(int)other.args.size(); ++i ) + { + ofxOscArgType argType = other.getArgType( i ); + if ( argType == OFXOSC_TYPE_INT32 ) + args.push_back( new ofxOscArgInt32( other.getArgAsInt32( i ) ) ); + else if ( argType == OFXOSC_TYPE_FLOAT ) + args.push_back( new ofxOscArgFloat( other.getArgAsFloat( i ) ) ); + else if ( argType == OFXOSC_TYPE_STRING ) + args.push_back( new ofxOscArgString( other.getArgAsString( i ) ) ); + else + { + assert( false && "bad argument type" ); + } + } + + return *this; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/src/ofxOscMessage.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,96 @@ +/* + + Copyright (c) 2007-2009, Damian Stewart + All rights reserved. + + 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. + * Neither the name of the developer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''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 DAMIAN STEWART 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. + */ + + +#ifndef _ofxOscMESSAGE_H +#define _ofxOscMESSAGE_H + +#include "ofxOscArg.h" +#include <vector> +#include <string> + +using namespace std; + +class ofxOscMessage +{ +public: + ofxOscMessage(); + ~ofxOscMessage(); + ofxOscMessage( const ofxOscMessage& other ){ copy ( other ); } + ofxOscMessage& operator= ( const ofxOscMessage& other ) { return copy( other ); } + /// for operator= and copy constructor + ofxOscMessage& copy( const ofxOscMessage& other ); + + /// clear this message, erase all contents + void clear(); + + /// return the address + string getAddress() const { return address; } + + /// return the remote ip + string getRemoteIp() { return remote_host; } + /// return the remote port + int getRemotePort() { return remote_port; } + + /// return number of argumentsļ + int getNumArgs() const; + /// return argument type code for argument # index + ofxOscArgType getArgType( int index ) const; + /// return argument type name as string + /// - either "int", "float", or "string" + string getArgTypeName( int index ) const; + + /// get the argument with the given index as an int, float, or string + /// ensure that the type matches what you're requesting + /// (eg for an int argument, getArgType(index)==OF_TYPE_INT32 + /// or getArgTypeName(index)=="int32") + int32_t getArgAsInt32( int index ) const; + float getArgAsFloat( int index ) const; + string getArgAsString( int index ) const; + + /// message construction + void setAddress( string _address ) { address = _address; }; + /// host and port of the remote endpoint + void setRemoteEndpoint( string host, int port ) { remote_host = host; remote_port = port; } + void addIntArg( int32_t argument ); + void addFloatArg( float argument ); + void addStringArg( string argument ); + + +private: + + string address; + vector<ofxOscArg*> args; + + string remote_host; + int remote_port; + + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/src/ofxOscReceiver.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,240 @@ +/* + + Copyright (c) 2007-2009, Damian Stewart + All rights reserved. + + 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. + * Neither the name of the developer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''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 DAMIAN STEWART 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. + */ + +#include "ofxOscReceiver.h" + +#ifndef TARGET_WIN32 + #include <pthread.h> +#endif +#include <iostream> +#include <assert.h> + +ofxOscReceiver::ofxOscReceiver() +{ + listen_socket = NULL; +} + +void ofxOscReceiver::setup( int listen_port ) +{ + // if we're already running, shutdown before running again + if ( listen_socket ) + shutdown(); + + // create the mutex + #ifdef TARGET_WIN32 + mutex = CreateMutexA( NULL, FALSE, NULL ); + #else + pthread_mutex_init( &mutex, NULL ); + #endif + + // create socket + socketHasShutdown = false; + listen_socket = new UdpListeningReceiveSocket( IpEndpointName( IpEndpointName::ANY_ADDRESS, listen_port ), this ); + + // start thread + #ifdef TARGET_WIN32 + thread = CreateThread( + NULL, // default security attributes + 0, // use default stack size + &ofxOscReceiver::startThread, // thread function + (void*)this, // argument to thread function + 0, // use default creation flags + NULL); // we don't the the thread id + + #else + pthread_create( &thread, NULL, &ofxOscReceiver::startThread, (void*)this ); + #endif +} + +void ofxOscReceiver::shutdown() +{ + if ( listen_socket ) + { + // tell the socket to shutdown + listen_socket->AsynchronousBreak(); + // wait for shutdown to complete + while (!socketHasShutdown) + { + #ifdef TARGET_WIN32 + Sleep(1); + #else + // sleep 0.1ms + usleep(100); + #endif + } + + // thread will clean up itself + + // clean up the mutex + #ifdef TARGET_WIN32 + ReleaseMutex( mutex ); + #else + pthread_mutex_destroy( &mutex ); + #endif + + // delete the socket + delete listen_socket; + listen_socket = NULL; + } +} + +ofxOscReceiver::~ofxOscReceiver() +{ + shutdown(); +} + +#ifdef TARGET_WIN32 +DWORD WINAPI +#else +void* +#endif + ofxOscReceiver::startThread( void* receiverInstance ) +{ + // cast the instance + ofxOscReceiver* instance = (ofxOscReceiver*)receiverInstance; + // start the socket listener + instance->listen_socket->Run(); + // socket listener has finished - remember this fact + instance->socketHasShutdown = true; + // return + #ifdef TARGET_WIN32 + return 0; + #else + return NULL; + #endif +} + +void ofxOscReceiver::ProcessMessage( const osc::ReceivedMessage &m, const IpEndpointName& remoteEndpoint ) +{ + // convert the message to an ofxOscMessage + ofxOscMessage* ofMessage = new ofxOscMessage(); + + // set the address + ofMessage->setAddress( m.AddressPattern() ); + + // set the sender ip/host + char endpoint_host[ IpEndpointName::ADDRESS_STRING_LENGTH ]; + remoteEndpoint.AddressAsString( endpoint_host ); + ofMessage->setRemoteEndpoint( endpoint_host, remoteEndpoint.port ); + + // transfer the arguments + for ( osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin(); + arg != m.ArgumentsEnd(); + ++arg ) + { + if ( arg->IsInt32() ) + ofMessage->addIntArg( arg->AsInt32Unchecked() ); + else if ( arg->IsFloat() ) + ofMessage->addFloatArg( arg->AsFloatUnchecked() ); + else if ( arg->IsString() ) + ofMessage->addStringArg( arg->AsStringUnchecked() ); + else + { + assert( false && "message argument is not int, float, or string" ); + } + } + + // now add to the queue + + // at this point we are running inside the thread created by startThread, + // so anyone who calls hasWaitingMessages() or getNextMessage() is coming + // from a different thread + + // so we have to practise shared memory management + + // grab a lock on the queue + grabMutex(); + + // add incoming message on to the queue + messages.push_back( ofMessage ); + + // release the lock + releaseMutex(); +} + +bool ofxOscReceiver::hasWaitingMessages() +{ + // grab a lock on the queue + grabMutex(); + + // check the length of the queue + int queue_length = (int)messages.size(); + + // release the lock + releaseMutex(); + + // return whether we have any messages + return queue_length > 0; +} + +bool ofxOscReceiver::getNextMessage( ofxOscMessage* message ) +{ + // grab a lock on the queue + grabMutex(); + + // check if there are any to be got + if ( messages.size() == 0 ) + { + // no: release the mutex + releaseMutex(); + return false; + } + + // copy the message from the queue to message + ofxOscMessage* src_message = messages.front(); + message->copy( *src_message ); + + // now delete the src message + delete src_message; + // and remove it from the queue + messages.pop_front(); + + // release the lock on the queue + releaseMutex(); + + // return success + return true; +} + +void ofxOscReceiver::grabMutex() +{ +#ifdef TARGET_WIN32 + WaitForSingleObject( mutex, INFINITE ); +#else + pthread_mutex_lock( &mutex ); +#endif +} + +void ofxOscReceiver::releaseMutex() +{ +#ifdef TARGET_WIN32 + ReleaseMutex( mutex ); +#else + pthread_mutex_unlock( &mutex ); +#endif +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/src/ofxOscReceiver.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,108 @@ +/* + + Copyright (c) 2007-2009, Damian Stewart + All rights reserved. + + 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. + * Neither the name of the developer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''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 DAMIAN STEWART 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. + */ + + +#ifndef _ofxOscRECEIVER_H +#define _ofxOscRECEIVER_H + +#include <deque> +#include "ofMain.h" + +#ifdef TARGET_WIN32 +// threads +#include <windows.h> +#else +// threads +#include <pthread.h> +#endif + +// osc +#include "OscTypes.h" +#include "OscPacketListener.h" +#include "UdpSocket.h" + +// ofxOsc +#include "ofxOscMessage.h" + +class ofxOscReceiver : public osc::OscPacketListener +{ +public: + ofxOscReceiver(); + ~ofxOscReceiver(); + + /// listen_port is the port to listen for messages on + void setup( int listen_port ); + + /// returns true if there are any messages waiting for collection + bool hasWaitingMessages(); + /// take the next message on the queue of received messages, copy its details into message, and + /// remove it from the queue. return false if there are no more messages to be got, otherwise + /// return true + bool getNextMessage( ofxOscMessage* ); + +protected: + /// process an incoming osc message and add it to the queue + virtual void ProcessMessage( const osc::ReceivedMessage &m, const IpEndpointName& remoteEndpoint ); + +private: + // shutdown the listener + void shutdown(); + + // start the listening thread +#ifdef TARGET_WIN32 + static DWORD WINAPI startThread( void* ofxOscReceiverInstance ); +#else + static void* startThread( void* ofxOscReceiverInstance ); +#endif + // queue of osc messages + std::deque< ofxOscMessage* > messages; + + // socket to listen on + UdpListeningReceiveSocket* listen_socket; + + // mutex helpers + void grabMutex(); + void releaseMutex(); + +#ifdef TARGET_WIN32 + // thread to listen with + HANDLE thread; + // mutex for the thread queue + HANDLE mutex; +#else + // thread to listen with + pthread_t thread; + // mutex for the message queue + pthread_mutex_t mutex; +#endif + // ready to be deleted + bool socketHasShutdown; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/src/ofxOscSender.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,121 @@ +/* + + Copyright (c) 2007-2009, Damian Stewart + All rights reserved. + + 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. + * Neither the name of the developer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''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 DAMIAN STEWART 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. + */ + + +#include "ofxOscSender.h" + + +#include "UdpSocket.h" + +#include <assert.h> + +ofxOscSender::ofxOscSender() +{ + socket = NULL; +} + +ofxOscSender::~ofxOscSender() +{ + if ( socket ) + shutdown(); +} + +void ofxOscSender::setup( std::string hostname, int port ) +{ + if ( socket ) + shutdown(); + + socket = new UdpTransmitSocket( IpEndpointName( hostname.c_str(), port ) ); +} + +void ofxOscSender::shutdown() +{ + if ( socket ) + delete socket; + socket = NULL; +} + +void ofxOscSender::sendBundle( ofxOscBundle& bundle ) +{ + static const int OUTPUT_BUFFER_SIZE = 32768; + char buffer[OUTPUT_BUFFER_SIZE]; + osc::OutboundPacketStream p(buffer, OUTPUT_BUFFER_SIZE ); + + // serialise the bundle + appendBundle( bundle, p ); + + socket->Send( p.Data(), p.Size() ); +} + +void ofxOscSender::sendMessage( ofxOscMessage& message ) +{ + static const int OUTPUT_BUFFER_SIZE = 16384; + char buffer[OUTPUT_BUFFER_SIZE]; + osc::OutboundPacketStream p( buffer, OUTPUT_BUFFER_SIZE ); + + // serialise the message + p << osc::BeginBundleImmediate; + appendMessage( message, p ); + p << osc::EndBundle; + + socket->Send( p.Data(), p.Size() ); +} + +void ofxOscSender::appendBundle( ofxOscBundle& bundle, osc::OutboundPacketStream& p ) +{ + // recursively serialise the bundle + p << osc::BeginBundleImmediate; + for ( int i=0; i<bundle.getBundleCount(); i++ ) + { + appendBundle( bundle.getBundleAt( i ), p ); + } + for ( int i=0; i<bundle.getMessageCount(); i++ ) + { + appendMessage( bundle.getMessageAt( i ), p ); + } + p << osc::EndBundle; +} + +void ofxOscSender::appendMessage( ofxOscMessage& message, osc::OutboundPacketStream& p ) +{ + p << osc::BeginMessage( message.getAddress().c_str() ); + for ( int i=0; i< message.getNumArgs(); ++i ) + { + if ( message.getArgType(i) == OFXOSC_TYPE_INT32 ) + p << message.getArgAsInt32( i ); + else if ( message.getArgType( i ) == OFXOSC_TYPE_FLOAT ) + p << message.getArgAsFloat( i ); + else if ( message.getArgType( i ) == OFXOSC_TYPE_STRING ) + p << message.getArgAsString( i ).c_str(); + else + { + assert( false && "bad argument type" ); + } + } + p << osc::EndMessage; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/addons/ofxOsc/src/ofxOscSender.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,75 @@ +/* + + Copyright (c) 2007-2009, Damian Stewart + All rights reserved. + + 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. + * Neither the name of the developer nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DAMIAN STEWART ''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 DAMIAN STEWART 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. + */ + + + +#ifndef _ofxOscSENDER_H +#define _ofxOscSENDER_H + +/** + +ofxOscSender + +an ofxOscSender sends messages to a single host/port + +*/ + +class UdpTransmitSocket; +#include <string> +#include "OscTypes.h" +#include "OscOutboundPacketStream.h" + +#include "ofxOscBundle.h" +#include "ofxOscMessage.h" + + +class ofxOscSender +{ +public: + ofxOscSender(); + ~ofxOscSender(); + + /// send messages to hostname and port + void setup( std::string hostname, int port ); + + /// send the given message + void sendMessage( ofxOscMessage& message ); + /// send the given bundle + void sendBundle( ofxOscBundle& bundle ); + +private: + void shutdown(); + + // helper methods for constructing messages + void appendBundle( ofxOscBundle& bundle, osc::OutboundPacketStream& p ); + void appendMessage( ofxOscMessage& message, osc::OutboundPacketStream& p ); + + UdpTransmitSocket* socket; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/midi division.rtf Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,11 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\paperw11900\paperh16840\margl1440\margr1440\vieww9000\viewh8400\viewkind0 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural + +\f0\fs24 \cf0 midi :\ +\ +z ppq: parts in a bar\ +\ +bar dividing by x/y time sig - i.e. x measures of (z/y)} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/midiFileReader/MIDIComposition.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,43 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + This is a modified version of a source file from the + Rosegarden MIDI and audio sequencer and notation editor. + This file copyright 2000-2010 Richard Bown and Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, 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. + + 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. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + 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. + + Except as contained in this notice, the names of the authors + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef _MIDI_COMPOSITION_H_ +#define _MIDI_COMPOSITION_H_ + +#include "MIDIEvent.h" +#include <vector> +#include <map> + +typedef std::vector<MIDIEvent> MIDITrack; +typedef std::map<unsigned int, MIDITrack> MIDIComposition; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/midiFileReader/MIDIEvent.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,242 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + This is a modified version of a source file from the + Rosegarden MIDI and audio sequencer and notation editor. + This file copyright 2000-2010 Richard Bown and Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, 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. + + 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. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + 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. + + Except as contained in this notice, the names of the authors + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef _MIDI_EVENT_H_ +#define _MIDI_EVENT_H_ + +#include <string> +#include <iostream> + +typedef unsigned char MIDIByte; + +namespace MIDIConstants +{ + static const char *const MIDI_FILE_HEADER = "MThd"; + static const char *const MIDI_TRACK_HEADER = "MTrk"; + + static const MIDIByte MIDI_STATUS_BYTE_MASK = 0x80; + static const MIDIByte MIDI_MESSAGE_TYPE_MASK = 0xF0; + static const MIDIByte MIDI_CHANNEL_NUM_MASK = 0x0F; + + static const MIDIByte MIDI_NOTE_OFF = 0x80; + static const MIDIByte MIDI_NOTE_ON = 0x90; + static const MIDIByte MIDI_POLY_AFTERTOUCH = 0xA0; + static const MIDIByte MIDI_CTRL_CHANGE = 0xB0; + static const MIDIByte MIDI_PROG_CHANGE = 0xC0; + static const MIDIByte MIDI_CHNL_AFTERTOUCH = 0xD0; + static const MIDIByte MIDI_PITCH_BEND = 0xE0; + static const MIDIByte MIDI_SELECT_CHNL_MODE = 0xB0; + static const MIDIByte MIDI_SYSTEM_EXCLUSIVE = 0xF0; + static const MIDIByte MIDI_TC_QUARTER_FRAME = 0xF1; + static const MIDIByte MIDI_SONG_POSITION_PTR = 0xF2; + static const MIDIByte MIDI_SONG_SELECT = 0xF3; + static const MIDIByte MIDI_TUNE_REQUEST = 0xF6; + static const MIDIByte MIDI_END_OF_EXCLUSIVE = 0xF7; + static const MIDIByte MIDI_TIMING_CLOCK = 0xF8; + static const MIDIByte MIDI_START = 0xFA; + static const MIDIByte MIDI_CONTINUE = 0xFB; + static const MIDIByte MIDI_STOP = 0xFC; + static const MIDIByte MIDI_ACTIVE_SENSING = 0xFE; + static const MIDIByte MIDI_SYSTEM_RESET = 0xFF; + static const MIDIByte MIDI_SYSEX_NONCOMMERCIAL = 0x7D; + static const MIDIByte MIDI_SYSEX_NON_RT = 0x7E; + static const MIDIByte MIDI_SYSEX_RT = 0x7F; + static const MIDIByte MIDI_SYSEX_RT_COMMAND = 0x06; + static const MIDIByte MIDI_SYSEX_RT_RESPONSE = 0x07; + static const MIDIByte MIDI_MMC_STOP = 0x01; + static const MIDIByte MIDI_MMC_PLAY = 0x02; + static const MIDIByte MIDI_MMC_DEFERRED_PLAY = 0x03; + static const MIDIByte MIDI_MMC_FAST_FORWARD = 0x04; + static const MIDIByte MIDI_MMC_REWIND = 0x05; + static const MIDIByte MIDI_MMC_RECORD_STROBE = 0x06; + static const MIDIByte MIDI_MMC_RECORD_EXIT = 0x07; + static const MIDIByte MIDI_MMC_RECORD_PAUSE = 0x08; + static const MIDIByte MIDI_MMC_PAUSE = 0x08; + static const MIDIByte MIDI_MMC_EJECT = 0x0A; + static const MIDIByte MIDI_MMC_LOCATE = 0x44; + static const MIDIByte MIDI_FILE_META_EVENT = 0xFF; + static const MIDIByte MIDI_SEQUENCE_NUMBER = 0x00; + static const MIDIByte MIDI_TEXT_EVENT = 0x01; + static const MIDIByte MIDI_COPYRIGHT_NOTICE = 0x02; + static const MIDIByte MIDI_TRACK_NAME = 0x03; + static const MIDIByte MIDI_INSTRUMENT_NAME = 0x04; + static const MIDIByte MIDI_LYRIC = 0x05; + static const MIDIByte MIDI_TEXT_MARKER = 0x06; + static const MIDIByte MIDI_CUE_POINT = 0x07; + static const MIDIByte MIDI_CHANNEL_PREFIX = 0x20; + static const MIDIByte MIDI_CHANNEL_PREFIX_OR_PORT = 0x21; + static const MIDIByte MIDI_END_OF_TRACK = 0x2F; + static const MIDIByte MIDI_SET_TEMPO = 0x51; + static const MIDIByte MIDI_SMPTE_OFFSET = 0x54; + static const MIDIByte MIDI_TIME_SIGNATURE = 0x58; + static const MIDIByte MIDI_KEY_SIGNATURE = 0x59; + static const MIDIByte MIDI_SEQUENCER_SPECIFIC = 0x7F; + static const MIDIByte MIDI_CONTROLLER_BANK_MSB = 0x00; + static const MIDIByte MIDI_CONTROLLER_VOLUME = 0x07; + static const MIDIByte MIDI_CONTROLLER_BANK_LSB = 0x20; + static const MIDIByte MIDI_CONTROLLER_MODULATION = 0x01; + static const MIDIByte MIDI_CONTROLLER_PAN = 0x0A; + static const MIDIByte MIDI_CONTROLLER_SUSTAIN = 0x40; + static const MIDIByte MIDI_CONTROLLER_RESONANCE = 0x47; + static const MIDIByte MIDI_CONTROLLER_RELEASE = 0x48; + static const MIDIByte MIDI_CONTROLLER_ATTACK = 0x49; + static const MIDIByte MIDI_CONTROLLER_FILTER = 0x4A; + static const MIDIByte MIDI_CONTROLLER_REVERB = 0x5B; + static const MIDIByte MIDI_CONTROLLER_CHORUS = 0x5D; + static const MIDIByte MIDI_CONTROLLER_NRPN_1 = 0x62; + static const MIDIByte MIDI_CONTROLLER_NRPN_2 = 0x63; + static const MIDIByte MIDI_CONTROLLER_RPN_1 = 0x64; + static const MIDIByte MIDI_CONTROLLER_RPN_2 = 0x65; + static const MIDIByte MIDI_CONTROLLER_SOUNDS_OFF = 0x78; + static const MIDIByte MIDI_CONTROLLER_RESET = 0x79; + static const MIDIByte MIDI_CONTROLLER_LOCAL = 0x7A; + static const MIDIByte MIDI_CONTROLLER_ALL_NOTES_OFF = 0x7B; + static const MIDIByte MIDI_PERCUSSION_CHANNEL = 9; + + typedef enum { + MIDI_SINGLE_TRACK_FILE = 0x00, + MIDI_SIMULTANEOUS_TRACK_FILE = 0x01, + MIDI_SEQUENTIAL_TRACK_FILE = 0x02, + MIDI_FILE_BAD_FORMAT = 0xFF + } MIDIFileFormatType; +} + +class MIDIEvent +{ +public: + MIDIEvent(unsigned long deltaTime, + MIDIByte eventCode, + MIDIByte data1 = 0, + MIDIByte data2 = 0) : + m_deltaTime(deltaTime), + m_duration(0), + m_eventCode(eventCode), + m_data1(data1), + m_data2(data2), + m_metaEventCode(0) + { } + + MIDIEvent(unsigned long deltaTime, + MIDIByte eventCode, + MIDIByte metaEventCode, + const std::string &metaMessage) : + m_deltaTime(deltaTime), + m_duration(0), + m_eventCode(eventCode), + m_data1(0), + m_data2(0), + m_metaEventCode(metaEventCode), + m_metaMessage(metaMessage) + { } + + MIDIEvent(unsigned long deltaTime, + MIDIByte eventCode, + const std::string &sysEx) : + m_deltaTime(deltaTime), + m_duration(0), + m_eventCode(eventCode), + m_data1(0), + m_data2(0), + m_metaEventCode(0), + m_metaMessage(sysEx) + { } + + ~MIDIEvent() { } + + void setTime(const unsigned long &time) { m_deltaTime = time; } + void setDuration(const unsigned long& duration) { m_duration = duration;} + unsigned long addTime(const unsigned long &time) { + m_deltaTime += time; + return m_deltaTime; + } + + int getMessageType() const + { return (m_eventCode & MIDIConstants::MIDI_MESSAGE_TYPE_MASK); } + + int getChannelNumber() const + { return (m_eventCode & MIDIConstants::MIDI_CHANNEL_NUM_MASK); } + + unsigned long getTime() const { return m_deltaTime; } + unsigned long getDuration() const { return m_duration; } + + int getPitch() const { return m_data1; } + int getVelocity() const { return m_data2; } + int getData1() const { return m_data1; } + int getData2() const { return m_data2; } + int getEventCode() const { return m_eventCode; } + + bool isMeta() const { return (m_eventCode == MIDIConstants::MIDI_FILE_META_EVENT); } + + int getMetaEventCode() const { return m_metaEventCode; } + std::string getMetaMessage() const { return m_metaMessage; } + void setMetaMessage(const std::string &meta) { m_metaMessage = meta; } + + friend bool operator<(const MIDIEvent &a, const MIDIEvent &b); + +private: + unsigned long m_deltaTime; + unsigned long m_duration; + MIDIByte m_eventCode; + MIDIByte m_data1; // or Note + MIDIByte m_data2; // or Velocity + MIDIByte m_metaEventCode; + std::string m_metaMessage; +}; + +// Comparator for sorting +// +struct MIDIEventCmp +{ + bool operator()(const MIDIEvent &mE1, const MIDIEvent &mE2) const + { return mE1.getTime() < mE2.getTime(); } + + bool operator()(const MIDIEvent *mE1, const MIDIEvent *mE2) const + { return mE1->getTime() < mE2->getTime(); } +}; + +class MIDIException : virtual public std::exception +{ +public: + MIDIException(std::string message) throw() : m_message(message) { + std::cerr << "WARNING: MIDI exception: " << message.c_str() << std::endl; + } + virtual ~MIDIException() throw() { } + + virtual const char *what() const throw() { + return m_message.c_str(); + } + +protected: + std::string m_message; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/midiFileReader/MIDIFileReader.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,664 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + This is a modified version of a source file from the + Rosegarden MIDI and audio sequencer and notation editor. + This file copyright 2000-2010 Richard Bown and Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, 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. + + 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. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + 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. + + Except as contained in this notice, the names of the authors + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + + +#include <iostream> +#include <fstream> +#include <string> +#include <cstdio> + +#include "MIDIFileReader.h" +#include "MIDIEvent.h" + +#include <sstream> + +using std::string; +using std::ifstream; +using std::stringstream; +using std::cerr; +using std::endl; +using std::ends; +using std::ios; + +using namespace MIDIConstants; + +//#define DEBUG_MIDI_FILE_READER 1 + +#define throw_exception(...) do { \ + char message[128]; \ + snprintf(message, 128, __VA_ARGS__); \ + throw MIDIException(std::string(message)); \ + } while (0) + + + +MIDIFileReader::MIDIFileReader(std::string path) : + m_timingDivision(0), + m_format(MIDI_FILE_BAD_FORMAT), + m_numberOfTracks(0), + m_trackByteCount(0), + m_decrementCount(false), + m_path(path), + m_midiFile(0), + m_fileSize(0) +{ + if (parseFile()) { + m_error = ""; + } +} + +MIDIFileReader::~MIDIFileReader() +{ +} + +bool +MIDIFileReader::isOK() const +{ + return (m_error == ""); +} + +std::string +MIDIFileReader::getError() const +{ + return m_error; +} + +long +MIDIFileReader::midiBytesToLong(const string& bytes) +{ + if (bytes.length() != 4) { + throw_exception("Wrong length for long data in MIDI stream (%d, should be %d)", (int)bytes.length(), 4); + } + + long longRet = ((long)(((MIDIByte)bytes[0]) << 24)) | + ((long)(((MIDIByte)bytes[1]) << 16)) | + ((long)(((MIDIByte)bytes[2]) << 8)) | + ((long)((MIDIByte)(bytes[3]))); + + return longRet; +} + +int +MIDIFileReader::midiBytesToInt(const string& bytes) +{ + if (bytes.length() != 2) { + throw_exception("Wrong length for int data in MIDI stream (%d, should be %d)", (int)bytes.length(), 2); + } + + int intRet = ((int)(((MIDIByte)bytes[0]) << 8)) | + ((int)(((MIDIByte)bytes[1]))); + return(intRet); +} + + +// Gets a single byte from the MIDI byte stream. For each track +// section we can read only a specified number of bytes held in +// m_trackByteCount. +// +MIDIByte +MIDIFileReader::getMIDIByte() +{ + if (!m_midiFile) { + throw_exception("getMIDIByte called but no MIDI file open"); + } + + if (m_midiFile->eof()) { + throw_exception("End of MIDI file encountered while reading"); + } + + if (m_decrementCount && m_trackByteCount <= 0) { + throw_exception("Attempt to get more bytes than expected on Track"); + } + + char byte; + if (m_midiFile->read(&byte, 1)) { + --m_trackByteCount; + return (MIDIByte)byte; + } + + throw_exception("Attempt to read past MIDI file end"); +} + + +// Gets a specified number of bytes from the MIDI byte stream. For +// each track section we can read only a specified number of bytes +// held in m_trackByteCount. +// +string +MIDIFileReader::getMIDIBytes(unsigned long numberOfBytes) +{ + if (!m_midiFile) { + throw_exception("getMIDIBytes called but no MIDI file open"); + } + + if (m_midiFile->eof()) { + throw_exception("End of MIDI file encountered while reading"); + } + + if (m_decrementCount && (numberOfBytes > (unsigned long)m_trackByteCount)) { + throw_exception("Attempt to get more bytes than available on Track (%lu, only have %ld)", numberOfBytes, m_trackByteCount); + } + + string stringRet; + char fileMIDIByte; + + while (stringRet.length() < numberOfBytes && + m_midiFile->read(&fileMIDIByte, 1)) { + stringRet += fileMIDIByte; + } + + // if we've reached the end of file without fulfilling the + // quota then panic as our parsing has performed incorrectly + // + if (stringRet.length() < numberOfBytes) { + stringRet = ""; + throw_exception("Attempt to read past MIDI file end"); + } + + // decrement the byte count + if (m_decrementCount) + m_trackByteCount -= stringRet.length(); + + return stringRet; +} + + +// Get a long number of variable length from the MIDI byte stream. +// +long +MIDIFileReader::getNumberFromMIDIBytes(int firstByte) +{ + if (!m_midiFile) { + throw_exception("getNumberFromMIDIBytes called but no MIDI file open"); + } + + long longRet = 0; + MIDIByte midiByte; + + if (firstByte >= 0) { + midiByte = (MIDIByte)firstByte; + } else if (m_midiFile->eof()) { + return longRet; + } else { + midiByte = getMIDIByte(); + } + + longRet = midiByte; + if (midiByte & 0x80) { + longRet &= 0x7F; + do { + midiByte = getMIDIByte(); + longRet = (longRet << 7) + (midiByte & 0x7F); + } while (!m_midiFile->eof() && (midiByte & 0x80)); + } + + return longRet; +} + + +// Seek to the next track in the midi file and set the number +// of bytes to be read in the counter m_trackByteCount. +// +bool +MIDIFileReader::skipToNextTrack() +{ + if (!m_midiFile) { + throw_exception("skipToNextTrack called but no MIDI file open"); + } + + string buffer, buffer2; + m_trackByteCount = -1; + m_decrementCount = false; + + while (!m_midiFile->eof() && (m_decrementCount == false)) { + buffer = getMIDIBytes(4); + if (buffer.compare(0, 4, MIDI_TRACK_HEADER) == 0) { + m_trackByteCount = midiBytesToLong(getMIDIBytes(4)); + m_decrementCount = true; + } + } + + if (m_trackByteCount == -1) { // we haven't found a track + return false; + } else { + return true; + } +} + + +// Read in a MIDI file. The parsing process throws exceptions back up +// here if we run into trouble which we can then pass back out to +// whoever called us using a nice bool. +// +bool +MIDIFileReader::parseFile() +{ + m_error = ""; + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "MIDIFileReader::open() : fileName = " << m_path.toStdString() << endl; +#endif + + // Open the file + m_midiFile = new ifstream(m_path.c_str(), ios::in | ios::binary); + + if (!*m_midiFile) { + m_error = "File not found or not readable."; + m_format = MIDI_FILE_BAD_FORMAT; + delete m_midiFile; + m_midiFile = 0; + return false; + } + + bool retval = false; + + try { + + // Set file size so we can count it off + // + m_midiFile->seekg(0, ios::end); + m_fileSize = m_midiFile->tellg(); + m_midiFile->seekg(0, ios::beg); + + // Parse the MIDI header first. The first 14 bytes of the file. + if (!parseHeader(getMIDIBytes(14))) { + m_format = MIDI_FILE_BAD_FORMAT; + m_error = "Not a MIDI file."; + goto done; + } + + for (unsigned int j = 0; j < m_numberOfTracks; ++j) { + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "Parsing Track " << j << endl; +#endif + + if (!skipToNextTrack()) { +#ifdef DEBUG_MIDI_FILE_READER + cerr << "Couldn't find Track " << j << endl; +#endif + m_error = "File corrupted or in non-standard format?"; + m_format = MIDI_FILE_BAD_FORMAT; + goto done; + } + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "Track has " << m_trackByteCount << " bytes" << endl; +#endif + + // Run through the events taking them into our internal + // representation. + if (!parseTrack(j)) { +#ifdef DEBUG_MIDI_FILE_READER + cerr << "Track " << j << " parsing failed" << endl; +#endif + m_error = "File corrupted or in non-standard format?"; + m_format = MIDI_FILE_BAD_FORMAT; + goto done; + } + } + + retval = true; + + } catch (MIDIException e) { + + cerr << "MIDIFileReader::open() - caught exception - " << e.what() << endl; + m_error = e.what(); + } + +done: + m_midiFile->close(); + delete m_midiFile; + + for (unsigned int track = 0; track < m_numberOfTracks; ++track) { + + // Convert the deltaTime to an absolute time since the track + // start. The addTime method returns the sum of the current + // MIDI Event delta time plus the argument. + + unsigned long acc = 0; + + for (MIDITrack::iterator i = m_midiComposition[track].begin(); + i != m_midiComposition[track].end(); ++i) { +#ifdef DEBUG_MIDI_FILE_READER + cerr << "converting delta time " << i->getTime(); +#endif + acc = i->addTime(acc); +#ifdef DEBUG_MIDI_FILE_READER + cerr << " to " << i->getTime() << endl; +#endif + } + + consolidateNoteOffEvents(track); + } + + return retval; +} + +// Parse and ensure the MIDI Header is legitimate +// +bool +MIDIFileReader::parseHeader(const string &midiHeader) +{ + if (midiHeader.size() < 14) { +#ifdef DEBUG_MIDI_FILE_READER + cerr << "MIDIFileReader::parseHeader() - file header undersized" << endl; +#endif + return false; + } + + if (midiHeader.compare(0, 4, MIDI_FILE_HEADER) != 0) { +#ifdef DEBUG_MIDI_FILE_READER + cerr << "MIDIFileReader::parseHeader()" + << "- file header not found or malformed" + << endl; +#endif + return false; + } + + if (midiBytesToLong(midiHeader.substr(4,4)) != 6L) { +#ifdef DEBUG_MIDI_FILE_READER + cerr << "MIDIFileReader::parseHeader()" + << " - header length incorrect" + << endl; +#endif + return false; + } + + m_format = (MIDIFileFormatType) midiBytesToInt(midiHeader.substr(8,2)); + m_numberOfTracks = midiBytesToInt(midiHeader.substr(10,2)); + m_timingDivision = midiBytesToInt(midiHeader.substr(12,2)); + +#ifdef DEBUG_MIDI_FILE_READER + if (m_timingDivision < 0) { + cerr << "MIDIFileReader::parseHeader()" + << " - file uses SMPTE timing" + << endl; + } +#endif + + return true; +} + +// Extract the contents from a MIDI file track and places it into +// our local map of MIDI events. +// +bool +MIDIFileReader::parseTrack(unsigned int trackNum) +{ + MIDIByte midiByte, metaEventCode, data1, data2; + MIDIByte eventCode = 0x80; + string metaMessage; + unsigned int messageLength; + unsigned long deltaTime; + unsigned long accumulatedTime = 0; + + // Remember the last non-meta status byte (-1 if we haven't seen one) + int runningStatus = -1; + + while (!m_midiFile->eof() && (m_trackByteCount > 0)) { + + if (eventCode < 0x80) { +#ifdef DEBUG_MIDI_FILE_READER + cerr << "WARNING: Invalid event code " << eventCode + << " in MIDI file" << endl; +#endif + throw_exception("Invalid event code %d found", int(eventCode)); + } + + deltaTime = getNumberFromMIDIBytes(); + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "read delta time " << deltaTime << endl; +#endif + + // Get a single byte + midiByte = getMIDIByte(); + + if (!(midiByte & MIDI_STATUS_BYTE_MASK)) { + + if (runningStatus < 0) { + throw_exception("Running status used for first event in track"); + } + + eventCode = (MIDIByte)runningStatus; + data1 = midiByte; + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "using running status (byte " << int(midiByte) << " found)" << endl; +#endif + } else { +#ifdef DEBUG_MIDI_FILE_READER + cerr << "have new event code " << int(midiByte) << endl; +#endif + eventCode = midiByte; + data1 = getMIDIByte(); + } + + if (eventCode == MIDI_FILE_META_EVENT) { + + metaEventCode = data1; + messageLength = getNumberFromMIDIBytes(); + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "Meta event of type " << int(metaEventCode) << " and " << messageLength << " bytes found, putting on track " << metaTrack << endl; +#endif + metaMessage = getMIDIBytes(messageLength); + + accumulatedTime += deltaTime; + + MIDIEvent e(deltaTime, + MIDI_FILE_META_EVENT, + metaEventCode, + metaMessage); + + m_midiComposition[trackNum].push_back(e); + + if (metaEventCode == MIDI_TRACK_NAME) { + m_trackNames[trackNum] = metaMessage.c_str(); + } + + } else { // non-meta events + + runningStatus = eventCode; + + int channel = (eventCode & MIDI_CHANNEL_NUM_MASK); + + accumulatedTime += deltaTime; + + switch (eventCode & MIDI_MESSAGE_TYPE_MASK) { + + case MIDI_NOTE_ON: + case MIDI_NOTE_OFF: + case MIDI_POLY_AFTERTOUCH: + case MIDI_CTRL_CHANGE: + data2 = getMIDIByte(); + + { + // create and store our event + MIDIEvent midiEvent(deltaTime, eventCode, data1, data2); + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "MIDI event for channel " << channel << " (track " + << trackNum << ") with delta time " << deltaTime << endl; +#endif + + m_midiComposition[trackNum].push_back(midiEvent); + } + break; + + case MIDI_PITCH_BEND: + data2 = getMIDIByte(); + + { + // create and store our event + MIDIEvent midiEvent(deltaTime, eventCode, data1, data2); + m_midiComposition[trackNum].push_back(midiEvent); + } + break; + + case MIDI_PROG_CHANGE: + case MIDI_CHNL_AFTERTOUCH: + + { + // create and store our event + MIDIEvent midiEvent(deltaTime, eventCode, data1); + m_midiComposition[trackNum].push_back(midiEvent); + } + break; + + case MIDI_SYSTEM_EXCLUSIVE: + messageLength = getNumberFromMIDIBytes(data1); + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "SysEx of " << messageLength << " bytes found" << endl; +#endif + + metaMessage= getMIDIBytes(messageLength); + + if (MIDIByte(metaMessage[metaMessage.length() - 1]) != + MIDI_END_OF_EXCLUSIVE) + { +#ifdef DEBUG_MIDI_FILE_READER + cerr << "MIDIFileReader::parseTrack() - " + << "malformed or unsupported SysEx type" + << endl; +#endif + continue; + } + + // chop off the EOX + // length fixed by Pedro Lopez-Cabanillas (20030523) + // + metaMessage = metaMessage.substr(0, metaMessage.length()-1); + + { + MIDIEvent midiEvent(deltaTime, + MIDI_SYSTEM_EXCLUSIVE, + metaMessage); + m_midiComposition[trackNum].push_back(midiEvent); + } + break; + + case MIDI_END_OF_EXCLUSIVE: +#ifdef DEBUG_MIDI_FILE_READER + cerr << "MIDIFileReader::parseTrack() - " + << "Found a stray MIDI_END_OF_EXCLUSIVE" << endl; +#endif + break; + + default: +#ifdef DEBUG_MIDI_FILE_READER + cerr << "MIDIFileReader::parseTrack()" + << " - Unsupported MIDI Event Code: " + << (int)eventCode << endl; +#endif + break; + } + } + } + + return true; +} + +// Delete dead NOTE OFF and NOTE ON/Zero Velocity Events after +// reading them and modifying their relevant NOTE ONs. Return true +// if there are some notes in this track. +// +bool +MIDIFileReader::consolidateNoteOffEvents(unsigned int track) +{ + bool notesOnTrack = false; + bool noteOffFound; + + MIDITrack &t = m_midiComposition[track]; + + for (MIDITrack::iterator i = t.begin(); i != t.end(); ++i) { + + if (i->getMessageType() == MIDI_NOTE_ON && i->getVelocity() > 0) { + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "Looking for note-offs for note at " << i->getTime() << " (pitch " << (int)i->getPitch() << ")" << endl; +#endif + + notesOnTrack = true; + noteOffFound = false; + + for (MIDITrack::iterator j = i; j != t.end(); ++j) { + + if ((j->getChannelNumber() == i->getChannelNumber()) && + (j->getPitch() == i->getPitch()) && + (j->getMessageType() == MIDI_NOTE_OFF || + (j->getMessageType() == MIDI_NOTE_ON && + j->getVelocity() == 0x00))) { + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "Found note-off at " << j->getTime() << " for note at " << i->getTime() << endl; +#endif + + i->setDuration(j->getTime() - i->getTime()); + +#ifdef DEBUG_MIDI_FILE_READER + cerr << "Duration is now " << i->getDuration() << endl; +#endif + + t.erase(j); + + noteOffFound = true; + break; + } + } + + // If no matching NOTE OFF has been found then set + // Event duration to length of track + // + if (!noteOffFound) { +#ifdef DEBUG_MIDI_FILE_READER + cerr << "Failed to find note-off for note at " << i->getTime() << endl; +#endif + MIDITrack::iterator j = t.end(); + --j; + i->setDuration(j->getTime() - i->getTime()); + } + } + } + + return notesOnTrack; +} + +MIDIComposition +MIDIFileReader::load() const +{ + return m_midiComposition; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/midiFileReader/MIDIFileReader.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,93 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + This is a modified version of a source file from the + Rosegarden MIDI and audio sequencer and notation editor. + This file copyright 2000-2010 Richard Bown and Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, 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. + + 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. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + 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. + + Except as contained in this notice, the names of the authors + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#ifndef _MIDI_FILE_READER_H_ +#define _MIDI_FILE_READER_H_ + +#include "MIDIComposition.h" + +#include <set> +#include <iostream> + +typedef unsigned char MIDIByte; + +class MIDIFileReader +{ +public: + MIDIFileReader(std::string path); + virtual ~MIDIFileReader(); + + virtual bool isOK() const; + virtual std::string getError() const; + + virtual MIDIComposition load() const; + + MIDIConstants::MIDIFileFormatType getFormat() const { return m_format; } + int getTimingDivision() const { return m_timingDivision; } + +protected: + + bool parseFile(); + bool parseHeader(const std::string &midiHeader); + bool parseTrack(unsigned int trackNum); + bool consolidateNoteOffEvents(unsigned int track); + + // Internal convenience functions + // + int midiBytesToInt(const std::string &bytes); + long midiBytesToLong(const std::string &bytes); + + long getNumberFromMIDIBytes(int firstByte = -1); + + MIDIByte getMIDIByte(); + std::string getMIDIBytes(unsigned long bytes); + + bool skipToNextTrack(); + + int m_timingDivision; // pulses per quarter note + MIDIConstants::MIDIFileFormatType m_format; + unsigned int m_numberOfTracks; + + long m_trackByteCount; + bool m_decrementCount; + + std::map<int, std::string> m_trackNames; + MIDIComposition m_midiComposition; + + std::string m_path; + std::ifstream *m_midiFile; + size_t m_fileSize; + std::string m_error; +}; + + +#endif // _MIDI_FILE_READER_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/BayesianArrayStructure.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,386 @@ +/* + * BayesianArrayStructure.cpp + * midiCannamReader + * + * Created by Andrew on 17/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "BayesianArrayStructure.h" + +BayesianArrayStructure::BayesianArrayStructure(){ + printf("Bayesian structure: DeFault constructor called"); + + prior.createVector(1); + likelihood.createVector(1); + posterior.createVector(1); + + + tmpPrior.createVector(240); + tmpPrior.addGaussianShape(100, 40, 1); + tmpPrior.addGaussianShape(200, 10, 0.2); + tmpPrior.translateDistribution(20); + + lastEventTime = ofGetElapsedTimeMillis(); + + speedDecayWidth = 20; + speedDecayAmount = 10; +} + +BayesianArrayStructure::BayesianArrayStructure(int length){ + printf("BAYESIAN STURTUCRE CREATED LENGTH: %i\n", length); + //this constructor isnt called it seems + prior.createVector(length); + likelihood.createVector(length); + posterior.createVector(length); + +} + + + +void BayesianArrayStructure::resetSize(int length){ + printf("BAYESIAN STRUCTURE size is : %i\n", length); + + prior.createVector(length); + likelihood.createVector(length); + posterior.createVector(length); + + acceleration.createVector(length); + +} + + + +void BayesianArrayStructure::resetSpeedToOne(){ + relativeSpeedPrior.zero(); + relativeSpeedPosterior.zero(); + relativeSpeedLikelihood.zero(); + + relativeSpeedPosterior.addGaussianShape(40, 5, 0.6); + + relativeSpeedPosterior.addGaussianShape(100, 5, 0.8); + relativeSpeedPosterior.renormalise(); + relativeSpeedPosterior.getMaximum(); + + acceleration.addGaussianShape(2000, 20, 0.8); + +} + +void BayesianArrayStructure::resetSpeedSize(int length){ + printf("BAYESIAN SPEED size is : %i\n", length); + + relativeSpeedPrior.createVector(length); + relativeSpeedLikelihood.createVector(length); + relativeSpeedPosterior.createVector(length); + + + +} +void BayesianArrayStructure::setRelativeSpeedScalar(double f){ + relativeSpeedPrior.scalar = f; + relativeSpeedPosterior.scalar = f; + relativeSpeedLikelihood.scalar = f; +} + +void BayesianArrayStructure::simpleExample(){ + //simple example + prior.addGaussianShape(50, 10, 1); + prior.addGaussianShape(150, 30, 0.3); + prior.addGaussianShape(250, 30, 0.2); + + likelihood.addGaussianShape(90, 20, 0.6); + likelihood.addConstant(0.02); + posterior.doProduct(prior, likelihood); + +// relativeSpeedPosterior.addToIndex(100, 1); +// relativeSpeedPosterior.addToIndex(40, 0.7); + relativeSpeedPosterior.addGaussianShape(100, 20, 1); +// relativeSpeedPosterior.addGaussianShape(10, 2, 0.5); + relativeSpeedPosterior.getMaximum(); + +} + +void BayesianArrayStructure::copyPriorToPosterior(){ + + for (int i = 0;i < prior.arraySize;i++){ + posterior.array[i] = prior.array[i]; + } +} + +void BayesianArrayStructure::resetArrays(){ + prior.zero(); + likelihood.zero(); + prior.addGaussianShape(0, 80, 1); + likelihood.addConstant(1); + posterior.zero(); + posterior.addGaussianShape(0, 60, 1); + setNewDistributionOffsets(0); + bestEstimate = 0; +// lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); + +} + +void BayesianArrayStructure::updateBestEstimate(){ + double timeDiff = ofGetElapsedTimeMillis() - lastEventTime;//lastBestEstimateUpdateTime; + + bestEstimate = posterior.getIndexInRealTerms(posterior.MAPestimate) + timeDiff*relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.MAPestimate); + // + //lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); +} + +void BayesianArrayStructure::calculatePosterior(){ + posterior.doProduct(prior, likelihood); + posterior.renormalise(); + + /* + int i; + for (i = 0;i < prior.length;i++){ + // printf("priori [%i] is %f\n", i, prior[i]); + *(posterior+i) = *(prior+i); + // posterior[i] = likelihood[i] * prior[i]; + } + */ + + +} + + + + +void BayesianArrayStructure::setNewDistributionOffsets(const double& newOffset){ + prior.offset = newOffset; + likelihood.offset = newOffset; +// posterior.offset = newOffset; +} + + +void BayesianArrayStructure::crossUpdateArrays(DynamicVector& position, DynamicVector& speed, double timeDifference){ + //set the cutoff for offset of position first! XXX + +// printf("time difference %f, ", timeDifference); + + double timeDifferenceInPositionVectorUnits = timeDifference / prior.scalar; + + prior.zero();//kill prior + calculateNewPriorOffset(timeDifference);//set new prior offset here + + for (int i = 0;i < speed.arraySize;i++){ +// printf("[%i] %f\n", i, speed.array[i]); + //set speed + double speedValue = speed.getIndexInRealTerms(i);//so for scalar 0.01, 50 -> speed value of 0.5 + + //so we have moved + int distanceMoved = round(timeDifferenceInPositionVectorUnits * speedValue);//round the value + + if (speed.array[i] != 0){ + + // printf("speed [%i] gives %f moved %i\n", i, speedValue, distanceMoved); + + for (int postIndex = 0;postIndex < position.arraySize;postIndex++){ + //old posterior contributing to new prior + int newPriorIndex = postIndex + position.offset - prior.offset + distanceMoved; + if (newPriorIndex >= 0 && newPriorIndex < prior.arraySize){ + prior.addToIndex(newPriorIndex, position.array[postIndex]*speed.array[i]); + // printf("adding [%i] : %f\n", newPriorIndex, posterior.array[postIndex]*speed.array[i]); + } + + } + + }//if not zero + }//end speed + + prior.renormalise(); + +} + +void BayesianArrayStructure::calculateNewPriorOffset(const double& timeDifference){ + + double maxSpeed = relativeSpeedPosterior.getIndexInRealTerms(relativeSpeedPosterior.MAPestimate); + // printf("Maxspeed is %f\n", maxSpeed); + + double priorMax = posterior.getMaximum(); + double distanceTravelled = maxSpeed * (timeDifference / prior.scalar); + double newMaxLocation = posterior.MAPestimate + distanceTravelled; + // printf("MAP: %i, tim df %f, distance %f, new location %f\n", posterior.MAPestimate, timeDifference, distanceTravelled, newMaxLocation); + +} + + +void BayesianArrayStructure::decaySpeedDistribution(double timeDifference){ + + // commented for the moment + double relativeAmount = max(1.0, timeDifference/1000.); +// printf("decay %f around %i \n", timeDifference, relativeSpeedPosterior.MAPestimate); + relativeAmount *= speedDecayAmount; + relativeSpeedPosterior.renormalise(); + relativeSpeedPosterior.addGaussianShape(relativeSpeedPosterior.MAPestimate, speedDecayWidth, relativeAmount); + + relativeSpeedPosterior.renormalise(); + double newMax = relativeSpeedPosterior.getMaximum(); + + //old code +// relativeSpeedPosterior.addGaussianShape(relativeSpeedPosterior.MAPestimate, speedDecayWidth, 10); + //relativeSpeedPosterior.addConstant(1); + + /* + relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior); + relativeSpeedLikelihood.zero(); + relativeSpeedLikelihood.addConstant(0.2); + relativeSpeedLikelihood.addGaussianShape(relativeSpeedPosterior.maximumValue, speedDecayWidth, relativeAmount); + relativeSpeedPosterior.doProduct(relativeSpeedPrior, relativeSpeedLikelihood); + relativeSpeedPosterior.renormalise(); + */ + + + +} + +void BayesianArrayStructure::updateTempoDistribution(const double& speedRatio, const double& matchFactor){ + //speedratio is speed of played relative to the recording + + double index = relativeSpeedLikelihood.getRealTermsAsIndex(speedRatio); +// printf("\nindex of likelihood would be %f\n", index); + if (index >= 0 && index < relativeSpeedPrior.length){ + //then we can do update + + //set new likelihood + relativeSpeedLikelihood.zero(); + relativeSpeedLikelihood.addConstant(0.02); + + relativeSpeedLikelihood.addGaussianShape(index , 5, 0.5*matchFactor); + + + //copy posterior to prior + relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior); + + //update + relativeSpeedPosterior.doProduct(relativeSpeedPrior, relativeSpeedLikelihood); + + //normalise + relativeSpeedPosterior.renormalise(); + + relativeSpeedPosterior.getMaximum(); + }//end if within range + + +} + + +void BayesianArrayStructure::setFlatTempoLikelihood(){ //set new likelihood + relativeSpeedLikelihood.zero(); + relativeSpeedLikelihood.addConstant(0.3); +} + +void BayesianArrayStructure::updateTempoLikelihood(const double& speedRatio, const double& matchFactor){ + + double index = relativeSpeedLikelihood.getRealTermsAsIndex(speedRatio); + + if (index >= 0 && index < relativeSpeedPrior.length){ + relativeSpeedLikelihood.addGaussianShape(index , 5, 0.5);//*matchFactor); + } +} + + +void BayesianArrayStructure::calculateTempoUpdate(){ + //copy posterior to prior + relativeSpeedPrior.copyFromDynamicVector(relativeSpeedPosterior); + + //update + relativeSpeedPosterior.doProduct(relativeSpeedPrior, relativeSpeedLikelihood); + + //normalise + relativeSpeedPosterior.renormalise(); + + relativeSpeedPosterior.getMaximum(); + +} + + +void BayesianArrayStructure::drawArrays(){ + + //bayesArray.drawFloatArray(&bayesArray.prior[0], 0, 200); + //bayesArray.drawFloatArray(&bayesArray.prior[0], 0, 200); + + int displaySize = prior.arraySize; + ofSetColor(255,0,0); + prior.drawVector(0, displaySize); + ofSetColor(0,255,0); + likelihood.drawVector(0, displaySize); + ofSetColor(0,0,255); + posterior.drawVector(0, displaySize); + ofSetColor(255,255,0); + relativeSpeedPosterior.drawVector(0, relativeSpeedPosterior.arraySize); + +// ofSetColor(255,255,255); +// tmpPrior.drawVector(0,300); + +} + + +void BayesianArrayStructure::drawTempoArrays(){ + ofSetColor(0,255,255); + relativeSpeedPrior.drawVector(0, relativeSpeedPrior.arraySize); + + ofSetColor(255,0,255); + relativeSpeedLikelihood.drawVector(0, relativeSpeedLikelihood.arraySize); + + ofSetColor(255,255,0); + relativeSpeedPosterior.drawVector(0, relativeSpeedPosterior.arraySize); + + ofSetColor(255,255, 255); + ofLine(screenWidth/2, 0, screenWidth/2, ofGetHeight());//middle of screen + + ofSetColor(0, 255, 0); + double fractionOfScreen = ((double)relativeSpeedPosterior.MAPestimate / relativeSpeedPosterior.length); + ofLine(screenWidth * fractionOfScreen, 0, screenWidth * fractionOfScreen, ofGetHeight()); +} + + +void BayesianArrayStructure::drawArraysRelativeToTimeframe(const double& startTimeMillis, const double& endTimeMillis){ + + screenWidth = ofGetWidth(); + + int startArrayIndex = 0; + + if (prior.getIndexInRealTerms(prior.arraySize-1) > startTimeMillis){ + //i.e. the array is on the page + + while (prior.getIndexInRealTerms(startArrayIndex) < startTimeMillis){ + startArrayIndex++; + } + int endArrayIndex = prior.arraySize-1; + //could find constraints here + if (prior.getIndexInRealTerms(prior.arraySize-1) > endTimeMillis) + endArrayIndex = (floor)((endTimeMillis - prior.offset)/prior.scalar); + + //so we need to figure where start and end array are on screen + int startScreenPosition, endScreenPosition; + double screenWidthMillis = endTimeMillis - startTimeMillis; + + startScreenPosition = (prior.getIndexInRealTerms(startArrayIndex) - startTimeMillis)*screenWidth/screenWidthMillis; + endScreenPosition = (double)(prior.getIndexInRealTerms(endArrayIndex) - startTimeMillis)*screenWidth/screenWidthMillis; + + ofSetColor(0,0,100); + string relativeString = " offset "+ofToString(prior.offset, 1);//starttimes("+ofToString(startTimeMillis)+", "+ofToString(endTimeMillis); + relativeString += ": index "+ofToString(startArrayIndex)+" , "+ofToString(endArrayIndex)+" ["; +// relativeString += ofToString(prior.getIndexInRealTerms(endArrayIndex), 3)+"] (sc-width:"+ofToString(screenWidthMillis, 1)+") "; + relativeString += " mapped to screen "+ofToString(startScreenPosition)+" , "+ofToString(endScreenPosition); + ofDrawBitmapString(relativeString, 100, 180); + + ofSetColor(0, 200, 0); + likelihood.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition); + + ofSetColor(0,0,200); + prior.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition); + + ofSetColor(200, 0, 0); + posterior.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition); + +// ofSetColor(0, 200, 255); +// acceleration.drawConstrainedVector(startArrayIndex, endArrayIndex, startScreenPosition, endScreenPosition); + + + } + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/BayesianArrayStructure.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,72 @@ +/* + * BayesianArrayStructure.h + * midiCannamReader + * + * Created by Andrew on 17/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "ofMain.h" +//#include "DynamicBayesianArray.h" +#include "DynamicVector.h" + +class BayesianArrayStructure { + +public: +// BayesianArrayStructure(); + BayesianArrayStructure(); + BayesianArrayStructure(int length); + + void calculatePosterior(); + void drawArrays(); + void drawArraysRelativeToTimeframe(const double& startTimeMillis, const double& endTimeMillis); + + void drawTempoArrays(); + + void resetSize(int length); + void resetArrays(); + void simpleExample(); + + double screenWidth; + + void copyPriorToPosterior(); +// DynamicBayesianArray bayesArray; + + double lastEventTime; + + DynamicVector tmpPrior; + + DynamicVector prior; + DynamicVector posterior; + DynamicVector likelihood; + + DynamicVector relativeSpeedPrior; + DynamicVector relativeSpeedLikelihood; + DynamicVector relativeSpeedPosterior; + DynamicVector acceleration; + + void resetSpeedToOne(); + + double bestEstimate; + void updateBestEstimate(); +// double lastBestEstimateUpdateTime; + + double speedDecayWidth, speedDecayAmount; + void decaySpeedDistribution(double timeDifference); + + void resetSpeedSize(int length); + void setRelativeSpeedScalar(double f); + void calculateNewPriorOffset(const double& timeDifference); + void setNewDistributionOffsets(const double& newOffset); + + void updateTempoDistribution(const double& speedRatio, const double& matchFactor); + + void setFlatTempoLikelihood(); + void calculateTempoUpdate(); + void updateTempoLikelihood(const double& speedRatio, const double& matchFactor); + + void crossUpdateArrays(DynamicVector& position, DynamicVector& speed, double timeDifference); + +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DynamicBayesianArray.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,326 @@ +/* + * DynamicDynamicBayesianArray.cpp + * midiCannamReader + * + * Created by Andrew on 17/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "DynamicBayesianArray.h" +#include "math.h" +#include "ofMain.h" + +DynamicBayesianArray::DynamicBayesianArray(){ + +// prior.createVector(240); +// likelihood.createVector(240); +// posterior.createVector(240); + testVector.createVector(240); + testVector.addGaussianShape(100,10, 0.1); + + + likelihoodNoise = 0.5; + likelihoodMean = ARRAY_SIZE/2; + likelihoodStdDev = ARRAY_SIZE / 12; + initialiseArray(); +} + +void DynamicBayesianArray::initialiseArray(){ + + //maximumIndex = 12;//change this + setGaussianPrior(ARRAY_SIZE/2, ARRAY_SIZE/1); + setGaussianLikelihood(ARRAY_SIZE/2, ARRAY_SIZE/1);//likelihoodMean, likelihoodStdDev); + + calculatePosterior(); + renormalisePosterior(); + posteriorDecayRate = 0.06; + + eighthNoteProportion = 0.35;//must be less than 0.5 to discriminate - was 0.4 + earlySixteenthNoteProportion = 0; + lateSixteenthNoteProportion = 0; + decayNoiseAmount = 0.1; + decayNoiseStdDev = ARRAY_SIZE/24; + standardDeviation = likelihoodStdDev; + setDecayNoiseGaussian(ARRAY_SIZE/2, decayNoiseStdDev); + + setGaussianLikelihood(likelihoodMean, likelihoodStdDev); +} + + +void DynamicBayesianArray::setGaussianPrior(float mean, float StdDev){ + int i; + for (i=0;i<ARRAY_SIZE;i++){ + prior[i] = (1/(StdDev*sqrt(2*PI)))*exp(-1*(i-mean)*(i-mean)/(2*StdDev*StdDev)); + //posterior[i] = prior[i]; + } +} + +void DynamicBayesianArray::setGaussianPosterior(float mean, float StdDev){ + int i; + for (i=0;i<ARRAY_SIZE;i++){ + posterior[i] = (1/(StdDev*sqrt(2*PI)))*exp(-1*(i-mean)*(i-mean)/(2*StdDev*StdDev)); + } +} + + +void DynamicBayesianArray::setGaussianLikelihood(float mean, float StdDev){ + if (mean >= 0 && mean <= ARRAY_SIZE){ + int i; float eighthDifference; + int eighthPosition = ((int)mean + ARRAY_SIZE/2)%ARRAY_SIZE; + float mainDifference; + float gaussianProportion = 1 - likelihoodNoise; + + for (i=0;i < ARRAY_SIZE;i++){ + + mainDifference = min( double(fabs(i-mean)) , (double)(i + ARRAY_SIZE - mean)); + //without * (1 - eighthNoteProportion) + likelihood[i] = gaussianProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(mainDifference)*(mainDifference)/(2*StdDev*StdDev)) ; + + likelihood[i] += (likelihoodNoise / ARRAY_SIZE); + //likelihood[i] = (float) max(gaussianProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(i-mean)*(i-mean)/(2*StdDev*StdDev)) , + //(double) (likelihoodNoise / ARRAY_SIZE) ); + } + // renormaliseArray(&likelihood[0], ARRAY_SIZE); + }//end if mean within limits +} + +void DynamicBayesianArray::calculatePosterior(){ + int i; + for (i=0;i < ARRAY_SIZE;i++){ + posterior[i] = likelihood[i] * prior[i]; + } + //renormalisePosterior(); +} + + +float DynamicBayesianArray::getMaximum(float *ptr, int length){ + int i; + float max = 0; + for (i=0;i < length;i++){ + if (*(ptr+i)>max) + max = *(ptr+i); + } + maximumValue = max; + return max; +} + +float* DynamicBayesianArray::getMaximumEstimate(float *ptr, int length){ + float returnArray[2]; + int i; + float max = 0; + maximumIndex = 0; + for (i=0;i < length;i++){ + if (*(ptr+i)>max){ + max = *(ptr+i); + maximumIndex = i; + } + } + returnArray[0] = max; + returnArray[1] = maximumIndex; + maximumValue = max; + return &returnArray[0]; +} + + + +double DynamicBayesianArray::getIntegratedEstimateIndex(){ + int i; + float integratedQuantity = 0; + float integratedTotal = 0; + double integratedIndex = 0; + for (i=0;i < ARRAY_SIZE;i++){ + integratedQuantity += posterior[i];//the values of the probability distribution + integratedTotal += i*posterior[i]; + } + if (integratedQuantity > 0){ + integratedIndex = integratedTotal / integratedQuantity; + } + integratedEstimate = (float) integratedIndex; + return integratedIndex; +} + + +double DynamicBayesianArray::calculateStandardDeviation(){ + + double total = 0; + double pdfSum; + double variance = 0; + for (int i=0;i < ARRAY_SIZE;i++){ + //*posterior[i] * + total += posterior[i] * (i - integratedEstimate) * (i - integratedEstimate);//the values of the probability distribution + pdfSum += posterior[i]; + } + + if (pdfSum > 0) + variance = total / pdfSum; + else + variance = ARRAY_SIZE; + + standardDeviation = sqrt(variance); + return standardDeviation; +} + + + +void DynamicBayesianArray::renormaliseArray(float *ptr, int length){ + int i; + float totalArea = 0; + for (i=0;i < length;i++){ + totalArea += *(ptr+i); + } + + for (i=0;i < length;i++){ + *(ptr+i) /= totalArea; + } + +} + +void DynamicBayesianArray::resetPrior(){ + int i; + for (i=0;i<ARRAY_SIZE;i++){ + prior[i] = posterior[i]; + } +} + +void DynamicBayesianArray::renormalisePosterior(){ + int i; + float totalArea = 0; + for (i=0;i < ARRAY_SIZE;i++){ + totalArea += posterior[i]; + } + + for (i=0;i < ARRAY_SIZE;i++){ + posterior[i] /= totalArea; + } + +} + +void DynamicBayesianArray::decayPosterior(){ + float *pointer; + pointer = getMaximumEstimate(&posterior[0], ARRAY_SIZE); + float maximum; + maximum = *pointer; + int i; + for (i=0;i<ARRAY_SIZE;i++){ + posterior[i] += (maximum - posterior[i]) * posteriorDecayRate * 0.01;;//usded to be * maximum not minus value + } + maximumIndex = *(pointer+1); +} + +void DynamicBayesianArray::setDecayNoiseGaussian(float mean, float StdDev){ + int i; + for (i=0;i<ARRAY_SIZE;i++){ + decayNoiseArray[i] = (1/(StdDev*sqrt(2*PI)))*exp(-1*(i-mean)*(i-mean)/(2*StdDev*StdDev)); + } +} + +void DynamicBayesianArray::decayPosteriorWithGaussianNoise(){ + + int i; + float currentMaximum = getMaximum(&posterior[0], ARRAY_SIZE); + for (i=0;i<ARRAY_SIZE;i++){ + posterior[i] += decayNoiseArray[(i - (int)maximumIndex + ((3*ARRAY_SIZE)/2)) % ARRAY_SIZE] * currentMaximum * decayNoiseAmount; + //posteriorDecayRate * 0.01;;//usded to be * maximum not minus value + } + +} + +void DynamicBayesianArray::resetMaximumPosterior(){ + int i; + float max = 0; + for (i=0;i < ARRAY_SIZE;i++){ + if (posterior[i]>max){ + maximumIndex = i; + max = posterior[i]; + } + } +} + +void DynamicBayesianArray::translateDistribution(int translationIndex){ + int tmpIndex; + //copy array + int i; + for (i=0;i < ARRAY_SIZE;i++){ + tempPosteriorArray[i] = posterior[i] ; + } + //translate values + for (i=0;i < ARRAY_SIZE;i++){ + tmpIndex = (i + translationIndex + ARRAY_SIZE)%ARRAY_SIZE; + posterior[tmpIndex] = tempPosteriorArray[i]; + } + //now delete tmp array +} + + +void DynamicBayesianArray::drawFloatArray(float* arrayToDraw, const int& minIndex, const int& maxIndex){ + + if (minIndex >= 0){ + + double stepSize = ofGetWidth() / (double)(maxIndex - minIndex); + double screenHeight = ofGetHeight(); + double maxVal = getMaximum(&arrayToDraw[0], maxIndex); + + for (int i = minIndex+1;i < maxIndex;i++){ + + ofLine (stepSize*(i-1), screenHeight * (1 - arrayToDraw[i-1] / maxVal), stepSize*i, screenHeight * (1 - arrayToDraw[i] / maxVal) ); + } + + } + + +} + + + +/* +void DynamicBayesianArray::drawDoubleArray(double[]& arrayToDraw, const int& minIndex, const int& maxIndex){ + + if (minIndex >= 0 && maxIndex <= arrayToDraw.size(0)) + +} +*/ +/* + void DynamicBayesianArray::setGaussianLikelihoodForBeats(float mean, float StdDev){ + //this has eighth and sixteenth positions included + + if (mean >= 0 && mean <= ARRAY_SIZE){ + int i; float eighthDifference; + int eighthPosition = ((int)mean + ARRAY_SIZE/2)%ARRAY_SIZE; + int earlySixteenthPosition = ((int)mean + (3*ARRAY_SIZE/4))%ARRAY_SIZE;; + int lateSixteenthPosition = ((int)mean + (ARRAY_SIZE/4))%ARRAY_SIZE;; + + float mainDifference, sixteenthDifference; + float gaussianProportion = 1 - likelihoodNoise; + float mainProportion = (1 - eighthNoteProportion - earlySixteenthNoteProportion - lateSixteenthNoteProportion); + + for (i=0;i < ARRAY_SIZE;i++){ + + mainDifference = min( fabs(i-mean) , (double)(i + ARRAY_SIZE - mean)); + likelihood[i] = gaussianProportion * mainProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(mainDifference)*(mainDifference)/(2*StdDev*StdDev)) ; + + eighthDifference = min( abs(i - eighthPosition) , i + ARRAY_SIZE - eighthPosition); + eighthDifference = min(eighthDifference , (float)(ARRAY_SIZE + eighthPosition - i )); + //for e.g. +0.43, or -0.47 we require the gaussian around the half note too + likelihood[i] += gaussianProportion * eighthNoteProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(eighthDifference)*(eighthDifference)/(2*StdDev*StdDev)) ; + + sixteenthDifference = min( abs(i - earlySixteenthPosition) , i + ARRAY_SIZE - earlySixteenthPosition); + sixteenthDifference = min(sixteenthDifference , (float)(ARRAY_SIZE + earlySixteenthPosition - i )); + //for e.g. +0.43, or -0.47 we require the gaussian around the half note too + likelihood[i] += gaussianProportion * earlySixteenthNoteProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(sixteenthDifference)*(sixteenthDifference)/(2*StdDev*StdDev)) ; + + sixteenthDifference = min( abs(i - lateSixteenthPosition) , i + ARRAY_SIZE - lateSixteenthPosition); + sixteenthDifference = min(sixteenthDifference , (float)(ARRAY_SIZE + lateSixteenthPosition - i )); + //for e.g. +0.43, or -0.47 we require the gaussian around the half note too + likelihood[i] += gaussianProportion * lateSixteenthNoteProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(sixteenthDifference)*(sixteenthDifference)/(2*StdDev*StdDev)) ; + + + + likelihood[i] += (likelihoodNoise / ARRAY_SIZE); + //likelihood[i] = (float) max(gaussianProportion * (1/(StdDev*sqrt(2*PI)))*exp(-1*(i-mean)*(i-mean)/(2*StdDev*StdDev)) , + //(double) (likelihoodNoise / ARRAY_SIZE) ); + } + // renormaliseArray(&likelihood[0], ARRAY_SIZE); + }//end if mean within limits + } + */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DynamicBayesianArray.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,104 @@ +/* + * DynamicBayesianArray.h + * midiCannamReader + * + * Created by Andrew on 17/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +/* + * DynamicBayesianArray.cpp + * bayesianTest5 + * + * Created by Andrew Robertson on 08/05/2010. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ + +/* + * DynamicBayesianArray.h + * bayesianTest5 + * + * Created by Andrew Robertson on 08/05/2010. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ + +#include "ofMain.h" + +#include "DynamicVector.h" + +#ifndef _DYNAMIC_BAYESIAN_ARRAY +#define _DYNAMIC_BAYESIAN_ARRAY + +#define ARRAY_SIZE 240 + + +class DynamicBayesianArray{ + +public: + + DynamicBayesianArray(); + void initialiseArray(); + +// void setGaussianLikelihoodForBeats(float mean, float StdDev); + void setGaussianLikelihood(float mean, float StdDev); + void setGaussianPrior(float mean, float StdDev); + void setGaussianPosterior(float mean, float StdDev); + + void calculatePosterior(); + void renormalisePosterior(); + void resetMaximumPosterior();//resets the max index + void decayPosteriorWithGaussianNoise(); + void translateDistribution(int translationIndex); + void setDecayNoiseGaussian(float mean, float StdDev); + double calculateStandardDeviation(); + + int arraySize; + + + float getMaximum(float *ptr, int length); + void renormaliseArray(float *ptr, int length); + void resetPrior(); + void decayPosterior(); + float* getMaximumEstimate(float *ptr, int length); + double getIntegratedEstimateIndex(); + +// void drawArray(const int& minIndex, const int& maxIndex); + void drawFloatArray(float* arrayToDraw, const int& minIndex, const int& maxIndex); + void drawDoubleArray(double* arrayToDraw, const int& minIndex, const int& maxIndex); + + + typedef std::vector<double> DoubleVector; +// typedef std::vector<IntVector> DoubleMatrix; + + +// DynamicVector prior; +// DynamicVector posterior; +// DynamicVector likelihood; + + DynamicVector testVector; +// DynamicVector prior; + + float prior [ARRAY_SIZE]; + float posterior [ARRAY_SIZE]; + float likelihood [ARRAY_SIZE]; + float tempPosteriorArray[ARRAY_SIZE]; + + float decayNoiseArray[ARRAY_SIZE]; + float decayNoiseStdDev, decayNoiseAmount; + + float likelihoodMean, likelihoodStdDev, likelihoodNoise; + float maximumTest, posteriorDecayRate, maximumValue; + float eighthNoteProportion, earlySixteenthNoteProportion, lateSixteenthNoteProportion ; + float maximumEstimate, maximumIndex, integratedEstimate; + double standardDeviation; + +private: +}; + +#endif + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DynamicVector.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,175 @@ +/* + * DynamicVector.cpp + * midiCannamReader + * + * Created by Andrew on 18/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "DynamicVector.h" + +DynamicVector::DynamicVector(){ + length = 0; + arraySize = 0; + maximumValue = 0; + MAPestimate = 0; + offset = 0; + scalar = 1; +} + +void DynamicVector::copyFromDynamicVector(const DynamicVector& dynamicVec){ + if (dynamicVec.length == length){ + for (int i = 0;i < length;i++) + array[i] = dynamicVec.array[i]; + } + else{ + printf("CANNOT COPY VECTORS OF NON SAME LENGTH!!\n"); + } +} + +void DynamicVector::createVector(int len){ + array.clear(); + for (int i = 0; i < len;i++){ + array.push_back(0); + } + length = len; + arraySize = array.size(); +} + + +double DynamicVector::getMaximum(){ + int i; + double max = 0; + for (i=0;i < length;i++){ + if (array[i] > max){ + max = array[i]; + MAPestimate = i; + } + } + maximumValue = max; + return max; +} + +void DynamicVector::zero(){ + for (int i = 0;i < array.size();i++) + array[i] = 0; +} + +void DynamicVector::renormalise(){ + double tmpMax = getMaximum(); + if (tmpMax > 0){ +// printf("renormalise : max is %f and size is %i\n", tmpMax, arraySize); + for (int i = 0;i < array.size();i++) + array[i] /= tmpMax; + + } + //printArray(); +} + +void DynamicVector::doProduct(DynamicVector& arrayOne, DynamicVector& arrayTwo){ + + for (int i = 0;i < arrayOne.length;i++) + array[i] = arrayOne.array[i] * arrayTwo.array[i]; +} + + +void DynamicVector::printArray(){ + for (int i = 0;i < arraySize;i++){ + printf("[%i] = %f\n", i, array[i]); + } +} + +void DynamicVector::translateDistribution(int translationIndex){ + int tmpIndex; + DoubleVector tmpArray; + int i; + + for (i=0;i < arraySize;i++){ + tmpArray.push_back(array[i]); + } + //translate values + for (i=0;i < arraySize;i++){ + tmpIndex = (i + translationIndex + arraySize)%arraySize; + array[tmpIndex] = tmpArray[i]; + } + tmpArray.clear(); + //now delete tmp array +} + +void DynamicVector::addGaussianShape(double mean, double StdDev, double factor){ + int i; + for (i=0;i<array.size();i++){ + array[i] += factor*(1/(StdDev*sqrt(2*PI)))*exp(-1*(i-mean)*(i-mean)/(2*StdDev*StdDev)); + } + //printf("ADDED GAUSSIAN SHAPE %i\n", (int)array.size()); +} + +void DynamicVector::addConstant(double value){ + for (int i=0;i<array.size();i++){ + array[i] += value; + } +} + + +void DynamicVector::addToIndex(int index, double constant){ + array[index] += constant; +} + + +double DynamicVector::getIndexInRealTerms(const int& index){ + if (index < arraySize) + return (offset + scalar*index); + else + return 0; +} + +double DynamicVector::getRealTermsAsIndex(double value){ + value -= offset; + value /= scalar; + + return value; + +} + +void DynamicVector::drawVector(const int& minIndex, const int& maxIndex){ + + + double stepSize = ofGetWidth() / (double)(maxIndex - minIndex); + double screenHeight = ofGetHeight(); + double maxVal = getMaximum(); + + for (int i = max(1,minIndex+1);i < min(maxIndex, (int)array.size());i++){ + ofLine (stepSize*(i-1), screenHeight * (1 - array[i-1] / maxVal), stepSize*i, screenHeight * (1 - array[i] / maxVal) ); + } + +} + + +void DynamicVector::drawConstrainedVector(const int& minIndex, const int& maxIndex, const int& minScreenIndex, const int& maxScreenIndex){ + //constrain the height and width + + double stepSize = (maxScreenIndex - minScreenIndex) / (double)(maxIndex - minIndex);//step size in pixels per array bin + double screenHeight = ofGetHeight(); + double maxVal = getMaximum(); + + //OPTIMIZE!! XXX could just add stepsize each time + //not add minindex each time + int i = max(1,minIndex+1); +// ofDrawBitmapString("i = "+ofToString(i)+" :: screen min: "+ofToString(minScreenIndex + stepSize*(i-minIndex-1)), 20, 640); + + while ((minScreenIndex + stepSize*(i-minIndex)) < 0) + i++;//only draw what is on the screen + + for ( ; i < min(maxIndex+1, (int)array.size());i++){ + ofLine (minScreenIndex + (stepSize*(i-minIndex-1)), screenHeight * (1 - array[i-1] / maxVal), + minScreenIndex + (stepSize*(i-minIndex)), screenHeight * (1 - array[i] / maxVal) ); + + } + + ofLine(minScreenIndex, screenHeight, minScreenIndex, screenHeight/2); + ofLine(maxScreenIndex, screenHeight, maxScreenIndex, screenHeight/2); + +// ofDrawBitmapString(ofToString(stepSize, 2)+" "+ofToString(maxScreenIndex - minScreenIndex, 0), 20, 600); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DynamicVector.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,56 @@ +/* + * DynamicVector.h + * midiCannamReader + * + * Created by Andrew on 18/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +//OPTIMIZE CONSTRAINED VECTOR + +#include "stdlib.h" +#include "ofMain.h" + +#ifndef _DYNAMIC_VECTOR +#define _DYNAMIC_VECTOR + +class DynamicVector{ +public: + DynamicVector(); + + void createVector(int len); + void renormalise(); + void translateDistribution(int translationIndex); + typedef std::vector<double> DoubleVector; + DoubleVector array; + double getMaximum(); + void drawVector(const int& minIndex, const int& maxIndex); + void drawConstrainedVector(const int& minIndex, const int& maxIndex, const int& minScreenIndex, const int& maxScreenIndex); + + void addConstant(double value); + void addGaussianShape(double mean, double stddev, double factor); + void addToIndex(int index, double constant); + + void doProduct(DynamicVector& arrayOne, DynamicVector& arrayTwo); + + double getIndexInRealTerms(const int& index); + double getRealTermsAsIndex(double value); + + void printArray(); + void zero(); + + void copyFromDynamicVector(const DynamicVector& dynamicVec); + + //variables + int length, arraySize; + double maximumValue; + int MAPestimate; + + double offset; + double scalar;//each array point is this much of the quantity + //i.e. array[index] contributes to (offset + scalar*index) in real terms + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/drawMidiNotes.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,87 @@ +/* + * drawMidiNotes.cpp + * midiCannamReader + * + * Created by Andrew on 17/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "drawMidiNotes.h" + +drawMidiNotes::drawMidiNotes(){ + + + ticksPerScreen = 8000; + tickLocation = 0; + pulsesPerQuarternote = 240; + noteArrayIndex = 0; + noteMinimum = 30; + noteMaximum = 96; + screenWidth = ofGetWidth(); + screenHeight = ofGetHeight(); + noteHeight = screenHeight / (float)(noteMaximum - noteMinimum); +} + +void drawMidiNotes::reset(){ + noteArrayIndex = 0; + tickLocation = 0; + lastPeriodUpdateTime = ofGetElapsedTimeMillis(); + +} + +void drawMidiNotes::updatePlayPosition(){ + double timeDifference = ofGetElapsedTimeMillis() - lastPeriodUpdateTime; + //this is time diff in milliseconds + //then we have + double quarterNoteIntervals = (timeDifference / period); + tickLocation = quarterNoteIntervals * pulsesPerQuarternote; + +} + +void drawMidiNotes::drawFile(const IntMatrix& noteOnMatrix){ + int size = noteOnMatrix.size(); + if (size > 0){ + + int numberOfScreensIn = tickLocation / ticksPerScreen; + + while (noteArrayIndex < noteOnMatrix.size() && tickLocation > noteOnMatrix[noteArrayIndex][0] ) + noteArrayIndex++; + + while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < noteOnMatrix[noteArrayIndex][0]) + noteArrayIndex--; + + //need to start where we currently are in file + int maxNoteIndexToPrint = noteArrayIndex; + int minNoteIndexToPrint = noteArrayIndex; + + + while (maxNoteIndexToPrint < noteOnMatrix.size() && noteOnMatrix[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen ) + maxNoteIndexToPrint++; + + while (minNoteIndexToPrint > 0 && minNoteIndexToPrint < size && noteOnMatrix[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen) + minNoteIndexToPrint--; + + + for (int tmpIndex = minNoteIndexToPrint;tmpIndex < maxNoteIndexToPrint;tmpIndex++){ + int xLocation = (float)(noteOnMatrix[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*screenWidth/(float)ticksPerScreen; + int duration = (float)(noteOnMatrix[tmpIndex][3]*screenWidth)/(float)ticksPerScreen; + + + int yLocation = screenHeight - ((noteOnMatrix[tmpIndex][1] - noteMinimum )*screenHeight/ (float)(noteMaximum - noteMinimum)); + ofRect(xLocation,yLocation, duration, noteHeight); + + } + + int xLocation = (float)(tickLocation - numberOfScreensIn*ticksPerScreen)*screenWidth/(float)ticksPerScreen; + ofLine(xLocation, 0, xLocation, screenHeight); + + // if (noteArrayIndex < size ) + // printf("tick %i :: note array :%i: %i\n", tickLocation, noteArrayIndex, noteOnMatrix[noteArrayIndex][0]); + // else + // printf("end of file\n"); + + + } + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/drawMidiNotes.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,42 @@ +/* + * drawMidiNotes.h + * midiCannamReader + * + * Created by Andrew on 17/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + + +#include "ofMain.h" + +class drawMidiNotes{ +public: + drawMidiNotes(); + void updatePlayPosition(); + + typedef std::vector<double> DoubleVector; + typedef std::vector<DoubleVector> DoubleMatrix; + + DoubleMatrix beatPeriodMatrix; + + typedef std::vector<int> IntVector; + typedef std::vector<IntVector> IntMatrix; + + void drawFile(const IntMatrix& noteOnMatrix); + void reset(); + + int ticksPerScreen; + int tickLocation; + int noteArrayIndex; + + int noteMinimum, noteMaximum; + int screenWidth, screenHeight; + float noteHeight; + float tempo; + double period; + int pulsesPerQuarternote; + double lastPeriodUpdateTime; + + +}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,16 @@ +#include "ofMain.h" +#include "testApp.h" +#include "ofAppGlutWindow.h" + +//======================================================================== +int main( ){ + + ofAppGlutWindow window; + ofSetupOpenGL(&window, 1024,768, OF_WINDOW); // <-------- setup the GL context + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp( new testApp()); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/midiEventHolder.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,429 @@ +/* + * midiEventHolder.cpp + * midiCannamReader3 + * + * Created by Andrew on 19/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ +//hello + +#include "midiEventHolder.h" + +midiEventHolder::midiEventHolder(){ +// recordedNoteOnIndex = 0; + + width = ofGetWidth(); + height = ofGetHeight(); + screenWidth= &width; + screenHeight = &height; + + ticksPerScreen = 4000; + tickLocation = 0; + pulsesPerQuarternote = 240; + noteArrayIndex = 0; + noteMinimum = 30; + noteMaximum = 96; + + minimumMatchSpeed = 0.5; + maximumMatchSpeed = 2.0; + likelihoodWidth = 100; + likelihoodToNoiseRatio = 50; + + matchWindowWidth = 6000;//window size for matching in ms + + bayesStruct.resetSize(4000); + bayesStruct.resetSpeedSize(200); + bayesStruct.setRelativeSpeedScalar(0.01); + bayesStruct.relativeSpeedPrior.getMaximum(); + bayesStruct.simpleExample(); + + noteHeight = (*screenHeight) / (float)(noteMaximum - noteMinimum); +} + + + +void midiEventHolder::reset(){ + noteArrayIndex = 0; + tickLocation = 0; + lastPeriodUpdateTime = ofGetElapsedTimeMillis(); + bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); + numberOfScreensIn = 0; +// recordedNoteOnIndex = 0; + bayesStruct.setNewDistributionOffsets(0); + bayesStruct.posterior.offset = 0; + + playedEventTimes.clear(); + playedNoteOnMatrix.clear(); + matchMatrix.clear(); + + bayesStruct.resetSpeedToOne(); + +} + +void midiEventHolder::printNotes(){ + printf("RECORDED MATRIX"); + for (int i = 0;i < recordedNoteOnMatrix.size();i++){ + printf("%i :: %i @ %f\n", recordedNoteOnMatrix[i][0], recordedNoteOnMatrix[i][1], recordedEventTimes[i]); + } +} + + +double midiEventHolder::getEventTimeTicks(double millis){ + return (millis * pulsesPerQuarternote / period); +} + +double midiEventHolder::getEventTimeMillis(double ticks){ + return (period * ticks / (double) pulsesPerQuarternote); +} + +void midiEventHolder::newNoteOnEvent(int pitch, int velocity, double timePlayed){ + + //MOVE INTO BAYESSTRUCT?? XXX + //bayesStruct.copyPriorToPosterior(); + //why was this here?? + bayesStruct.prior.copyFromDynamicVector(bayesStruct.posterior);//try the otehr way + //bayesStruct.copyPriorToPosterior(); + //need to get new MAP position and set the offset of the arrays + //currently bestEstimate is the approx for the new MAP position + + + //add the new event to our played information matrix + IntVector v; + v.push_back(pitch); + v.push_back(velocity); + playedNoteOnMatrix.push_back(v); + + + //would update the arrays at this point to show where out current location (phase) and tempo is. + double timeNow = ofGetElapsedTimeMillis() - startTime; + recentNoteOnTime = timeNow; + + printf("Max time %f OF time %f \n", timePlayed, timeNow); + + playedEventTimes.push_back(timePlayed); + + double timeDifference = ofGetElapsedTimeMillis() - bayesStruct.lastEventTime; + + //addnoise to the tempo distribution + bayesStruct.decaySpeedDistribution(timeDifference); + + +// double newMAPestimateTime = bayesStruct.posterior.getIndexInRealTerms(bayesStruct.posterior.MAPestimate); + //was offset + bayesStruct.posterior.MAPestimate; but this doesnt include scalar to convert to millis + + timeString = "Pitch:"+ofToString(pitch); + timeString += ", time now:"+ofToString(timeNow, 1); + timeString += " TD "+ofToString(timeDifference, 1); + timeString += " offset "+ofToString(bayesStruct.posterior.offset , 0); + timeString += " map Est: "+ofToString(bayesStruct.posterior.MAPestimate, 0); +// timeString += " Previous time" + ofToString(newMAPestimateTime,0); + timeString += " speedMap "+ofToString(bayesStruct.relativeSpeedPosterior.MAPestimate, 2); + timeString += " :: "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 2); + +// newMAPestimateTime += (timeDifference * bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate)); +// timeString += " : Predicted MAP time" + ofToString(newMAPestimateTime,0); + + //then we recalculate the window start based on MAP being central + //then we do the matches on these and the likelihood on these. + + bayesStruct.setNewDistributionOffsets(max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2))); +// bayesStruct.prior.offset = max(0.,newMAPestimateTime - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); + + timeString += " \n : new offset " + ofToString(bayesStruct.prior.offset , 0); + timeString += " \n best estimate "+ofToString(bayesStruct.bestEstimate, 1); + timeString += " map "+ofToString(bayesStruct.relativeSpeedPosterior.MAPestimate, 1); + timeString += " rel speed "+ofToString(bayesStruct.relativeSpeedPosterior.getIndexInRealTerms(bayesStruct.relativeSpeedPosterior.MAPestimate), 1); + + + //be able to draw the prior in correct location relative to the midi notes + bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, timeDifference); +// bayesStruct.crossUpdateArrays(bayesStruct.prior, bayesStruct.relativeSpeedPosterior, timeDifference); + + + timeString += " new OFF "+ofToString(bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2), 1); + timeString += " notearrayindex "+ofToString(noteArrayIndex, 0); + //when this is off teh screen there is a problem somehow XXX + bayesStruct.posterior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); +// bayesStruct.prior.offset = max(0., bayesStruct.bestEstimate - (bayesStruct.prior.scalar*bayesStruct.prior.arraySize/2)); + //trying to switch to prior + + bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); + + //do the cross update to find current posterior for location + int numberOfMatchesFound = findLocalMatches(pitch); + setMatchLikelihoods(numberOfMatchesFound); + bayesStruct.calculatePosterior(); + + //having found matches we have matches for new note and matches for previous notes + findLocalTempoPairs(); + + + +} + +int midiEventHolder::findLocalMatches(int notePitch){ + + //here we find the matches to the new note within appropriate range + + matchString += ", "+ofToString(notePitch); + + windowStartTime = max(0.0,(bayesStruct.bestEstimate - matchWindowWidth/2));//was playPositionInMillis + int numberOfMatches = findMatch(notePitch, windowStartTime, windowStartTime + matchWindowWidth); + + return numberOfMatches; + + +} + + +void midiEventHolder::setMatchLikelihoods(int numberOfMatches){ +//reset the offset to match the prior + bayesStruct.likelihood.offset = bayesStruct.prior.offset; + bayesStruct.likelihood.zero();//set to zero + + + + for (int i = 0;i < numberOfMatches && matchesFound[i] >= 0 && matchesFound[i] < recordedEventTimes.size();i++){ + // printf("match times %i of %i::%f adding likelihood to %f\n", i, numberOfMatches, recordedEventTimes[matchesFound[i]], recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset); + //this is the vent time since start of file + if (recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset < bayesStruct.likelihood.arraySize){ + bayesStruct.likelihood.addGaussianShape(recordedEventTimes[matchesFound[i]] - bayesStruct.likelihood.offset, likelihoodWidth, 0.5 * likelihoodToNoiseRatio); + }//end if + } + bayesStruct.likelihood.addConstant(0.01); +} + +int midiEventHolder::findMatch(const int& notePitch, const int& startTime, const int& endTime){ + + matchesFound.clear(); + int startIndex = 0; + + if (recordedEventTimes.size() > 0){ + + //get to the right range of events to check in + while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < startTime) + startIndex++; + + } + + + while (startIndex < recordedEventTimes.size() && recordedEventTimes[startIndex] < endTime){ + if (recordedNoteOnMatrix[startIndex][1] == notePitch){ + matchesFound.push_back(startIndex); + } + startIndex++; + } + +// printf("%i MATCHES TO Note %i found\n", (int)matchesFound.size(), notePitch); + int size = matchesFound.size(); + + IntVector v; + v.push_back(size); + for (int i = 0;i < matchesFound.size();i++) + v.push_back(matchesFound[i]); + + matchMatrix.push_back(v); + + return size; +} + +bool midiEventHolder::checkIfMatchedNote(const int& tmpIndex){ + for (int i = 0;i < matchesFound.size();i++){ + if (matchesFound[i] == tmpIndex) + return true; + } + return false; +} + + + +void midiEventHolder::findLocalTempoPairs(){ + + int currentPlayedIndex = playedNoteOnMatrix.size()-1; +// printf("played %i : %i, vel %i\n", currentPlayedIndex, playedNoteOnMatrix[currentPlayedIndex][0], playedNoteOnMatrix[currentPlayedIndex][1]); +// printMatchesFound(); +// printMatchMatrix(); +// printf("possible notes \n"); + + + for (int i = 0;i < matchMatrix[currentPlayedIndex][0];i++){ + + int recordedCurrentIndex = matchMatrix[currentPlayedIndex][i+1]; + + int previousIndex = currentPlayedIndex-1; + + while (previousIndex >= 0 && playedEventTimes[previousIndex] + 2000 > playedEventTimes[currentPlayedIndex]) { + double playedTimeDifference = playedEventTimes[currentPlayedIndex] - playedEventTimes[previousIndex]; + + for (int k = 0;k < matchMatrix[previousIndex][0];k++){ + int recordedPreviousIndex = matchMatrix[previousIndex][k+1]; + + // printf("(%i)", matchMatrix[currentPlayedIndex][i+1]); + // printf("[%i] :: ", recordedPreviousIndex); + + double recordedTimeDifference = recordedEventTimes[recordedCurrentIndex] - recordedEventTimes[recordedPreviousIndex]; + /// printf(" rec{%f} vs play(%f) ", recordedTimeDifference, playedTimeDifference); + + //we want the speed of the recording relative to that of the playing live + + double speedRatio = recordedTimeDifference / playedTimeDifference; + if (speedRatio <= maximumMatchSpeed && speedRatio >= minimumMatchSpeed){ + + // printf("update on speed ratio %f", speedRatio); + // commented for debug + bayesStruct.updateTempoDistribution(speedRatio, 0.1);//second paramter is confidence in the match + + } + // printf("\n"); + } + + previousIndex--; + }//end while previousindex countdown + }//end for loop through possible current matches + + +} + + +void midiEventHolder::updatePlayPosition(){ + + //in actual fact if we are changing the speed of the play position + //we will need to update this via the file + + double timeDifference = ofGetElapsedTimeMillis() - lastPeriodUpdateTime; + //this is time diff in milliseconds + //then we have + double quarterNoteIntervals = (timeDifference / period); + tickLocation = quarterNoteIntervals * pulsesPerQuarternote; + + playPositionInMillis = timeDifference;//based on updating from when we change period + //this to be added + + bayesStruct.updateBestEstimate(); + +} + + +void midiEventHolder::drawFile(){ + //draws midi file on scrolling screen + int size = recordedNoteOnMatrix.size(); + if (size > 0){ + + numberOfScreensIn = floor(bayesStruct.bestEstimate / getEventTimeMillis(ticksPerScreen));//rpounds down on no screens in + + // numberOfScreensIn = tickLocation / ticksPerScreen;//rounds down + timeOffsetForScreen = getEventTimeMillis(numberOfScreensIn * ticksPerScreen); + + while (noteArrayIndex < recordedNoteOnMatrix.size() && tickLocation > recordedNoteOnMatrix[noteArrayIndex][0] ) + noteArrayIndex++; + + + while (noteArrayIndex > 0 && noteArrayIndex < size && tickLocation < recordedNoteOnMatrix[noteArrayIndex][0]) + noteArrayIndex--; + + //need to start where we currently are in file + int maxNoteIndexToPrint = noteArrayIndex; + int minNoteIndexToPrint = noteArrayIndex; + + while (maxNoteIndexToPrint < recordedNoteOnMatrix.size() && recordedNoteOnMatrix[maxNoteIndexToPrint][0] < (numberOfScreensIn+1)*ticksPerScreen ) + maxNoteIndexToPrint++; + + while (minNoteIndexToPrint > 0 && minNoteIndexToPrint < size && recordedNoteOnMatrix[minNoteIndexToPrint][0] > numberOfScreensIn*ticksPerScreen) + minNoteIndexToPrint--; + + for (int tmpIndex = max(0,minNoteIndexToPrint);tmpIndex < min(maxNoteIndexToPrint, (int)recordedNoteOnMatrix.size());tmpIndex++){ + + if (checkIfMatchedNote(tmpIndex)) + ofSetColor(0,0,255); + else + ofSetColor(255,255,255); + + // XXX replace ofgetwidth below + //if (tmpIndex >= 0 && tmpIndex < size) + int xLocation = (float)(recordedNoteOnMatrix[tmpIndex][0] - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen; + int duration = (float)(recordedNoteOnMatrix[tmpIndex][3]*(*screenWidth))/(float)ticksPerScreen; + + + int yLocation = (*screenHeight) - ((recordedNoteOnMatrix[tmpIndex][1] - noteMinimum )*(*screenHeight)/ (float)(noteMaximum - noteMinimum)); + ofRect(xLocation,yLocation, duration, noteHeight); + + } + + + int xLocation;// = getLocationFromTicks(tickLocation); + // ofLine(xLocation, 0, xLocation, (*screenHeight)); + + //orange line at best estimate + xLocation = getLocationFromMillis(bayesStruct.bestEstimate); + ofSetColor(250,100,0); + ofLine(xLocation, 0, xLocation, (*screenHeight)); + + + //lines where matching window start and end are + ofSetColor(0,100,255); + xLocation = getLocationFromMillis(windowStartTime); + ofLine(xLocation, 0, xLocation, (*screenHeight)); + xLocation = getLocationFromMillis(windowStartTime+matchWindowWidth); + ofLine(xLocation, 0, xLocation, (*screenHeight)); + + + } + + ofDrawBitmapString(ofToString(timeOffsetForScreen, 1), 20,20); + + ofDrawBitmapString(timeString, 20, 60); + +// bayesStruct.drawArrays(); + +// ofSetColor(200,200,0); +// bayesStruct.prior.drawConstrainedVector(0, bayesStruct.prior.arraySize, 400, 800); + + //need to draw arrays within correct timescope + bayesStruct.drawArraysRelativeToTimeframe(timeOffsetForScreen, timeOffsetForScreen + getEventTimeMillis(ticksPerScreen)); + + //bayesStruct.drawTempoArrays(); + + ofDrawBitmapString(matchString, 20, ofGetHeight() - 20); + +} + +int midiEventHolder::getLocationFromTicks(double tickPosition){ + return (int)((float)(tickPosition - numberOfScreensIn*ticksPerScreen)*(*screenWidth)/(float)ticksPerScreen); +} + +int midiEventHolder::getLocationFromMillis(double millisPosition){ + //(getEventTimeTicks(windowStartTime+matchWindowWidth) - numberOfScreensIn*ticksPerScreen)*(*screenWidth) / (double)ticksPerScreen + return (millisPosition - timeOffsetForScreen)*(*screenWidth)/getEventTimeMillis(ticksPerScreen); +} + + +void midiEventHolder::exampleCrossUpdate(){ + + bayesStruct.crossUpdateArrays(bayesStruct.posterior, bayesStruct.relativeSpeedPosterior, 200); + +} + + +void midiEventHolder::setStartPlayingTimes(){ + lastPeriodUpdateTime = ofGetElapsedTimeMillis(); + bayesStruct.lastEventTime = ofGetElapsedTimeMillis(); + startTime = lastPeriodUpdateTime; + + bayesStruct.resetArrays(); +// bayesStruct.lastBestEstimateUpdateTime = ofGetElapsedTimeMillis(); + matchString = ""; +} + + +void midiEventHolder::printMatchMatrix(){ + printf("match matrix:\n"); + for (int i = 0;i < matchMatrix.size();i++){ + for (int k = 0;k < matchMatrix[i].size();k++){ + printf("%i , ", matchMatrix[i][k]); + } + printf("\n"); + } + + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/midiEventHolder.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,106 @@ +/* + * midiEventHolder.h + * midiCannamReader3 + * + * Created by Andrew on 19/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ +#include "ofMain.h" +#include "BayesianArrayStructure.h" + +class midiEventHolder{ + +public: + + midiEventHolder(); + void printNotes(); + + typedef std::vector<int> IntVector; + typedef std::vector<IntVector> IntMatrix; + + typedef std::vector<bool> BoolVector; + + typedef std::vector<double> DoubleVector; + typedef std::vector<DoubleVector> DoubleMatrix; + + //the rehearsal version + IntMatrix recordedNoteOnMatrix;//note, velocity, duration + IntVector matchesFound; + BoolVector noteOnMatches; +// int recordedNoteOnIndex; + DoubleVector recordedEventTimes; + + IntMatrix playedNoteOnMatrix; + DoubleVector playedEventTimes; + int playedNoteIndex; + IntMatrix matchMatrix; + + + double minimumMatchSpeed , maximumMatchSpeed; + + double period, pulsesPerQuarternote; + double getEventTimeMillis(double ticks); + double getEventTimeTicks(double millis); + + int getLocationFromTicks(double tickPosition); + int getLocationFromMillis(double millisPosition); + + double windowStartTime; + + //functions for finding match to incoming note + void newNoteOnEvent(int pitch, int velocity, double timePlayed); + int findLocalMatches(int notePitch); + bool checkIfMatchedNote(const int& tmpIndex); + int findMatch(const int& notePitch, const int& startTime, const int& endTime); + + + void findLocalTempoPairs(); + + + double likelihoodWidth; + double likelihoodToNoiseRatio; + + void printMatchMatrix(); + + void setMatchLikelihoods(int numberOfMatches); + + void setStartPlayingTimes(); + + int width, height; + ///// + string matchString; + void updatePlayPosition(); + + DoubleMatrix beatPeriodMatrix; + + void drawFile(); + void reset(); + + int ticksPerScreen; + int tickLocation; + int numberOfScreensIn; + int noteArrayIndex; + + int matchWindowWidth; + + int noteMinimum, noteMaximum; + int* screenWidth; + int* screenHeight; + float noteHeight; + float tempo; + double lastPeriodUpdateTime; + + double playPositionInMillis; + + double timeOffsetForScreen; + + double recentNoteOnTime; + + void exampleCrossUpdate(); + BayesianArrayStructure bayesStruct; + + string timeString; + double startTime; + +}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testApp.cpp Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,424 @@ +#include "testApp.h" + +//-------------------------------------------------------------- +void testApp::setup(){ + midiFileName = "../../../data/entertainer.mid"; + int retVal = cannamMainFunction(); + + playing = false; + /* + bayesStruct.resetSize(1000); + bayesStruct.resetSpeedSize(200); + bayesStruct.setRelativeSpeedScalar(0.01); + bayesStruct.simpleExample(); + */ + + receiver.setup( PORT ); + + screenWidth = ofGetWidth(); + screenHeight = ofGetHeight(); + midiEvents.screenWidth = &screenWidth; + midiEvents.screenHeight = &screenHeight; + ofSetFrameRate(100); +} + +//-------------------------------------------------------------- +void testApp::update(){ + if (playing){ + midiEvents.updatePlayPosition(); + midiEvents.bayesStruct.updateBestEstimate(); + } +// drawer.tickLocation+=20; + + // check for waiting messages + while( receiver.hasWaitingMessages() ) + { + ofxOscMessage m; + receiver.getNextMessage( &m ); + + if ( m.getAddress() == "/midinoteon" ) + { + int newMidiOnPitch = m.getArgAsInt32(0); + int velocity = m.getArgAsInt32(1); + double time = m.getArgAsFloat(2); + + if (velocity != 0) + midiEvents.newNoteOnEvent(newMidiOnPitch, velocity, time); + + } + + if ( m.getAddress() == "/startplaying" ) + { + startPlaying(); + } + + if ( m.getAddress() == "/stopplaying" ) + { + stopPlaying(); + } + }//end while osc + +} + +//-------------------------------------------------------------- +void testApp::draw(){ + + midiEvents.drawFile(); + +} + +//-------------------------------------------------------------- +void testApp::keyPressed(int key){ + + + if (key == ' '){ + startPlaying(); + } + + if (key == 'c'){ + double timenow = ofGetElapsedTimeMillis(); + midiEvents.exampleCrossUpdate(); + timenow *= -1; + timenow += ofGetElapsedTimeMillis(); + printf("CROSS UPDATE TOOK %f", timenow); + } + + if (key == OF_KEY_RETURN) + stopPlaying(); + + if (key == OF_KEY_UP){ + if (midiEvents.ticksPerScreen >= 4000) + midiEvents.ticksPerScreen += 2000; + else + midiEvents.ticksPerScreen += 500; + } + + if (key == 'm'){ +// midiEvents.findMatch(84, 0, 10000); + } + + if (key == OF_KEY_DOWN){ + if (midiEvents.ticksPerScreen >= 4000) + midiEvents.ticksPerScreen -= 2000; + else if (midiEvents.ticksPerScreen > 500) + midiEvents.ticksPerScreen -= 500; + } + + if (key == 'w') + midiEvents.printMatchMatrix(); + + if (key == 'p'){ + midiEvents.printNotes(); + } + + if (key == 'l') + midiEvents.bayesStruct.decaySpeedDistribution(100); + + if (key == 'o'){ + //open audio file + string *filePtr; + filePtr = &midiFileName; + + if (getFilenameFromDialogBox(filePtr)){ + printf("Midifile: Loaded name okay :\n'%s' \n", midiFileName.c_str()); + cannamMainFunction(); + } + + } +} + +//-------------------------------------------------------------- +void testApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void testApp::mouseMoved(int x, int y ){ + +} + +//-------------------------------------------------------------- +void testApp::mouseDragged(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void testApp::mousePressed(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void testApp::mouseReleased(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void testApp::windowResized(int w, int h){ + screenWidth = w; + screenHeight = h; + midiEvents.noteHeight = screenHeight / (float)(midiEvents.noteMaximum - midiEvents.noteMinimum); + +} + + + +void testApp::startPlaying(){ + playing = !playing; + midiEvents.reset(); + midiEvents.setStartPlayingTimes(); + //this is where we stop and start playing +} + +void testApp::stopPlaying(){ + playing = false; +} + +bool testApp::getFilenameFromDialogBox(string* fileNameToSave){ + //this uses a pointer structure within the loader and returns true if the dialogue box was used successfully + // first, create a string that will hold the URL + string URL; + + // openFile(string& URL) returns 1 if a file was picked + // returns 0 when something went wrong or the user pressed 'cancel' + int response = ofxFileDialogOSX::openFile(URL); + if(response){ + // now you can use the URL + *fileNameToSave = URL; + //printf("\n filename is %s \n", soundFileName.c_str()); + return true; + } + else { + // soundFileName = "OPEN canceled. "; + printf("\n open file cancelled \n"); + return false; + } + + + +} + + + + +int testApp::cannamMainFunction(){ + + + midiEvents.recordedNoteOnMatrix.clear();//where we store the note ons + + //int main(int argc, char **argv) + //{ + // if (argc != 2) { + // cerr << "Usage: midifile <file.mid>" << endl; + // return 1; + // } + + std::string filename = midiFileName;//argv[1]; + + MIDIFileReader fr(filename); + if (!fr.isOK()) { + std::cerr << "Error: " << fr.getError().c_str() << std::endl; + return 1; + } + + MIDIComposition c = fr.load(); + + switch (fr.getFormat()) { + case MIDI_SINGLE_TRACK_FILE: cout << "Format: MIDI Single Track File" << endl; break; + case MIDI_SIMULTANEOUS_TRACK_FILE: cout << "Format: MIDI Simultaneous Track File" << endl; break; + case MIDI_SEQUENTIAL_TRACK_FILE: cout << "Format: MIDI Sequential Track File" << endl; break; + default: cout << "Format: Unknown MIDI file format?" << endl; break; + } + + cout << "Tracks: " << c.size() << endl; + + int td = fr.getTimingDivision(); + if (td < 32768) { + cout << "Timing division: " << fr.getTimingDivision() << " ppq" << endl; + + midiEvents.pulsesPerQuarternote = fr.getTimingDivision(); + } else { + int frames = 256 - (td >> 8); + int subframes = td & 0xff; + cout << "SMPTE timing: " << frames << " fps, " << subframes << " subframes" << endl; + } + + for (MIDIComposition::const_iterator i = c.begin(); i != c.end(); ++i) { + + cout << "Start of track: " << i->first+1 << endl; + + for (MIDITrack::const_iterator j = i->second.begin(); j != i->second.end(); ++j) { + + unsigned int t = j->getTime(); + int ch = j->getChannelNumber(); + + if (j->isMeta()) { + int code = j->getMetaEventCode(); + string name; + bool printable = true; + switch (code) { + + case MIDI_END_OF_TRACK: + cout << t << ": End of track" << endl; + break; + + case MIDI_TEXT_EVENT: name = "Text"; break; + case MIDI_COPYRIGHT_NOTICE: name = "Copyright"; break; + case MIDI_TRACK_NAME: name = "Track name"; break; + case MIDI_INSTRUMENT_NAME: name = "Instrument name"; break; + case MIDI_LYRIC: name = "Lyric"; break; + case MIDI_TEXT_MARKER: name = "Text marker"; break; + case MIDI_SEQUENCE_NUMBER: name = "Sequence number"; printable = false; break; + case MIDI_CHANNEL_PREFIX_OR_PORT: name = "Channel prefix or port"; printable = false; break; + case MIDI_CUE_POINT: name = "Cue point"; break; + case MIDI_CHANNEL_PREFIX: name = "Channel prefix"; printable = false; break; + case MIDI_SEQUENCER_SPECIFIC: name = "Sequencer specific"; printable = false; break; + case MIDI_SMPTE_OFFSET: name = "SMPTE offset"; printable = false; break; + + case MIDI_SET_TEMPO: + { + int m0 = j->getMetaMessage()[0]; + int m1 = j->getMetaMessage()[1]; + int m2 = j->getMetaMessage()[2]; + long tempo = (((m0 << 8) + m1) << 8) + m2; + + cout << t << ": Tempo: " << 60000000.0 / double(tempo) << endl; + midiEvents.tempo = 60000000.0 / double(tempo); + midiEvents.period = double(tempo)/1000.0; + + printf("period double is %f\n", midiEvents.period); + } + break; + + case MIDI_TIME_SIGNATURE: + { + int numerator = j->getMetaMessage()[0]; + int denominator = 1 << (int)j->getMetaMessage()[1]; + + cout << t << ": Time signature: " << numerator << "/" << denominator << endl; + } + + case MIDI_KEY_SIGNATURE: + { + int accidentals = j->getMetaMessage()[0]; + int isMinor = j->getMetaMessage()[1]; + bool isSharp = accidentals < 0 ? false : true; + accidentals = accidentals < 0 ? -accidentals : accidentals; + cout << t << ": Key signature: " << accidentals << " " + << (isSharp ? + (accidentals > 1 ? "sharps" : "sharp") : + (accidentals > 1 ? "flats" : "flat")) + << (isMinor ? ", minor" : ", major") << endl; + } + + } + + + if (name != "") { + if (printable) { + cout << t << ": File meta event: code " << code + << ": " << name << ": \"" << j->getMetaMessage() + << "\"" << endl; + } else { + cout << t << ": File meta event: code " << code + << ": " << name << ": "; + for (int k = 0; k < j->getMetaMessage().length(); ++k) { + cout << (int)j->getMetaMessage()[k] << " "; + } + } + } + continue; + } + + switch (j->getMessageType()) { + + case MIDI_NOTE_ON: + cout << t << ": Note: channel " << ch + << " duration " << j->getDuration() + << " pitch " << j->getPitch() + << " velocity " << j->getVelocity() + << "event time " << midiEvents.getEventTimeMillis(t) << endl; + v.clear(); + v.push_back(t); + v.push_back(j->getPitch()); + v.push_back(j->getVelocity()); + v.push_back(j->getDuration()); + midiEvents.recordedNoteOnMatrix.push_back(v); + midiEvents.recordedEventTimes.push_back(midiEvents.getEventTimeMillis(t)); + break; + + case MIDI_POLY_AFTERTOUCH: + cout << t << ": Polyphonic aftertouch: channel " << ch + << " pitch " << j->getPitch() + << " pressure " << j->getData2() << endl; + break; + + case MIDI_CTRL_CHANGE: + { + int controller = j->getData1(); + string name; + switch (controller) { + case MIDI_CONTROLLER_BANK_MSB: name = "Bank select MSB"; break; + case MIDI_CONTROLLER_VOLUME: name = "Volume"; break; + case MIDI_CONTROLLER_BANK_LSB: name = "Bank select LSB"; break; + case MIDI_CONTROLLER_MODULATION: name = "Modulation wheel"; break; + case MIDI_CONTROLLER_PAN: name = "Pan"; break; + case MIDI_CONTROLLER_SUSTAIN: name = "Sustain"; break; + case MIDI_CONTROLLER_RESONANCE: name = "Resonance"; break; + case MIDI_CONTROLLER_RELEASE: name = "Release"; break; + case MIDI_CONTROLLER_ATTACK: name = "Attack"; break; + case MIDI_CONTROLLER_FILTER: name = "Filter"; break; + case MIDI_CONTROLLER_REVERB: name = "Reverb"; break; + case MIDI_CONTROLLER_CHORUS: name = "Chorus"; break; + case MIDI_CONTROLLER_NRPN_1: name = "NRPN 1"; break; + case MIDI_CONTROLLER_NRPN_2: name = "NRPN 2"; break; + case MIDI_CONTROLLER_RPN_1: name = "RPN 1"; break; + case MIDI_CONTROLLER_RPN_2: name = "RPN 2"; break; + case MIDI_CONTROLLER_SOUNDS_OFF: name = "All sounds off"; break; + case MIDI_CONTROLLER_RESET: name = "Reset"; break; + case MIDI_CONTROLLER_LOCAL: name = "Local"; break; + case MIDI_CONTROLLER_ALL_NOTES_OFF: name = "All notes off"; break; + } + cout << t << ": Controller change: channel " << ch + << " controller " << j->getData1(); + if (name != "") cout << " (" << name << ")"; + cout << " value " << j->getData2() << endl; + } + break; + + case MIDI_PROG_CHANGE: + cout << t << ": Program change: channel " << ch + << " program " << j->getData1() << endl; + break; + + case MIDI_CHNL_AFTERTOUCH: + cout << t << ": Channel aftertouch: channel " << ch + << " pressure " << j->getData1() << endl; + break; + + case MIDI_PITCH_BEND: + cout << t << ": Pitch bend: channel " << ch + << " value " << (int)j->getData2() * 128 + (int)j->getData1() << endl; + break; + + case MIDI_SYSTEM_EXCLUSIVE: + cout << t << ": System exclusive: code " + << (int)j->getMessageType() << " message length " << + j->getMetaMessage().length() << endl; + break; + + + } + + + } + + + } + + //} + + + + +}//end cannam midi main +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testApp.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,77 @@ +#ifndef _TEST_APP +#define _TEST_APP + + +//midieventholder - newMidiEvents() sent there +//create cannamMidiLoader for cannamMainfunction + + +//check new prior offset function - how is used? + + + +//check the widening function - adding decay noise +//ticksperscreen could be better as millis per screen + + + + + +#include "ofMain.h" + +#include "MIDIFileReader.h" +#include "ofxFileDialogOSX.h" +#include "drawMidiNotes.h" +#include "DynamicBayesianArray.h" + +#include <iostream> +#include "midiEventHolder.h" + +#include "ofxOsc.h" +#define PORT 12121 + +using namespace std; +using namespace MIDIConstants; + +class testApp : public ofBaseApp{ + + public: + void setup(); + void update(); + void draw(); + + void keyPressed (int key); + void keyReleased(int key); + void mouseMoved(int x, int y ); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void windowResized(int w, int h); + + void startPlaying(); + void stopPlaying(); + bool getFilenameFromDialogBox(string* fileNameToSave); + + typedef std::vector<int> IntVector; + typedef std::vector<double> DoubleVector; +// typedef std::vector<IntVector> IntMatrix; + IntVector v; + + midiEventHolder midiEvents; + + int cannamMainFunction(); + string midiFileName; + + bool playing; + //drawMidiNotes drawer; + +// BayesianArrayStructure bayesStruct; + + int screenWidth, screenHeight; + +private: + ofxOscReceiver receiver; + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/untitled.h Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,12 @@ +/* + * untitled.h + * midiCannamReader + * + * Created by Andrew on 18/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "ofMain.h" + +class Double \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/workingNotes.rtf Tue Aug 16 11:29:59 2011 +0100 @@ -0,0 +1,19 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\paperw11900\paperh16840\margl1440\margr1440\vieww9000\viewh8400\viewkind0 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural + +\f0\fs24 \cf0 BUGS:\ +When prior and posterior etc are split off the screen, it doesn't find the right indices for them. Are we writing the correct prior vector? constrained limits?\ +\ +\ +using best estimate continually - good in the new note on function?\ +\ ++ + + + + + + + + \ +\ +best estimate locked to map so need to free\ +\ +need to do relative tempo estimates\ +\ +} \ No newline at end of file