add RtMidi for eventual MIDI support

This commit is contained in:
tildearrow 2022-02-13 15:02:43 -05:00
parent 65e3e623f2
commit aa0e318543
51 changed files with 11881 additions and 0 deletions

View File

@ -36,6 +36,7 @@ option(BUILD_GUI "Build the tracker (disable to build only a headless player)" $
option(WITH_JACK "Whether to build with JACK support. Auto-detects if JACK is available" ${WITH_JACK_DEFAULT})
option(SYSTEM_FMT "Use a system-installed version of fmt instead of the vendored one" OFF)
option(SYSTEM_LIBSNDFILE "Use a system-installed version of libsndfile instead of the vendored one" OFF)
option(SYSTEM_RTMIDI "Use a system-installed version of RtMidi instead of the vendored one" OFF)
option(SYSTEM_ZLIB "Use a system-installed version of zlib instead of the vendored one" OFF)
option(SYSTEM_SDL2 "Use a system-installed version of SDL2 instead of the vendored one" ${SYSTEM_SDL2_DEFAULT})
option(WARNINGS_ARE_ERRORS "Whether warnings in furnace's C++ code should be treated as errors" OFF)
@ -102,6 +103,22 @@ else()
message(STATUS "Using vendored libsndfile")
endif()
if (SYSTEM_RTMIDI)
find_package(PkgConfig REQUIRED)
pkg_check_modules(RTMIDI REQUIRED rtmidi)
list(APPEND DEPENDENCIES_INCLUDE_DIRS ${RTMIDI_INCLUDE_DIRS})
list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${RTMIDI_CFLAGS_OTHER})
list(APPEND DEPENDENCIES_LIBRARIES ${RTMIDI_LIBRARIES})
list(APPEND DEPENDENCIES_LIBRARY_DIRS ${RTMIDI_LIBRARY_DIRS})
list(APPEND DEPENDENCIES_LINK_OPTIONS ${RTMIDI_LDFLAGS_OTHER})
list(APPEND DEPENDENCIES_LEGACY_LDFLAGS ${RTMIDI_LDFLAGS})
message(STATUS "Using system-installed RtMidi")
else()
add_subdirectory(extern/rtmidi EXCLUDE_FROM_ALL)
list(APPEND DEPENDENCIES_LIBRARIES rtmidi)
message(STATUS "Using vendored RtMidi")
endif()
if (SYSTEM_ZLIB)
find_package(PkgConfig REQUIRED)
pkg_check_modules(ZLIB REQUIRED zlib)

