Updated RtAudio/RtMidi for new release, plus additional documentation updates.

This commit is contained in:
Gary Scavone
2019-04-18 09:18:19 -04:00
parent 38970124ec
commit b6143915a9
14 changed files with 1545 additions and 872 deletions

View File

@@ -1,5 +1,5 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(STK, 4.6.0, gary@music.mcgill.ca, stk)
AC_INIT(STK, 4.6.1, gary@music.mcgill.ca, stk)
AC_CONFIG_AUX_DIR(config)
AC_CONFIG_SRCDIR(src/Stk.cpp)
AC_CONFIG_FILES(Makefile src/Makefile projects/demo/Makefile projects/effects/Makefile projects/ragamatic/Makefile projects/examples/Makefile projects/examples/libMakefile projects/eguitar/Makefile)

View File

@@ -2,7 +2,7 @@ The Synthesis ToolKit in C++ (STK)
By Perry R. Cook and Gary P. Scavone, 1995--2019.
v.4.6.1 (18 April 2017)
v.4.6.1 (18 April 2019)
- see github site for complete details (github.com/thestk/stk)
- various documentation updates
- new Recorder (flute a la Verge) class (thanks to Mathias Bredholt)

View File

@@ -7,6 +7,7 @@
and OSS), Macintosh OS X (CoreAudio and Jack), and Windows
(DirectSound, ASIO and WASAPI) operating systems.
RtAudio GitHub site: https://github.com/thestk/rtaudio
RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
RtAudio: realtime audio i/o C++ classes
@@ -45,7 +46,21 @@
#ifndef __RTAUDIO_H
#define __RTAUDIO_H
#define RTAUDIO_VERSION "5.0.0"
#define RTAUDIO_VERSION "5.1.0"
#if defined _WIN32 || defined __CYGWIN__
#if defined(RTAUDIO_EXPORT)
#define RTAUDIO_DLL_PUBLIC __declspec(dllexport)
#else
#define RTAUDIO_DLL_PUBLIC
#endif
#else
#if __GNUC__ >= 4
#define RTAUDIO_DLL_PUBLIC __attribute__( (visibility( "default" )) )
#else
#define RTAUDIO_DLL_PUBLIC
#endif
#endif
#include <string>
#include <vector>
@@ -179,6 +194,7 @@ static const RtAudioStreamStatus RTAUDIO_OUTPUT_UNDERFLOW = 0x2; // The output
\param userData A pointer to optional data provided by the client
when opening the stream (default = NULL).
\return
To continue normal stream operation, the RtAudioCallback function
should return a value of zero. To stop the stream and drain the
output buffer, the function should return a value of one. To abort
@@ -200,7 +216,7 @@ typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer,
*/
/************************************************************************/
class RtAudioError : public std::runtime_error
class RTAUDIO_DLL_PUBLIC RtAudioError : public std::runtime_error
{
public:
//! Defined RtAudioError types.
@@ -260,7 +276,7 @@ typedef void (*RtAudioErrorCallback)( RtAudioError::Type type, const std::string
class RtApi;
class RtAudio
class RTAUDIO_DLL_PUBLIC RtAudio
{
public:
@@ -275,7 +291,8 @@ class RtAudio
WINDOWS_WASAPI, /*!< The Microsoft WASAPI API. */
WINDOWS_ASIO, /*!< The Steinberg Audio Stream I/O API. */
WINDOWS_DS, /*!< The Microsoft DirectSound API. */
RTAUDIO_DUMMY /*!< A compilable but non-functional API. */
RTAUDIO_DUMMY, /*!< A compilable but non-functional API. */
NUM_APIS /*!< Number of values in this enum. */
};
//! The public device information structure for returning queried values.
@@ -387,6 +404,29 @@ class RtAudio
*/
static void getCompiledApi( std::vector<RtAudio::Api> &apis );
//! Return the name of a specified compiled audio API.
/*!
This obtains a short lower-case name used for identification purposes.
This value is guaranteed to remain identical across library versions.
If the API is unknown, this function will return the empty string.
*/
static std::string getApiName( RtAudio::Api api );
//! Return the display name of a specified compiled audio API.
/*!
This obtains a long name used for display purposes.
If the API is unknown, this function will return the empty string.
*/
static std::string getApiDisplayName( RtAudio::Api api );
//! Return the compiled audio API having the given name.
/*!
A case insensitive comparison will check the specified name
against the list of compiled APIs, and return the one which
matches. On failure, the function returns UNSPECIFIED.
*/
static RtAudio::Api getCompiledApiByName( const std::string &name );
//! The class constructor.
/*!
The constructor performs minor initialization tasks. An exception
@@ -583,6 +623,7 @@ class RtAudio
#endif
#include <windows.h>
#include <process.h>
#include <stdint.h>
typedef uintptr_t ThreadHandle;
typedef CRITICAL_SECTION StreamMutex;
@@ -651,7 +692,6 @@ class S24 {
return *this;
}
S24( const S24& v ) { *this = v; }
S24( const double& d ) { *this = (int) d; }
S24( const float& f ) { *this = (int) f; }
S24( const signed short& s ) { *this = (int) s; }
@@ -671,7 +711,7 @@ class S24 {
#include <sstream>
class RtApi
class RTAUDIO_DLL_PUBLIC RtApi
{
public:
@@ -864,7 +904,6 @@ public:
void startStream( void );
void stopStream( void );
void abortStream( void );
long getStreamLatency( void );
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,
@@ -900,7 +939,6 @@ public:
void startStream( void );
void stopStream( void );
void abortStream( void );
long getStreamLatency( void );
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,
@@ -935,7 +973,6 @@ public:
void startStream( void );
void stopStream( void );
void abortStream( void );
long getStreamLatency( void );
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,
@@ -973,7 +1010,6 @@ public:
void startStream( void );
void stopStream( void );
void abortStream( void );
long getStreamLatency( void );
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,
@@ -1003,7 +1039,7 @@ class RtApiWasapi : public RtApi
{
public:
RtApiWasapi();
~RtApiWasapi();
virtual ~RtApiWasapi();
RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_WASAPI; }
unsigned int getDeviceCount( void );

View File

@@ -5,7 +5,8 @@
This class implements some common functionality for the realtime
MIDI input/output subclasses RtMidiIn and RtMidiOut.
RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
RtMidi GitHub site: https://github.com/thestk/rtmidi
RtMidi WWW site: http://www.music.mcgill.ca/~gary/rtmidi/
RtMidi: realtime MIDI i/o C++ classes
Copyright (c) 2003-2019 Gary P. Scavone
@@ -43,7 +44,21 @@
#ifndef RTMIDI_H
#define RTMIDI_H
#define RTMIDI_VERSION "3.0.0"
#if defined _WIN32 || defined __CYGWIN__
#if defined(RTMIDI_EXPORT)
#define RTMIDI_DLL_PUBLIC __declspec(dllexport)
#else
#define RTMIDI_DLL_PUBLIC
#endif
#else
#if __GNUC__ >= 4
#define RTMIDI_DLL_PUBLIC __attribute__( (visibility( "default" )) )
#else
#define RTMIDI_DLL_PUBLIC
#endif
#endif
#define RTMIDI_VERSION "4.0.0"
#include <exception>
#include <iostream>
@@ -60,7 +75,7 @@
*/
/************************************************************************/
class RtMidiError : public std::exception
class RTMIDI_DLL_PUBLIC RtMidiError : public std::exception
{
public:
//! Defined RtMidiError types.
@@ -79,7 +94,8 @@ class RtMidiError : public std::exception
};
//! The constructor.
RtMidiError( const std::string& message, Type type = RtMidiError::UNSPECIFIED ) throw() : message_(message), type_(type) {}
RtMidiError( const std::string& message, Type type = RtMidiError::UNSPECIFIED ) throw()
: message_(message), type_(type) {}
//! The destructor.
virtual ~RtMidiError( void ) throw() {}
@@ -113,10 +129,9 @@ typedef void (*RtMidiErrorCallback)( RtMidiError::Type type, const std::string &
class MidiApi;
class RtMidi
class RTMIDI_DLL_PUBLIC RtMidi
{
public:
//! MIDI API specifier arguments.
enum Api {
UNSPECIFIED, /*!< Search for a working compiled API. */
@@ -124,7 +139,8 @@ class RtMidi
LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */
UNIX_JACK, /*!< The JACK Low-Latency MIDI Server API. */
WINDOWS_MM, /*!< The Microsoft Multimedia MIDI API. */
RTMIDI_DUMMY /*!< A compilable but non-functional API. */
RTMIDI_DUMMY, /*!< A compilable but non-functional API. */
NUM_APIS /*!< Number of values in this enum. */
};
//! A static function to determine the current RtMidi version.
@@ -138,6 +154,29 @@ class RtMidi
*/
static void getCompiledApi( std::vector<RtMidi::Api> &apis ) throw();
//! Return the name of a specified compiled MIDI API.
/*!
This obtains a short lower-case name used for identification purposes.
This value is guaranteed to remain identical across library versions.
If the API is unknown, this function will return the empty string.
*/
static std::string getApiName( RtMidi::Api api );
//! Return the display name of a specified compiled MIDI API.
/*!
This obtains a long name used for display purposes.
If the API is unknown, this function will return the empty string.
*/
static std::string getApiDisplayName( RtMidi::Api api );
//! Return the compiled MIDI API having the given name.
/*!
A case insensitive comparison will check the specified name
against the list of compiled APIs, and return the one which
matches. On failure, the function returns UNSPECIFIED.
*/
static RtMidi::Api getCompiledApiByName( const std::string &name );
//! Pure virtual openPort() function.
virtual void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi" ) ) = 0;
@@ -153,6 +192,9 @@ class RtMidi
//! Pure virtual closePort() function.
virtual void closePort( void ) = 0;
void setClientName( const std::string &clientName );
void setPortName( const std::string &portName );
//! Returns true if a port is open and false if not.
/*!
Note that this only applies to connections made with the openPort()
@@ -168,10 +210,8 @@ class RtMidi
virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 ) = 0;
protected:
RtMidi();
virtual ~RtMidi();
MidiApi *rtapi_;
};
@@ -188,8 +228,6 @@ class RtMidi
time. With the OS-X, Linux ALSA, and JACK MIDI APIs, it is also
possible to open a virtual input port to which other MIDI software
clients can connect.
by Gary P. Scavone, 2003-2019.
*/
/**********************************************************************/
@@ -207,7 +245,7 @@ class RtMidi
//
// **************************************************************** //
class RtMidiIn : public RtMidi
class RTMIDI_DLL_PUBLIC RtMidiIn : public RtMidi
{
public:
@@ -335,7 +373,6 @@ class RtMidiIn : public RtMidi
protected:
void openMidiApi( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit );
};
/**********************************************************************/
@@ -349,15 +386,12 @@ class RtMidiIn : public RtMidi
connect to more than one MIDI device at the same time. With the
OS-X, Linux ALSA and JACK MIDI APIs, it is also possible to open a
virtual port to which other MIDI software clients can connect.
by Gary P. Scavone, 2003-2019.
*/
/**********************************************************************/
class RtMidiOut : public RtMidi
class RTMIDI_DLL_PUBLIC RtMidiOut : public RtMidi
{
public:
//! Default constructor that allows an optional client name.
/*!
An exception will be thrown if a MIDI system initialization error occurs.
@@ -458,7 +492,7 @@ class RtMidiOut : public RtMidi
//
// **************************************************************** //
class MidiApi
class RTMIDI_DLL_PUBLIC MidiApi
{
public:
@@ -468,6 +502,8 @@ class MidiApi
virtual void openPort( unsigned int portNumber, const std::string &portName ) = 0;
virtual void openVirtualPort( const std::string &portName ) = 0;
virtual void closePort( void ) = 0;
virtual void setClientName( const std::string &clientName ) = 0;
virtual void setPortName( const std::string &portName ) = 0;
virtual unsigned int getPortCount( void ) = 0;
virtual std::string getPortName( unsigned int portNumber ) = 0;
@@ -489,7 +525,7 @@ protected:
void *errorCallbackUserData_;
};
class MidiInApi : public MidiApi
class RTMIDI_DLL_PUBLIC MidiInApi : public MidiApi
{
public:
@@ -524,8 +560,7 @@ class MidiInApi : public MidiApi
: 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);
unsigned int size( unsigned int *back=0, unsigned int *front=0 );
};
// The RtMidiInData structure is used to pass private class data to
@@ -544,16 +579,15 @@ class MidiInApi : public MidiApi
// Default constructor.
RtMidiInData()
: ignoreFlags(7), doInput(false), firstMessage(true),
apiData(0), usingCallback(false), userCallback(0), userData(0),
continueSysex(false) {}
: ignoreFlags(7), doInput(false), firstMessage(true), apiData(0), usingCallback(false),
userCallback(0), userData(0), continueSysex(false) {}
};
protected:
RtMidiInData inputData_;
};
class MidiOutApi : public MidiApi
class RTMIDI_DLL_PUBLIC MidiOutApi : public MidiApi
{
public:
@@ -573,12 +607,12 @@ inline void RtMidiIn :: openPort( unsigned int portNumber, const std::string &po
inline void RtMidiIn :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
inline void RtMidiIn :: closePort( void ) { rtapi_->closePort(); }
inline bool RtMidiIn :: isPortOpen() const { return rtapi_->isPortOpen(); }
inline void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData ) { ((MidiInApi *)rtapi_)->setCallback( callback, userData ); }
inline void RtMidiIn :: cancelCallback( void ) { ((MidiInApi *)rtapi_)->cancelCallback(); }
inline void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData ) { static_cast<MidiInApi *>(rtapi_)->setCallback( callback, userData ); }
inline void RtMidiIn :: cancelCallback( void ) { static_cast<MidiInApi *>(rtapi_)->cancelCallback(); }
inline unsigned int RtMidiIn :: getPortCount( void ) { return rtapi_->getPortCount(); }
inline std::string RtMidiIn :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
inline void RtMidiIn :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense ) { ((MidiInApi *)rtapi_)->ignoreTypes( midiSysex, midiTime, midiSense ); }
inline double RtMidiIn :: getMessage( std::vector<unsigned char> *message ) { return ((MidiInApi *)rtapi_)->getMessage( message ); }
inline void RtMidiIn :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense ) { static_cast<MidiInApi *>(rtapi_)->ignoreTypes( midiSysex, midiTime, midiSense ); }
inline double RtMidiIn :: getMessage( std::vector<unsigned char> *message ) { return static_cast<MidiInApi *>(rtapi_)->getMessage( message ); }
inline void RtMidiIn :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
inline RtMidi::Api RtMidiOut :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
@@ -588,207 +622,8 @@ inline void RtMidiOut :: closePort( void ) { rtapi_->closePort(); }
inline bool RtMidiOut :: isPortOpen() const { return rtapi_->isPortOpen(); }
inline unsigned int RtMidiOut :: getPortCount( void ) { return rtapi_->getPortCount(); }
inline std::string RtMidiOut :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
inline void RtMidiOut :: sendMessage( 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 :: sendMessage( const std::vector<unsigned char> *message ) { static_cast<MidiOutApi *>(rtapi_)->sendMessage( &message->at(0), message->size() ); }
inline void RtMidiOut :: sendMessage( const unsigned char *message, size_t size ) { static_cast<MidiOutApi *>(rtapi_)->sendMessage( message, size ); }
inline void RtMidiOut :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); }
// **************************************************************** //
//
// MidiInApi and MidiOutApi subclass prototypes.
//
// **************************************************************** //
#if !defined(__LINUX_ALSA__) && !defined(__UNIX_JACK__) && !defined(__MACOSX_CORE__) && !defined(__WINDOWS_MM__)
#define __RTMIDI_DUMMY__
#endif
#if defined(__MACOSX_CORE__)
class MidiInCore: public MidiInApi
{
public:
MidiInCore( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInCore( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
protected:
void initialize( const std::string& clientName );
};
class MidiOutCore: public MidiOutApi
{
public:
MidiOutCore( const std::string &clientName );
~MidiOutCore( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( const unsigned char *message, size_t size );
protected:
void initialize( const std::string& clientName );
};
#endif
#if defined(__UNIX_JACK__)
class MidiInJack: public MidiInApi
{
public:
MidiInJack( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInJack( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
protected:
std::string clientName;
void connect( void );
void initialize( const std::string& clientName );
};
class MidiOutJack: public MidiOutApi
{
public:
MidiOutJack( const std::string &clientName );
~MidiOutJack( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( const unsigned char *message, size_t size );
protected:
std::string clientName;
void connect( void );
void initialize( const std::string& clientName );
};
#endif
#if defined(__LINUX_ALSA__)
class MidiInAlsa: public MidiInApi
{
public:
MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInAlsa( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
protected:
void initialize( const std::string& clientName );
};
class MidiOutAlsa: public MidiOutApi
{
public:
MidiOutAlsa( const std::string &clientName );
~MidiOutAlsa( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( const unsigned char *message, size_t size );
protected:
void initialize( const std::string& clientName );
};
#endif
#if defined(__WINDOWS_MM__)
class MidiInWinMM: public MidiInApi
{
public:
MidiInWinMM( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInWinMM( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
protected:
void initialize( const std::string& clientName );
};
class MidiOutWinMM: public MidiOutApi
{
public:
MidiOutWinMM( const std::string &clientName );
~MidiOutWinMM( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( const unsigned char *message, size_t size );
protected:
void initialize( const std::string& clientName );
};
#endif
#if defined(__RTMIDI_DUMMY__)
class MidiInDummy: public MidiInApi
{
public:
MidiInDummy( const std::string &/*clientName*/, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) { errorString_ = "MidiInDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
void openVirtualPort( const std::string &/*portName*/ ) {}
void closePort( void ) {}
unsigned int getPortCount( void ) { return 0; }
std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
protected:
void initialize( const std::string& /*clientName*/ ) {}
};
class MidiOutDummy: public MidiOutApi
{
public:
MidiOutDummy( const std::string &/*clientName*/ ) { errorString_ = "MidiOutDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
void openVirtualPort( const std::string &/*portName*/ ) {}
void closePort( void ) {}
unsigned int getPortCount( void ) { return 0; }
std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
void sendMessage( const unsigned char * /*message*/, size_t /*size*/ ) {}
protected:
void initialize( const std::string& /*clientName*/ ) {}
};
#endif
#endif

View File

@@ -1,5 +1,5 @@
# Tcl/Tk Demo GUI for the Synthesis Toolkit (STK)
# by Gary P. Scavone, CCRMA, Stanford University, 1995--2017.
# by Gary P. Scavone, CCRMA, CAML, Stanford & McGill Universities, 1995--2019.
# Set initial control values
set pitch 64.0

View File

@@ -1,6 +1,6 @@
The Synthesis ToolKit in C++ (STK)
By Perry R. Cook and Gary P. Scavone, 1995--2017.
By Perry R. Cook and Gary P. Scavone, 1995--2019.
EFFECTS PROJECT:

View File

@@ -13,7 +13,7 @@
Stanford, bearing the names of Karplus and/or
Strong.
by Perry R. Cook and Gary P. Scavone, 1995--2017.
by Perry R. Cook and Gary P. Scavone, 1995--2019.
*/
/***************************************************/

View File

@@ -24,7 +24,7 @@ namespace stk {
Stanford, bearing the names of Karplus and/or
Strong.
by Perry R. Cook and Gary P. Scavone, 1995--2017.
by Perry R. Cook and Gary P. Scavone, 1995--2019.
*/
/***************************************************/

View File

@@ -8,7 +8,7 @@
sample rates. You can specify the maximum polyphony (maximum
number of simultaneous voices) in Tabla.h.
by Perry R. Cook and Gary P. Scavone, 1995--2017.
by Perry R. Cook and Gary P. Scavone, 1995--2019.
*/
/***************************************************/

View File

@@ -17,7 +17,7 @@ namespace stk {
sample rates. You can specify the maximum polyphony (maximum
number of simultaneous voices) in Tabla.h.
by Perry R. Cook and Gary P. Scavone, 1995--2017.
by Perry R. Cook and Gary P. Scavone, 1995--2019.
*/
/***************************************************/

View File

@@ -8,7 +8,7 @@
sample rates. You can specify the maximum polyphony (maximum
number of simultaneous voices) in VoicDrum.h.
by Perry R. Cook and Gary P. Scavone, 1995--2017.
by Perry R. Cook and Gary P. Scavone, 1995--2019.
*/
/***************************************************/

View File

@@ -17,7 +17,7 @@ namespace stk {
sample rates. You can specify the maximum polyphony (maximum
number of simultaneous voices) in VoicDrum.h.
by Perry R. Cook and Gary P. Scavone, 1995--2017.
by Perry R. Cook and Gary P. Scavone, 1995--2019.
*/
/***************************************************/

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,8 @@
This class implements some common functionality for the realtime
MIDI input/output subclasses RtMidiIn and RtMidiOut.
RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
RtMidi GitHub site: https://github.com/thestk/rtmidi
RtMidi WWW site: http://www.music.mcgill.ca/~gary/rtmidi/
RtMidi: realtime MIDI i/o C++ classes
Copyright (c) 2003-2019 Gary P. Scavone
@@ -47,8 +48,227 @@
#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
// flag can be defined (e.g. in your project file) to disable this behaviour.
//#define RTMIDI_DO_NOT_ENSURE_UNIQUE_PORTNAMES
// **************************************************************** //
//
// MidiInApi and MidiOutApi subclass prototypes.
//
// **************************************************************** //
#if !defined(__LINUX_ALSA__) && !defined(__UNIX_JACK__) && !defined(__MACOSX_CORE__) && !defined(__WINDOWS_MM__)
#define __RTMIDI_DUMMY__
#endif
#if defined(__MACOSX_CORE__)
class MidiInCore: public MidiInApi
{
public:
MidiInCore( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInCore( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
void setClientName( const std::string &clientName );
void setPortName( const std::string &portName );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
protected:
void initialize( const std::string& clientName );
};
class MidiOutCore: public MidiOutApi
{
public:
MidiOutCore( const std::string &clientName );
~MidiOutCore( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
void setClientName( const std::string &clientName );
void setPortName( const std::string &portName );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( const unsigned char *message, size_t size );
protected:
void initialize( const std::string& clientName );
};
#endif
#if defined(__UNIX_JACK__)
class MidiInJack: public MidiInApi
{
public:
MidiInJack( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInJack( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
void setClientName( const std::string &clientName );
void setPortName( const std::string &portName);
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
protected:
std::string clientName;
void connect( void );
void initialize( const std::string& clientName );
};
class MidiOutJack: public MidiOutApi
{
public:
MidiOutJack( const std::string &clientName );
~MidiOutJack( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
void setClientName( const std::string &clientName );
void setPortName( const std::string &portName);
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( const unsigned char *message, size_t size );
protected:
std::string clientName;
void connect( void );
void initialize( const std::string& clientName );
};
#endif
#if defined(__LINUX_ALSA__)
class MidiInAlsa: public MidiInApi
{
public:
MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInAlsa( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
void setClientName( const std::string &clientName );
void setPortName( const std::string &portName);
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
protected:
void initialize( const std::string& clientName );
};
class MidiOutAlsa: public MidiOutApi
{
public:
MidiOutAlsa( const std::string &clientName );
~MidiOutAlsa( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
void setClientName( const std::string &clientName );
void setPortName( const std::string &portName );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( const unsigned char *message, size_t size );
protected:
void initialize( const std::string& clientName );
};
#endif
#if defined(__WINDOWS_MM__)
class MidiInWinMM: public MidiInApi
{
public:
MidiInWinMM( const std::string &clientName, unsigned int queueSizeLimit );
~MidiInWinMM( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
void setClientName( const std::string &clientName );
void setPortName( const std::string &portName );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
protected:
void initialize( const std::string& clientName );
};
class MidiOutWinMM: public MidiOutApi
{
public:
MidiOutWinMM( const std::string &clientName );
~MidiOutWinMM( void );
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
void openPort( unsigned int portNumber, const std::string &portName );
void openVirtualPort( const std::string &portName );
void closePort( void );
void setClientName( const std::string &clientName );
void setPortName( const std::string &portName );
unsigned int getPortCount( void );
std::string getPortName( unsigned int portNumber );
void sendMessage( const unsigned char *message, size_t size );
protected:
void initialize( const std::string& clientName );
};
#endif
#if defined(__RTMIDI_DUMMY__)
class MidiInDummy: public MidiInApi
{
public:
MidiInDummy( const std::string &/*clientName*/, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) { errorString_ = "MidiInDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
void openVirtualPort( const std::string &/*portName*/ ) {}
void closePort( void ) {}
void setClientName( const std::string &/*clientName*/ ) {};
void setPortName( const std::string &/*portName*/ ) {};
unsigned int getPortCount( void ) { return 0; }
std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
protected:
void initialize( const std::string& /*clientName*/ ) {}
};
class MidiOutDummy: public MidiOutApi
{
public:
MidiOutDummy( const std::string &/*clientName*/ ) { errorString_ = "MidiOutDummy: This class provides no functionality."; error( RtMidiError::WARNING, errorString_ ); }
RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; }
void openPort( unsigned int /*portNumber*/, const std::string &/*portName*/ ) {}
void openVirtualPort( const std::string &/*portName*/ ) {}
void closePort( void ) {}
void setClientName( const std::string &/*clientName*/ ) {};
void setPortName( const std::string &/*portName*/ ) {};
unsigned int getPortCount( void ) { return 0; }
std::string getPortName( unsigned int /*portNumber*/ ) { return ""; }
void sendMessage( const unsigned char * /*message*/, size_t /*size*/ ) {}
protected:
void initialize( const std::string& /*clientName*/ ) {}
};
#endif
//*********************************************************************//
// RtMidi Definitions
@@ -70,29 +290,92 @@ std::string RtMidi :: getVersion( void ) throw()
return std::string( RTMIDI_VERSION );
}
void RtMidi :: getCompiledApi( std::vector<RtMidi::Api> &apis ) throw()
{
apis.clear();
// Define API names and display names.
// Must be in same order as API enum.
extern "C" {
const char* rtmidi_api_names[][2] = {
{ "unspecified" , "Unknown" },
{ "core" , "CoreMidi" },
{ "alsa" , "ALSA" },
{ "jack" , "Jack" },
{ "winmm" , "Windows MultiMedia" },
{ "dummy" , "Dummy" },
};
const unsigned int rtmidi_num_api_names =
sizeof(rtmidi_api_names)/sizeof(rtmidi_api_names[0]);
// The order here will control the order of RtMidi's API search in
// the constructor.
extern "C" const RtMidi::Api rtmidi_compiled_apis[] = {
#if defined(__MACOSX_CORE__)
apis.push_back( MACOSX_CORE );
RtMidi::MACOSX_CORE,
#endif
#if defined(__LINUX_ALSA__)
apis.push_back( LINUX_ALSA );
RtMidi::LINUX_ALSA,
#endif
#if defined(__UNIX_JACK__)
apis.push_back( UNIX_JACK );
RtMidi::UNIX_JACK,
#endif
#if defined(__WINDOWS_MM__)
apis.push_back( WINDOWS_MM );
RtMidi::WINDOWS_MM,
#endif
#if defined(__RTMIDI_DUMMY__)
apis.push_back( RTMIDI_DUMMY );
RtMidi::RTMIDI_DUMMY,
#endif
RtMidi::UNSPECIFIED,
};
extern "C" const unsigned int rtmidi_num_compiled_apis =
sizeof(rtmidi_compiled_apis)/sizeof(rtmidi_compiled_apis[0])-1;
}
// This is a compile-time check that rtmidi_num_api_names == RtMidi::NUM_APIS.
// If the build breaks here, check that they match.
template<bool b> class StaticAssert { private: StaticAssert() {} };
template<> class StaticAssert<true>{ public: StaticAssert() {} };
class StaticAssertions { StaticAssertions() {
StaticAssert<rtmidi_num_api_names == RtMidi::NUM_APIS>();
}};
void RtMidi :: getCompiledApi( std::vector<RtMidi::Api> &apis ) throw()
{
apis = std::vector<RtMidi::Api>(rtmidi_compiled_apis,
rtmidi_compiled_apis + rtmidi_num_compiled_apis);
}
std::string RtMidi :: getApiName( RtMidi::Api api )
{
if (api < 0 || api >= RtMidi::NUM_APIS)
return "";
return rtmidi_api_names[api][0];
}
std::string RtMidi :: getApiDisplayName( RtMidi::Api api )
{
if (api < 0 || api >= RtMidi::NUM_APIS)
return "Unknown";
return rtmidi_api_names[api][1];
}
RtMidi::Api RtMidi :: getCompiledApiByName( const std::string &name )
{
unsigned int i=0;
for (i = 0; i < rtmidi_num_compiled_apis; ++i)
if (name == rtmidi_api_names[rtmidi_compiled_apis[i]][0])
return rtmidi_compiled_apis[i];
return RtMidi::UNSPECIFIED;
}
void RtMidi :: setClientName( const std::string &clientName )
{
rtapi_->setClientName( clientName );
}
void RtMidi :: setPortName( const std::string &portName )
{
rtapi_->setPortName( portName );
}
//*********************************************************************//
// RtMidiIn Definitions
//*********************************************************************//
@@ -124,7 +407,7 @@ void RtMidiIn :: openMidiApi( RtMidi::Api api, const std::string &clientName, un
#endif
}
RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit )
RTMIDI_DLL_PUBLIC RtMidiIn :: RtMidiIn( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit )
: RtMidi()
{
if ( api != UNSPECIFIED ) {
@@ -192,7 +475,7 @@ void RtMidiOut :: openMidiApi( RtMidi::Api api, const std::string &clientName )
#endif
}
RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string &clientName)
RTMIDI_DLL_PUBLIC RtMidiOut :: RtMidiOut( RtMidi::Api api, const std::string &clientName)
{
if ( api != UNSPECIFIED ) {
// Attempt to open the specified API.
@@ -479,10 +762,12 @@ static void midiInputCallback( const MIDIPacketList *list, void *procRef, void *
// function.
nBytes = packet->length;
if ( nBytes == 0 ) continue;
if ( nBytes == 0 ) {
packet = MIDIPacketNext( packet );
continue;
}
// Calculate time stamp.
if ( data->firstMessage ) {
message.timeStamp = 0.0;
data->firstMessage = false;
@@ -497,11 +782,10 @@ static void midiInputCallback( const MIDIPacketList *list, void *procRef, void *
if ( !continueSysex )
message.timeStamp = time * 0.000000001;
}
apiData->lastTime = packet->timeStamp;
if ( apiData->lastTime == 0 ) { // this happens when receiving asynchronous sysex messages
apiData->lastTime = AudioGetCurrentHostTime();
}
//std::cout << "TimeStamp = " << packet->timeStamp << std::endl;
// Track whether any non-filtered messages were found in this
// packet for timestamp calculation
bool foundNonFiltered = false;
iByte = 0;
if ( continueSysex ) {
@@ -570,6 +854,7 @@ static void midiInputCallback( const MIDIPacketList *list, void *procRef, void *
// Copy the MIDI data to our vector.
if ( size ) {
foundNonFiltered = true;
message.bytes.assign( &packet->data[iByte], &packet->data[iByte+size] );
if ( !continueSysex ) {
// If not a continuing sysex message, invoke the user callback function or queue the message.
@@ -588,19 +873,29 @@ static void midiInputCallback( const MIDIPacketList *list, void *procRef, void *
}
}
}
// Save the time of the last non-filtered message
if ( foundNonFiltered ) {
apiData->lastTime = packet->timeStamp;
if ( apiData->lastTime == 0 ) { // this happens when receiving asynchronous sysex messages
apiData->lastTime = AudioGetCurrentHostTime();
}
}
packet = MIDIPacketNext(packet);
}
}
MidiInCore :: MidiInCore( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
MidiInCore :: MidiInCore( const std::string &clientName, unsigned int queueSizeLimit )
: MidiInApi( queueSizeLimit )
{
initialize( clientName );
MidiInCore::initialize( clientName );
}
MidiInCore :: ~MidiInCore( void )
{
// Close a connection if it exists.
closePort();
MidiInCore::closePort();
// Cleanup.
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
@@ -658,9 +953,12 @@ void MidiInCore :: openPort( unsigned int portNumber, const std::string &portNam
MIDIPortRef port;
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
OSStatus result = MIDIInputPortCreate( data->client,
CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
portNameRef,
midiInputCallback, (void *)&inputData_, &port );
CFRelease( portNameRef );
if ( result != noErr ) {
MIDIClientDispose( data->client );
errorString_ = "MidiInCore::openPort: error creating OS-X MIDI input port.";
@@ -700,9 +998,12 @@ void MidiInCore :: openVirtualPort( const std::string &portName )
// Create a virtual MIDI input destination.
MIDIEndpointRef endpoint;
CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
OSStatus result = MIDIDestinationCreate( data->client,
CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
portNameRef,
midiInputCallback, (void *)&inputData_, &endpoint );
CFRelease( portNameRef );
if ( result != noErr ) {
errorString_ = "MidiInCore::openVirtualPort: error creating virtual OS-X MIDI destination.";
error( RtMidiError::DRIVER_ERROR, errorString_ );
@@ -730,6 +1031,22 @@ void MidiInCore :: closePort( void )
connected_ = false;
}
void MidiInCore :: setClientName ( const std::string& )
{
errorString_ = "MidiInCore::setClientName: this function is not implemented for the MACOSX_CORE API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiInCore :: setPortName ( const std::string& )
{
errorString_ = "MidiInCore::setPortName: this function is not implemented for the MACOSX_CORE API!";
error( RtMidiError::WARNING, errorString_ );
}
unsigned int MidiInCore :: getPortCount()
{
CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
@@ -798,6 +1115,7 @@ CFStringRef EndpointName( MIDIEndpointRef endpoint, bool isExternal )
// prepend the device name to the entity name
if ( CFStringGetLength( result ) > 0 )
CFStringInsert( result, 0, CFSTR(" ") );
CFStringInsert( result, 0, str );
}
CFRelease( str );
@@ -844,7 +1162,8 @@ static CFStringRef ConnectedEndpointName( MIDIEndpointRef endpoint )
if ( str != NULL ) {
if ( anyStrings )
CFStringAppend( result, CFSTR(", ") );
else anyStrings = true;
else
anyStrings = true;
CFStringAppend( result, str );
CFRelease( str );
}
@@ -891,15 +1210,16 @@ std::string MidiInCore :: getPortName( unsigned int portNumber )
// Class Definitions: MidiOutCore
//*********************************************************************//
MidiOutCore :: MidiOutCore( const std::string &clientName ) : MidiOutApi()
MidiOutCore :: MidiOutCore( const std::string &clientName )
: MidiOutApi()
{
initialize( clientName );
MidiOutCore::initialize( clientName );
}
MidiOutCore :: ~MidiOutCore( void )
{
// Close a connection if it exists.
closePort();
MidiOutCore::closePort();
// Cleanup.
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
@@ -987,9 +1307,7 @@ void MidiOutCore :: openPort( unsigned int portNumber, const std::string &portNa
MIDIPortRef port;
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
OSStatus result = MIDIOutputPortCreate( data->client,
portNameRef,
&port );
OSStatus result = MIDIOutputPortCreate( data->client, portNameRef, &port );
CFRelease( portNameRef );
if ( result != noErr ) {
MIDIClientDispose( data->client );
@@ -1031,6 +1349,22 @@ void MidiOutCore :: closePort( void )
connected_ = false;
}
void MidiOutCore :: setClientName ( const std::string& )
{
errorString_ = "MidiOutCore::setClientName: this function is not implemented for the MACOSX_CORE API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiOutCore :: setPortName ( const std::string& )
{
errorString_ = "MidiOutCore::setPortName: this function is not implemented for the MACOSX_CORE API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiOutCore :: openVirtualPort( const std::string &portName )
{
CoreMidiData *data = static_cast<CoreMidiData *> (apiData_);
@@ -1043,9 +1377,10 @@ void MidiOutCore :: openVirtualPort( const std::string &portName )
// Create a virtual MIDI output source.
MIDIEndpointRef endpoint;
OSStatus result = MIDISourceCreate( data->client,
CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII ),
&endpoint );
CFStringRef portNameRef = CFStringCreateWithCString( NULL, portName.c_str(), kCFStringEncodingASCII );
OSStatus result = MIDISourceCreate( data->client, portNameRef, &endpoint );
CFRelease( portNameRef );
if ( result != noErr ) {
errorString_ = "MidiOutCore::initialize: error creating OS-X virtual MIDI source.";
error( RtMidiError::DRIVER_ERROR, errorString_ );
@@ -1284,6 +1619,8 @@ static void *alsaMidiHandler( void *ptr )
break;
}
}
doDecode = true;
break;
default:
doDecode = true;
@@ -1320,21 +1657,25 @@ static void *alsaMidiHandler( void *ptr )
// https://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
// Perform the carry for the later subtraction by updating y.
// Temp var y is timespec because computation requires signed types,
// while snd_seq_real_time_t has unsigned types.
snd_seq_real_time_t &x( ev->time.time );
snd_seq_real_time_t &y(apiData->lastTime);
struct timespec y;
y.tv_nsec = apiData->lastTime.tv_nsec;
y.tv_sec = apiData->lastTime.tv_sec;
if ( x.tv_nsec < y.tv_nsec ) {
int nsec = (y.tv_nsec - x.tv_nsec) / 1000000000 + 1;
int nsec = (y.tv_nsec - (int)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;
int nsec = ((int)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;
time = (int)x.tv_sec - y.tv_sec + ((int)x.tv_nsec - y.tv_nsec)*1e-9;
apiData->lastTime = ev->time.time;
@@ -1372,15 +1713,16 @@ static void *alsaMidiHandler( void *ptr )
return 0;
}
MidiInAlsa :: MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
MidiInAlsa :: MidiInAlsa( const std::string &clientName, unsigned int queueSizeLimit )
: MidiInApi( queueSizeLimit )
{
initialize( clientName );
MidiInAlsa::initialize( clientName );
}
MidiInAlsa :: ~MidiInAlsa()
{
// Close a connection if it exists.
closePort();
MidiInAlsa::closePort();
// Shutdown the input thread.
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
@@ -1719,6 +2061,24 @@ void MidiInAlsa :: closePort( void )
}
}
void MidiInAlsa :: setClientName( const std::string &clientName )
{
AlsaMidiData *data = static_cast<AlsaMidiData *> ( apiData_ );
snd_seq_set_client_name( data->seq, clientName.c_str() );
}
void MidiInAlsa :: setPortName( const std::string &portName )
{
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
snd_seq_port_info_t *pinfo;
snd_seq_port_info_alloca( &pinfo );
snd_seq_get_port_info( data->seq, data->vport, pinfo );
snd_seq_port_info_set_name( pinfo, portName.c_str() );
snd_seq_set_port_info( data->seq, data->vport, pinfo );
}
//*********************************************************************//
// API: LINUX ALSA
// Class Definitions: MidiOutAlsa
@@ -1726,13 +2086,13 @@ void MidiInAlsa :: closePort( void )
MidiOutAlsa :: MidiOutAlsa( const std::string &clientName ) : MidiOutApi()
{
initialize( clientName );
MidiOutAlsa::initialize( clientName );
}
MidiOutAlsa :: ~MidiOutAlsa()
{
// Close a connection if it exists.
closePort();
MidiOutAlsa::closePort();
// Cleanup.
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
@@ -1898,6 +2258,24 @@ void MidiOutAlsa :: closePort( void )
}
}
void MidiOutAlsa :: setClientName( const std::string &clientName )
{
AlsaMidiData *data = static_cast<AlsaMidiData *> ( apiData_ );
snd_seq_set_client_name( data->seq, clientName.c_str() );
}
void MidiOutAlsa :: setPortName( const std::string &portName )
{
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
snd_seq_port_info_t *pinfo;
snd_seq_port_info_alloca( &pinfo );
snd_seq_get_port_info( data->seq, data->vport, pinfo );
snd_seq_port_info_set_name( pinfo, portName.c_str() );
snd_seq_set_port_info( data->seq, data->vport, pinfo );
}
void MidiOutAlsa :: openVirtualPort( const std::string &portName )
{
AlsaMidiData *data = static_cast<AlsaMidiData *> (apiData_);
@@ -2045,7 +2423,6 @@ static void CALLBACK midiInputCallback( HMIDIIN /*hmin*/,
data->firstMessage = false;
}
else apiData->message.timeStamp = (double) ( timestamp - apiData->lastTime ) * 0.001;
apiData->lastTime = timestamp;
if ( inputStatus == MIM_DATA ) { // Channel or system message
@@ -2106,6 +2483,9 @@ static void CALLBACK midiInputCallback( HMIDIIN /*hmin*/,
else return;
}
// Save the time of the last non-filtered message
apiData->lastTime = timestamp;
if ( data->usingCallback ) {
RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData );
@@ -2120,15 +2500,16 @@ static void CALLBACK midiInputCallback( HMIDIIN /*hmin*/,
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 );
MidiInWinMM::initialize( clientName );
}
MidiInWinMM :: ~MidiInWinMM()
{
// Close a connection if it exists.
closePort();
MidiInWinMM::closePort();
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
DeleteCriticalSection( &(data->_mutex) );
@@ -2269,6 +2650,22 @@ void MidiInWinMM :: closePort( void )
}
}
void MidiInWinMM :: setClientName ( const std::string& )
{
errorString_ = "MidiInWinMM::setClientName: this function is not implemented for the WINDOWS_MM API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiInWinMM :: setPortName ( const std::string& )
{
errorString_ = "MidiInWinMM::setPortName: this function is not implemented for the WINDOWS_MM API!";
error( RtMidiError::WARNING, errorString_ );
}
unsigned int MidiInWinMM :: getPortCount()
{
return midiInGetNumDevs();
@@ -2293,7 +2690,7 @@ std::string MidiInWinMM :: getPortName( unsigned int portNumber )
// Next lines added to add the portNumber to the name so that
// the device's names are sure to be listed with individual names
// even when they have the same brand name
#ifdef RTMIDI_ENSURE_UNIQUE_PORTNAMES
#ifndef RTMIDI_DO_NOT_ENSURE_UNIQUE_PORTNAMES
std::ostringstream os;
os << " ";
os << portNumber;
@@ -2310,13 +2707,13 @@ std::string MidiInWinMM :: getPortName( unsigned int portNumber )
MidiOutWinMM :: MidiOutWinMM( const std::string &clientName ) : MidiOutApi()
{
initialize( clientName );
MidiOutWinMM::initialize( clientName );
}
MidiOutWinMM :: ~MidiOutWinMM()
{
// Close a connection if it exists.
closePort();
MidiOutWinMM::closePort();
// Cleanup.
WinMidiData *data = static_cast<WinMidiData *> (apiData_);
@@ -2363,7 +2760,7 @@ std::string MidiOutWinMM :: getPortName( unsigned int portNumber )
// the device's names are sure to be listed with individual names
// even when they have the same brand name
std::ostringstream os;
#ifdef RTMIDI_ENSURE_UNIQUE_PORTNAMES
#ifndef RTMIDI_DO_NOT_ENSURE_UNIQUE_PORTNAMES
os << " ";
os << portNumber;
stringName += os.str();
@@ -2421,6 +2818,22 @@ void MidiOutWinMM :: closePort( void )
}
}
void MidiOutWinMM :: setClientName ( const std::string& )
{
errorString_ = "MidiOutWinMM::setClientName: this function is not implemented for the WINDOWS_MM API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiOutWinMM :: setPortName ( const std::string& )
{
errorString_ = "MidiOutWinMM::setPortName: this function is not implemented for the WINDOWS_MM API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiOutWinMM :: openVirtualPort( const std::string &/*portName*/ )
{
// This function cannot be implemented for the Windows MM MIDI API.
@@ -2556,29 +2969,64 @@ static int jackProcessIn( jack_nframes_t nframes, void *arg )
// Is port created?
if ( jData->port == NULL ) return 0;
void *buff = jack_port_get_buffer( jData->port, nframes );
bool& continueSysex = rtData->continueSysex;
unsigned char& ignoreFlags = rtData->ignoreFlags;
// We have midi events in buffer
int evCount = jack_midi_get_event_count( buff );
for (int j = 0; j < evCount; j++) {
MidiInApi::MidiMessage message;
message.bytes.clear();
MidiInApi::MidiMessage& message = rtData->message;
jack_midi_event_get( &event, buff, j );
for ( unsigned int i = 0; i < event.size; i++ )
message.bytes.push_back( event.buffer[i] );
// Compute the delta time.
time = jack_get_time();
if ( rtData->firstMessage == true )
if ( rtData->firstMessage == true ) {
message.timeStamp = 0.0;
rtData->firstMessage = false;
else
} else
message.timeStamp = ( time - jData->lastTime ) * 0.000001;
jData->lastTime = time;
if ( !rtData->continueSysex ) {
if ( !continueSysex )
message.bytes.clear();
if ( !( ( continueSysex || event.buffer[0] == 0xF0 ) && ( ignoreFlags & 0x01 ) ) ) {
// Unless this is a (possibly continued) SysEx message and we're ignoring SysEx,
// copy the event buffer into the MIDI message struct.
for ( unsigned int i = 0; i < event.size; i++ )
message.bytes.push_back( event.buffer[i] );
}
switch ( event.buffer[0] ) {
case 0xF0:
// Start of a SysEx message
continueSysex = event.buffer[event.size - 1] != 0xF7;
if ( ignoreFlags & 0x01 ) continue;
break;
case 0xF1:
case 0xF8:
// MIDI Time Code or Timing Clock message
if ( ignoreFlags & 0x02 ) continue;
break;
case 0xFE:
// Active Sensing message
if ( ignoreFlags & 0x04 ) continue;
break;
default:
if ( continueSysex ) {
// Continuation of a SysEx message
continueSysex = event.buffer[event.size - 1] != 0xF7;
if ( ignoreFlags & 0x01 ) continue;
}
// All other MIDI messages
}
if ( !continueSysex ) {
// If not a continuation of a SysEx message,
// invoke the user callback function or queue the message.
if ( rtData->usingCallback ) {
RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) rtData->userCallback;
callback( message.timeStamp, &message.bytes, rtData->userData );
@@ -2594,9 +3042,10 @@ static int jackProcessIn( jack_nframes_t nframes, void *arg )
return 0;
}
MidiInJack :: MidiInJack( const std::string &clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit )
MidiInJack :: MidiInJack( const std::string &clientName, unsigned int queueSizeLimit )
: MidiInApi( queueSizeLimit )
{
initialize( clientName );
MidiInJack::initialize( clientName );
}
void MidiInJack :: initialize( const std::string& clientName )
@@ -2632,7 +3081,7 @@ void MidiInJack :: connect()
MidiInJack :: ~MidiInJack()
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
closePort();
MidiInJack::closePort();
if ( data->client )
jack_client_close( data->client );
@@ -2659,6 +3108,8 @@ void MidiInJack :: openPort( unsigned int portNumber, const std::string &portNam
// Connecting to the output
std::string name = getPortName( portNumber );
jack_connect( data->client, name.c_str(), jack_port_name( data->port ) );
connected_ = true;
}
void MidiInJack :: openVirtualPort( const std::string &portName )
@@ -2714,7 +3165,9 @@ std::string MidiInJack :: getPortName( unsigned int portNumber )
return retStr;
}
if ( ports[portNumber] == NULL ) {
unsigned int i;
for ( i=0; i<portNumber && ports[i]; i++ ) {}
if ( i < portNumber || !ports[portNumber] ) {
std::ostringstream ost;
ost << "MidiInJack::getPortName: the 'portNumber' argument (" << portNumber << ") is invalid.";
errorString_ = ost.str();
@@ -2722,7 +3175,7 @@ std::string MidiInJack :: getPortName( unsigned int portNumber )
}
else retStr.assign( ports[portNumber] );
free( ports );
jack_free( ports );
return retStr;
}
@@ -2733,6 +3186,26 @@ void MidiInJack :: closePort()
if ( data->port == NULL ) return;
jack_port_unregister( data->client, data->port );
data->port = NULL;
connected_ = false;
}
void MidiInJack:: setClientName( const std::string& )
{
errorString_ = "MidiInJack::setClientName: this function is not implemented for the UNIX_JACK API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiInJack :: setPortName( const std::string &portName )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
#ifdef JACK_HAS_PORT_RENAME
jack_port_rename( data->client, data->port, portName.c_str() );
#else
jack_port_set_name( data->port, portName.c_str() );
#endif
}
//*********************************************************************//
@@ -2770,7 +3243,7 @@ static int jackProcessOut( jack_nframes_t nframes, void *arg )
MidiOutJack :: MidiOutJack( const std::string &clientName ) : MidiOutApi()
{
initialize( clientName );
MidiOutJack::initialize( clientName );
}
void MidiOutJack :: initialize( const std::string& clientName )
@@ -2813,7 +3286,7 @@ void MidiOutJack :: connect()
MidiOutJack :: ~MidiOutJack()
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
closePort();
MidiOutJack::closePort();
// Cleanup
jack_ringbuffer_free( data->buffSize );
@@ -2850,6 +3323,8 @@ void MidiOutJack :: openPort( unsigned int portNumber, const std::string &portNa
// Connecting to the output
std::string name = getPortName( portNumber );
jack_connect( data->client, jack_port_name( data->port ), name.c_str() );
connected_ = true;
}
void MidiOutJack :: openVirtualPort( const std::string &portName )
@@ -2926,8 +3401,7 @@ void MidiOutJack :: closePort()
#ifdef HAVE_SEMAPHORE
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != -1)
{
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 );
@@ -2936,6 +3410,26 @@ void MidiOutJack :: closePort()
jack_port_unregister( data->client, data->port );
data->port = NULL;
connected_ = false;
}
void MidiOutJack:: setClientName( const std::string& )
{
errorString_ = "MidiOutJack::setClientName: this function is not implemented for the UNIX_JACK API!";
error( RtMidiError::WARNING, errorString_ );
}
void MidiOutJack :: setPortName( const std::string &portName )
{
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
#ifdef JACK_HAS_PORT_RENAME
jack_port_rename( data->client, data->port, portName.c_str() );
#else
jack_port_set_name( data->port, portName.c_str() );
#endif
}
void MidiOutJack :: sendMessage( const unsigned char *message, size_t size )
@@ -2944,8 +3438,7 @@ void MidiOutJack :: sendMessage( const unsigned char *message, size_t size )
JackMidiData *data = static_cast<JackMidiData *> (apiData_);
// Write full message to buffer
jack_ringbuffer_write( data->buffMessage, ( const char * ) message,
nBytes );
jack_ringbuffer_write( data->buffMessage, ( const char * ) message, nBytes );
jack_ringbuffer_write( data->buffSize, ( char * ) &nBytes, sizeof( nBytes ) );
}