mirror of
https://github.com/thestk/stk
synced 2026-02-07 17:56:16 +00:00
Update of RtAudio and RtMidi classes in advance of 4.6.0 release.
This commit is contained in:
@@ -45,11 +45,11 @@
|
|||||||
#ifndef __RTAUDIO_H
|
#ifndef __RTAUDIO_H
|
||||||
#define __RTAUDIO_H
|
#define __RTAUDIO_H
|
||||||
|
|
||||||
#define RTAUDIO_VERSION "4.1.2"
|
#define RTAUDIO_VERSION "5.0.0"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <exception>
|
#include <stdexcept>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
/*! \typedef typedef unsigned long RtAudioFormat;
|
/*! \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_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency.
|
||||||
- \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use.
|
- \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use.
|
||||||
- \e RTAUDIO_ALSA_USE_DEFAULT: Use the "default" PCM device (ALSA only).
|
- \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
|
By default, RtAudio streams pass and receive audio data from the
|
||||||
client in an interleaved format. By passing 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
|
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
|
open the "default" PCM device when using the ALSA API. Note that this
|
||||||
will override any specified input or output device id.
|
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;
|
typedef unsigned int RtAudioStreamFlags;
|
||||||
static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1; // Use non-interleaved buffers (default = interleaved).
|
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_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_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_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;
|
/*! \typedef typedef unsigned long RtAudioStreamStatus;
|
||||||
\brief RtAudio stream status (over- or underflow) flags.
|
\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:
|
public:
|
||||||
//! Defined RtAudioError types.
|
//! Defined RtAudioError types.
|
||||||
@@ -214,25 +219,22 @@ class RtAudioError : public std::exception
|
|||||||
};
|
};
|
||||||
|
|
||||||
//! The constructor.
|
//! The constructor.
|
||||||
RtAudioError( const std::string& message, Type type = RtAudioError::UNSPECIFIED ) throw() : message_(message), type_(type) {}
|
RtAudioError( const std::string& message,
|
||||||
|
Type type = RtAudioError::UNSPECIFIED )
|
||||||
//! The destructor.
|
: std::runtime_error(message), type_(type) {}
|
||||||
virtual ~RtAudioError( void ) throw() {}
|
|
||||||
|
|
||||||
//! Prints thrown error message to stderr.
|
//! 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.
|
//! 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.
|
//! Returns the thrown error message string.
|
||||||
virtual const std::string& getMessage(void) const throw() { return message_; }
|
virtual const std::string getMessage(void) const
|
||||||
|
{ return std::string(what()); }
|
||||||
//! Returns the thrown error message as a c-style string.
|
|
||||||
virtual const char* what( void ) const throw() { return message_.c_str(); }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string message_;
|
|
||||||
Type type_;
|
Type type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -375,7 +377,7 @@ class RtAudio
|
|||||||
};
|
};
|
||||||
|
|
||||||
//! A static function to determine the current RtAudio version.
|
//! 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.
|
//! 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
|
the enumerated list values. Note that there can be more than one
|
||||||
API compiled for certain operating systems.
|
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.
|
//! The class constructor.
|
||||||
/*!
|
/*!
|
||||||
@@ -401,10 +403,10 @@ class RtAudio
|
|||||||
If a stream is running or open, it will be stopped and closed
|
If a stream is running or open, it will be stopped and closed
|
||||||
automatically.
|
automatically.
|
||||||
*/
|
*/
|
||||||
~RtAudio() throw();
|
~RtAudio();
|
||||||
|
|
||||||
//! Returns the audio API specifier for the current instance of 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.
|
//! 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
|
is called, thus supporting devices connected \e after instantiation. If
|
||||||
a system error occurs during processing, a warning will be issued.
|
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.
|
//! 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
|
client's responsibility to verify that a device is available
|
||||||
before attempting to open a stream.
|
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.
|
//! 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
|
client's responsibility to verify that a device is available
|
||||||
before attempting to open a stream.
|
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.
|
//! 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
|
If a stream is not open, this function issues a warning and
|
||||||
returns (no exception is thrown).
|
returns (no exception is thrown).
|
||||||
*/
|
*/
|
||||||
void closeStream( void ) throw();
|
void closeStream( void );
|
||||||
|
|
||||||
//! A function that starts a stream.
|
//! A function that starts a stream.
|
||||||
/*!
|
/*!
|
||||||
@@ -528,10 +530,10 @@ class RtAudio
|
|||||||
void abortStream( void );
|
void abortStream( void );
|
||||||
|
|
||||||
//! Returns true if a stream is open and false if not.
|
//! 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.
|
//! 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.
|
//! Returns the number of elapsed seconds since the stream was started.
|
||||||
/*!
|
/*!
|
||||||
@@ -565,7 +567,7 @@ class RtAudio
|
|||||||
unsigned int getStreamSampleRate( void );
|
unsigned int getStreamSampleRate( void );
|
||||||
|
|
||||||
//! Specify whether warning messages should be printed to stderr.
|
//! Specify whether warning messages should be printed to stderr.
|
||||||
void showWarnings( bool value = true ) throw();
|
void showWarnings( bool value = true );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -616,7 +618,7 @@ struct CallbackInfo {
|
|||||||
|
|
||||||
// Default constructor.
|
// Default constructor.
|
||||||
CallbackInfo()
|
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 RtAudio::Api RtAudio :: getCurrentApi( void ) { return rtapi_->getCurrentApi(); }
|
||||||
inline unsigned int RtAudio :: getDeviceCount( void ) throw() { return rtapi_->getDeviceCount(); }
|
inline unsigned int RtAudio :: getDeviceCount( void ) { return rtapi_->getDeviceCount(); }
|
||||||
inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { return rtapi_->getDeviceInfo( device ); }
|
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 :: getDefaultInputDevice( void ) { return rtapi_->getDefaultInputDevice(); }
|
||||||
inline unsigned int RtAudio :: getDefaultOutputDevice( void ) throw() { return rtapi_->getDefaultOutputDevice(); }
|
inline unsigned int RtAudio :: getDefaultOutputDevice( void ) { return rtapi_->getDefaultOutputDevice(); }
|
||||||
inline void RtAudio :: closeStream( void ) throw() { return rtapi_->closeStream(); }
|
inline void RtAudio :: closeStream( void ) { return rtapi_->closeStream(); }
|
||||||
inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); }
|
inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); }
|
||||||
inline void RtAudio :: stopStream( void ) { return rtapi_->stopStream(); }
|
inline void RtAudio :: stopStream( void ) { return rtapi_->stopStream(); }
|
||||||
inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); }
|
inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); }
|
||||||
inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); }
|
inline bool RtAudio :: isStreamOpen( void ) const { return rtapi_->isStreamOpen(); }
|
||||||
inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); }
|
inline bool RtAudio :: isStreamRunning( void ) const { return rtapi_->isStreamRunning(); }
|
||||||
inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); }
|
inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); }
|
||||||
inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); }
|
inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); }
|
||||||
inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); }
|
inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); }
|
||||||
inline void RtAudio :: setStreamTime( double time ) { return rtapi_->setStreamTime( time ); }
|
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.
|
// RtApi Subclass prototypes.
|
||||||
|
|
||||||
@@ -912,6 +914,8 @@ public:
|
|||||||
unsigned int firstChannel, unsigned int sampleRate,
|
unsigned int firstChannel, unsigned int sampleRate,
|
||||||
RtAudioFormat format, unsigned int *bufferSize,
|
RtAudioFormat format, unsigned int *bufferSize,
|
||||||
RtAudio::StreamOptions *options );
|
RtAudio::StreamOptions *options );
|
||||||
|
|
||||||
|
bool shouldAutoconnect_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
155
include/RtMidi.h
155
include/RtMidi.h
@@ -43,7 +43,7 @@
|
|||||||
#ifndef RTMIDI_H
|
#ifndef RTMIDI_H
|
||||||
#define RTMIDI_H
|
#define RTMIDI_H
|
||||||
|
|
||||||
#define RTMIDI_VERSION "2.1.1"
|
#define RTMIDI_VERSION "3.0.0"
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -139,10 +139,10 @@ class RtMidi
|
|||||||
static void getCompiledApi( std::vector<RtMidi::Api> &apis ) throw();
|
static void getCompiledApi( std::vector<RtMidi::Api> &apis ) throw();
|
||||||
|
|
||||||
//! Pure virtual openPort() function.
|
//! 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.
|
//! 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.
|
//! Pure virtual getPortCount() function.
|
||||||
virtual unsigned int getPortCount() = 0;
|
virtual unsigned int getPortCount() = 0;
|
||||||
@@ -154,6 +154,10 @@ class RtMidi
|
|||||||
virtual void closePort( void ) = 0;
|
virtual void closePort( void ) = 0;
|
||||||
|
|
||||||
//! Returns true if a port is open and false if not.
|
//! 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;
|
virtual bool isPortOpen( void ) const = 0;
|
||||||
|
|
||||||
//! Set an error callback function to be invoked when an error has occured.
|
//! 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
|
possible to open a virtual input port to which other MIDI software
|
||||||
clients can connect.
|
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.
|
\param queueSizeLimit An optional size of the MIDI input queue can be specified.
|
||||||
*/
|
*/
|
||||||
RtMidiIn( RtMidi::Api api=UNSPECIFIED,
|
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 );
|
unsigned int queueSizeLimit = 100 );
|
||||||
|
|
||||||
//! If a MIDI connection is still open, it will be closed by the destructor.
|
//! 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.
|
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.
|
\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).
|
//! 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
|
\param portName An optional name for the application port that is
|
||||||
used to connect to portId can be specified.
|
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.
|
//! Set a callback function to be invoked for incoming MIDI messages.
|
||||||
/*!
|
/*!
|
||||||
@@ -282,6 +286,10 @@ class RtMidiIn : public RtMidi
|
|||||||
void closePort( void );
|
void closePort( void );
|
||||||
|
|
||||||
//! Returns true if a port is open and false if not.
|
//! 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;
|
virtual bool isPortOpen() const;
|
||||||
|
|
||||||
//! Return the number of available MIDI input ports.
|
//! 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 a string identifier for the specified MIDI input port number.
|
||||||
/*!
|
/*!
|
||||||
\return The name of the port with the given Id is returned.
|
\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 );
|
std::string getPortName( unsigned int portNumber = 0 );
|
||||||
|
|
||||||
@@ -325,7 +334,7 @@ class RtMidiIn : public RtMidi
|
|||||||
virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
|
virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
|
||||||
|
|
||||||
protected:
|
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
|
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.
|
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).
|
JACK (OS-X).
|
||||||
*/
|
*/
|
||||||
RtMidiOut( RtMidi::Api api=UNSPECIFIED,
|
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.
|
//! The destructor closes any open MIDI connections.
|
||||||
~RtMidiOut( void ) throw();
|
~RtMidiOut( void ) throw();
|
||||||
@@ -373,12 +382,16 @@ class RtMidiOut : public RtMidi
|
|||||||
exception is thrown if an error occurs while attempting to make
|
exception is thrown if an error occurs while attempting to make
|
||||||
the port connection.
|
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).
|
//! Close an open MIDI connection (if one exists).
|
||||||
void closePort( void );
|
void closePort( void );
|
||||||
|
|
||||||
//! Returns true if a port is open and false if not.
|
//! 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;
|
virtual bool isPortOpen() const;
|
||||||
|
|
||||||
//! Create a virtual output port, with optional name, to allow software connections (OS X, JACK and ALSA only).
|
//! 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
|
An exception is thrown if an error occurs while attempting to
|
||||||
create the virtual port.
|
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.
|
//! Return the number of available MIDI output ports.
|
||||||
unsigned int getPortCount( void );
|
unsigned int getPortCount( void );
|
||||||
|
|
||||||
//! Return a string identifier for the specified MIDI port type and number.
|
//! 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 );
|
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
|
An exception is thrown if an error occurs during output or an
|
||||||
output connection was not previously established.
|
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.
|
//! 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 );
|
virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
|
||||||
|
|
||||||
protected:
|
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();
|
MidiApi();
|
||||||
virtual ~MidiApi();
|
virtual ~MidiApi();
|
||||||
virtual RtMidi::Api getCurrentApi( void ) = 0;
|
virtual RtMidi::Api getCurrentApi( void ) = 0;
|
||||||
virtual void openPort( unsigned int portNumber, 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 openVirtualPort( const std::string &portName ) = 0;
|
||||||
virtual void closePort( void ) = 0;
|
virtual void closePort( void ) = 0;
|
||||||
|
|
||||||
virtual unsigned int getPortCount( 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.
|
// messages. Each message represents one and only one MIDI message.
|
||||||
struct MidiMessage {
|
struct MidiMessage {
|
||||||
std::vector<unsigned char> bytes;
|
std::vector<unsigned char> bytes;
|
||||||
|
|
||||||
|
//! Time in seconds elapsed since the previous message
|
||||||
double timeStamp;
|
double timeStamp;
|
||||||
|
|
||||||
// Default constructor.
|
// Default constructor.
|
||||||
@@ -489,13 +516,16 @@ class MidiInApi : public MidiApi
|
|||||||
struct MidiQueue {
|
struct MidiQueue {
|
||||||
unsigned int front;
|
unsigned int front;
|
||||||
unsigned int back;
|
unsigned int back;
|
||||||
unsigned int size;
|
|
||||||
unsigned int ringSize;
|
unsigned int ringSize;
|
||||||
MidiMessage *ring;
|
MidiMessage *ring;
|
||||||
|
|
||||||
// Default constructor.
|
// Default constructor.
|
||||||
MidiQueue()
|
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
|
// The RtMidiInData structure is used to pass private class data to
|
||||||
@@ -529,7 +559,7 @@ class MidiOutApi : public MidiApi
|
|||||||
|
|
||||||
MidiOutApi( void );
|
MidiOutApi( void );
|
||||||
virtual ~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 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 :: 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 :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
|
||||||
inline void RtMidiIn :: closePort( void ) { rtapi_->closePort(); }
|
inline void RtMidiIn :: closePort( void ) { rtapi_->closePort(); }
|
||||||
inline bool RtMidiIn :: isPortOpen() const { return rtapi_->isPortOpen(); }
|
inline bool RtMidiIn :: isPortOpen() const { return rtapi_->isPortOpen(); }
|
||||||
inline void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData ) { ((MidiInApi *)rtapi_)->setCallback( callback, userData ); }
|
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 void RtMidiIn :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
|
||||||
|
|
||||||
inline RtMidi::Api RtMidiOut :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
|
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 :: 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 :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
|
||||||
inline void RtMidiOut :: closePort( void ) { rtapi_->closePort(); }
|
inline void RtMidiOut :: closePort( void ) { rtapi_->closePort(); }
|
||||||
inline bool RtMidiOut :: isPortOpen() const { return rtapi_->isPortOpen(); }
|
inline bool RtMidiOut :: isPortOpen() const { return rtapi_->isPortOpen(); }
|
||||||
inline unsigned int RtMidiOut :: getPortCount( void ) { return rtapi_->getPortCount(); }
|
inline unsigned int RtMidiOut :: getPortCount( void ) { return rtapi_->getPortCount(); }
|
||||||
inline std::string RtMidiOut :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
|
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); }
|
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
|
class MidiInCore: public MidiInApi
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MidiInCore( const std::string clientName, unsigned int queueSizeLimit );
|
MidiInCore( const std::string &clientName, unsigned int queueSizeLimit );
|
||||||
~MidiInCore( void );
|
~MidiInCore( void );
|
||||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
|
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
|
||||||
void openPort( unsigned int portNumber, const std::string portName );
|
void openPort( unsigned int portNumber, const std::string &portName );
|
||||||
void openVirtualPort( const std::string portName );
|
void openVirtualPort( const std::string &portName );
|
||||||
void closePort( void );
|
void closePort( void );
|
||||||
unsigned int getPortCount( void );
|
unsigned int getPortCount( void );
|
||||||
std::string getPortName( unsigned int portNumber );
|
std::string getPortName( unsigned int portNumber );
|
||||||
@@ -592,15 +623,15 @@ class MidiInCore: public MidiInApi
|
|||||||
class MidiOutCore: public MidiOutApi
|
class MidiOutCore: public MidiOutApi
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MidiOutCore( const std::string clientName );
|
MidiOutCore( const std::string &clientName );
|
||||||
~MidiOutCore( void );
|
~MidiOutCore( void );
|
||||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
|
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
|
||||||
void openPort( unsigned int portNumber, const std::string portName );
|
void openPort( unsigned int portNumber, const std::string &portName );
|
||||||
void openVirtualPort( const std::string portName );
|
void openVirtualPort( const std::string &portName );
|
||||||
void closePort( void );
|
void closePort( void );
|
||||||
unsigned int getPortCount( void );
|
unsigned int getPortCount( void );
|
||||||
std::string getPortName( unsigned int portNumber );
|
std::string getPortName( unsigned int portNumber );
|
||||||
void sendMessage( std::vector<unsigned char> *message );
|
void sendMessage( const unsigned char *message, size_t size );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initialize( const std::string& clientName );
|
void initialize( const std::string& clientName );
|
||||||
@@ -613,11 +644,11 @@ class MidiOutCore: public MidiOutApi
|
|||||||
class MidiInJack: public MidiInApi
|
class MidiInJack: public MidiInApi
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MidiInJack( const std::string clientName, unsigned int queueSizeLimit );
|
MidiInJack( const std::string &clientName, unsigned int queueSizeLimit );
|
||||||
~MidiInJack( void );
|
~MidiInJack( void );
|
||||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
|
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
|
||||||
void openPort( unsigned int portNumber, const std::string portName );
|
void openPort( unsigned int portNumber, const std::string &portName );
|
||||||
void openVirtualPort( const std::string portName );
|
void openVirtualPort( const std::string &portName );
|
||||||
void closePort( void );
|
void closePort( void );
|
||||||
unsigned int getPortCount( void );
|
unsigned int getPortCount( void );
|
||||||
std::string getPortName( unsigned int portNumber );
|
std::string getPortName( unsigned int portNumber );
|
||||||
@@ -632,15 +663,15 @@ class MidiInJack: public MidiInApi
|
|||||||
class MidiOutJack: public MidiOutApi
|
class MidiOutJack: public MidiOutApi
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MidiOutJack( const std::string clientName );
|
MidiOutJack( const std::string &clientName );
|
||||||
~MidiOutJack( void );
|
~MidiOutJack( void );
|
||||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
|
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
|
||||||
void openPort( unsigned int portNumber, const std::string portName );
|
void openPort( unsigned int portNumber, const std::string &portName );
|
||||||
void openVirtualPort( const std::string portName );
|
void openVirtualPort( const std::string &portName );
|
||||||
void closePort( void );
|
void closePort( void );
|
||||||
unsigned int getPortCount( void );
|
unsigned int getPortCount( void );
|
||||||
std::string getPortName( unsigned int portNumber );
|
std::string getPortName( unsigned int portNumber );
|
||||||
void sendMessage( std::vector<unsigned char> *message );
|
void sendMessage( const unsigned char *message, size_t size );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string clientName;
|
std::string clientName;
|
||||||
@@ -656,11 +687,11 @@ class MidiOutJack: public MidiOutApi
|
|||||||
class MidiInAlsa: public MidiInApi
|
class MidiInAlsa: public MidiInApi
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MidiInAlsa( const std::string clientName, unsigned int queueSizeLimit );
|
MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit );
|
||||||
~MidiInAlsa( void );
|
~MidiInAlsa( void );
|
||||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
|
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
|
||||||
void openPort( unsigned int portNumber, const std::string portName );
|
void openPort( unsigned int portNumber, const std::string &portName );
|
||||||
void openVirtualPort( const std::string portName );
|
void openVirtualPort( const std::string &portName );
|
||||||
void closePort( void );
|
void closePort( void );
|
||||||
unsigned int getPortCount( void );
|
unsigned int getPortCount( void );
|
||||||
std::string getPortName( unsigned int portNumber );
|
std::string getPortName( unsigned int portNumber );
|
||||||
@@ -672,15 +703,15 @@ class MidiInAlsa: public MidiInApi
|
|||||||
class MidiOutAlsa: public MidiOutApi
|
class MidiOutAlsa: public MidiOutApi
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MidiOutAlsa( const std::string clientName );
|
MidiOutAlsa( const std::string &clientName );
|
||||||
~MidiOutAlsa( void );
|
~MidiOutAlsa( void );
|
||||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
|
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
|
||||||
void openPort( unsigned int portNumber, const std::string portName );
|
void openPort( unsigned int portNumber, const std::string &portName );
|
||||||
void openVirtualPort( const std::string portName );
|
void openVirtualPort( const std::string &portName );
|
||||||
void closePort( void );
|
void closePort( void );
|
||||||
unsigned int getPortCount( void );
|
unsigned int getPortCount( void );
|
||||||
std::string getPortName( unsigned int portNumber );
|
std::string getPortName( unsigned int portNumber );
|
||||||
void sendMessage( std::vector<unsigned char> *message );
|
void sendMessage( const unsigned char *message, size_t size );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initialize( const std::string& clientName );
|
void initialize( const std::string& clientName );
|
||||||
@@ -693,11 +724,11 @@ class MidiOutAlsa: public MidiOutApi
|
|||||||
class MidiInWinMM: public MidiInApi
|
class MidiInWinMM: public MidiInApi
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MidiInWinMM( const std::string clientName, unsigned int queueSizeLimit );
|
MidiInWinMM( const std::string &clientName, unsigned int queueSizeLimit );
|
||||||
~MidiInWinMM( void );
|
~MidiInWinMM( void );
|
||||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
|
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
|
||||||
void openPort( unsigned int portNumber, const std::string portName );
|
void openPort( unsigned int portNumber, const std::string &portName );
|
||||||
void openVirtualPort( const std::string portName );
|
void openVirtualPort( const std::string &portName );
|
||||||
void closePort( void );
|
void closePort( void );
|
||||||
unsigned int getPortCount( void );
|
unsigned int getPortCount( void );
|
||||||
std::string getPortName( unsigned int portNumber );
|
std::string getPortName( unsigned int portNumber );
|
||||||
@@ -709,15 +740,15 @@ class MidiInWinMM: public MidiInApi
|
|||||||
class MidiOutWinMM: public MidiOutApi
|
class MidiOutWinMM: public MidiOutApi
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MidiOutWinMM( const std::string clientName );
|
MidiOutWinMM( const std::string &clientName );
|
||||||
~MidiOutWinMM( void );
|
~MidiOutWinMM( void );
|
||||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
|
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
|
||||||
void openPort( unsigned int portNumber, const std::string portName );
|
void openPort( unsigned int portNumber, const std::string &portName );
|
||||||
void openVirtualPort( const std::string portName );
|
void openVirtualPort( const std::string &portName );
|
||||||
void closePort( void );
|
void closePort( void );
|
||||||
unsigned int getPortCount( void );
|
unsigned int getPortCount( void );
|
||||||
std::string getPortName( unsigned int portNumber );
|
std::string getPortName( unsigned int portNumber );
|
||||||
void sendMessage( std::vector<unsigned char> *message );
|
void sendMessage( const unsigned char *message, size_t size );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initialize( const std::string& clientName );
|
void initialize( const std::string& clientName );
|
||||||
@@ -730,13 +761,13 @@ class MidiOutWinMM: public MidiOutApi
|
|||||||
class MidiInDummy: public MidiInApi
|
class MidiInDummy: public MidiInApi
|
||||||
{
|
{
|
||||||
public:
|
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; }
|
RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
|
||||||
void openPort( unsigned int /*portNumber*/, const std::string /*portName*/ ) {}
|
void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
|
||||||
void openVirtualPort( const std::string /*portName*/ ) {}
|
void openVirtualPort( const std::string &/*portName*/ ) {}
|
||||||
void closePort( void ) {}
|
void closePort( void ) {}
|
||||||
unsigned int getPortCount( void ) { return 0; }
|
unsigned int getPortCount( void ) { return 0; }
|
||||||
std::string getPortName( unsigned int portNumber ) { return ""; }
|
std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initialize( const std::string& /*clientName*/ ) {}
|
void initialize( const std::string& /*clientName*/ ) {}
|
||||||
@@ -745,14 +776,14 @@ class MidiInDummy: public MidiInApi
|
|||||||
class MidiOutDummy: public MidiOutApi
|
class MidiOutDummy: public MidiOutApi
|
||||||
{
|
{
|
||||||
public:
|
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; }
|
RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
|
||||||
void openPort( unsigned int /*portNumber*/, const std::string /*portName*/ ) {}
|
void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
|
||||||
void openVirtualPort( const std::string /*portName*/ ) {}
|
void openVirtualPort( const std::string &/*portName*/ ) {}
|
||||||
void closePort( void ) {}
|
void closePort( void ) {}
|
||||||
unsigned int getPortCount( void ) { return 0; }
|
unsigned int getPortCount( void ) { return 0; }
|
||||||
std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
|
std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
|
||||||
void sendMessage( std::vector<unsigned char> * /*message*/ ) {}
|
void sendMessage( const unsigned char * /*message*/, size_t /*size*/ ) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initialize( const std::string& /*clientName*/ ) {}
|
void initialize( const std::string& /*clientName*/ ) {}
|
||||||
|
|||||||
176
src/RtAudio.cpp
176
src/RtAudio.cpp
@@ -1,4 +1,4 @@
|
|||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/*! \class RtAudio
|
/*! \class RtAudio
|
||||||
\brief Realtime audio i/o C++ classes.
|
\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 "RtAudio.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
#include <cmath>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
// Static variable definitions.
|
// 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;
|
return RTAUDIO_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()
|
void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis )
|
||||||
{
|
{
|
||||||
apis.clear();
|
apis.clear();
|
||||||
|
|
||||||
@@ -209,7 +210,7 @@ RtAudio :: RtAudio( RtAudio::Api api )
|
|||||||
throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );
|
throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
RtAudio :: ~RtAudio() throw()
|
RtAudio :: ~RtAudio()
|
||||||
{
|
{
|
||||||
if ( rtapi_ )
|
if ( rtapi_ )
|
||||||
delete rtapi_;
|
delete rtapi_;
|
||||||
@@ -427,6 +428,9 @@ void RtApi :: setStreamTime( double time )
|
|||||||
|
|
||||||
if ( time >= 0.0 )
|
if ( time >= 0.0 )
|
||||||
stream_.streamTime = time;
|
stream_.streamTime = time;
|
||||||
|
#if defined( HAVE_GETTIMEOFDAY )
|
||||||
|
gettimeofday( &stream_.lastTickTimestamp, NULL );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int RtApi :: getStreamSampleRate( void )
|
unsigned int RtApi :: getStreamSampleRate( void )
|
||||||
@@ -1943,7 +1947,7 @@ struct JackHandle {
|
|||||||
static void jackSilentError( const char * ) {};
|
static void jackSilentError( const char * ) {};
|
||||||
|
|
||||||
RtApiJack :: RtApiJack()
|
RtApiJack :: RtApiJack()
|
||||||
{
|
:shouldAutoconnect_(true) {
|
||||||
// Nothing to do here.
|
// Nothing to do here.
|
||||||
#if !defined(__RTAUDIO_DEBUG__)
|
#if !defined(__RTAUDIO_DEBUG__)
|
||||||
// Turn off Jack's internal error reporting.
|
// Turn off Jack's internal error reporting.
|
||||||
@@ -2354,6 +2358,8 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
|
|||||||
// here.
|
// here.
|
||||||
if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );
|
if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );
|
||||||
|
|
||||||
|
if ( options && options->flags & RTAUDIO_JACK_DONT_CONNECT ) shouldAutoconnect_ = false;
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -2443,7 +2449,7 @@ void RtApiJack :: startStream( void )
|
|||||||
const char **ports;
|
const char **ports;
|
||||||
|
|
||||||
// Get the list of available ports.
|
// Get the list of available ports.
|
||||||
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
|
if ( shouldAutoconnect_ && (stream_.mode == OUTPUT || stream_.mode == DUPLEX) ) {
|
||||||
result = 1;
|
result = 1;
|
||||||
ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
|
ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
|
||||||
if ( ports == NULL) {
|
if ( ports == NULL) {
|
||||||
@@ -2467,7 +2473,7 @@ void RtApiJack :: startStream( void )
|
|||||||
free(ports);
|
free(ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
|
if ( shouldAutoconnect_ && (stream_.mode == INPUT || stream_.mode == DUPLEX) ) {
|
||||||
result = 1;
|
result = 1;
|
||||||
ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput );
|
ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput );
|
||||||
if ( ports == NULL) {
|
if ( ports == NULL) {
|
||||||
@@ -3859,8 +3865,7 @@ private:
|
|||||||
// In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate
|
// 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 HW and the user. The convertBufferWasapi function is used to perform this conversion
|
||||||
// between HwIn->UserIn and UserOut->HwOut during the stream callback loop.
|
// 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
|
// This sample rate converter works best with conversions between one rate and its multiple.
|
||||||
// one rate and its multiple.
|
|
||||||
void convertBufferWasapi( char* outBuffer,
|
void convertBufferWasapi( char* outBuffer,
|
||||||
const char* inBuffer,
|
const char* inBuffer,
|
||||||
const unsigned int& channelCount,
|
const unsigned int& channelCount,
|
||||||
@@ -3872,40 +3877,129 @@ void convertBufferWasapi( char* outBuffer,
|
|||||||
{
|
{
|
||||||
// calculate the new outSampleCount and relative sampleStep
|
// calculate the new outSampleCount and relative sampleStep
|
||||||
float sampleRatio = ( float ) outSampleRate / inSampleRate;
|
float sampleRatio = ( float ) outSampleRate / inSampleRate;
|
||||||
|
float sampleRatioInv = ( float ) 1 / sampleRatio;
|
||||||
float sampleStep = 1.0f / sampleRatio;
|
float sampleStep = 1.0f / sampleRatio;
|
||||||
float inSampleFraction = 0.0f;
|
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
|
// if inSampleRate is a multiple of outSampleRate (or vice versa) there's no need to interpolate
|
||||||
for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
|
if ( floor( sampleRatio ) == sampleRatio || floor( sampleRatioInv ) == sampleRatioInv )
|
||||||
{
|
{
|
||||||
unsigned int inSample = ( unsigned int ) inSampleFraction;
|
// frame-by-frame, copy each relative input sample into it's corresponding output sample
|
||||||
|
for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
|
||||||
switch ( format )
|
|
||||||
{
|
{
|
||||||
case RTAUDIO_SINT8:
|
unsigned int inSample = ( unsigned int ) inSampleFraction;
|
||||||
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
|
switch ( format )
|
||||||
inSampleFraction += sampleStep;
|
{
|
||||||
|
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
|
// Various revisions for RtAudio 4.0 by Gary Scavone, April 2007
|
||||||
// Changed device query structure for RtAudio 4.0.7, January 2010
|
// Changed device query structure for RtAudio 4.0.7, January 2010
|
||||||
|
|
||||||
|
#include <mmsystem.h>
|
||||||
|
#include <mmreg.h>
|
||||||
#include <dsound.h>
|
#include <dsound.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -5275,8 +5371,8 @@ RtApiDs :: RtApiDs()
|
|||||||
|
|
||||||
RtApiDs :: ~RtApiDs()
|
RtApiDs :: ~RtApiDs()
|
||||||
{
|
{
|
||||||
if ( coInitialized_ ) CoUninitialize(); // balanced call.
|
|
||||||
if ( stream_.state != STREAM_CLOSED ) closeStream();
|
if ( stream_.state != STREAM_CLOSED ) closeStream();
|
||||||
|
if ( coInitialized_ ) CoUninitialize(); // balanced call.
|
||||||
}
|
}
|
||||||
|
|
||||||
// The DirectSound default output is always the first device.
|
// The DirectSound default output is always the first device.
|
||||||
@@ -8695,8 +8791,10 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
|
|||||||
info.nativeFormats |= RTAUDIO_SINT8;
|
info.nativeFormats |= RTAUDIO_SINT8;
|
||||||
if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE )
|
if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE )
|
||||||
info.nativeFormats |= RTAUDIO_SINT32;
|
info.nativeFormats |= RTAUDIO_SINT32;
|
||||||
|
#ifdef AFMT_FLOAT
|
||||||
if ( mask & AFMT_FLOAT )
|
if ( mask & AFMT_FLOAT )
|
||||||
info.nativeFormats |= RTAUDIO_FLOAT32;
|
info.nativeFormats |= RTAUDIO_FLOAT32;
|
||||||
|
#endif
|
||||||
if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE )
|
if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE )
|
||||||
info.nativeFormats |= RTAUDIO_SINT24;
|
info.nativeFormats |= RTAUDIO_SINT24;
|
||||||
|
|
||||||
@@ -9023,7 +9121,7 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify the sample rate setup worked.
|
// Verify the sample rate setup worked.
|
||||||
if ( abs( srate - sampleRate ) > 100 ) {
|
if ( abs( srate - (int)sampleRate ) > 100 ) {
|
||||||
close( fd );
|
close( fd );
|
||||||
errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ").";
|
errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ").";
|
||||||
errorText_ = errorStream_.str();
|
errorText_ = errorStream_.str();
|
||||||
|
|||||||
369
src/RtMidi.cpp
369
src/RtMidi.cpp
@@ -46,6 +46,10 @@
|
|||||||
#endif
|
#endif
|
||||||
#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
|
// RtMidi Definitions
|
||||||
//*********************************************************************//
|
//*********************************************************************//
|
||||||
@@ -57,8 +61,7 @@ RtMidi :: RtMidi()
|
|||||||
|
|
||||||
RtMidi :: ~RtMidi()
|
RtMidi :: ~RtMidi()
|
||||||
{
|
{
|
||||||
if ( rtapi_ )
|
delete rtapi_;
|
||||||
delete rtapi_;
|
|
||||||
rtapi_ = 0;
|
rtapi_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,10 +97,9 @@ void RtMidi :: getCompiledApi( std::vector<RtMidi::Api> &apis ) throw()
|
|||||||
// RtMidiIn Definitions
|
// 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;
|
rtapi_ = 0;
|
||||||
|
|
||||||
#if defined(__UNIX_JACK__)
|
#if defined(__UNIX_JACK__)
|
||||||
@@ -122,7 +124,7 @@ void RtMidiIn :: openMidiApi( RtMidi::Api api, const std::string clientName, uns
|
|||||||
#endif
|
#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()
|
: RtMidi()
|
||||||
{
|
{
|
||||||
if ( api != UNSPECIFIED ) {
|
if ( api != UNSPECIFIED ) {
|
||||||
@@ -141,7 +143,7 @@ RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string clientName, unsigned in
|
|||||||
getCompiledApi( apis );
|
getCompiledApi( apis );
|
||||||
for ( unsigned int i=0; i<apis.size(); i++ ) {
|
for ( unsigned int i=0; i<apis.size(); i++ ) {
|
||||||
openMidiApi( apis[i], clientName, queueSizeLimit );
|
openMidiApi( apis[i], clientName, queueSizeLimit );
|
||||||
if ( rtapi_->getPortCount() ) break;
|
if ( rtapi_ && rtapi_->getPortCount() ) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( rtapi_ ) return;
|
if ( rtapi_ ) return;
|
||||||
@@ -163,10 +165,9 @@ RtMidiIn :: ~RtMidiIn() throw()
|
|||||||
// RtMidiOut Definitions
|
// 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;
|
rtapi_ = 0;
|
||||||
|
|
||||||
#if defined(__UNIX_JACK__)
|
#if defined(__UNIX_JACK__)
|
||||||
@@ -191,7 +192,7 @@ void RtMidiOut :: openMidiApi( RtMidi::Api api, const std::string clientName )
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string clientName )
|
RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string &clientName)
|
||||||
{
|
{
|
||||||
if ( api != UNSPECIFIED ) {
|
if ( api != UNSPECIFIED ) {
|
||||||
// Attempt to open the specified API.
|
// Attempt to open the specified API.
|
||||||
@@ -209,7 +210,7 @@ RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string clientName )
|
|||||||
getCompiledApi( apis );
|
getCompiledApi( apis );
|
||||||
for ( unsigned int i=0; i<apis.size(); i++ ) {
|
for ( unsigned int i=0; i<apis.size(); i++ ) {
|
||||||
openMidiApi( apis[i], clientName );
|
openMidiApi( apis[i], clientName );
|
||||||
if ( rtapi_->getPortCount() ) break;
|
if ( rtapi_ && rtapi_->getPortCount() ) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( rtapi_ ) return;
|
if ( rtapi_ ) return;
|
||||||
@@ -231,7 +232,7 @@ RtMidiOut :: ~RtMidiOut() throw()
|
|||||||
//*********************************************************************//
|
//*********************************************************************//
|
||||||
|
|
||||||
MidiApi :: MidiApi( void )
|
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;
|
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.
|
// Copy queued message to the vector pointer argument and then "pop" it.
|
||||||
std::vector<unsigned char> *bytes = &(inputData_.queue.ring[inputData_.queue.front].bytes);
|
msg->assign( ring[_front].bytes.begin(), ring[_front].bytes.end() );
|
||||||
message->assign( bytes->begin(), bytes->end() );
|
*timeStamp = ring[_front].timeStamp;
|
||||||
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;
|
|
||||||
|
|
||||||
return deltaTime;
|
// Update front
|
||||||
|
front = (front+1)%ringSize;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//*********************************************************************//
|
//*********************************************************************//
|
||||||
@@ -470,13 +521,7 @@ static void midiInputCallback( const MIDIPacketList *list, void *procRef, void *
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// As long as we haven't reached our queue size limit, push the message.
|
// As long as we haven't reached our queue size limit, push the message.
|
||||||
if ( data->queue.size < data->queue.ringSize ) {
|
if (!data->queue.push(message))
|
||||||
data->queue.ring[data->queue.back++] = message;
|
|
||||||
if ( data->queue.back == data->queue.ringSize )
|
|
||||||
data->queue.back = 0;
|
|
||||||
data->queue.size++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
|
std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
|
||||||
}
|
}
|
||||||
message.bytes.clear();
|
message.bytes.clear();
|
||||||
@@ -534,13 +579,7 @@ static void midiInputCallback( const MIDIPacketList *list, void *procRef, void *
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// As long as we haven't reached our queue size limit, push the message.
|
// As long as we haven't reached our queue size limit, push the message.
|
||||||
if ( data->queue.size < data->queue.ringSize ) {
|
if (!data->queue.push(message))
|
||||||
data->queue.ring[data->queue.back++] = message;
|
|
||||||
if ( data->queue.back == data->queue.ringSize )
|
|
||||||
data->queue.back = 0;
|
|
||||||
data->queue.size++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
|
std::cerr << "\nMidiInCore: message queue limit reached!!\n\n";
|
||||||
}
|
}
|
||||||
message.bytes.clear();
|
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 );
|
initialize( clientName );
|
||||||
}
|
}
|
||||||
@@ -577,7 +616,9 @@ void MidiInCore :: initialize( const std::string& clientName )
|
|||||||
CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
|
CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
|
||||||
OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
|
OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
|
||||||
if ( result != noErr ) {
|
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_ );
|
error( RtMidiError::DRIVER_ERROR, errorString_ );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -591,7 +632,7 @@ void MidiInCore :: initialize( const std::string& clientName )
|
|||||||
CFRelease(name);
|
CFRelease(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiInCore :: openPort( unsigned int portNumber, const std::string portName )
|
void MidiInCore :: openPort( unsigned int portNumber, const std::string &portName )
|
||||||
{
|
{
|
||||||
if ( connected_ ) {
|
if ( connected_ ) {
|
||||||
errorString_ = "MidiInCore::openPort: a valid connection already exists!";
|
errorString_ = "MidiInCore::openPort: a valid connection already exists!";
|
||||||
@@ -653,7 +694,7 @@ void MidiInCore :: openPort( unsigned int portNumber, const std::string portName
|
|||||||
connected_ = true;
|
connected_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiInCore :: openVirtualPort( const std::string portName )
|
void MidiInCore :: openVirtualPort( const std::string &portName )
|
||||||
{
|
{
|
||||||
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
|
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
|
||||||
|
|
||||||
@@ -678,10 +719,12 @@ void MidiInCore :: closePort( void )
|
|||||||
|
|
||||||
if ( data->endpoint ) {
|
if ( data->endpoint ) {
|
||||||
MIDIEndpointDispose( data->endpoint );
|
MIDIEndpointDispose( data->endpoint );
|
||||||
|
data->endpoint = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( data->port ) {
|
if ( data->port ) {
|
||||||
MIDIPortDispose( data->port );
|
MIDIPortDispose( data->port );
|
||||||
|
data->port = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
connected_ = false;
|
connected_ = false;
|
||||||
@@ -837,7 +880,7 @@ std::string MidiInCore :: getPortName( unsigned int portNumber )
|
|||||||
|
|
||||||
portRef = MIDIGetSource( portNumber );
|
portRef = MIDIGetSource( portNumber );
|
||||||
nameRef = ConnectedEndpointName(portRef);
|
nameRef = ConnectedEndpointName(portRef);
|
||||||
CFStringGetCString( nameRef, name, sizeof(name), CFStringGetSystemEncoding());
|
CFStringGetCString( nameRef, name, sizeof(name), kCFStringEncodingUTF8);
|
||||||
CFRelease( nameRef );
|
CFRelease( nameRef );
|
||||||
|
|
||||||
return stringName = name;
|
return stringName = name;
|
||||||
@@ -848,7 +891,7 @@ std::string MidiInCore :: getPortName( unsigned int portNumber )
|
|||||||
// Class Definitions: MidiOutCore
|
// Class Definitions: MidiOutCore
|
||||||
//*********************************************************************//
|
//*********************************************************************//
|
||||||
|
|
||||||
MidiOutCore :: MidiOutCore( const std::string clientName ) : MidiOutApi()
|
MidiOutCore :: MidiOutCore( const std::string &clientName ) : MidiOutApi()
|
||||||
{
|
{
|
||||||
initialize( clientName );
|
initialize( clientName );
|
||||||
}
|
}
|
||||||
@@ -872,7 +915,9 @@ void MidiOutCore :: initialize( const std::string& clientName )
|
|||||||
CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
|
CFStringRef name = CFStringCreateWithCString( NULL, clientName.c_str(), kCFStringEncodingASCII );
|
||||||
OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
|
OSStatus result = MIDIClientCreate(name, NULL, NULL, &client );
|
||||||
if ( result != noErr ) {
|
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_ );
|
error( RtMidiError::DRIVER_ERROR, errorString_ );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -909,13 +954,13 @@ std::string MidiOutCore :: getPortName( unsigned int portNumber )
|
|||||||
|
|
||||||
portRef = MIDIGetDestination( portNumber );
|
portRef = MIDIGetDestination( portNumber );
|
||||||
nameRef = ConnectedEndpointName(portRef);
|
nameRef = ConnectedEndpointName(portRef);
|
||||||
CFStringGetCString( nameRef, name, sizeof(name), CFStringGetSystemEncoding());
|
CFStringGetCString( nameRef, name, sizeof(name), kCFStringEncodingUTF8 );
|
||||||
CFRelease( nameRef );
|
CFRelease( nameRef );
|
||||||
|
|
||||||
return stringName = name;
|
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_ ) {
|
if ( connected_ ) {
|
||||||
errorString_ = "MidiOutCore::openPort: a valid connection already exists!";
|
errorString_ = "MidiOutCore::openPort: a valid connection already exists!";
|
||||||
@@ -941,9 +986,11 @@ void MidiOutCore :: openPort( unsigned int portNumber, const std::string portNam
|
|||||||
|
|
||||||
MIDIPortRef port;
|
MIDIPortRef port;
|
||||||
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
|
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
|
||||||
|
CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
|
||||||
OSStatus result = MIDIOutputPortCreate( data->client,
|
OSStatus result = MIDIOutputPortCreate( data->client,
|
||||||
CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
|
portNameRef,
|
||||||
&port );
|
&port );
|
||||||
|
CFRelease( portNameRef );
|
||||||
if ( result != noErr ) {
|
if ( result != noErr ) {
|
||||||
MIDIClientDispose( data->client );
|
MIDIClientDispose( data->client );
|
||||||
errorString_ = "MidiOutCore::openPort: error creating OS-X MIDI output port.";
|
errorString_ = "MidiOutCore::openPort: error creating OS-X MIDI output port.";
|
||||||
@@ -973,16 +1020,18 @@ void MidiOutCore :: closePort( void )
|
|||||||
|
|
||||||
if ( data->endpoint ) {
|
if ( data->endpoint ) {
|
||||||
MIDIEndpointDispose( data->endpoint );
|
MIDIEndpointDispose( data->endpoint );
|
||||||
|
data->endpoint = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( data->port ) {
|
if ( data->port ) {
|
||||||
MIDIPortDispose( data->port );
|
MIDIPortDispose( data->port );
|
||||||
|
data->port = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
connected_ = false;
|
connected_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiOutCore :: openVirtualPort( std::string portName )
|
void MidiOutCore :: openVirtualPort( const std::string &portName )
|
||||||
{
|
{
|
||||||
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
|
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
|
||||||
|
|
||||||
@@ -1007,11 +1056,11 @@ void MidiOutCore :: openVirtualPort( std::string portName )
|
|||||||
data->endpoint = endpoint;
|
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
|
// We use the MIDISendSysex() function to asynchronously send sysex
|
||||||
// messages. Otherwise, we use a single CoreMIDI MIDIPacket.
|
// messages. Otherwise, we use a single CoreMidi MIDIPacket.
|
||||||
unsigned int nBytes = message->size();
|
unsigned int nBytes = static_cast<unsigned int> (size);
|
||||||
if ( nBytes == 0 ) {
|
if ( nBytes == 0 ) {
|
||||||
errorString_ = "MidiOutCore::sendMessage: no data in message argument!";
|
errorString_ = "MidiOutCore::sendMessage: no data in message argument!";
|
||||||
error( RtMidiError::WARNING, errorString_ );
|
error( RtMidiError::WARNING, errorString_ );
|
||||||
@@ -1022,7 +1071,7 @@ void MidiOutCore :: sendMessage( std::vector<unsigned char> *message )
|
|||||||
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
|
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
|
||||||
OSStatus result;
|
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?";
|
errorString_ = "MidiOutCore::sendMessage: message format problem ... not sysex but > 3 bytes?";
|
||||||
error( RtMidiError::WARNING, errorString_ );
|
error( RtMidiError::WARNING, errorString_ );
|
||||||
return;
|
return;
|
||||||
@@ -1036,7 +1085,7 @@ void MidiOutCore :: sendMessage( std::vector<unsigned char> *message )
|
|||||||
ByteCount remainingBytes = nBytes;
|
ByteCount remainingBytes = nBytes;
|
||||||
while (remainingBytes && packet) {
|
while (remainingBytes && packet) {
|
||||||
ByteCount bytesForPacket = remainingBytes > 65535 ? 65535 : remainingBytes; // 65535 = maximum size of a MIDIPacket
|
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);
|
packet = MIDIPacketListAdd( packetList, listSize, packet, timeStamp, bytesForPacket, dataStartPtr);
|
||||||
remainingBytes -= bytesForPacket;
|
remainingBytes -= bytesForPacket;
|
||||||
}
|
}
|
||||||
@@ -1106,7 +1155,7 @@ struct AlsaMidiData {
|
|||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
pthread_t dummy_thread_id;
|
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 queue_id; // an input queue is needed to get timestamped events
|
||||||
int trigger_fds[2];
|
int trigger_fds[2];
|
||||||
};
|
};
|
||||||
@@ -1124,7 +1173,7 @@ static void *alsaMidiHandler( void *ptr )
|
|||||||
AlsaMidiData *apiData = static_cast<AlsaMidiData *> (data->apiData);
|
AlsaMidiData *apiData = static_cast<AlsaMidiData *> (data->apiData);
|
||||||
|
|
||||||
long nBytes;
|
long nBytes;
|
||||||
unsigned long long time, lastTime;
|
double time;
|
||||||
bool continueSysex = false;
|
bool continueSysex = false;
|
||||||
bool doDecode = false;
|
bool doDecode = false;
|
||||||
MidiInApi::MidiMessage message;
|
MidiInApi::MidiMessage message;
|
||||||
@@ -1266,14 +1315,33 @@ static void *alsaMidiHandler( void *ptr )
|
|||||||
|
|
||||||
// Method 2: Use the ALSA sequencer event time data.
|
// Method 2: Use the ALSA sequencer event time data.
|
||||||
// (thanks to Pedro Lopez-Cabanillas!).
|
// (thanks to Pedro Lopez-Cabanillas!).
|
||||||
time = ( ev->time.time.tv_sec * 1000000 ) + ( ev->time.time.tv_nsec/1000 );
|
|
||||||
lastTime = time;
|
// Using method from:
|
||||||
time -= apiData->lastTime;
|
// https://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
|
||||||
apiData->lastTime = lastTime;
|
|
||||||
|
// 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 )
|
if ( data->firstMessage == true )
|
||||||
data->firstMessage = false;
|
data->firstMessage = false;
|
||||||
else
|
else
|
||||||
message.timeStamp = time * 0.000001;
|
message.timeStamp = time;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if defined(__RTMIDI_DEBUG__)
|
#if defined(__RTMIDI_DEBUG__)
|
||||||
@@ -1292,13 +1360,7 @@ static void *alsaMidiHandler( void *ptr )
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// As long as we haven't reached our queue size limit, push the message.
|
// As long as we haven't reached our queue size limit, push the message.
|
||||||
if ( data->queue.size < data->queue.ringSize ) {
|
if (!data->queue.push(message))
|
||||||
data->queue.ring[data->queue.back++] = message;
|
|
||||||
if ( data->queue.back == data->queue.ringSize )
|
|
||||||
data->queue.back = 0;
|
|
||||||
data->queue.size++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
std::cerr << "\nMidiInAlsa: message queue limit reached!!\n\n";
|
std::cerr << "\nMidiInAlsa: message queue limit reached!!\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1310,7 +1372,7 @@ static void *alsaMidiHandler( void *ptr )
|
|||||||
return 0;
|
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 );
|
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 ) {
|
while ( snd_seq_query_next_port( seq, pinfo ) >= 0 ) {
|
||||||
unsigned int atyp = snd_seq_port_info_get_type( pinfo );
|
unsigned int atyp = snd_seq_port_info_get_type( pinfo );
|
||||||
if ( ( ( atyp & SND_SEQ_PORT_TYPE_MIDI_GENERIC ) == 0 ) &&
|
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 );
|
unsigned int caps = snd_seq_port_info_get_capability( pinfo );
|
||||||
if ( ( caps & type ) != type ) continue;
|
if ( ( caps & type ) != type ) continue;
|
||||||
if ( count == portNumber ) return 1;
|
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 );
|
snd_seq_get_any_client_info( data->seq, cnum, cinfo );
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << snd_seq_client_info_get_name( cinfo );
|
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 << " "; // 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 << snd_seq_port_info_get_client( pinfo ); // with full portnames added to ensure individual device names
|
||||||
os << ":";
|
os << ":";
|
||||||
@@ -1455,7 +1521,7 @@ std::string MidiInAlsa :: getPortName( unsigned int portNumber )
|
|||||||
return stringName;
|
return stringName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiInAlsa :: openPort( unsigned int portNumber, const std::string portName )
|
void MidiInAlsa :: openPort( unsigned int portNumber, const std::string &portName )
|
||||||
{
|
{
|
||||||
if ( connected_ ) {
|
if ( connected_ ) {
|
||||||
errorString_ = "MidiInAlsa::openPort: a valid connection already exists!";
|
errorString_ = "MidiInAlsa::openPort: a valid connection already exists!";
|
||||||
@@ -1563,7 +1629,7 @@ void MidiInAlsa :: openPort( unsigned int portNumber, const std::string portName
|
|||||||
connected_ = true;
|
connected_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiInAlsa :: openVirtualPort( std::string portName )
|
void MidiInAlsa :: openVirtualPort( const std::string &portName )
|
||||||
{
|
{
|
||||||
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
|
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
|
||||||
if ( data->vport < 0 ) {
|
if ( data->vport < 0 ) {
|
||||||
@@ -1658,7 +1724,7 @@ void MidiInAlsa :: closePort( void )
|
|||||||
// Class Definitions: MidiOutAlsa
|
// Class Definitions: MidiOutAlsa
|
||||||
//*********************************************************************//
|
//*********************************************************************//
|
||||||
|
|
||||||
MidiOutAlsa :: MidiOutAlsa( const std::string clientName ) : MidiOutApi()
|
MidiOutAlsa :: MidiOutAlsa( const std::string &clientName ) : MidiOutApi()
|
||||||
{
|
{
|
||||||
initialize( clientName );
|
initialize( clientName );
|
||||||
}
|
}
|
||||||
@@ -1740,6 +1806,8 @@ std::string MidiOutAlsa :: getPortName( unsigned int portNumber )
|
|||||||
snd_seq_get_any_client_info( data->seq, cnum, cinfo );
|
snd_seq_get_any_client_info( data->seq, cnum, cinfo );
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << snd_seq_client_info_get_name(cinfo);
|
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 << " "; // 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 << snd_seq_port_info_get_client( pinfo ); // with full portnames added to ensure individual device names
|
||||||
os << ":";
|
os << ":";
|
||||||
@@ -1754,7 +1822,7 @@ std::string MidiOutAlsa :: getPortName( unsigned int portNumber )
|
|||||||
return stringName;
|
return stringName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiOutAlsa :: openPort( unsigned int portNumber, const std::string portName )
|
void MidiOutAlsa :: openPort( unsigned int portNumber, const std::string &portName )
|
||||||
{
|
{
|
||||||
if ( connected_ ) {
|
if ( connected_ ) {
|
||||||
errorString_ = "MidiOutAlsa::openPort: a valid connection already exists!";
|
errorString_ = "MidiOutAlsa::openPort: a valid connection already exists!";
|
||||||
@@ -1825,11 +1893,12 @@ void MidiOutAlsa :: closePort( void )
|
|||||||
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
|
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
|
||||||
snd_seq_unsubscribe_port( data->seq, data->subscription );
|
snd_seq_unsubscribe_port( data->seq, data->subscription );
|
||||||
snd_seq_port_subscribe_free( data->subscription );
|
snd_seq_port_subscribe_free( data->subscription );
|
||||||
|
data->subscription = 0;
|
||||||
connected_ = false;
|
connected_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiOutAlsa :: openVirtualPort( std::string portName )
|
void MidiOutAlsa :: openVirtualPort( const std::string &portName )
|
||||||
{
|
{
|
||||||
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
|
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
|
||||||
if ( data->vport < 0 ) {
|
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;
|
int result;
|
||||||
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
|
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
|
||||||
unsigned int nBytes = message->size();
|
unsigned int nBytes = static_cast<unsigned int> (size);
|
||||||
if ( nBytes > data->bufferSize ) {
|
if ( nBytes > data->bufferSize ) {
|
||||||
data->bufferSize = nBytes;
|
data->bufferSize = nBytes;
|
||||||
result = snd_midi_event_resize_buffer ( data->coder, 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_source(&ev, data->vport);
|
||||||
snd_seq_ev_set_subs(&ev);
|
snd_seq_ev_set_subs(&ev);
|
||||||
snd_seq_ev_set_direct(&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 );
|
result = snd_midi_event_encode( data->coder, data->buffer, (long)nBytes, &ev );
|
||||||
if ( result < (int)nBytes ) {
|
if ( result < (int)nBytes ) {
|
||||||
errorString_ = "MidiOutAlsa::sendMessage: event parsing error!";
|
errorString_ = "MidiOutAlsa::sendMessage: event parsing error!";
|
||||||
@@ -1911,6 +1980,34 @@ void MidiOutAlsa :: sendMessage( std::vector<unsigned char> *message )
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <mmsystem.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_SIZE 1024
|
||||||
#define RT_SYSEX_BUFFER_COUNT 4
|
#define RT_SYSEX_BUFFER_COUNT 4
|
||||||
|
|
||||||
@@ -2015,21 +2112,15 @@ static void CALLBACK midiInputCallback( HMIDIIN /*hmin*/,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// As long as we haven't reached our queue size limit, push the message.
|
// As long as we haven't reached our queue size limit, push the message.
|
||||||
if ( data->queue.size < data->queue.ringSize ) {
|
if (!data->queue.push(apiData->message))
|
||||||
data->queue.ring[data->queue.back++] = apiData->message;
|
std::cerr << "\nMidiInWinMM: message queue limit reached!!\n\n";
|
||||||
if ( data->queue.back == data->queue.ringSize )
|
|
||||||
data->queue.back = 0;
|
|
||||||
data->queue.size++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the vector for the next input message.
|
// Clear the vector for the next input message.
|
||||||
apiData->message.bytes.clear();
|
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 );
|
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_ ) {
|
if ( connected_ ) {
|
||||||
errorString_ = "MidiInWinMM::openPort: a valid connection already exists!";
|
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) );
|
result = midiInPrepareHeader( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
|
||||||
if ( result != MMSYSERR_NOERROR ) {
|
if ( result != MMSYSERR_NOERROR ) {
|
||||||
midiInClose( data->inHandle );
|
midiInClose( data->inHandle );
|
||||||
|
data->inHandle = 0;
|
||||||
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (PrepareHeader).";
|
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (PrepareHeader).";
|
||||||
error( RtMidiError::DRIVER_ERROR, errorString_ );
|
error( RtMidiError::DRIVER_ERROR, errorString_ );
|
||||||
return;
|
return;
|
||||||
@@ -2123,6 +2215,7 @@ void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portN
|
|||||||
result = midiInAddBuffer( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
|
result = midiInAddBuffer( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) );
|
||||||
if ( result != MMSYSERR_NOERROR ) {
|
if ( result != MMSYSERR_NOERROR ) {
|
||||||
midiInClose( data->inHandle );
|
midiInClose( data->inHandle );
|
||||||
|
data->inHandle = 0;
|
||||||
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (AddBuffer).";
|
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port (AddBuffer).";
|
||||||
error( RtMidiError::DRIVER_ERROR, errorString_ );
|
error( RtMidiError::DRIVER_ERROR, errorString_ );
|
||||||
return;
|
return;
|
||||||
@@ -2132,6 +2225,7 @@ void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portN
|
|||||||
result = midiInStart( data->inHandle );
|
result = midiInStart( data->inHandle );
|
||||||
if ( result != MMSYSERR_NOERROR ) {
|
if ( result != MMSYSERR_NOERROR ) {
|
||||||
midiInClose( data->inHandle );
|
midiInClose( data->inHandle );
|
||||||
|
data->inHandle = 0;
|
||||||
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port.";
|
errorString_ = "MidiInWinMM::openPort: error starting Windows MM MIDI input port.";
|
||||||
error( RtMidiError::DRIVER_ERROR, errorString_ );
|
error( RtMidiError::DRIVER_ERROR, errorString_ );
|
||||||
return;
|
return;
|
||||||
@@ -2140,7 +2234,7 @@ void MidiInWinMM :: openPort( unsigned int portNumber, const std::string /*portN
|
|||||||
connected_ = true;
|
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.
|
// This function cannot be implemented for the Windows MM MIDI API.
|
||||||
errorString_ = "MidiInWinMM::openVirtualPort: cannot be implemented in 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];
|
delete [] data->sysexBuffer[i];
|
||||||
if ( result != MMSYSERR_NOERROR ) {
|
if ( result != MMSYSERR_NOERROR ) {
|
||||||
midiInClose( data->inHandle );
|
midiInClose( data->inHandle );
|
||||||
|
data->inHandle = 0;
|
||||||
errorString_ = "MidiInWinMM::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader).";
|
errorString_ = "MidiInWinMM::openPort: error closing Windows MM MIDI input port (midiInUnprepareHeader).";
|
||||||
error( RtMidiError::DRIVER_ERROR, errorString_ );
|
error( RtMidiError::DRIVER_ERROR, errorString_ );
|
||||||
return;
|
return;
|
||||||
@@ -2168,6 +2263,7 @@ void MidiInWinMM :: closePort( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
midiInClose( data->inHandle );
|
midiInClose( data->inHandle );
|
||||||
|
data->inHandle = 0;
|
||||||
connected_ = false;
|
connected_ = false;
|
||||||
LeaveCriticalSection( &(data->_mutex) );
|
LeaveCriticalSection( &(data->_mutex) );
|
||||||
}
|
}
|
||||||
@@ -2192,22 +2288,17 @@ std::string MidiInWinMM :: getPortName( unsigned int portNumber )
|
|||||||
|
|
||||||
MIDIINCAPS deviceCaps;
|
MIDIINCAPS deviceCaps;
|
||||||
midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
|
midiInGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIINCAPS));
|
||||||
|
stringName = ConvertToUTF8( deviceCaps.szPname );
|
||||||
#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
|
|
||||||
|
|
||||||
// Next lines added to add the portNumber to the name so that
|
// Next lines added to add the portNumber to the name so that
|
||||||
// the device's names are sure to be listed with individual names
|
// the device's names are sure to be listed with individual names
|
||||||
// even when they have the same brand name
|
// even when they have the same brand name
|
||||||
|
#ifdef RTMIDI_ENSURE_UNIQUE_PORTNAMES
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << " ";
|
os << " ";
|
||||||
os << portNumber;
|
os << portNumber;
|
||||||
stringName += os.str();
|
stringName += os.str();
|
||||||
|
#endif
|
||||||
|
|
||||||
return stringName;
|
return stringName;
|
||||||
}
|
}
|
||||||
@@ -2217,7 +2308,7 @@ std::string MidiInWinMM :: getPortName( unsigned int portNumber )
|
|||||||
// Class Definitions: MidiOutWinMM
|
// Class Definitions: MidiOutWinMM
|
||||||
//*********************************************************************//
|
//*********************************************************************//
|
||||||
|
|
||||||
MidiOutWinMM :: MidiOutWinMM( const std::string clientName ) : MidiOutApi()
|
MidiOutWinMM :: MidiOutWinMM( const std::string &clientName ) : MidiOutApi()
|
||||||
{
|
{
|
||||||
initialize( clientName );
|
initialize( clientName );
|
||||||
}
|
}
|
||||||
@@ -2266,27 +2357,22 @@ std::string MidiOutWinMM :: getPortName( unsigned int portNumber )
|
|||||||
|
|
||||||
MIDIOUTCAPS deviceCaps;
|
MIDIOUTCAPS deviceCaps;
|
||||||
midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
|
midiOutGetDevCaps( portNumber, &deviceCaps, sizeof(MIDIOUTCAPS));
|
||||||
|
stringName = ConvertToUTF8( deviceCaps.szPname );
|
||||||
#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
|
|
||||||
|
|
||||||
// Next lines added to add the portNumber to the name so that
|
// Next lines added to add the portNumber to the name so that
|
||||||
// the device's names are sure to be listed with individual names
|
// the device's names are sure to be listed with individual names
|
||||||
// even when they have the same brand name
|
// even when they have the same brand name
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
|
#ifdef RTMIDI_ENSURE_UNIQUE_PORTNAMES
|
||||||
os << " ";
|
os << " ";
|
||||||
os << portNumber;
|
os << portNumber;
|
||||||
stringName += os.str();
|
stringName += os.str();
|
||||||
|
#endif
|
||||||
|
|
||||||
return stringName;
|
return stringName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string /*portName*/ )
|
void MidiOutWinMM :: openPort( unsigned int portNumber, const std::string &/*portName*/ )
|
||||||
{
|
{
|
||||||
if ( connected_ ) {
|
if ( connected_ ) {
|
||||||
errorString_ = "MidiOutWinMM::openPort: a valid connection already exists!";
|
errorString_ = "MidiOutWinMM::openPort: a valid connection already exists!";
|
||||||
@@ -2330,22 +2416,23 @@ void MidiOutWinMM :: closePort( void )
|
|||||||
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
|
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
|
||||||
midiOutReset( data->outHandle );
|
midiOutReset( data->outHandle );
|
||||||
midiOutClose( data->outHandle );
|
midiOutClose( data->outHandle );
|
||||||
|
data->outHandle = 0;
|
||||||
connected_ = false;
|
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.
|
// This function cannot be implemented for the Windows MM MIDI API.
|
||||||
errorString_ = "MidiOutWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
|
errorString_ = "MidiOutWinMM::openVirtualPort: cannot be implemented in Windows MM MIDI API!";
|
||||||
error( RtMidiError::WARNING, errorString_ );
|
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;
|
if ( !connected_ ) return;
|
||||||
|
|
||||||
unsigned int nBytes = static_cast<unsigned int>(message->size());
|
unsigned int nBytes = static_cast<unsigned int>(size);
|
||||||
if ( nBytes == 0 ) {
|
if ( nBytes == 0 ) {
|
||||||
errorString_ = "MidiOutWinMM::sendMessage: message argument is empty!";
|
errorString_ = "MidiOutWinMM::sendMessage: message argument is empty!";
|
||||||
error( RtMidiError::WARNING, errorString_ );
|
error( RtMidiError::WARNING, errorString_ );
|
||||||
@@ -2354,7 +2441,7 @@ void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
|
|||||||
|
|
||||||
MMRESULT result;
|
MMRESULT result;
|
||||||
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
|
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
|
||||||
if ( message->at(0) == 0xF0 ) { // Sysex message
|
if ( message[0] == 0xF0 ) { // Sysex message
|
||||||
|
|
||||||
// Allocate buffer for sysex data.
|
// Allocate buffer for sysex data.
|
||||||
char *buffer = (char *) malloc( nBytes );
|
char *buffer = (char *) malloc( nBytes );
|
||||||
@@ -2365,7 +2452,7 @@ void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy data to buffer.
|
// 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.
|
// Create and prepare MIDIHDR structure.
|
||||||
MIDIHDR sysex;
|
MIDIHDR sysex;
|
||||||
@@ -2406,7 +2493,7 @@ void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
|
|||||||
DWORD packet;
|
DWORD packet;
|
||||||
unsigned char *ptr = (unsigned char *) &packet;
|
unsigned char *ptr = (unsigned char *) &packet;
|
||||||
for ( unsigned int i=0; i<nBytes; ++i ) {
|
for ( unsigned int i=0; i<nBytes; ++i ) {
|
||||||
*ptr = message->at(i);
|
*ptr = message[i];
|
||||||
++ptr;
|
++ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2436,6 +2523,9 @@ void MidiOutWinMM :: sendMessage( std::vector<unsigned char> *message )
|
|||||||
#include <jack/jack.h>
|
#include <jack/jack.h>
|
||||||
#include <jack/midiport.h>
|
#include <jack/midiport.h>
|
||||||
#include <jack/ringbuffer.h>
|
#include <jack/ringbuffer.h>
|
||||||
|
#ifdef HAVE_SEMAPHORE
|
||||||
|
#include <semaphore.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define JACK_RINGBUFFER_SIZE 16384 // Default size for ringbuffer
|
#define JACK_RINGBUFFER_SIZE 16384 // Default size for ringbuffer
|
||||||
|
|
||||||
@@ -2445,6 +2535,10 @@ struct JackMidiData {
|
|||||||
jack_ringbuffer_t *buffSize;
|
jack_ringbuffer_t *buffSize;
|
||||||
jack_ringbuffer_t *buffMessage;
|
jack_ringbuffer_t *buffMessage;
|
||||||
jack_time_t lastTime;
|
jack_time_t lastTime;
|
||||||
|
#ifdef HAVE_SEMAPHORE
|
||||||
|
sem_t sem_cleanup;
|
||||||
|
sem_t sem_needpost;
|
||||||
|
#endif
|
||||||
MidiInApi :: RtMidiInData *rtMidiIn;
|
MidiInApi :: RtMidiInData *rtMidiIn;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2491,13 +2585,7 @@ static int jackProcessIn( jack_nframes_t nframes, void *arg )
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// As long as we haven't reached our queue size limit, push the message.
|
// As long as we haven't reached our queue size limit, push the message.
|
||||||
if ( rtData->queue.size < rtData->queue.ringSize ) {
|
if (!rtData->queue.push(message))
|
||||||
rtData->queue.ring[rtData->queue.back++] = message;
|
|
||||||
if ( rtData->queue.back == rtData->queue.ringSize )
|
|
||||||
rtData->queue.back = 0;
|
|
||||||
rtData->queue.size++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
std::cerr << "\nMidiInJack: message queue limit reached!!\n\n";
|
std::cerr << "\nMidiInJack: message queue limit reached!!\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2506,7 +2594,7 @@ static int jackProcessIn( jack_nframes_t nframes, void *arg )
|
|||||||
return 0;
|
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 );
|
initialize( clientName );
|
||||||
}
|
}
|
||||||
@@ -2551,7 +2639,7 @@ MidiInJack :: ~MidiInJack()
|
|||||||
delete data;
|
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_);
|
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 ) );
|
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_);
|
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 );
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiOutJack :: MidiOutJack( const std::string clientName ) : MidiOutApi()
|
MidiOutJack :: MidiOutJack( const std::string &clientName ) : MidiOutApi()
|
||||||
{
|
{
|
||||||
initialize( clientName );
|
initialize( clientName );
|
||||||
}
|
}
|
||||||
@@ -2687,6 +2780,10 @@ void MidiOutJack :: initialize( const std::string& clientName )
|
|||||||
|
|
||||||
data->port = NULL;
|
data->port = NULL;
|
||||||
data->client = 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;
|
this->clientName = clientName;
|
||||||
|
|
||||||
connect();
|
connect();
|
||||||
@@ -2725,10 +2822,15 @@ MidiOutJack :: ~MidiOutJack()
|
|||||||
jack_client_close( data->client );
|
jack_client_close( data->client );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SEMAPHORE
|
||||||
|
sem_destroy(&data->sem_cleanup);
|
||||||
|
sem_destroy(&data->sem_needpost);
|
||||||
|
#endif
|
||||||
|
|
||||||
delete data;
|
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_);
|
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() );
|
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_);
|
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
|
||||||
|
|
||||||
@@ -2821,18 +2923,29 @@ void MidiOutJack :: closePort()
|
|||||||
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
|
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
|
||||||
|
|
||||||
if ( data->port == NULL ) return;
|
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 );
|
jack_port_unregister( data->client, data->port );
|
||||||
data->port = NULL;
|
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_);
|
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
|
||||||
|
|
||||||
// Write full message to buffer
|
// Write full message to buffer
|
||||||
jack_ringbuffer_write( data->buffMessage, ( const char * ) &( *message )[0],
|
jack_ringbuffer_write( data->buffMessage, ( const char * ) message,
|
||||||
message->size() );
|
nBytes );
|
||||||
jack_ringbuffer_write( data->buffSize, ( char * ) &nBytes, sizeof( nBytes ) );
|
jack_ringbuffer_write( data->buffSize, ( char * ) &nBytes, sizeof( nBytes ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user