278
extern/rtmidi/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,278 @@
# 2018 (c) Juan G. Victores, Bartek Łukawski, Stephen Sinclair
# CopyPolicy: RtMidi license.
# additional modifications for Furnace by tildearrow.
# Set minimum CMake required version for this project.
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
# Define a C++ project.
project(RtMidi LANGUAGES CXX C)
# standards version
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Check for Jack (any OS)
# RtMidi JACK is not going to be used as I will use my own JACK MIDI implementation.
set(HAVE_JACK FALSE)
#find_library(JACK_LIB jack)
#find_package(PkgConfig)
#pkg_check_modules(jack jack)
#if(JACK_LIB OR jack_FOUND)
# set(HAVE_JACK TRUE)
#endif()
# Necessary for Windows
#if(WIN32)
# set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
#endif()
# Standard CMake options
option(BUILD_SHARED_LIBS "Build as shared library" OFF)
#if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
# set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug;Release;RelWithDebInfo;MinSizeRel")
#endif()
#if(WINDOWS)
# set(CMAKE_DEBUG_POSTFIX d CACHE STRING "Postfix for debug version of library")
#endif()
# Build Options
#set(RTMIDI_TARGETNAME_UNINSTALL "uninstall" CACHE STRING "Name of 'uninstall' build target")
# API Options
#option(RTMIDI_API_JACK "Compile with JACK support." ${HAVE_JACK})
if(UNIX AND NOT APPLE)
option(RTMIDI_API_ALSA "Compile with ALSA support." ON)
endif()
option(RTMIDI_API_WINMM "Compile with WINMM support." ${WIN32})
option(RTMIDI_API_CORE "Compile with CoreMIDI support." ${APPLE})
# Add -Wall if possible
#if (CMAKE_COMPILER_IS_GNUCXX)
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
#endif (CMAKE_COMPILER_IS_GNUCXX)
# Add debug flags
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-D__RTMIDI_DEBUG__)
if (CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
endif (CMAKE_COMPILER_IS_GNUCXX)
endif ()
# Read libtool version info from configure.ac
#set(R "m4_define\\(\\[lt_([a-z]+)\\], ([0-9]+)\\)")
#file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/configure.ac" CONFIGAC
# REGEX ${R})
#foreach(_S ${CONFIGAC})
# string(REGEX REPLACE ${R} "\\1" k ${_S})
# string(REGEX REPLACE ${R} "\\2" v ${_S})
# set(SO_${k} ${v})
#endforeach()
#math(EXPR SO_current_minus_age "${SO_current} - ${SO_age}")
#set(SO_VER "${SO_current_minus_age}")
#set(FULL_VER "${SO_current_minus_age}.${SO_revision}.${SO_age}")
# Read package version info from configure.ac
#set(R "AC_INIT\\(RtMidi, ([0-9\\.]+),.*\\)")
#file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/configure.ac" CONFIGAC
# REGEX ${R})
#string(REGEX REPLACE ${R} "\\1" PACKAGE_VERSION ${CONFIGAC})
# Init variables
set(rtmidi_SOURCES RtMidi.cpp RtMidi.h rtmidi_c.cpp rtmidi_c.h)
set(LINKLIBS)
set(PUBLICLINKLIBS)
set(INCDIRS)
set(PKGCONFIG_REQUIRES)
set(LIBS_REQUIRES)
set(API_DEFS)
set(API_LIST)
# Tweak API-specific configuration.
# ALSA
if(RTMIDI_API_ALSA)
set(NEED_PTHREAD ON)
find_package(ALSA)
if (NOT ALSA_FOUND)
message(FATAL_ERROR "ALSA API requested but no ALSA dev libraries found")
endif()
list(APPEND INCDIRS ${ALSA_INCLUDE_DIR})
list(APPEND LINKLIBS ${ALSA_LIBRARY})
list(APPEND PKGCONFIG_REQUIRES "alsa")
list(APPEND API_DEFS "-D__LINUX_ALSA__")
list(APPEND API_LIST "alsa")
endif()
# WinMM
if(RTMIDI_API_WINMM)
list(APPEND API_DEFS "-D__WINDOWS_MM__")
list(APPEND API_LIST "winmm")
list(APPEND LINKLIBS winmm)
endif()
# CoreMIDI
if(RTMIDI_API_CORE)
find_library(CORESERVICES_LIB CoreServices)
find_library(COREAUDIO_LIB CoreAudio)
find_library(COREMIDI_LIB CoreMIDI)
find_library(COREFOUNDATION_LIB CoreFoundation)
list(APPEND API_DEFS "-D__MACOSX_CORE__")
list(APPEND API_LIST "coremidi")
list(APPEND LINKLIBS ${CORESERVICES_LIB} ${COREAUDIO_LIB} ${COREMIDI_LIB} ${COREFOUNDATION_LIB})
list(APPEND LIBS_REQUIRES "-framework CoreServices -framework CoreAudio -framework CoreMIDI -framework CoreFoundation")
list(APPEND LINKFLAGS "-Wl,-F/Library/Frameworks")
endif()
# pthread
if (NEED_PTHREAD)
find_package(Threads REQUIRED
CMAKE_THREAD_PREFER_PTHREAD
THREADS_PREFER_PTHREAD_FLAG)
list(APPEND PUBLICLINKLIBS Threads::Threads)
endif()
# Create library targets.
set(LIB_TARGETS)
# Use RTMIDI_BUILD_SHARED_LIBS / RTMIDI_BUILD_STATIC_LIBS if they
# are defined, otherwise default to standard BUILD_SHARED_LIBS.
if (DEFINED RTMIDI_BUILD_SHARED_LIBS AND NOT RTMIDI_BUILD_SHARED_LIBS STREQUAL "")
if (RTMIDI_BUILD_SHARED_LIBS)
add_library(rtmidi SHARED ${rtmidi_SOURCES})
else()
add_library(rtmidi STATIC ${rtmidi_SOURCES})
endif()
elseif (DEFINED RTMIDI_BUILD_STATIC_LIBS AND NOT RTMIDI_BUILD_STATIC_LIBS STREQUAL "")
if (RTMIDI_BUILD_STATIC_LIBS)
add_library(rtmidi STATIC ${rtmidi_SOURCES})
else()
add_library(rtmidi SHARED ${rtmidi_SOURCES})
endif()
else()
add_library(rtmidi ${rtmidi_SOURCES})
endif()
list(APPEND LIB_TARGETS rtmidi)
# Add headers destination for install rule.
#set_property(TARGET rtmidi PROPERTY PUBLIC_HEADER RtMidi.h rtmidi_c.h)
#set_target_properties(rtmidi PROPERTIES
# SOVERSION ${SO_VER}
# VERSION ${FULL_VER})
# Set include paths, populate target interface.
target_include_directories(rtmidi PRIVATE ${INCDIRS}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
# Set compile-time definitions
target_compile_definitions(rtmidi PRIVATE ${API_DEFS})
target_compile_definitions(rtmidi PRIVATE RTMIDI_EXPORT)
target_link_libraries(rtmidi PUBLIC ${PUBLICLINKLIBS}
PRIVATE ${LINKLIBS})
# Set standard installation directories.
#include(GNUInstallDirs)
# Add tests if requested.
#option(RTMIDI_BUILD_TESTING "Build test programs" ON)
#if (NOT DEFINED RTMIDI_BUILD_TESTING OR RTMIDI_BUILD_TESTING STREQUAL "")
# set(RTMIDI_BUILD_TESTING ${BUILD_TESTING})
#endif()
#if (RTMIDI_BUILD_TESTING)
# include(CTest)
# add_executable(cmidiin tests/cmidiin.cpp)
# add_executable(midiclock tests/midiclock.cpp)
# add_executable(midiout tests/midiout.cpp)
# add_executable(midiprobe tests/midiprobe.cpp)
# add_executable(qmidiin tests/qmidiin.cpp)
# add_executable(sysextest tests/sysextest.cpp)
# add_executable(apinames tests/apinames.cpp)
# add_executable(testcapi tests/testcapi.c)
# list(GET LIB_TARGETS 0 LIBRTMIDI)
# set_target_properties(cmidiin midiclock midiout midiprobe qmidiin sysextest apinames testcapi
# PROPERTIES RUNTIME_OUTPUT_DIRECTORY tests
# INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}
# LINK_LIBRARIES ${LIBRTMIDI})
# add_test(NAME apinames COMMAND apinames)
#endif()
# Set standard installation directories.
#include(GNUInstallDirs)
# Message
string(REPLACE ";" " " apilist "${API_LIST}")
message(STATUS "Compiling with support for: ${apilist}")
# PkgConfig file
#string(REPLACE ";" " " req "${PKGCONFIG_REQUIRES}")
#string(REPLACE ";" " " req_libs "${LIBS_REQUIRES}")
#string(REPLACE ";" " " api "${API_DEFS}")
#set(prefix ${CMAKE_INSTALL_PREFIX})
#configure_file("${CMAKE_CURRENT_SOURCE_DIR}/rtmidi.pc.in" "rtmidi.pc" @ONLY)
# Add install rule.
#install(TARGETS ${LIB_TARGETS}
# EXPORT RtMidiTargets
# LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
# ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
# PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/rtmidi)
# Store the package in the user registry.
#export(PACKAGE RtMidi)
# Set installation path for CMake files.
#set(RTMIDI_CMAKE_DESTINATION share/rtmidi)
# Export library target (build-tree).
#export(EXPORT RtMidiTargets
# NAMESPACE RtMidi::)
# Export library target (install-tree).
#install(EXPORT RtMidiTargets
# DESTINATION ${RTMIDI_CMAKE_DESTINATION}
# NAMESPACE RtMidi::)
# Configure uninstall target.
#configure_file(
# "${CMAKE_CURRENT_SOURCE_DIR}/cmake/RtMidiConfigUninstall.cmake.in"
# "${CMAKE_BINARY_DIR}/RtMidiConfigUninstall.cmake" @ONLY)
# Create uninstall target.
#add_custom_target(${RTMIDI_TARGETNAME_UNINSTALL}
# COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/RtMidiConfigUninstall.cmake)
#install(
# FILES ${CMAKE_CURRENT_BINARY_DIR}/rtmidi.pc
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
# Set up CMake package
#include(CMakePackageConfigHelpers)
# Write cmake package version file
#write_basic_package_version_file(
# RtMidi-config-version.cmake
# VERSION ${FULL_VER}
# COMPATIBILITY SameMajorVersion
#)
# Write cmake package config file
#configure_package_config_file (
# cmake/RtMidi-config.cmake.in
# RtMidi-config.cmake
# INSTALL_DESTINATION "${RTMIDI_CMAKE_DESTINATION}"
#)
# Install package files
#install (
# FILES
# "${CMAKE_CURRENT_BINARY_DIR}/RtMidi-config.cmake"
# "${CMAKE_CURRENT_BINARY_DIR}/RtMidi-config-version.cmake"
# DESTINATION
# "${RTMIDI_CMAKE_DESTINATION}"
#)

27
extern/rtmidi/LICENSE vendored Normal file
View File

@ -0,0 +1,27 @@
RtMidi: realtime MIDI i/o C++ classes
Copyright (c) 2003-2021 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
asked to send the modifications to the original developer so that
they can be incorporated into the canonical version. This is,
however, not a binding provision of this license.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

21
extern/rtmidi/Makefile.am vendored Normal file
View File

@ -0,0 +1,21 @@
SUBDIRS = . tests
if MAKE_DOC
SUBDIRS += doc
endif
lib_LTLIBRARIES = %D%/librtmidi.la
%C%_librtmidi_la_CXXFLAGS = -DRTMIDI_EXPORT
%C%_librtmidi_la_LDFLAGS = -no-undefined -export-dynamic -version-info @SO_VERSION@
%C%_librtmidi_la_SOURCES = \
%D%/RtMidi.cpp \
%D%/rtmidi_c.cpp
rtmidi_incdir = $(includedir)/rtmidi
rtmidi_inc_HEADERS = \
%D%/RtMidi.h \
%D%/rtmidi_c.h
pkgconfigdatadir = $(libdir)/pkgconfig
pkgconfigdata_DATA = rtmidi.pc
EXTRA_DIST = autogen.sh README.md msw rtmidi-config.in contrib cmake CMakeLists.txt

39
extern/rtmidi/README.md vendored Normal file
View File

@ -0,0 +1,39 @@
# RtMidi
![Build Status](https://github.com/thestk/rtmidi/actions/workflows/ci.yml/badge.svg)
A set of C++ classes that provide a common API for realtime MIDI input/output across Linux (ALSA & JACK), Macintosh OS X (CoreMIDI & JACK) and Windows (Multimedia).
By Gary P. Scavone, 2003-2021.
This distribution of RtMidi contains the following:
- `doc`: RtMidi documentation (also online at http://www.music.mcgill.ca/~gary/rtmidi/)
- `tests`: example RtMidi programs
On Unix systems, type `./configure` in the top level directory, then `make` in the `tests/` directory to compile the test programs. In Windows, open the Visual C++ workspace file located in the `tests/` directory.
If you checked out the code from git, please run `./autogen.sh` before `./configure`.
## Overview
RtMidi is a set of C++ classes (`RtMidiIn`, `RtMidiOut`, and API specific classes) that provide a common API (Application Programming Interface) for realtime MIDI input/output across Linux (ALSA, JACK), Macintosh OS X (CoreMIDI, JACK), and Windows (Multimedia Library) operating systems. RtMidi significantly simplifies the process of interacting with computer MIDI hardware and software. It was designed with the following goals:
- object oriented C++ design
- simple, common API across all supported platforms
- only one header and one source file for easy inclusion in programming projects
- MIDI device enumeration
MIDI input and output functionality are separated into two classes, `RtMidiIn` and `RtMidiOut`. Each class instance supports only a single MIDI connection. RtMidi does not provide timing functionality (i.e., output messages are sent immediately). Input messages are timestamped with delta times in seconds (via a `double` floating point type). MIDI data is passed to the user as raw bytes using an `std::vector<unsigned char>`.
## Windows
In some cases, for example to use RtMidi with GS Synth, it may be necessary for your program to call `CoInitializeEx` and `CoUninitialize` on entry to and exit from the thread that uses RtMidi.
## Further reading
For complete documentation on RtMidi, see the `doc` directory of the distribution or surf to http://www.music.mcgill.ca/~gary/rtmidi/.
## Legal and ethical
The RtMidi license is similar to the MIT License, with the added *feature* that modifications be sent to the developer. Please see [LICENSE](LICENSE).

3934
extern/rtmidi/RtMidi.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

658
extern/rtmidi/RtMidi.h vendored Normal file
View File

@ -0,0 +1,658 @@
/**********************************************************************/
/*! \class RtMidi
\brief An abstract base class for realtime MIDI input/output.
This class implements some common functionality for the realtime
MIDI input/output subclasses RtMidiIn and RtMidiOut.
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-2021 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
asked to send the modifications to the original developer so that
they can be incorporated into the canonical version. This is,
however, not a binding provision of this license.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**********************************************************************/
/*!
\file RtMidi.h
*/
#ifndef RTMIDI_H
#define RTMIDI_H
#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 "5.0.0"
#include <exception>
#include <iostream>
#include <string>
#include <vector>
/************************************************************************/
/*! \class RtMidiError
\brief Exception handling class for RtMidi.
The RtMidiError class is quite simple but it does allow errors to be
"caught" by RtMidiError::Type. See the RtMidi documentation to know
which methods can throw an RtMidiError.
*/
/************************************************************************/
class RTMIDI_DLL_PUBLIC RtMidiError : public std::exception
{
public:
//! Defined RtMidiError types.
enum Type {
WARNING, /*!< A non-critical error. */
DEBUG_WARNING, /*!< A non-critical error which might be useful for debugging. */
UNSPECIFIED, /*!< The default, unspecified error type. */
NO_DEVICES_FOUND, /*!< No devices found on system. */
INVALID_DEVICE, /*!< An invalid device ID was specified. */
MEMORY_ERROR, /*!< An error occured during memory allocation. */
INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */
INVALID_USE, /*!< The function was called incorrectly. */
DRIVER_ERROR, /*!< A system driver error occured. */
SYSTEM_ERROR, /*!< A system error occured. */
THREAD_ERROR /*!< A thread error occured. */
};
//! The constructor.
RtMidiError( const std::string& message, Type type = RtMidiError::UNSPECIFIED ) throw()
: message_(message), type_(type) {}
//! The destructor.
virtual ~RtMidiError( void ) throw() {}
//! Prints thrown error message to stderr.
virtual void printMessage( void ) const throw() { std::cerr << '\n' << message_ << "\n\n"; }
//! Returns the thrown error message type.
virtual const Type& getType( void ) const throw() { return type_; }
//! Returns the thrown error message string.
virtual const std::string& getMessage( void ) const throw() { return message_; }
//! Returns the thrown error message as a c-style string.
virtual const char* what( void ) const throw() { return message_.c_str(); }
protected:
std::string message_;
Type type_;
};
//! RtMidi error callback function prototype.
/*!
\param type Type of error.
\param errorText Error description.
Note that class behaviour is undefined after a critical error (not
a warning) is reported.
*/
typedef void (*RtMidiErrorCallback)( RtMidiError::Type type, const std::string &errorText, void *userData );
class MidiApi;
class RTMIDI_DLL_PUBLIC RtMidi
{
public:
RtMidi(RtMidi&& other) noexcept;
//! MIDI API specifier arguments.
enum Api {
UNSPECIFIED, /*!< Search for a working compiled API. */
MACOSX_CORE, /*!< Macintosh OS-X CoreMIDI API. */
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. */
WEB_MIDI_API, /*!< W3C Web MIDI API. */
NUM_APIS /*!< Number of values in this enum. */
};
//! A static function to determine the current RtMidi version.
static std::string getVersion( void ) throw();
//! A static function to determine the available compiled MIDI APIs.
/*!
The values returned in the std::vector can be compared against
the enumerated list values. Note that there can be more than one
API compiled for certain operating systems.
*/
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;
//! Pure virtual openVirtualPort() function.
virtual void openVirtualPort( const std::string &portName = std::string( "RtMidi" ) ) = 0;
//! Pure virtual getPortCount() function.
virtual unsigned int getPortCount() = 0;
//! Pure virtual getPortName() function.
virtual std::string getPortName( unsigned int portNumber = 0 ) = 0;
//! 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()
function, not to virtual ports.
*/
virtual bool isPortOpen( void ) const = 0;
//! Set an error callback function to be invoked when an error has occured.
/*!
The callback function will be called whenever an error has occured. It is best
to set the error callback function before opening a port.
*/
virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 ) = 0;
protected:
RtMidi();
virtual ~RtMidi();
MidiApi *rtapi_;
/* Make the class non-copyable */
RtMidi(RtMidi& other) = delete;
RtMidi& operator=(RtMidi& other) = delete;
};
/**********************************************************************/
/*! \class RtMidiIn
\brief A realtime MIDI input class.
This class provides a common, platform-independent API for
realtime MIDI input. It allows access to a single MIDI input
port. Incoming MIDI messages are either saved to a queue for
retrieval using the getMessage() function or immediately passed to
a user-specified callback function. Create multiple instances of
this class to 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 input port to which other MIDI software
clients can connect.
*/
/**********************************************************************/
// **************************************************************** //
//
// RtMidiIn and RtMidiOut class declarations.
//
// RtMidiIn / RtMidiOut are "controllers" used to select an available
// MIDI input or output interface. They present common APIs for the
// user to call but all functionality is implemented by the classes
// MidiInApi, MidiOutApi and their subclasses. RtMidiIn and RtMidiOut
// each create an instance of a MidiInApi or MidiOutApi subclass based
// on the user's API choice. If no choice is made, they attempt to
// make a "logical" API selection.
//
// **************************************************************** //
class RTMIDI_DLL_PUBLIC RtMidiIn : public RtMidi
{
public:
//! User callback function type definition.
typedef void (*RtMidiCallback)( double timeStamp, std::vector<unsigned char> *message, void *userData );
//! Default constructor that allows an optional api, client name and queue size.
/*!
An exception will be thrown if a MIDI system initialization
error occurs. The queue size defines the maximum number of
messages that can be held in the MIDI queue (when not using a
callback function). If the queue size limit is reached,
incoming messages will be ignored.
If no API argument is specified and multiple API support has been
compiled, the default order of use is ALSA, JACK (Linux) and CORE,
JACK (OS-X).
\param api An optional API id can be specified.
\param clientName An optional client name can be specified. This
will be used to group the ports that are created
by the application.
\param queueSizeLimit An optional size of the MIDI input queue can be specified.
*/
RtMidiIn( RtMidi::Api api=UNSPECIFIED,
const std::string& clientName = "RtMidi Input Client",
unsigned int queueSizeLimit = 100 );
RtMidiIn(RtMidiIn&& other) noexcept : RtMidi(std::move(other)) { }
//! If a MIDI connection is still open, it will be closed by the destructor.
~RtMidiIn ( void ) throw();
//! Returns the MIDI API specifier for the current instance of RtMidiIn.
RtMidi::Api getCurrentApi( void ) throw();
//! Open a MIDI input connection given by enumeration number.
/*!
\param portNumber An optional port number greater than 0 can be specified.
Otherwise, the default or first port found is opened.
\param portName An optional name for the application port that is used to connect to portId can be specified.
*/
void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi Input" ) );
//! Create a virtual input port, with optional name, to allow software connections (OS X, JACK and ALSA only).
/*!
This function creates a virtual MIDI input port to which other
software applications can connect. This type of functionality
is currently only supported by the Macintosh OS-X, any JACK,
and Linux ALSA APIs (the function returns an error for the other APIs).
\param portName An optional name for the application port that is
used to connect to portId can be specified.
*/
void openVirtualPort( const std::string &portName = std::string( "RtMidi Input" ) );
//! Set a callback function to be invoked for incoming MIDI messages.
/*!
The callback function will be called whenever an incoming MIDI
message is received. While not absolutely necessary, it is best
to set the callback function before opening a MIDI port to avoid
leaving some messages in the queue.
\param callback A callback function must be given.
\param userData Optionally, a pointer to additional data can be
passed to the callback function whenever it is called.
*/
void setCallback( RtMidiCallback callback, void *userData = 0 );
//! Cancel use of the current callback function (if one exists).
/*!
Subsequent incoming MIDI messages will be written to the queue
and can be retrieved with the \e getMessage function.
*/
void cancelCallback();
//! Close an open MIDI connection (if one exists).
void closePort( void );
//! Returns true if a port is open and false if not.
/*!
Note that this only applies to connections made with the openPort()
function, not to virtual ports.
*/
virtual bool isPortOpen() const;
//! Return the number of available MIDI input ports.
/*!
\return This function returns the number of MIDI ports of the selected API.
*/
unsigned int getPortCount();
//! Return a string identifier for the specified MIDI input port number.
/*!
\return The name of the port with the given Id is returned.
\retval An empty string is returned if an invalid port specifier
is provided. User code should assume a UTF-8 encoding.
*/
std::string getPortName( unsigned int portNumber = 0 );
//! Specify whether certain MIDI message types should be queued or ignored during input.
/*!
By default, MIDI timing and active sensing messages are ignored
during message input because of their relative high data rates.
MIDI sysex messages are ignored by default as well. Variable
values of "true" imply that the respective message type will be
ignored.
*/
void ignoreTypes( bool midiSysex = true, bool midiTime = true, bool midiSense = true );
//! Fill the user-provided vector with the data bytes for the next available MIDI message in the input queue and return the event delta-time in seconds.
/*!
This function returns immediately whether a new message is
available or not. A valid message is indicated by a non-zero
vector size. An exception is thrown if an error occurs during
message retrieval or an input connection was not previously
established.
*/
double getMessage( std::vector<unsigned char> *message );
//! Set an error callback function to be invoked when an error has occured.
/*!
The callback function will be called whenever an error has occured. It is best
to set the error callback function before opening a port.
*/
virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
//! Set maximum expected incoming message size.
/*!
For APIs that require manual buffer management, it can be useful to set the buffer
size and buffer count when expecting to receive large SysEx messages. Note that
currently this function has no effect when called after openPort(). The default
buffer size is 1024 with a count of 4 buffers, which should be sufficient for most
cases; as mentioned, this does not affect all API backends, since most either support
dynamically scalable buffers or take care of buffer handling themselves. It is
principally intended for users of the Windows MM backend who must support receiving
especially large messages.
*/
virtual void setBufferSize( unsigned int size, unsigned int count );
protected:
void openMidiApi( RtMidi::Api api, const std::string &clientName, unsigned int queueSizeLimit );
};
/**********************************************************************/
/*! \class RtMidiOut
\brief A realtime MIDI output class.
This class provides a common, platform-independent API for MIDI
output. It allows one to probe available MIDI output ports, to
connect to one such port, and to send MIDI bytes immediately over
the connection. Create multiple instances of this class to
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.
*/
/**********************************************************************/
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.
If no API argument is specified and multiple API support has been
compiled, the default order of use is ALSA, JACK (Linux) and CORE,
JACK (OS-X).
*/
RtMidiOut( RtMidi::Api api=UNSPECIFIED,
const std::string& clientName = "RtMidi Output Client" );
RtMidiOut(RtMidiOut&& other) noexcept : RtMidi(std::move(other)) { }
//! The destructor closes any open MIDI connections.
~RtMidiOut( void ) throw();
//! Returns the MIDI API specifier for the current instance of RtMidiOut.
RtMidi::Api getCurrentApi( void ) throw();
//! Open a MIDI output connection.
/*!
An optional port number greater than 0 can be specified.
Otherwise, the default or first port found is opened. An
exception is thrown if an error occurs while attempting to make
the port connection.
*/
void openPort( unsigned int portNumber = 0, const std::string &portName = std::string( "RtMidi Output" ) );
//! Close an open MIDI connection (if one exists).
void closePort( void );
//! Returns true if a port is open and false if not.
/*!
Note that this only applies to connections made with the openPort()
function, not to virtual ports.
*/
virtual bool isPortOpen() const;
//! Create a virtual output port, with optional name, to allow software connections (OS X, JACK and ALSA only).
/*!
This function creates a virtual MIDI output port to which other
software applications can connect. This type of functionality
is currently only supported by the Macintosh OS-X, Linux ALSA
and JACK APIs (the function does nothing with the other APIs).
An exception is thrown if an error occurs while attempting to
create the virtual port.
*/
void openVirtualPort( const std::string &portName = std::string( "RtMidi Output" ) );
//! Return the number of available MIDI output ports.
unsigned int getPortCount( void );
//! Return a string identifier for the specified MIDI port type and number.
/*!
\return The name of the port with the given Id is returned.
\retval An empty string is returned if an invalid port specifier
is provided. User code should assume a UTF-8 encoding.
*/
std::string getPortName( unsigned int portNumber = 0 );
//! 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.
*/
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.
/*!
The callback function will be called whenever an error has occured. It is best
to set the error callback function before opening a port.
*/
virtual void setErrorCallback( RtMidiErrorCallback errorCallback = NULL, void *userData = 0 );
protected:
void openMidiApi( RtMidi::Api api, const std::string &clientName );
};
// **************************************************************** //
//
// MidiInApi / MidiOutApi class declarations.
//
// Subclasses of MidiInApi and MidiOutApi contain all API- and
// OS-specific code necessary to fully implement the RtMidi API.
//
// Note that MidiInApi and MidiOutApi are abstract base classes and
// cannot be explicitly instantiated. RtMidiIn and RtMidiOut will
// create instances of a MidiInApi or MidiOutApi subclass.
//
// **************************************************************** //
class RTMIDI_DLL_PUBLIC MidiApi
{
public:
MidiApi();
virtual ~MidiApi();
virtual RtMidi::Api getCurrentApi( void ) = 0;
virtual void openPort( unsigned int portNumber, const std::string &portName ) = 0;
virtual void openVirtualPort( const std::string &portName ) = 0;
virtual void 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;
inline bool isPortOpen() const { return connected_; }
void setErrorCallback( RtMidiErrorCallback errorCallback, void *userData );
//! A basic error reporting function for RtMidi classes.
void error( RtMidiError::Type type, std::string errorString );
protected:
virtual void initialize( const std::string& clientName ) = 0;
void *apiData_;
bool connected_;
std::string errorString_;
RtMidiErrorCallback errorCallback_;
bool firstErrorOccurred_;
void *errorCallbackUserData_;
};
class RTMIDI_DLL_PUBLIC MidiInApi : public MidiApi
{
public:
MidiInApi( unsigned int queueSizeLimit );
virtual ~MidiInApi( void );
void setCallback( RtMidiIn::RtMidiCallback callback, void *userData );
void cancelCallback( void );
virtual void ignoreTypes( bool midiSysex, bool midiTime, bool midiSense );
double getMessage( std::vector<unsigned char> *message );
virtual void setBufferSize( unsigned int size, unsigned int count );
// A MIDI structure used internally by the class to store incoming
// messages. Each message represents one and only one MIDI message.
struct MidiMessage {
std::vector<unsigned char> bytes;
//! Time in seconds elapsed since the previous message
double timeStamp;
// Default constructor.
MidiMessage()
: bytes(0), timeStamp(0.0) {}
};
struct MidiQueue {
unsigned int front;
unsigned int back;
unsigned int ringSize;
MidiMessage *ring;
// Default constructor.
MidiQueue()
: 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 MIDI input handling function or thread.
struct RtMidiInData {
MidiQueue queue;
MidiMessage message;
unsigned char ignoreFlags;
bool doInput;
bool firstMessage;
void *apiData;
bool usingCallback;
RtMidiIn::RtMidiCallback userCallback;
void *userData;
bool continueSysex;
unsigned int bufferSize;
unsigned int bufferCount;
// Default constructor.
RtMidiInData()
: ignoreFlags(7), doInput(false), firstMessage(true), apiData(0), usingCallback(false),
userCallback(0), userData(0), continueSysex(false), bufferSize(1024), bufferCount(4) {}
};
protected:
RtMidiInData inputData_;
};
class RTMIDI_DLL_PUBLIC MidiOutApi : public MidiApi
{
public:
MidiOutApi( void );
virtual ~MidiOutApi( void );
virtual void sendMessage( const unsigned char *message, size_t size ) = 0;
};
// **************************************************************** //
//
// Inline RtMidiIn and RtMidiOut definitions.
//
// **************************************************************** //
inline RtMidi::Api RtMidiIn :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
inline void RtMidiIn :: openPort( unsigned int portNumber, const std::string &portName ) { rtapi_->openPort( portNumber, portName ); }
inline void RtMidiIn :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
inline void RtMidiIn :: closePort( void ) { rtapi_->closePort(); }
inline bool RtMidiIn :: isPortOpen() const { return rtapi_->isPortOpen(); }
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 ) { 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 void RtMidiIn :: setBufferSize( unsigned int size, unsigned int count ) { static_cast<MidiInApi *>(rtapi_)->setBufferSize(size, count); }
inline RtMidi::Api RtMidiOut :: getCurrentApi( void ) throw() { return rtapi_->getCurrentApi(); }
inline void RtMidiOut :: openPort( unsigned int portNumber, const std::string &portName ) { rtapi_->openPort( portNumber, portName ); }
inline void RtMidiOut :: openVirtualPort( const std::string &portName ) { rtapi_->openVirtualPort( portName ); }
inline void RtMidiOut :: 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 ) { 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); }
#endif

107
extern/rtmidi/autogen.sh vendored Executable file
View File

@ -0,0 +1,107 @@
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
DIE=0
if test -z "$*"; then
echo "**Warning**: I am going to run \`configure' with arguments for"
echo "developer/maintainer mode. If you wish to pass extra arguments,"
echo "(such as --prefix), please specify them on the \`$0'"
echo "command line."
echo "If you wish to run configure yourself, please specify --no-configure."
echo
fi
(test -f $srcdir/configure.ac) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
echo " top-level package directory"
exit 1
}
# Make some directories required by automake, if they don't exist
if ! [ -d config ]; then mkdir -v config; fi
if ! [ -d m4 ]; then mkdir -v m4; fi
if ! autoreconf --version </dev/null >/dev/null 2>&1
then
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have \`autoconf' installed."
echo "Download the appropriate package for your distribution,"
echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
DIE=1
}
(grep "^LT_INIT" $srcdir/configure.ac >/dev/null) && {
(libtoolize --version) < /dev/null > /dev/null 2>&1 \
&& LIBTOOLIZE=libtoolize || {
(glibtoolize --version) < /dev/null > /dev/null 2>&1 \
&& LIBTOOLIZE=glibtoolize || {
echo
echo "**Error**: You must have \`libtool' installed."
echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/"
DIE=1
}
}
}
(automake --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: You must have \`automake' installed."
echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/"
DIE=1
NO_AUTOMAKE=yes
}
# if no automake, don't bother testing for aclocal
test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "**Error**: Missing \`aclocal'. The version of \`automake'"
echo "installed doesn't appear recent enough."
echo "You can get automake from ftp://ftp.gnu.org/pub/gnu/"
DIE=1
}
if test "$DIE" -eq 1; then
exit 1
fi
case $CC in
xlc )
am_opt=--include-deps;;
esac
echo "Running aclocal $aclocalinclude ..."
aclocal $ACLOCAL_FLAGS || exit 1
echo "Running $LIBTOOLIZE ..."
$LIBTOOLIZE || exit 1
echo "Running automake --gnu $am_opt ..."
automake --add-missing --gnu $am_opt || exit 1
echo "Running autoconf ..."
autoconf || exit 1
else # autoreconf instead
echo "Running autoreconf --verbose --install ..."
autoreconf --verbose --install || exit 1
fi
if ( echo "$@" | grep -q -e "--no-configure" ); then
NOCONFIGURE=1
fi
conf_flags="--enable-maintainer-mode --enable-debug --disable-silent-rules"
if test x$NOCONFIGURE = x; then
echo Running $srcdir/configure $conf_flags "$@" ...
$srcdir/configure $conf_flags "$@" \
&& echo Now type \`make\' to compile. || exit 1
else
echo Skipping configure process.
fi

View File

@ -0,0 +1,20 @@
#.rst:
# RtMidi
# -------
#
# The following import targets are created
#
# ::
#
#
# RtMidi::rtmidi
#
#
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
if(NOT TARGET rtmidi)
include("${CMAKE_CURRENT_LIST_DIR}/RtMidiTargets.cmake")
endif()

View File

@ -0,0 +1,21 @@
if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
if(EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
endif(NOT "${rm_retval}" STREQUAL 0)
else(EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
endif(EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)

254
extern/rtmidi/configure.ac vendored Normal file
View File

@ -0,0 +1,254 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(RtMidi, 5.0.0, gary.scavone@mcgill.ca, rtmidi)
AC_CONFIG_AUX_DIR(config)
AC_CONFIG_SRCDIR(RtMidi.cpp)
AC_CONFIG_FILES([rtmidi-config rtmidi.pc Makefile tests/Makefile doc/Makefile doc/doxygen/Doxyfile])
AM_INIT_AUTOMAKE([1.14 -Wall -Werror foreign subdir-objects])
# libtool version: current:revision:age
#
# If the library source code has changed at all since the last update, then
# increment revision (`c:r:a' becomes `c:r+1:a').
#
# If any interfaces have been added, removed, or changed since the last update,
# increment current, and set revision to 0.
#
# If any interfaces have been added since the last public release, then
# increment age.
#
# If any interfaces have been removed since the last public release, then set
# age to 0.
m4_define([lt_current], 6)
m4_define([lt_revision], 0)
m4_define([lt_age], 0)
m4_define([lt_version_info], [lt_current:lt_revision:lt_age])
m4_define([lt_current_minus_age], [m4_eval(lt_current - lt_age)])
SO_VERSION=lt_version_info
AC_SUBST(SO_VERSION)
AC_SUBST(LIBS)
AC_SUBST(api)
AC_SUBST(req)
AC_SUBST(req_libs)
api=""
req=""
req_libs=""
# Fill GXX with something before test.
GXX="no"
# if the user did not provide any CXXFLAGS, we can override them
AS_IF([test "x$CXXFLAGS" = "x" ], [override_cxx=yes], [override_cxx=no])
AS_IF([test "x$CFLAGS" = "x" ], [override_c=yes], [override_c=no])
# Check version number coherency between RtMidi.h and configure.ac
AC_MSG_CHECKING([that version numbers are coherent])
RTMIDI_VERSION=`sed -n 's/#define RTMIDI_VERSION "\(.*\)"/\1/p' $srcdir/RtMidi.h`
AS_IF(
[test "x$RTMIDI_VERSION" != "x$PACKAGE_VERSION"],
[AC_MSG_FAILURE([testing RTMIDI_VERSION==PACKAGE_VERSION failed, check that RtMidi.h defines RTMIDI_VERSION as "$PACKAGE_VERSION" or that the first line of configure.ac has been updated.])])
# Enable some nice automake features if they are available
m4_ifdef([AM_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
# standards version
m4_include([m4/ax_cxx_compile_stdcxx.m4])
AX_CXX_COMPILE_STDCXX(11, noext, mandatory)
# configure flags
AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug], [enable various debugging output])])
AC_ARG_WITH(jack, [AS_HELP_STRING([--with-jack], [choose JACK server support])])
AC_ARG_WITH(alsa, [AS_HELP_STRING([--with-alsa], [choose native ALSA sequencer API support (linux only)])])
AC_ARG_WITH(core, [AS_HELP_STRING([--with-core], [ choose CoreMIDI API support (mac only)])])
AC_ARG_WITH(winmm, [AS_HELP_STRING([--with-winmm], [ choose Windows MultiMedia (MM) API support (win32 only)])])
AC_ARG_WITH(winks, [AS_HELP_STRING([--with-winks], [ choose kernel streaming support (win32 only)])])
AC_ARG_WITH(webmidi, [AS_HELP_STRING([--with-webmidi], [ choose Web MIDI support])])
# Checks for programs.
AC_PROG_CXX(g++ CC c++ cxx)
AM_PROG_AR
AC_PATH_PROG(AR, ar, no)
AS_IF([test "x$AR" = "xno"], [
AC_MSG_ERROR([Could not find ar - needed to create a library])
])
LT_INIT([win32-dll])
AC_CONFIG_MACRO_DIR([m4])
# Checks for header files.
AC_HEADER_STDC
#AC_CHECK_HEADERS(sys/ioctl.h unistd.h)
# Check for POSIX semaphore support
AC_CHECK_HEADER([semaphore.h], [
AC_CHECK_LIB(pthread, sem_init,
AC_DEFINE([HAVE_SEMAPHORE],[1],[Define to 1 if you have POSIX semaphore support on your system.]),
AC_MSG_WARN([POSIX semaphore support not found; data may be lost on closePort]))
])
# check for debug
AC_MSG_CHECKING(whether to compile debug version)
debugflags=""
object_path=Release
AS_CASE([${enable_debug}],
[ yes ], [
AC_MSG_RESULT([yes])
CPPFLAGS="-D__RTMIDI_DEBUG ${CPPFLAGS}"
debugflags="${debugflags} -g"
object_path=Debug
],
[ no ], [
AC_MSG_RESULT([no!])
debugflags="${debugflags} -O3"
], [
AC_MSG_RESULT([no])
])
# For debugging and optimization ... overwrite default because it has both -g and -O2
AS_IF([test "x$debugflags" != x],
AS_IF([test "x$override_cxx" = "xyes" ], CXXFLAGS="$CXXFLAGS $debugflags", CXXFLAGS="$debugflags $CXXFLAGS")
AS_IF([test "x$override_c" = "xyes" ], CFLAGS="$CFLAGS $debugflags", CFLAGS="$debugflags $CFLAGS")
)
# Check compiler and use -Wall if gnu.
AS_IF([test "x$GXX" = "xyes"], [
CXXFLAGS="-Wall -Wextra ${CXXFLAGS}"
])
# Checks for doxygen
AC_CHECK_PROG( DOXYGEN, [doxygen], [doxygen] )
AM_CONDITIONAL( MAKE_DOC, [test "x${DOXYGEN}" != x] )
# Copy doc files to build dir if necessary
AC_CONFIG_LINKS( [doc/doxygen/footer.html:doc/doxygen/footer.html] )
AC_CONFIG_LINKS( [doc/doxygen/header.html:doc/doxygen/header.html] )
AC_CONFIG_LINKS( [doc/doxygen/tutorial.txt:doc/doxygen/tutorial.txt] )
AC_CONFIG_LINKS( [doc/images/ccrma.gif:doc/images/ccrma.gif] )
AC_CONFIG_LINKS( [doc/images/mcgill.gif:doc/images/mcgill.gif] )
# Checks for package options and external software
AC_CANONICAL_HOST
# Aggregate options into a single string.
AS_IF([test "x$with_jack" = "xyes"], [systems="$systems jack"])
AS_IF([test "x$with_alsa" = "xyes"], [systems="$systems alsa"])
AS_IF([test "x$with_core" = "xyes"], [systems="$systems core"])
AS_IF([test "x$with_winmm" = "xyes"], [systems="$systems winmm"])
AS_IF([test "x$with_winks" = "xyes"], [systems="$systems winks"])
AS_IF([test "x$with_webmidi" = "xyes"], [systems="$systems webmidi"])
AS_IF([test "x$with_dummy" = "xyes"], [systems="$systems dummy"])
required=" $systems "
# If none, assign defaults if any are known for this OS.
# User must specified with-* options for any unknown OS.
AS_IF([test "x$systems" = "x"],
AS_CASE([$host],
[*-*-linux*], [systems="alsa jack"],
[*-*-gnu], [systems="jack"],
[*-*-kfreebsd*-gnu], [systems="jack"],
[*-apple*], [systems="core jack"],
[*-mingw32*], [systems="winmm winks jack"],
[*-mingw64*], [systems="winmm winks jack"]
))
# If any were specifically requested disabled, do it.
AS_IF([test "x$with_jack" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v jack`])
AS_IF([test "x$with_alsa" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v alsa`])
AS_IF([test "x$with_winmm" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v winmm`])
AS_IF([test "x$with_winks" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v winks`])
AS_IF([test "x$with_core" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v core`])
AS_IF([test "x$with_webmidi" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v webmidi`])
AS_IF([test "x$with_dummy" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v dummy`])
systems=" `echo $systems|tr \\\\n ' '` "
# For each MIDI system, check if it is selected and found.
# Note: Order specified above is not necessarily respected. However,
# *actual* priority is set at run-time, see RtMidiIn::openMidiApi and RtMidiOut::openMidiApi.
# One AS_CASE per system, since they are not mutually-exclusive.
AS_CASE(["$systems"], [*" jack "*], [
AC_CHECK_LIB(jack, jack_client_open,
[api="$api -D__UNIX_JACK__"
req="$req jack"
need_pthread=yes
found="$found Jack"
LIBS="-ljack $LIBS"],
AS_CASE(["$required"], [*" jack "*],
AC_MSG_ERROR([JACK support requires the jack library!])))
AC_CHECK_LIB(jack, jack_port_rename, AC_DEFINE(JACK_HAS_PORT_RENAME), )
])
AS_CASE(["$systems"], [*" alsa "*], [
AC_CHECK_LIB(asound, snd_seq_open,
[api="$api -D__LINUX_ALSA__"
req="$req alsa"
need_pthread=yes
found="$found ALSA"
LIBS="-lasound $LIBS"],
AS_CASE(["$required"], [*" alsa "*],
AC_MSG_ERROR([ALSA support requires the asound library!])))
])
AS_CASE(["$systems"], [*" core "*], [
AC_CHECK_HEADER(CoreMIDI/CoreMIDI.h,
[api="$api -D__MACOSX_CORE__"
req_libs="$req_libs -framework CoreMIDI -framework CoreAudio -framework CoreFoundation"
need_pthread=yes
found="$found CoreMIDI",
LIBS="$LIBS -framework CoreMIDI -framework CoreFoundation -framework CoreAudio"],
AS_CASE(["$required"], [*" core "*],
AC_MSG_ERROR([CoreMIDI header files not found!])))
])
AS_CASE(["$systems"], [*" winmm "*], [
AC_CHECK_HEADERS(windows.h mmsystem.h,
[api="$api -D__WINDOWS_MM__"
CPPFLAGS="-I$srcdir/include $CPPFLAGS"
need_ole32=yes
found="$found WinMM"
api="$api -D__WINDOWS_MM__"
LIBS="-lwinmm ${LIBS}"])
])
AS_CASE(["$systems"], [*" winks "*], [
AC_CHECK_HEADERS(windows.h audioclient.h avrt.h mmdeviceapi.h,
[api="$api -D__WINDOWS_WINKS__"
CPPFLAGS="-I$srcdir/include $CPPFLAGS"
need_ole32=yes
found="$found kernel-streaming"
api="$api -D__WINDOWS_WINKS__"
LIBS="-lsetupapi -lksuser ${LIBS}"])
])
AS_CASE(["$systems"], [*" webmidi "*], [
AC_CHECK_HEADERS(emscripten.h,
[api="$api -D__WEB_MIDI_API__"
found="$found Web MIDI"])
])
AS_IF([test -n "$need_ole32"], [LIBS="-lole32 $LIBS"])
AS_IF([test -n "$need_pthread"],[
AC_MSG_CHECKING([for pthread])
AC_CHECK_LIB(pthread, pthread_create, ,
AC_MSG_ERROR([RtAudio requires the pthread library!]))])
AC_MSG_CHECKING([for MIDI API])
# Error case: no known realtime systems found.
AS_IF([test x"$api" = "x"], [
AC_MSG_RESULT([none])
AC_MSG_ERROR([No known system type found for MIDI support!])
], [
AC_MSG_RESULT([$found])
])
CPPFLAGS="$CPPFLAGS $api"
AC_OUTPUT
chmod oug+x rtmidi-config

View File

@ -0,0 +1,355 @@
package rtmidi
/*
#cgo CXXFLAGS: -g
#cgo LDFLAGS: -g
#cgo linux CXXFLAGS: -D__LINUX_ALSA__
#cgo linux LDFLAGS: -lasound -pthread
#cgo windows CXXFLAGS: -D__WINDOWS_MM__
#cgo windows LDFLAGS: -luuid -lksuser -lwinmm -lole32
#cgo darwin CXXFLAGS: -D__MACOSX_CORE__
#cgo darwin LDFLAGS: -framework CoreServices -framework CoreAudio -framework CoreMIDI -framework CoreFoundation
#include <stdlib.h>
#include <stdint.h>
#include "rtmidi_stub.h"
extern void goMIDIInCallback(double ts, unsigned char *msg, size_t msgsz, void *arg);
static inline void midiInCallback(double ts, const unsigned char *msg, size_t msgsz, void *arg) {
goMIDIInCallback(ts, (unsigned char*) msg, msgsz, arg);
}
static inline void cgoSetCallback(RtMidiPtr in, int cb_id) {
rtmidi_in_set_callback(in, midiInCallback, (void*)(uintptr_t) cb_id);
}
*/
import "C"
import (
"errors"
"sync"
"unsafe"
)
// API is an enumeration of possible MIDI API specifiers.
type API C.enum_RtMidiApi
const (
// APIUnspecified searches for a working compiled API.
APIUnspecified API = C.RTMIDI_API_UNSPECIFIED
// APIMacOSXCore uses Macintosh OS-X CoreMIDI API.
APIMacOSXCore = C.RTMIDI_API_MACOSX_CORE
// APILinuxALSA uses the Advanced Linux Sound Architecture API.
APILinuxALSA = C.RTMIDI_API_LINUX_ALSA
// APIUnixJack uses the JACK Low-Latency MIDI Server API.
APIUnixJack = C.RTMIDI_API_UNIX_JACK
// APIWindowsMM uses the Microsoft Multimedia MIDI API.
APIWindowsMM = C.RTMIDI_API_WINDOWS_MM
// APIDummy is a compilable but non-functional API.
APIDummy = C.RTMIDI_API_RTMIDI_DUMMY
)
func (api API) String() string {
switch api {
case APIUnspecified:
return "unspecified"
case APILinuxALSA:
return "alsa"
case APIUnixJack:
return "jack"
case APIMacOSXCore:
return "coreaudio"
case APIWindowsMM:
return "winmm"
case APIDummy:
return "dummy"
}
return "?"
}
// CompiledAPI determines the available compiled MIDI APIs.
func CompiledAPI() (apis []API) {
n := C.rtmidi_get_compiled_api(nil, 0)
capis := make([]C.enum_RtMidiApi, n, n)
C.rtmidi_get_compiled_api(&capis[0], C.uint(n))
for _, capi := range capis {
apis = append(apis, API(capi))
}
return apis
}
// MIDI interface provides a common, platform-independent API for realtime MIDI
// device enumeration and handling MIDI ports.
type MIDI interface {
OpenPort(port int, name string) error
OpenVirtualPort(name string) error
Close() error
PortCount() (int, error)
PortName(port int) (string, error)
}
// MIDIIn interface provides a common, platform-independent API for realtime
// MIDI input. It allows access to a single MIDI input port. Incoming MIDI
// messages are either saved to a queue for retrieval using the Message()
// method or immediately passed to a user-specified callback function. Create
// multiple instances of this class to connect to more than one MIDI device at
// the same time.
type MIDIIn interface {
MIDI
API() (API, error)
IgnoreTypes(midiSysex bool, midiTime bool, midiSense bool) error
SetCallback(func(MIDIIn, []byte, float64)) error
CancelCallback() error
Message() ([]byte, float64, error)
Destroy()
}
// MIDIOut interface provides a common, platform-independent API for MIDI
// output. It allows one to probe available MIDI output ports, to connect to
// one such port, and to send MIDI bytes immediately over the connection.
// Create multiple instances of this class to connect to more than one MIDI
// device at the same time.
type MIDIOut interface {
MIDI
API() (API, error)
SendMessage([]byte) error
Destroy()
}
type midi struct {
midi C.RtMidiPtr
}
func (m *midi) OpenPort(port int, name string) error {
p := C.CString(name)
defer C.free(unsafe.Pointer(p))
C.rtmidi_open_port(m.midi, C.uint(port), p)
if !m.midi.ok {
return errors.New(C.GoString(m.midi.msg))
}
return nil
}
func (m *midi) OpenVirtualPort(name string) error {
p := C.CString(name)
defer C.free(unsafe.Pointer(p))
C.rtmidi_open_virtual_port(m.midi, p)
if !m.midi.ok {
return errors.New(C.GoString(m.midi.msg))
}
return nil
}
func (m *midi) PortName(port int) (string, error) {
p := C.rtmidi_get_port_name(m.midi, C.uint(port))
if !m.midi.ok {
return "", errors.New(C.GoString(m.midi.msg))
}
defer C.free(unsafe.Pointer(p))
return C.GoString(p), nil
}
func (m *midi) PortCount() (int, error) {
n := C.rtmidi_get_port_count(m.midi)
if !m.midi.ok {
return 0, errors.New(C.GoString(m.midi.msg))
}
return int(n), nil
}
func (m *midi) Close() error {
C.rtmidi_close_port(C.RtMidiPtr(m.midi))
if !m.midi.ok {
return errors.New(C.GoString(m.midi.msg))
}
return nil
}
type midiIn struct {
midi
in C.RtMidiInPtr
cb func(MIDIIn, []byte, float64)
}
type midiOut struct {
midi
out C.RtMidiOutPtr
}
// NewMIDIInDefault opens a default MIDIIn port.
func NewMIDIInDefault() (MIDIIn, error) {
in := C.rtmidi_in_create_default()
if !in.ok {
defer C.rtmidi_in_free(in)
return nil, errors.New(C.GoString(in.msg))
}
return &midiIn{in: in, midi: midi{midi: C.RtMidiPtr(in)}}, nil
}
// NewMIDIIn opens a single MIDIIn port using the given API. One can provide a
// custom port name and a desired queue size for the incomming MIDI messages.
func NewMIDIIn(api API, name string, queueSize int) (MIDIIn, error) {
p := C.CString(name)
defer C.free(unsafe.Pointer(p))
in := C.rtmidi_in_create(C.enum_RtMidiApi(api), p, C.uint(queueSize))
if !in.ok {
defer C.rtmidi_in_free(in)
return nil, errors.New(C.GoString(in.msg))
}
return &midiIn{in: in, midi: midi{midi: C.RtMidiPtr(in)}}, nil
}
func (m *midiIn) API() (API, error) {
api := C.rtmidi_in_get_current_api(m.in)
if !m.in.ok {
return APIUnspecified, errors.New(C.GoString(m.in.msg))
}
return API(api), nil
}
func (m *midiIn) Close() error {
unregisterMIDIIn(m)
if err := m.midi.Close(); err != nil {
return err
}
C.rtmidi_in_free(m.in)
return nil
}
func (m *midiIn) IgnoreTypes(midiSysex bool, midiTime bool, midiSense bool) error {
C.rtmidi_in_ignore_types(m.in, C._Bool(midiSysex), C._Bool(midiTime), C._Bool(midiSense))
if !m.in.ok {
return errors.New(C.GoString(m.in.msg))
}
return nil
}
var (
mu sync.Mutex
inputs = map[int]*midiIn{}
)
func registerMIDIIn(m *midiIn) int {
mu.Lock()
defer mu.Unlock()
for i := 0; ; i++ {
if _, ok := inputs[i]; !ok {
inputs[i] = m
return i
}
}
}
func unregisterMIDIIn(m *midiIn) {
mu.Lock()
defer mu.Unlock()
for i := 0; i < len(inputs); i++ {
if inputs[i] == m {
delete(inputs, i)
return
}
}
}
func findMIDIIn(k int) *midiIn {
mu.Lock()
defer mu.Unlock()
return inputs[k]
}
//export goMIDIInCallback
func goMIDIInCallback(ts C.double, msg *C.uchar, msgsz C.size_t, arg unsafe.Pointer) {
k := int(uintptr(arg))
m := findMIDIIn(k)
m.cb(m, C.GoBytes(unsafe.Pointer(msg), C.int(msgsz)), float64(ts))
}
func (m *midiIn) SetCallback(cb func(MIDIIn, []byte, float64)) error {
k := registerMIDIIn(m)
m.cb = cb
C.cgoSetCallback(m.in, C.int(k))
if !m.in.ok {
return errors.New(C.GoString(m.in.msg))
}
return nil
}
func (m *midiIn) CancelCallback() error {
unregisterMIDIIn(m)
C.rtmidi_in_cancel_callback(m.in)
if !m.in.ok {
return errors.New(C.GoString(m.in.msg))
}
return nil
}
func (m *midiIn) Message() ([]byte, float64, error) {
msg := make([]C.uchar, 64*1024, 64*1024)
sz := C.size_t(len(msg))
r := C.rtmidi_in_get_message(m.in, &msg[0], &sz)
if !m.in.ok {
return nil, 0, errors.New(C.GoString(m.in.msg))
}
b := make([]byte, int(sz), int(sz))
for i, c := range msg[:sz] {
b[i] = byte(c)
}
return b, float64(r), nil
}
func (m *midiIn) Destroy() {
C.rtmidi_in_free(m.in)
}
// NewMIDIOutDefault opens a default MIDIOut port.
func NewMIDIOutDefault() (MIDIOut, error) {
out := C.rtmidi_out_create_default()
if !out.ok {
defer C.rtmidi_out_free(out)
return nil, errors.New(C.GoString(out.msg))
}
return &midiOut{out: out, midi: midi{midi: C.RtMidiPtr(out)}}, nil
}
// NewMIDIOut opens a single MIDIIn port using the given API with the given port name.
func NewMIDIOut(api API, name string) (MIDIOut, error) {
p := C.CString(name)
defer C.free(unsafe.Pointer(p))
out := C.rtmidi_out_create(C.enum_RtMidiApi(api), p)
if !out.ok {
defer C.rtmidi_out_free(out)
return nil, errors.New(C.GoString(out.msg))
}
return &midiOut{out: out, midi: midi{midi: C.RtMidiPtr(out)}}, nil
}
func (m *midiOut) API() (API, error) {
api := C.rtmidi_out_get_current_api(m.out)
if !m.out.ok {
return APIUnspecified, errors.New(C.GoString(m.out.msg))
}
return API(api), nil
}
func (m *midiOut) Close() error {
if err := m.midi.Close(); err != nil {
return err
}
C.rtmidi_out_free(m.out)
return nil
}
func (m *midiOut) SendMessage(b []byte) error {
p := C.CBytes(b)
defer C.free(unsafe.Pointer(p))
C.rtmidi_out_send_message(m.out, (*C.uchar)(p), C.int(len(b)))
if !m.out.ok {
return errors.New(C.GoString(m.out.msg))
}
return nil
}
func (m *midiOut) Destroy() {
C.rtmidi_out_free(m.out)
}

View File

@ -0,0 +1,4 @@
#include "../../../RtMidi.h"
#include "../../../RtMidi.cpp"
#include "../../../rtmidi_c.cpp"

View File

@ -0,0 +1 @@
#include "../../../rtmidi_c.h"

View File

@ -0,0 +1,46 @@
package rtmidi
import (
"log"
)
func ExampleCompiledAPI() {
for _, api := range CompiledAPI() {
log.Println("Compiled API: ", api)
}
}
func ExampleMIDIIn_Message() {
in, err := NewMIDIInDefault()
if err != nil {
log.Fatal(err)
}
defer in.Destroy()
if err := in.OpenPort(0, "RtMidi"); err != nil {
log.Fatal(err)
}
defer in.Close()
for {
m, t, err := in.Message()
if len(m) > 0 {
log.Println(m, t, err)
}
}
}
func ExampleMIDIIn_SetCallback() {
in, err := NewMIDIInDefault()
if err != nil {
log.Fatal(err)
}
defer in.Destroy()
if err := in.OpenPort(0, "RtMidi"); err != nil {
log.Fatal(err)
}
defer in.Close()
in.SetCallback(func(m MIDIIn, msg []byte, t float64) {
log.Println(msg, t)
})
<-make(chan struct{})
}

33
extern/rtmidi/doc/Makefile.am vendored Normal file
View File

@ -0,0 +1,33 @@
MAINTAINERCLEANFILES=Makefile.in
CLEANFILES=doxygen-build.stamp
DOX=Doxyfile
EXTRA_DIST=html release.txt
INSTIMAGES=html/doxygen.png
DOC_STAMPS=doxygen-build.stamp
DOC_DIR=$(HTML_DIR)
all-local: doxygen-build.stamp
doxygen-build.stamp: doxygen/$(DOX) $(top_srcdir)/RtMidi.h $(top_srcdir)/rtmidi_c.h
@echo '*** Running doxygen ***'
cd doxygen; $(DOXYGEN) $(DOX)
touch doxygen-build.stamp
clean-local:
rm -f *~ *.bak $(DOC_STAMPS) || true
if test -d html; then rm -fr html; fi
if test -d latex; then rm -fr latex; fi
if test -d man; then rm -fr man; fi
distclean-local: clean
rm -f *.stamp || true
if test -d html; then rm -rf html; fi
html-local: $(DOC_STAMPS)

1865
extern/rtmidi/doc/doxygen/Doxyfile.in vendored Normal file

File diff suppressed because it is too large Load Diff

9
extern/rtmidi/doc/doxygen/footer.html vendored Normal file
View File

@ -0,0 +1,9 @@
<HR>
<table><tr><td><img src="../images/mcgill.gif" width=165></td>
<td>&copy;2003-2021 Gary P. Scavone, McGill University. All Rights Reserved.<br>
Maintained by Gary P. Scavone, gary at music.mcgill.ca</td></tr>
</table>
</BODY>
</HTML>

9
extern/rtmidi/doc/doxygen/header.html vendored Normal file
View File

@ -0,0 +1,9 @@
<HTML>
<HEAD>
<TITLE>The RtMidi Tutorial</TITLE>
<LINK HREF="doxygen.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<CENTER>
<a class="qindex" href="index.html">Tutorial</a> &nbsp; <a class="qindex" href="annotated.html">Class/Enum List</a> &nbsp; <a class="qindex" href="files.html">File List</a> &nbsp; <a class="qindex" href="functions.html">Compound Members</a> &nbsp; <a class="qindex" href="group__C-interface.html">C interface</a> &nbsp; </CENTER>
<HR>

View File

@ -0,0 +1,11 @@
#include "RtMidi.h"
int main() {
try {
RtMidiIn midiin;
} catch (RtMidiError &error) {
// Handle the exception here
error.printMessage();
}
return 0;
}

484
extern/rtmidi/doc/doxygen/tutorial.txt vendored Normal file
View File

@ -0,0 +1,484 @@
/*! \mainpage The RtMidi Tutorial
<CENTER>\ref intro &nbsp;&nbsp; \ref download &nbsp;&nbsp; \ref start &nbsp;&nbsp; \ref error &nbsp;&nbsp; \ref probing &nbsp;&nbsp; \ref output &nbsp;&nbsp; \ref input &nbsp;&nbsp; \ref virtual &nbsp;&nbsp; \ref compiling &nbsp;&nbsp; \ref debug &nbsp;&nbsp; \ref multi &nbsp;&nbsp; \ref apinotes &nbsp;&nbsp; \ref acknowledge &nbsp;&nbsp; \ref license</CENTER>
\section intro Introduction
RtMidi is a set of C++ classes (RtMidiIn, RtMidiOut and API-specific classes) that provides a common API (Application Programming Interface) for realtime MIDI input/output across Linux (ALSA & JACK), Macintosh OS X (CoreMIDI & JACK), and Windows (Multimedia Library) operating systems. RtMidi significantly simplifies the process of interacting with computer MIDI hardware and software. It was designed with the following goals:
- object oriented C++ design
- simple, common API across all supported platforms
- only one header and one source file for easy inclusion in programming projects
- MIDI device enumeration
Where applicable, multiple API support can be compiled and a particular API specified when creating an RtAudio instance.
MIDI input and output functionality are separated into two classes, RtMidiIn and RtMidiOut. Each class instance supports only a single MIDI connection. RtMidi does not provide timing functionality (i.e., output messages are sent immediately). Input messages are timestamped with delta times in seconds (via a \c double floating point type). MIDI data is passed to the user as raw bytes using an std::vector<unsigned char>.
\section whatsnew What's New (Version 5.0.0)
The version number has been bumped to 5.0.0 because a new API (Web MIDI) was added, as well as at least one new function. Changes in this release include:
- see git history for complete list of changes
- new Web MIDI API
- iOS support
- new setBufferSize() function
- fixes for WinMM, Jack
- added C API test program
- now requiring C++11
- build system updates
- midiprobe probes all compiled APIs
- various build system updates and code efficiencies
\section download Download
Latest Release (16 November 2021): <A href="http://www.music.mcgill.ca/~gary/rtmidi/release/rtmidi-5.0.0.tar.gz">Version 5.0.0</A>
\section start Getting Started
The first thing that must be done when using RtMidi is to create an instance of the RtMidiIn or RtMidiOut subclasses. RtMidi is an abstract base class, which itself cannot be instantiated. Each default constructor attempts to establish any necessary "connections" with the underlying MIDI system. RtMidi uses C++ exceptions to report errors, necessitating try/catch blocks around many member functions. An RtMidiError can be thrown during instantiation in some circumstances. A warning message may also be reported if no MIDI devices are found during instantiation. The RtMidi classes have been designed to work with "hot pluggable" or virtual (software) MIDI devices, making it possible to connect to MIDI devices that may not have been present when the classes were instantiated. The following code example demonstrates default object construction and destruction:
\include getting_started.cpp
Obviously, this example doesn't demonstrate any of the real functionality of RtMidi. However, all uses of RtMidi must begin with construction and must end with class destruction. Further, it is necessary that all class methods that can throw a C++ exception be called within a try/catch block.
\section error Error Handling
RtMidi uses a C++ exception handler called RtMidiError, which is
declared and defined in RtMidi.h. The RtMidiError class is quite
simple but it does allow errors to be "caught" by RtMidiError::Type.
Many RtMidi methods can "throw" an RtMidiError, most typically if a
driver error occurs or an invalid function argument is specified.
There are a number of cases within RtMidi where warning messages may
be displayed but an exception is not thrown. A client error callback
function can be specified (via the RtMidi::setErrorCallback function)
that is invoked when an error occurs. By default, error messages are
not automatically displayed in RtMidi unless the preprocessor
definition __RTMIDI_DEBUG__ is defined during compilation. Messages
associated with caught exceptions can be displayed with, for example,
the RtMidiError::printMessage() function.
\section probing Probing Ports / Devices
A client generally must query the available MIDI ports before deciding which to use. The following example outlines how this can be done.
\code
// midiprobe.cpp
#include <iostream>
#include <cstdlib>
#include "RtMidi.h"
int main()
{
RtMidiIn *midiin = 0;
RtMidiOut *midiout = 0;
// RtMidiIn constructor
try {
midiin = new RtMidiIn();
}
catch ( RtMidiError &error ) {
error.printMessage();
exit( EXIT_FAILURE );
}
// Check inputs.
unsigned int nPorts = midiin->getPortCount();
std::cout << "\nThere are " << nPorts << " MIDI input sources available.\n";
std::string portName;
for ( unsigned int i=0; i<nPorts; i++ ) {
try {
portName = midiin->getPortName(i);
}
catch ( RtMidiError &error ) {
error.printMessage();
goto cleanup;
}
std::cout << " Input Port #" << i+1 << ": " << portName << '\n';
}
// RtMidiOut constructor
try {
midiout = new RtMidiOut();
}
catch ( RtMidiError &error ) {
error.printMessage();
exit( EXIT_FAILURE );
}
// Check outputs.
nPorts = midiout->getPortCount();
std::cout << "\nThere are " << nPorts << " MIDI output ports available.\n";
for ( unsigned int i=0; i<nPorts; i++ ) {
try {
portName = midiout->getPortName(i);
}
catch (RtMidiError &error) {
error.printMessage();
goto cleanup;
}
std::cout << " Output Port #" << i+1 << ": " << portName << '\n';
}
std::cout << '\n';
// Clean up
cleanup:
delete midiin;
delete midiout;
return 0;
}
\endcode
Note that the port enumeration is system specific and will change if any devices are unplugged or plugged (or a new virtual port opened or closed) by the user. Thus, the port numbers should be verified immediately before opening a port. As well, if a user unplugs a device (or closes a virtual port) while a port connection exists to that device/port, a MIDI system error will be generated.
\section output MIDI Output
The RtMidiOut class provides simple functionality to immediately send messages over a MIDI connection. No timing functionality is provided. Note that there is an overloaded RtMidiOut::sendMessage() function that does not use std::vectors.
In the following example, we omit necessary error checking and details regarding OS-dependent sleep functions. For a complete example, see the \c midiout.cpp program in the \c tests directory.
\code
// midiout.cpp
#include <iostream>
#include <cstdlib>
#include "RtMidi.h"
int main()
{
RtMidiOut *midiout = new RtMidiOut();
std::vector<unsigned char> message;
// Check available ports.
unsigned int nPorts = midiout->getPortCount();
if ( nPorts == 0 ) {
std::cout << "No ports available!\n";
goto cleanup;
}
// Open first available port.
midiout->openPort( 0 );
// Send out a series of MIDI messages.
// Program change: 192, 5
message.push_back( 192 );
message.push_back( 5 );
midiout->sendMessage( &message );
// Control Change: 176, 7, 100 (volume)
message[0] = 176;
message[1] = 7;
message.push_back( 100 );
midiout->sendMessage( &message );
// Note On: 144, 64, 90
message[0] = 144;
message[1] = 64;
message[2] = 90;
midiout->sendMessage( &message );
SLEEP( 500 ); // Platform-dependent ... see example in tests directory.
// Note Off: 128, 64, 40
message[0] = 128;
message[1] = 64;
message[2] = 40;
midiout->sendMessage( &message );
// Clean up
cleanup:
delete midiout;
return 0;
}
\endcode
\section input MIDI Input
The RtMidiIn class uses an internal callback function or thread to receive incoming MIDI messages from a port or device. These messages are then either queued and read by the user via calls to the RtMidiIn::getMessage() function or immediately passed to a user-specified callback function (which must be "registered" using the RtMidiIn::setCallback() function). Note that if you have multiple instances of RtMidiIn, each may have its own thread. We'll provide examples of both usages.
The RtMidiIn class provides the RtMidiIn::ignoreTypes() function to specify that certain MIDI message types be ignored. By default, system exclusive, timing, and active sensing messages are ignored.
\subsection qmidiin Queued MIDI Input
The RtMidiIn::getMessage() function does not block. If a MIDI message is available in the queue, it is copied to the user-provided \c std::vector<unsigned char> container. When no MIDI message is available, the function returns an empty container. The default maximum MIDI queue size is 1024 messages. This value may be modified with the RtMidiIn::setQueueSizeLimit() function. If the maximum queue size limit is reached, subsequent incoming MIDI messages are discarded until the queue size is reduced.
In the following example, we omit some necessary error checking and details regarding OS-dependent sleep functions. For a more complete example, see the \c qmidiin.cpp program in the \c tests directory.
\code
// qmidiin.cpp
#include <iostream>
#include <cstdlib>
#include <signal.h>
#include "RtMidi.h"
bool done;
static void finish(int ignore){ done = true; }
int main()
{
RtMidiIn *midiin = new RtMidiIn();
std::vector<unsigned char> message;
int nBytes, i;
double stamp;
// Check available ports.
unsigned int nPorts = midiin->getPortCount();
if ( nPorts == 0 ) {
std::cout << "No ports available!\n";
goto cleanup;
}
midiin->openPort( 0 );
// Don't ignore sysex, timing, or active sensing messages.
midiin->ignoreTypes( false, false, false );
// Install an interrupt handler function.
done = false;
(void) signal(SIGINT, finish);
// Periodically check input queue.
std::cout << "Reading MIDI from port ... quit with Ctrl-C.\n";
while ( !done ) {
stamp = midiin->getMessage( &message );
nBytes = message.size();
for ( i=0; i<nBytes; i++ )
std::cout << "Byte " << i << " = " << (int)message[i] << ", ";
if ( nBytes > 0 )
std::cout << "stamp = " << stamp << std::endl;
// Sleep for 10 milliseconds ... platform-dependent.
SLEEP( 10 );
}
// Clean up
cleanup:
delete midiin;
return 0;
}
\endcode
\subsection cmidiin MIDI Input with User Callback
When set, a user-provided callback function will be invoked after the input of a complete MIDI message. It is possible to provide a pointer to user data that can be accessed in the callback function (not shown here). It is necessary to set the callback function immediately after opening the port to avoid having incoming messages written to the queue (which is not emptied when a callback function is set). If you are worried about this happening, you can check the queue using the RtMidi::getMessage() function to verify it is empty (after the callback function is set).
In the following example, we omit some necessary error checking. For a more complete example, see the \c cmidiin.cpp program in the \c tests directory.
\code
// cmidiin.cpp
#include <iostream>
#include <cstdlib>
#include "RtMidi.h"
void mycallback( double deltatime, std::vector< unsigned char > *message, void *userData )
{
unsigned int nBytes = message->size();
for ( unsigned int i=0; i<nBytes; i++ )
std::cout << "Byte " << i << " = " << (int)message->at(i) << ", ";
if ( nBytes > 0 )
std::cout << "stamp = " << deltatime << std::endl;
}
int main()
{
RtMidiIn *midiin = new RtMidiIn();
// Check available ports.
unsigned int nPorts = midiin->getPortCount();
if ( nPorts == 0 ) {
std::cout << "No ports available!\n";
goto cleanup;
}
midiin->openPort( 0 );
// Set our callback function. This should be done immediately after
// opening the port to avoid having incoming messages written to the
// queue.
midiin->setCallback( &mycallback );
// Don't ignore sysex, timing, or active sensing messages.
midiin->ignoreTypes( false, false, false );
std::cout << "\nReading MIDI input ... press <enter> to quit.\n";
char input;
std::cin.get(input);
// Clean up
cleanup:
delete midiin;
return 0;
}
\endcode
\section virtual Virtual Ports
The Linux ALSA, Macintosh CoreMIDI and JACK APIs allow for the establishment of virtual input and output MIDI ports to which other software clients can connect. RtMidi incorporates this functionality with the RtMidiIn::openVirtualPort() and RtMidiOut::openVirtualPort() functions. Any messages sent with the RtMidiOut::sendMessage() function will also be transmitted through an open virtual output port. If a virtual input port is open and a user callback function is set, the callback function will be invoked when messages arrive via that port. If a callback function is not set, the user must poll the input queue to check whether messages have arrived. No notification is provided for the establishment of a client connection via a virtual port. The RtMidi::isPortOpen() function does not report the status of ports created with the RtMidi::openVirtualPort() function.
\section compiling Compiling
In order to compile RtMidi for a specific OS and API, it is necessary to supply the appropriate preprocessor definition and library within the compiler statement:
<P>
<TABLE BORDER=2 COLS=5 WIDTH="100%">
<TR BGCOLOR="beige">
<TD WIDTH="5%"><B>OS:</B></TD>
<TD WIDTH="5%"><B>MIDI API:</B></TD>
<TD WIDTH="5%"><B>Preprocessor Definition:</B></TD>
<TD WIDTH="5%"><B>Library or Framework:</B></TD>
<TD><B>Example Compiler Statement:</B></TD>
</TR>
<TR>
<TD>Linux</TD>
<TD>ALSA Sequencer</TD>
<TD>__LINUX_ALSA__</TD>
<TD><TT>asound, pthread</TT></TD>
<TD><TT>g++ -Wall -D__LINUX_ALSA__ -o midiprobe midiprobe.cpp RtMidi.cpp -lasound -lpthread</TT></TD>
</TR>
<TR>
<TD>Linux or Mac</TD>
<TD>JACK MIDI</TD>
<TD>__UNIX_JACK__</TD>
<TD><TT>jack</TT></TD>
<TD><TT>g++ -Wall -D__UNIX_JACK__ -o midiprobe midiprobe.cpp RtMidi.cpp -ljack</TT></TD>
</TR>
<TR>
<TD>Macintosh OS X</TD>
<TD>CoreMIDI</TD>
<TD>__MACOSX_CORE__</TD>
<TD><TT>CoreMIDI, CoreAudio, CoreFoundation</TT></TD>
<TD><TT>g++ -Wall -D__MACOSX_CORE__ -o midiprobe midiprobe.cpp RtMidi.cpp -framework CoreMIDI -framework CoreAudio -framework CoreFoundation</TT></TD>
</TR>
<TR>
<TD>Windows</TD>
<TD>Multimedia Library</TD>
<TD>__WINDOWS_MM__</TD>
<TD><TT>winmm.lib, multithreaded</TT></TD>
<TD><I>compiler specific</I></TD>
</TR>
</TABLE>
<P>
The example compiler statements above could be used to compile the <TT>midiprobe.cpp</TT> example file, assuming that <TT>midiprobe.cpp</TT>, <TT>RtMidi.h</TT> and <TT>RtMidi.cpp</TT> all exist in the same directory.
\section debug Debugging
If you are having problems getting RtMidi to run on your system, try passing the preprocessor definition <TT>__RTMIDI_DEBUG__</TT> to the compiler (or define it in RtMidi.h). A variety of warning messages will be displayed that may help in determining the problem. Also try using the programs included in the <tt>tests</tt> directory. The program <tt>midiprobe</tt> displays the queried capabilities of all MIDI ports found.
\section multi Using Simultaneous Multiple APIs
Support for each MIDI API is encapsulated in specific MidiInApi or MidiOutApi subclasses, making it possible to compile and instantiate multiple API-specific subclasses on a given operating system. For example, one can compile both CoreMIDI and JACK support on the OS-X operating system by providing the appropriate preprocessor definitions for each. In a run-time situation, one might first attempt to determine whether any JACK ports are available. This can be done by specifying the api argument RtMidi::UNIX_JACK when attempting to create an instance of RtMidiIn or RtMidiOut. If no available ports are found, then an instance of RtMidi with the api argument RtMidi::MACOSX_CORE can be created. Alternately, if no api argument is specified, RtMidi will first look for JACK ports and if none are found, then CoreMIDI ports (in linux, the search order is JACK and then ALSA. In theory, it should also be possible to have separate instances of RtMidi open at the same time with different underlying API support, though this has not been tested.
The static function RtMidi::getCompiledApi() is provided to determine the available compiled API support. The function RtMidi::getCurrentApi() indicates the API selected for a given RtMidi instance.
\section apinotes API Notes
RtMidi is designed to provide a common API across the various supported operating systems and audio libraries. Despite that, some issues should be mentioned with regard to each.
\subsection linux Linux:
RtMidi for Linux was developed using the Fedora distribution. Two different MIDI APIs are supported on Linux platforms: <A href="http://www.alsa-project.org/">ALSA</A> and <A href="http://jackit.sourceforge.net/">JACK</A>. A decision was made to not include support for the OSS API because the OSS API provides very limited functionality and because <A href="http://www.alsa-project.org/">ALSA</A> support is now incorporated in the Linux kernel. The ALSA sequencer and JACK APIs allows for virtual software input and output ports.
\subsection macosx Macintosh OS X (CoreAudio):
The Apple CoreMIDI API allows for the establishment of virtual input and output ports to which other software applications can connect.
The RtMidi JACK support can be compiled on Macintosh OS-X systems, as well as in Linux.
\subsection windowsds Windows (Multimedia Library):
The \c configure script provides support for the MinGW compiler.
The Windows Multimedia library MIDI calls used in RtMidi do not make use of streaming functionality. Incoming system exclusive messages read by RtMidiIn are limited to a length as defined by the preprocessor definition RT_SYSEX_BUFFER_SIZE (set in RtMidi.cpp). The default value is 1024. There is no such limit for outgoing sysex messages via RtMidiOut.
RtMidi was originally developed with Visual C++ version 6.0 but has been tested with Virtual Studio 2010.
\section acknowledge Development & Acknowledgements
RtMidi is on github (https://github.com/thestk/rtmidi). Many thanks to the developers that are helping to maintain and improve RtMidi.
In years past, the following people provided bug fixes and improvements:
- Stephen Sinclair (Git repo, code and build system)
- amosonn
- Christopher Arndt
- Atsushi Eno (C API)
- Sebastien Alaiwan (JACK memory leaks, Windows kernel streaming)
- Jean-Baptiste Berruchon (Windows sysex code)
- Pedro Lopez-Cabanillas (ALSA sequencer API, client naming)
- Jason Champion (MSW project file for library build)
- Chris Chronopoulos
- JP Cimalando
- Eduardo Coutinho (Windows device names)
- Mattes D
- Michael Dahl
- Paul Dean (increment optimization)
- Francisco Demartino
- Luc Deschenaux (sysex issues)
- John Dey (OS-X timestamps)
- Christoph Eckert (ALSA sysex fixes)
- Thiago Goulart
- Ashley Hedges
- Sam Hocevar
- Rorey Jaffe
- jgvictores
- Martin Koegler (various fixes)
- Immanuel Litzroth (OS-X sysex fix)
- Bartek Lukawski
- Andi McClure
- Jon McCormack (Snow Leopard updates)
- Phildo
- Lane Spangler
- Axel Schmidt (client naming)
- Ryan Schmidt
- Saga Musix
- Bart Spaans
- Alexander Svetalkin (JACK MIDI)
- Ben Swift
- Casey Tucker (OS-X driver information, sysex sending)
- Bastiaan Verreijt (Windows sysex multi-buffer code)
- Dan Wilcox
- Yuri
- Serge Zaitsev
- Iohannes Zm&ouml;lnig
\section license License
RtMidi: realtime MIDI i/o C++ classes<BR>
Copyright (c) 2003-2019 Gary P. Scavone
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
Any person wishing to distribute modifications to the Software is
asked to send the modifications to the original developer so that
they can be incorporated into the canonical version. This is,
however, not a binding provision of this license.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

BIN
extern/rtmidi/doc/images/ccrma.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
extern/rtmidi/doc/images/mcgill.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

141
extern/rtmidi/doc/release.txt vendored Normal file
View File

@ -0,0 +1,141 @@
RtMidi - a set of C++ classes that provides a common API for realtime MIDI input/output across Linux (ALSA & JACK), Macintosh OS X (CoreMIDI & JACK), and Windows (Multimedia Library).
By Gary P. Scavone, 2003-2021 (with help from many others, especially Stephen Sinclair!)
v.5.0.0: (16 November 2021)
- see git history for complete list of changes
- new Web MIDI API
- iOS support
- new setBufferSize() function
- fixes for WinMM, Jack
- added C API test program
- now requiring C++11
- build system updates
- midiprobe probes all compiled APIs
- various build system updates and code efficiencies
v.4.0.0: (17 April 2019)
- see git history for complete list of changes
- updates to test programs to clarify port numbering
- new C API wrapper
- new functions to get API names
- miscellaneous sysex fixes in Jack and ALSA
- new setPortName() method (for Jack and ALSA)
- new setClientName() method (for ALSA)
- various build system updates and code efficiencies
v.3.0.0: (31 August 2017)
- see git history for complete list of changes
- new sendMessage() function that does not use std::vector
- various std::string updates, including use of UTF8 for port names
- fixes for the MIDI queue
- various build system updates and code efficiencies
v2.1.1: (11 February 2016)
- updates to automake routines
- added C API (thanks to Atsushi Eno!)
- JACK ringbuffer allocation change
- OSX virtual port closing fix
- OSX sysex sending fix
- moved Windows kernel streaming code to other branch because it is incomplete
- miscellaneous small fixes
v2.1.0: (30 March 2014)
- renamed RtError class to RtMidiError and embedded it in RtMidi.h (and deleted RtError.h)
- fix to CoreMIDI implementation to support dynamic port changes
- removed global ALSA sequencer objects because they were not thread safe (Martin Koegler)
- fix for ALSA timing ignore flag (Devin Anderson)
- fix for ALSA incorrect use of snd_seq_create_port() function (Tobias Schlemmer)
- fix for international character support in CoreMIDI (Martin Finke)
- fix for unicode conversion in WinMM (Dan Wilcox)
- added custom error hook that allows the client to capture an RtMidi error outside of the RtMidi code (Pavel Mogilevskiy)
- added RtMidi::isPortOpen function (Pavel Mogilevskiy)
- updated OS-X sysex sending mechanism to use normal message sending, which fixes a problem where virtual ports didn't receive sysex messages
- Windows update to avoid lockups when shutting down while sending/receiving sysex messages (ptarabbia)
- OS-X fix to avoid empty messages in callbacks when ignoring sysex messages and split sysexes are received (codepainters)
- ALSA openPort fix to better distinguish sender and receiver (Russell Smyth)
- Windows Kernel Streaming support removed because it was uncompilable and incomplete
v2.0.1: (26 July 2012)
- small fixes for problems reported by Chris Arndt (scoping, preprocessor, and include)
v2.0.0: (18 June 2012)
- revised structure to support multiple simultaneous compiled APIs
- revised ALSA client hierarchy so subsequent instances share same client (thanks to Dan Wilcox)
- added beta Windows kernel streaming support (thanks to Sebastien Alaiwan)
- updates to compile as a shared library or dll
- updated license
- various memory-leak fixes (thanks to Sebastien Alaiwan and Martin Koegler)
- fix for continue sysex problem (thanks to Luc Deschenaux)
- removed SGI (IRIX) support
v1.0.15: (11 August 2011)
- updates for wide character support in Windows
- stopped using std::queue and implemented internal MIDI ring buffer (for thread safety ... thanks to Michael Behrman)
- removal of the setQueueSizeLimit() function ... queue size limit now an optional arguement to constructor
v1.0.14: (17 April 2011)
- bug fix to Jack MIDI support (thanks to Alexander Svetalkin and Pedro Lopez-Cabanillas)
v1.0.13: (7 April 2011)
- updated RtError.h to the same version as in RtAudio
- new Jack MIDI support in Linux (thanks to Alexander Svetalkin)
v1.0.12: (17 February 2011)
- Windows 64-bit pointer fixes (thanks to Ward Kockelkorn)
- removed possible exceptions from getPortName() functions
- changed sysex sends in OS-X to use MIDISendSysex() function (thanks to Casey Tucker)
- bug fixes to time code parsing in OS-X and ALSA (thanks to Greg)
- added MSW project file to build as library (into lib/ directory ... thanks to Jason Champion)
v1.0.11: (29 January 2010)
- added CoreServices/CoreServices.h include for OS-X 10.6 and gcc4.2 compile (thanks to Jon McCormack)
- various increment optimizations (thanks to Paul Dean)
- fixed incorrectly located snd_seq_close() function in ALSA API (thanks to Pedro Lopez-Cabanillas)
- updates to Windows sysex code to better deal with possible delivery problems (thanks to Bastiaan Verreijt)
v1.0.10: (3 June 2009)
- fix adding timestamp to OS-X sendMessage() function (thanks to John Dey)
v1.0.9: (30 April 2009)
- added #ifdef AVOID_TIMESTAMPING to conditionally compile support for event timestamping of ALSA sequencer events. This is useful for programs not needing timestamps, saving valuable system resources.
- updated functionality in OSX_CORE for getting driver name (thanks to Casey Tucker)
v1.0.8: (29 January 2009)
- bug fixes for concatenating segmented sysex messages in ALSA (thanks to Christoph Eckert)
- update to ALSA sequencer port enumeration (thanks to Pedro Lopez-Cabonillas)
- bug fixes for concatenating segmented sysex messages in OS-X (thanks to Emmanuel Litzroth)
- added functionality for naming clients (thanks to Pedro Lopez-Cabonillas and Axel Schmidt)
- bug fix in Windows when receiving sysex messages if the ignore flag was set (thanks to Pedro Lopez-Cabonillas)
v1.0.7: (7 December 2007)
- configure and Makefile changes for MinGW
- renamed midiinfo.cpp to midiprobe.cpp and updated VC++ project/workspace
v1.0.6: (9 March 2006)
- bug fix for timestamp problem in ALSA (thanks to Pedro Lopez-Cabanillas)
v1.0.5: (18 November 2005)
- added optional port name to openVirtualPort() functions
- fixed UNICODE problem in Windows getting device names (thanks Eduardo Coutinho!).
- fixed bug in Windows with respect to getting Sysex data (thanks Jean-Baptiste Berruchon!)
v1.0.4: (14 October 2005)
- added check for status byte == 0xF8 if ignoring timing messages
- changed pthread attribute to SCHED_OTHER (from SCHED_RR) to avoid thread problem when realtime cababilities are not enabled.
- now using ALSA sequencer time stamp information (thanks to Pedro Lopez-Cabanillas)
- fixed memory leak in ALSA implementation
- now concatenate segmented sysex messages in ALSA
v1.0.3: (22 November 2004)
- added common pure virtual functions to RtMidi abstract base class
v1.0.2: (21 September 2004)
- added warning messages to openVirtualPort() functions in Windows and Irix (where it can't be implemented)
v1.0.1: (20 September 2004)
- changed ALSA preprocessor definition to __LINUX_ALSASEQ__
v1.0.0: (17 September 2004)
- first release of new independent class with both input and output functionality

View File

@ -0,0 +1,951 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the specified
# version of the C++ standard. If necessary, add switches to CXX and
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
# or '14' (for the C++14 standard).
#
# The second argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The third argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline support for the specified C++ standard is
# required and that the macro should error out if no mode with that
# support is found. If specified 'optional', then configuration proceeds
# regardless, after defining HAVE_CXX${VERSION} if and only if a
# supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 11
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
[$2], [noext], [],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for alternative in ${ax_cxx_compile_alternatives}; do
switch="-std=gnu++${alternative}"
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
done
fi])
m4_if([$2], [ext], [], [dnl
if test x$ac_success = xno; then
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for alternative in ${ax_cxx_compile_alternatives}; do
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
done
if test x$ac_success = xyes; then
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
fi
fi
if test x$ac_success = xno; then
HAVE_CXX$1=0
AC_MSG_NOTICE([No compiler with C++$1 support was found])
else
HAVE_CXX$1=1
AC_DEFINE(HAVE_CXX$1,1,
[define if the compiler supports basic C++$1 syntax])
fi
AC_SUBST(HAVE_CXX$1)
])
dnl Test body for checking C++11 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
)
dnl Test body for checking C++14 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)
dnl Tests for new features in C++11
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
// If the compiler admits that it is not ready for C++11, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#else
namespace cxx11
{
namespace test_static_assert
{
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
}
namespace test_final_override
{
struct Base
{
virtual ~Base() {}
virtual void f() {}
};
struct Derived : public Base
{
virtual ~Derived() override {}
virtual void f() override {}
};
}
namespace test_double_right_angle_brackets
{
template < typename T >
struct check {};
typedef check<void> single_type;
typedef check<check<void>> double_type;
typedef check<check<check<void>>> triple_type;
typedef check<check<check<check<void>>>> quadruple_type;
}
namespace test_decltype
{
int
f()
{
int a = 1;
decltype(a) b = 2;
return a + b;
}
}
namespace test_type_deduction
{
template < typename T1, typename T2 >
struct is_same
{
static const bool value = false;
};
template < typename T >
struct is_same<T, T>
{
static const bool value = true;
};
template < typename T1, typename T2 >
auto
add(T1 a1, T2 a2) -> decltype(a1 + a2)
{
return a1 + a2;
}
int
test(const int c, volatile int v)
{
static_assert(is_same<int, decltype(0)>::value == true, "");
static_assert(is_same<int, decltype(c)>::value == false, "");
static_assert(is_same<int, decltype(v)>::value == false, "");
auto ac = c;
auto av = v;
auto sumi = ac + av + 'x';
auto sumf = ac + av + 1.0;
static_assert(is_same<int, decltype(ac)>::value == true, "");
static_assert(is_same<int, decltype(av)>::value == true, "");
static_assert(is_same<int, decltype(sumi)>::value == true, "");
static_assert(is_same<int, decltype(sumf)>::value == false, "");
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
return (sumf > 0.0) ? sumi : add(c, v);
}
}
namespace test_noexcept
{
int f() { return 0; }
int g() noexcept { return 0; }
static_assert(noexcept(f()) == false, "");
static_assert(noexcept(g()) == true, "");
}
namespace test_constexpr
{
template < typename CharT >
unsigned long constexpr
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
{
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
}
template < typename CharT >
unsigned long constexpr
strlen_c(const CharT *const s) noexcept
{
return strlen_c_r(s, 0UL);
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("1") == 1UL, "");
static_assert(strlen_c("example") == 7UL, "");
static_assert(strlen_c("another\0example") == 7UL, "");
}
namespace test_rvalue_references
{
template < int N >
struct answer
{
static constexpr int value = N;
};
answer<1> f(int&) { return answer<1>(); }
answer<2> f(const int&) { return answer<2>(); }
answer<3> f(int&&) { return answer<3>(); }
void
test()
{
int i = 0;
const int c = 0;
static_assert(decltype(f(i))::value == 1, "");
static_assert(decltype(f(c))::value == 2, "");
static_assert(decltype(f(0))::value == 3, "");
}
}
namespace test_uniform_initialization
{
struct test
{
static const int zero {};
static const int one {1};
};
static_assert(test::zero == 0, "");
static_assert(test::one == 1, "");
}
namespace test_lambdas
{
void
test1()
{
auto lambda1 = [](){};
auto lambda2 = lambda1;
lambda1();
lambda2();
}
int
test2()
{
auto a = [](int i, int j){ return i + j; }(1, 2);
auto b = []() -> int { return '0'; }();
auto c = [=](){ return a + b; }();
auto d = [&](){ return c; }();
auto e = [a, &b](int x) mutable {
const auto identity = [](int y){ return y; };
for (auto i = 0; i < a; ++i)
a += b--;
return x + identity(a + b);
}(0);
return a + b + c + d + e;
}
int
test3()
{
const auto nullary = [](){ return 0; };
const auto unary = [](int x){ return x; };
using nullary_t = decltype(nullary);
using unary_t = decltype(unary);
const auto higher1st = [](nullary_t f){ return f(); };
const auto higher2nd = [unary](nullary_t f1){
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
};
return higher1st(nullary) + higher2nd(nullary)(unary);
}
}
namespace test_variadic_templates
{
template <int...>
struct sum;
template <int N0, int... N1toN>
struct sum<N0, N1toN...>
{
static constexpr auto value = N0 + sum<N1toN...>::value;
};
template <>
struct sum<>
{
static constexpr auto value = 0;
};
static_assert(sum<>::value == 0, "");
static_assert(sum<1>::value == 1, "");
static_assert(sum<23>::value == 23, "");
static_assert(sum<1, 2>::value == 3, "");
static_assert(sum<5, 5, 11>::value == 21, "");
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
}
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
// because of this.
namespace test_template_alias_sfinae
{
struct foo {};
template<typename T>
using member = typename T::member_type;
template<typename T>
void func(...) {}
template<typename T>
void func(member<T>*) {}
void test();
void test() { func<foo>(0); }
}
} // namespace cxx11
#endif // __cplusplus >= 201103L
]])
dnl Tests for new features in C++14
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
// If the compiler admits that it is not ready for C++14, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201402L
#error "This is not a C++14 compiler"
#else
namespace cxx14
{
namespace test_polymorphic_lambdas
{
int
test()
{
const auto lambda = [](auto&&... args){
const auto istiny = [](auto x){
return (sizeof(x) == 1UL) ? 1 : 0;
};
const int aretiny[] = { istiny(args)... };
return aretiny[0];
};
return lambda(1, 1L, 1.0f, '1');
}
}
namespace test_binary_literals
{
constexpr auto ivii = 0b0000000000101010;
static_assert(ivii == 42, "wrong value");
}
namespace test_generalized_constexpr
{
template < typename CharT >
constexpr unsigned long
strlen_c(const CharT *const s) noexcept
{
auto length = 0UL;
for (auto p = s; *p; ++p)
++length;
return length;
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("x") == 1UL, "");
static_assert(strlen_c("test") == 4UL, "");
static_assert(strlen_c("another\0test") == 7UL, "");
}
namespace test_lambda_init_capture
{
int
test()
{
auto x = 0;
const auto lambda1 = [a = x](int b){ return a + b; };
const auto lambda2 = [a = lambda1(x)](){ return a; };
return lambda2();
}
}
namespace test_digit_separators
{
constexpr auto ten_million = 100'000'000;
static_assert(ten_million == 100000000, "");
}
namespace test_return_type_deduction
{
auto f(int& x) { return x; }
decltype(auto) g(int& x) { return x; }
template < typename T1, typename T2 >
struct is_same
{
static constexpr auto value = false;
};
template < typename T >
struct is_same<T, T>
{
static constexpr auto value = true;
};
int
test()
{
auto x = 0;
static_assert(is_same<int, decltype(f(x))>::value, "");
static_assert(is_same<int&, decltype(g(x))>::value, "");
return x;
}
}
} // namespace cxx14
#endif // __cplusplus >= 201402L
]])
dnl Tests for new features in C++17
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
// If the compiler admits that it is not ready for C++17, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201703L
#error "This is not a C++17 compiler"
#else
#include <initializer_list>
#include <utility>
#include <type_traits>
namespace cxx17
{
namespace test_constexpr_lambdas
{
constexpr int foo = [](){return 42;}();
}
namespace test::nested_namespace::definitions
{
}
namespace test_fold_expression
{
template<typename... Args>
int multiply(Args... args)
{
return (args * ... * 1);
}
template<typename... Args>
bool all(Args... args)
{
return (args && ...);
}
}
namespace test_extended_static_assert
{
static_assert (true);
}
namespace test_auto_brace_init_list
{
auto foo = {5};
auto bar {5};
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
static_assert(std::is_same<int, decltype(bar)>::value);
}
namespace test_typename_in_template_template_parameter
{
template<template<typename> typename X> struct D;
}
namespace test_fallthrough_nodiscard_maybe_unused_attributes
{
int f1()
{
return 42;
}
[[nodiscard]] int f2()
{
[[maybe_unused]] auto unused = f1();
switch (f1())
{
case 17:
f1();
[[fallthrough]];
case 42:
f1();
}
return f1();
}
}
namespace test_extended_aggregate_initialization
{
struct base1
{
int b1, b2 = 42;
};
struct base2
{
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2
{
int d;
};
derived d1 {{1, 2}, {}, 4}; // full initialization
derived d2 {{}, {}, 4}; // value-initialized bases
}
namespace test_general_range_based_for_loop
{
struct iter
{
int i;
int& operator* ()
{
return i;
}
const int& operator* () const
{
return i;
}
iter& operator++()
{
++i;
return *this;
}
};
struct sentinel
{
int i;
};
bool operator== (const iter& i, const sentinel& s)
{
return i.i == s.i;
}
bool operator!= (const iter& i, const sentinel& s)
{
return !(i == s);
}
struct range
{
iter begin() const
{
return {0};
}
sentinel end() const
{
return {5};
}
};
void f()
{
range r {};
for (auto i : r)
{
[[maybe_unused]] auto v = i;
}
}
}
namespace test_lambda_capture_asterisk_this_by_value
{
struct t
{
int i;
int foo()
{
return [*this]()
{
return i;
}();
}
};
}
namespace test_enum_class_construction
{
enum class byte : unsigned char
{};
byte foo {42};
}
namespace test_constexpr_if
{
template <bool cond>
int f ()
{
if constexpr(cond)
{
return 13;
}
else
{
return 42;
}
}
}
namespace test_selection_statement_with_initializer
{
int f()
{
return 13;
}
int f2()
{
if (auto i = f(); i > 0)
{
return 3;
}
switch (auto i = f(); i + 4)
{
case 17:
return 2;
default:
return 1;
}
}
}
namespace test_template_argument_deduction_for_class_templates
{
template <typename T1, typename T2>
struct pair
{
pair (T1 p1, T2 p2)
: m1 {p1},
m2 {p2}
{}
T1 m1;
T2 m2;
};
void f()
{
[[maybe_unused]] auto p = pair{13, 42u};
}
}
namespace test_non_type_auto_template_parameters
{
template <auto n>
struct B
{};
B<5> b1;
B<'a'> b2;
}
namespace test_structured_bindings
{
int arr[2] = { 1, 2 };
std::pair<int, int> pr = { 1, 2 };
auto f1() -> int(&)[2]
{
return arr;
}
auto f2() -> std::pair<int, int>&
{
return pr;
}
struct S
{
int x1 : 2;
volatile double y1;
};
S f3()
{
return {};
}
auto [ x1, y1 ] = f1();
auto& [ xr1, yr1 ] = f1();
auto [ x2, y2 ] = f2();
auto& [ xr2, yr2 ] = f2();
const auto [ x3, y3 ] = f3();
}
namespace test_exception_spec_type_system
{
struct Good {};
struct Bad {};
void g1() noexcept;
void g2();
template<typename T>
Bad
f(T*, T*);
template<typename T1, typename T2>
Good
f(T1*, T2*);
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
}
namespace test_inline_variables
{
template<class T> void f(T)
{}
template<class T> inline T g(T)
{
return T{};
}
template<> inline void f<>(int)
{}
template<> int g<>(int)
{
return 5;
}
}
} // namespace cxx17
#endif // __cplusplus < 201703L
]])

1
extern/rtmidi/msw/readme vendored Normal file
View File

@ -0,0 +1 @@
This directory contains a Visual Studio 2008 project, contributed by Jason Champion, to build rtmidi as a library. The library builds to the <rtmidi-x.x.x>\lib directory.

20
extern/rtmidi/msw/rtmidilib.sln vendored Executable file
View File

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtmidilib", "rtmidilib.vcproj", "{EBFE5EB3-182A-47A6-922B-52ECF777F6A3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EBFE5EB3-182A-47A6-922B-52ECF777F6A3}.Debug|Win32.ActiveCfg = Debug|Win32
{EBFE5EB3-182A-47A6-922B-52ECF777F6A3}.Debug|Win32.Build.0 = Debug|Win32
{EBFE5EB3-182A-47A6-922B-52ECF777F6A3}.Release|Win32.ActiveCfg = Release|Win32
{EBFE5EB3-182A-47A6-922B-52ECF777F6A3}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

186
extern/rtmidi/msw/rtmidilib.vcproj vendored Executable file
View File

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="rtmidilib"
ProjectGUID="{EBFE5EB3-182A-47A6-922B-52ECF777F6A3}"
RootNamespace="rtmidilib"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="__WINDOWS_MM__"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="..\lib\rtmidid.lib"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="__WINDOWS_MM__"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="..\lib\rtmidi.lib"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\RtMidi.cpp"
>
</File>
<File
RelativePath="..\rtmidi_c.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\RtError.h"
>
</File>
<File
RelativePath="..\RtMidi.h"
>
</File>
<File
RelativePath="..\rtmidi_c.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

19
extern/rtmidi/rtmidi-config.in vendored Normal file
View File

@ -0,0 +1,19 @@
#! /bin/sh
if (test "x$#" != "x1") ; then
echo "Usage: $0 [--libs | --cxxflags | --cppflags]"
exit;
fi
LIBRARY="@LIBS@"
CXXFLAGS="@CXXFLAGS@"
CPPFLAGS="@CPPFLAGS@"
if (test "x$1" = "x--libs") ; then
echo "$LIBRARY -lrtmidi"
elif (test "x$1" = "x--cxxflags") ; then
echo "$CXXFLAGS"
elif (test "x$1" = "x--cppflags") ; then
echo "$CPPFLAGS"
else
echo "Unknown option: $1"
fi

12
extern/rtmidi/rtmidi.pc.in vendored Normal file
View File

@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include/rtmidi
Name: librtmidi
Description: RtMidi - a set of C++ classes that provide a common API for realtime MIDI input/output
Version: @PACKAGE_VERSION@
Requires.private: @req@
Libs: -L${libdir} -lrtmidi
Libs.private: -lpthread @req_libs@
Cflags: -pthread -I${includedir} @api@

372
extern/rtmidi/rtmidi_c.cpp vendored Normal file
View File

@ -0,0 +1,372 @@
#include <string.h>
#include <stdlib.h>
#include "rtmidi_c.h"
#include "RtMidi.h"
/* Compile-time assertions that will break if the enums are changed in
* the future without synchronizing them properly. If you get (g++)
* "error: StaticAssert<b>::StaticAssert() [with bool b = false] is
* private within this context", it means enums are not aligned. */
template<bool b> class StaticAssert { private: StaticAssert() {} };
template<> class StaticAssert<true>{ public: StaticAssert() {} };
#define ENUM_EQUAL(x,y) StaticAssert<(int)x==(int)y>()
class StaticAssertions { StaticAssertions() {
ENUM_EQUAL( RTMIDI_API_UNSPECIFIED, RtMidi::UNSPECIFIED );
ENUM_EQUAL( RTMIDI_API_MACOSX_CORE, RtMidi::MACOSX_CORE );
ENUM_EQUAL( RTMIDI_API_LINUX_ALSA, RtMidi::LINUX_ALSA );
ENUM_EQUAL( RTMIDI_API_UNIX_JACK, RtMidi::UNIX_JACK );
ENUM_EQUAL( RTMIDI_API_WINDOWS_MM, RtMidi::WINDOWS_MM );
ENUM_EQUAL( RTMIDI_API_RTMIDI_DUMMY, RtMidi::RTMIDI_DUMMY );
ENUM_EQUAL( RTMIDI_ERROR_WARNING, RtMidiError::WARNING );
ENUM_EQUAL( RTMIDI_ERROR_DEBUG_WARNING, RtMidiError::DEBUG_WARNING );
ENUM_EQUAL( RTMIDI_ERROR_UNSPECIFIED, RtMidiError::UNSPECIFIED );
ENUM_EQUAL( RTMIDI_ERROR_NO_DEVICES_FOUND, RtMidiError::NO_DEVICES_FOUND );
ENUM_EQUAL( RTMIDI_ERROR_INVALID_DEVICE, RtMidiError::INVALID_DEVICE );
ENUM_EQUAL( RTMIDI_ERROR_MEMORY_ERROR, RtMidiError::MEMORY_ERROR );
ENUM_EQUAL( RTMIDI_ERROR_INVALID_PARAMETER, RtMidiError::INVALID_PARAMETER );
ENUM_EQUAL( RTMIDI_ERROR_INVALID_USE, RtMidiError::INVALID_USE );
ENUM_EQUAL( RTMIDI_ERROR_DRIVER_ERROR, RtMidiError::DRIVER_ERROR );
ENUM_EQUAL( RTMIDI_ERROR_SYSTEM_ERROR, RtMidiError::SYSTEM_ERROR );
ENUM_EQUAL( RTMIDI_ERROR_THREAD_ERROR, RtMidiError::THREAD_ERROR );
}};
class CallbackProxyUserData
{
public:
CallbackProxyUserData (RtMidiCCallback cCallback, void *userData)
: c_callback (cCallback), user_data (userData)
{
}
RtMidiCCallback c_callback;
void *user_data;
};
extern "C" const enum RtMidiApi rtmidi_compiled_apis[]; // casting from RtMidi::Api[]
extern "C" const unsigned int rtmidi_num_compiled_apis;
/* RtMidi API */
int rtmidi_get_compiled_api (enum RtMidiApi *apis, unsigned int apis_size)
{
unsigned num = rtmidi_num_compiled_apis;
if (apis) {
num = (num < apis_size) ? num : apis_size;
memcpy(apis, rtmidi_compiled_apis, num * sizeof(enum RtMidiApi));
}
return (int)num;
}
extern "C" const char* rtmidi_api_names[][2];
const char *rtmidi_api_name(enum RtMidiApi api) {
if (api < 0 || api >= RTMIDI_API_NUM)
return NULL;
return rtmidi_api_names[api][0];
}
const char *rtmidi_api_display_name(enum RtMidiApi api)
{
if (api < 0 || api >= RTMIDI_API_NUM)
return "Unknown";
return rtmidi_api_names[api][1];
}
enum RtMidiApi rtmidi_compiled_api_by_name(const char *name) {
RtMidi::Api api = RtMidi::UNSPECIFIED;
if (name) {
api = RtMidi::getCompiledApiByName(name);
}
return (enum RtMidiApi)api;
}
void rtmidi_error (MidiApi *api, enum RtMidiErrorType type, const char* errorString)
{
std::string msg = errorString;
api->error ((RtMidiError::Type) type, msg);
}
void rtmidi_open_port (RtMidiPtr device, unsigned int portNumber, const char *portName)
{
std::string name = portName;
try {
((RtMidi*) device->ptr)->openPort (portNumber, name);
} catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
}
}
void rtmidi_open_virtual_port (RtMidiPtr device, const char *portName)
{
std::string name = portName;
try {
((RtMidi*) device->ptr)->openVirtualPort (name);
} catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
}
}
void rtmidi_close_port (RtMidiPtr device)
{
try {
((RtMidi*) device->ptr)->closePort ();
} catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
}
}
unsigned int rtmidi_get_port_count (RtMidiPtr device)
{
try {
return ((RtMidi*) device->ptr)->getPortCount ();
} catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
return -1;
}
}
int rtmidi_get_port_name (RtMidiPtr device, unsigned int portNumber, char * bufOut, int * bufLen)
{
if (bufOut == nullptr && bufLen == nullptr) {
return -1;
}
std::string name;
try {
name = ((RtMidi*) device->ptr)->getPortName (portNumber);
} catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
return -1;
}
if (bufOut == nullptr) {
*bufLen = static_cast<int>(name.size()) + 1;
return 0;
}
return snprintf(bufOut, static_cast<size_t>(*bufLen), "%s", name.c_str());
}
/* RtMidiIn API */
RtMidiInPtr rtmidi_in_create_default ()
{
RtMidiWrapper* wrp = new RtMidiWrapper;
try {
RtMidiIn* rIn = new RtMidiIn ();
wrp->ptr = (void*) rIn;
wrp->data = 0;
wrp->ok = true;
wrp->msg = "";
} catch (const RtMidiError & err) {
wrp->ptr = 0;
wrp->data = 0;
wrp->ok = false;
wrp->msg = err.what ();
}
return wrp;
}
RtMidiInPtr rtmidi_in_create (enum RtMidiApi api, const char *clientName, unsigned int queueSizeLimit)
{
std::string name = clientName;
RtMidiWrapper* wrp = new RtMidiWrapper;
try {
RtMidiIn* rIn = new RtMidiIn ((RtMidi::Api) api, name, queueSizeLimit);
wrp->ptr = (void*) rIn;
wrp->data = 0;
wrp->ok = true;
wrp->msg = "";
} catch (const RtMidiError & err) {
wrp->ptr = 0;
wrp->data = 0;
wrp->ok = false;
wrp->msg = err.what ();
}
return wrp;
}
void rtmidi_in_free (RtMidiInPtr device)
{
if (device->data)
delete (CallbackProxyUserData*) device->data;
delete (RtMidiIn*) device->ptr;
delete device;
}
enum RtMidiApi rtmidi_in_get_current_api (RtMidiPtr device)
{
try {
return (RtMidiApi) ((RtMidiIn*) device->ptr)->getCurrentApi ();
} catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
return RTMIDI_API_UNSPECIFIED;
}
}
static
void callback_proxy (double timeStamp, std::vector<unsigned char> *message, void *userData)
{
CallbackProxyUserData* data = reinterpret_cast<CallbackProxyUserData*> (userData);
data->c_callback (timeStamp, message->data (), message->size (), data->user_data);
}
void rtmidi_in_set_callback (RtMidiInPtr device, RtMidiCCallback callback, void *userData)
{
device->data = (void*) new CallbackProxyUserData (callback, userData);
try {
((RtMidiIn*) device->ptr)->setCallback (callback_proxy, device->data);
} catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
delete (CallbackProxyUserData*) device->data;
device->data = 0;
}
}
void rtmidi_in_cancel_callback (RtMidiInPtr device)
{
try {
((RtMidiIn*) device->ptr)->cancelCallback ();
delete (CallbackProxyUserData*) device->data;
device->data = 0;
} catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
}
}
void rtmidi_in_ignore_types (RtMidiInPtr device, bool midiSysex, bool midiTime, bool midiSense)
{
((RtMidiIn*) device->ptr)->ignoreTypes (midiSysex, midiTime, midiSense);
}
double rtmidi_in_get_message (RtMidiInPtr device,
unsigned char *message,
size_t *size)
{
try {
// FIXME: use allocator to achieve efficient buffering
std::vector<unsigned char> v;
double ret = ((RtMidiIn*) device->ptr)->getMessage (&v);
if (v.size () > 0 && v.size() <= *size) {
memcpy (message, v.data (), (int) v.size ());
}
*size = v.size();
return ret;
}
catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
return -1;
}
catch (...) {
device->ok = false;
device->msg = "Unknown error";
return -1;
}
}
/* RtMidiOut API */
RtMidiOutPtr rtmidi_out_create_default ()
{
RtMidiWrapper* wrp = new RtMidiWrapper;
try {
RtMidiOut* rOut = new RtMidiOut ();
wrp->ptr = (void*) rOut;
wrp->data = 0;
wrp->ok = true;
wrp->msg = "";
} catch (const RtMidiError & err) {
wrp->ptr = 0;
wrp->data = 0;
wrp->ok = false;
wrp->msg = err.what ();
}
return wrp;
}
RtMidiOutPtr rtmidi_out_create (enum RtMidiApi api, const char *clientName)
{
RtMidiWrapper* wrp = new RtMidiWrapper;
std::string name = clientName;
try {
RtMidiOut* rOut = new RtMidiOut ((RtMidi::Api) api, name);
wrp->ptr = (void*) rOut;
wrp->data = 0;
wrp->ok = true;
wrp->msg = "";
} catch (const RtMidiError & err) {
wrp->ptr = 0;
wrp->data = 0;
wrp->ok = false;
wrp->msg = err.what ();
}
return wrp;
}
void rtmidi_out_free (RtMidiOutPtr device)
{
delete (RtMidiOut*) device->ptr;
delete device;
}
enum RtMidiApi rtmidi_out_get_current_api (RtMidiPtr device)
{
try {
return (RtMidiApi) ((RtMidiOut*) device->ptr)->getCurrentApi ();
} catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
return RTMIDI_API_UNSPECIFIED;
}
}
int rtmidi_out_send_message (RtMidiOutPtr device, const unsigned char *message, int length)
{
try {
((RtMidiOut*) device->ptr)->sendMessage (message, length);
return 0;
}
catch (const RtMidiError & err) {
device->ok = false;
device->msg = err.what ();
return -1;
}
catch (...) {
device->ok = false;
device->msg = "Unknown error";
return -1;
}
}

251
extern/rtmidi/rtmidi_c.h vendored Normal file
View File

@ -0,0 +1,251 @@
/************************************************************************/
/*! \defgroup C-interface
@{
\brief C interface to realtime MIDI input/output C++ classes.
RtMidi offers a C-style interface, principally for use in binding
RtMidi to other programming languages. All structs, enums, and
functions listed here have direct analogs (and simply call to)
items in the C++ RtMidi class and its supporting classes and
types
*/
/************************************************************************/
/*!
\file rtmidi_c.h
*/
#include <stdbool.h>
#include <stddef.h>
#ifndef RTMIDI_C_H
#define RTMIDI_C_H
#if defined(RTMIDI_EXPORT)
#if defined _WIN32 || defined __CYGWIN__
#define RTMIDIAPI __declspec(dllexport)
#else
#define RTMIDIAPI __attribute__((visibility("default")))
#endif
#else
#define RTMIDIAPI //__declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
//! \brief Wraps an RtMidi object for C function return statuses.
struct RtMidiWrapper {
//! The wrapped RtMidi object.
void* ptr;
void* data;
//! True when the last function call was OK.
bool ok;
//! If an error occured (ok != true), set to an error message.
const char* msg;
};
//! \brief Typedef for a generic RtMidi pointer.
typedef struct RtMidiWrapper* RtMidiPtr;
//! \brief Typedef for a generic RtMidiIn pointer.
typedef struct RtMidiWrapper* RtMidiInPtr;
//! \brief Typedef for a generic RtMidiOut pointer.
typedef struct RtMidiWrapper* RtMidiOutPtr;
//! \brief MIDI API specifier arguments. See \ref RtMidi::Api.
enum RtMidiApi {
RTMIDI_API_UNSPECIFIED, /*!< Search for a working compiled API. */
RTMIDI_API_MACOSX_CORE, /*!< Macintosh OS-X CoreMIDI API. */
RTMIDI_API_LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */
RTMIDI_API_UNIX_JACK, /*!< The Jack Low-Latency MIDI Server API. */
RTMIDI_API_WINDOWS_MM, /*!< The Microsoft Multimedia MIDI API. */
RTMIDI_API_RTMIDI_DUMMY, /*!< A compilable but non-functional API. */
RTMIDI_API_NUM /*!< Number of values in this enum. */
};
//! \brief Defined RtMidiError types. See \ref RtMidiError::Type.
enum RtMidiErrorType {
RTMIDI_ERROR_WARNING, /*!< A non-critical error. */
RTMIDI_ERROR_DEBUG_WARNING, /*!< A non-critical error which might be useful for debugging. */
RTMIDI_ERROR_UNSPECIFIED, /*!< The default, unspecified error type. */
RTMIDI_ERROR_NO_DEVICES_FOUND, /*!< No devices found on system. */
RTMIDI_ERROR_INVALID_DEVICE, /*!< An invalid device ID was specified. */
RTMIDI_ERROR_MEMORY_ERROR, /*!< An error occured during memory allocation. */
RTMIDI_ERROR_INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */
RTMIDI_ERROR_INVALID_USE, /*!< The function was called incorrectly. */
RTMIDI_ERROR_DRIVER_ERROR, /*!< A system driver error occured. */
RTMIDI_ERROR_SYSTEM_ERROR, /*!< A system error occured. */
RTMIDI_ERROR_THREAD_ERROR /*!< A thread error occured. */
};
/*! \brief The type of a RtMidi callback function.
*
* \param timeStamp The time at which the message has been received.
* \param message The midi message.
* \param userData Additional user data for the callback.
*
* See \ref RtMidiIn::RtMidiCallback.
*/
typedef void(* RtMidiCCallback) (double timeStamp, const unsigned char* message,
size_t messageSize, void *userData);
/* RtMidi API */
/*! \brief Determine the available compiled MIDI APIs.
*
* If the given `apis` parameter is null, returns the number of available APIs.
* Otherwise, fill the given apis array with the RtMidi::Api values.
*
* \param apis An array or a null value.
* \param apis_size Number of elements pointed to by apis
* \return number of items needed for apis array if apis==NULL, or
* number of items written to apis array otherwise. A negative
* return value indicates an error.
*
* See \ref RtMidi::getCompiledApi().
*/
RTMIDIAPI int rtmidi_get_compiled_api (enum RtMidiApi *apis, unsigned int apis_size);
//! \brief Return the name of a specified compiled MIDI API.
//! See \ref RtMidi::getApiName().
RTMIDIAPI const char *rtmidi_api_name(enum RtMidiApi api);
//! \brief Return the display name of a specified compiled MIDI API.
//! See \ref RtMidi::getApiDisplayName().
RTMIDIAPI const char *rtmidi_api_display_name(enum RtMidiApi api);
//! \brief Return the compiled MIDI API having the given name.
//! See \ref RtMidi::getCompiledApiByName().
RTMIDIAPI enum RtMidiApi rtmidi_compiled_api_by_name(const char *name);
//! \internal Report an error.
RTMIDIAPI void rtmidi_error (enum RtMidiErrorType type, const char* errorString);
/*! \brief Open a MIDI port.
*
* \param port Must be greater than 0
* \param portName Name for the application port.
*
* See RtMidi::openPort().
*/
RTMIDIAPI void rtmidi_open_port (RtMidiPtr device, unsigned int portNumber, const char *portName);
/*! \brief Creates a virtual MIDI port to which other software applications can
* connect.
*
* \param portName Name for the application port.
*
* See RtMidi::openVirtualPort().
*/
RTMIDIAPI void rtmidi_open_virtual_port (RtMidiPtr device, const char *portName);
/*! \brief Close a MIDI connection.
* See RtMidi::closePort().
*/
RTMIDIAPI void rtmidi_close_port (RtMidiPtr device);
/*! \brief Return the number of available MIDI ports.
* See RtMidi::getPortCount().
*/
RTMIDIAPI unsigned int rtmidi_get_port_count (RtMidiPtr device);
/*! \brief Access a string identifier for the specified MIDI input port number.
*
* To prevent memory leaks a char buffer must be passed to this function.
* NULL can be passed as bufOut parameter, and that will write the required buffer length in the bufLen.
*
* See RtMidi::getPortName().
*/
RTMIDIAPI int rtmidi_get_port_name (RtMidiPtr device, unsigned int portNumber, char * bufOut, int * bufLen);
/* RtMidiIn API */
//! \brief Create a default RtMidiInPtr value, with no initialization.
RTMIDIAPI RtMidiInPtr rtmidi_in_create_default (void);
/*! \brief Create a RtMidiInPtr value, with given api, clientName and queueSizeLimit.
*
* \param api An optional API id can be specified.
* \param clientName An optional client name can be specified. This
* will be used to group the ports that are created
* by the application.
* \param queueSizeLimit An optional size of the MIDI input queue can be
* specified.
*
* See RtMidiIn::RtMidiIn().
*/
RTMIDIAPI RtMidiInPtr rtmidi_in_create (enum RtMidiApi api, const char *clientName, unsigned int queueSizeLimit);
//! \brief Free the given RtMidiInPtr.
RTMIDIAPI void rtmidi_in_free (RtMidiInPtr device);
//! \brief Returns the MIDI API specifier for the given instance of RtMidiIn.
//! See \ref RtMidiIn::getCurrentApi().
RTMIDIAPI enum RtMidiApi rtmidi_in_get_current_api (RtMidiPtr device);
//! \brief Set a callback function to be invoked for incoming MIDI messages.
//! See \ref RtMidiIn::setCallback().
RTMIDIAPI void rtmidi_in_set_callback (RtMidiInPtr device, RtMidiCCallback callback, void *userData);
//! \brief Cancel use of the current callback function (if one exists).
//! See \ref RtMidiIn::cancelCallback().
RTMIDIAPI void rtmidi_in_cancel_callback (RtMidiInPtr device);
//! \brief Specify whether certain MIDI message types should be queued or ignored during input.
//! See \ref RtMidiIn::ignoreTypes().
RTMIDIAPI void rtmidi_in_ignore_types (RtMidiInPtr device, bool midiSysex, bool midiTime, bool midiSense);
/*! Fill the user-provided array with the data bytes for the next available
* MIDI message in the input queue and return the event delta-time in seconds.
*
* \param message Must point to a char* that is already allocated.
* SYSEX messages maximum size being 1024, a statically
* allocated array could
* be sufficient.
* \param size Is used to return the size of the message obtained.
* Must be set to the size of \ref message when calling.
*
* See RtMidiIn::getMessage().
*/
RTMIDIAPI double rtmidi_in_get_message (RtMidiInPtr device, unsigned char *message, size_t *size);
/* RtMidiOut API */
//! \brief Create a default RtMidiInPtr value, with no initialization.
RTMIDIAPI RtMidiOutPtr rtmidi_out_create_default (void);
/*! \brief Create a RtMidiOutPtr value, with given and clientName.
*
* \param api An optional API id can be specified.
* \param clientName An optional client name can be specified. This
* will be used to group the ports that are created
* by the application.
*
* See RtMidiOut::RtMidiOut().
*/
RTMIDIAPI RtMidiOutPtr rtmidi_out_create (enum RtMidiApi api, const char *clientName);
//! \brief Free the given RtMidiOutPtr.
RTMIDIAPI void rtmidi_out_free (RtMidiOutPtr device);
//! \brief Returns the MIDI API specifier for the given instance of RtMidiOut.
//! See \ref RtMidiOut::getCurrentApi().
RTMIDIAPI enum RtMidiApi rtmidi_out_get_current_api (RtMidiPtr device);
//! \brief Immediately send a single message out an open MIDI output port.
//! See \ref RtMidiOut::sendMessage().
RTMIDIAPI int rtmidi_out_send_message (RtMidiOutPtr device, const unsigned char *message, int length);
#ifdef __cplusplus
}
#endif
#endif
/*! }@ */

View File

38
extern/rtmidi/tests/Makefile.am vendored Normal file
View File

@ -0,0 +1,38 @@
noinst_PROGRAMS = midiprobe midiout qmidiin cmidiin sysextest midiclock_in midiclock_out \
apinames testcapi
AM_CXXFLAGS = -Wall -I$(top_srcdir)
AM_CFLAGS = -Wall -I$(top_srcdir)
midiprobe_SOURCES = midiprobe.cpp
midiprobe_LDADD = $(top_builddir)/librtmidi.la
midiout_SOURCES = midiout.cpp
midiout_LDADD = $(top_builddir)/librtmidi.la
qmidiin_SOURCES = qmidiin.cpp
qmidiin_LDADD = $(top_builddir)/librtmidi.la
cmidiin_SOURCES = cmidiin.cpp
cmidiin_LDADD = $(top_builddir)/librtmidi.la
sysextest_SOURCES = sysextest.cpp
sysextest_LDADD = $(top_builddir)/librtmidi.la
midiclock_in_SOURCES = midiclock.cpp
midiclock_in_LDADD = $(top_builddir)/librtmidi.la
midiclock_out_SOURCES = midiclock.cpp
midiclock_out_LDADD = $(top_builddir)/librtmidi.la
apinames_SOURCES = apinames.cpp
apinames_LDADD = $(top_builddir)/librtmidi.la
testcapi_SOURCES = testcapi.c
testcapi_LDADD = $(top_builddir)/librtmidi.la
EXTRA_DIST = cmidiin.dsp midiout.dsp midiprobe.dsp qmidiin.dsp \
sysextest.dsp RtMidi.dsw
TESTS = apinames

View File

77
extern/rtmidi/tests/RtMidi.dsw vendored Normal file
View File

@ -0,0 +1,77 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "cmidiin"=".\cmidiin.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "midiout"=".\midiout.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "midiprobe"=".\midiprobe.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "qmidiin"=".\qmidiin.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "sysextest"=".\sysextest.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

159
extern/rtmidi/tests/apinames.cpp vendored Normal file
View File

@ -0,0 +1,159 @@
/******************************************/
/*
apinames.cpp
by Jean Pierre Cimalando, 2018.
This program tests parts of RtMidi related
to API names, the conversion from name to API
and vice-versa.
*/
/******************************************/
#include "RtMidi.h"
#include <cctype>
#include <cstdlib>
#include <iostream>
int test_cpp() {
std::vector<RtMidi::Api> apis;
RtMidi::getCompiledApi( apis );
// ensure the known APIs return valid names
std::cout << "API names by identifier (C++):\n";
for ( size_t i = 0; i < apis.size() ; ++i ) {
const std::string name = RtMidi::getApiName(apis[i]);
if (name.empty()) {
std::cout << "Invalid name for API " << (int)apis[i] << "\n";
exit(1);
}
const std::string displayName = RtMidi::getApiDisplayName(apis[i]);
if (displayName.empty()) {
std::cout << "Invalid display name for API " << (int)apis[i] << "\n";
exit(1);
}
std::cout << "* " << (int)apis[i] << " '" << name << "': '" << displayName << "'\n";
}
// ensure unknown APIs return the empty string
{
const std::string name = RtMidi::getApiName((RtMidi::Api)-1);
if (!name.empty()) {
std::cout << "Bad string for invalid API '" << name << "'\n";
exit(1);
}
const std::string displayName = RtMidi::getApiDisplayName((RtMidi::Api)-1);
if (displayName!="Unknown") {
std::cout << "Bad display string for invalid API '" << displayName << "'\n";
exit(1);
}
}
// try getting API identifier by name
std::cout << "API identifiers by name (C++):\n";
for ( size_t i = 0; i < apis.size() ; ++i ) {
std::string name = RtMidi::getApiName(apis[i]);
if ( RtMidi::getCompiledApiByName(name) != apis[i] ) {
std::cout << "Bad identifier for API '" << name << "'\n";
exit( 1 );
}
std::cout << "* '" << name << "': " << (int)apis[i] << "\n";
for ( size_t j = 0; j < name.size(); ++j )
name[j] = (j & 1) ? toupper(name[j]) : tolower(name[j]);
RtMidi::Api api = RtMidi::getCompiledApiByName(name);
if ( api != RtMidi::UNSPECIFIED ) {
std::cout << "Identifier " << (int)api << " for invalid API '" << name << "'\n";
exit( 1 );
}
}
// try getting an API identifier by unknown name
{
RtMidi::Api api;
api = RtMidi::getCompiledApiByName("");
if ( api != RtMidi::UNSPECIFIED ) {
std::cout << "Bad identifier for unknown API name\n";
exit( 1 );
}
}
return 0;
}
#include "rtmidi_c.h"
int test_c() {
unsigned api_count = rtmidi_get_compiled_api(NULL, 0);
std::vector<RtMidiApi> apis(api_count);
rtmidi_get_compiled_api(apis.data(), api_count);
// ensure the known APIs return valid names
std::cout << "API names by identifier (C):\n";
for ( size_t i = 0; i < api_count; ++i) {
const std::string name = rtmidi_api_name(apis[i]);
if (name.empty()) {
std::cout << "Invalid name for API " << (int)apis[i] << "\n";
exit(1);
}
const std::string displayName = rtmidi_api_display_name(apis[i]);
if (displayName.empty()) {
std::cout << "Invalid display name for API " << (int)apis[i] << "\n";
exit(1);
}
std::cout << "* " << (int)apis[i] << " '" << name << "': '" << displayName << "'\n";
}
// ensure unknown APIs return the empty string
{
const char *s = rtmidi_api_name((RtMidiApi)-1);
const std::string name(s?s:"");
if (!name.empty()) {
std::cout << "Bad string for invalid API '" << name << "'\n";
exit(1);
}
s = rtmidi_api_display_name((RtMidiApi)-1);
const std::string displayName(s?s:"");
if (displayName!="Unknown") {
std::cout << "Bad display string for invalid API '" << displayName << "'\n";
exit(1);
}
}
// try getting API identifier by name
std::cout << "API identifiers by name (C):\n";
for ( size_t i = 0; i < api_count ; ++i ) {
const char *s = rtmidi_api_name(apis[i]);
std::string name(s?s:"");
if ( rtmidi_compiled_api_by_name(name.c_str()) != apis[i] ) {
std::cout << "Bad identifier for API '" << name << "'\n";
exit( 1 );
}
std::cout << "* '" << name << "': " << (int)apis[i] << "\n";
for ( size_t j = 0; j < name.size(); ++j )
name[j] = (j & 1) ? toupper(name[j]) : tolower(name[j]);
RtMidiApi api = rtmidi_compiled_api_by_name(name.c_str());
if ( api != RTMIDI_API_UNSPECIFIED ) {
std::cout << "Identifier " << (int)api << " for invalid API '" << name << "'\n";
exit( 1 );
}
}
// try getting an API identifier by unknown name
{
RtMidiApi api;
api = rtmidi_compiled_api_by_name("");
if ( api != RTMIDI_API_UNSPECIFIED ) {
std::cout << "Bad identifier for unknown API name\n";
exit( 1 );
}
}
return 0;
}
int main()
{
test_cpp();
test_c();
}

111
extern/rtmidi/tests/cmidiin.cpp vendored Normal file
View File

@ -0,0 +1,111 @@
//*****************************************//
// cmidiin.cpp
// by Gary Scavone, 2003-2004.
//
// Simple program to test MIDI input and
// use of a user callback function.
//
//*****************************************//
#include <iostream>
#include <cstdlib>
#include "RtMidi.h"
void usage( void ) {
// Error function in case of incorrect command-line
// argument specifications.
std::cout << "\nuseage: cmidiin <port>\n";
std::cout << " where port = the device to use (first / default = 0).\n\n";
exit( 0 );
}
void mycallback( double deltatime, std::vector< unsigned char > *message, void */*userData*/ )
{
unsigned int nBytes = message->size();
for ( unsigned int i=0; i<nBytes; i++ )
std::cout << "Byte " << i << " = " << (int)message->at(i) << ", ";
if ( nBytes > 0 )
std::cout << "stamp = " << deltatime << std::endl;
}
// This function should be embedded in a try/catch block in case of
// an exception. It offers the user a choice of MIDI ports to open.
// It returns false if there are no ports available.
bool chooseMidiPort( RtMidiIn *rtmidi );
int main( int argc, char ** /*argv[]*/ )
{
RtMidiIn *midiin = 0;
// Minimal command-line check.
if ( argc > 2 ) usage();
try {
// RtMidiIn constructor
midiin = new RtMidiIn();
// Call function to select port.
if ( chooseMidiPort( midiin ) == false ) goto cleanup;
// Set our callback function. This should be done immediately after
// opening the port to avoid having incoming messages written to the
// queue instead of sent to the callback function.
midiin->setCallback( &mycallback );
// Don't ignore sysex, timing, or active sensing messages.
midiin->ignoreTypes( false, false, false );
std::cout << "\nReading MIDI input ... press <enter> to quit.\n";
char input;
std::cin.get(input);
} catch ( RtMidiError &error ) {
error.printMessage();
}
cleanup:
delete midiin;
return 0;
}
bool chooseMidiPort( RtMidiIn *rtmidi )
{
std::cout << "\nWould you like to open a virtual input port? [y/N] ";
std::string keyHit;
std::getline( std::cin, keyHit );
if ( keyHit == "y" ) {
rtmidi->openVirtualPort();
return true;
}
std::string portName;
unsigned int i = 0, nPorts = rtmidi->getPortCount();
if ( nPorts == 0 ) {
std::cout << "No input ports available!" << std::endl;
return false;
}
if ( nPorts == 1 ) {
std::cout << "\nOpening " << rtmidi->getPortName() << std::endl;
}
else {
for ( i=0; i<nPorts; i++ ) {
portName = rtmidi->getPortName(i);
std::cout << " Input port #" << i << ": " << portName << '\n';
}
do {
std::cout << "\nChoose a port number: ";
std::cin >> i;
} while ( i >= nPorts );
std::getline( std::cin, keyHit ); // used to clear out stdin
}
rtmidi->openPort( i );
return true;
}

110
extern/rtmidi/tests/cmidiin.dsp vendored Normal file
View File

@ -0,0 +1,110 @@
# Microsoft Developer Studio Project File - Name="cmidiin" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=cmidiin - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "cmidiin.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "cmidiin.mak" CFG="cmidiin - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "cmidiin - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "cmidiin - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "cmidiin - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "cmidiin___Win32_Release"
# PROP BASE Intermediate_Dir "cmidiin___Win32_Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ""
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_MM__" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "cmidiin - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "cmidiin___Win32_Debug"
# PROP BASE Intermediate_Dir "cmidiin___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ""
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_MM__" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "cmidiin - Win32 Release"
# Name "cmidiin - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\cmidiin.cpp
# End Source File
# Begin Source File
SOURCE=..\RtMidi.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\RtMidi.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

231
extern/rtmidi/tests/midiclock.cpp vendored Normal file
View File

@ -0,0 +1,231 @@
//*****************************************//
// midiclock.cpp
//
// Simple program to test MIDI clock sync. Run midiclock_in in one
// console and midiclock_out in the other, make sure to choose
// options that connect the clocks between programs on your platform.
//
// (C)2016 Refer to README.md in this archive for copyright.
//
//*****************************************//
#include <iostream>
#include <cstdlib>
#include "RtMidi.h"
// Platform-dependent sleep routines.
#if defined(WIN32)
#include <windows.h>
#define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds )
#else // Unix variants
#include <unistd.h>
#define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) )
#endif
// These functions should be embedded in a try/catch block in case of
// an exception. It offers the user a choice of MIDI ports to open.
// It returns false if there are no ports available.
bool chooseInputPort( RtMidiIn *rtmidi );
bool chooseOutputPort( RtMidiOut *rtmidi );
void mycallback( double deltatime, std::vector< unsigned char > *message, void *user )
{
unsigned int *clock_count = reinterpret_cast<unsigned int*>(user);
// Ignore longer messages
if (message->size() != 1)
return;
unsigned int msg = message->at(0);
if (msg == 0xFA)
std::cout << "START received" << std::endl;
if (msg == 0xFB)
std::cout << "CONTINUE received" << std::endl;
if (msg == 0xFC)
std::cout << "STOP received" << std::endl;
if (msg == 0xF8) {
if (++*clock_count == 24) {
double bpm = 60.0 / 24.0 / deltatime;
std::cout << "One beat, estimated BPM = " << bpm <<std::endl;
*clock_count = 0;
}
}
else
*clock_count = 0;
}
int clock_in()
{
RtMidiIn *midiin = 0;
unsigned int clock_count = 0;
try {
// RtMidiIn constructor
midiin = new RtMidiIn();
// Call function to select port.
if ( chooseInputPort( midiin ) == false ) goto cleanup;
// Set our callback function. This should be done immediately after
// opening the port to avoid having incoming messages written to the
// queue instead of sent to the callback function.
midiin->setCallback( &mycallback, &clock_count );
// Don't ignore sysex, timing, or active sensing messages.
midiin->ignoreTypes( false, false, false );
std::cout << "\nReading MIDI input ... press <enter> to quit.\n";
char input;
std::cin.get(input);
} catch ( RtMidiError &error ) {
error.printMessage();
}
cleanup:
delete midiin;
return 0;
}
int clock_out()
{
RtMidiOut *midiout = 0;
std::vector<unsigned char> message;
int sleep_ms = 0, k = 0, j = 0;
// RtMidiOut constructor
try {
midiout = new RtMidiOut();
}
catch ( RtMidiError &error ) {
error.printMessage();
exit( EXIT_FAILURE );
}
// Call function to select port.
try {
if ( chooseOutputPort( midiout ) == false ) goto cleanup;
}
catch ( RtMidiError &error ) {
error.printMessage();
goto cleanup;
}
// Period in ms = 100 BPM
// 100*24 ticks / 1 minute, so (60*1000) / (100*24) = 25 ms / tick
sleep_ms = 25;
std::cout << "Generating clock at "
<< (60.0 / 24.0 / sleep_ms * 1000.0)
<< " BPM." << std::endl;
// Send out a series of MIDI clock messages.
// MIDI start
message.clear();
message.push_back( 0xFA );
midiout->sendMessage( &message );
std::cout << "MIDI start" << std::endl;
for (j=0; j < 8; j++)
{
if (j > 0)
{
// MIDI continue
message.clear();
message.push_back( 0xFB );
midiout->sendMessage( &message );
std::cout << "MIDI continue" << std::endl;
}
for (k=0; k < 96; k++) {
// MIDI clock
message.clear();
message.push_back( 0xF8 );
midiout->sendMessage( &message );
if (k % 24 == 0)
std::cout << "MIDI clock (one beat)" << std::endl;
SLEEP( sleep_ms );
}
// MIDI stop
message.clear();
message.push_back( 0xFC );
midiout->sendMessage( &message );
std::cout << "MIDI stop" << std::endl;
SLEEP( 500 );
}
// MIDI stop
message.clear();
message.push_back( 0xFC );
midiout->sendMessage( &message );
std::cout << "MIDI stop" << std::endl;
SLEEP( 500 );
std::cout << "Done!" << std::endl;
// Clean up
cleanup:
delete midiout;
return 0;
}
int main( int, const char *argv[] )
{
std::string prog(argv[0]);
if (prog.find("midiclock_in") != prog.npos) {
clock_in();
}
else if (prog.find("midiclock_out") != prog.npos) {
clock_out();
}
else {
std::cout << "Don't know what to do as " << prog << std::endl;
}
return 0;
}
template<typename RT>
bool choosePort( RT *rtmidi, const char *dir )
{
std::string portName;
unsigned int i = 0, nPorts = rtmidi->getPortCount();
if ( nPorts == 0 ) {
std::cout << "No " << dir << " ports available!" << std::endl;
return false;
}
if ( nPorts == 1 ) {
std::cout << "\nOpening " << rtmidi->getPortName() << std::endl;
}
else {
for ( i=0; i<nPorts; i++ ) {
portName = rtmidi->getPortName(i);
std::cout << " " << dir << " port #" << i << ": " << portName << '\n';
}
do {
std::cout << "\nChoose a port number: ";
std::cin >> i;
} while ( i >= nPorts );
}
std::cout << "\n";
rtmidi->openPort( i );
return true;
}
bool chooseInputPort( RtMidiIn *rtmidi )
{
return choosePort<RtMidiIn>( rtmidi, "input" );
}
bool chooseOutputPort( RtMidiOut *rtmidi )
{
return choosePort<RtMidiOut>( rtmidi, "output" );
}

146
extern/rtmidi/tests/midiout.cpp vendored Normal file
View File

@ -0,0 +1,146 @@
//*****************************************//
// midiout.cpp
// by Gary Scavone, 2003-2004.
//
// Simple program to test MIDI output.
//
//*****************************************//
#include <iostream>
#include <cstdlib>
#include "RtMidi.h"
// Platform-dependent sleep routines.
#if defined(WIN32)
#include <windows.h>
#define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds )
#else // Unix variants
#include <unistd.h>
#define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) )
#endif
// This function should be embedded in a try/catch block in case of
// an exception. It offers the user a choice of MIDI ports to open.
// It returns false if there are no ports available.
bool chooseMidiPort( RtMidiOut *rtmidi );
int main( void )
{
RtMidiOut *midiout = 0;
std::vector<unsigned char> message;
// RtMidiOut constructor
try {
midiout = new RtMidiOut();
}
catch ( RtMidiError &error ) {
error.printMessage();
exit( EXIT_FAILURE );
}
// Call function to select port.
try {
if ( chooseMidiPort( midiout ) == false ) goto cleanup;
}
catch ( RtMidiError &error ) {
error.printMessage();
goto cleanup;
}
// Send out a series of MIDI messages.
// Program change: 192, 5
message.push_back( 192 );
message.push_back( 5 );
midiout->sendMessage( &message );
SLEEP( 500 );
message[0] = 0xF1;
message[1] = 60;
midiout->sendMessage( &message );
// Control Change: 176, 7, 100 (volume)
message[0] = 176;
message[1] = 7;
message.push_back( 100 );
midiout->sendMessage( &message );
// Note On: 144, 64, 90
message[0] = 144;
message[1] = 64;
message[2] = 90;
midiout->sendMessage( &message );
SLEEP( 500 );
// Note Off: 128, 64, 40
message[0] = 128;
message[1] = 64;
message[2] = 40;
midiout->sendMessage( &message );
SLEEP( 500 );
// Control Change: 176, 7, 40
message[0] = 176;
message[1] = 7;
message[2] = 40;
midiout->sendMessage( &message );
SLEEP( 500 );
// Sysex: 240, 67, 4, 3, 2, 247
message[0] = 240;
message[1] = 67;
message[2] = 4;
message.push_back( 3 );
message.push_back( 2 );
message.push_back( 247 );
midiout->sendMessage( &message );
// Clean up
cleanup:
delete midiout;
return 0;
}
bool chooseMidiPort( RtMidiOut *rtmidi )
{
std::cout << "\nWould you like to open a virtual output port? [y/N] ";
std::string keyHit;
std::getline( std::cin, keyHit );
if ( keyHit == "y" ) {
rtmidi->openVirtualPort();
return true;
}
std::string portName;
unsigned int i = 0, nPorts = rtmidi->getPortCount();
if ( nPorts == 0 ) {
std::cout << "No output ports available!" << std::endl;
return false;
}
if ( nPorts == 1 ) {
std::cout << "\nOpening " << rtmidi->getPortName() << std::endl;
}
else {
for ( i=0; i<nPorts; i++ ) {
portName = rtmidi->getPortName(i);
std::cout << " Output port #" << i << ": " << portName << '\n';
}
do {
std::cout << "\nChoose a port number: ";
std::cin >> i;
} while ( i >= nPorts );
}
std::cout << "\n";
rtmidi->openPort( i );
return true;
}

110
extern/rtmidi/tests/midiout.dsp vendored Normal file
View File

@ -0,0 +1,110 @@
# Microsoft Developer Studio Project File - Name="midiout" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=midiout - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "midiout.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "midiout.mak" CFG="midiout - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "midiout - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "midiout - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "midiout - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "midiout___Win32_Release"
# PROP BASE Intermediate_Dir "midiout___Win32_Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ""
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_MM__" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "midiout - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "midiout___Win32_Debug"
# PROP BASE Intermediate_Dir "midiout___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ""
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_MM__" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "midiout - Win32 Release"
# Name "midiout - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\midiout.cpp
# End Source File
# Begin Source File
SOURCE=..\RtMidi.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\RtMidi.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

76
extern/rtmidi/tests/midiprobe.cpp vendored Normal file
View File

@ -0,0 +1,76 @@
// midiprobe.cpp
//
// Simple program to check MIDI inputs and outputs.
//
// by Gary Scavone, 2003-2012.
#include <iostream>
#include <cstdlib>
#include <map>
#include "RtMidi.h"
int main()
{
// Create an api map.
std::map<int, std::string> apiMap;
apiMap[RtMidi::MACOSX_CORE] = "OS-X CoreMIDI";
apiMap[RtMidi::WINDOWS_MM] = "Windows MultiMedia";
apiMap[RtMidi::UNIX_JACK] = "Jack Client";
apiMap[RtMidi::LINUX_ALSA] = "Linux ALSA";
apiMap[RtMidi::RTMIDI_DUMMY] = "RtMidi Dummy";
std::vector< RtMidi::Api > apis;
RtMidi :: getCompiledApi( apis );
std::cout << "\nCompiled APIs:\n";
for ( unsigned int i=0; i<apis.size(); i++ )
std::cout << " " << apiMap[ apis[i] ] << std::endl;
std::cout << std::endl;
for ( unsigned int i=0; i<apis.size(); i++ ){
std::cout << "Probing with API " << apiMap[ apis[i] ] << std::endl;
RtMidiIn *midiin = 0;
RtMidiOut *midiout = 0;
try {
// RtMidiIn constructor ... exception possible
midiin = new RtMidiIn(apis[i]);
std::cout << "\nCurrent input API: " << apiMap[ midiin->getCurrentApi() ] << std::endl;
// Check inputs.
unsigned int nPorts = midiin->getPortCount();
std::cout << "\nThere are " << nPorts << " MIDI input sources available.\n";
for ( unsigned i=0; i<nPorts; i++ ) {
std::string portName = midiin->getPortName(i);
std::cout << " Input Port #" << i << ": " << portName << '\n';
}
// RtMidiOut constructor ... exception possible
midiout = new RtMidiOut(apis[i]);
std::cout << "\nCurrent output API: " << apiMap[ midiout->getCurrentApi() ] << std::endl;
// Check outputs.
nPorts = midiout->getPortCount();
std::cout << "\nThere are " << nPorts << " MIDI output ports available.\n";
for ( unsigned i=0; i<nPorts; i++ ) {
std::string portName = midiout->getPortName(i);
std::cout << " Output Port #" << i << ": " << portName << std::endl;
}
std::cout << std::endl;
} catch ( RtMidiError &error ) {
error.printMessage();
}
delete midiin;
delete midiout;
}
return 0;
}

110
extern/rtmidi/tests/midiprobe.dsp vendored Normal file
View File

@ -0,0 +1,110 @@
# Microsoft Developer Studio Project File - Name="midiprobe" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=midiprobe - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "midiprobe.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "midiprobe.mak" CFG="midiprobe - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "midiprobe - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "midiprobe - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "midiprobe - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "midiprobe___Win32_Release"
# PROP BASE Intermediate_Dir "midiprobe___Win32_Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ""
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_MM__" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "midiprobe - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "midiprobe___Win32_Debug"
# PROP BASE Intermediate_Dir "midiprobe___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ""
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_MM__" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "midiprobe - Win32 Release"
# Name "midiprobe - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\midiprobe.cpp
# End Source File
# Begin Source File
SOURCE=..\RtMidi.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\RtMidi.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

98
extern/rtmidi/tests/qmidiin.cpp vendored Normal file
View File

@ -0,0 +1,98 @@
//*****************************************//
// qmidiin.cpp
// by Gary Scavone, 2003-2004.
//
// Simple program to test MIDI input and
// retrieval from the queue.
//
//*****************************************//
#include <iostream>
#include <cstdlib>
#include <signal.h>
#include "RtMidi.h"
// Platform-dependent sleep routines.
#if defined(WIN32)
#include <windows.h>
#define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds )
#else // Unix variants
#include <unistd.h>
#define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) )
#endif
bool done;
static void finish( int /*ignore*/ ){ done = true; }
void usage( void ) {
// Error function in case of incorrect command-line
// argument specifications.
std::cout << "\nusage: qmidiin <port>\n";
std::cout << " where port = the device to use (first / default = 0).\n\n";
exit( 0 );
}
int main( int argc, char *argv[] )
{
RtMidiIn *midiin = 0;
std::vector<unsigned char> message;
int nBytes, i;
double stamp;
// Minimal command-line check.
if ( argc > 2 ) usage();
// RtMidiIn constructor
try {
midiin = new RtMidiIn();
}
catch ( RtMidiError &error ) {
error.printMessage();
exit( EXIT_FAILURE );
}
// Check available ports vs. specified.
unsigned int port = 0;
unsigned int nPorts = midiin->getPortCount();
if ( argc == 2 ) port = (unsigned int) atoi( argv[1] );
if ( port >= nPorts ) {
delete midiin;
std::cout << "Invalid port specifier!\n";
usage();
}
try {
midiin->openPort( port );
}
catch ( RtMidiError &error ) {
error.printMessage();
goto cleanup;
}
// Don't ignore sysex, timing, or active sensing messages.
midiin->ignoreTypes( false, false, false );
// Install an interrupt handler function.
done = false;
(void) signal(SIGINT, finish);
// Periodically check input queue.
std::cout << "Reading MIDI from port " << midiin->getPortName() << " ... quit with Ctrl-C.\n";
while ( !done ) {
stamp = midiin->getMessage( &message );
nBytes = message.size();
for ( i=0; i<nBytes; i++ )
std::cout << "Byte " << i << " = " << (int)message[i] << ", ";
if ( nBytes > 0 )
std::cout << "stamp = " << stamp << std::endl;
// Sleep for 10 milliseconds.
SLEEP( 10 );
}
// Clean up
cleanup:
delete midiin;
return 0;
}

110
extern/rtmidi/tests/qmidiin.dsp vendored Normal file
View File

@ -0,0 +1,110 @@
# Microsoft Developer Studio Project File - Name="qmidiin" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=qmidiin - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "qmidiin.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "qmidiin.mak" CFG="qmidiin - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "qmidiin - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "qmidiin - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "qmidiin - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "qmidiin___Win32_Release"
# PROP BASE Intermediate_Dir "qmidiin___Win32_Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ""
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_MM__" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "qmidiin - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "qmidiin___Win32_Debug"
# PROP BASE Intermediate_Dir "qmidiin___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ""
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_MM__" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "qmidiin - Win32 Release"
# Name "qmidiin - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\qmidiin.cpp
# End Source File
# Begin Source File
SOURCE=..\RtMidi.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\RtMidi.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

152
extern/rtmidi/tests/sysextest.cpp vendored Normal file
View File

@ -0,0 +1,152 @@
//*****************************************//
// sysextest.cpp
// by Gary Scavone, 2003-2005.
//
// Simple program to test MIDI sysex sending and receiving.
//
//*****************************************//
#include <iostream>
#include <cstdlib>
#include <typeinfo>
#include "RtMidi.h"
void usage( void ) {
std::cout << "\nuseage: sysextest N\n";
std::cout << " where N = length of sysex data to send / receive.\n\n";
exit( 0 );
}
// Platform-dependent sleep routines.
#if defined(WIN32)
#include <windows.h>
#define SLEEP( milliseconds ) Sleep( (DWORD) milliseconds )
#else // Unix variants
#include <unistd.h>
#define SLEEP( milliseconds ) usleep( (unsigned long) (milliseconds * 1000.0) )
#endif
// This function should be embedded in a try/catch block in case of
// an exception. It offers the user a choice of MIDI ports to open.
// It returns false if there are no ports available.
bool chooseMidiPort( RtMidi *rtmidi );
void mycallback( double deltatime, std::vector< unsigned char > *message, void * /*userData*/ )
{
unsigned int nBytes = message->size();
for ( unsigned int i=0; i<nBytes; i++ )
std::cout << "Byte " << i << " = " << (int)message->at(i) << ", ";
if ( nBytes > 0 )
std::cout << "# of bytes = " << nBytes << ", stamp = " << deltatime << std::endl;
}
int main( int argc, char *argv[] )
{
RtMidiOut *midiout = 0;
RtMidiIn *midiin = 0;
std::vector<unsigned char> message;
unsigned int i, nBytes;
// Minimal command-line check.
if ( argc != 2 ) usage();
nBytes = (unsigned int) atoi( argv[1] );
// RtMidiOut and RtMidiIn constructors
try {
midiout = new RtMidiOut();
midiin = new RtMidiIn();
}
catch ( RtMidiError &error ) {
error.printMessage();
goto cleanup;
}
// Don't ignore sysex, timing, or active sensing messages.
midiin->ignoreTypes( false, true, true );
try {
if ( chooseMidiPort( midiin ) == false ) goto cleanup;
if ( chooseMidiPort( midiout ) == false ) goto cleanup;
midiin->setCallback( &mycallback );
message.push_back( 0xF6 );
midiout->sendMessage( &message );
SLEEP( 500 ); // pause a little
// Create a long sysex message of numbered bytes and send it out ... twice.
for ( int n=0; n<2; n++ ) {
message.clear();
message.push_back( 240 );
for ( i=0; i<nBytes; i++ )
message.push_back( i % 128 );
message.push_back( 247 );
midiout->sendMessage( &message );
SLEEP( 500 ); // pause a little
}
}
catch ( RtMidiError &error ) {
error.printMessage();
goto cleanup;
}
// Clean up
cleanup:
delete midiout;
delete midiin;
return 0;
}
bool chooseMidiPort( RtMidi *rtmidi )
{
bool isInput = false;
if ( typeid( *rtmidi ) == typeid( RtMidiIn ) )
isInput = true;
if ( isInput )
std::cout << "\nWould you like to open a virtual input port? [y/N] ";
else
std::cout << "\nWould you like to open a virtual output port? [y/N] ";
std::string keyHit;
std::getline( std::cin, keyHit );
if ( keyHit == "y" ) {
rtmidi->openVirtualPort();
return true;
}
std::string portName;
unsigned int i = 0, nPorts = rtmidi->getPortCount();
if ( nPorts == 0 ) {
if ( isInput )
std::cout << "No input ports available!" << std::endl;
else
std::cout << "No output ports available!" << std::endl;
return false;
}
if ( nPorts == 1 ) {
std::cout << "\nOpening " << rtmidi->getPortName() << std::endl;
}
else {
for ( i=0; i<nPorts; i++ ) {
portName = rtmidi->getPortName(i);
if ( isInput )
std::cout << " Input port #" << i << ": " << portName << '\n';
else
std::cout << " Output port #" << i << ": " << portName << '\n';
}
do {
std::cout << "\nChoose a port number: ";
std::cin >> i;
} while ( i >= nPorts );
}
std::cout << std::endl;
rtmidi->openPort( i );
return true;
}

110
extern/rtmidi/tests/sysextest.dsp vendored Normal file
View File

@ -0,0 +1,110 @@
# Microsoft Developer Studio Project File - Name="sysextest" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=sysextest - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "sysextest.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "sysextest.mak" CFG="sysextest - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "sysextest - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "sysextest - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "sysextest - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "sysextest___Win32_Release"
# PROP BASE Intermediate_Dir "sysextest___Win32_Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ""
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GR /GX /O2 /I "../" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_MM__" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "sysextest - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "sysextest___Win32_Debug"
# PROP BASE Intermediate_Dir "sysextest___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ""
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "../" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_MM__" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "sysextest - Win32 Release"
# Name "sysextest - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\RtMidi.cpp
# End Source File
# Begin Source File
SOURCE=.\sysextest.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\RtMidi.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

26
extern/rtmidi/tests/testcapi.c vendored Normal file
View File

@ -0,0 +1,26 @@
#include <stdio.h>
#include "rtmidi_c.h"
/* Test that the C API for RtMidi is working. */
struct RtMidiWrapper *midiin;
struct RtMidiWrapper *midiout;
int main() {
if ((midiin = rtmidi_in_create_default())) {
unsigned int ports = rtmidi_get_port_count(midiin);
printf("MIDI input ports found: %u\n", ports);
rtmidi_close_port(midiin);
rtmidi_in_free(midiin);
}
if ((midiout = rtmidi_out_create_default())) {
unsigned int ports = rtmidi_get_port_count(midiout);
printf("MIDI output ports found: %u\n", ports);
rtmidi_close_port(midiout);
rtmidi_out_free(midiout);
}
return 0;
}

1
src/audio/rtmidi.h Normal file
View File

@ -0,0 +1 @@
#include "../../extern/rtmidi/RtMidi.h"

View File

@ -1,6 +1,7 @@
#ifndef _TAAUDIO_H
#define _TAAUDIO_H
#include "../ta-utils.h"
#include <vector>
struct SampleRateChangeEvent {
double rate;
@ -79,4 +80,73 @@ class TAAudio {
virtual ~TAAudio();
};
enum TAMidiMessageTypes {
TA_MIDI_NOTE_OFF=0x80,
TA_MIDI_NOTE_ON=0x90,
TA_MIDI_AFTERTOUCH=0xa0,
TA_MIDI_CONTROL=0xb0,
TA_MIDI_PROGRAM=0xc0,
TA_MIDI_CHANNEL_AFTERTOUCH=0xd0,
TA_MIDI_PITCH_BEND=0xe0,
TA_MIDI_SYSEX=0xf0,
TA_MIDI_MTC_FRAME=0xf1,
TA_MIDI_POSITION=0xf2,
TA_MIDI_SONG_SELECT=0xf3,
TA_MIDI_TUNE_REQUEST=0xf6,
TA_MIDI_SYSEX_END=0xf7,
TA_MIDI_CLOCK=0xf8,
TA_MIDI_MACHINE_PLAY=0xfa,
TA_MIDI_MACHINE_RESUME=0xfb,
TA_MIDI_MACHINE_STOP=0xfc,
TA_MIDI_KEEPALIVE=0xfe,
TA_MIDI_RESET=0xff
};
struct TAMidiMessage {
unsigned char type;
union {
struct {
unsigned char note, vol;
} note;
struct {
unsigned char which, val;
} control;
unsigned char patch;
unsigned char pressure;
struct {
unsigned char low, high;
} pitch;
struct {
unsigned int vendor;
} sysEx;
unsigned char timeCode;
struct {
unsigned char low, high;
} position;
unsigned char song;
} data;
unsigned char* sysExData;
size_t sysExLen;
void submitSysEx(std::vector<unsigned char> data);
void done();
};
class TAMidiIn {
public:
bool next(TAMidiMessage& where);
};
class TAMidiOut {
public:
bool send(TAMidiMessage& what);
};
class TAMidi {
std::vector<TAMidiIn*> in;
std::vector<TAMidiOut*> out;
};
#endif