Update of RtAudio and RtMidi classes in advance of 4.6.0 release.

This commit is contained in:
Gary Scavone
2017-08-31 17:28:55 -07:00
parent d6c67cc479
commit 11d1dc54f3
4 changed files with 10699 additions and 10453 deletions

View File

@@ -45,11 +45,11 @@
#ifndef __RTAUDIO_H
#define __RTAUDIO_H
#define RTAUDIO_VERSION "4.1.2"
#define RTAUDIO_VERSION "5.0.0"
#include <string>
#include <vector>
#include <exception>
#include <stdexcept>
#include <iostream>
/*! \typedef typedef unsigned long RtAudioFormat;
@@ -86,6 +86,7 @@ static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/mi
- \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency.
- \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use.
- \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only).
- \e RTAUDIO_JACK_DONT_CONNECT: Do not automatically connect ports (JACK only).
By default, RtAudio streams pass and receive audio data from the
client in an interleaved format. By passing the
@@ -117,6 +118,9 @@ static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/mi
If the RTAUDIO_ALSA_USE_DEFAULT flag is set, RtAudio will attempt to
open the "default" PCM device when using the ALSA API. Note that this
will override any specified input or output device id.
If the RTAUDIO_JACK_DONT_CONNECT flag is set, RtAudio will not attempt
to automatically connect the ports of the client to the audio device.
*/
typedef unsigned int RtAudioStreamFlags;
static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1; // Use non-interleaved buffers (default = interleaved).
@@ -124,6 +128,7 @@ static const RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY = 0x2; // Attempt to s
static const RtAudioStreamFlags RTAUDIO_HOG_DEVICE = 0x4; // Attempt grab device and prevent use by others.
static const RtAudioStreamFlags RTAUDIO_SCHEDULE_REALTIME = 0x8; // Try to select realtime scheduling for callback thread.
static const RtAudioStreamFlags RTAUDIO_ALSA_USE_DEFAULT = 0x10; // Use the "default" PCM device (ALSA only).
static const RtAudioStreamFlags RTAUDIO_JACK_DONT_CONNECT = 0x20; // Do not automatically connect ports (JACK only).
/*! \typedef typedef unsigned long RtAudioStreamStatus;
\brief RtAudio stream status (over- or underflow) flags.
@@ -195,7 +200,7 @@ typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer,
*/
/************************************************************************/
class RtAudioError : public std::exception
class RtAudioError : public std::runtime_error
{
public:
//! Defined RtAudioError types.
@@ -214,25 +219,22 @@ class RtAudioError : public std::exception
};
//! The constructor.
RtAudioError( const std::string& message, Type type = RtAudioError::UNSPECIFIED ) throw() : message_(message), type_(type) {}
//! The destructor.
virtual ~RtAudioError( void ) throw() {}
RtAudioError( const std::string& message,
Type type = RtAudioError::UNSPECIFIED )
: std::runtime_error(message), type_(type) {}
//! Prints thrown error message to stderr.
virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; }
virtual void printMessage( void ) const
{ std::cerr << '\n' << what() << "\n\n"; }
//! Returns the thrown error message type.
virtual const Type& getType(void) const throw() { return type_; }
virtual const Type& getType(void) const { return type_; }
//! Returns the thrown error message string.
virtual const std::string& getMessage(void) const throw() { return message_; }
//! Returns the thrown error message as a c-style string.
virtual const char* what( void ) const throw() { return message_.c_str(); }
virtual const std::string getMessage(void) const
{ return std::string(what()); }
protected:
std::string message_;
Type type_;
};
@@ -375,7 +377,7 @@ class RtAudio
};
//! A static function to determine the current RtAudio version.
static std::string getVersion( void ) throw();
static std::string getVersion( void );
//! A static function to determine the available compiled audio APIs.
/*!
@@ -383,7 +385,7 @@ class RtAudio
the enumerated list values. Note that there can be more than one
API compiled for certain operating systems.
*/
static void getCompiledApi( std::vector<RtAudio::Api> &apis ) throw();
static void getCompiledApi( std::vector<RtAudio::Api> &apis );
//! The class constructor.
/*!
@@ -401,10 +403,10 @@ class RtAudio
If a stream is running or open, it will be stopped and closed
automatically.
*/
~RtAudio() throw();
~RtAudio();
//! Returns the audio API specifier for the current instance of RtAudio.
RtAudio::Api getCurrentApi( void ) throw();
RtAudio::Api getCurrentApi( void );
//! A public function that queries for the number of audio devices available.
/*!
@@ -412,7 +414,7 @@ class RtAudio
is called, thus supporting devices connected \e after instantiation. If
a system error occurs during processing, a warning will be issued.
*/
unsigned int getDeviceCount( void ) throw();
unsigned int getDeviceCount( void );
//! Return an RtAudio::DeviceInfo structure for a specified device number.
/*!
@@ -435,7 +437,7 @@ class RtAudio
client's responsibility to verify that a device is available
before attempting to open a stream.
*/
unsigned int getDefaultOutputDevice( void ) throw();
unsigned int getDefaultOutputDevice( void );
//! A function that returns the index of the default input device.
/*!
@@ -445,7 +447,7 @@ class RtAudio
client's responsibility to verify that a device is available
before attempting to open a stream.
*/
unsigned int getDefaultInputDevice( void ) throw();
unsigned int getDefaultInputDevice( void );
//! A public function for opening a stream with the specified parameters.
/*!
@@ -498,7 +500,7 @@ class RtAudio
If a stream is not open, this function issues a warning and
returns (no exception is thrown).
*/
void closeStream( void ) throw();
void closeStream( void );
//! A function that starts a stream.
/*!
@@ -528,10 +530,10 @@ class RtAudio
void abortStream( void );
//! Returns true if a stream is open and false if not.
bool isStreamOpen( void ) const throw();
bool isStreamOpen( void ) const;
//! Returns true if the stream is running and false if it is stopped or not open.
bool isStreamRunning( void ) const throw();
bool isStreamRunning( void ) const;
//! Returns the number of elapsed seconds since the stream was started.
/*!
@@ -565,7 +567,7 @@ class RtAudio
unsigned int getStreamSampleRate( void );
//! Specify whether warning messages should be printed to stderr.
void showWarnings( bool value = true ) throw();
void showWarnings( bool value = true );
protected:
@@ -616,7 +618,7 @@ struct CallbackInfo {
// Default constructor.
CallbackInfo()
:object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false) {}
:object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false), priority(0) {}
};
// **************************************************************** //
@@ -824,22 +826,22 @@ protected:
//
// **************************************************************** //
inline RtAudio::Api RtAudio :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
inline unsigned int RtAudio :: getDeviceCount( void ) throw() { return rtapi_->getDeviceCount(); }
inline RtAudio::Api RtAudio :: getCurrentApi( void ) { return rtapi_->getCurrentApi(); }
inline unsigned int RtAudio :: getDeviceCount( void ) { return rtapi_->getDeviceCount(); }
inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { return rtapi_->getDeviceInfo( device ); }
inline unsigned int RtAudio :: getDefaultInputDevice( void ) throw() { return rtapi_->getDefaultInputDevice(); }
inline unsigned int RtAudio :: getDefaultOutputDevice( void ) throw() { return rtapi_->getDefaultOutputDevice(); }
inline void RtAudio :: closeStream( void ) throw() { return rtapi_->closeStream(); }
inline unsigned int RtAudio :: getDefaultInputDevice( void ) { return rtapi_->getDefaultInputDevice(); }
inline unsigned int RtAudio :: getDefaultOutputDevice( void ) { return rtapi_->getDefaultOutputDevice(); }
inline void RtAudio :: closeStream( void ) { return rtapi_->closeStream(); }
inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); }
inline void RtAudio :: stopStream( void ) { return rtapi_->stopStream(); }
inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); }
inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); }
inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); }
inline bool RtAudio :: isStreamOpen( void ) const { return rtapi_->isStreamOpen(); }
inline bool RtAudio :: isStreamRunning( void ) const { return rtapi_->isStreamRunning(); }
inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); }
inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); }
inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); }
inline void RtAudio :: setStreamTime( double time ) { return rtapi_->setStreamTime( time ); }
inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); }
inline void RtAudio :: showWarnings( bool value ) { rtapi_->showWarnings( value ); }
// RtApi Subclass prototypes.
@@ -912,6 +914,8 @@ public:
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options );
bool shouldAutoconnect_;
};
#endif

View File

@@ -43,7 +43,7 @@
#ifndef RTMIDI_H
#define RTMIDI_H
#define RTMIDI_VERSION "2.1.1"
#define RTMIDI_VERSION "3.0.0"
#include <exception>
#include <iostream>
@@ -139,10 +139,10 @@ class RtMidi
static void getCompiledApi( std::vector<RtMidi::Api> &apis ) throw();
//! Pure virtual openPort() function.
virtual void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi" ) ) = 0;
virtual void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi" ) ) = 0;
//! Pure virtual openVirtualPort() function.
virtual void openVirtualPort( const std::string portName = std::string( "RtMidi" ) ) = 0;
virtual void openVirtualPort( const std::string &portName = std::string( "RtMidi" ) ) = 0;
//! Pure virtual getPortCount() function.
virtual unsigned int getPortCount() = 0;
@@ -154,6 +154,10 @@ class RtMidi
virtual void closePort( void ) = 0;
//! Returns true if a port is open and false if not.
/*!
Note that this only applies to connections made with the openPort()
function, not to virtual ports.
*/
virtual bool isPortOpen( void ) const = 0;
//! Set an error callback function to be invoked when an error has occured.
@@ -185,7 +189,7 @@ class RtMidi
possible to open a virtual input port to which other MIDI software
clients can connect.
by Gary P. Scavone, 2003-2014.
by Gary P. Scavone, 2003-2017.
*/
/**********************************************************************/
@@ -229,7 +233,7 @@ class RtMidiIn : public RtMidi
\param queueSizeLimit An optional size of the MIDI input queue can be specified.
*/
RtMidiIn( RtMidi::Api api=UNSPECIFIED,
const std::string clientName = std::string( "RtMidi Input Client"),
const std::string& clientName = "RtMidi Input Client",
unsigned int queueSizeLimit = 100 );
//! If a MIDI connection is still open, it will be closed by the destructor.
@@ -244,7 +248,7 @@ class RtMidiIn : public RtMidi
Otherwise, the default or first port found is opened.
\param portName An optional name for the application port that is used to connect to portId can be specified.
*/
void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi Input" ) );
void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi Input" ) );
//! Create a virtual input port, with optional name, to allow software connections (OS X, JACK and ALSA only).
/*!
@@ -256,7 +260,7 @@ class RtMidiIn : public RtMidi
\param portName An optional name for the application port that is
used to connect to portId can be specified.
*/
void openVirtualPort( const std::string portName = std::string( "RtMidi Input" ) );
void openVirtualPort( const std::string &portName = std::string( "RtMidi Input" ) );
//! Set a callback function to be invoked for incoming MIDI messages.
/*!
@@ -282,6 +286,10 @@ class RtMidiIn : public RtMidi
void closePort( void );
//! Returns true if a port is open and false if not.
/*!
Note that this only applies to connections made with the openPort()
function, not to virtual ports.
*/
virtual bool isPortOpen() const;
//! Return the number of available MIDI input ports.
@@ -293,7 +301,8 @@ class RtMidiIn : public RtMidi
//! Return a string identifier for the specified MIDI input port number.
/*!
\return The name of the port with the given Id is returned.
\retval An empty string is returned if an invalid port specifier is provided.
\retval An empty string is returned if an invalid port specifier
is provided. User code should assume a UTF-8 encoding.
*/
std::string getPortName( unsigned int portNumber = 0 );
@@ -325,7 +334,7 @@ class RtMidiIn : public RtMidi
virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
protected:
void openMidiApi( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit );
void openMidiApi( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit );
};
@@ -341,7 +350,7 @@ class RtMidiIn : public RtMidi
OS-X, Linux ALSA and JACK MIDI APIs, it is also possible to open a
virtual port to which other MIDI software clients can connect.
by Gary P. Scavone, 2003-2014.
by Gary P. Scavone, 2003-2017.
*/
/**********************************************************************/
@@ -358,7 +367,7 @@ class RtMidiOut : public RtMidi
JACK (OS-X).
*/
RtMidiOut( RtMidi::Api api=UNSPECIFIED,
const std::string clientName = std::string( "RtMidi Output Client") );
const std::string& clientName = "RtMidi Output Client" );
//! The destructor closes any open MIDI connections.
~RtMidiOut( void ) throw();
@@ -373,12 +382,16 @@ class RtMidiOut : public RtMidi
exception is thrown if an error occurs while attempting to make
the port connection.
*/
void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi Output" ) );
void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi Output" ) );
//! Close an open MIDI connection (if one exists).
void closePort( void );
//! Returns true if a port is open and false if not.
/*!
Note that this only applies to connections made with the openPort()
function, not to virtual ports.
*/
virtual bool isPortOpen() const;
//! Create a virtual output port, with optional name, to allow software connections (OS X, JACK and ALSA only).
@@ -390,14 +403,16 @@ class RtMidiOut : public RtMidi
An exception is thrown if an error occurs while attempting to
create the virtual port.
*/
void openVirtualPort( const std::string portName = std::string( "RtMidi Output" ) );
void openVirtualPort( const std::string &portName = std::string( "RtMidi Output" ) );
//! Return the number of available MIDI output ports.
unsigned int getPortCount( void );
//! Return a string identifier for the specified MIDI port type and number.
/*!
An empty string is returned if an invalid port specifier is provided.
\return The name of the port with the given Id is returned.
\retval An empty string is returned if an invalid port specifier
is provided. User code should assume a UTF-8 encoding.
*/
std::string getPortName( unsigned int portNumber = 0 );
@@ -406,7 +421,17 @@ class RtMidiOut : public RtMidi
An exception is thrown if an error occurs during output or an
output connection was not previously established.
*/
void sendMessage( std::vector<unsigned char> *message );
void sendMessage( const std::vector<unsigned char> *message );
//! Immediately send a single message out an open MIDI output port.
/*!
An exception is thrown if an error occurs during output or an
output connection was not previously established.
\param message A pointer to the MIDI message as raw bytes
\param size Length of the MIDI message in bytes
*/
void sendMessage( const unsigned char *message, size_t size );
//! Set an error callback function to be invoked when an error has occured.
/*!
@@ -416,7 +441,7 @@ class RtMidiOut : public RtMidi
virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
protected:
void openMidiApi( RtMidi::Api api, const std::string clientName );
void openMidiApi( RtMidi::Api api, const std::string &clientName );
};
@@ -440,8 +465,8 @@ class MidiApi
MidiApi();
virtual ~MidiApi();
virtual RtMidi::Api getCurrentApi( void ) = 0;
virtual void openPort( unsigned int portNumber, const std::string portName ) = 0;
virtual void openVirtualPort( const std::string portName ) = 0;
virtual void openPort( unsigned int portNumber, const std::string &portName ) = 0;
virtual void openVirtualPort( const std::string &portName ) = 0;
virtual void closePort( void ) = 0;
virtual unsigned int getPortCount( void ) = 0;
@@ -479,6 +504,8 @@ class MidiInApi : public MidiApi
// messages. Each message represents one and only one MIDI message.
struct MidiMessage {
std::vector<unsigned char> bytes;
//! Time in seconds elapsed since the previous message
double timeStamp;
// Default constructor.
@@ -489,13 +516,16 @@ class MidiInApi : public MidiApi
struct MidiQueue {
unsigned int front;
unsigned int back;
unsigned int size;
unsigned int ringSize;
MidiMessage *ring;
// Default constructor.
MidiQueue()
:front(0), back(0), size(0), ringSize(0) {}
:front(0), back(0), ringSize(0), ring(0) {}
bool push(const MidiMessage&);
bool pop(std::vector<unsigned char>*, double*);
unsigned int size(unsigned int *back=0,
unsigned int *front=0);
};
// The RtMidiInData structure is used to pass private class data to
@@ -529,7 +559,7 @@ class MidiOutApi : public MidiApi
MidiOutApi( void );
virtual ~MidiOutApi( void );
virtual void sendMessage( std::vector<unsigned char> *message ) = 0;
virtual void sendMessage( const unsigned char *message, size_t size ) = 0;
};
// **************************************************************** //
@@ -539,8 +569,8 @@ class MidiOutApi : public MidiApi
// **************************************************************** //
inline RtMidi::Api RtMidiIn :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
inline void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName ) { rtapi_->openPort( portNumber, portName ); }
inline void RtMidiIn :: openVirtualPort( const std::string portName ) { rtapi_->openVirtualPort( portName ); }
inline void RtMidiIn :: openPort( unsigned int portNumber, const std::string &portName ) { rtapi_->openPort( portNumber, portName ); }
inline void RtMidiIn :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
inline void RtMidiIn :: closePort( void ) { rtapi_->closePort(); }
inline bool RtMidiIn :: isPortOpen() const { return rtapi_->isPortOpen(); }
inline void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData ) { ((MidiInApi *)rtapi_)->setCallback( callback, userData ); }
@@ -552,13 +582,14 @@ inline double RtMidiIn :: getMessage( std::vector<unsigned char> *message ) { re
inline void RtMidiIn :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
inline RtMidi::Api RtMidiOut :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
inline void RtMidiOut :: openPort( unsigned int portNumber, const std::string portName ) { rtapi_->openPort( portNumber, portName ); }
inline void RtMidiOut :: openVirtualPort( const std::string portName ) { rtapi_->openVirtualPort( portName ); }
inline void RtMidiOut :: openPort( unsigned int portNumber, const std::string &portName ) { rtapi_->openPort( portNumber, portName ); }
inline void RtMidiOut :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
inline void RtMidiOut :: closePort( void ) { rtapi_->closePort(); }
inline bool RtMidiOut :: isPortOpen() const { return rtapi_->isPortOpen(); }
inline unsigned int RtMidiOut :: getPortCount( void ) { return rtapi_->getPortCount(); }
inline std::string RtMidiOut :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
inline void RtMidiOut :: sendMessage( std::vector<unsigned char> *message ) { ((MidiOutApi *)rtapi_)->sendMessage( message ); }
inline void RtMidiOut :: sendMessage( const std::vector<unsigned char> *message ) { ((MidiOutApi *)rtapi_)->sendMessage( &message->at(0), message->size() ); }
inline void RtMidiOut :: sendMessage( const unsigned char *message, size_t size ) { ((MidiOutApi *)rtapi_)->sendMessage( message, size ); }
inline void RtMidiOut :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
// **************************************************************** //
@@ -576,11 +607,11 @@ inline void RtMidiOut :: setErrorCallback( RtMidiErrorCallback errorCallback, vo
class MidiInCore: public MidiInApi
{
public:
MidiInCore( const std::string clientName, unsigned int queueSizeLimit );
MidiInCore( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInCore( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
void openPort( unsigned int portNumber, const std::string portName );
void openVirtualPort( const std::string portName );
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
@@ -592,15 +623,15 @@ class MidiInCore: public MidiInApi
class MidiOutCore: public MidiOutApi
{
public:
MidiOutCore( const std::string clientName );
MidiOutCore( const std::string &clientName );
~MidiOutCore( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
void openPort( unsigned int portNumber, const std::string portName );
void openVirtualPort( const std::string portName );
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( std::vector<unsigned char> *message );
void sendMessage( const unsigned char *message, size_t size );
protected:
void initialize( const std::string& clientName );
@@ -613,11 +644,11 @@ class MidiOutCore: public MidiOutApi
class MidiInJack: public MidiInApi
{
public:
MidiInJack( const std::string clientName, unsigned int queueSizeLimit );
MidiInJack( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInJack( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
void openPort( unsigned int portNumber, const std::string portName );
void openVirtualPort( const std::string portName );
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
@@ -632,15 +663,15 @@ class MidiInJack: public MidiInApi
class MidiOutJack: public MidiOutApi
{
public:
MidiOutJack( const std::string clientName );
MidiOutJack( const std::string &clientName );
~MidiOutJack( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
void openPort( unsigned int portNumber, const std::string portName );
void openVirtualPort( const std::string portName );
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( std::vector<unsigned char> *message );
void sendMessage( const unsigned char *message, size_t size );
protected:
std::string clientName;
@@ -656,11 +687,11 @@ class MidiOutJack: public MidiOutApi
class MidiInAlsa: public MidiInApi
{
public:
MidiInAlsa( const std::string clientName, unsigned int queueSizeLimit );
MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInAlsa( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
void openPort( unsigned int portNumber, const std::string portName );
void openVirtualPort( const std::string portName );
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
@@ -672,15 +703,15 @@ class MidiInAlsa: public MidiInApi
class MidiOutAlsa: public MidiOutApi
{
public:
MidiOutAlsa( const std::string clientName );
MidiOutAlsa( const std::string &clientName );
~MidiOutAlsa( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
void openPort( unsigned int portNumber, const std::string portName );
void openVirtualPort( const std::string portName );
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( std::vector<unsigned char> *message );
void sendMessage( const unsigned char *message, size_t size );
protected:
void initialize( const std::string& clientName );
@@ -693,11 +724,11 @@ class MidiOutAlsa: public MidiOutApi
class MidiInWinMM: public MidiInApi
{
public:
MidiInWinMM( const std::string clientName, unsigned int queueSizeLimit );
MidiInWinMM( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInWinMM( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
void openPort( unsigned int portNumber, const std::string portName );
void openVirtualPort( const std::string portName );
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
@@ -709,15 +740,15 @@ class MidiInWinMM: public MidiInApi
class MidiOutWinMM: public MidiOutApi
{
public:
MidiOutWinMM( const std::string clientName );
MidiOutWinMM( const std::string &clientName );
~MidiOutWinMM( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
void openPort( unsigned int portNumber, const std::string portName );
void openVirtualPort( const std::string portName );
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( std::vector<unsigned char> *message );
void sendMessage( const unsigned char *message, size_t size );
protected:
void initialize( const std::string& clientName );
@@ -730,13 +761,13 @@ class MidiOutWinMM: public MidiOutApi
class MidiInDummy: public MidiInApi
{
public:
MidiInDummy( const std::string /*clientName*/, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) { errorString_ = "MidiInDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
MidiInDummy( const std::string &/*clientName*/, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) { errorString_ = "MidiInDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
void openPort( unsigned int /*portNumber*/, const std::string /*portName*/ ) {}
void openVirtualPort( const std::string /*portName*/ ) {}
void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
void openVirtualPort( const std::string &/*portName*/ ) {}
void closePort( void ) {}
unsigned int getPortCount( void ) { return 0; }
std::string getPortName( unsigned int portNumber ) { return ""; }
std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
protected:
void initialize( const std::string& /*clientName*/ ) {}
@@ -745,14 +776,14 @@ class MidiInDummy: public MidiInApi
class MidiOutDummy: public MidiOutApi
{
public:
MidiOutDummy( const std::string /*clientName*/ ) { errorString_ = "MidiOutDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
MidiOutDummy( const std::string &/*clientName*/ ) { errorString_ = "MidiOutDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
void openPort( unsigned int /*portNumber*/, const std::string /*portName*/ ) {}
void openVirtualPort( const std::string /*portName*/ ) {}
void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
void openVirtualPort( const std::string &/*portName*/ ) {}
void closePort( void ) {}
unsigned int getPortCount( void ) { return 0; }
std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
void sendMessage( std::vector<unsigned char> * /*message*/ ) {}
void sendMessage( const unsigned char * /*message*/, size_t /*size*/ ) {}
protected:
void initialize( const std::string& /*clientName*/ ) {}

View File

@@ -1,4 +1,4 @@
/************************************************************************/
/************************************************************************/
/*! \class RtAudio
\brief Realtime audio i/o C++ classes.
@@ -38,13 +38,14 @@
*/
/************************************************************************/
// RtAudio: Version 4.1.2
// RtAudio: Version 5.0.0
#include "RtAudio.h"
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cmath>
#include <algorithm>
// Static variable definitions.
@@ -92,12 +93,12 @@ const unsigned int RtApi::SAMPLE_RATES[] = {
//
// *************************************************** //
std::string RtAudio :: getVersion( void ) throw()
std::string RtAudio :: getVersion( void )
{
return RTAUDIO_VERSION;
}
void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()
void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis )
{
apis.clear();
@@ -209,7 +210,7 @@ RtAudio :: RtAudio( RtAudio::Api api )
throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );
}
RtAudio :: ~RtAudio() throw()
RtAudio :: ~RtAudio()
{
if ( rtapi_ )
delete rtapi_;
@@ -427,6 +428,9 @@ void RtApi :: setStreamTime( double time )
if ( time >= 0.0 )
stream_.streamTime = time;
#if defined( HAVE_GETTIMEOFDAY )
gettimeofday( &stream_.lastTickTimestamp, NULL );
#endif
}
unsigned int RtApi :: getStreamSampleRate( void )
@@ -1943,7 +1947,7 @@ struct JackHandle {
static void jackSilentError( const char * ) {};
RtApiJack :: RtApiJack()
{
:shouldAutoconnect_(true) {
// Nothing to do here.
#if !defined(__RTAUDIO_DEBUG__)
// Turn off Jack's internal error reporting.
@@ -2354,6 +2358,8 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
// here.
if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );
if ( options && options->flags & RTAUDIO_JACK_DONT_CONNECT ) shouldAutoconnect_ = false;
return SUCCESS;
error:
@@ -2443,7 +2449,7 @@ void RtApiJack :: startStream( void )
const char **ports;
// Get the list of available ports.
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
if ( shouldAutoconnect_ && (stream_.mode == OUTPUT || stream_.mode == DUPLEX) ) {
result = 1;
ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
if ( ports == NULL) {
@@ -2467,7 +2473,7 @@ void RtApiJack :: startStream( void )
free(ports);
}
if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
if ( shouldAutoconnect_ && (stream_.mode == INPUT || stream_.mode == DUPLEX) ) {
result = 1;
ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput );
if ( ports == NULL) {
@@ -3859,8 +3865,7 @@ private:
// In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate
// between HW and the user. The convertBufferWasapi function is used to perform this conversion
// between HwIn->UserIn and UserOut->HwOut during the stream callback loop.
// This sample rate converter favors speed over quality, and works best with conversions between
// one rate and its multiple.
// This sample rate converter works best with conversions between one rate and its multiple.
void convertBufferWasapi( char* outBuffer,
const char* inBuffer,
const unsigned int& channelCount,
@@ -3872,40 +3877,129 @@ void convertBufferWasapi( char* outBuffer,
{
// calculate the new outSampleCount and relative sampleStep
float sampleRatio = ( float ) outSampleRate / inSampleRate;
float sampleRatioInv = ( float ) 1 / sampleRatio;
float sampleStep = 1.0f / sampleRatio;
float inSampleFraction = 0.0f;
outSampleCount = ( unsigned int ) roundf( inSampleCount * sampleRatio );
outSampleCount = ( unsigned int ) std::roundf( inSampleCount * sampleRatio );
// frame-by-frame, copy each relative input sample into it's corresponding output sample
for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
// if inSampleRate is a multiple of outSampleRate (or vice versa) there's no need to interpolate
if ( floor( sampleRatio ) == sampleRatio || floor( sampleRatioInv ) == sampleRatioInv )
{
unsigned int inSample = ( unsigned int ) inSampleFraction;
switch ( format )
// frame-by-frame, copy each relative input sample into it's corresponding output sample
for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
{
case RTAUDIO_SINT8:
memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );
break;
case RTAUDIO_SINT16:
memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );
break;
case RTAUDIO_SINT24:
memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );
break;
case RTAUDIO_SINT32:
memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );
break;
case RTAUDIO_FLOAT32:
memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );
break;
case RTAUDIO_FLOAT64:
memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );
break;
}
unsigned int inSample = ( unsigned int ) inSampleFraction;
// jump to next in sample
inSampleFraction += sampleStep;
switch ( format )
{
case RTAUDIO_SINT8:
memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );
break;
case RTAUDIO_SINT16:
memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );
break;
case RTAUDIO_SINT24:
memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );
break;
case RTAUDIO_SINT32:
memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );
break;
case RTAUDIO_FLOAT32:
memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );
break;
case RTAUDIO_FLOAT64:
memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );
break;
}
// jump to next in sample
inSampleFraction += sampleStep;
}
}
else // else interpolate
{
// frame-by-frame, copy each relative input sample into it's corresponding output sample
for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
{
unsigned int inSample = ( unsigned int ) inSampleFraction;
float inSampleDec = inSampleFraction - inSample;
unsigned int frameInSample = inSample * channelCount;
unsigned int frameOutSample = outSample * channelCount;
switch ( format )
{
case RTAUDIO_SINT8:
{
for ( unsigned int channel = 0; channel < channelCount; channel++ )
{
char fromSample = ( ( char* ) inBuffer )[ frameInSample + channel ];
char toSample = ( ( char* ) inBuffer )[ frameInSample + channelCount + channel ];
char sampleDiff = ( char ) ( ( toSample - fromSample ) * inSampleDec );
( ( char* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
}
break;
}
case RTAUDIO_SINT16:
{
for ( unsigned int channel = 0; channel < channelCount; channel++ )
{
short fromSample = ( ( short* ) inBuffer )[ frameInSample + channel ];
short toSample = ( ( short* ) inBuffer )[ frameInSample + channelCount + channel ];
short sampleDiff = ( short ) ( ( toSample - fromSample ) * inSampleDec );
( ( short* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
}
break;
}
case RTAUDIO_SINT24:
{
for ( unsigned int channel = 0; channel < channelCount; channel++ )
{
int fromSample = ( ( S24* ) inBuffer )[ frameInSample + channel ].asInt();
int toSample = ( ( S24* ) inBuffer )[ frameInSample + channelCount + channel ].asInt();
int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec );
( ( S24* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
}
break;
}
case RTAUDIO_SINT32:
{
for ( unsigned int channel = 0; channel < channelCount; channel++ )
{
int fromSample = ( ( int* ) inBuffer )[ frameInSample + channel ];
int toSample = ( ( int* ) inBuffer )[ frameInSample + channelCount + channel ];
int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec );
( ( int* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
}
break;
}
case RTAUDIO_FLOAT32:
{
for ( unsigned int channel = 0; channel < channelCount; channel++ )
{
float fromSample = ( ( float* ) inBuffer )[ frameInSample + channel ];
float toSample = ( ( float* ) inBuffer )[ frameInSample + channelCount + channel ];
float sampleDiff = ( toSample - fromSample ) * inSampleDec;
( ( float* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
}
break;
}
case RTAUDIO_FLOAT64:
{
for ( unsigned int channel = 0; channel < channelCount; channel++ )
{
double fromSample = ( ( double* ) inBuffer )[ frameInSample + channel ];
double toSample = ( ( double* ) inBuffer )[ frameInSample + channelCount + channel ];
double sampleDiff = ( toSample - fromSample ) * inSampleDec;
( ( double* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
}
break;
}
}
// jump to next in sample
inSampleFraction += sampleStep;
}
}
}
@@ -5195,6 +5289,8 @@ Exit:
// Various revisions for RtAudio 4.0 by Gary Scavone, April 2007
// Changed device query structure for RtAudio 4.0.7, January 2010
#include <mmsystem.h>
#include <mmreg.h>
#include <dsound.h>
#include <assert.h>
#include <algorithm>
@@ -5275,8 +5371,8 @@ RtApiDs :: RtApiDs()
RtApiDs :: ~RtApiDs()
{
if ( coInitialized_ ) CoUninitialize(); // balanced call.
if ( stream_.state != STREAM_CLOSED ) closeStream();
if ( coInitialized_ ) CoUninitialize(); // balanced call.
}
// The DirectSound default output is always the first device.
@@ -8695,8 +8791,10 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
info.nativeFormats |= RTAUDIO_SINT8;
if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE )
info.nativeFormats |= RTAUDIO_SINT32;
#ifdef AFMT_FLOAT
if ( mask & AFMT_FLOAT )
info.nativeFormats |= RTAUDIO_FLOAT32;
#endif
if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE )
info.nativeFormats |= RTAUDIO_SINT24;
@@ -9023,7 +9121,7 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
}
// Verify the sample rate setup worked.
if ( abs( srate - sampleRate ) > 100 ) {
if ( abs( srate - (int)sampleRate ) > 100 ) {
close( fd );
errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ").";
errorText_ = errorStream_.str();

View File

@@ -46,6 +46,10 @@
#endif
#endif
// Default for Windows is to add an identifier to the port names; this
// flag can be undefined to disable this behaviour.
#define RTMIDI_ENSURE_UNIQUE_PORTNAMES
//*********************************************************************//
// RtMidi Definitions
//*********************************************************************//
@@ -57,8 +61,7 @@ RtMidi :: RtMidi()
RtMidi :: ~RtMidi()
{
if ( rtapi_ )
delete rtapi_;
delete rtapi_;
rtapi_ = 0;
}
@@ -94,10 +97,9 @@ void RtMidi :: getCompiledApi( std::vector<RtMidi::Api> &apis ) throw()
// RtMidiIn Definitions
//*********************************************************************//
void RtMidiIn :: openMidiApi( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit )
void RtMidiIn :: openMidiApi( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit )
{
if ( rtapi_ )
delete rtapi_;
delete rtapi_;
rtapi_ = 0;
#if defined(__UNIX_JACK__)
@@ -122,7 +124,7 @@ void RtMidiIn :: openMidiApi( RtMidi::Api api, const std::string clientName, uns
#endif
}
RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit )
RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit )
: RtMidi()
{
if ( api != UNSPECIFIED ) {
@@ -141,7 +143,7 @@ RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string clientName, unsigned in
getCompiledApi( apis );
for ( unsigned int i=0; i<apis.size(); i++ ) {
openMidiApi( apis[i], clientName, queueSizeLimit );
if ( rtapi_->getPortCount() ) break;
if ( rtapi_ && rtapi_->getPortCount() ) break;
}
if ( rtapi_ ) return;
@@ -163,10 +165,9 @@ RtMidiIn :: ~RtMidiIn() throw()
// RtMidiOut Definitions
//*********************************************************************//
void RtMidiOut :: openMidiApi( RtMidi::Api api, const std::string clientName )
void RtMidiOut :: openMidiApi( RtMidi::Api api, const std::string &clientName )
{
if ( rtapi_ )
delete rtapi_;
delete rtapi_;
rtapi_ = 0;
#if defined(__UNIX_JACK__)
@@ -191,7 +192,7 @@ void RtMidiOut :: openMidiApi( RtMidi::Api api, const std::string clientName )
#endif
}
RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string clientName )
RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string &clientName)
{
if ( api != UNSPECIFIED ) {
// Attempt to open the specified API.
@@ -209,7 +210,7 @@ RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string clientName )
getCompiledApi( apis );
for ( unsigned int i=0; i<apis.size(); i++ ) {
openMidiApi( apis[i], clientName );
if ( rtapi_->getPortCount() ) break;
if ( rtapi_ && rtapi_->getPortCount() ) break;
}
if ( rtapi_ ) return;
@@ -231,7 +232,7 @@ RtMidiOut :: ~RtMidiOut() throw()
//*********************************************************************//
MidiApi :: MidiApi( void )
: apiData_( 0 ), connected_( false ), errorCallback_(0), errorCallbackUserData_(0)
: apiData_( 0 ), connected_( false ), errorCallback_(0), firstErrorOccurred_(false), errorCallbackUserData_(0)
{
}
@@ -343,18 +344,68 @@ double MidiInApi :: getMessage( std::vector<unsigned char> *message )
return 0.0;
}
if ( inputData_.queue.size == 0 ) return 0.0;
double timeStamp;
if (!inputData_.queue.pop(message, &timeStamp))
return 0.0;
return timeStamp;
}
unsigned int MidiInApi::MidiQueue::size(unsigned int *__back,
unsigned int *__front)
{
// Access back/front members exactly once and make stack copies for
// size calculation
unsigned int _back = back, _front = front, _size;
if (_back >= _front)
_size = _back - _front;
else
_size = ringSize - _front + _back;
// Return copies of back/front so no new and unsynchronized accesses
// to member variables are needed.
if (__back) *__back = _back;
if (__front) *__front = _front;
return _size;
}
// As long as we haven't reached our queue size limit, push the message.
bool MidiInApi::MidiQueue::push(const MidiInApi::MidiMessage& msg)
{
// Local stack copies of front/back
unsigned int _back, _front, _size;
// Get back/front indexes exactly once and calculate current size
_size = size(&_back, &_front);
if ( _size < ringSize-1 )
{
ring[_back] = msg;
back = (back+1)%ringSize;
return true;
}
return false;
}
bool MidiInApi::MidiQueue::pop(std::vector<unsigned char> *msg, double* timeStamp)
{
// Local stack copies of front/back
unsigned int _back, _front, _size;
// Get back/front indexes exactly once and calculate current size
_size = size(&_back, &_front);
if (_size == 0)
return false;
// Copy queued message to the vector pointer argument and then "pop" it.
std::vector<unsigned char> *bytes = &(inputData_.queue.ring[inputData_.queue.front].bytes);
message->assign( bytes->begin(), bytes->end() );
double deltaTime = inputData_.queue.ring[inputData_.queue.front].timeStamp;
inputData_.queue.size--;
inputData_.queue.front++;
if ( inputData_.queue.front == inputData_.queue.ringSize )
inputData_.queue.front = 0;
msg->assign( ring[_front].bytes.begin(), ring[_front].bytes.end() );
*timeStamp = ring[_front].timeStamp;
return deltaTime;
// Update front
front = (front+1)%ringSize;
return true;
}
//*********************************************************************//
@@ -470,13 +521,7 @@ static void midiInputCallback( const MIDIPacketList *list, void *procRef, void *
}
else {
// As long as we haven't reached our queue size limit, push the message.
if ( data->queue.size < data->queue.ringSize ) {
data->queue.ring[data->queue.back++] = message;
if ( data->queue.back == data->queue.ringSize )
data->queue.back = 0;
data->queue.size++;
}
else
if (!data->queue.push(message))
std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
}
message.bytes.clear();
@@ -534,13 +579,7 @@ static void midiInputCallback( const MIDIPacketList *list, void *procRef, void *
}
else {
// As long as we haven't reached our queue size limit, push the message.
if ( data->queue.size < data->queue.ringSize ) {
data->queue.ring[data->queue.back++] = message;
if ( data->queue.back == data->queue.ringSize )
data->queue.back = 0;
data->queue.size++;
}
else
if (!data->queue.push(message))
std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
}
message.bytes.clear();
@@ -553,7 +592,7 @@ static void midiInputCallback( const MIDIPacketList *list, void *procRef, void *
}
}
MidiInCore :: MidiInCore( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
MidiInCore :: MidiInCore( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
{
initialize( clientName );
}
@@ -577,7 +616,9 @@ void MidiInCore :: initialize( const std::string& clientName )
CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
if ( result != noErr ) {
errorString_ = "MidiInCore::initialize: error creating OS-X MIDI client object.";
std::ostringstream ost;
ost << "MidiInCore::initialize: error creating OS-X MIDI client object (" << result << ").";
errorString_ = ost.str();
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
@@ -591,7 +632,7 @@ void MidiInCore :: initialize( const std::string& clientName )
CFRelease(name);
}
void MidiInCore :: openPort( unsigned int portNumber, const std::string portName )
void MidiInCore :: openPort( unsigned int portNumber, const std::string &portName )
{
if ( connected_ ) {
errorString_ = "MidiInCore::openPort: a valid connection already exists!";
@@ -653,7 +694,7 @@ void MidiInCore :: openPort( unsigned int portNumber, const std::string portName
connected_ = true;
}
void MidiInCore :: openVirtualPort( const std::string portName )
void MidiInCore :: openVirtualPort( const std::string &portName )
{
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
@@ -678,10 +719,12 @@ void MidiInCore :: closePort( void )
if ( data->endpoint ) {
MIDIEndpointDispose( data->endpoint );
data->endpoint = 0;
}
if ( data->port ) {
MIDIPortDispose( data->port );
data->port = 0;
}
connected_ = false;
@@ -837,7 +880,7 @@ std::string MidiInCore :: getPortName( unsigned int portNumber )
portRef = MIDIGetSource( portNumber );
nameRef = ConnectedEndpointName(portRef);
CFStringGetCString( nameRef, name, sizeof(name), CFStringGetSystemEncoding());
CFStringGetCString( nameRef, name, sizeof(name), kCFStringEncodingUTF8);
CFRelease( nameRef );
return stringName = name;
@@ -848,7 +891,7 @@ std::string MidiInCore :: getPortName( unsigned int portNumber )
// Class Definitions: MidiOutCore
//*********************************************************************//
MidiOutCore :: MidiOutCore( const std::string clientName ) : MidiOutApi()
MidiOutCore :: MidiOutCore( const std::string &clientName ) : MidiOutApi()
{
initialize( clientName );
}
@@ -872,7 +915,9 @@ void MidiOutCore :: initialize( const std::string& clientName )
CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
if ( result != noErr ) {
errorString_ = "MidiOutCore::initialize: error creating OS-X MIDI client object.";
std::ostringstream ost;
ost << "MidiInCore::initialize: error creating OS-X MIDI client object (" << result << ").";
errorString_ = ost.str();
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
}
@@ -909,13 +954,13 @@ std::string MidiOutCore :: getPortName( unsigned int portNumber )
portRef = MIDIGetDestination( portNumber );
nameRef = ConnectedEndpointName(portRef);
CFStringGetCString( nameRef, name, sizeof(name), CFStringGetSystemEncoding());
CFStringGetCString( nameRef, name, sizeof(name), kCFStringEncodingUTF8 );
CFRelease( nameRef );
return stringName = name;
}
void MidiOutCore :: openPort( unsigned int portNumber, const std::string portName )
void MidiOutCore :: openPort( unsigned int portNumber, const std::string &portName )
{
if ( connected_ ) {
errorString_ = "MidiOutCore::openPort: a valid connection already exists!";
@@ -941,9 +986,11 @@ void MidiOutCore :: openPort( unsigned int portNumber, const std::string portNam
MIDIPortRef port;
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
OSStatus result = MIDIOutputPortCreate( data->client,
CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
portNameRef,
&port );
CFRelease( portNameRef );
if ( result != noErr ) {
MIDIClientDispose( data->client );
errorString_ = "MidiOutCore::openPort: error creating OS-X MIDI output port.";
@@ -973,16 +1020,18 @@ void MidiOutCore :: closePort( void )
if ( data->endpoint ) {
MIDIEndpointDispose( data->endpoint );
data->endpoint = 0;
}
if ( data->port ) {
MIDIPortDispose( data->port );
data->port = 0;
}
connected_ = false;
}
void MidiOutCore :: openVirtualPort( std::string portName )
void MidiOutCore :: openVirtualPort( const std::string &portName )
{
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
@@ -1007,11 +1056,11 @@ void MidiOutCore :: openVirtualPort( std::string portName )
data->endpoint = endpoint;
}
void MidiOutCore :: sendMessage( std::vector<unsigned char> *message )
void MidiOutCore :: sendMessage( const unsigned char *message, size_t size )
{
// We use the MIDISendSysex() function to asynchronously send sysex
// messages. Otherwise, we use a single CoreMIDI MIDIPacket.
unsigned int nBytes = message->size();
// messages. Otherwise, we use a single CoreMidi MIDIPacket.
unsigned int nBytes = static_cast<unsigned int> (size);
if ( nBytes == 0 ) {
errorString_ = "MidiOutCore::sendMessage: no data in message argument!";
error( RtMidiError::WARNING, errorString_ );
@@ -1022,7 +1071,7 @@ void MidiOutCore :: sendMessage( std::vector<unsigned char> *message )
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
OSStatus result;
if ( message->at(0) != 0xF0 && nBytes > 3 ) {
if ( message[0] != 0xF0 && nBytes > 3 ) {
errorString_ = "MidiOutCore::sendMessage: message format problem ... not sysex but > 3 bytes?";
error( RtMidiError::WARNING, errorString_ );
return;
@@ -1036,7 +1085,7 @@ void MidiOutCore :: sendMessage( std::vector<unsigned char> *message )
ByteCount remainingBytes = nBytes;
while (remainingBytes && packet) {
ByteCount bytesForPacket = remainingBytes > 65535 ? 65535 : remainingBytes; // 65535 = maximum size of a MIDIPacket
const Byte* dataStartPtr = (const Byte *) &message->at( nBytes - remainingBytes );
const Byte* dataStartPtr = (const Byte *) &message[nBytes - remainingBytes];
packet = MIDIPacketListAdd( packetList, listSize, packet, timeStamp, bytesForPacket, dataStartPtr);
remainingBytes -= bytesForPacket;
}
@@ -1106,7 +1155,7 @@ struct AlsaMidiData {
unsigned char *buffer;
pthread_t thread;
pthread_t dummy_thread_id;
unsigned long long lastTime;
snd_seq_real_time_t lastTime;
int queue_id; // an input queue is needed to get timestamped events
int trigger_fds[2];
};
@@ -1124,7 +1173,7 @@ static void *alsaMidiHandler( void *ptr )
AlsaMidiData *apiData = static_cast<AlsaMidiData *> (data->apiData);
long nBytes;
unsigned long long time, lastTime;
double time;
bool continueSysex = false;
bool doDecode = false;
MidiInApi::MidiMessage message;
@@ -1266,14 +1315,33 @@ static void *alsaMidiHandler( void *ptr )
// Method 2: Use the ALSA sequencer event time data.
// (thanks to Pedro Lopez-Cabanillas!).
time = ( ev->time.time.tv_sec * 1000000 ) + ( ev->time.time.tv_nsec/1000 );
lastTime = time;
time -= apiData->lastTime;
apiData->lastTime = lastTime;
// Using method from:
// https://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
// Perform the carry for the later subtraction by updating y.
snd_seq_real_time_t &x(ev->time.time);
snd_seq_real_time_t &y(apiData->lastTime);
if (x.tv_nsec < y.tv_nsec) {
int nsec = (y.tv_nsec - x.tv_nsec) / 1000000000 + 1;
y.tv_nsec -= 1000000000 * nsec;
y.tv_sec += nsec;
}
if (x.tv_nsec - y.tv_nsec > 1000000000) {
int nsec = (x.tv_nsec - y.tv_nsec) / 1000000000;
y.tv_nsec += 1000000000 * nsec;
y.tv_sec -= nsec;
}
// Compute the time difference.
time = x.tv_sec - y.tv_sec + (x.tv_nsec - y.tv_nsec)*1e-9;
apiData->lastTime = ev->time.time;
if ( data->firstMessage == true )
data->firstMessage = false;
else
message.timeStamp = time * 0.000001;
message.timeStamp = time;
}
else {
#if defined(__RTMIDI_DEBUG__)
@@ -1292,13 +1360,7 @@ static void *alsaMidiHandler( void *ptr )
}
else {
// As long as we haven't reached our queue size limit, push the message.
if ( data->queue.size < data->queue.ringSize ) {
data->queue.ring[data->queue.back++] = message;
if ( data->queue.back == data->queue.ringSize )
data->queue.back = 0;
data->queue.size++;
}
else
if (!data->queue.push(message))
std::cerr << "\nMidiInAlsa: message queue limit reached!!\n\n";
}
}
@@ -1310,7 +1372,7 @@ static void *alsaMidiHandler( void *ptr )
return 0;
}
MidiInAlsa :: MidiInAlsa( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
MidiInAlsa :: MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
{
initialize( clientName );
}
@@ -1405,7 +1467,9 @@ unsigned int portInfo( snd_seq_t *seq, snd_seq_port_info_t *pinfo, unsigned int
while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) {
unsigned int atyp = snd_seq_port_info_get_type( pinfo );
if ( ( ( atyp & SND_SEQ_PORT_TYPE_MIDI_GENERIC ) == 0 ) &&
( ( atyp & SND_SEQ_PORT_TYPE_SYNTH ) == 0 ) ) continue;
( ( atyp & SND_SEQ_PORT_TYPE_SYNTH ) == 0 ) &&
( ( atyp & SND_SEQ_PORT_TYPE_APPLICATION ) == 0 ) ) continue;
unsigned int caps = snd_seq_port_info_get_capability( pinfo );
if ( ( caps & type ) != type ) continue;
if ( count == portNumber ) return 1;
@@ -1441,6 +1505,8 @@ std::string MidiInAlsa :: getPortName( unsigned int portNumber )
snd_seq_get_any_client_info( data->seq, cnum, cinfo );
std::ostringstream os;
os << snd_seq_client_info_get_name( cinfo );
os << ":";
os << snd_seq_port_info_get_name( pinfo );
os << " "; // These lines added to make sure devices are listed
os << snd_seq_port_info_get_client( pinfo ); // with full portnames added to ensure individual device names
os << ":";
@@ -1455,7 +1521,7 @@ std::string MidiInAlsa :: getPortName( unsigned int portNumber )
return stringName;
}
void MidiInAlsa :: openPort( unsigned int portNumber, const std::string portName )
void MidiInAlsa :: openPort( unsigned int portNumber, const std::string &portName )
{
if ( connected_ ) {
errorString_ = "MidiInAlsa::openPort: a valid connection already exists!";
@@ -1563,7 +1629,7 @@ void MidiInAlsa :: openPort( unsigned int portNumber, const std::string portName
connected_ = true;
}
void MidiInAlsa :: openVirtualPort( std::string portName )
void MidiInAlsa :: openVirtualPort( const std::string &portName )
{
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
if ( data->vport < 0 ) {
@@ -1658,7 +1724,7 @@ void MidiInAlsa :: closePort( void )
// Class Definitions: MidiOutAlsa
//*********************************************************************//
MidiOutAlsa :: MidiOutAlsa( const std::string clientName ) : MidiOutApi()
MidiOutAlsa :: MidiOutAlsa( const std::string &clientName ) : MidiOutApi()
{
initialize( clientName );
}
@@ -1740,6 +1806,8 @@ std::string MidiOutAlsa :: getPortName( unsigned int portNumber )
snd_seq_get_any_client_info( data->seq, cnum, cinfo );
std::ostringstream os;
os << snd_seq_client_info_get_name(cinfo);
os << ":";
os << snd_seq_port_info_get_name( pinfo );
os << " "; // These lines added to make sure devices are listed
os << snd_seq_port_info_get_client( pinfo ); // with full portnames added to ensure individual device names
os << ":";
@@ -1754,7 +1822,7 @@ std::string MidiOutAlsa :: getPortName( unsigned int portNumber )
return stringName;
}
void MidiOutAlsa :: openPort( unsigned int portNumber, const std::string portName )
void MidiOutAlsa :: openPort( unsigned int portNumber, const std::string &portName )
{
if ( connected_ ) {
errorString_ = "MidiOutAlsa::openPort: a valid connection already exists!";
@@ -1825,11 +1893,12 @@ void MidiOutAlsa :: closePort( void )
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
snd_seq_unsubscribe_port( data->seq, data->subscription );
snd_seq_port_subscribe_free( data->subscription );
data->subscription = 0;
connected_ = false;
}
}
void MidiOutAlsa :: openVirtualPort( std::string portName )
void MidiOutAlsa :: openVirtualPort( const std::string &portName )
{
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
if ( data->vport < 0 ) {
@@ -1844,11 +1913,11 @@ void MidiOutAlsa :: openVirtualPort( std::string portName )
}
}
void MidiOutAlsa :: sendMessage( std::vector<unsigned char> *message )
void MidiOutAlsa :: sendMessage( const unsigned char *message, size_t size )
{
int result;
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
unsigned int nBytes = message->size();
unsigned int nBytes = static_cast<unsigned int> (size);
if ( nBytes > data->bufferSize ) {
data->bufferSize = nBytes;
result = snd_midi_event_resize_buffer ( data->coder, nBytes);
@@ -1871,7 +1940,7 @@ void MidiOutAlsa :: sendMessage( std::vector<unsigned char> *message )
snd_seq_ev_set_source(&ev, data->vport);
snd_seq_ev_set_subs(&ev);
snd_seq_ev_set_direct(&ev);
for ( unsigned int i=0; i<nBytes; ++i ) data->buffer[i] = message->at(i);
for ( unsigned int i=0; i<nBytes; ++i ) data->buffer[i] = message[i];
result = snd_midi_event_encode( data->coder, data->buffer, (long)nBytes, &ev );
if ( result < (int)nBytes ) {
errorString_ = "MidiOutAlsa::sendMessage: event parsing error!";
@@ -1911,6 +1980,34 @@ void MidiOutAlsa :: sendMessage( std::vector<unsigned char> *message )
#include <windows.h>
#include <mmsystem.h>
// Convert a null-terminated wide string or ANSI-encoded string to UTF-8.
static std::string ConvertToUTF8(const TCHAR *str)
{
std::string u8str;
const WCHAR *wstr = L"";
#if defined( UNICODE ) || defined( _UNICODE )
wstr = str;
#else
// Convert from ANSI encoding to wide string
int wlength = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
std::wstring wstrtemp;
if ( wlength )
{
wstrtemp.assign( wlength - 1, 0 );
MultiByteToWideChar( CP_ACP, 0, str, -1, &wstrtemp[0], wlength );
wstr = &wstrtemp[0];
}
#endif
// Convert from wide string to UTF-8
int length = WideCharToMultiByte( CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL );
if ( length )
{
u8str.assign( length - 1, 0 );
length = WideCharToMultiByte( CP_UTF8, 0, wstr, -1, &u8str[0], length, NULL, NULL );
}
return u8str;
}
#define RT_SYSEX_BUFFER_SIZE 1024
#define RT_SYSEX_BUFFER_COUNT 4
@@ -2015,21 +2112,15 @@ static void CALLBACK midiInputCallback( HMIDIIN /*hmin*/,
}
else {
// As long as we haven't reached our queue size limit, push the message.
if ( data->queue.size < data->queue.ringSize ) {
data->queue.ring[data->queue.back++] = apiData->message;
if ( data->queue.back == data->queue.ringSize )
data->queue.back = 0;
data->queue.size++;
}
else
std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
if (!data->queue.push(apiData->message))
std::cerr << "\nMidiInWinMM: message queue limit reached!!\n\n";
}
// Clear the vector for the next input message.
apiData->message.bytes.clear();
}
MidiInWinMM :: MidiInWinMM( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
MidiInWinMM :: MidiInWinMM( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
{
initialize( clientName );
}
@@ -2068,7 +2159,7 @@ void MidiInWinMM :: initialize( const std::string& /*clientName*/ )
}
}
void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ )
void MidiInWinMM :: openPort( unsigned int portNumber, const std::string &/*portName*/ )
{
if ( connected_ ) {
errorString_ = "MidiInWinMM::openPort: a valid connection already exists!";
@@ -2114,6 +2205,7 @@ void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portN
result = midiInPrepareHeader( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
if ( result != MMSYSERR_NOERROR ) {
midiInClose( data->inHandle );
data->inHandle = 0;
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (PrepareHeader).";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
@@ -2123,6 +2215,7 @@ void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portN
result = midiInAddBuffer( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
if ( result != MMSYSERR_NOERROR ) {
midiInClose( data->inHandle );
data->inHandle = 0;
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (AddBuffer).";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
@@ -2132,6 +2225,7 @@ void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portN
result = midiInStart( data->inHandle );
if ( result != MMSYSERR_NOERROR ) {
midiInClose( data->inHandle );
data->inHandle = 0;
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port.";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
@@ -2140,7 +2234,7 @@ void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portN
connected_ = true;
}
void MidiInWinMM :: openVirtualPort( std::string /*portName*/ )
void MidiInWinMM :: openVirtualPort( const std::string &/*portName*/ )
{
// This function cannot be implemented for the Windows MM MIDI API.
errorString_ = "MidiInWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
@@ -2161,6 +2255,7 @@ void MidiInWinMM :: closePort( void )
delete [] data->sysexBuffer[i];
if ( result != MMSYSERR_NOERROR ) {
midiInClose( data->inHandle );
data->inHandle = 0;
errorString_ = "MidiInWinMM::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader).";
error( RtMidiError::DRIVER_ERROR, errorString_ );
return;
@@ -2168,6 +2263,7 @@ void MidiInWinMM :: closePort( void )
}
midiInClose( data->inHandle );
data->inHandle = 0;
connected_ = false;
LeaveCriticalSection( &(data->_mutex) );
}
@@ -2192,22 +2288,17 @@ std::string MidiInWinMM :: getPortName( unsigned int portNumber )
MIDIINCAPS deviceCaps;
midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
#if defined( UNICODE ) || defined( _UNICODE )
int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL) - 1;
stringName.assign( length, 0 );
length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, static_cast<int>(wcslen(deviceCaps.szPname)), &stringName[0], length, NULL, NULL);
#else
stringName = std::string( deviceCaps.szPname );
#endif
stringName = ConvertToUTF8( deviceCaps.szPname );
// Next lines added to add the portNumber to the name so that
// the device's names are sure to be listed with individual names
// even when they have the same brand name
#ifdef RTMIDI_ENSURE_UNIQUE_PORTNAMES
std::ostringstream os;
os << " ";
os << portNumber;
stringName += os.str();
#endif
return stringName;
}
@@ -2217,7 +2308,7 @@ std::string MidiInWinMM :: getPortName( unsigned int portNumber )
// Class Definitions: MidiOutWinMM
//*********************************************************************//
MidiOutWinMM :: MidiOutWinMM( const std::string clientName ) : MidiOutApi()
MidiOutWinMM :: MidiOutWinMM( const std::string &clientName ) : MidiOutApi()
{
initialize( clientName );
}
@@ -2266,27 +2357,22 @@ std::string MidiOutWinMM :: getPortName( unsigned int portNumber )
MIDIOUTCAPS deviceCaps;
midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
#if defined( UNICODE ) || defined( _UNICODE )
int length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, -1, NULL, 0, NULL, NULL) - 1;
stringName.assign( length, 0 );
length = WideCharToMultiByte(CP_UTF8, 0, deviceCaps.szPname, static_cast<int>(wcslen(deviceCaps.szPname)), &stringName[0], length, NULL, NULL);
#else
stringName = std::string( deviceCaps.szPname );
#endif
stringName = ConvertToUTF8( deviceCaps.szPname );
// Next lines added to add the portNumber to the name so that
// the device's names are sure to be listed with individual names
// even when they have the same brand name
std::ostringstream os;
#ifdef RTMIDI_ENSURE_UNIQUE_PORTNAMES
os << " ";
os << portNumber;
stringName += os.str();
#endif
return stringName;
}
void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ )
void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string &/*portName*/ )
{
if ( connected_ ) {
errorString_ = "MidiOutWinMM::openPort: a valid connection already exists!";
@@ -2330,22 +2416,23 @@ void MidiOutWinMM :: closePort( void )
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
midiOutReset( data->outHandle );
midiOutClose( data->outHandle );
data->outHandle = 0;
connected_ = false;
}
}
void MidiOutWinMM :: openVirtualPort( std::string /*portName*/ )
void MidiOutWinMM :: openVirtualPort( const std::string &/*portName*/ )
{
// This function cannot be implemented for the Windows MM MIDI API.
errorString_ = "MidiOutWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
void MidiOutWinMM :: sendMessage( const unsigned char *message, size_t size )
{
if ( !connected_ ) return;
unsigned int nBytes = static_cast<unsigned int>(message->size());
unsigned int nBytes = static_cast<unsigned int>(size);
if ( nBytes == 0 ) {
errorString_ = "MidiOutWinMM::sendMessage: message argument is empty!";
error( RtMidiError::WARNING, errorString_ );
@@ -2354,7 +2441,7 @@ void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
MMRESULT result;
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
if ( message->at(0) == 0xF0 ) { // Sysex message
if ( message[0] == 0xF0 ) { // Sysex message
// Allocate buffer for sysex data.
char *buffer = (char *) malloc( nBytes );
@@ -2365,7 +2452,7 @@ void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
}
// Copy data to buffer.
for ( unsigned int i=0; i<nBytes; ++i ) buffer[i] = message->at(i);
for ( unsigned int i=0; i<nBytes; ++i ) buffer[i] = message[i];
// Create and prepare MIDIHDR structure.
MIDIHDR sysex;
@@ -2406,7 +2493,7 @@ void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
DWORD packet;
unsigned char *ptr = (unsigned char *) &packet;
for ( unsigned int i=0; i<nBytes; ++i ) {
*ptr = message->at(i);
*ptr = message[i];
++ptr;
}
@@ -2436,6 +2523,9 @@ void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
#include <jack/jack.h>
#include <jack/midiport.h>
#include <jack/ringbuffer.h>
#ifdef HAVE_SEMAPHORE
#include <semaphore.h>
#endif
#define JACK_RINGBUFFER_SIZE 16384 // Default size for ringbuffer
@@ -2445,6 +2535,10 @@ struct JackMidiData {
jack_ringbuffer_t *buffSize;
jack_ringbuffer_t *buffMessage;
jack_time_t lastTime;
#ifdef HAVE_SEMAPHORE
sem_t sem_cleanup;
sem_t sem_needpost;
#endif
MidiInApi :: RtMidiInData *rtMidiIn;
};
@@ -2491,13 +2585,7 @@ static int jackProcessIn( jack_nframes_t nframes, void *arg )
}
else {
// As long as we haven't reached our queue size limit, push the message.
if ( rtData->queue.size < rtData->queue.ringSize ) {
rtData->queue.ring[rtData->queue.back++] = message;
if ( rtData->queue.back == rtData->queue.ringSize )
rtData->queue.back = 0;
rtData->queue.size++;
}
else
if (!rtData->queue.push(message))
std::cerr << "\nMidiInJack: message queue limit reached!!\n\n";
}
}
@@ -2506,7 +2594,7 @@ static int jackProcessIn( jack_nframes_t nframes, void *arg )
return 0;
}
MidiInJack :: MidiInJack( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
MidiInJack :: MidiInJack( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
{
initialize( clientName );
}
@@ -2551,7 +2639,7 @@ MidiInJack :: ~MidiInJack()
delete data;
}
void MidiInJack :: openPort( unsigned int portNumber, const std::string portName )
void MidiInJack :: openPort( unsigned int portNumber, const std::string &portName )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
@@ -2573,7 +2661,7 @@ void MidiInJack :: openPort( unsigned int portNumber, const std::string portName
jack_connect( data->client, name.c_str(), jack_port_name( data->port ) );
}
void MidiInJack :: openVirtualPort( const std::string portName )
void MidiInJack :: openVirtualPort( const std::string &portName )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
@@ -2672,10 +2760,15 @@ static int jackProcessOut( jack_nframes_t nframes, void *arg )
jack_ringbuffer_read( data->buffMessage, (char *) midiData, (size_t) space );
}
#ifdef HAVE_SEMAPHORE
if (!sem_trywait(&data->sem_needpost))
sem_post(&data->sem_cleanup);
#endif
return 0;
}
MidiOutJack :: MidiOutJack( const std::string clientName ) : MidiOutApi()
MidiOutJack :: MidiOutJack( const std::string &clientName ) : MidiOutApi()
{
initialize( clientName );
}
@@ -2687,6 +2780,10 @@ void MidiOutJack :: initialize( const std::string& clientName )
data->port = NULL;
data->client = NULL;
#ifdef HAVE_SEMAPHORE
sem_init(&data->sem_cleanup, 0, 0);
sem_init(&data->sem_needpost, 0, 0);
#endif
this->clientName = clientName;
connect();
@@ -2725,10 +2822,15 @@ MidiOutJack :: ~MidiOutJack()
jack_client_close( data->client );
}
#ifdef HAVE_SEMAPHORE
sem_destroy(&data->sem_cleanup);
sem_destroy(&data->sem_needpost);
#endif
delete data;
}
void MidiOutJack :: openPort( unsigned int portNumber, const std::string portName )
void MidiOutJack :: openPort( unsigned int portNumber, const std::string &portName )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
@@ -2750,7 +2852,7 @@ void MidiOutJack :: openPort( unsigned int portNumber, const std::string portNam
jack_connect( data->client, jack_port_name( data->port ), name.c_str() );
}
void MidiOutJack :: openVirtualPort( const std::string portName )
void MidiOutJack :: openVirtualPort( const std::string &portName )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
@@ -2821,18 +2923,29 @@ void MidiOutJack :: closePort()
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
if ( data->port == NULL ) return;
#ifdef HAVE_SEMAPHORE
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != -1)
{
ts.tv_sec += 1; // wait max one second
sem_post(&data->sem_needpost);
sem_timedwait(&data->sem_cleanup, &ts);
}
#endif
jack_port_unregister( data->client, data->port );
data->port = NULL;
}
void MidiOutJack :: sendMessage( std::vector<unsigned char> *message )
void MidiOutJack :: sendMessage( const unsigned char *message, size_t size )
{
int nBytes = message->size();
int nBytes = static_cast<int>(size);
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
// Write full message to buffer
jack_ringbuffer_write( data->buffMessage, ( const char * ) &( *message )[0],
message->size() );
jack_ringbuffer_write( data->buffMessage, ( const char * ) message,
nBytes );
jack_ringbuffer_write( data->buffSize, ( char * ) &nBytes, sizeof( nBytes ) );
}