summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2024-10-07 19:30:56 +0200
committerMitja Felicijan <mitja.felicijan@gmail.com>2024-10-07 19:30:56 +0200
commit40a899bd6ee536eae093337bf2d0dcc8db4e46f1 (patch)
tree485ace3e6fd28b91f394efd277732651e10824d8
parent6fc4bddfdf8e056469f316c1a0fe488efbb4253a (diff)
downloadttdaw-40a899bd6ee536eae093337bf2d0dcc8db4e46f1.tar.gz
Moved example code examples folder
-rw-r--r--example3.c53
-rw-r--r--examples/Makefile5
-rw-r--r--examples/example1.c (renamed from example1.c)4
-rw-r--r--examples/example2.c (renamed from example2.c)6
-rw-r--r--examples/example4.c (renamed from example4.c)0
-rwxr-xr-xportmidi.h974
-rw-r--r--portmidi/.github/workflows/build.yml47
-rw-r--r--portmidi/.github/workflows/docs.yml28
-rw-r--r--portmidi/.gitignore62
-rw-r--r--portmidi/CHANGELOG.txt213
-rw-r--r--portmidi/CMakeLists.txt188
-rw-r--r--portmidi/Doxyfile2682
-rw-r--r--portmidi/README.md128
-rwxr-xr-xportmidi/README.txt88
-rw-r--r--portmidi/license.txt40
-rw-r--r--portmidi/packaging/PortMidiConfig.cmake.in15
-rw-r--r--portmidi/packaging/portmidi.pc.in11
-rw-r--r--portmidi/pm_common/CMakeLists.txt167
-rwxr-xr-xportmidi/pm_common/pminternal.h190
-rwxr-xr-xportmidi/pm_common/pmutil.c284
-rwxr-xr-xportmidi/pm_common/pmutil.h184
-rwxr-xr-xportmidi/pm_common/portmidi.c1472
-rwxr-xr-xportmidi/pm_common/portmidi.h974
-rw-r--r--portmidi/pm_haiku/pmhaiku.cpp473
-rw-r--r--portmidi/pm_java/CMakeLists.txt56
-rw-r--r--portmidi/pm_java/README.txt62
-rw-r--r--portmidi/pm_java/jportmidi/JPortMidi.java541
-rw-r--r--portmidi/pm_java/jportmidi/JPortMidiApi.java117
-rw-r--r--portmidi/pm_java/jportmidi/JPortMidiException.java12
-rw-r--r--portmidi/pm_java/make.bat50
-rw-r--r--portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h293
-rw-r--r--portmidi/pm_java/pmjni/pmjni.c354
-rw-r--r--portmidi/pm_java/pmjni/pmjni.rc63
-rwxr-xr-xportmidi/pm_linux/README_LINUX.txt99
-rwxr-xr-xportmidi/pm_linux/pmlinux.c68
-rwxr-xr-xportmidi/pm_linux/pmlinuxalsa.c893
-rwxr-xr-xportmidi/pm_linux/pmlinuxalsa.h6
-rw-r--r--portmidi/pm_linux/pmlinuxnull.c31
-rw-r--r--portmidi/pm_linux/pmlinuxnull.h6
-rwxr-xr-xportmidi/pm_mac/Makefile.osx125
-rw-r--r--portmidi/pm_mac/README_MAC.txt65
-rwxr-xr-xportmidi/pm_mac/pmmac.c44
-rwxr-xr-xportmidi/pm_mac/pmmacosxcm.c1179
-rwxr-xr-xportmidi/pm_mac/pmmacosxcm.h4
-rw-r--r--portmidi/pm_sndio/pmsndio.c365
-rw-r--r--portmidi/pm_sndio/pmsndio.h5
-rw-r--r--portmidi/pm_test/CMakeLists.txt46
-rw-r--r--portmidi/pm_test/README.txt363
-rw-r--r--portmidi/pm_test/fast.c290
-rw-r--r--portmidi/pm_test/fastrcv.c255
-rwxr-xr-xportmidi/pm_test/latency.c287
-rw-r--r--portmidi/pm_test/midiclock.c282
-rwxr-xr-xportmidi/pm_test/midithread.c343
-rwxr-xr-xportmidi/pm_test/midithru.c455
-rwxr-xr-xportmidi/pm_test/mm.c595
-rw-r--r--portmidi/pm_test/multivirtual.c223
-rw-r--r--portmidi/pm_test/pmlist.c63
-rw-r--r--portmidi/pm_test/qtest.c174
-rw-r--r--portmidi/pm_test/recvvirtual.c175
-rw-r--r--portmidi/pm_test/sendvirtual.c194
-rwxr-xr-xportmidi/pm_test/sysex.c556
-rwxr-xr-xportmidi/pm_test/testio.c594
-rwxr-xr-xportmidi/pm_test/txdata.syx257
-rw-r--r--portmidi/pm_test/virttest.c339
-rwxr-xr-xportmidi/pm_win/README_WIN.txt174
-rwxr-xr-xportmidi/pm_win/debugging_dlls.txt145
-rwxr-xr-xportmidi/pm_win/pmwin.c98
-rwxr-xr-xportmidi/pm_win/pmwinmm.c1196
-rwxr-xr-xportmidi/pm_win/pmwinmm.h5
-rw-r--r--portmidi/pm_win/static.cmake24
-rw-r--r--portmidi/portmusic_logo.pngbin753 -> 0 bytes
-rwxr-xr-xportmidi/porttime/porttime.c3
-rwxr-xr-xportmidi/porttime/porttime.h103
-rw-r--r--portmidi/porttime/pthaiku.cpp88
-rwxr-xr-xportmidi/porttime/ptlinux.c139
-rwxr-xr-xportmidi/porttime/ptmacosx_cf.c140
-rwxr-xr-xportmidi/porttime/ptmacosx_mach.c204
-rwxr-xr-xportmidi/porttime/ptwinmm.c70
78 files changed, 10 insertions, 20596 deletions
diff --git a/example3.c b/example3.c
deleted file mode 100644
index a2103f2..0000000
--- a/example3.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "portmidi/pm_common/portmidi.h"
-
-#define NUM_INPUTS 16
-
-int main() {
- PmError err;
- PmStream *stream;
- PmEvent events[128];
- int i, num_events;
-
- // Initialize PortMIDI
- err = Pm_Initialize();
- if (err != pmNoError) {
- fprintf(stderr, "Error initializing PortMIDI: %s\n", Pm_GetErrorText(err));
- exit(1);
- }
-
- /* // Open a MIDI input device */
- stream = (PortMidiStream *)Pm_OpenInput(&err, NULL, NULL, NUM_INPUTS, NULL, 0);
- if (err != pmNoError) {
- fprintf(stderr, "Error opening MIDI input device: %s\n", Pm_GetErrorText(err));
- Pm_Terminate();
- exit(1);
- }
-
- /* // Read MIDI messages from the input device */
- /* while (1) { */
- /* num_events = Pm_Read(stream, events, 128); */
- /* if (num_events > 0) { */
- /* for (i = 0; i < num_events; i++) { */
- /* if (events[i].message & 0xff00) { */
- /* // This is a status message (note on, note off, etc.) */
- /* printf("Message: 0x%02x\n", events[i].message); */
- /* /1* printf("Status: 0x%02x, Data 1: 0x%02x, Data 2: 0x%02x\n", *1/ */
- /* /1* events[i].message & 0xf0, events[i].message[0], events[i].message[1]); *1/ */
- /* } */
- /* } */
- /* } */
- /* } */
-
- /* // Close the MIDI input device */
- Pm_Close(stream);
-
- // Terminate PortMIDI
- Pm_Terminate();
-
- return 0;
-}
-
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 0000000..5f77125
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,5 @@
+tests:
+ $(CC) -Wall example1.c ../minisdl_audio.c -lm -ldl -lpthread -o example1
+ $(CC) -Wall example2.c ../minisdl_audio.c -lm -ldl -lpthread -o example2
+ $(CC) -Wall example4.c -lasound -lm -o example4
+
diff --git a/example1.c b/examples/example1.c
index 200fd1b..91800ad 100644
--- a/example1.c
+++ b/examples/example1.c
@@ -1,7 +1,7 @@
#define TSF_IMPLEMENTATION
-#include "tsf.h"
+#include "../tsf.h"
-#include "minisdl_audio.h"
+#include "../minisdl_audio.h"
//This is a minimal SoundFont with a single loopin saw-wave sample/instrument/preset (484 bytes)
const static unsigned char MinimalSoundFont[] = {
diff --git a/example2.c b/examples/example2.c
index cfc0fc0..b4c7d73 100644
--- a/example2.c
+++ b/examples/example2.c
@@ -1,7 +1,7 @@
-#include "minisdl_audio.h"
+#include "../minisdl_audio.h"
#define TSF_IMPLEMENTATION
-#include "tsf.h"
+#include "../tsf.h"
// Holds the global instance pointer
static tsf* g_TinySoundFont;
@@ -35,7 +35,7 @@ int main(int argc, char *argv[]) {
}
// Load the SoundFont from a file
- g_TinySoundFont = tsf_load_filename("sf2/florestan-subset.sf2");
+ g_TinySoundFont = tsf_load_filename("../sf2/florestan-subset.sf2");
if (!g_TinySoundFont) {
fprintf(stderr, "Could not load SoundFont\n");
return 1;
diff --git a/example4.c b/examples/example4.c
index 1dc9ebe..1dc9ebe 100644
--- a/example4.c
+++ b/examples/example4.c
diff --git a/portmidi.h b/portmidi.h
deleted file mode 100755
index 8696a73..0000000
--- a/portmidi.h
+++ /dev/null
@@ -1,974 +0,0 @@
-#ifndef PORTMIDI_PORTMIDI_H
-#define PORTMIDI_PORTMIDI_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/*
- * PortMidi Portable Real-Time MIDI Library
- * PortMidi API Header File
- * Latest version available at: http://sourceforge.net/projects/portmedia
- *
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- * Copyright (c) 2001-2006 Roger B. Dannenberg
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS 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.
- */
-
-/*
- * The text above constitutes the entire PortMidi license; however,
- * the PortMusic community also makes the following non-binding requests:
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version. It is also
- * requested that these non-binding requests be included along with the
- * license above.
- */
-
-/* CHANGELOG FOR PORTMIDI
- * (see ../CHANGELOG.txt)
- *
- * NOTES ON HOST ERROR REPORTING:
- *
- * PortMidi errors (of type PmError) are generic,
- * system-independent errors. When an error does not map to one of
- * the more specific PmErrors, the catch-all code pmHostError is
- * returned. This means that PortMidi has retained a more specific
- * system-dependent error code. The caller can get more information
- * by calling Pm_GetHostErrorText() to get a text string describing
- * the error. Host errors can arise asynchronously from callbacks,
- * * so there is no specific return code. Asynchronous errors are
- * checked and reported by Pm_Poll. You can also check by calling
- * Pm_HasHostError(). If this returns TRUE, Pm_GetHostErrorText()
- * will return a text description of the error.
- *
- * NOTES ON COMPILE-TIME SWITCHES
- *
- * DEBUG assumes stdio and a console. Use this if you want
- * automatic, simple error reporting, e.g. for prototyping. If
- * you are using MFC or some other graphical interface with no
- * console, DEBUG probably should be undefined.
- * PM_CHECK_ERRORS more-or-less takes over error checking for
- * return values, stopping your program and printing error
- * messages when an error occurs. This also uses stdio for
- * console text I/O. You can selectively disable this error
- * checking by declaring extern int pm_check_errors; and
- * setting pm_check_errors = FALSE; You can also reenable.
- */
-/**
- \defgroup grp_basics Basic Definitions
- @{
-*/
-
-#include <stdint.h>
-
-#ifdef _WINDLL
-#define PMEXPORT __declspec(dllexport)
-#else
-#define PMEXPORT
-#endif
-
-#ifndef FALSE
- #define FALSE 0
-#endif
-#ifndef TRUE
- #define TRUE 1
-#endif
-
-/* default size of buffers for sysex transmission: */
-#define PM_DEFAULT_SYSEX_BUFFER_SIZE 1024
-
-
-typedef enum {
- pmNoError = 0, /**< Normal return value indicating no error. */
- pmNoData = 0, /**< @brief No error, also indicates no data available.
- * Use this constant where a value greater than zero would
- * indicate data is available.
- */
- pmGotData = 1, /**< A "no error" return also indicating data available. */
- pmHostError = -10000,
- pmInvalidDeviceId, /**< Out of range or
- * output device when input is requested or
- * input device when output is requested or
- * device is already opened.
- */
- pmInsufficientMemory,
- pmBufferTooSmall,
- pmBufferOverflow,
- pmBadPtr, /**< #PortMidiStream parameter is NULL or
- * stream is not opened or
- * stream is output when input is required or
- * stream is input when output is required. */
- pmBadData, /**< Illegal midi data, e.g., missing EOX. */
- pmInternalError,
- pmBufferMaxSize, /**< Buffer is already as large as it can be. */
- pmNotImplemented, /**< The function is not implemented, nothing was done. */
- pmInterfaceNotSupported, /**< The requested interface is not supported. */
- pmNameConflict, /**< Cannot create virtual device because name is taken. */
- pmDeviceRemoved /**< Output attempted after (USB) device was removed. */
- /* NOTE: If you add a new error type, you must update Pm_GetErrorText(). */
-} PmError; /**< @brief @enum PmError PortMidi error code; a common return type.
- * No error is indicated by zero; errors are indicated by < 0.
- */
-
-/**
- Pm_Initialize() is the library initialization function - call this before
- using the library.
-
- *NOTE:* PortMidi scans for available devices when #Pm_Initialize
- is called. To observe subsequent changes in the available
- devices, you must shut down PortMidi by calling #Pm_Terminate and
- then restart by calling #Pm_Initialize again. *IMPORTANT*: On
- MacOS, #Pm_Initialize *must* always be called on the same
- thread. Otherwise, changes in the available MIDI devices will
- *not* be seen by PortMidi. As an example, if you start PortMidi in
- a thread for processing MIDI, do not try to rescan devices by
- calling #Pm_Initialize in a GUI thread. Instead, start PortMidi
- the first time and every time in the GUI thread. Alternatively,
- let the GUI request a restart in the MIDI thread. (These
- restrictions only apply to macOS.) Speaking of threads, on all
- platforms, you are allowed to call #Pm_Initialize in one thread,
- yet send MIDI or poll for incoming MIDI in another
- thread. However, PortMidi is not "thread safe," which means you
- cannot allow threads to call PortMidi functions concurrently.
-
- @return pmNoError.
-
- PortMidi is designed to support multiple interfaces (such as ALSA,
- CoreMIDI and WinMM). It is possible to return pmNoError because there
- are no supported interfaces. In that case, zero devices will be
- available.
-*/
-PMEXPORT PmError Pm_Initialize(void);
-
-/**
- Pm_Terminate() is the library termination function - call this after
- using the library.
-*/
-PMEXPORT PmError Pm_Terminate(void);
-
-/** Represents an open MIDI device. */
-typedef void PortMidiStream;
-
-/** A shorter form of #PortMidiStream. */
-#define PmStream PortMidiStream
-
-/** Test whether stream has a pending host error. Normally, the client
- finds out about errors through returned error codes, but some
- errors can occur asynchronously where the client does not
- explicitly call a function, and therefore cannot receive an error
- code. The client can test for a pending error using
- Pm_HasHostError(). If true, the error can be accessed by calling
- Pm_GetHostErrorText(). Pm_Poll() is similar to Pm_HasHostError(),
- but if there is no error, it will return TRUE (1) if there is a
- pending input message.
-*/
-PMEXPORT int Pm_HasHostError(PortMidiStream * stream);
-
-
-/** Translate portmidi error number into human readable message.
- These strings are constants (set at compile time) so client has
- no need to allocate storage.
-*/
-PMEXPORT const char *Pm_GetErrorText(PmError errnum);
-
-/** Translate portmidi host error into human readable message.
- These strings are computed at run time, so client has to allocate storage.
- After this routine executes, the host error is cleared.
-*/
-PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len);
-
-/** Any host error msg has at most this many characters, including EOS. */
-#define PM_HOST_ERROR_MSG_LEN 256u
-
-/** Devices are represented as small integers. Device ids range from 0
- to Pm_CountDevices()-1. Pm_GetDeviceInfo() is used to get information
- about the device, and Pm_OpenInput() and PmOpenOutput() are used to
- open the device.
-*/
-typedef int PmDeviceID;
-
-/** This PmDeviceID (constant) value represents no device and may be
- returned by Pm_GetDefaultInputDeviceID() or
- Pm_GetDefaultOutputDeviceID() if no default exists.
-*/
-#define pmNoDevice -1
-
-/** MIDI device information is returned in this structure, which is
- owned by PortMidi and read-only to applications. See Pm_GetDeviceInfo().
-*/
-#define PM_DEVICEINFO_VERS 200
-typedef struct {
- int structVersion; /**< @brief this internal structure version */
- const char *interf; /**< @brief underlying MIDI API, e.g.
- "MMSystem" or "DirectX" */
- char *name; /**< @brief device name, e.g. "USB MidiSport 1x1" */
- int input; /**< @brief true iff input is available */
- int output; /**< @brief true iff output is available */
- int opened; /**< @brief used by generic PortMidi for error checking */
- int is_virtual; /**< @brief true iff this is/was a virtual device */
-} PmDeviceInfo;
-
-/** MIDI system-dependent device or driver info is passed in this
- structure, which is owned by the caller.
-*/
-#define PM_SYSDEPINFO_VERS 210
-
-enum PmSysDepPropertyKey {
- pmKeyNone = 0, /**< a "noop" key value */
- /** CoreMIDI Manufacturer name, value is string */
- pmKeyCoreMidiManufacturer = 1,
- /** Linux ALSA snd_seq_port_info_set_name, value is a string. Can be
- passed in PmSysDepInfo to Pm_OpenInput or Pm_OpenOutput when opening
- a device. The created port will be named accordingly and will be
- visible for externally made connections (subscriptions). (Linux ALSA
- ports are always enabled for this, but only get application-specific
- names if you give it one.) This key/value is ignored when opening
- virtual ports, which are named when they are created.) */
- pmKeyAlsaPortName = 2,
- /** Linux ALSA snd_seq_set_client_name, value is a string.
- Can be passed in PmSysDepInfo to Pm_OpenInput or Pm_OpenOutput.
- Pm_CreateVirtualInput or Pm_CreateVirtualOutput. Will override
- any previously set client name and applies to all ports. */
- pmKeyAlsaClientName = 3
- /* if system-dependent code introduces more options, register
- the key here to avoid conflicts. */
-};
-
-/** System-dependent information can be passed when creating and opening
- ports using this data structure, which stores alternating keys and
- values (addresses). See `pm_test/sendvirtual.c`, `pm_test/recvvirtual.c`,
- and `pm_test/testio.c` for examples.
- */
-typedef struct {
- int structVersion; /**< @brief this structure version */
- int length; /**< @brief number of properties in this structure */
- struct {
- enum PmSysDepPropertyKey key;
- const void *value;
- } properties[];
-} PmSysDepInfo;
-
-
-/** Get devices count, ids range from 0 to Pm_CountDevices()-1. */
-PMEXPORT int Pm_CountDevices(void);
-
-/**
- Return the default device ID or pmNoDevice if there are no devices.
- The result (but not pmNoDevice) can be passed to Pm_OpenMidi().
-
- The use of these functions is not recommended. There is no natural
- "default device" on any system, so defaults must be set by users.
- (Currently, PortMidi just returns the first device it finds as
- "default", so if there *is* a default, implementors should use
- pm_add_device to add system default input and output devices
- first.)
-
- The recommended solution is pass the burden to applications. It is
- easy to scan devices with PortMidi and build a device menu, and to
- save menu selections in application preferences for next
- time. This is my recommendation for any GUI program. For simple
- command-line applications and utilities, see pm_test where all the
- test programs now accept device numbers on the command line and/or
- prompt for their entry.
-
- On linux, you can create virtual ports and use an external program
- to set up inter-application and device connections.
-
- Some advice for preferences: MIDI devices used to be built-in or
- plug-in cards, so the numbers rarely changed. Now MIDI devices are
- often plug-in USB devices, so device numbers change, and you
- probably need to design to reinitialize PortMidi to rescan
- devices. MIDI is pretty stateless, so this isn't a big problem,
- although it means you cannot find a new device while playing or
- recording MIDI.
-
- Since device numbering can change whenever a USB device is plugged
- in, preferences should record *names* of devices rather than
- device numbers. It is simple enough to use string matching to find
- a prefered device, so PortMidi does not provide any built-in
- lookup function.
-*/
-PMEXPORT PmDeviceID Pm_GetDefaultInputDeviceID(void);
-
-/** @brief see PmDeviceID Pm_GetDefaultInputDeviceID() */
-PMEXPORT PmDeviceID Pm_GetDefaultOutputDeviceID(void);
-
-/** Find a device that matches a pattern.
-
- @param pattern a substring of the device name, or if the pattern
- contains the two-character separator ", ", then the first part of
- the pattern represents a device interface substring and the second
- part after the separator represents a device name substring.
-
- @param is_input restricts the search to an input when true, or an
- output when false.
-
- @return the number of the first device whose device interface
- contains the interface pattern (if any), whose device name
- contains the name pattern, and whose direction (input or output)
- matches the #is_input parameter. If no match is found, #pmNoDevice
- (-1) is returned.
-*/
-PMEXPORT PmDeviceID Pm_FindDevice(char *pattern, int is_input);
-
-
-/** Represents a millisecond clock with arbitrary start time.
- This type is used for all MIDI timestamps and clocks.
-*/
-typedef int32_t PmTimestamp;
-typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
-
-/** TRUE if t1 before t2 */
-#define PmBefore(t1,t2) (((t1)-(t2)) < 0)
-/** @} */
-/**
- \defgroup grp_device Input/Output Devices Handling
- @{
-*/
-/** Get a PmDeviceInfo structure describing a MIDI device.
-
- @param id the device to be queried.
-
- If \p id is out of range or if the device designates a deleted
- virtual device, the function returns NULL.
-
- The returned structure is owned by the PortMidi implementation and
- must not be manipulated or freed. The pointer is guaranteed to be
- valid between calls to Pm_Initialize() and Pm_Terminate().
-*/
-PMEXPORT const PmDeviceInfo *Pm_GetDeviceInfo(PmDeviceID id);
-
-/** Open a MIDI device for input.
-
- @param stream the address of a #PortMidiStream pointer which will
- receive a pointer to the newly opened stream.
-
- @param inputDevice the ID of the device to be opened (see #PmDeviceID).
-
- @param inputSysDepInfo a pointer to an optional system-dependent
- data structure (a #PmSysDepInfo struct) containing additional
- information for device setup or handle processing. This parameter
- is never required for correct operation. If not used, specify
- NULL. Declared `void *` here for backward compatibility. Note that
- with Linux ALSA, you can use this parameter to specify a client name
- and port name.
-
- @param bufferSize the number of input events to be buffered
- waiting to be read using Pm_Read(). Messages will be lost if the
- number of unread messages exceeds this value.
-
- @param time_proc (address of) a procedure that returns time in
- milliseconds. It may be NULL, in which case a default millisecond
- timebase (PortTime) is used. If the application wants to use
- PortTime, it should start the timer (call Pt_Start) before calling
- Pm_OpenInput or Pm_OpenOutput. If the application tries to start
- the timer *after* Pm_OpenInput or Pm_OpenOutput, it may get a
- ptAlreadyStarted error from Pt_Start, and the application's
- preferred time resolution and callback function will be ignored.
- \p time_proc result values are appended to incoming MIDI data,
- normally by mapping system-provided timestamps to the \p time_proc
- timestamps to maintain the precision of system-provided
- timestamps.
-
- @param time_info is a pointer passed to time_proc.
-
- @return #pmNoError and places a pointer to a valid
- #PortMidiStream in the stream argument. If the open operation
- fails, a nonzero error code is returned (see #PMError) and
- the value of stream is invalid.
-
- Any stream that is successfully opened should eventually be closed
- by calling Pm_Close().
-*/
-PMEXPORT PmError Pm_OpenInput(PortMidiStream** stream,
- PmDeviceID inputDevice,
- void *inputSysDepInfo,
- int32_t bufferSize,
- PmTimeProcPtr time_proc,
- void *time_info);
-
-/** Open a MIDI device for output.
-
- @param stream the address of a #PortMidiStream pointer which will
- receive a pointer to the newly opened stream.
-
- @param outputDevice the ID of the device to be opened (see #PmDeviceID).
-
- @param inputSysDepInfo a pointer to an optional system-specific
- data structure (a #PmSysDepInfo struct) containing additional
- information for device setup or handle processing. This parameter
- is never required for correct operation. If not used, specify
- NULL. Declared `void *` here for backward compatibility. Note that
- with Linux ALSA, you can use this parameter to specify a client name
- and port name.
-
- @param bufferSize the number of output events to be buffered
- waiting for output. In some cases -- see below -- PortMidi does
- not buffer output at all and merely passes data to a lower-level
- API, in which case \p bufferSize is ignored. Since MIDI speeds now
- vary from 1 to 50 or more messages per ms (over USB), put some
- thought into this number. E.g. if latency is 20ms and you want to
- burst 100 messages in that time (5000 messages per second), you
- should set \p bufferSize to at least 100. The default on Windows
- assumes an average rate of 500 messages per second and in this
- example, output would be slowed waiting for free buffers.
-
- @param latency the delay in milliseconds applied to timestamps
- to determine when the output should actually occur. (If latency is
- < 0, 0 is assumed.) If latency is zero, timestamps are ignored
- and all output is delivered immediately. If latency is greater
- than zero, output is delayed until the message timestamp plus the
- latency. (NOTE: the time is measured relative to the time source
- indicated by time_proc. Timestamps are absolute, not relative
- delays or offsets.) In some cases, PortMidi can obtain better
- timing than your application by passing timestamps along to the
- device driver or hardware, so the best strategy to minimize jitter
- is: wait until the real time to send the message, compute the
- message, attach the *ideal* output time (not the current real
- time, because some time may have elapsed), and send the
- message. The \p latency will be added to the timestamp, and
- provided the elapsed computation time has not exceeded \p latency,
- the message will be delivered according to the timestamp. If the
- real time is already past the timestamp, the message will be
- delivered as soon as possible. Latency may also help you to
- synchronize MIDI data to audio data by matching \p latency to the
- audio buffer latency.
-
- @param time_proc (address of) a pointer to a procedure that
- returns time in milliseconds. It may be NULL, in which case a
- default millisecond timebase (PortTime) is used. If the
- application wants to use PortTime, it should start the timer (call
- Pt_Start) before calling #Pm_OpenInput or #Pm_OpenOutput. If the
- application tries to start the timer *after* #Pm_OpenInput or
- #Pm_OpenOutput, it may get a #ptAlreadyStarted error from #Pt_Start,
- and the application's preferred time resolution and callback
- function will be ignored. \p time_proc times are used to schedule
- outgoing MIDI data (when latency is non-zero), usually by mapping
- from time_proc timestamps to internal system timestamps to
- maintain the precision of system-supported timing.
-
- @param time_info a pointer passed to time_proc.
-
- @return #pmNoError and places a pointer to a valid #PortMidiStream
- in the stream argument. If the operation fails, a nonzero error
- code is returned (see PMError) and the value of \p stream is
- invalid.
-
- Note: ALSA appears to have a fixed-size priority queue for timed
- output messages. Testing indicates the queue can hold a little
- over 400 3-byte MIDI messages. Thus, you can send 10,000
- messages/second if the latency is 30ms (30ms * 10000 msgs/sec *
- 0.001 sec/ms = 300 msgs), but not if the latency is 50ms
- (resulting in about 500 pending messages, which is greater than
- the 400 message limit). Since timestamps in ALSA are relative,
- they are of less value than absolute timestamps in macOS and
- Windows. This is a limitation of ALSA and apparently a design
- flaw.
-
- Example 1: If I provide a timestamp of 5000, latency is 1, and
- time_proc returns 4990, then the desired output time will be when
- time_proc returns timestamp+latency = 5001. This will be 5001-4990
- = 11ms from now.
-
- Example 2: If I want to send at exactly 5010, and latency is 10, I
- should wait until 5000, compute the messages and provide a
- timestamp of 5000. As long as computation takes less than 10ms,
- the message will be delivered at time 5010.
-
- Example 3 (recommended): It is often convenient to ignore latency.
- E.g. if a sequence says to output at time 5010, just wait until
- 5010, compute the message and use 5010 for the timestamp. Delivery
- will then be at 5010+latency, but unless you are synchronizing to
- something else, the absolute delay by latency will not matter.
-
- Any stream that is successfully opened should eventually be closed
- by calling Pm_Close().
-*/
-PMEXPORT PmError Pm_OpenOutput(PortMidiStream** stream,
- PmDeviceID outputDevice,
- void *outputSysDepInfo,
- int32_t bufferSize,
- PmTimeProcPtr time_proc,
- void *time_info,
- int32_t latency);
-
-/** Create a virtual input device.
-
- @param name gives the virtual device name, which is visible to
- other applications.
-
- @param interf is the interface (System API) used to create the
- device Default interfaces are "MMSystem", "CoreMIDI" and
- "ALSA". Currently, these are the only ones implemented, but future
- implementations could support DirectMusic, Jack, sndio, or others.
-
- @param sysDepInfo contains interface-dependent additional
- information (a #PmSysDepInfo struct), e.g., hints or options. This
- parameter is never required for correct operation. If not used,
- specify NULL. Declared `void *` here for backward compatibility.
-
- @return a device ID or #pmNameConflict (\p name is invalid or
- already exists) or #pmInterfaceNotSupported (\p interf is does not
- match a supported interface).
-
- The created virtual device appears to other applications as if it
- is an output device. The device must be opened to obtain a stream
- and read from it.
-
- Virtual devices are not supported by Windows (Multimedia API). Calls
- on Windows do nothing except return #pmNotImplemented.
-*/
-PMEXPORT PmError Pm_CreateVirtualInput(const char *name,
- const char *interf,
- void *sysDepInfo);
-
-/** Create a virtual output device.
-
- @param name gives the virtual device name, which is visible to
- other applications.
-
- @param interf is the interface (System API) used to create the
- device Default interfaces are "MMSystem", "CoreMIDI" and
- "ALSA". Currently, these are the only ones implemented, but future
- implementations could support DirectMusic, Jack, sndio, or others.
-
- @param sysDepInfo contains interface-dependent additional
- information (a #PmSysDepInfo struct), e.g., hints or options. This
- parameter is never required for correct operation. If not used,
- specify NULL. Declared `void *` here for backward compatibility.
-
- @return a device ID or #pmInvalidDeviceId (\p name is invalid or
- already exists) or #pmInterfaceNotSupported (\p interf is does not
- match a supported interface).
-
- The created virtual device appears to other applications as if it
- is an input device. The device must be opened to obtain a stream
- and write to it.
-
- Virtual devices are not supported by Windows (Multimedia API). Calls
- on Windows do nothing except return #pmNotImplemented.
-*/
-PMEXPORT PmError Pm_CreateVirtualOutput(const char *name,
- const char *interf,
- void *sysDepInfo);
-
-/** Remove a virtual device.
-
- @param device a device ID (small integer) designating the device.
-
- The device is removed; other applications can no longer see or open
- this virtual device, which may be either for input or output. The
- device must not be open. The device ID may be reused, but existing
- devices are not renumbered. This means that the device ID could be
- in the range from 0 to #Pm_CountDevices(), yet the device ID does
- not designate a device. In that case, passing the ID to
- #Pm_GetDeviceInfo() will return NULL.
-
- @return #pmNoError if the device was deleted or #pmInvalidDeviceId
- if the device is open, already deleted, or \p device is out of
- range.
-*/
-PMEXPORT PmError Pm_DeleteVirtualDevice(PmDeviceID device);
- /** @} */
-
-/**
- @defgroup grp_events_filters Events and Filters Handling
- @{
-*/
-
-/* Filter bit-mask definitions */
-/** filter active sensing messages (0xFE): */
-#define PM_FILT_ACTIVE (1 << 0x0E)
-/** filter system exclusive messages (0xF0): */
-#define PM_FILT_SYSEX (1 << 0x00)
-/** filter MIDI clock message (0xF8) */
-#define PM_FILT_CLOCK (1 << 0x08)
-/** filter play messages (start 0xFA, stop 0xFC, continue 0xFB) */
-#define PM_FILT_PLAY ((1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B))
-/** filter tick messages (0xF9) */
-#define PM_FILT_TICK (1 << 0x09)
-/** filter undefined FD messages */
-#define PM_FILT_FD (1 << 0x0D)
-/** filter undefined real-time messages */
-#define PM_FILT_UNDEFINED PM_FILT_FD
-/** filter reset messages (0xFF) */
-#define PM_FILT_RESET (1 << 0x0F)
-/** filter all real-time messages */
-#define PM_FILT_REALTIME (PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK | \
- PM_FILT_PLAY | PM_FILT_UNDEFINED | PM_FILT_RESET | PM_FILT_TICK)
-/** filter note-on and note-off (0x90-0x9F and 0x80-0x8F */
-#define PM_FILT_NOTE ((1 << 0x19) | (1 << 0x18))
-/** filter channel aftertouch (most midi controllers use this) (0xD0-0xDF)*/
-#define PM_FILT_CHANNEL_AFTERTOUCH (1 << 0x1D)
-/** per-note aftertouch (0xA0-0xAF) */
-#define PM_FILT_POLY_AFTERTOUCH (1 << 0x1A)
-/** filter both channel and poly aftertouch */
-#define PM_FILT_AFTERTOUCH (PM_FILT_CHANNEL_AFTERTOUCH | \
- PM_FILT_POLY_AFTERTOUCH)
-/** Program changes (0xC0-0xCF) */
-#define PM_FILT_PROGRAM (1 << 0x1C)
-/** Control Changes (CC's) (0xB0-0xBF)*/
-#define PM_FILT_CONTROL (1 << 0x1B)
-/** Pitch Bender (0xE0-0xEF*/
-#define PM_FILT_PITCHBEND (1 << 0x1E)
-/** MIDI Time Code (0xF1)*/
-#define PM_FILT_MTC (1 << 0x01)
-/** Song Position (0xF2) */
-#define PM_FILT_SONG_POSITION (1 << 0x02)
-/** Song Select (0xF3)*/
-#define PM_FILT_SONG_SELECT (1 << 0x03)
-/** Tuning request (0xF6) */
-#define PM_FILT_TUNE (1 << 0x06)
-/** All System Common messages (mtc, song position, song select, tune request) */
-#define PM_FILT_SYSTEMCOMMON (PM_FILT_MTC | PM_FILT_SONG_POSITION | \
- PM_FILT_SONG_SELECT | PM_FILT_TUNE)
-
-
-/* Set filters on an open input stream to drop selected input types.
-
- @param stream an open MIDI input stream.
-
- @param filters indicate message types to filter (block).
-
- @return #pmNoError or an error code.
-
- By default, only active sensing messages are filtered.
- To prohibit, say, active sensing and sysex messages, call
- Pm_SetFilter(stream, PM_FILT_ACTIVE | PM_FILT_SYSEX);
-
- Filtering is useful when midi routing or midi thru functionality
- is being provided by the user application.
- For example, you may want to exclude timing messages (clock, MTC,
- start/stop/continue), while allowing note-related messages to pass.
- Or you may be using a sequencer or drum-machine for MIDI clock
- information but want to exclude any notes it may play.
- */
-PMEXPORT PmError Pm_SetFilter(PortMidiStream* stream, int32_t filters);
-
-/** Create a mask that filters one channel. */
-#define Pm_Channel(channel) (1<<(channel))
-
-/** Filter incoming messages based on channel.
-
- @param stream an open MIDI input stream.
-
- @param mask indicates channels to be received.
-
- @return #pmNoError or an error code.
-
- The \p mask is a 16-bit bitfield corresponding to appropriate channels.
- The #Pm_Channel macro can assist in calling this function.
- I.e. to receive only input on channel 1, call with
- Pm_SetChannelMask(Pm_Channel(1));
- Multiple channels should be OR'd together, like
- Pm_SetChannelMask(Pm_Channel(10) | Pm_Channel(11))
-
- Note that channels are numbered 0 to 15 (not 1 to 16). Most
- synthesizer and interfaces number channels starting at 1, but
- PortMidi numbers channels starting at 0.
-
- All channels are allowed by default
-*/
-PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask);
-
-/** Terminate outgoing messages immediately.
-
- @param stream an open MIDI output stream.
-
- @result #pmNoError or an error code.
-
- The caller should immediately close the output port; this call may
- result in transmission of a partial MIDI message. There is no
- abort for Midi input because the user can simply ignore messages
- in the buffer and close an input device at any time. If the
- specified behavior cannot be achieved through the system-level
- interface (ALSA, CoreMIDI, etc.), the behavior may be that of
- Pm_Close().
- */
-PMEXPORT PmError Pm_Abort(PortMidiStream* stream);
-
-/** Close a midi stream, flush any pending buffers if possible.
-
- @param stream an open MIDI input or output stream.
-
- @result #pmNoError or an error code.
-
- If the system-level interface (ALSA, CoreMIDI, etc.) does not
- support flushing remaining messages, the behavior may be one of
- the following (most preferred first): block until all pending
- timestamped messages are delivered; deliver messages to a server
- or kernel process for later delivery but return immediately; drop
- messages (as in Pm_Abort()). Therefore, to be safe, applications
- should wait until the output queue is empty before calling
- Pm_Close(). E.g. calling Pt_Sleep(100 + latency); will give a
- 100ms "cushion" beyond latency (if any) before closing.
-*/
-PMEXPORT PmError Pm_Close(PortMidiStream* stream);
-
-/** (re)synchronize to the time_proc passed when the stream was opened.
-
- @param stream an open MIDI input or output stream.
-
- @result #pmNoError or an error code.
-
- Typically, this is used when the stream must be opened before the
- time_proc reference is actually advancing. In this case, message
- timing may be erratic, but since timestamps of zero mean "send
- immediately," initialization messages with zero timestamps can be
- written without a functioning time reference and without
- problems. Before the first MIDI message with a non-zero timestamp
- is written to the stream, the time reference must begin to advance
- (for example, if the time_proc computes time based on audio
- samples, time might begin to advance when an audio stream becomes
- active). After time_proc return values become valid, and BEFORE
- writing the first non-zero timestamped MIDI message, call
- Pm_Synchronize() so that PortMidi can observe the difference
- between the current time_proc value and its MIDI stream time.
-
- In the more normal case where time_proc values advance
- continuously, there is no need to call #Pm_Synchronize. PortMidi
- will always synchronize at the first output message and
- periodically thereafter.
-*/
-PMEXPORT PmError Pm_Synchronize(PortMidiStream* stream);
-
-
-/** Encode a short Midi message into a 32-bit word. If data1
- and/or data2 are not present, use zero.
-*/
-#define Pm_Message(status, data1, data2) \
- ((((data2) << 16) & 0xFF0000) | \
- (((data1) << 8) & 0xFF00) | \
- ((status) & 0xFF))
-/** Extract the status field from a 32-bit midi message. */
-#define Pm_MessageStatus(msg) ((msg) & 0xFF)
-/** Extract the 1st data field (e.g., pitch) from a 32-bit midi message. */
-#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
-/** Extract the 2nd data field (e.g., velocity) from a 32-bit midi message. */
-#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)
-
-typedef uint32_t PmMessage; /**< @brief see #PmEvent */
-/**
- All MIDI data comes in the form of PmEvent structures. A sysex
- message is encoded as a sequence of PmEvent structures, with each
- structure carrying 4 bytes of the message, i.e. only the first
- PmEvent carries the status byte.
-
- All other MIDI messages take 1 to 3 bytes and are encoded in a whole
- PmMessage with status in the low-order byte and remaining bytes
- unused, i.e., a 3-byte note-on message will occupy 3 low-order bytes
- of PmMessage, leaving the high-order byte unused.
-
- Note that MIDI allows nested messages: the so-called "real-time" MIDI
- messages can be inserted into the MIDI byte stream at any location,
- including within a sysex message. MIDI real-time messages are one-byte
- messages used mainly for timing (see the MIDI spec). PortMidi retains
- the order of non-real-time MIDI messages on both input and output, but
- it does not specify exactly how real-time messages are processed. This
- is particulary problematic for MIDI input, because the input parser
- must either prepare to buffer an unlimited number of sysex message
- bytes or to buffer an unlimited number of real-time messages that
- arrive embedded in a long sysex message. To simplify things, the input
- parser is allowed to pass real-time MIDI messages embedded within a
- sysex message, and it is up to the client to detect, process, and
- remove these messages as they arrive.
-
- When receiving sysex messages, the sysex message is terminated
- by either an EOX status byte (anywhere in the 4 byte messages) or
- by a non-real-time status byte in the low order byte of the message.
- If you get a non-real-time status byte but there was no EOX byte, it
- means the sysex message was somehow truncated. This is not
- considered an error; e.g., a missing EOX can result from the user
- disconnecting a MIDI cable during sysex transmission.
-
- A real-time message can occur within a sysex message. A real-time
- message will always occupy a full PmEvent with the status byte in
- the low-order byte of the PmEvent message field. (This implies that
- the byte-order of sysex bytes and real-time message bytes may not
- be preserved -- for example, if a real-time message arrives after
- 3 bytes of a sysex message, the real-time message will be delivered
- first. The first word of the sysex message will be delivered only
- after the 4th byte arrives, filling the 4-byte PmEvent message field.
-
- The timestamp field is observed when the output port is opened with
- a non-zero latency. A timestamp of zero means "use the current time",
- which in turn means to deliver the message with a delay of
- latency (the latency parameter used when opening the output port.)
- Do not expect PortMidi to sort data according to timestamps --
- messages should be sent in the correct order, and timestamps MUST
- be non-decreasing. See also "Example" for Pm_OpenOutput() above.
-
- A sysex message will generally fill many #PmEvent structures. On
- output to a #PortMidiStream with non-zero latency, the first timestamp
- on sysex message data will determine the time to begin sending the
- message. PortMidi implementations may ignore timestamps for the
- remainder of the sysex message.
-
- On input, the timestamp ideally denotes the arrival time of the
- status byte of the message. The first timestamp on sysex message
- data will be valid. Subsequent timestamps may denote
- when message bytes were actually received, or they may be simply
- copies of the first timestamp.
-
- Timestamps for nested messages: If a real-time message arrives in
- the middle of some other message, it is enqueued immediately with
- the timestamp corresponding to its arrival time. The interrupted
- non-real-time message or 4-byte packet of sysex data will be enqueued
- later. The timestamp of interrupted data will be equal to that of
- the interrupting real-time message to insure that timestamps are
- non-decreasing.
- */
-typedef struct {
- PmMessage message;
- PmTimestamp timestamp;
-} PmEvent;
-
-/** @} */
-
-/** \defgroup grp_io Reading and Writing Midi Messages
- @{
-*/
-/** Retrieve midi data into a buffer.
-
- @param stream the open input stream.
-
- @return the number of events read, or, if the result is negative,
- a #PmError value will be returned.
-
- The Buffer Overflow Problem
-
- The problem: if an input overflow occurs, data will be lost,
- ultimately because there is no flow control all the way back to
- the data source. When data is lost, the receiver should be
- notified and some sort of graceful recovery should take place,
- e.g. you shouldn't resume receiving in the middle of a long sysex
- message.
-
- With a lock-free fifo, which is pretty much what we're stuck with
- to enable portability to the Mac, it's tricky for the producer and
- consumer to synchronously reset the buffer and resume normal
- operation.
-
- Solution: the entire buffer managed by PortMidi will be flushed
- when an overflow occurs. The consumer (Pm_Read()) gets an error
- message (#pmBufferOverflow) and ordinary processing resumes as
- soon as a new message arrives. The remainder of a partial sysex
- message is not considered to be a "new message" and will be
- flushed as well.
-*/
-PMEXPORT int Pm_Read(PortMidiStream *stream, PmEvent *buffer, int32_t length);
-
-/** Test whether input is available.
-
- @param stream an open input stream.
-
- @return TRUE, FALSE, or an error value.
-
- If there was an asynchronous error, pmHostError is returned and you must
- call again to determine if input is (also) available.
-
- You should probably *not* use this function. Call Pm_Read()
- instead. If it returns 0, then there is no data available. It is
- possible for Pm_Poll() to return TRUE before the complete message
- is available, so Pm_Read() could return 0 even after Pm_Poll()
- returns TRUE. Only call Pm_Poll() if you want to know that data is
- probably available even though you are not ready to receive data.
-*/
-PMEXPORT PmError Pm_Poll(PortMidiStream *stream);
-
-/** Write MIDI data from a buffer.
-
- @param stream an open output stream.
-
- @param buffer (address of) an array of MIDI event data.
-
- @param length the length of the \p buffer.
-
- @return TRUE, FALSE, or an error value.
-
- \b buffer may contain:
- - short messages
- - sysex messages that are converted into a sequence of PmEvent
- structures, e.g. sending data from a file or forwarding them
- from midi input, with 4 SysEx bytes per PmEvent message,
- low-order byte first, until the last message, which may
- contain from 1 to 4 bytes ending in MIDI EOX (0xF7).
- - PortMidi allows 1-byte real-time messages to be embedded
- within SysEx messages, but only on 4-byte boundaries so
- that SysEx data always uses a full 4 bytes (except possibly
- at the end). Each real-time message always occupies a full
- PmEvent (3 of the 4 bytes in the PmEvent's message are
- ignored) even when embedded in a SysEx message.
-
- Use Pm_WriteSysEx() to write a sysex message stored as a contiguous
- array of bytes.
-
- Sysex data may contain embedded real-time messages.
-
- \p buffer is managed by the caller. The buffer may be destroyed
- as soon as this call returns.
-*/
-PMEXPORT PmError Pm_Write(PortMidiStream *stream, PmEvent *buffer,
- int32_t length);
-
-/** Write a timestamped non-system-exclusive midi message.
-
- @param stream an open output stream.
-
- @param when timestamp for the event.
-
- @param msg the data for the event.
-
- @result #pmNoError or an error code.
-
- Messages are delivered in order, and timestamps must be
- non-decreasing. (But timestamps are ignored if the stream was
- opened with latency = 0, and otherwise, non-decreasing timestamps
- are "corrected" to the lowest valid value.)
-*/
-PMEXPORT PmError Pm_WriteShort(PortMidiStream *stream, PmTimestamp when,
- PmMessage msg);
-
-/** Write a timestamped system-exclusive midi message.
-
- @param stream an open output stream.
-
- @param when timestamp for the event.
-
- @param msg the sysex message, terminated with an EOX status byte.
-
- @result #pmNoError or an error code.
-
- \p msg is managed by the caller and may be destroyed when this
- call returns.
-*/
-PMEXPORT PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when,
- unsigned char *msg);
-
-/** @} */
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* PORTMIDI_PORTMIDI_H */
diff --git a/portmidi/.github/workflows/build.yml b/portmidi/.github/workflows/build.yml
deleted file mode 100644
index 351b5cb..0000000
--- a/portmidi/.github/workflows/build.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-name: build
-
-on:
- push:
- pull_request:
-
-jobs:
- build:
- strategy:
- fail-fast: false
- matrix:
- include:
- - name: Ubuntu
- os: ubuntu-latest
- install_dir: ~/portmidi
- cmake_extras: -DCMAKE_BUILD_TYPE=RelWithDebInfo
- - name: macOS
- os: macos-latest
- install_dir: ~/portmidi
- cmake_extras: -DCMAKE_BUILD_TYPE=RelWithDebInfo
- - name: Windows
- os: windows-latest
- install_dir: C:\portmidi
- cmake_config: --config RelWithDebInfo
-
- name: ${{ matrix.name }}
- runs-on: ${{ matrix.os }}
- steps:
- - name: Check out Git repository
- uses: actions/checkout@v2
- - name: "[Ubuntu] Install dependencies"
- run: sudo apt install -y libasound2-dev
- if: runner.os == 'Linux'
- - name: Configure
- run: cmake -D CMAKE_INSTALL_PREFIX=${{ matrix.install_dir }} ${{ matrix.cmake_extras }} -S . -B build
- - name: Build
- run: cmake --build build ${{ matrix.cmake_config }}
- env:
- CMAKE_BUILD_PARALLEL_LEVEL: 2
- - name: Install
- run: cmake --install . ${{ matrix.cmake_config }}
- working-directory: build
- - name: Upload Build Artifact
- uses: actions/upload-artifact@v2
- with:
- name: ${{ matrix.name }} portmidi build
- path: ${{ matrix.install_dir }}
diff --git a/portmidi/.github/workflows/docs.yml b/portmidi/.github/workflows/docs.yml
deleted file mode 100644
index d0e251b..0000000
--- a/portmidi/.github/workflows/docs.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: Generate Docs
-
-on:
- push:
- branches:
- - main
- workflow_dispatch:
-
-jobs:
- doxygen:
- name: Doxygen
- runs-on: ubuntu-latest
- steps:
- - name: "Check out repository"
- uses: actions/checkout@v2
-
- - name: Install Doxygen
- run: sudo apt-get update && sudo apt-get install -y --no-install-recommends doxygen
-
- - name: Generate Documentation
- run: doxygen
- working-directory: .
-
- - name: Deploy to GitHub Pages
- uses: peaceiris/actions-gh-pages@v3
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- publish_dir: docs/html
diff --git a/portmidi/.gitignore b/portmidi/.gitignore
deleted file mode 100644
index 19d6650..0000000
--- a/portmidi/.gitignore
+++ /dev/null
@@ -1,62 +0,0 @@
-.DS_Store
-build*/
-*~
-CMakeCache.txt
-CMakeFiles/
-CMakeScripts/
-/portmidi.pc
-/x64/
-/Debug/
-/Release/
-/pm_java/pmdefaults/pmdefaults.jar
-/pm_java/pmdefaults.sln
-/pm_java/pmjni.dir/
-/pm_java/x64/
-portmidi.build/
-cmake_install.cmake
-*.xcodeproj/
-/.vs/
-/portmidi.sln
-*.vcxproj
-*.vcxproj.filters
-*.vcxproj.user
-/Makefile
-/libportmidi.so*
-/libportmidi.a
-/libportmidi_static.a
-/libpmjni.so*
-/packaging/PortMidiConfig.cmake
-/packaging/PortMidiConfigVersion.cmake
-/packaging/portmidi.pc
-/pm_common/Makefile
-/pm_common/portmidi.dir/
-/pm_java/Makefile
-/pm_test/Debug/
-/pm_test/Release/
-/pm_test/Makefile
-/pm_test/fastrcv
-/pm_test/fastrcv.dir/
-/pm_test/latency
-/pm_test/latency.dir/
-/pm_test/midiclock
-/pm_test/midiclock.dir/
-/pm_test/midithread
-/pm_test/midithread.dir/
-/pm_test/midithru
-/pm_test/midithru.dir/
-/pm_test/mm
-/pm_test/mm.dir/
-/pm_test/multivirtual
-/pm_test/qtest
-/pm_test/qtest.dir/
-/pm_test/recvvirtual
-/pm_test/sendvirtual
-/pm_test/sysex
-/pm_test/sysex.dir/
-/pm_test/testio
-/pm_test/testio.dir/
-/pm_test/virttest
-/pm_test/fast
-/pm_test/fast.dir/
-/pm_test/pmlist
-/pm_test/pmlist.dir/
diff --git a/portmidi/CHANGELOG.txt b/portmidi/CHANGELOG.txt
deleted file mode 100644
index fee4330..0000000
--- a/portmidi/CHANGELOG.txt
+++ /dev/null
@@ -1,213 +0,0 @@
-/* CHANGELOG FOR PORTMIDI
- *
- * 21Feb22 v2.0.3 Roger Dannenberg
- * - this version allows multiple hardware devices to have the same name.
- *
- * 03Jan22 v2.0.2 Roger Dannenberg
- * - many changes for CMake including install support
- * - bare-bones Java and PmDefaults support. It runs, but no
- * installation.
- *
- * 16Sep21 Roger Dannenberg
- * - Added CreateVirtualInput and CreateVirtualOutput functions (macOS
- * & Linux) only.
- * - Fix for unicode endpoints on macOS CoreMIDI.
- * - Parsing in macOS of realtime message embedded in short messages
- * (can this actually happen?)
- * - renamed pm_test/test.c to pm_test/testio.c
- * - with this release, pm_java, pm_csharp, pm_cl, pm_python, pm_qt
- * are marked as "legacy code" and README.txt's refer to other
- * projects. I had hoped for "one-stop shopping" for language
- * bindings, but developers decided to move work to independent
- * repositories. Maybe that's better.
- *
- * 19Oct09 Roger Dannenberg
- * - Changes dynamic library names from portmidi_d to portmidi to
- * be backward-compatible with programs expecting a library by
- * the old name.
- *
- * 04Oct09 Roger Dannenberg
- * - Converted to using Cmake.
- * - Renamed static and dynamic library files to portmidi_s and portmidi_d
- * - Eliminated VC9 and VC8 files (went back to simply test.vcproj, etc.,
- * use Cmake to switch from the provided VC9 files to VC8 or other)
- * - Many small changes to prepare for 64-bit architectures (but only
- * tested on 32-bit machines)
- *
- * 16Jun09 Roger Dannenberg
- * - Started using Microsoft Visual C++ Version 9 (Express). Converted
- * all *-VC9.vcproj file to *.vcproj and renamed old project files to
- * *-VC8.proj. Previously, output from VC9 went to special VC9 files,
- * that breaks any program or script looking for output in release or
- * debug files, so now both compiler version output to the same folders.
- * Now, debug version uses static linking with debug DLL runtime, and
- * release version uses static linking with statically linked runtime.
- * Converted to Inno Setup and worked on scripts to make things build
- * properly, especially pmdefaults.
- *
- * 02Jan09 Roger Dannenberg
- * - Created Java interface and wrote PmDefaults application to set
- * values for Pm_GetDefaultInputDeviceID() and
- * Pm_GetDefaultOutputDeviceID(). Other fixes.
- *
- * 19Jun08 Roger Dannenberg and Austin Sung
- * - Removed USE_DLL_FOR_CLEANUP -- Windows 2000 through Vista seem to be
- * fixed now, and can recover if MIDI ports are left open
- * - Various other minor patches
- *
- * 17Jan07 Roger Dannenberg
- * - Lots more help for Common Lisp user in pm_cl
- * - Minor fix to eliminate a compiler warning
- * - Went back to single library in OS X for both portmidi and porttime
- *
- * 16Jan07 Roger Dannenberg
- * - OOPS! fixed bug where short messages all had zero data
- * - Makefile.osx static library build now makes universal (i386 + ppc)
- * binaries
- *
- * 15Jan07 Roger Dannenberg
- * - multiple rewrites of sysex handling code to take care of
- * error-handling, embedded messages, message filtering,
- * driver bugs, and host limitations.
- * - fixed windows to use dwBufferLength rather than
- * dwBytesRecorded for long buffer output (fix by Nigel Brown)
- * - Win32 MME code always appends an extra zero to long buffer
- * output to work around a problem with earlier versions of Midi Yoke
- * - Added mm, a command line Midi Monitor to pm_test suite
- * - Revised copyright notice to match PortAudio/MIT license (requests
- * are moved out of the license proper and into a separate paragraph)
- *
- * 18Oct06 Roger Dannenberg
- * - replace FIFO in pmutil with Light Pipe-based multiprocessor-safe alg.
- * - replace FIFO in portmidi.c with PmQueue from pmutil
- *
- * 07Oct06 cpr & Roger Dannenberg
- * - overhaul of CoreMIDI input to handle running status and multiple
- * - messages per packet, with additional error detection
- * - added Leigh Smith and Rick Taube support for Common Lisp and
- * - dynamic link libraries in OSX
- * - initialize static global seq = NULL in pmlinuxalsa.c
- *
- * 05Sep06 Sebastien Frippiat
- * - check if (ALSA) seq exists before closing it in pm_linuxalsa_term()
- *
- * 05Sep06 Andreas Micheler and Cecilio
- * - fixed memory leak by freeing someo objects in pm_winmm_term()
- * - and another leak by freeing descriptors in Pm_Terminate()
- *
- * 23Aug06 RBD
- * - various minor fixes
- *
- * 04Nov05 Olivier Tristan
- * - changes to OS X to properly retrieve real device name on CoreMidi
- *
- * 19Jul05 Roger Dannenberg
- * - included pmBufferMaxSize in Pm_GetErrorText()
- *
- * 23Mar05 Torgier Strand Henriksen
- * - cleaner termination of porttime thread under Linux
- *
- * 15Nov04 Ben Allison
- * - sysex output now uses one buffer/message and reallocates buffer
- * - if needed
- * - filters expanded for many message types and channels
- * - detailed changes are as follows:
- * ------------- in pmwinmm.c --------------
- * - new #define symbol: OUTPUT_BYTES_PER_BUFFER
- * - change SYSEX_BYTES_PER_BUFFER to 1024
- * - added MIDIHDR_BUFFER_LENGTH(x) to correctly count midihdr buffer length
- * - change MIDIHDR_SIZE(x) to (MIDIHDR_BUFFER_LENGTH(x) + sizeof(MIDIHDR))
- * - change allocate_buffer to use new MIDIHDR_BUFFER_LENGTH macro
- * - new macros for MIDIHDR_SYSEX_SIZE and MIDIHDR_SYSEX_BUFFER_LENGTH
- * - similar to above, but counts appropriately for sysex messages
- * - added the following members to midiwinmm_struct for sysex data:
- * - LPMIDIHDR *sysex_buffers; ** pool of buffers for sysex data **
- * - int num_sysex_buffers; ** how many sysex buffers **
- * - int next_sysex_buffer; ** index of next sysexbuffer to send **
- * - HANDLE sysex_buffer_signal; ** to wait for free sysex buffer **
- * - duplicated allocate_buffer, alocate_buffers and get_free_output_buffer
- * - into equivalent sysex_buffer form
- * - changed winmm_in_open to initialize new midiwinmm_struct members and
- * - to use the new allocate_sysex_buffer() function instead of
- * - allocate_buffer()
- * - changed winmm_out_open to initialize new members, create sysex buffer
- * - signal, and allocate 2 sysex buffers
- * - changed winmm_out_delete to free sysex buffers and shut down the sysex
- * - buffer signal
- * - create new function resize_sysex_buffer which resizes m->hdr to the
- * - passed size, and corrects the midiwinmm_struct accordingly.
- * - changed winmm_write_byte to use new resize_sysex_buffer function,
- * - if resize fails, write current buffer to output and continue
- * - changed winmm_out_callback to use buffer_signal or sysex_buffer_signal
- * - depending on which buffer was finished
- * ------------- in portmidi.h --------------
- * - added pmBufferMaxSize to PmError to indicate that the buffer would be
- * - too large for the underlying API
- * - added additional filters
- * - added prototype, documentation, and helper macro for Pm_SetChannelMask
- * ------------- in portmidi.c --------------
- * - added pm_status_filtered() and pm_realtime_filtered() functions to
- * separate filtering logic from buffer logic in pm_read_short
- * - added Pm_SetChannelMask function
- * - added pm_channel_filtered() function
- * ------------- in pminternal.h --------------
- * - added member to PortMidiStream for channel mask
- *
- * 25May04 RBD
- * - removed support for MIDI THRU
- * - moved filtering from Pm_Read to pm_enqueue to avoid buffer ovfl
- * - extensive work on Mac OS X port, especially sysex and error handling
- *
- * 18May04 RBD
- * - removed side-effects from assert() calls. Now you can disable assert().
- * - no longer check pm_hosterror everywhere, fixing a bug where an open
- * failure could cause a write not to work on a previously opened port
- * until you call Pm_GetHostErrorText().
- * 16May04 RBD and Chris Roberts
- * - Some documentation wordsmithing in portmidi.h
- * - Dynamically allocate port descriptor structures
- * - Fixed parameter error in midiInPrepareBuffer and midiInAddBuffer.
- *
- * 09Oct03 RBD
- * - Changed Thru handling. Now the client does all the work and the client
- * must poll or read to keep thru messages flowing.
- *
- * 31May03 RBD
- * - Fixed various bugs.
- * - Added linux ALSA support with help from Clemens Ladisch
- * - Added Mac OS X support, implemented by Jon Parise, updated and
- * integrated by Andrew Zeldis and Zico Kolter
- * - Added latency program to build histogram of system latency using PortTime.
- *
- * 30Jun02 RBD Extensive rewrite of sysex handling. It works now.
- * Extensive reworking of error reporting and error text -- no
- * longer use dictionary call to delete data; instead, Pm_Open
- * and Pm_Close clean up before returning an error code, and
- * error text is saved in a system-independent location.
- * Wrote sysex.c to test sysex message handling.
- *
- * 15Jun02 BCT changes:
- * - Added pmHostError text handling.
- * - For robustness, check PortMidi stream args not NULL.
- * - Re-C-ANSI-fied code (changed many C++ comments to C style)
- * - Reorganized code in pmwinmm according to input/output functionality (made
- * cleanup handling easier to reason about)
- * - Fixed Pm_Write calls (portmidi.h says these should not return length but Pm_Error)
- * - Cleaned up memory handling (now system specific data deleted via dictionary
- * call in PortMidi, allows client to query host errors).
- * - Added explicit asserts to verify various aspects of pmwinmm implementation behaves as
- * logic implies it should. Specifically: verified callback routines not reentrant and
- * all verified status for all unchecked Win32 MMedia API calls perform successfully
- * - Moved portmidi initialization and clean-up routines into DLL to fix Win32 MMedia API
- * bug (i.e. if devices not explicitly closed, must reboot to debug application further).
- * With this change, clients no longer need explicitly call Pm_Initialize, Pm_Terminate, or
- * explicitly Pm_Close open devices when using WinMM version of PortMidi.
- *
- * 23Jan02 RBD Fixed bug in pmwinmm.c thru handling
- *
- * 21Jan02 RBD Added tests in Pm_OpenInput() and Pm_OpenOutput() to prevent
- * opening an input as output and vice versa.
- * Added comments and documentation.
- * Implemented Pm_Terminate().
- *
- */
diff --git a/portmidi/CMakeLists.txt b/portmidi/CMakeLists.txt
deleted file mode 100644
index 0107e8c..0000000
--- a/portmidi/CMakeLists.txt
+++ /dev/null
@@ -1,188 +0,0 @@
-# portmidi
-# Roger B. Dannenberg (and others)
-# Sep 2009 - 2021
-
-cmake_minimum_required(VERSION 3.21)
-# (ALSA::ALSA new in 3.12 and used in pm_common/CMakeLists.txt)
-# Some Java stuff failed on 3.17 but works with 3.20+
-
-cmake_policy(SET CMP0091 NEW) # enables MSVC_RUNTIME_LIBRARY target property
-
-# Previously, PortMidi versions were simply SVN commit version numbers.
-# Versions are now in the form x.y.z
-# Changed 1.0 to 2.0 because API is extended with virtual ports:
-set(SOVERSION "2")
-set(VERSION "2.0.4")
-
-project(portmidi VERSION "${VERSION}"
- DESCRIPTION "Cross-Platform MIDI IO")
-
-set(LIBRARY_SOVERSION "${SOVERSION}")
-set(LIBRARY_VERSION "${VERSION}")
-
-option(BUILD_SHARED_LIBS "Build shared libraries" ON)
-
-option(PM_USE_STATIC_RUNTIME
- "Use MSVC static runtime. Only applies when BUILD_SHARED_LIBS is OFF"
- ON)
-
-option(USE_SNDIO "Use sndio" OFF)
-
-# MSVCRT_DLL is used to construct the MSVC_RUNTIME_LIBRARY property
-# (see pm_common/CMakeLists.txt and pm_test/CMakeLists.txt)
-if(PM_USE_STATIC_RUNTIME AND NOT BUILD_SHARED_LIBS)
- set(MSVCRT_DLL "")
-else()
- set(MSVCRT_DLL "DLL")
-endif()
-
-# Always build with position-independent code (-fPIC)
-set(CMAKE_POSITION_INDEPENDENT_CODE ON)
-
-set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9 CACHE STRING
- "make for this OS version or higher")
-
-# PM_ACTUAL_LIB_NAME is in this scope -- see pm_common/CMakeLists.txt
-# PM_NEEDED_LIBS is in this scope -- see pm_common/CMakeLists.txt
-
-include(GNUInstallDirs)
-
-# Build Types
-# credit: http://cliutils.gitlab.io/modern-cmake/chapters/features.html
-set(DEFAULT_BUILD_TYPE "Release")
-if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
- message(STATUS
- "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.")
- set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE
- STRING "Choose the type of build." FORCE)
- # Set the possible values of build type for cmake-gui
- set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
- "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
-endif()
-
-# where to put libraries? Everything goes here in this directory
-# (or Debug or Release, depending on the OS)
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
-set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
-
-option(BUILD_JAVA_NATIVE_INTERFACE
- "build the Java PortMidi interface library" OFF)
-
-# Defines are used in both portmidi (in pm_common/) and pmjni (in pm_java),
-# so define them here to be inherited by both libraries.
-#
-# PortMidi software architecture supports multiple system API's to lower-
-# level MIDI drivers, e.g. PMNULL (no drivers), Jack (but not supported yet),
-# and sndio (BSD, not supported yet). Interfaces are selected by defining,
-# e.g., PMALSA. (In principle, we should require PMCOREMIDI (for macOS)
-# and PMWINMM (for windows), but these are assumed.
-#
-if(APPLE OR WIN32)
-else(APPLE_OR_WIN32)
- set(LINUX_DEFINES "PMALSA" CACHE STRING "must define either PMALSA or PMNULL")
- add_compile_definitions(${LINUX_DEFINES})
-endif(APPLE OR WIN32)
-
-if(BUILD_JAVA_NATIVE_INTERFACE)
- message(WARNING
- "Java API and PmDefaults program updated 2021, but support has "
- "been discontinued. If you need/use this, let developers know.")
- set(PMJNI_IF_EXISTS "pmjni") # used by INSTALL below
-else(BUILD_JAVA_NATIVE_INTERFACE)
- set(PMJNI_IF_EXISTS "") # used by INSTALL below
-endif(BUILD_JAVA_NATIVE_INTERFACE)
-
-
-# Something like this might help if you need to build for a specific cpu type:
-# set(CMAKE_OSX_ARCHITECTURES x86_64 CACHE STRING
-# "change to support other architectures" FORCE)
-
-include_directories(pm_common porttime)
-add_subdirectory(pm_common)
-
-option(BUILD_PORTMIDI_TESTS
- "Build test programs, including midi monitor (mm)" OFF)
-if(BUILD_PORTMIDI_TESTS)
- add_subdirectory(pm_test)
-endif(BUILD_PORTMIDI_TESTS)
-
-# See note above about Java support (probably) discontinued
-if(BUILD_JAVA_NATIVE_INTERFACE)
- add_subdirectory(pm_java)
-endif(BUILD_JAVA_NATIVE_INTERFACE)
-
-# Install the libraries and headers (Linux and Mac OS X command line)
-INSTALL(TARGETS portmidi ${PMJNI_IF_EXISTS}
- EXPORT PortMidiTargets
- LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
- ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
- RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
- INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
-
-INSTALL(FILES
- pm_common/portmidi.h
- pm_common/pmutil.h
- porttime/porttime.h
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
-
-# pkgconfig - generate pc file
-# See https://cmake.org/cmake/help/latest/command/configure_file.html
-if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
- set(PKGCONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
-else()
- set(PKGCONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
-endif()
-if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
- set(PKGCONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
-else()
- set(PKGCONFIG_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
-endif()
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/packaging/portmidi.pc.in
- ${CMAKE_CURRENT_BINARY_DIR}/packaging/portmidi.pc @ONLY)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/packaging/portmidi.pc
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
-
-# CMake config
-set(PORTMIDI_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/PortMidi")
-install(
- EXPORT PortMidiTargets
- FILE PortMidiTargets.cmake
- NAMESPACE PortMidi::
- DESTINATION "${PORTMIDI_INSTALL_CMAKEDIR}"
-)
-include(CMakePackageConfigHelpers)
-configure_package_config_file(packaging/PortMidiConfig.cmake.in
- "${CMAKE_CURRENT_BINARY_DIR}/packaging/PortMidiConfig.cmake"
- INSTALL_DESTINATION "${PORTMIDI_INSTALL_CMAKEDIR}"
-)
-write_basic_package_version_file(
- "${CMAKE_CURRENT_BINARY_DIR}/packaging/PortMidiConfigVersion.cmake"
- VERSION "${CMAKE_PROJECT_VERSION}"
- COMPATIBILITY SameMajorVersion
-)
-install(
- FILES
- "${CMAKE_CURRENT_BINARY_DIR}/packaging/PortMidiConfig.cmake"
- "${CMAKE_CURRENT_BINARY_DIR}/packaging/PortMidiConfigVersion.cmake"
- DESTINATION "${PORTMIDI_INSTALL_CMAKEDIR}"
-)
-
-
-
-
-# Finding out what CMake is doing is really hard, e.g. COMPILE_FLAGS
-# does not include COMPILE_OPTIONS or COMPILE_DEFINTIONS. Thus, the
-# following report is probably not complete...
-MESSAGE(STATUS "PortMidi Library name: " ${PM_ACTUAL_LIB_NAME})
-MESSAGE(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
-MESSAGE(STATUS "Library Type: " ${LIB_TYPE})
-MESSAGE(STATUS "Compiler flags: " ${CMAKE_CXX_COMPILE_FLAGS})
-get_directory_property(prop COMPILE_DEFINITIONS)
-MESSAGE(STATUS "Compile definitions: " ${prop})
-get_directory_property(prop COMPILE_OPTIONS)
-MESSAGE(STATUS "Compile options: " ${prop})
-MESSAGE(STATUS "Compiler cxx debug flags: " ${CMAKE_CXX_FLAGS_DEBUG})
-MESSAGE(STATUS "Compiler cxx release flags: " ${CMAKE_CXX_FLAGS_RELEASE})
-MESSAGE(STATUS "Compiler cxx min size flags: " ${CMAKE_CXX_FLAGS_MINSIZEREL})
-MESSAGE(STATUS "Compiler cxx flags: " ${CMAKE_CXX_FLAGS})
-
diff --git a/portmidi/Doxyfile b/portmidi/Doxyfile
deleted file mode 100644
index 95e3708..0000000
--- a/portmidi/Doxyfile
+++ /dev/null
@@ -1,2682 +0,0 @@
-# Doxyfile 1.9.2
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the configuration
-# file that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME = PortMidi
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER =
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF = "Cross-platform MIDI IO library"
-
-# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
-# in the documentation. The maximum height of the logo should not exceed 55
-# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
-# the logo to the output directory.
-
-PROJECT_LOGO = portmusic_logo.png
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
-OUTPUT_DIRECTORY = ../github-portmidi-portmidi_docs
-
-# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS = NO
-
-# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
-# characters to appear in the names of generated files. If set to NO, non-ASCII
-# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
-# U+3044.
-# The default value is: NO.
-
-ALLOW_UNICODE_NAMES = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
-# description of a member or function before the detailed description
-#
-# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF = "The $name class" \
- "The $name widget" \
- "The $name file" \
- is \
- provides \
- specifies \
- contains \
- represents \
- a \
- an \
- the
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB = NO
-
-# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES = YES
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF = YES
-
-# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
-# such as
-# /***************
-# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
-# Javadoc-style will behave just like regular comments and it will not be
-# interpreted by doxygen.
-# The default value is: NO.
-
-JAVADOC_BANNER = NO
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# By default Python docstrings are displayed as preformatted text and doxygen's
-# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
-# doxygen's special commands can be used and the contents of the docstring
-# documentation blocks is shown as doxygen documentation.
-# The default value is: YES.
-
-PYTHON_DOCSTRING = YES
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: YES.
-
-INHERIT_DOCS = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
-# page for each member. If set to NO, the documentation of a member will be part
-# of the file/class/namespace that contains it.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE = 4
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:^^"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". Note that you cannot put \n's in the value part of an alias
-# to insert newlines (in the resulting output). You can put ^^ in the value part
-# of an alias to insert a newline as if a physical newline was in the original
-# file. When you need a literal { or } or , in the value part of an alias you
-# have to escape them by means of a backslash (\), this can lead to conflicts
-# with the commands \{ and \} for these it is advised to use the version @{ and
-# @} or use a double escape (\\{ and \\})
-
-ALIASES =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C = NO
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL = NO
-
-# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
-# sources only. Doxygen will then generate output that is more tailored for that
-# language. For instance, namespaces will be presented as modules, types will be
-# separated into more groups, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_SLICE = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
-# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
-# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
-# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
-# tries to guess whether the code is fixed or free formatted code, this is the
-# default for Fortran type files). For instance to make doxygen treat .inc files
-# as Fortran files (default is PHP), and .f files as C (default is Fortran),
-# use: inc=Fortran f=C.
-#
-# Note: For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen. When specifying no_extension you should add
-# * to the FILE_PATTERNS.
-#
-# Note see also the list of default file extension mappings.
-
-EXTENSION_MAPPING =
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See https://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: YES.
-
-MARKDOWN_SUPPORT = YES
-
-# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
-# to that level are automatically included in the table of contents, even if
-# they do not have an id attribute.
-# Note: This feature currently applies only to Markdown headings.
-# Minimum value: 0, maximum value: 99, default value: 5.
-# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
-
-TOC_INCLUDE_HEADINGS = 5
-
-# When enabled doxygen tries to link words that correspond to documented
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by putting a % sign in front of the word or
-# globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# If one adds a struct or class to a group and this option is enabled, then also
-# any nested class or struct is added to the same group. By default this option
-# is disabled and one has to add nested compounds explicitly via \ingroup.
-# The default value is: NO.
-
-GROUP_NESTED_COMPOUNDS = NO
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS = NO
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT = YES
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE = 0
-
-# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
-# during processing. When set to 0 doxygen will based this on the number of
-# cores available in the system. You can set it explicitly to a value larger
-# than 0 to get more control over the balance between CPU load and processing
-# speed. At this moment only the input processing can be done using multiple
-# threads. Since this is still an experimental feature the default is set to 1,
-# which effectively disables parallel processing. Please report any issues you
-# encounter. Generating dot graphs in parallel is controlled by the
-# DOT_NUM_THREADS setting.
-# Minimum value: 0, maximum value: 32, default value: 1.
-
-NUM_PROC_THREADS = 1
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
-EXTRACT_ALL = NO
-
-# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
-# methods of a class will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIV_VIRTUAL = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE = NO
-
-# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
-EXTRACT_STATIC = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO,
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. If set to YES, local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO, only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES = NO
-
-# If this flag is set to YES, the name of an unnamed parameter in a declaration
-# will be determined by the corresponding definition. By default unnamed
-# parameters remain unnamed in the output.
-# The default value is: YES.
-
-RESOLVE_UNNAMED_PARAMS = YES
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO, these classes will be included in the various overviews. This option
-# has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# declarations. If set to NO, these declarations will be included in the
-# documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO, these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS = NO
-
-# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
-# able to match the capabilities of the underlying filesystem. In case the
-# filesystem is case sensitive (i.e. it supports files in the same directory
-# whose names only differ in casing), the option must be set to YES to properly
-# deal with such files in case they appear in the input. For filesystems that
-# are not case sensitive the option should be be set to NO to properly deal with
-# output files written for symbols that only differ in casing, such as for two
-# classes, one named CLASS and the other named Class, and to also support
-# references to files without having to specify the exact matching casing. On
-# Windows (including Cygwin) and MacOS, users should typically set this option
-# to NO, whereas on Linux or other Unix flavors it should typically be set to
-# YES.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES, the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES = YES
-
-# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
-# append additional text to a page's title, such as Class Reference. If set to
-# YES the compound reference will be hidden.
-# The default value is: NO.
-
-HIDE_COMPOUND_REFERENCE= NO
-
-# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
-# will show which file needs to be included to use the class.
-# The default value is: YES.
-
-SHOW_HEADERFILE = YES
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: NO.
-
-STRICT_PROTO_MATCHING = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
-# list. This list is created by putting \todo commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
-# list. This list is created by putting \test commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES, the
-# list will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file. See also section "Changing the
-# layout of pages" for information.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE =
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. See also \cite for info how to create references.
-
-CITE_BIB_FILES =
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED = YES
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as documenting some parameters in
-# a documented function twice, or documenting parameters that don't exist or
-# using markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR = YES
-
-# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
-# function parameter documentation. If set to NO, doxygen will accept that some
-# parameters have no documentation without warning.
-# The default value is: YES.
-
-WARN_IF_INCOMPLETE_DOC = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO, doxygen will only warn about wrong parameter
-# documentation, but not about the absence of documentation. If EXTRACT_ALL is
-# set to YES then this flag will automatically be disabled. See also
-# WARN_IF_INCOMPLETE_DOC
-# The default value is: NO.
-
-WARN_NO_PARAMDOC = NO
-
-# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
-# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
-# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
-# at the end of the doxygen process doxygen will return with a non-zero status.
-# Possible values are: NO, YES and FAIL_ON_WARNINGS.
-# The default value is: NO.
-
-WARN_AS_ERROR = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
-# Note: If this tag is empty the current directory is searched.
-
-INPUT =pm_common porttime/porttime.h pm_common/pmutil.h
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see:
-# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# read by doxygen.
-#
-# Note the list of default checked file patterns might differ from the list of
-# default file extension mappings.
-#
-# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
-# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
-# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
-# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
-# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
-# *.vhdl, *.ucf, *.qsf and *.ice.
-
-FILE_PATTERNS = *.c \
- *.cc \
- *.cxx \
- *.cpp \
- *.c++ \
- *.java \
- *.ii \
- *.ixx \
- *.ipp \
- *.i++ \
- *.inl \
- *.idl \
- *.ddl \
- *.odl \
- *.h \
- *.hh \
- *.hxx \
- *.hpp \
- *.h++ \
- *.l \
- *.cs \
- *.d \
- *.php \
- *.php4 \
- *.php5 \
- *.phtml \
- *.inc \
- *.m \
- *.markdown \
- *.md \
- *.mm \
- *.dox \
- *.py \
- *.pyw \
- *.f90 \
- *.f95 \
- *.f03 \
- *.f08 \
- *.f18 \
- *.f \
- *.for \
- *.vhd \
- *.vhdl \
- *.ucf \
- *.qsf \
- *.ice
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS = TRUE, FALSE, PMEXPORT
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS = *
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# properly processed by doxygen.
-
-INPUT_FILTER =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-#
-# Note that for custom extensions or not directly supported extensions you also
-# need to set EXTENSION_MAPPING for the extension otherwise the files are not
-# properly processed by doxygen.
-
-FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS =
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# entity all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see https://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS = YES
-
-# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
-# clang parser (see:
-# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
-# performance. This can be particularly helpful with template rich C++ code for
-# which doxygen's built-in parser lacks the necessary type information.
-# Note: The availability of this option depends on whether or not doxygen was
-# generated with the -Duse_libclang=ON option for CMake.
-# The default value is: NO.
-
-CLANG_ASSISTED_PARSING = NO
-
-# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
-# tag is set to YES then doxygen will add the directory of each input to the
-# include path.
-# The default value is: YES.
-# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
-
-CLANG_ADD_INC_PATHS = YES
-
-# If clang assisted parsing is enabled you can provide the compiler with command
-# line options that you would normally use when invoking the compiler. Note that
-# the include paths will already be set by doxygen for the files and directories
-# specified with INPUT and INCLUDE_PATH.
-# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
-
-CLANG_OPTIONS =
-
-# If clang assisted parsing is enabled you can provide the clang parser with the
-# path to the directory containing a file called compile_commands.json. This
-# file is the compilation database (see:
-# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
-# options used when the source files were built. This is equivalent to
-# specifying the -p option to a clang tool, such as clang-check. These options
-# will then be passed to the parser. Any options specified with CLANG_OPTIONS
-# will be added as well.
-# Note: The availability of this option depends on whether or not doxygen was
-# generated with the -Duse_libclang=ON option for CMake.
-
-CLANG_DATABASE_PATH =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX = YES
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT = docs
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER =
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET =
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# cascading style sheets that are included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefore more robust against future updates.
-# Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the style sheet and background images according to
-# this color. Hue is specified as an angle on a color-wheel, see
-# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
-# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use gray-scales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to YES can help to show when doxygen was last run and thus if the
-# documentation is up to date.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP = NO
-
-# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
-# documentation will contain a main index with vertical navigation menus that
-# are dynamically created via JavaScript. If disabled, the navigation index will
-# consists of multiple levels of tabs that are statically embedded in every HTML
-# page. Disable this option to support browsers that do not have JavaScript,
-# like the Qt help browser.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_MENUS = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see:
-# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
-# create a documentation set, doxygen will generate a Makefile in the HTML
-# output directory. Running make will produce the docset in that directory and
-# running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
-# genXcode/_index.html for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID = org.doxygen.Project
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# on Windows. In the beginning of 2021 Microsoft took the original page, with
-# a.o. the download links, offline the HTML help workshop was already many years
-# in maintenance mode). You can download the HTML help workshop from the web
-# archives at Installation executable (see:
-# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
-# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP = NO
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE =
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler (hhc.exe). If non-empty,
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION =
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated
-# (YES) or that it should be included in the main .chm file (NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI = NO
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING =
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated
-# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
-# enables the Previous and Next buttons.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see:
-# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see:
-# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see:
-# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME =
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see:
-# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS =
-
-# The QHG_LOCATION tag can be used to specify the location (absolute path
-# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
-# run qhelpgenerator on the generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID = org.doxygen.Project
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine tune the look of the index (see "Fine-tuning the output"). As an
-# example, the default style sheet generated by doxygen has an example that
-# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
-# Since the tree basically has the same information as the tab index, you could
-# consider setting DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW = YES
-
-# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
-# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
-# area (value NO) or if it should extend to the full height of the window (value
-# YES). Setting this to YES gives a layout similar to
-# https://docs.readthedocs.io with more room for contents, but less room for the
-# project logo, title, and description. If either GENERATOR_TREEVIEW or
-# DISABLE_INDEX is set to NO, this option has no effect.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FULL_SIDEBAR = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH = 250
-
-# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW = NO
-
-# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
-# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
-# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
-# the HTML output. These images will generally look nicer at scaled resolutions.
-# Possible values are: png (the default) and svg (looks nicer but requires the
-# pdf2svg or inkscape tool).
-# The default value is: png.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FORMULA_FORMAT = png
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE = 10
-
-# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT = YES
-
-# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
-# to create new LaTeX commands to be used in formulas as building blocks. See
-# the section "Including formulas" for details.
-
-FORMULA_MACROFILE =
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# https://www.mathjax.org) which uses client side JavaScript for the rendering
-# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX = NO
-
-# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
-# Note that the different versions of MathJax have different requirements with
-# regards to the different settings, so it is possible that also other MathJax
-# settings have to be changed when switching between the different MathJax
-# versions.
-# Possible values are: MathJax_2 and MathJax_3.
-# The default value is: MathJax_2.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_VERSION = MathJax_2
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. For more details about the output format see MathJax
-# version 2 (see:
-# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
-# (see:
-# http://docs.mathjax.org/en/latest/web/components/output.html).
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility. This is the name for Mathjax version 2, for MathJax version 3
-# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
-# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
-# is the name for Mathjax version 3, for MathJax version 2 this will be
-# translated into HTML-CSS) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from https://www.mathjax.org before deployment. The default value is:
-# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
-# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH =
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html
-# #tex-and-latex-extensions):
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# For example for MathJax version 3 (see
-# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
-# MATHJAX_EXTENSIONS = ams
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS =
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see:
-# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using JavaScript. There
-# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
-# setting. When disabled, doxygen will generate a PHP script for searching and
-# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
-# and searching needs to be provided by external tools. See the section
-# "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see:
-# https://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see:
-# https://xapian.org/). See the section "External Indexing and Searching" for
-# details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL =
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID =
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when not enabling USE_PDFLATEX the default is latex when enabling
-# USE_PDFLATEX the default is pdflatex and when in the later case latex is
-# chosen this is overwritten by pdflatex. For specific output languages the
-# default can have been set differently, this depends on the implementation of
-# the output language.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME =
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# Note: This tag is used in the Makefile / make.bat.
-# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
-# (.tex).
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
-# generate index for LaTeX. In case there is no backslash (\) as first character
-# it will be automatically added in the LaTeX code.
-# Note: This tag is used in the generated output file (.tex).
-# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
-# The default value is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_MAKEINDEX_CMD = makeindex
-
-# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE = a4
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. The package can be specified just
-# by its name or with the correct syntax as to be used with the LaTeX
-# \usepackage command. To get the times font for instance you can specify :
-# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
-# To use the option intlimits with the amsmath package you can specify:
-# EXTRA_PACKAGES=[intlimits]{amsmath}
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
-# the generated LaTeX document. The header should contain everything until the
-# first chapter. If it is left blank doxygen will generate a standard header. It
-# is highly recommended to start with a default header using
-# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
-# and then modify the file new_header.tex. See also section "Doxygen usage" for
-# information on how to generate the default header that doxygen normally uses.
-#
-# Note: Only use a user-defined header if you know what you are doing!
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. The following
-# commands have a special meaning inside the header (and footer): For a
-# description of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER =
-
-# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
-# the generated LaTeX document. The footer should contain everything after the
-# last chapter. If it is left blank doxygen will generate a standard footer. See
-# LATEX_HEADER for more information on how to generate a default footer and what
-# special commands can be used inside the footer. See also section "Doxygen
-# usage" for information on how to generate the default footer that doxygen
-# normally uses. Note: Only use a user-defined footer if you know what you are
-# doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER =
-
-# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# LaTeX style sheets that are included after the standard style sheets created
-# by doxygen. Using this option one can overrule certain style aspects. Doxygen
-# will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list).
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_STYLESHEET =
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS = YES
-
-# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
-# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
-# files. Set this option to YES, to get a higher quality PDF documentation.
-#
-# See also section LATEX_CMD_NAME for selecting the engine.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BIB_STYLE = plain
-
-# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
-# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_TIMESTAMP = NO
-
-# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
-# path from which the emoji images will be read. If a relative path is entered,
-# it will be relative to the LATEX_OUTPUT directory. If left blank the
-# LATEX_OUTPUT directory will be used.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EMOJI_DIRECTORY =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# configuration file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's configuration file. A template extensions file can be
-# generated using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION = .3
-
-# The MAN_SUBDIR tag determines the name of the directory created within
-# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
-# MAN_EXTENSION with the initial . removed.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_SUBDIR =
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT = xml
-
-# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING = YES
-
-# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
-# namespace members in file scope as well, matching the HTML output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_NS_MEMB_FILE_SCOPE = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT = docbook
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
-# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
-# the structure of the code including all documentation. Note that this feature
-# is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to Sqlite3 output
-#---------------------------------------------------------------------------
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO, the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
-# in the source code. If set to NO, only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES, the include files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro definition that overrules the
-# definition found in the source code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all references to function-like macros that are alone on a line, have
-# an all uppercase name, and do not end with a semicolon. Such function macros
-# are typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have a unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
-# the class index. If set to NO, only the inherited external classes will be
-# listed.
-# The default value is: NO.
-
-ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS = YES
-
-# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS = NO
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH =
-
-# If set to YES the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
-HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: NO.
-
-HAVE_DOT = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS = 0
-
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH =
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH = YES
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag UML_LOOK is set to YES.
-
-UML_LIMIT_NUM_FIELDS = 10
-
-# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
-# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
-# tag is set to YES, doxygen will add type and arguments for attributes and
-# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
-# will not generate fields with class member information in the UML graphs. The
-# class diagrams will look similar to the default class diagrams but using UML
-# notation for the relationships.
-# Possible values are: NO, YES and NONE.
-# The default value is: NO.
-# This tag requires that the tag UML_LOOK is set to YES.
-
-DOT_UML_DETAILS = NO
-
-# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
-# to display on a single line. If the actual line length exceeds this threshold
-# significantly it will wrapped across multiple lines. Some heuristics are apply
-# to avoid ugly line breaks.
-# Minimum value: 0, maximum value: 1000, default value: 17.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_WRAP_THRESHOLD = 17
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH = YES
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command. Disabling a call graph can be
-# accomplished by means of the command \hidecallgraph.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH = NO
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command. Disabling a caller graph can be
-# accomplished by means of the command \hidecallergraph.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH = NO
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY = YES
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. For an explanation of the image formats see the section
-# output formats in the documentation of the dot tool (Graphviz (see:
-# http://www.graphviz.org/)).
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
-# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
-# png:gdiplus:gdiplus.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS =
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-DIAFILE_DIRS =
-
-# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
-# path where java can find the plantuml.jar file. If left blank, it is assumed
-# PlantUML is not used or called during a preprocessing step. Doxygen will
-# generate a warning when it encounters a \startuml command in this case and
-# will not generate output for the diagram.
-
-PLANTUML_JAR_PATH =
-
-# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
-# configuration file for plantuml.
-
-PLANTUML_CFG_FILE =
-
-# When using plantuml, the specified paths are searched for files specified by
-# the !include statement in a plantuml block.
-
-PLANTUML_INCLUDE_PATH =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS = NO
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
-# files that are used to generate the various graphs.
-#
-# Note: This setting is not only used for dot files but also for msc temporary
-# files.
-# The default value is: YES.
-
-DOT_CLEANUP = YES
diff --git a/portmidi/README.md b/portmidi/README.md
deleted file mode 100644
index 3f0463c..0000000
--- a/portmidi/README.md
+++ /dev/null
@@ -1,128 +0,0 @@
-# PortMidi - Cross-Platform MIDI IO
-
-This is the canonical release of PortMidi.
-
-See other repositories within [PortMidi](https://github.com/PortMidi)
-for related code and bindings (although currently, not much is here).
-
-## [Full C API documentation is here.](https://portmidi.github.io/portmidi_docs/)
-
-## Compiling and Using PortMidi
-
-Use CMake (or ccmake) to create a Makefile for Linux/BSD or a
-project file for Xcode or MS Visual Studio. Use make or an IDE to compile:
-```
-sudo apt install libasound2-dev # on Linux, you need ALSA
-cd portmidi # start in the top-level portmidi directory
-ccmake . # set any options interactively, type c to configure
- # type g to generate a Makefile or IDE project
- # type q to quit
- # (alternatively, run the CMake GUI and use
- # Configure and Generate buttons to build IDE project)
-make # compile sources and build PortMidi library
- # (alternatively, open project file with your IDE)
-sudo make install # if you want to install to your system
-```
-
-## Installation
-
-My advice is to build PortMidi and statically link it to your
-application. This gives you more control over versions. However,
-installing PortMidi to your system is preferred by some, and the
-following should do it:
-```
-cmake .
-make
-sudo make install
-```
-
-## Language Bindings
-
-Here is a guide to some other projects using PortMidi. There is not
-much coordination, so let us know if there are better or alternative
-bindings for these and other languages:
-
-- Python: Various libraries and packages exist; search and ye shall
- find. If you wouldn't like to do research, check out [mido](https://mido.readthedocs.io/en/stable/)
-- [SML](https://github.com/jh-midi/portmidi-sml2)
-- [OCaml](https://ocaml.org/p/portmidi/0.1)
-- [Haskell](https://hackage.haskell.org/package/PortMidi)
-- [Erlang](https://hexdocs.pm/portmidi/PortMidi.html)
-- [Julia](https://github.com/SteffenPL/PortMidi.jl)
-- [C#](https://github.com/net-core-audio/portmidi)
-- [Rust](https://musitdev.github.io/portmidi-rs/)
-- [Go](https://github.com/rakyll/portmidi)
-- [Odin](https://pkg.odin-lang.org/vendor/portmidi/)
-- [Serpent](https://sourceforge.net/projects/serpent/) - a real-time
- Python-like language has PortMidi built-in, a MIDI-timestamp-aware
- scheduler, and GUI support for device selection.
-- [Pd (Pure Data)](https://puredata.info/) uses PortMidi.
-
-
-## What's New?
-
-(Not so new, but significant:) Support for the **PmDefaults** program,
-which enabled a graphical interface to select default MIDI devices,
-has been removed for lack of interest. This allowed us to also remove
-C code to read and parse Java preference files on various systems,
-simplifying the library. **PmDefaults** allowed simple command-line
-programs to use `Pm_DefaultInputDeviceID()` and
-`Pm_DefaultOutputDeviceID()` rather than creating device selection
-interfaces. Now, you should either pass devices on the command line or
-create your own selection interface when building a GUI
-application. (See pm_tests for examples.) `Pm_DefaultInputDeviceID()`
-and `Pm_DefaultOutputDeviceID()` now return a valid device if
-possible, but they may not actually reflect any user preference.
-
-Haiku support in a minimal implementation. See TODO's in source.
-
-sndio is also minimally supported, allowing basic PortMidi functions
-in OpenBSD, FreeBSD, and NetBSD by setting USE_SNDIO for CMake, but
-not delayed/timestamped output and virtual devices.
-
-# Other Repositories
-
-PortMidi used to be part of the PortMedia suite, but this repo has
-been reduced to mostly just C/C++ code for PortMidi. You will find
-some other repositories in this PortMidi project set up for language
-bindings (volunteers and contributors are invited!). Other code
-removed from previous releases of PortMedia include:
-
-## PortSMF
-
-A Standard MIDI File (SMF) (and more) library is in the [portsmf
-repository](https://github.com/rbdannenberg/portsmf).
-
-PortSMF is a library for reading/writing/editing Standard MIDI
-Files. It is actually much more, with a general representation of
-events and updates with properties consisting of attributes and typed
-values. Familiar properties of pitch, time, duration, and channel are
-built into events and updates to make them faster to access and more
-compact.
-
-To my knowledge, PortSMF has the most complete and useful handling of
-MIDI tempo tracks. E.g., you can edit notes according to either beat
-or time, and you can edit tempo tracks, for example, flattening the
-tempo while preserving the beat alignment, preserving the real time
-while changing the tempo or stretching the tempo over some interval.
-
-In addition to Standard MIDI Files, PortSMF supports an ASCII
-representation called Allegro. PortSMF and Allegro are used for
-Audacity Note Tracks.
-
-## scorealign
-
-Scorealign used to be part of the PortMedia suite. It is now at the
-[scorealign repository](https://github.com/rbdannenberg/scorealign).
-
-Scorealign aligns audio-to-audio, audio-to-MIDI or MIDI-to-MIDI using
-dynamic time warping (DTW) of a computed chromagram
-representation. There are some added smoothing tricks to improve
-performance. This library is written in C and runs substantially
-faster than most other implementations, especially those written in
-MATLAB, due to the core DTW algorithm. Users should be warned that
-while chromagrams are robust features for alignment, they achieve
-robustness by operating at fairly high granularity, e.g., durations of
-around 100ms, which limits time precision. Other more recent
-algorithms can doubtless do better, but be cautious of claims, since
-it all depends on what assumptions you can make about the music.
diff --git a/portmidi/README.txt b/portmidi/README.txt
deleted file mode 100755
index e09aa2e..0000000
--- a/portmidi/README.txt
+++ /dev/null
@@ -1,88 +0,0 @@
-README for PortMidi
-
-Roger B. Dannenberg
-
-Documentation for PortMidi is found in pm_common/portmidi.h.
-Documentation in HTML is available at portmidi.github.io/portmidi_docs/
-
-Additional documentation:
- - README.md (overview, how to build, what's new)
- - Windows: see pm_win/README_WIN.txt and pm_win/debugging_dlls.txt
- - Linux: see pm_linux/README_LINUX.txt
- - Mac OSX: see pm_mac/README_MAC.txt
- - Other Languages: look for other repos at github.com/PortMidi,
- and search README.md for pointers to other projects.
-
----------- some notes on the design of PortMidi ----------
-
-POINTERS VS DEVICE NUMBERS
-
-When you open a MIDI port, PortMidi allocates a structure to
-maintain the state of the open device. Since every device is
-also listed in a table, you might think it would be simpler to
-use the table index rather than a pointer to identify a device.
-This would also help with error checking (it's hard to make
-sure a pointer is valid). PortMidi's design parallels that of
-PortAudio.
-
-ERROR HANDLING
-
-Error handling turned out to be much more complicated than expected.
-PortMidi functions return error codes that the caller can check.
-In addition, errors may occur asynchronously due to MIDI input.
-However, for Windows, there are virtually no errors that can
-occur if the code is correct and not passing bogus values. One
-exception is an error that the system is out of memory, but my
-guess is that one is unlikely to recover gracefully from that.
-Therefore, all errors in callbacks are guarded by assert(), which
-means not guarded at all in release configurations.
-
-Ordinarily, the caller checks for an error code. If the error is
-system-dependent, pmHostError is returned and the caller can
-call Pm_GetHostErrorText to get a text description of the error.
-
-Host error codes are system-specific and are recorded in the
-system-specific data allocated for each open MIDI port.
-However, if an error occurs on open or close,
-we cannot store the error with the device because there will be
-no device data (assuming PortMidi cleans up after devices that
-are not open). For open and close, we will convert the error
-to text, copy it to a global string, and set pm_hosterror, a
-global flag.
-
-Similarly, whenever a Read or Write operation returns pmHostError,
-the corresponding error string is copied to a global string
-and pm_hosterror is set. This makes getting error strings
-simple and uniform, although it does cost a string copy and some
-overhead even if the user does not want to look at the error data.
-
-The system-specific Read, Write, Poll, etc. implementations should
-check for asynchronous errors and return immediately if one is
-found so that these get reported. This happens in the Mac OS X
-code, where lots of things are happening in callbacks, but again,
-in Windows, there are no error codes recorded in callbacks.
-
-DEBUGGING
-
-If you are building a console application for research, we suggest
-compiling with the option PM_CHECK_ERRORS. This will insert a
-check for error return values at the end of each PortMidi
-function. If an error is encountered, a text message is printed
-using printf(), the user is asked to type ENTER, and then exit(-1)
-is called to clean up and terminate the program.
-
-You should not use PM_CHECK_ERRORS if printf() does not work
-(e.g. this is not a console application under Windows, or there
-is no visible console on some other OS), and you should not use
-PM_CHECK_ERRORS if you intend to recover from errors rather than
-abruptly terminate the program.
-
-The Windows version (and perhaps others) also offers a DEBUG
-compile-time option. See README_WIN.txt.
-
-RELEASE
-
-To make a new release, update VERSION variable in CMakeLists.txt.
-
-Update CHANGELOG.txt. What's new?
-
diff --git a/portmidi/license.txt b/portmidi/license.txt
deleted file mode 100644
index c757b37..0000000
--- a/portmidi/license.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * PortMidi Portable Real-Time MIDI Library
- *
- * license.txt -- a copy of the PortMidi copyright notice and license information
- *
- * Latest version available at: http://sourceforge.net/projects/portmedia
- *
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- * Copyright (c) 2001-2009 Roger B. Dannenberg
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS 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.
- */
-
-/*
- * The text above constitutes the entire PortMidi license; however,
- * the PortMusic community also makes the following non-binding requests:
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version. It is also
- * requested that these non-binding requests be included along with the
- * license above.
- */
diff --git a/portmidi/packaging/PortMidiConfig.cmake.in b/portmidi/packaging/PortMidiConfig.cmake.in
deleted file mode 100644
index 0d24f4d..0000000
--- a/portmidi/packaging/PortMidiConfig.cmake.in
+++ /dev/null
@@ -1,15 +0,0 @@
-@PACKAGE_INIT@
-
-include(CMakeFindDependencyMacro)
-if(UNIX AND NOT APPLE AND NOT HAIKU AND (@LINUX_DEFINES@ MATCHES ".*PMALSA.*"))
- find_dependency(ALSA)
-endif()
-
-if(NOT WIN32)
- set(THREADS_PREFER_PTHREAD_FLAG ON)
- find_package(Threads REQUIRED)
-endif()
-
-include("${CMAKE_CURRENT_LIST_DIR}/PortMidiTargets.cmake")
-
-check_required_components(PortMidi)
diff --git a/portmidi/packaging/portmidi.pc.in b/portmidi/packaging/portmidi.pc.in
deleted file mode 100644
index e9d929c..0000000
--- a/portmidi/packaging/portmidi.pc.in
+++ /dev/null
@@ -1,11 +0,0 @@
-prefix=@CMAKE_INSTALL_PREFIX@
-exec_prefix=${prefix}
-libdir=@PKGCONFIG_LIBDIR@
-includedir=@PKGCONFIG_INCLUDEDIR@
-
-Name: @CMAKE_PROJECT_NAME@
-Description: @CMAKE_PROJECT_DESCRIPTION@
-Version: @CMAKE_PROJECT_VERSION@
-Cflags: -I${includedir}
-Libs: -L${libdir} -l@CMAKE_PROJECT_NAME@
-Requires.private: @PKGCONFIG_REQUIRES_PRIVATE@
diff --git a/portmidi/pm_common/CMakeLists.txt b/portmidi/pm_common/CMakeLists.txt
deleted file mode 100644
index 1ad54ad..0000000
--- a/portmidi/pm_common/CMakeLists.txt
+++ /dev/null
@@ -1,167 +0,0 @@
-# pm_common/CMakeLists.txt -- how to build portmidi library
-
-# creates the portmidi library
-# exports PM_NEEDED_LIBS to parent. It seems that PM_NEEDED_LIBS for
-# Linux should include Thread::Thread and ALSA::ALSA, but these
-# are not visible in other CMake files, even though the portmidi
-# target is. Therefore, Thread::Thread is replaced by
-# CMAKE_THREAD_LIBS_INIT and ALSA::ALSA is replaced by ALSA_LIBRARIES.
-# Is there a better way to do this? Maybe this whole file should be
-# at the parent level.
-
-# Support alternative name for static libraries to avoid confusion.
-# (In particular, Xcode has automatically converted portmidi.a to
-# portmidi.dylib without warning, so using portmidi-static.a eliminates
-# this possibility, but default for all libs is "portmidi"):
-set(PM_STATIC_LIB_NAME "portmidi" CACHE STRING
- "For static builds, the PortMidi library name, e.g. portmidi-static.
- Default is portmidi")
-set(PM_ACTUAL_LIB_NAME "portmidi")
-if(NOT BUILD_SHARED_LIBS)
- set(PM_ACTUAL_LIB_NAME ${PM_STATIC_LIB_NAME})
-endif()
-
-# set the build directory for libportmidi.a to be in portmidi, not in
-# portmidi/pm_common. Must be done here BEFORE add_library below.
-if(APPLE OR WIN32)
- set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
- # set the build directory for .dylib libraries
- set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
- set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
-endif(APPLE OR WIN32)
-
-# we need full paths to sources because they are shared with other targets
-# (in particular pmjni). Set PMDIR to the top-level portmidi directory:
-get_filename_component(PMDIR ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
-set(PM_LIB_PUBLIC_SRC ${PMDIR}/pm_common/portmidi.c
- ${PMDIR}/pm_common/pmutil.c
- ${PMDIR}/porttime/porttime.c)
-add_library(portmidi ${PM_LIB_PUBLIC_SRC})
-
-# MSVCRT_DLL is "DLL" for shared runtime library, and "" for static:
-set_target_properties(portmidi PROPERTIES
- VERSION ${LIBRARY_VERSION}
- SOVERSION ${LIBRARY_SOVERSION}
- OUTPUT_NAME "${PM_ACTUAL_LIB_NAME}"
- MSVC_RUNTIME_LIBRARY
- "MultiThreaded$<$<CONFIG:Debug>:Debug>${MSVCRT_DLL}"
- WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
-target_include_directories(portmidi PUBLIC
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
- $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
-
-
-option(PM_CHECK_ERRORS
-"Insert a check for error return values at the end of each PortMidi function.
-If an error is encountered, a text message is printed using printf(), the user
-is asked to type ENTER, and then exit(-1) is called to clean up and terminate
-the program.
-
-You should not use PM_CHECK_ERRORS if printf() does not work (e.g. this is not
-a console application under Windows, or there is no visible console on some
-other OS), and you should not use PM_CHECK_ERRORS if you intend to recover
-from errors rather than abruptly terminate the program." OFF)
-if(PM_CHECK_ERRORS)
- target_compile_definitions(portmidi PRIVATE PM_CHECK_ERRORS)
-endif(PM_CHECK_ERRORS)
-
-macro(prepend_path RESULT PATH)
- set(${RESULT})
- foreach(FILE ${ARGN})
- list(APPEND ${RESULT} "${PATH}${FILE}")
- endforeach(FILE)
-endmacro(prepend_path)
-
-# UNIX needs pthread library
-if(NOT WIN32)
- set(THREADS_PREFER_PTHREAD_FLAG ON)
- find_package(Threads REQUIRED)
-endif()
-
-# Check for sndio
-if(USE_SNDIO)
- include (FindPackageHandleStandardArgs)
- find_path(SNDIO_INCLUDE_DIRS NAMES sndio.h)
- find_library(SNDIO_LIBRARY sndio)
- find_package_handle_standard_args(Sndio
- REQUIRED_VARS SNDIO_LIBRARY SNDIO_INCLUDE_DIRS)
-endif(USE_SNDIO)
-
-# first include the appropriate system-dependent file:
-if(SNDIO_FOUND AND USE_SNDIO)
- set(PM_LIB_PRIVATE_SRC
- ${PMDIR}/porttime/ptlinux.c
- ${PMDIR}/pm_sndio/pmsndio.c)
- set(PM_NEEDED_LIBS Threads::Threads ${SNDIO_LIBRARY} PARENT_SCOPE)
- target_link_libraries(portmidi PRIVATE Threads::Threads ${SNDIO_LIBRARY})
- target_include_directories(portmidi PRIVATE ${SNDIO_INCLUDE_DIRS})
-elseif(UNIX AND APPLE)
- set(Threads::Threads "" PARENT_SCOPE)
- set(PM_LIB_PRIVATE_SRC
- ${PMDIR}/porttime/ptmacosx_mach.c
- ${PMDIR}/pm_mac/pmmac.c
- ${PMDIR}/pm_mac/pmmacosxcm.c)
- set(PM_NEEDED_LIBS
- ${CMAKE_THREAD_LIBS_INIT}
- -Wl,-framework,CoreAudio
- -Wl,-framework,CoreFoundation
- -Wl,-framework,CoreMidi
- -Wl,-framework,CoreServices
- PARENT_SCOPE)
- target_link_libraries(portmidi PRIVATE
- Threads::Threads
- -Wl,-framework,CoreAudio
- -Wl,-framework,CoreFoundation
- -Wl,-framework,CoreMidi
- -Wl,-framework,CoreServices
- )
- # set to CMake default; is this right?:
- set_target_properties(portmidi PROPERTIES MACOSX_RPATH ON)
-elseif(HAIKU)
- set(PM_LIB_PRIVATE_SRC
- ${PMDIR}/porttime/pthaiku.cpp
- ${PMDIR}/pm_haiku/pmhaiku.cpp)
- set(PM_NEEDED_LIBS be midi midi2 PARENT_SCOPE)
- target_link_libraries(portmidi PRIVATE be midi midi2)
-elseif(UNIX)
- target_compile_definitions(portmidi PRIVATE ${LINUX_FLAGS})
- set(PM_LIB_PRIVATE_SRC
- ${PMDIR}/porttime/ptlinux.c
- ${PMDIR}/pm_linux/pmlinux.c
- ${PMDIR}/pm_linux/pmlinuxnull.c)
- if(${LINUX_DEFINES} MATCHES ".*PMALSA.*")
- # Note that ALSA is not required if PMNULL is defined -- PortMidi will then
- # compile without ALSA and report no MIDI devices. Later, PMSNDIO or PMJACK
- # might be additional options.
- find_package(ALSA REQUIRED)
- list(APPEND PM_LIB_PRIVATE_SRC ${PMDIR}/pm_linux/pmlinuxalsa.c)
- set(PM_NEEDED_LIBS ${CMAKE_THREAD_LIBS_INIT} ${ALSA_LIBRARIES} PARENT_SCOPE)
- target_link_libraries(portmidi PRIVATE Threads::Threads ALSA::ALSA)
- set(PKGCONFIG_REQUIRES_PRIVATE "alsa" PARENT_SCOPE)
- else()
- message(WARNING "No PMALSA, so PortMidi will not use ALSA, "
- "and will not find or open MIDI devices.")
- set(PM_NEEDED_LIBS ${CMAKE_THREAD_LIBS_INIT} PARENT_SCOPE)
- target_link_libraries(portmidi PRIVATE Threads::Threads)
- endif()
-elseif(WIN32)
- set(PM_LIB_PRIVATE_SRC
- ${PMDIR}/porttime/ptwinmm.c
- ${PMDIR}/pm_win/pmwin.c
- ${PMDIR}/pm_win/pmwinmm.c)
- set(PM_NEEDED_LIBS winmm PARENT_SCOPE)
- target_link_libraries(portmidi PRIVATE winmm)
-# if(NOT BUILD_SHARED_LIBS AND PM_USE_STATIC_RUNTIME)
- # /MDd is multithread debug DLL, /MTd is multithread debug
- # /MD is multithread DLL, /MT is multithread. Change to static:
-# include(../pm_win/static.cmake)
-# endif()
-else()
- message(FATAL_ERROR "Operating system not supported.")
-endif()
-
-set(PM_LIB_PUBLIC_SRC ${PM_LIB_PUBLIC_SRC} PARENT_SCOPE) # export to parent
-set(PM_LIB_PRIVATE_SRC ${PM_LIB_PRIVATE_SRC} PARENT_SCOPE) # export to parent
-
-target_sources(portmidi PRIVATE ${PM_LIB_PRIVATE_SRC})
-
diff --git a/portmidi/pm_common/pminternal.h b/portmidi/pm_common/pminternal.h
deleted file mode 100755
index 8b3d8f5..0000000
--- a/portmidi/pm_common/pminternal.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/** @file pminternal.h header for PortMidi implementations */
-
-/* this file is included by files that implement library internals */
-/* Here is a guide to implementers:
- provide an initialization function similar to pm_winmm_init()
- add your initialization function to pm_init()
- Note that your init function should never require not-standard
- libraries or fail in any way. If the interface is not available,
- simply do not call pm_add_device. This means that non-standard
- libraries should try to do dynamic linking at runtime using a DLL
- and return without error if the DLL cannot be found or if there
- is any other failure.
- implement functions as indicated in pm_fns_type to open, read, write,
- close, etc.
- call pm_add_device() for each input and output device, passing it a
- pm_fns_type structure.
- assumptions about pm_fns_type functions are given below.
- */
-
-/** @cond INTERNAL - add INTERNAL to Doxygen ENABLED_SECTIONS to include */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern int pm_initialized; /* see note in portmidi.c */
-extern PmDeviceID pm_default_input_device_id;
-extern PmDeviceID pm_default_output_device_id;
-
-/* these are defined in system-specific file */
-void *pm_alloc(size_t s);
-void pm_free(void *ptr);
-
-/* if a host error (an error reported by the host MIDI API that is not
- * mapped to a PortMidi error code) occurs in a synchronous operation
- * (i.e., not in a callback from another thread) set these: */
-extern int pm_hosterror; /* boolean */
-extern char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
-
-struct pm_internal_struct;
-
-/* these do not use PmInternal because it is not defined yet... */
-typedef PmError (*pm_write_short_fn)(struct pm_internal_struct *midi,
- PmEvent *buffer);
-typedef PmError (*pm_begin_sysex_fn)(struct pm_internal_struct *midi,
- PmTimestamp timestamp);
-typedef PmError (*pm_end_sysex_fn)(struct pm_internal_struct *midi,
- PmTimestamp timestamp);
-typedef PmError (*pm_write_byte_fn)(struct pm_internal_struct *midi,
- unsigned char byte, PmTimestamp timestamp);
-typedef PmError (*pm_write_realtime_fn)(struct pm_internal_struct *midi,
- PmEvent *buffer);
-typedef PmError (*pm_write_flush_fn)(struct pm_internal_struct *midi,
- PmTimestamp timestamp);
-typedef PmTimestamp (*pm_synchronize_fn)(struct pm_internal_struct *midi);
-/* pm_open_fn should clean up all memory and close the device if any part
- of the open fails */
-typedef PmError (*pm_open_fn)(struct pm_internal_struct *midi,
- void *driverInfo);
-typedef PmError (*pm_create_fn)(int is_input, const char *name,
- void *driverInfo);
-typedef PmError (*pm_delete_fn)(PmDeviceID id);
-typedef PmError (*pm_abort_fn)(struct pm_internal_struct *midi);
-/* pm_close_fn should clean up all memory and close the device if any
- part of the close fails. */
-typedef PmError (*pm_close_fn)(struct pm_internal_struct *midi);
-typedef PmError (*pm_poll_fn)(struct pm_internal_struct *midi);
-typedef unsigned int (*pm_check_host_error_fn)(struct pm_internal_struct *midi);
-
-typedef struct {
- pm_write_short_fn write_short; /* output short MIDI msg */
- pm_begin_sysex_fn begin_sysex; /* prepare to send a sysex message */
- pm_end_sysex_fn end_sysex; /* marks end of sysex message */
- pm_write_byte_fn write_byte; /* accumulate one more sysex byte */
- pm_write_realtime_fn write_realtime; /* send real-time msg within sysex */
- pm_write_flush_fn write_flush; /* send any accumulated but unsent data */
- pm_synchronize_fn synchronize; /* synchronize PM time to stream time */
- pm_open_fn open; /* open MIDI device */
- pm_abort_fn abort; /* abort */
- pm_close_fn close; /* close device */
- pm_poll_fn poll; /* read pending midi events into portmidi buffer */
- pm_check_host_error_fn check_host_error; /* true when device has had host */
- /* error; sets pm_hosterror and writes message to pm_hosterror_text */
-} pm_fns_node, *pm_fns_type;
-
-
-/* when open fails, the dictionary gets this set of functions: */
-extern pm_fns_node pm_none_dictionary;
-
-typedef struct {
- PmDeviceInfo pub; /* some portmidi state also saved in here (for automatic
- device closing -- see PmDeviceInfo struct) */
- int deleted; /* is this is a deleted virtual device? */
- void *descriptor; /* ID number passed to win32 multimedia API open,
- * coreMIDI endpoint, etc., representing the device */
- struct pm_internal_struct *pm_internal; /* points to PmInternal device */
- /* when the device is open, allows automatic device closing */
- pm_fns_type dictionary;
-} descriptor_node, *descriptor_type;
-
-extern int pm_descriptor_max;
-extern descriptor_type pm_descriptors;
-extern int pm_descriptor_len;
-
-typedef uint32_t (*time_get_proc_type)(void *time_info);
-
-typedef struct pm_internal_struct {
- int device_id; /* which device is open (index to pm_descriptors) */
- short is_input; /* MIDI IN (true) or MIDI OUT (false) */
- short is_removed; /* MIDI device was removed */
- PmTimeProcPtr time_proc; /* where to get the time */
- void *time_info; /* pass this to get_time() */
- int32_t buffer_len; /* how big is the buffer or queue? */
- PmQueue *queue;
-
- int32_t latency; /* time delay in ms between timestamps and actual output */
- /* set to zero to get immediate, simple blocking output */
- /* if latency is zero, timestamps will be ignored; */
- /* if midi input device, this field ignored */
-
- int sysex_in_progress; /* when sysex status is seen, this flag becomes
- * true until EOX is seen. When true, new data is appended to the
- * stream of outgoing bytes. When overflow occurs, sysex data is
- * dropped (until an EOX or non-real-timei status byte is seen) so
- * that, if the overflow condition is cleared, we don't start
- * sending data from the middle of a sysex message. If a sysex
- * message is filtered, sysex_in_progress is false, causing the
- * message to be dropped. */
- PmMessage message; /* buffer for 4 bytes of sysex data */
- int message_count; /* how many bytes in sysex_message so far */
- int short_message_count; /* how many bytes are expected in short message */
- unsigned char running_status; /* running status byte or zero if none */
- int32_t filters; /* flags that filter incoming message classes */
- int32_t channel_mask; /* filter incoming messages based on channel */
- PmTimestamp last_msg_time; /* timestamp of last message */
- PmTimestamp sync_time; /* time of last synchronization */
- PmTimestamp now; /* set by PmWrite to current time */
- int first_message; /* initially true, used to run first synchronization */
- pm_fns_type dictionary; /* implementation functions */
- void *api_info; /* system-dependent state */
- /* the following are used to expedite sysex data */
- /* on windows, in debug mode, based on some profiling, these optimizations
- * cut the time to process sysex bytes from about 7.5 to 0.26 usec/byte,
- * but this does not count time in the driver, so I don't know if it is
- * important
- */
- unsigned char *fill_base; /* addr of ptr to sysex data */
- uint32_t *fill_offset_ptr; /* offset of next sysex byte */
- uint32_t fill_length; /* how many sysex bytes to write */
-} PmInternal;
-
-/* what is the length of this short message? */
-int pm_midi_length(PmMessage msg);
-
-/* defined by system specific implementation, e.g. pmwinmm, used by PortMidi */
-void pm_init(void);
-void pm_term(void);
-
-/* defined by portMidi, used by pmwinmm */
-PmError none_write_short(PmInternal *midi, PmEvent *buffer);
-PmError none_write_byte(PmInternal *midi, unsigned char byte,
- PmTimestamp timestamp);
-PmTimestamp none_synchronize(PmInternal *midi);
-
-PmError pm_fail_fn(PmInternal *midi);
-PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp);
-PmError pm_success_fn(PmInternal *midi);
-PmError pm_add_interf(char *interf, pm_create_fn create_fn,
- pm_delete_fn delete_fn);
-PmError pm_add_device(char *interf, const char *name, int is_input,
- int is_virtual, void *descriptor, pm_fns_type dictionary);
-void pm_undo_add_device(int id);
-uint32_t pm_read_bytes(PmInternal *midi, const unsigned char *data, int len,
- PmTimestamp timestamp);
-void pm_read_short(PmInternal *midi, PmEvent *event);
-
-#define none_write_flush pm_fail_timestamp_fn
-#define none_sysex pm_fail_timestamp_fn
-#define none_poll pm_fail_fn
-#define success_poll pm_success_fn
-
-#define MIDI_REALTIME_MASK 0xf8
-#define is_real_time(msg) \
- ((Pm_MessageStatus(msg) & MIDI_REALTIME_MASK) == MIDI_REALTIME_MASK)
-
-#ifdef __cplusplus
-}
-#endif
-
-/** @endcond */
diff --git a/portmidi/pm_common/pmutil.c b/portmidi/pm_common/pmutil.c
deleted file mode 100755
index a70fe2f..0000000
--- a/portmidi/pm_common/pmutil.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/* pmutil.c -- some helpful utilities for building midi
- applications that use PortMidi
- */
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-#include "portmidi.h"
-#include "pmutil.h"
-#include "pminternal.h"
-
-#ifdef WIN32
-#define bzero(addr, siz) memset(addr, 0, siz)
-#endif
-
-// #define QUEUE_DEBUG 1
-#ifdef QUEUE_DEBUG
-#include "stdio.h"
-#endif
-
-typedef struct {
- long head;
- long tail;
- long len;
- long overflow;
- int32_t msg_size; /* number of int32_t in a message including extra word */
- int32_t peek_overflow;
- int32_t *buffer;
- int32_t *peek;
- int32_t peek_flag;
-} PmQueueRep;
-
-
-PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg)
-{
- int32_t int32s_per_msg =
- (int32_t) (((bytes_per_msg + sizeof(int32_t) - 1) &
- ~(sizeof(int32_t) - 1)) / sizeof(int32_t));
- PmQueueRep *queue = (PmQueueRep *) pm_alloc(sizeof(PmQueueRep));
- if (!queue) /* memory allocation failed */
- return NULL;
-
- /* need extra word per message for non-zero encoding */
- queue->len = num_msgs * (int32s_per_msg + 1);
- queue->buffer = (int32_t *) pm_alloc(queue->len * sizeof(int32_t));
- bzero(queue->buffer, queue->len * sizeof(int32_t));
- if (!queue->buffer) {
- pm_free(queue);
- return NULL;
- } else { /* allocate the "peek" buffer */
- queue->peek = (int32_t *) pm_alloc(int32s_per_msg * sizeof(int32_t));
- if (!queue->peek) {
- /* free everything allocated so far and return */
- pm_free(queue->buffer);
- pm_free(queue);
- return NULL;
- }
- }
- bzero(queue->buffer, queue->len * sizeof(int32_t));
- queue->head = 0;
- queue->tail = 0;
- /* msg_size is in words */
- queue->msg_size = int32s_per_msg + 1; /* note extra word is counted */
- queue->overflow = FALSE;
- queue->peek_overflow = FALSE;
- queue->peek_flag = FALSE;
- return queue;
-}
-
-
-PMEXPORT PmError Pm_QueueDestroy(PmQueue *q)
-{
- PmQueueRep *queue = (PmQueueRep *) q;
-
- /* arg checking */
- if (!queue || !queue->buffer || !queue->peek)
- return pmBadPtr;
-
- pm_free(queue->peek);
- pm_free(queue->buffer);
- pm_free(queue);
- return pmNoError;
-}
-
-
-PMEXPORT PmError Pm_Dequeue(PmQueue *q, void *msg)
-{
- long head;
- PmQueueRep *queue = (PmQueueRep *) q;
- int i;
- int32_t *msg_as_int32 = (int32_t *) msg;
-
- /* arg checking */
- if (!queue)
- return pmBadPtr;
- /* a previous peek operation encountered an overflow, but the overflow
- * has not yet been reported to client, so do it now. No message is
- * returned, but on the next call, we will return the peek buffer.
- */
- if (queue->peek_overflow) {
- queue->peek_overflow = FALSE;
- return pmBufferOverflow;
- }
- if (queue->peek_flag) {
- memcpy(msg, queue->peek, (queue->msg_size - 1) * sizeof(int32_t));
- queue->peek_flag = FALSE;
- return pmGotData;
- }
-
- head = queue->head;
- /* if writer overflows, it writes queue->overflow = tail+1 so that
- * when the reader gets to that position in the buffer, it can
- * return the overflow condition to the reader. The problem is that
- * at overflow, things have wrapped around, so tail == head, and the
- * reader will detect overflow immediately instead of waiting until
- * it reads everything in the buffer, wrapping around again to the
- * point where tail == head. So the condition also checks that
- * queue->buffer[head] is zero -- if so, then the buffer is now
- * empty, and we're at the point in the msg stream where overflow
- * occurred. It's time to signal overflow to the reader. If
- * queue->buffer[head] is non-zero, there's a message there and we
- * should read all the way around the buffer before signalling overflow.
- * There is a write-order dependency here, but to fail, the overflow
- * field would have to be written while an entire buffer full of
- * writes are still pending. I'm assuming out-of-order writes are
- * possible, but not that many.
- */
- if (queue->overflow == head + 1 && !queue->buffer[head]) {
- queue->overflow = 0; /* non-overflow condition */
- return pmBufferOverflow;
- }
-
- /* test to see if there is data in the queue -- test from back
- * to front so if writer is simultaneously writing, we don't
- * waste time discovering the write is not finished
- */
- for (i = queue->msg_size - 1; i >= 0; i--) {
- if (!queue->buffer[head + i]) {
- return pmNoData;
- }
- }
- memcpy(msg, (char *) &queue->buffer[head + 1],
- sizeof(int32_t) * (queue->msg_size - 1));
- /* fix up zeros */
- i = queue->buffer[head];
- while (i < queue->msg_size) {
- int32_t j;
- i--; /* msg does not have extra word so shift down */
- j = msg_as_int32[i];
- msg_as_int32[i] = 0;
- i = j;
- }
- /* signal that data has been removed by zeroing: */
- bzero((char *) &queue->buffer[head], sizeof(int32_t) * queue->msg_size);
-
- /* update head */
- head += queue->msg_size;
- if (head == queue->len) head = 0;
- queue->head = head;
- return pmGotData; /* success */
-}
-
-
-
-PMEXPORT PmError Pm_SetOverflow(PmQueue *q)
-{
- PmQueueRep *queue = (PmQueueRep *) q;
- long tail;
- /* arg checking */
- if (!queue)
- return pmBadPtr;
- /* no more enqueue until receiver acknowledges overflow */
- if (queue->overflow) return pmBufferOverflow;
- tail = queue->tail;
- queue->overflow = tail + 1;
- return pmBufferOverflow;
-}
-
-
-PMEXPORT PmError Pm_Enqueue(PmQueue *q, void *msg)
-{
- PmQueueRep *queue = (PmQueueRep *) q;
- long tail;
- int i;
- int32_t *src = (int32_t *) msg;
- int32_t *ptr;
- int32_t *dest;
- int rslt;
- if (!queue)
- return pmBadPtr;
- /* no more enqueue until receiver acknowledges overflow */
- if (queue->overflow) return pmBufferOverflow;
- rslt = Pm_QueueFull(q);
- /* already checked above: if (rslt == pmBadPtr) return rslt; */
- tail = queue->tail;
- if (rslt) {
- queue->overflow = tail + 1;
- return pmBufferOverflow;
- }
-
- /* queue is has room for message, and overflow flag is cleared */
- ptr = &queue->buffer[tail];
- dest = ptr + 1;
- for (i = 1; i < queue->msg_size; i++) {
- int32_t j = src[i - 1];
- if (!j) {
- *ptr = i;
- ptr = dest;
- } else {
- *dest = j;
- }
- dest++;
- }
- *ptr = i;
- tail += queue->msg_size;
- if (tail == queue->len) tail = 0;
- queue->tail = tail;
- return pmNoError;
-}
-
-
-PMEXPORT int Pm_QueueEmpty(PmQueue *q)
-{
- PmQueueRep *queue = (PmQueueRep *) q;
- return (!queue) || /* null pointer -> return "empty" */
- (queue->buffer[queue->head] == 0 && !queue->peek_flag);
-}
-
-
-PMEXPORT int Pm_QueueFull(PmQueue *q)
-{
- long tail;
- int i;
- PmQueueRep *queue = (PmQueueRep *) q;
- /* arg checking */
- if (!queue)
- return pmBadPtr;
- tail = queue->tail;
- /* test to see if there is space in the queue */
- for (i = 0; i < queue->msg_size; i++) {
- if (queue->buffer[tail + i]) {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-
-PMEXPORT void *Pm_QueuePeek(PmQueue *q)
-{
- PmError rslt;
- int32_t temp;
- PmQueueRep *queue = (PmQueueRep *) q;
- /* arg checking */
- if (!queue)
- return NULL;
-
- if (queue->peek_flag) {
- return queue->peek;
- }
- /* this is ugly: if peek_overflow is set, then Pm_Dequeue()
- * returns immediately with pmBufferOverflow, but here, we
- * want Pm_Dequeue() to really check for data. If data is
- * there, we can return it
- */
- temp = queue->peek_overflow;
- queue->peek_overflow = FALSE;
- rslt = Pm_Dequeue(q, queue->peek);
- queue->peek_overflow = temp;
-
- if (rslt == 1) {
- queue->peek_flag = TRUE;
- return queue->peek;
- } else if (rslt == pmBufferOverflow) {
- /* when overflow is indicated, the queue is empty and the
- * first message that was dropped by Enqueue (signalling
- * pmBufferOverflow to its caller) would have been the next
- * message in the queue. Pm_QueuePeek will return NULL, but
- * remember that an overflow occurred. (see Pm_Dequeue)
- */
- queue->peek_overflow = TRUE;
- }
- return NULL;
-}
-
diff --git a/portmidi/pm_common/pmutil.h b/portmidi/pm_common/pmutil.h
deleted file mode 100755
index 46c618e..0000000
--- a/portmidi/pm_common/pmutil.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/** @file pmutil.h lock-free queue for building MIDI
- applications with PortMidi.
-
- PortMidi is not reentrant, and locks can suffer from priority
- inversion. To support coordination between system callbacks, a
- high-priority thread created with PortTime, and the main
- application thread, PortMidi uses a lock-free, non-blocking
- queue. The queue implementation is not particular to MIDI and is
- available for other uses.
- */
-
-#ifndef PORTMIDI_PMUTIL_H
-#define PORTMIDI_PMUTIL_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/** @defgroup grp_pmutil Lock-free Queue
- @{
-*/
-
-/** The queue representation is opaque. Declare a queue as PmQueue * */
-typedef void PmQueue;
-
-/** create a single-reader, single-writer queue.
-
- @param num_msgs the number of messages the queue can hold
-
- @param the fixed message size
-
- @return the allocated and initialized queue, or NULL if memory
- cannot be allocated. Allocation uses #pm_malloc().
-
- The queue only accepts fixed sized messages.
-
- This queue implementation uses the "light pipe" algorithm which
- operates correctly even with multi-processors and out-of-order
- memory writes. (see Alexander Dokumentov, "Lock-free Interprocess
- Communication," Dr. Dobbs Portal, http://www.ddj.com/,
- articleID=189401457, June 15, 2006. This algorithm requires that
- messages be translated to a form where no words contain
- zeros. Each word becomes its own "data valid" tag. Because of this
- translation, we cannot return a pointer to data still in the queue
- when the "peek" method is called. Instead, a buffer is
- preallocated so that data can be copied there. Pm_QueuePeek()
- dequeues a message into this buffer and returns a pointer to it. A
- subsequent Pm_Dequeue() will copy from this buffer.
-
- This implementation does not try to keep reader/writer data in
- separate cache lines or prevent thrashing on cache lines.
- However, this algorithm differs by doing inserts/removals in
- units of messages rather than units of machine words. Some
- performance improvement might be obtained by not clearing data
- immediately after a read, but instead by waiting for the end
- of the cache line, especially if messages are smaller than
- cache lines. See the Dokumentov article for explanation.
-
- The algorithm is extended to handle "overflow" reporting. To
- report an overflow, the sender writes the current tail position to
- a field. The receiver must acknowlege receipt by zeroing the
- field. The sender will not send more until the field is zeroed.
- */
-PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg);
-
-/** destroy a queue and free its storage.
-
- @param queue a queue created by #Pm_QueueCreate().
-
- @return pmNoError or an error code.
-
- Uses #pm_free().
-
- */
-PMEXPORT PmError Pm_QueueDestroy(PmQueue *queue);
-
-/** remove one message from the queue, copying it into \p msg.
-
- @param queue a queue created by #Pm_QueueCreate().
-
- @param msg address to which the message, if any, is copied.
-
- @return 1 if successful, and 0 if the queue is empty. Returns
- #pmBufferOverflow if what would have been the next thing in the
- queue was dropped due to overflow. (So when overflow occurs, the
- receiver can receive a queue full of messages before getting the
- overflow report. This protocol ensures that the reader will be
- notified when data is lost due to overflow.
- */
-PMEXPORT PmError Pm_Dequeue(PmQueue *queue, void *msg);
-
-/** insert one message into the queue, copying it from \p msg.
-
- @param queue a queue created by #Pm_QueueCreate().
-
- @param msg address of the message to be enqueued.
-
- @return #pmNoError if successful and #pmBufferOverflow if the
- queue was already full. If #pmBufferOverflow is returned, the
- overflow flag is set.
- */
-PMEXPORT PmError Pm_Enqueue(PmQueue *queue, void *msg);
-
-/** test if the queue is full.
-
- @param queue a queue created by #Pm_QueueCreate().
-
- @return non-zero iff the queue is empty, and @pmBadPtr if \p queue
- is NULL.
-
- The full condition may change immediately because a parallel
- dequeue operation could be in progress. The result is
- pessimistic: if it returns false (zero) to the single writer, then
- #Pm_Enqueue() is guaranteed to succeed.
- */
-PMEXPORT int Pm_QueueFull(PmQueue *queue);
-
-/** test if the queue is empty.
-
- @param queue a queue created by #Pm_QueueCreate().
-
- @return zero iff the queue is either empty or NULL.
-
- The empty condition may change immediately because a parallel
- enqueue operation could be in progress. Furthermore, the
- result is optimistic: it may say false, when due to
- out-of-order writes, the full message has not arrived. Therefore,
- #Pm_Dequeue() could still return 0 after #Pm_QueueEmpty() returns
- false.
-*/
-PMEXPORT int Pm_QueueEmpty(PmQueue *queue);
-
-/** get a pointer to the item at the head of the queue.
-
- @param queue a queue created by #Pm_QueueCreate().
-
- @result a pointer to the head message or NULL if the queue is empty.
-
- The message is not removed from the queue. #Pm_QueuePeek() will
- not indicate when an overflow occurs. If you want to get and check
- #pmBufferOverflow messages, use the return value of
- #Pm_QueuePeek() *only* as an indication that you should call
- #Pm_Dequeue(). At the point where a direct call to #Pm_Dequeue()
- would return #pmBufferOverflow, #Pm_QueuePeek() will return NULL,
- but internally clear the #pmBufferOverflow flag, enabling
- #Pm_Enqueue() to resume enqueuing messages. A subsequent call to
- #Pm_QueuePeek() will return a pointer to the first message *after*
- the overflow. Using this as an indication to call #Pm_Dequeue(),
- the first call to #Pm_Dequeue() will return #pmBufferOverflow. The
- second call will return success, copying the same message pointed
- to by the previous #Pm_QueuePeek().
-
- When to use #Pm_QueuePeek(): (1) when you need to look at the message
- data to decide who should be called to receive it. (2) when you need
- to know a message is ready but cannot accept the message.
-
- Note that #Pm_QueuePeek() is not a fast check, so if possible, you
- might as well just call #Pm_Dequeue() and accept the data if it is there.
- */
-PMEXPORT void *Pm_QueuePeek(PmQueue *queue);
-
-/** allows the writer (enqueuer) to signal an overflow
- condition to the reader (dequeuer).
-
- @param queue a queue created by #Pm_QueueCreate().
-
- @return #pmNoError if overflow is set, or #pmBadPtr if queue is
- NULL, or #pmBufferOverflow if buffer is already in an overflow
- state.
-
- E.g., when transfering data from the OS to an application, if the
- OS indicates a buffer overrun, #Pm_SetOverflow() can be used to
- insure that the reader receives a #pmBufferOverflow result from
- #Pm_Dequeue().
- */
-PMEXPORT PmError Pm_SetOverflow(PmQueue *queue);
-
-/** @} */
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif // PORTMIDI_PMUTIL_H
diff --git a/portmidi/pm_common/portmidi.c b/portmidi/pm_common/portmidi.c
deleted file mode 100755
index e78ee73..0000000
--- a/portmidi/pm_common/portmidi.c
+++ /dev/null
@@ -1,1472 +0,0 @@
-/* portmidi.c -- cross-platform MIDI I/O library */
-/* see license.txt for license */
-
-#include "stdlib.h"
-#include "string.h"
-#include "portmidi.h"
-#include "porttime.h"
-#include "pmutil.h"
-#include "pminternal.h"
-#include <assert.h>
-
-#define MIDI_CLOCK 0xf8
-#define MIDI_ACTIVE 0xfe
-#define MIDI_STATUS_MASK 0x80
-#define MIDI_SYSEX 0xf0
-#define MIDI_EOX 0xf7
-#define MIDI_START 0xFA
-#define MIDI_STOP 0xFC
-#define MIDI_CONTINUE 0xFB
-#define MIDI_F9 0xF9
-#define MIDI_FD 0xFD
-#define MIDI_RESET 0xFF
-#define MIDI_NOTE_ON 0x90
-#define MIDI_NOTE_OFF 0x80
-#define MIDI_CHANNEL_AT 0xD0
-#define MIDI_POLY_AT 0xA0
-#define MIDI_PROGRAM 0xC0
-#define MIDI_CONTROL 0xB0
-#define MIDI_PITCHBEND 0xE0
-#define MIDI_MTC 0xF1
-#define MIDI_SONGPOS 0xF2
-#define MIDI_SONGSEL 0xF3
-#define MIDI_TUNE 0xF6
-
-#define is_empty(midi) ((midi)->tail == (midi)->head)
-
-/* these are not static so that (possibly) some system-dependent code
- * could override the portmidi.c default which is to use the first
- * device added using pm_add_device()
- */
-PmDeviceID pm_default_input_device_id = -1;
-PmDeviceID pm_default_output_device_id = -1;
-
-/* this is not static so that pm_init can set it directly
- * (see pmmac.c:pm_init())
- */
-int pm_initialized = FALSE;
-
-int pm_hosterror; /* boolean */
-
-/* if PM_CHECK_ERRORS is enabled, but the caller wants to
- * handle an error condition, declare this as extern and
- * set to FALSE (this override is provided specifically
- * for the test program virttest.c, where pmNameConflict
- * is expected in a call to Pm_CreateVirtualInput()):
- */
-int pm_check_errors = TRUE;
-
-char pm_hosterror_text[PM_HOST_ERROR_MSG_LEN];
-
-#ifdef PM_CHECK_ERRORS
-
-#include <stdio.h>
-
-#define STRING_MAX 80
-
-static void prompt_and_exit(void)
-{
- char line[STRING_MAX];
- printf("type ENTER...");
- char *rslt = fgets(line, STRING_MAX, stdin);
- /* this will clean up open ports: */
- exit(-1);
-}
-
-static PmError pm_errmsg(PmError err)
-{
- if (!pm_check_errors) { /* see pm_check_errors declaration above */
- ;
- } else if (err == pmHostError) {
- /* it seems pointless to allocate memory and copy the string,
- * so I will do the work of Pm_GetHostErrorText directly
- */
- printf("PortMidi found host error...\n %s\n", pm_hosterror_text);
- pm_hosterror = FALSE;
- pm_hosterror_text[0] = 0; /* clear the message */
- prompt_and_exit();
- } else if (err < 0) {
- printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err));
- prompt_and_exit();
- }
- return err;
-}
-#else
-#define pm_errmsg(err) err
-#endif
-
-
-int pm_midi_length(PmMessage msg)
-{
- int status, high, low;
- static int high_lengths[] = {
- 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 through 0x70 */
- 3, 3, 3, 3, 2, 2, 3, 1 /* 0x80 through 0xf0 */
- };
- static int low_lengths[] = {
- 1, 2, 3, 2, 1, 1, 1, 1, /* 0xf0 through 0xf8 */
- 1, 1, 1, 1, 1, 1, 1, 1 /* 0xf9 through 0xff */
- };
-
- status = msg & 0xFF;
- high = status >> 4;
- low = status & 15;
-
- return (high != 0xF) ? high_lengths[high] : low_lengths[low];
-}
-
-
-/*
-====================================================================
-system implementation of portmidi interface
-====================================================================
-*/
-
-int pm_descriptor_max = 0;
-int pm_descriptor_len = 0;
-descriptor_type pm_descriptors = NULL;
-
-/* interface pm_descriptors are simple: an array of string/fnptr pairs: */
-#define MAX_INTERF 4
-static struct {
- const char *interf;
- pm_create_fn create_fn;
- pm_delete_fn delete_fn;
-} pm_interf_list[MAX_INTERF];
-
-static int pm_interf_list_len = 0;
-
-
-/* pm_add_interf -- describe an interface to library
- *
- * This is called at initialization time, once for each
- * supported interface (e.g., CoreMIDI). The strings
- * are retained but NOT COPIED, so do not destroy them!
- *
- * The purpose is to register functions that create/delete
- * a virtual input or output device.
- *
- * returns pmInsufficientMemor if interface memory is
- * exceeded, otherwise returns pmNoError.
- */
-PmError pm_add_interf(char *interf, pm_create_fn create_fn,
- pm_delete_fn delete_fn)
-{
- if (pm_interf_list_len >= MAX_INTERF) {
- return pmInsufficientMemory;
- }
- pm_interf_list[pm_interf_list_len].interf = interf;
- pm_interf_list[pm_interf_list_len].create_fn = create_fn;
- pm_interf_list[pm_interf_list_len].delete_fn = delete_fn;
- pm_interf_list_len++;
- return pmNoError;
-}
-
-
-PmError pm_create_virtual(PmInternal *midi, int is_input, const char *interf,
- const char *name, void *device_info)
-{
- int i;
- if (pm_interf_list_len == 0) {
- return pmNotImplemented;
- }
- if (!interf) {
- /* default interface is the first one */
- interf = pm_interf_list[0].interf;
- }
- for (i = 0; i < pm_interf_list_len; i++) {
- if (strcmp(pm_interf_list[i].interf,
- interf) == 0) {
- int id = (*pm_interf_list[i].create_fn)(is_input, name,
- device_info);
- pm_descriptors[id].pub.is_virtual = TRUE;
- return id;
- }
- }
- return pmInterfaceNotSupported;
-}
-
-
-/* pm_add_device -- describe interface/device pair to library
- *
- * This is called at intialization time, once for each
- * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1).
- * This is also called when user creates a virtual device.
- *
- * Normally, increasing integer indices are returned. If the device
- * is virtual, a linear search is performed to ensure that the name
- * is unique. If the name is already taken, the call will fail and
- * no device is added.
- *
- * interf is assumed to be static memory, so it is NOT COPIED and
- * NOT FREED.
- * name is owned by caller, COPIED if needed, and FREED by PortMidi.
- * Caller is resposible for freeing name when pm_add_device returns.
- *
- * returns pmInvalidDeviceId if device memory is exceeded or a virtual
- * device would take the name of an existing device.
- * otherwise returns index (portmidi device_id) of the added device
- */
-PmError pm_add_device(char *interf, const char *name, int is_input,
- int is_virtual, void *descriptor, pm_fns_type dictionary) {
- /* printf("pm_add_device: %s %s %d %p %p\n",
- interf, name, is_input, descriptor, dictionary); */
- int device_id;
- PmDeviceInfo *d;
- /* if virtual, search for duplicate name or unused ID; otherwise,
- * just add a new device at the next integer available:
- */
- for (device_id = (is_virtual ? 0 : pm_descriptor_len);
- device_id < pm_descriptor_len; device_id++) {
- d = &pm_descriptors[device_id].pub;
- d->structVersion = PM_DEVICEINFO_VERS;
- if (strcmp(d->interf, interf) == 0 && strcmp(d->name, name) == 0) {
- /* only reuse a name if it is a deleted virtual device with
- * a matching direction (input or output) */
- if (pm_descriptors[device_id].deleted && is_input == d->input) {
- /* here, we know d->is_virtual because only virtual devices
- * can be deleted, and we know is_virtual because we are
- * in this loop.
- */
- pm_free((void *) d->name); /* reuse this device entry */
- d->name = NULL;
- break;
- /* name conflict exists if the new device appears to others as
- * the same direction (input or output) as the existing device.
- * Note that virtual inputs appear to others as outputs and
- * vice versa.
- * The direction of the new virtual device to others is "output"
- * if is_input, i.e., virtual inputs appear to others as outputs.
- * The existing device appears to others as "output" if
- * (d->is_virtual == d->input) by the same logic.
- * The compare will detect if device directions are the same:
- */
- } else if (is_input == (d->is_virtual == d->input)) {
- return pmNameConflict;
- }
- }
- }
- if (device_id >= pm_descriptor_max) {
- // expand pm_descriptors
- descriptor_type new_descriptors = (descriptor_type)
- pm_alloc(sizeof(descriptor_node) * (pm_descriptor_max + 32));
- if (!new_descriptors) return pmInsufficientMemory;
- if (pm_descriptors) {
- memcpy(new_descriptors, pm_descriptors,
- sizeof(descriptor_node) * pm_descriptor_max);
- pm_free(pm_descriptors);
- }
- pm_descriptor_max += 32;
- pm_descriptors = new_descriptors;
- }
- if (device_id == pm_descriptor_len) {
- pm_descriptor_len++; /* extending array of pm_descriptors */
- }
- d = &pm_descriptors[device_id].pub;
- d->interf = interf;
- d->name = pm_alloc(strlen(name) + 1);
- if (!d->name) {
- return pmInsufficientMemory;
- }
-#if defined(WIN32) && !defined(_WIN32)
-#pragma warning(suppress: 4996) // don't use suggested strncpy_s
-#endif
- strcpy(d->name, name);
- d->input = is_input;
- d->output = !is_input;
- d->is_virtual = FALSE; /* caller should set to TRUE if this is virtual */
-
- /* default state: nothing to close (for automatic device closing) */
- d->opened = FALSE;
-
- pm_descriptors[device_id].deleted = FALSE;
-
- /* ID number passed to win32 multimedia API open */
- pm_descriptors[device_id].descriptor = descriptor;
-
- /* points to PmInternal, allows automatic device closing */
- pm_descriptors[device_id].pm_internal = NULL;
-
- pm_descriptors[device_id].dictionary = dictionary;
-
- /* set the defaults to the first input and output we see */
- if (is_input && pm_default_input_device_id == -1) {
- pm_default_input_device_id = device_id;
- } else if (!is_input && pm_default_output_device_id == -1) {
- pm_default_output_device_id = device_id;
- }
-
- return device_id;
-}
-
-
-/* Undo a successful call to pm_add_device(). If a new device was
- * allocated, it must be the last device in pm_descriptors, so it is
- * easy to delete by decrementing the length of pm_descriptors, but
- * first free the name (which was copied to the heap). Otherwise,
- * the device must be a virtual device that was created previously
- * and is in the interior of the array of pm_descriptors. Leave it,
- * but mark it as deleted.
- */
-void pm_undo_add_device(int id)
-{
- /* Clear some fields (not all are strictly necessary) */
- pm_descriptors[id].deleted = TRUE;
- pm_descriptors[id].descriptor = NULL;
- pm_descriptors[id].pm_internal = NULL;
-
- if (id == pm_descriptor_len - 1) {
- pm_free(pm_descriptors[id].pub.name);
- pm_descriptor_len--;
- }
-}
-
-
-/* utility to look up device, given a pattern,
- note: pattern is modified
- */
-int Pm_FindDevice(char *pattern, int is_input)
-{
- int id = pmNoDevice;
- int i;
- /* first parse pattern into name, interf parts */
- char *interf_pref = ""; /* initially assume it is not there */
- char *name_pref = strstr(pattern, ", ");
-
- if (name_pref) { /* found separator, adjust the pointer */
- interf_pref = pattern;
- name_pref[0] = 0;
- name_pref += 2;
- } else {
- name_pref = pattern; /* whole string is the name pattern */
- }
- for (i = 0; i < pm_descriptor_len; i++) {
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (info->input == is_input &&
- strstr(info->name, name_pref) &&
- strstr(info->interf, interf_pref)) {
- id = i;
- break;
- }
- }
- return id;
-}
-
-
-/*
-====================================================================
-portmidi implementation
-====================================================================
-*/
-
-PMEXPORT int Pm_CountDevices(void)
-{
- Pm_Initialize();
- /* no error checking -- Pm_Initialize() does not fail */
- return pm_descriptor_len;
-}
-
-
-PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo(PmDeviceID id)
-{
- Pm_Initialize(); /* no error check needed */
- if (id >= 0 && id < pm_descriptor_len && !pm_descriptors[id].deleted) {
- return &pm_descriptors[id].pub;
- }
- return NULL;
-}
-
-/* pm_success_fn -- "noop" function pointer */
-PmError pm_success_fn(PmInternal *midi)
-{
- return pmNoError;
-}
-
-/* none_write -- returns an error if called */
-PmError none_write_short(PmInternal *midi, PmEvent *buffer)
-{
- return pmBadPtr;
-}
-
-/* pm_fail_timestamp_fn -- placeholder for begin_sysex and flush */
-PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp)
-{
- return pmBadPtr;
-}
-
-PmError none_write_byte(PmInternal *midi, unsigned char byte,
- PmTimestamp timestamp)
-{
- return pmBadPtr;
-}
-
-/* pm_fail_fn -- generic function, returns error if called */
-PmError pm_fail_fn(PmInternal *midi)
-{
- return pmBadPtr;
-}
-
-static PmError none_open(PmInternal *midi, void *driverInfo)
-{
- return pmBadPtr;
-}
-
-static unsigned int none_check_host_error(PmInternal * midi)
-{
- return FALSE;
-}
-
-PmTimestamp none_synchronize(PmInternal *midi)
-{
- return 0;
-}
-
-#define none_abort pm_fail_fn
-#define none_close pm_fail_fn
-
-pm_fns_node pm_none_dictionary = {
- none_write_short,
- none_sysex,
- none_sysex,
- none_write_byte,
- none_write_short,
- none_write_flush,
- none_synchronize,
- none_open,
- none_abort,
- none_close,
- none_poll,
- none_check_host_error,
-};
-
-
-PMEXPORT const char *Pm_GetErrorText(PmError errnum)
-{
- const char *msg;
-
- switch(errnum)
- {
- case pmNoError:
- msg = "";
- break;
- case pmHostError:
- msg = "PortMidi: Host error";
- break;
- case pmInvalidDeviceId:
- msg = "PortMidi: Invalid device ID";
- break;
- case pmInsufficientMemory:
- msg = "PortMidi: Insufficient memory";
- break;
- case pmBufferTooSmall:
- msg = "PortMidi: Buffer too small";
- break;
- case pmBadPtr:
- msg = "PortMidi: Bad pointer";
- break;
- case pmInternalError:
- msg = "PortMidi: Internal PortMidi Error";
- break;
- case pmBufferOverflow:
- msg = "PortMidi: Buffer overflow";
- break;
- case pmBadData:
- msg = "PortMidi: Invalid MIDI message Data";
- break;
- case pmBufferMaxSize:
- msg = "PortMidi: Buffer cannot be made larger";
- break;
- case pmNotImplemented:
- msg = "PortMidi: Function is not implemented";
- break;
- case pmInterfaceNotSupported:
- msg = "PortMidi: Interface not supported";
- break;
- case pmNameConflict:
- msg = "PortMidi: Cannot create virtual device: name is taken";
- break;
- case pmDeviceRemoved:
- msg = "PortMidi: Output attempted after (USB) device removed";
- break;
- default:
- msg = "PortMidi: Illegal error number";
- break;
- }
- return msg;
-}
-
-
-/* This can be called whenever you get a pmHostError return value
- * or TRUE from Pm_HasHostError().
- * The error will always be in the global pm_hosterror_text.
- */
-PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len)
-{
- assert(msg);
- assert(len > 0);
- if (pm_hosterror) {
-#if defined(WIN32) && !defined(_WIN32)
-#pragma warning(suppress: 4996) // don't use suggested strncpy_s
-#endif
- strncpy(msg, (char *) pm_hosterror_text, len);
- pm_hosterror = FALSE;
- pm_hosterror_text[0] = 0; /* clear the message; not necessary, but it
- might help with debugging */
- msg[len - 1] = 0; /* make sure string is terminated */
- } else {
- msg[0] = 0; /* no string to return */
- }
-}
-
-
-PMEXPORT int Pm_HasHostError(PortMidiStream * stream)
-{
- if (pm_hosterror) return TRUE;
- if (stream) {
- PmInternal * midi = (PmInternal *) stream;
- return (*midi->dictionary->check_host_error)(midi);
- }
- return FALSE;
-}
-
-
-PMEXPORT PmError Pm_Initialize(void)
-{
- if (!pm_initialized) {
- pm_descriptor_len = 0;
- pm_interf_list_len = 0;
- pm_hosterror = FALSE;
- pm_hosterror_text[0] = 0; /* the null string */
- pm_init();
- pm_initialized = TRUE;
- }
- return pmNoError;
-}
-
-
-PMEXPORT PmError Pm_Terminate(void)
-{
- if (pm_initialized) {
- pm_term();
- /* if there are no devices, pm_descriptors might still be NULL */
- if (pm_descriptors != NULL) {
- int i; /* free names copied into pm_descriptors */
- for (i = 0; i < pm_descriptor_len; i++) {
- if (pm_descriptors[i].pub.name) {
- pm_free(pm_descriptors[i].pub.name);
- }
- }
- pm_free(pm_descriptors);
- pm_descriptors = NULL;
- }
- pm_descriptor_len = 0;
- pm_descriptor_max = 0;
- pm_interf_list_len = 0;
- pm_initialized = FALSE;
- }
- return pmNoError;
-}
-
-
-/* Pm_Read -- read up to length messages from source into buffer */
-/*
- * returns number of messages actually read, or error code
- */
-PMEXPORT int Pm_Read(PortMidiStream *stream, PmEvent *buffer, int32_t length)
-{
- PmInternal *midi = (PmInternal *) stream;
- int n = 0;
- PmError err = pmNoError;
- pm_hosterror = FALSE;
- /* arg checking */
- if(midi == NULL)
- err = pmBadPtr;
- else if(!pm_descriptors[midi->device_id].pub.opened)
- err = pmBadPtr;
- else if(!pm_descriptors[midi->device_id].pub.input)
- err = pmBadPtr;
- /* First poll for data in the buffer...
- * This either simply checks for data, or attempts first to fill the buffer
- * with data from the MIDI hardware; this depends on the implementation.
- * We could call Pm_Poll here, but that would redo a lot of redundant
- * parameter checking, so I copied some code from Pm_Poll to here: */
- else err = (*(midi->dictionary->poll))(midi);
-
- if (err != pmNoError) {
- if (err == pmHostError) {
- midi->dictionary->check_host_error(midi);
- }
- return pm_errmsg(err);
- }
-
- while (n < length) {
- err = Pm_Dequeue(midi->queue, buffer++);
- if (err == pmBufferOverflow) {
- /* ignore the data we have retreived so far */
- return pm_errmsg(pmBufferOverflow);
- } else if (err == 0) { /* empty queue */
- break;
- }
- n++;
- }
- return n;
-}
-
-PMEXPORT PmError Pm_Poll(PortMidiStream *stream)
-{
- PmInternal *midi = (PmInternal *) stream;
- PmError err;
-
- pm_hosterror = FALSE;
- /* arg checking */
- if(midi == NULL)
- err = pmBadPtr;
- else if (!pm_descriptors[midi->device_id].pub.opened)
- err = pmBadPtr;
- else if (!pm_descriptors[midi->device_id].pub.input)
- err = pmBadPtr;
- else
- err = (*(midi->dictionary->poll))(midi);
-
- if (err != pmNoError) {
- return pm_errmsg(err);
- }
-
- return (PmError) !Pm_QueueEmpty(midi->queue);
-}
-
-
-/* this is called from Pm_Write and Pm_WriteSysEx to issue a
- * call to the system-dependent end_sysex function and handle
- * the error return
- */
-static PmError pm_end_sysex(PmInternal *midi)
-{
- PmError err = (*midi->dictionary->end_sysex)(midi, 0);
- midi->sysex_in_progress = FALSE;
- return err;
-}
-
-
-/* to facilitate correct error-handling, Pm_Write, Pm_WriteShort, and
- Pm_WriteSysEx all operate a state machine that "outputs" calls to
- write_short, begin_sysex, write_byte, end_sysex, and write_realtime */
-
-PMEXPORT PmError Pm_Write(PortMidiStream *stream, PmEvent *buffer,
- int32_t length)
-{
- PmInternal *midi = (PmInternal *) stream;
- PmError err = pmNoError;
- int i;
- int bits;
-
- pm_hosterror = FALSE;
- /* arg checking */
- if (midi == NULL) {
- err = pmBadPtr;
- } else {
- descriptor_type desc = &pm_descriptors[midi->device_id];
- if (!desc || !desc->pub.opened ||
- !desc->pub.output || !desc->pm_internal) {
- err = pmBadPtr;
- } else if (desc->pm_internal->is_removed) {
- err = pmDeviceRemoved;
- }
- }
- if (err != pmNoError) goto pm_write_error;
-
- if (midi->latency == 0) {
- midi->now = 0;
- } else {
- midi->now = (*(midi->time_proc))(midi->time_info);
- if (midi->first_message || midi->sync_time + 100 /*ms*/ < midi->now) {
- /* time to resync */
- midi->now = (*midi->dictionary->synchronize)(midi);
- midi->first_message = FALSE;
- }
- }
- /* error recovery: when a sysex is detected, we call
- * dictionary->begin_sysex() followed by calls to
- * dictionary->write_byte() and dictionary->write_realtime()
- * until an end-of-sysex is detected, when we call
- * dictionary->end_sysex(). After an error occurs,
- * Pm_Write() continues to call functions. For example,
- * it will continue to call write_byte() even after
- * an error sending a sysex message, and end_sysex() will be
- * called when an EOX or non-real-time status is found.
- * When errors are detected, Pm_Write() returns immediately,
- * so it is possible that this will drop data and leave
- * sysex messages in a partially transmitted state.
- */
- for (i = 0; i < length; i++) {
- uint32_t msg = buffer[i].message;
- bits = 0;
- /* is this a sysex message? */
- if (Pm_MessageStatus(msg) == MIDI_SYSEX) {
- if (midi->sysex_in_progress) {
- /* error: previous sysex was not terminated by EOX */
- midi->sysex_in_progress = FALSE;
- err = pmBadData;
- goto pm_write_error;
- }
- midi->sysex_in_progress = TRUE;
- if ((err = (*midi->dictionary->begin_sysex)(midi,
- buffer[i].timestamp)) != pmNoError)
- goto pm_write_error;
- if ((err = (*midi->dictionary->write_byte)(midi, MIDI_SYSEX,
- buffer[i].timestamp)) != pmNoError)
- goto pm_write_error;
- bits = 8;
- /* fall through to continue sysex processing */
- } else if ((msg & MIDI_STATUS_MASK) &&
- (Pm_MessageStatus(msg) != MIDI_EOX)) {
- /* a non-sysex message */
- if (midi->sysex_in_progress) {
- /* this should be a realtime message */
- if (is_real_time(msg)) {
- if ((err = (*midi->dictionary->write_realtime)(midi,
- &(buffer[i]))) != pmNoError)
- goto pm_write_error;
- } else {
- midi->sysex_in_progress = FALSE;
- err = pmBadData;
- /* ignore any error from this, because we already have one */
- /* pass 0 as timestamp -- it's ignored */
- (*midi->dictionary->end_sysex)(midi, 0);
- goto pm_write_error;
- }
- } else { /* regular short midi message */
- if ((err = (*midi->dictionary->write_short)(midi,
- &(buffer[i]))) != pmNoError)
- goto pm_write_error;
- continue;
- }
- }
- if (midi->sysex_in_progress) { /* send sysex bytes until EOX */
- /* see if we can accelerate data transfer */
- if (bits == 0 && midi->fill_base && /* 4 bytes to copy */
- (*midi->fill_offset_ptr) + 4 <= midi->fill_length &&
- (msg & 0x80808080) == 0) { /* all data */
- /* copy 4 bytes from msg to fill_base + fill_offset */
- unsigned char *ptr = midi->fill_base +
- *(midi->fill_offset_ptr);
- ptr[0] = msg; ptr[1] = msg >> 8;
- ptr[2] = msg >> 16; ptr[3] = msg >> 24;
- (*midi->fill_offset_ptr) += 4;
- continue;
- }
- /* no acceleration, so do byte-by-byte copying */
- while (bits < 32) {
- unsigned char midi_byte = (unsigned char) (msg >> bits);
- if ((err = (*midi->dictionary->write_byte)(midi, midi_byte,
- buffer[i].timestamp)) != pmNoError)
- goto pm_write_error;
- if (midi_byte == MIDI_EOX) {
- err = pm_end_sysex(midi);
- if (err != pmNoError) goto error_exit;
- break; /* from while loop */
- }
- bits += 8;
- }
- } else {
- /* not in sysex mode, but message did not start with status */
- err = pmBadData;
- goto pm_write_error;
- }
- }
- /* after all messages are processed, send the data */
- if (!midi->sysex_in_progress)
- err = (*midi->dictionary->write_flush)(midi, 0);
-pm_write_error:
- if (err == pmHostError) {
- midi->dictionary->check_host_error(midi);
- }
-error_exit:
- return pm_errmsg(err);
-}
-
-
-PMEXPORT PmError Pm_WriteShort(PortMidiStream *stream, PmTimestamp when,
- PmMessage msg)
-{
- PmEvent event;
-
- event.timestamp = when;
- event.message = msg;
- return Pm_Write(stream, &event, 1);
-}
-
-
-PMEXPORT PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when,
- unsigned char *msg)
-{
- /* allocate buffer space for PM_DEFAULT_SYSEX_BUFFER_SIZE bytes */
- /* each PmEvent holds sizeof(PmMessage) bytes of sysex data */
- #define BUFLEN ((int) (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage)))
- PmEvent buffer[BUFLEN];
- int buffer_size = 1; /* first time, send 1. After that, it's BUFLEN */
- PmInternal *midi = (PmInternal *) stream;
- PmError err = pmNoError;
- /* the next byte in the buffer is represented by an index, bufx, and
- a shift in bits */
- int shift = 0;
- int bufx = 0;
- buffer[0].message = 0;
- buffer[0].timestamp = when;
-
- while (1) {
- /* insert next byte into buffer */
- buffer[bufx].message |= ((*msg) << shift);
- shift += 8;
- if (*msg++ == MIDI_EOX) break;
- if (shift == 32) {
- shift = 0;
- bufx++;
- if (bufx == buffer_size) {
- err = Pm_Write(stream, buffer, buffer_size);
- /* note: Pm_Write has already called errmsg() */
- if (err) return err;
- /* prepare to fill another buffer */
- bufx = 0;
- buffer_size = BUFLEN;
- /* optimization: maybe we can just copy bytes */
- if (midi->fill_base) {
- while (*(midi->fill_offset_ptr) < midi->fill_length) {
- midi->fill_base[(*midi->fill_offset_ptr)++] = *msg;
- if (*msg++ == MIDI_EOX) {
- err = pm_end_sysex(midi);
- if (err != pmNoError) return pm_errmsg(err);
- goto end_of_sysex;
- }
- }
- /* I thought that I could do a pm_Write here and
- * change this if to a loop, avoiding calls in Pm_Write
- * to the slower write_byte, but since
- * sysex_in_progress is true, this will not flush
- * the buffer, and we'll infinite loop: */
- /* err = Pm_Write(stream, buffer, 0);
- if (err) return err; */
- /* instead, the way this works is that Pm_Write calls
- * write_byte on 4 bytes. The first, since the buffer
- * is full, will flush the buffer and allocate a new
- * one. This primes the buffer so
- * that we can return to the loop above and fill it
- * efficiently without a lot of function calls.
- */
- buffer_size = 1; /* get another message started */
- }
- }
- buffer[bufx].message = 0;
- buffer[bufx].timestamp = when;
- }
- /* keep inserting bytes until you find MIDI_EOX */
- }
-end_of_sysex:
- /* we're finished sending full buffers, but there may
- * be a partial one left.
- */
- if (shift != 0) bufx++; /* add partial message to buffer len */
- if (bufx) { /* bufx is number of PmEvents to send from buffer */
- err = Pm_Write(stream, buffer, bufx);
- if (err) return err;
- }
- return pmNoError;
-}
-
-
-
-PmError pm_create_internal(PmInternal **stream, PmDeviceID device_id,
- int is_input, int latency, PmTimeProcPtr time_proc,
- void *time_info, int buffer_size)
-{
- PmInternal *midi;
- if (device_id < 0 || device_id >= pm_descriptor_len) {
- return pmInvalidDeviceId;
- }
- if (latency < 0) { /* force a legal value */
- latency = 0;
- }
- /* create portMidi internal data */
- midi = (PmInternal *) pm_alloc(sizeof(PmInternal));
- *stream = midi;
- if (!midi) {
- return pmInsufficientMemory;
- }
- midi->device_id = device_id;
- midi->is_input = is_input;
- midi->is_removed = FALSE;
- midi->time_proc = time_proc;
- /* if latency != 0, we need a time reference for output.
- we always need a time reference for input.
- If none is provided, use PortTime library */
- if (time_proc == NULL && (latency != 0 || is_input)) {
- if (!Pt_Started())
- Pt_Start(1, 0, 0);
- /* time_get does not take a parameter, so coerce */
- midi->time_proc = (PmTimeProcPtr) Pt_Time;
- }
- midi->time_info = time_info;
- if (is_input) {
- midi->latency = 0; /* unused by input */
- if (buffer_size <= 0) buffer_size = 256; /* default buffer size */
- midi->queue = Pm_QueueCreate(buffer_size, (int32_t) sizeof(PmEvent));
- if (!midi->queue) {
- /* free portMidi data */
- *stream = NULL;
- pm_free(midi);
- return pmInsufficientMemory;
- }
- } else {
- /* if latency zero, output immediate (timestamps ignored) */
- /* if latency < 0, use 0 but don't return an error */
- if (latency < 0) latency = 0;
- midi->latency = latency;
- midi->queue = NULL; /* unused by output; input needs to allocate: */
- }
- midi->buffer_len = buffer_size; /* portMidi input storage */
- midi->sysex_in_progress = FALSE;
- midi->message = 0;
- midi->message_count = 0;
- midi->filters = (is_input ? PM_FILT_ACTIVE : 0);
- midi->channel_mask = 0xFFFF;
- midi->sync_time = 0;
- midi->first_message = TRUE;
- midi->api_info = NULL;
- midi->fill_base = NULL;
- midi->fill_offset_ptr = NULL;
- midi->fill_length = 0;
- midi->dictionary = pm_descriptors[device_id].dictionary;
- pm_descriptors[device_id].pm_internal = midi;
- return pmNoError;
-}
-
-
-PMEXPORT PmError Pm_OpenInput(PortMidiStream** stream,
- PmDeviceID inputDevice,
- void *inputDriverInfo,
- int32_t bufferSize,
- PmTimeProcPtr time_proc,
- void *time_info)
-{
- PmInternal *midi;
- PmError err = pmNoError;
- pm_hosterror = FALSE;
- *stream = NULL; /* invariant: *stream == midi */
-
- /* arg checking */
- if (!pm_descriptors[inputDevice].pub.input)
- err = pmInvalidDeviceId;
- else if (pm_descriptors[inputDevice].pub.opened)
- err = pmInvalidDeviceId;
- if (err != pmNoError)
- goto error_return;
-
- /* common initialization of PmInternal structure (midi): */
- err = pm_create_internal(&midi, inputDevice, TRUE, 0, time_proc,
- time_info, bufferSize);
- *stream = midi;
- if (err) {
- goto error_return;
- }
-
- /* open system dependent input device */
- err = (*midi->dictionary->open)(midi, inputDriverInfo);
- if (err) {
- *stream = NULL;
- pm_descriptors[inputDevice].pm_internal = NULL;
- /* free portMidi data */
- Pm_QueueDestroy(midi->queue);
- pm_free(midi);
- } else {
- /* portMidi input open successful */
- pm_descriptors[inputDevice].pub.opened = TRUE;
- }
-error_return:
- /* note: if there is a pmHostError, it is the responsibility
- * of the system-dependent code (*midi->dictionary->open)()
- * to set pm_hosterror and pm_hosterror_text
- */
- return pm_errmsg(err);
-}
-
-
-PMEXPORT PmError Pm_OpenOutput(PortMidiStream** stream,
- PmDeviceID outputDevice,
- void *outputDriverInfo,
- int32_t bufferSize,
- PmTimeProcPtr time_proc,
- void *time_info,
- int32_t latency)
-{
- PmInternal *midi;
- PmError err = pmNoError;
- pm_hosterror = FALSE;
- *stream = NULL;
-
- /* arg checking */
- if (outputDevice < 0 || outputDevice >= pm_descriptor_len)
- err = pmInvalidDeviceId;
- else if (!pm_descriptors[outputDevice].pub.output)
- err = pmInvalidDeviceId;
- else if (pm_descriptors[outputDevice].pub.opened)
- err = pmInvalidDeviceId;
- if (err != pmNoError)
- goto error_return;
-
- /* common initialization of PmInternal structure (midi): */
- err = pm_create_internal(&midi, outputDevice, FALSE, latency, time_proc,
- time_info, bufferSize);
- *stream = midi;
- if (err) {
- goto error_return;
- }
-
- /* open system dependent output device */
- err = (*midi->dictionary->open)(midi, outputDriverInfo);
- if (err) {
- *stream = NULL;
- pm_descriptors[outputDevice].pm_internal = NULL;
- /* free portMidi data */
- pm_free(midi);
- } else {
- /* portMidi input open successful */
- pm_descriptors[outputDevice].pub.opened = TRUE;
- }
-error_return:
- /* note: system-dependent code must set pm_hosterror and
- * pm_hosterror_text if a pmHostError occurs
- */
- return pm_errmsg(err);
-}
-
-
-static PmError create_virtual_device(const char *name, const char *interf,
- void *device_info, int is_input)
-{
- PmError err = pmNoError;
- int i;
- pm_hosterror = FALSE;
-
- /* arg checking */
- if (!name) {
- err = pmInvalidDeviceId;
- goto error_return;
- }
-
- Pm_Initialize(); /* just in case */
-
- /* create the virtual device */
- if (pm_interf_list_len == 0) {
- return pmNotImplemented;
- }
- if (!interf) {
- /* default interface is the first one */
- interf = pm_interf_list[0].interf;
- }
- /* look up and call the create_fn for interf(ace), e.g. "CoreMIDI" */
- for (i = 0; i < pm_interf_list_len; i++) {
- if (strcmp(pm_interf_list[i].interf, interf) == 0) {
- int id = (*pm_interf_list[i].create_fn)(is_input,
- name, device_info);
- /* id could be pmNameConflict or an actual descriptor index */
- if (id >= 0) {
- pm_descriptors[id].pub.is_virtual = TRUE;
- }
- err = id;
- goto error_return;
- }
- }
- err = pmInterfaceNotSupported;
-
-error_return:
- /* note: if there is a pmHostError, it is the responsibility
- * of the system-dependent code (*midi->dictionary->open)()
- * to set pm_hosterror and pm_hosterror_text
- */
- return pm_errmsg(err);
-}
-
-
-PMEXPORT PmError Pm_CreateVirtualInput(const char *name,
- const char *interf,
- void *deviceInfo)
-{
- return create_virtual_device(name, interf, deviceInfo, TRUE);
-}
-
-PMEXPORT PmError Pm_CreateVirtualOutput(const char *name, const char *interf,
- void *deviceInfo)
-{
- return create_virtual_device(name, interf, deviceInfo, FALSE);
-}
-
-PmError Pm_DeleteVirtualDevice(PmDeviceID id)
-{
- int i;
- const char *interf = pm_descriptors[id].pub.interf;
- PmError err = pmBadData; /* returned if we cannot find the interface-
- * specific delete function */
- /* arg checking */
- if (id < 0 || id >= pm_descriptor_len ||
- pm_descriptors[id].pub.opened || pm_descriptors[id].deleted) {
- return pmInvalidDeviceId;
- }
- /* delete function pointer is in interfaces list */
- for (i = 0; i < pm_interf_list_len; i++) {
- if (strcmp(pm_interf_list[i].interf, interf) == 0) {
- err = (*pm_interf_list[i].delete_fn)(id);
- break;
- }
- }
- pm_descriptors[id].deleted = TRUE;
- /* (pm_internal should already be NULL because !pub.opened) */
- pm_descriptors[id].pm_internal = NULL;
- pm_descriptors[id].descriptor = NULL;
- return err;
-}
-
-PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
-{
- PmInternal *midi = (PmInternal *) stream;
- PmError err = pmNoError;
-
- if (midi == NULL)
- err = pmBadPtr;
- else
- midi->channel_mask = mask;
-
- return pm_errmsg(err);
-}
-
-
-PMEXPORT PmError Pm_SetFilter(PortMidiStream *stream, int32_t filters)
-{
- PmInternal *midi = (PmInternal *) stream;
- PmError err = pmNoError;
-
- /* arg checking */
- if (midi == NULL)
- err = pmBadPtr;
- else if (!pm_descriptors[midi->device_id].pub.opened)
- err = pmBadPtr;
- else
- midi->filters = filters;
- return pm_errmsg(err);
-}
-
-
-PMEXPORT PmError Pm_Close(PortMidiStream *stream)
-{
- PmInternal *midi = (PmInternal *) stream;
- PmError err = pmNoError;
-
- pm_hosterror = FALSE;
- /* arg checking */
- if (midi == NULL) /* midi must point to something */
- err = pmBadPtr;
- /* if it is an open device, the device_id will be valid */
- else if (midi->device_id < 0 || midi->device_id >= pm_descriptor_len)
- err = pmBadPtr;
- /* and the device should be in the opened state */
- else if (!pm_descriptors[midi->device_id].pub.opened)
- err = pmBadPtr;
-
- if (err != pmNoError)
- goto error_return;
-
- /* close the device */
- err = (*midi->dictionary->close)(midi);
- /* even if an error occurred, continue with cleanup */
- pm_descriptors[midi->device_id].pm_internal = NULL;
- pm_descriptors[midi->device_id].pub.opened = FALSE;
- if (midi->queue) Pm_QueueDestroy(midi->queue);
- pm_free(midi);
-error_return:
- /* system dependent code must set pm_hosterror and
- * pm_hosterror_text if a pmHostError occurs.
- */
- return pm_errmsg(err);
-}
-
-PmError Pm_Synchronize(PortMidiStream* stream)
-{
- PmInternal *midi = (PmInternal *) stream;
- PmError err = pmNoError;
- if (midi == NULL)
- err = pmBadPtr;
- else if (!pm_descriptors[midi->device_id].pub.output)
- err = pmBadPtr;
- else if (!pm_descriptors[midi->device_id].pub.opened)
- err = pmBadPtr;
- else
- midi->first_message = TRUE;
- return err;
-}
-
-PMEXPORT PmError Pm_Abort(PortMidiStream* stream)
-{
- PmInternal *midi = (PmInternal *) stream;
- PmError err;
- /* arg checking */
- if (midi == NULL)
- err = pmBadPtr;
- else if (!pm_descriptors[midi->device_id].pub.output)
- err = pmBadPtr;
- else if (!pm_descriptors[midi->device_id].pub.opened)
- err = pmBadPtr;
- else
- err = (*midi->dictionary->abort)(midi);
-
- if (err == pmHostError) {
- midi->dictionary->check_host_error(midi);
- }
- return pm_errmsg(err);
-}
-
-
-
-/* pm_channel_filtered returns non-zero if the channel mask is
- blocking the current channel */
-#define pm_channel_filtered(status, mask) \
- ((((status) & 0xF0) != 0xF0) && (!(Pm_Channel((status) & 0x0F) & (mask))))
-
-
-/* The following two functions will checks to see if a MIDI message
- matches the filtering criteria. Since the sysex routines only want
- to filter realtime messages, we need to have separate routines.
- */
-
-
-/* pm_realtime_filtered returns non-zero if the filter will kill the
- current message. Note that only realtime messages are checked here.
- */
-#define pm_realtime_filtered(status, filters) \
- ((((status) & 0xF0) == 0xF0) && ((1 << ((status) & 0xF)) & (filters)))
-
-/*
- return ((status == MIDI_ACTIVE) && (filters & PM_FILT_ACTIVE))
- || ((status == MIDI_CLOCK) && (filters & PM_FILT_CLOCK))
- || ((status == MIDI_START) && (filters & PM_FILT_PLAY))
- || ((status == MIDI_STOP) && (filters & PM_FILT_PLAY))
- || ((status == MIDI_CONTINUE) && (filters & PM_FILT_PLAY))
- || ((status == MIDI_F9) && (filters & PM_FILT_F9))
- || ((status == MIDI_FD) && (filters & PM_FILT_FD))
- || ((status == MIDI_RESET) && (filters & PM_FILT_RESET))
- || ((status == MIDI_MTC) && (filters & PM_FILT_MTC))
- || ((status == MIDI_SONGPOS) && (filters & PM_FILT_SONG_POSITION))
- || ((status == MIDI_SONGSEL) && (filters & PM_FILT_SONG_SELECT))
- || ((status == MIDI_TUNE) && (filters & PM_FILT_TUNE));
-}*/
-
-
-/* pm_status_filtered returns non-zero if a filter will kill the
- current message, based on status. Note that sysex and real time are
- not checked. It is up to the subsystem (winmm, core midi, alsa) to
- filter sysex, as it is handled more easily and efficiently at that
- level. Realtime message are filtered in pm_realtime_filtered.
- */
-#define pm_status_filtered(status, filters) \
- ((1 << (16 + ((status) >> 4))) & (filters))
-
-
-/*
- return ((status == MIDI_NOTE_ON) && (filters & PM_FILT_NOTE))
- || ((status == MIDI_NOTE_OFF) && (filters & PM_FILT_NOTE))
- || ((status == MIDI_CHANNEL_AT) &&
- (filters & PM_FILT_CHANNEL_AFTERTOUCH))
- || ((status == MIDI_POLY_AT) && (filters & PM_FILT_POLY_AFTERTOUCH))
- || ((status == MIDI_PROGRAM) && (filters & PM_FILT_PROGRAM))
- || ((status == MIDI_CONTROL) && (filters & PM_FILT_CONTROL))
- || ((status == MIDI_PITCHBEND) && (filters & PM_FILT_PITCHBEND));
-
-}
-*/
-
-static void pm_flush_sysex(PmInternal *midi, PmTimestamp timestamp)
-{
- PmEvent event;
-
- /* there may be nothing in the buffer */
- if (midi->message_count == 0) return; /* nothing to flush */
-
- event.message = midi->message;
- event.timestamp = timestamp;
- /* copied from pm_read_short, avoids filtering */
- if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
- midi->sysex_in_progress = FALSE;
- }
- midi->message_count = 0;
- midi->message = 0;
-}
-
-
-/* pm_read_short and pm_read_bytes
- are the interface between system-dependent MIDI input handlers
- and the system-independent PortMIDI code.
- The input handler MUST obey these rules:
- 1) all short input messages must be sent to pm_read_short, which
- enqueues them to a FIFO for the application.
- 2) each buffer of sysex bytes should be reported by calling pm_read_bytes
- (which sets midi->sysex_in_progress). After the eox byte,
- pm_read_bytes will clear sysex_in_progress
- */
-
-/* pm_read_short is the place where all input messages arrive from
- system-dependent code such as pmwinmm.c. Here, the messages
- are entered into the PortMidi input buffer.
- */
-void pm_read_short(PmInternal *midi, PmEvent *event)
-{
- int status;
- /* arg checking */
- assert(midi != NULL);
- /* midi filtering is applied here */
- status = Pm_MessageStatus(event->message);
- if (!pm_status_filtered(status, midi->filters)
- && (!is_real_time(status) ||
- !pm_realtime_filtered(status, midi->filters))
- && !pm_channel_filtered(status, midi->channel_mask)) {
- /* if sysex is in progress and we get a status byte, it had
- better be a realtime message or the starting SYSEX byte;
- otherwise, we exit the sysex_in_progress state
- */
- if (midi->sysex_in_progress && (status & MIDI_STATUS_MASK)) {
- /* two choices: real-time or not. If it's real-time, then
- * this should be delivered as a sysex byte because it is
- * embedded in a sysex message
- */
- if (is_real_time(status)) {
- midi->message |= (status << (8 * midi->message_count++));
- if (midi->message_count == 4) {
- pm_flush_sysex(midi, event->timestamp);
- }
- } else { /* otherwise, it's not real-time. This interrupts
- * a sysex message in progress */
- midi->sysex_in_progress = FALSE;
- }
- } else if (Pm_Enqueue(midi->queue, event) == pmBufferOverflow) {
- midi->sysex_in_progress = FALSE;
- }
- }
-}
-
-
-/* pm_read_bytes -- a sequence of bytes has been read from a device.
- * parse the bytes into PmEvents and put them in the queue.
- * midi - the midi device
- * data - the bytes
- * len - the number of bytes
- * timestamp - when were the bytes received?
- *
- * returns how many bytes processed, which is always the len parameter
- */
-unsigned int pm_read_bytes(PmInternal *midi, const unsigned char *data,
- int len, PmTimestamp timestamp)
-{
- int i = 0; /* index into data, must not be unsigned (!) */
- PmEvent event;
- event.timestamp = timestamp;
- assert(midi);
-
- /* Since sysex messages may have embedded real-time messages, we
- * cannot simply send every consecutive group of 4 bytes as sysex
- * data. Instead, we insert each data byte into midi->message and
- * keep count using midi->message_count. If we encounter a
- * real-time message, it is sent immediately as a 1-byte PmEvent,
- * while sysex bytes are sent as PmEvents in groups of 4 bytes
- * until the sysex is either terminated by EOX (F7) or a
- * non-real-time message is encountered, indicating that the EOX
- * was dropped.
- */
-
- /* This is a finite state machine so that we can accept any number
- * of bytes, even if they contain partial messages.
- *
- * midi->sysex_in_progress says we are expecting sysex message bytes
- * (otherwise, expect a short message or real-time message)
- * midi->message accumulates bytes to enqueue for application
- * midi->message_count is the number of bytes accumulated
- * midi->short_message_count is how many bytes we need in midi->message,
- * therefore midi->message_count, before we have a complete message
- * midi->running_status is running status or 0 if there is none
- *
- * Set running status when: A status byte < F0 is received.
- * Clear running status when: A status byte from F0 through F7 is
- * received.
- * Ignore (drop) data bytes when running status is 0.
- *
- * Our output buffer (the application input buffer) can overflow
- * at any time. If that occurs, we have to clear sysex_in_progress
- * (otherwise, the buffer could be flushed and we could resume
- * inserting sysex bytes into the buffer, resulting in a continuation
- * of a sysex message even though a buffer full of bytes was dropped.)
- *
- * Since we have to parse everything and form <=4-byte PmMessages,
- * we send all messages via pm_read_short, which filters messages
- * according to midi->filters and clears sysex_in_progress on
- * buffer overflow. This also provides a "short cut" for short
- * messages that are already parsed, allowing API-specific code
- * to bypass this more expensive state machine. What if we are
- * getting a sysex message, but it is interrupted by a short
- * message (status 80-EF) and a direct call to pm_read_short?
- * Without some care, the state machine would still be in
- * sysex_in_progress mode, and subsequent data bytes would be
- * accumulated as more sysex data, which is wrong since you
- * cannot have a short message in the middle of a sysex message.
- * To avoid this problem, pm_read_short clears sysex_in_progress
- * when a non-real-time short message arrives.
- */
-
- while (i < len) {
- unsigned char byte = data[i++];
- if (is_real_time(byte)) {
- event.message = byte;
- pm_read_short(midi, &event);
- } else if (byte & MIDI_STATUS_MASK && byte != MIDI_EOX) {
- midi->message = byte;
- midi->message_count = 1;
- if (byte == MIDI_SYSEX) {
- midi->sysex_in_progress = TRUE;
- } else {
- midi->sysex_in_progress = FALSE;
- midi->short_message_count = pm_midi_length(midi->message);
- /* maybe we're done already with a 1-byte message: */
- if (midi->short_message_count == 1) {
- pm_read_short(midi, &event);
- midi->message_count = 0;
- }
- }
- } else if (midi->sysex_in_progress) { /* sysex data byte */
- /* accumulate sysex message data or EOX */
- midi->message |= (byte << (8 * midi->message_count++));
- if (midi->message_count == 4 || byte == MIDI_EOX) {
- event.message = midi->message;
- /* enqueue if not filtered, and then if there is overflow,
- stop sysex_in_progress */
- if (!(midi->filters & PM_FILT_SYSEX) &&
- Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
- midi->sysex_in_progress = FALSE;
- } else if (byte == MIDI_EOX) { /* continue unless EOX */
- midi->sysex_in_progress = FALSE;
- }
- midi->message_count = 0;
- midi->message = 0;
- }
- } else { /* no sysex in progress, must be short message */
- if (midi->message_count == 0) { /* need a running status */
- if (midi->running_status) {
- midi->message = midi->running_status;
- midi->message_count = 1;
- } else { /* drop data byte - not sysex and no status byte */
- continue;
- }
- }
- midi->message |= (byte << (8 * midi->message_count++));
- if (midi->message_count == midi->short_message_count) {
- event.message = midi->message;
- pm_read_short(midi, &event);
- }
- }
- }
- return i;
-}
diff --git a/portmidi/pm_common/portmidi.h b/portmidi/pm_common/portmidi.h
deleted file mode 100755
index 8696a73..0000000
--- a/portmidi/pm_common/portmidi.h
+++ /dev/null
@@ -1,974 +0,0 @@
-#ifndef PORTMIDI_PORTMIDI_H
-#define PORTMIDI_PORTMIDI_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/*
- * PortMidi Portable Real-Time MIDI Library
- * PortMidi API Header File
- * Latest version available at: http://sourceforge.net/projects/portmedia
- *
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- * Copyright (c) 2001-2006 Roger B. Dannenberg
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS 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.
- */
-
-/*
- * The text above constitutes the entire PortMidi license; however,
- * the PortMusic community also makes the following non-binding requests:
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version. It is also
- * requested that these non-binding requests be included along with the
- * license above.
- */
-
-/* CHANGELOG FOR PORTMIDI
- * (see ../CHANGELOG.txt)
- *
- * NOTES ON HOST ERROR REPORTING:
- *
- * PortMidi errors (of type PmError) are generic,
- * system-independent errors. When an error does not map to one of
- * the more specific PmErrors, the catch-all code pmHostError is
- * returned. This means that PortMidi has retained a more specific
- * system-dependent error code. The caller can get more information
- * by calling Pm_GetHostErrorText() to get a text string describing
- * the error. Host errors can arise asynchronously from callbacks,
- * * so there is no specific return code. Asynchronous errors are
- * checked and reported by Pm_Poll. You can also check by calling
- * Pm_HasHostError(). If this returns TRUE, Pm_GetHostErrorText()
- * will return a text description of the error.
- *
- * NOTES ON COMPILE-TIME SWITCHES
- *
- * DEBUG assumes stdio and a console. Use this if you want
- * automatic, simple error reporting, e.g. for prototyping. If
- * you are using MFC or some other graphical interface with no
- * console, DEBUG probably should be undefined.
- * PM_CHECK_ERRORS more-or-less takes over error checking for
- * return values, stopping your program and printing error
- * messages when an error occurs. This also uses stdio for
- * console text I/O. You can selectively disable this error
- * checking by declaring extern int pm_check_errors; and
- * setting pm_check_errors = FALSE; You can also reenable.
- */
-/**
- \defgroup grp_basics Basic Definitions
- @{
-*/
-
-#include <stdint.h>
-
-#ifdef _WINDLL
-#define PMEXPORT __declspec(dllexport)
-#else
-#define PMEXPORT
-#endif
-
-#ifndef FALSE
- #define FALSE 0
-#endif
-#ifndef TRUE
- #define TRUE 1
-#endif
-
-/* default size of buffers for sysex transmission: */
-#define PM_DEFAULT_SYSEX_BUFFER_SIZE 1024
-
-
-typedef enum {
- pmNoError = 0, /**< Normal return value indicating no error. */
- pmNoData = 0, /**< @brief No error, also indicates no data available.
- * Use this constant where a value greater than zero would
- * indicate data is available.
- */
- pmGotData = 1, /**< A "no error" return also indicating data available. */
- pmHostError = -10000,
- pmInvalidDeviceId, /**< Out of range or
- * output device when input is requested or
- * input device when output is requested or
- * device is already opened.
- */
- pmInsufficientMemory,
- pmBufferTooSmall,
- pmBufferOverflow,
- pmBadPtr, /**< #PortMidiStream parameter is NULL or
- * stream is not opened or
- * stream is output when input is required or
- * stream is input when output is required. */
- pmBadData, /**< Illegal midi data, e.g., missing EOX. */
- pmInternalError,
- pmBufferMaxSize, /**< Buffer is already as large as it can be. */
- pmNotImplemented, /**< The function is not implemented, nothing was done. */
- pmInterfaceNotSupported, /**< The requested interface is not supported. */
- pmNameConflict, /**< Cannot create virtual device because name is taken. */
- pmDeviceRemoved /**< Output attempted after (USB) device was removed. */
- /* NOTE: If you add a new error type, you must update Pm_GetErrorText(). */
-} PmError; /**< @brief @enum PmError PortMidi error code; a common return type.
- * No error is indicated by zero; errors are indicated by < 0.
- */
-
-/**
- Pm_Initialize() is the library initialization function - call this before
- using the library.
-
- *NOTE:* PortMidi scans for available devices when #Pm_Initialize
- is called. To observe subsequent changes in the available
- devices, you must shut down PortMidi by calling #Pm_Terminate and
- then restart by calling #Pm_Initialize again. *IMPORTANT*: On
- MacOS, #Pm_Initialize *must* always be called on the same
- thread. Otherwise, changes in the available MIDI devices will
- *not* be seen by PortMidi. As an example, if you start PortMidi in
- a thread for processing MIDI, do not try to rescan devices by
- calling #Pm_Initialize in a GUI thread. Instead, start PortMidi
- the first time and every time in the GUI thread. Alternatively,
- let the GUI request a restart in the MIDI thread. (These
- restrictions only apply to macOS.) Speaking of threads, on all
- platforms, you are allowed to call #Pm_Initialize in one thread,
- yet send MIDI or poll for incoming MIDI in another
- thread. However, PortMidi is not "thread safe," which means you
- cannot allow threads to call PortMidi functions concurrently.
-
- @return pmNoError.
-
- PortMidi is designed to support multiple interfaces (such as ALSA,
- CoreMIDI and WinMM). It is possible to return pmNoError because there
- are no supported interfaces. In that case, zero devices will be
- available.
-*/
-PMEXPORT PmError Pm_Initialize(void);
-
-/**
- Pm_Terminate() is the library termination function - call this after
- using the library.
-*/
-PMEXPORT PmError Pm_Terminate(void);
-
-/** Represents an open MIDI device. */
-typedef void PortMidiStream;
-
-/** A shorter form of #PortMidiStream. */
-#define PmStream PortMidiStream
-
-/** Test whether stream has a pending host error. Normally, the client
- finds out about errors through returned error codes, but some
- errors can occur asynchronously where the client does not
- explicitly call a function, and therefore cannot receive an error
- code. The client can test for a pending error using
- Pm_HasHostError(). If true, the error can be accessed by calling
- Pm_GetHostErrorText(). Pm_Poll() is similar to Pm_HasHostError(),
- but if there is no error, it will return TRUE (1) if there is a
- pending input message.
-*/
-PMEXPORT int Pm_HasHostError(PortMidiStream * stream);
-
-
-/** Translate portmidi error number into human readable message.
- These strings are constants (set at compile time) so client has
- no need to allocate storage.
-*/
-PMEXPORT const char *Pm_GetErrorText(PmError errnum);
-
-/** Translate portmidi host error into human readable message.
- These strings are computed at run time, so client has to allocate storage.
- After this routine executes, the host error is cleared.
-*/
-PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len);
-
-/** Any host error msg has at most this many characters, including EOS. */
-#define PM_HOST_ERROR_MSG_LEN 256u
-
-/** Devices are represented as small integers. Device ids range from 0
- to Pm_CountDevices()-1. Pm_GetDeviceInfo() is used to get information
- about the device, and Pm_OpenInput() and PmOpenOutput() are used to
- open the device.
-*/
-typedef int PmDeviceID;
-
-/** This PmDeviceID (constant) value represents no device and may be
- returned by Pm_GetDefaultInputDeviceID() or
- Pm_GetDefaultOutputDeviceID() if no default exists.
-*/
-#define pmNoDevice -1
-
-/** MIDI device information is returned in this structure, which is
- owned by PortMidi and read-only to applications. See Pm_GetDeviceInfo().
-*/
-#define PM_DEVICEINFO_VERS 200
-typedef struct {
- int structVersion; /**< @brief this internal structure version */
- const char *interf; /**< @brief underlying MIDI API, e.g.
- "MMSystem" or "DirectX" */
- char *name; /**< @brief device name, e.g. "USB MidiSport 1x1" */
- int input; /**< @brief true iff input is available */
- int output; /**< @brief true iff output is available */
- int opened; /**< @brief used by generic PortMidi for error checking */
- int is_virtual; /**< @brief true iff this is/was a virtual device */
-} PmDeviceInfo;
-
-/** MIDI system-dependent device or driver info is passed in this
- structure, which is owned by the caller.
-*/
-#define PM_SYSDEPINFO_VERS 210
-
-enum PmSysDepPropertyKey {
- pmKeyNone = 0, /**< a "noop" key value */
- /** CoreMIDI Manufacturer name, value is string */
- pmKeyCoreMidiManufacturer = 1,
- /** Linux ALSA snd_seq_port_info_set_name, value is a string. Can be
- passed in PmSysDepInfo to Pm_OpenInput or Pm_OpenOutput when opening
- a device. The created port will be named accordingly and will be
- visible for externally made connections (subscriptions). (Linux ALSA
- ports are always enabled for this, but only get application-specific
- names if you give it one.) This key/value is ignored when opening
- virtual ports, which are named when they are created.) */
- pmKeyAlsaPortName = 2,
- /** Linux ALSA snd_seq_set_client_name, value is a string.
- Can be passed in PmSysDepInfo to Pm_OpenInput or Pm_OpenOutput.
- Pm_CreateVirtualInput or Pm_CreateVirtualOutput. Will override
- any previously set client name and applies to all ports. */
- pmKeyAlsaClientName = 3
- /* if system-dependent code introduces more options, register
- the key here to avoid conflicts. */
-};
-
-/** System-dependent information can be passed when creating and opening
- ports using this data structure, which stores alternating keys and
- values (addresses). See `pm_test/sendvirtual.c`, `pm_test/recvvirtual.c`,
- and `pm_test/testio.c` for examples.
- */
-typedef struct {
- int structVersion; /**< @brief this structure version */
- int length; /**< @brief number of properties in this structure */
- struct {
- enum PmSysDepPropertyKey key;
- const void *value;
- } properties[];
-} PmSysDepInfo;
-
-
-/** Get devices count, ids range from 0 to Pm_CountDevices()-1. */
-PMEXPORT int Pm_CountDevices(void);
-
-/**
- Return the default device ID or pmNoDevice if there are no devices.
- The result (but not pmNoDevice) can be passed to Pm_OpenMidi().
-
- The use of these functions is not recommended. There is no natural
- "default device" on any system, so defaults must be set by users.
- (Currently, PortMidi just returns the first device it finds as
- "default", so if there *is* a default, implementors should use
- pm_add_device to add system default input and output devices
- first.)
-
- The recommended solution is pass the burden to applications. It is
- easy to scan devices with PortMidi and build a device menu, and to
- save menu selections in application preferences for next
- time. This is my recommendation for any GUI program. For simple
- command-line applications and utilities, see pm_test where all the
- test programs now accept device numbers on the command line and/or
- prompt for their entry.
-
- On linux, you can create virtual ports and use an external program
- to set up inter-application and device connections.
-
- Some advice for preferences: MIDI devices used to be built-in or
- plug-in cards, so the numbers rarely changed. Now MIDI devices are
- often plug-in USB devices, so device numbers change, and you
- probably need to design to reinitialize PortMidi to rescan
- devices. MIDI is pretty stateless, so this isn't a big problem,
- although it means you cannot find a new device while playing or
- recording MIDI.
-
- Since device numbering can change whenever a USB device is plugged
- in, preferences should record *names* of devices rather than
- device numbers. It is simple enough to use string matching to find
- a prefered device, so PortMidi does not provide any built-in
- lookup function.
-*/
-PMEXPORT PmDeviceID Pm_GetDefaultInputDeviceID(void);
-
-/** @brief see PmDeviceID Pm_GetDefaultInputDeviceID() */
-PMEXPORT PmDeviceID Pm_GetDefaultOutputDeviceID(void);
-
-/** Find a device that matches a pattern.
-
- @param pattern a substring of the device name, or if the pattern
- contains the two-character separator ", ", then the first part of
- the pattern represents a device interface substring and the second
- part after the separator represents a device name substring.
-
- @param is_input restricts the search to an input when true, or an
- output when false.
-
- @return the number of the first device whose device interface
- contains the interface pattern (if any), whose device name
- contains the name pattern, and whose direction (input or output)
- matches the #is_input parameter. If no match is found, #pmNoDevice
- (-1) is returned.
-*/
-PMEXPORT PmDeviceID Pm_FindDevice(char *pattern, int is_input);
-
-
-/** Represents a millisecond clock with arbitrary start time.
- This type is used for all MIDI timestamps and clocks.
-*/
-typedef int32_t PmTimestamp;
-typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
-
-/** TRUE if t1 before t2 */
-#define PmBefore(t1,t2) (((t1)-(t2)) < 0)
-/** @} */
-/**
- \defgroup grp_device Input/Output Devices Handling
- @{
-*/
-/** Get a PmDeviceInfo structure describing a MIDI device.
-
- @param id the device to be queried.
-
- If \p id is out of range or if the device designates a deleted
- virtual device, the function returns NULL.
-
- The returned structure is owned by the PortMidi implementation and
- must not be manipulated or freed. The pointer is guaranteed to be
- valid between calls to Pm_Initialize() and Pm_Terminate().
-*/
-PMEXPORT const PmDeviceInfo *Pm_GetDeviceInfo(PmDeviceID id);
-
-/** Open a MIDI device for input.
-
- @param stream the address of a #PortMidiStream pointer which will
- receive a pointer to the newly opened stream.
-
- @param inputDevice the ID of the device to be opened (see #PmDeviceID).
-
- @param inputSysDepInfo a pointer to an optional system-dependent
- data structure (a #PmSysDepInfo struct) containing additional
- information for device setup or handle processing. This parameter
- is never required for correct operation. If not used, specify
- NULL. Declared `void *` here for backward compatibility. Note that
- with Linux ALSA, you can use this parameter to specify a client name
- and port name.
-
- @param bufferSize the number of input events to be buffered
- waiting to be read using Pm_Read(). Messages will be lost if the
- number of unread messages exceeds this value.
-
- @param time_proc (address of) a procedure that returns time in
- milliseconds. It may be NULL, in which case a default millisecond
- timebase (PortTime) is used. If the application wants to use
- PortTime, it should start the timer (call Pt_Start) before calling
- Pm_OpenInput or Pm_OpenOutput. If the application tries to start
- the timer *after* Pm_OpenInput or Pm_OpenOutput, it may get a
- ptAlreadyStarted error from Pt_Start, and the application's
- preferred time resolution and callback function will be ignored.
- \p time_proc result values are appended to incoming MIDI data,
- normally by mapping system-provided timestamps to the \p time_proc
- timestamps to maintain the precision of system-provided
- timestamps.
-
- @param time_info is a pointer passed to time_proc.
-
- @return #pmNoError and places a pointer to a valid
- #PortMidiStream in the stream argument. If the open operation
- fails, a nonzero error code is returned (see #PMError) and
- the value of stream is invalid.
-
- Any stream that is successfully opened should eventually be closed
- by calling Pm_Close().
-*/
-PMEXPORT PmError Pm_OpenInput(PortMidiStream** stream,
- PmDeviceID inputDevice,
- void *inputSysDepInfo,
- int32_t bufferSize,
- PmTimeProcPtr time_proc,
- void *time_info);
-
-/** Open a MIDI device for output.
-
- @param stream the address of a #PortMidiStream pointer which will
- receive a pointer to the newly opened stream.
-
- @param outputDevice the ID of the device to be opened (see #PmDeviceID).
-
- @param inputSysDepInfo a pointer to an optional system-specific
- data structure (a #PmSysDepInfo struct) containing additional
- information for device setup or handle processing. This parameter
- is never required for correct operation. If not used, specify
- NULL. Declared `void *` here for backward compatibility. Note that
- with Linux ALSA, you can use this parameter to specify a client name
- and port name.
-
- @param bufferSize the number of output events to be buffered
- waiting for output. In some cases -- see below -- PortMidi does
- not buffer output at all and merely passes data to a lower-level
- API, in which case \p bufferSize is ignored. Since MIDI speeds now
- vary from 1 to 50 or more messages per ms (over USB), put some
- thought into this number. E.g. if latency is 20ms and you want to
- burst 100 messages in that time (5000 messages per second), you
- should set \p bufferSize to at least 100. The default on Windows
- assumes an average rate of 500 messages per second and in this
- example, output would be slowed waiting for free buffers.
-
- @param latency the delay in milliseconds applied to timestamps
- to determine when the output should actually occur. (If latency is
- < 0, 0 is assumed.) If latency is zero, timestamps are ignored
- and all output is delivered immediately. If latency is greater
- than zero, output is delayed until the message timestamp plus the
- latency. (NOTE: the time is measured relative to the time source
- indicated by time_proc. Timestamps are absolute, not relative
- delays or offsets.) In some cases, PortMidi can obtain better
- timing than your application by passing timestamps along to the
- device driver or hardware, so the best strategy to minimize jitter
- is: wait until the real time to send the message, compute the
- message, attach the *ideal* output time (not the current real
- time, because some time may have elapsed), and send the
- message. The \p latency will be added to the timestamp, and
- provided the elapsed computation time has not exceeded \p latency,
- the message will be delivered according to the timestamp. If the
- real time is already past the timestamp, the message will be
- delivered as soon as possible. Latency may also help you to
- synchronize MIDI data to audio data by matching \p latency to the
- audio buffer latency.
-
- @param time_proc (address of) a pointer to a procedure that
- returns time in milliseconds. It may be NULL, in which case a
- default millisecond timebase (PortTime) is used. If the
- application wants to use PortTime, it should start the timer (call
- Pt_Start) before calling #Pm_OpenInput or #Pm_OpenOutput. If the
- application tries to start the timer *after* #Pm_OpenInput or
- #Pm_OpenOutput, it may get a #ptAlreadyStarted error from #Pt_Start,
- and the application's preferred time resolution and callback
- function will be ignored. \p time_proc times are used to schedule
- outgoing MIDI data (when latency is non-zero), usually by mapping
- from time_proc timestamps to internal system timestamps to
- maintain the precision of system-supported timing.
-
- @param time_info a pointer passed to time_proc.
-
- @return #pmNoError and places a pointer to a valid #PortMidiStream
- in the stream argument. If the operation fails, a nonzero error
- code is returned (see PMError) and the value of \p stream is
- invalid.
-
- Note: ALSA appears to have a fixed-size priority queue for timed
- output messages. Testing indicates the queue can hold a little
- over 400 3-byte MIDI messages. Thus, you can send 10,000
- messages/second if the latency is 30ms (30ms * 10000 msgs/sec *
- 0.001 sec/ms = 300 msgs), but not if the latency is 50ms
- (resulting in about 500 pending messages, which is greater than
- the 400 message limit). Since timestamps in ALSA are relative,
- they are of less value than absolute timestamps in macOS and
- Windows. This is a limitation of ALSA and apparently a design
- flaw.
-
- Example 1: If I provide a timestamp of 5000, latency is 1, and
- time_proc returns 4990, then the desired output time will be when
- time_proc returns timestamp+latency = 5001. This will be 5001-4990
- = 11ms from now.
-
- Example 2: If I want to send at exactly 5010, and latency is 10, I
- should wait until 5000, compute the messages and provide a
- timestamp of 5000. As long as computation takes less than 10ms,
- the message will be delivered at time 5010.
-
- Example 3 (recommended): It is often convenient to ignore latency.
- E.g. if a sequence says to output at time 5010, just wait until
- 5010, compute the message and use 5010 for the timestamp. Delivery
- will then be at 5010+latency, but unless you are synchronizing to
- something else, the absolute delay by latency will not matter.
-
- Any stream that is successfully opened should eventually be closed
- by calling Pm_Close().
-*/
-PMEXPORT PmError Pm_OpenOutput(PortMidiStream** stream,
- PmDeviceID outputDevice,
- void *outputSysDepInfo,
- int32_t bufferSize,
- PmTimeProcPtr time_proc,
- void *time_info,
- int32_t latency);
-
-/** Create a virtual input device.
-
- @param name gives the virtual device name, which is visible to
- other applications.
-
- @param interf is the interface (System API) used to create the
- device Default interfaces are "MMSystem", "CoreMIDI" and
- "ALSA". Currently, these are the only ones implemented, but future
- implementations could support DirectMusic, Jack, sndio, or others.
-
- @param sysDepInfo contains interface-dependent additional
- information (a #PmSysDepInfo struct), e.g., hints or options. This
- parameter is never required for correct operation. If not used,
- specify NULL. Declared `void *` here for backward compatibility.
-
- @return a device ID or #pmNameConflict (\p name is invalid or
- already exists) or #pmInterfaceNotSupported (\p interf is does not
- match a supported interface).
-
- The created virtual device appears to other applications as if it
- is an output device. The device must be opened to obtain a stream
- and read from it.
-
- Virtual devices are not supported by Windows (Multimedia API). Calls
- on Windows do nothing except return #pmNotImplemented.
-*/
-PMEXPORT PmError Pm_CreateVirtualInput(const char *name,
- const char *interf,
- void *sysDepInfo);
-
-/** Create a virtual output device.
-
- @param name gives the virtual device name, which is visible to
- other applications.
-
- @param interf is the interface (System API) used to create the
- device Default interfaces are "MMSystem", "CoreMIDI" and
- "ALSA". Currently, these are the only ones implemented, but future
- implementations could support DirectMusic, Jack, sndio, or others.
-
- @param sysDepInfo contains interface-dependent additional
- information (a #PmSysDepInfo struct), e.g., hints or options. This
- parameter is never required for correct operation. If not used,
- specify NULL. Declared `void *` here for backward compatibility.
-
- @return a device ID or #pmInvalidDeviceId (\p name is invalid or
- already exists) or #pmInterfaceNotSupported (\p interf is does not
- match a supported interface).
-
- The created virtual device appears to other applications as if it
- is an input device. The device must be opened to obtain a stream
- and write to it.
-
- Virtual devices are not supported by Windows (Multimedia API). Calls
- on Windows do nothing except return #pmNotImplemented.
-*/
-PMEXPORT PmError Pm_CreateVirtualOutput(const char *name,
- const char *interf,
- void *sysDepInfo);
-
-/** Remove a virtual device.
-
- @param device a device ID (small integer) designating the device.
-
- The device is removed; other applications can no longer see or open
- this virtual device, which may be either for input or output. The
- device must not be open. The device ID may be reused, but existing
- devices are not renumbered. This means that the device ID could be
- in the range from 0 to #Pm_CountDevices(), yet the device ID does
- not designate a device. In that case, passing the ID to
- #Pm_GetDeviceInfo() will return NULL.
-
- @return #pmNoError if the device was deleted or #pmInvalidDeviceId
- if the device is open, already deleted, or \p device is out of
- range.
-*/
-PMEXPORT PmError Pm_DeleteVirtualDevice(PmDeviceID device);
- /** @} */
-
-/**
- @defgroup grp_events_filters Events and Filters Handling
- @{
-*/
-
-/* Filter bit-mask definitions */
-/** filter active sensing messages (0xFE): */
-#define PM_FILT_ACTIVE (1 << 0x0E)
-/** filter system exclusive messages (0xF0): */
-#define PM_FILT_SYSEX (1 << 0x00)
-/** filter MIDI clock message (0xF8) */
-#define PM_FILT_CLOCK (1 << 0x08)
-/** filter play messages (start 0xFA, stop 0xFC, continue 0xFB) */
-#define PM_FILT_PLAY ((1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B))
-/** filter tick messages (0xF9) */
-#define PM_FILT_TICK (1 << 0x09)
-/** filter undefined FD messages */
-#define PM_FILT_FD (1 << 0x0D)
-/** filter undefined real-time messages */
-#define PM_FILT_UNDEFINED PM_FILT_FD
-/** filter reset messages (0xFF) */
-#define PM_FILT_RESET (1 << 0x0F)
-/** filter all real-time messages */
-#define PM_FILT_REALTIME (PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK | \
- PM_FILT_PLAY | PM_FILT_UNDEFINED | PM_FILT_RESET | PM_FILT_TICK)
-/** filter note-on and note-off (0x90-0x9F and 0x80-0x8F */
-#define PM_FILT_NOTE ((1 << 0x19) | (1 << 0x18))
-/** filter channel aftertouch (most midi controllers use this) (0xD0-0xDF)*/
-#define PM_FILT_CHANNEL_AFTERTOUCH (1 << 0x1D)
-/** per-note aftertouch (0xA0-0xAF) */
-#define PM_FILT_POLY_AFTERTOUCH (1 << 0x1A)
-/** filter both channel and poly aftertouch */
-#define PM_FILT_AFTERTOUCH (PM_FILT_CHANNEL_AFTERTOUCH | \
- PM_FILT_POLY_AFTERTOUCH)
-/** Program changes (0xC0-0xCF) */
-#define PM_FILT_PROGRAM (1 << 0x1C)
-/** Control Changes (CC's) (0xB0-0xBF)*/
-#define PM_FILT_CONTROL (1 << 0x1B)
-/** Pitch Bender (0xE0-0xEF*/
-#define PM_FILT_PITCHBEND (1 << 0x1E)
-/** MIDI Time Code (0xF1)*/
-#define PM_FILT_MTC (1 << 0x01)
-/** Song Position (0xF2) */
-#define PM_FILT_SONG_POSITION (1 << 0x02)
-/** Song Select (0xF3)*/
-#define PM_FILT_SONG_SELECT (1 << 0x03)
-/** Tuning request (0xF6) */
-#define PM_FILT_TUNE (1 << 0x06)
-/** All System Common messages (mtc, song position, song select, tune request) */
-#define PM_FILT_SYSTEMCOMMON (PM_FILT_MTC | PM_FILT_SONG_POSITION | \
- PM_FILT_SONG_SELECT | PM_FILT_TUNE)
-
-
-/* Set filters on an open input stream to drop selected input types.
-
- @param stream an open MIDI input stream.
-
- @param filters indicate message types to filter (block).
-
- @return #pmNoError or an error code.
-
- By default, only active sensing messages are filtered.
- To prohibit, say, active sensing and sysex messages, call
- Pm_SetFilter(stream, PM_FILT_ACTIVE | PM_FILT_SYSEX);
-
- Filtering is useful when midi routing or midi thru functionality
- is being provided by the user application.
- For example, you may want to exclude timing messages (clock, MTC,
- start/stop/continue), while allowing note-related messages to pass.
- Or you may be using a sequencer or drum-machine for MIDI clock
- information but want to exclude any notes it may play.
- */
-PMEXPORT PmError Pm_SetFilter(PortMidiStream* stream, int32_t filters);
-
-/** Create a mask that filters one channel. */
-#define Pm_Channel(channel) (1<<(channel))
-
-/** Filter incoming messages based on channel.
-
- @param stream an open MIDI input stream.
-
- @param mask indicates channels to be received.
-
- @return #pmNoError or an error code.
-
- The \p mask is a 16-bit bitfield corresponding to appropriate channels.
- The #Pm_Channel macro can assist in calling this function.
- I.e. to receive only input on channel 1, call with
- Pm_SetChannelMask(Pm_Channel(1));
- Multiple channels should be OR'd together, like
- Pm_SetChannelMask(Pm_Channel(10) | Pm_Channel(11))
-
- Note that channels are numbered 0 to 15 (not 1 to 16). Most
- synthesizer and interfaces number channels starting at 1, but
- PortMidi numbers channels starting at 0.
-
- All channels are allowed by default
-*/
-PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask);
-
-/** Terminate outgoing messages immediately.
-
- @param stream an open MIDI output stream.
-
- @result #pmNoError or an error code.
-
- The caller should immediately close the output port; this call may
- result in transmission of a partial MIDI message. There is no
- abort for Midi input because the user can simply ignore messages
- in the buffer and close an input device at any time. If the
- specified behavior cannot be achieved through the system-level
- interface (ALSA, CoreMIDI, etc.), the behavior may be that of
- Pm_Close().
- */
-PMEXPORT PmError Pm_Abort(PortMidiStream* stream);
-
-/** Close a midi stream, flush any pending buffers if possible.
-
- @param stream an open MIDI input or output stream.
-
- @result #pmNoError or an error code.
-
- If the system-level interface (ALSA, CoreMIDI, etc.) does not
- support flushing remaining messages, the behavior may be one of
- the following (most preferred first): block until all pending
- timestamped messages are delivered; deliver messages to a server
- or kernel process for later delivery but return immediately; drop
- messages (as in Pm_Abort()). Therefore, to be safe, applications
- should wait until the output queue is empty before calling
- Pm_Close(). E.g. calling Pt_Sleep(100 + latency); will give a
- 100ms "cushion" beyond latency (if any) before closing.
-*/
-PMEXPORT PmError Pm_Close(PortMidiStream* stream);
-
-/** (re)synchronize to the time_proc passed when the stream was opened.
-
- @param stream an open MIDI input or output stream.
-
- @result #pmNoError or an error code.
-
- Typically, this is used when the stream must be opened before the
- time_proc reference is actually advancing. In this case, message
- timing may be erratic, but since timestamps of zero mean "send
- immediately," initialization messages with zero timestamps can be
- written without a functioning time reference and without
- problems. Before the first MIDI message with a non-zero timestamp
- is written to the stream, the time reference must begin to advance
- (for example, if the time_proc computes time based on audio
- samples, time might begin to advance when an audio stream becomes
- active). After time_proc return values become valid, and BEFORE
- writing the first non-zero timestamped MIDI message, call
- Pm_Synchronize() so that PortMidi can observe the difference
- between the current time_proc value and its MIDI stream time.
-
- In the more normal case where time_proc values advance
- continuously, there is no need to call #Pm_Synchronize. PortMidi
- will always synchronize at the first output message and
- periodically thereafter.
-*/
-PMEXPORT PmError Pm_Synchronize(PortMidiStream* stream);
-
-
-/** Encode a short Midi message into a 32-bit word. If data1
- and/or data2 are not present, use zero.
-*/
-#define Pm_Message(status, data1, data2) \
- ((((data2) << 16) & 0xFF0000) | \
- (((data1) << 8) & 0xFF00) | \
- ((status) & 0xFF))
-/** Extract the status field from a 32-bit midi message. */
-#define Pm_MessageStatus(msg) ((msg) & 0xFF)
-/** Extract the 1st data field (e.g., pitch) from a 32-bit midi message. */
-#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
-/** Extract the 2nd data field (e.g., velocity) from a 32-bit midi message. */
-#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)
-
-typedef uint32_t PmMessage; /**< @brief see #PmEvent */
-/**
- All MIDI data comes in the form of PmEvent structures. A sysex
- message is encoded as a sequence of PmEvent structures, with each
- structure carrying 4 bytes of the message, i.e. only the first
- PmEvent carries the status byte.
-
- All other MIDI messages take 1 to 3 bytes and are encoded in a whole
- PmMessage with status in the low-order byte and remaining bytes
- unused, i.e., a 3-byte note-on message will occupy 3 low-order bytes
- of PmMessage, leaving the high-order byte unused.
-
- Note that MIDI allows nested messages: the so-called "real-time" MIDI
- messages can be inserted into the MIDI byte stream at any location,
- including within a sysex message. MIDI real-time messages are one-byte
- messages used mainly for timing (see the MIDI spec). PortMidi retains
- the order of non-real-time MIDI messages on both input and output, but
- it does not specify exactly how real-time messages are processed. This
- is particulary problematic for MIDI input, because the input parser
- must either prepare to buffer an unlimited number of sysex message
- bytes or to buffer an unlimited number of real-time messages that
- arrive embedded in a long sysex message. To simplify things, the input
- parser is allowed to pass real-time MIDI messages embedded within a
- sysex message, and it is up to the client to detect, process, and
- remove these messages as they arrive.
-
- When receiving sysex messages, the sysex message is terminated
- by either an EOX status byte (anywhere in the 4 byte messages) or
- by a non-real-time status byte in the low order byte of the message.
- If you get a non-real-time status byte but there was no EOX byte, it
- means the sysex message was somehow truncated. This is not
- considered an error; e.g., a missing EOX can result from the user
- disconnecting a MIDI cable during sysex transmission.
-
- A real-time message can occur within a sysex message. A real-time
- message will always occupy a full PmEvent with the status byte in
- the low-order byte of the PmEvent message field. (This implies that
- the byte-order of sysex bytes and real-time message bytes may not
- be preserved -- for example, if a real-time message arrives after
- 3 bytes of a sysex message, the real-time message will be delivered
- first. The first word of the sysex message will be delivered only
- after the 4th byte arrives, filling the 4-byte PmEvent message field.
-
- The timestamp field is observed when the output port is opened with
- a non-zero latency. A timestamp of zero means "use the current time",
- which in turn means to deliver the message with a delay of
- latency (the latency parameter used when opening the output port.)
- Do not expect PortMidi to sort data according to timestamps --
- messages should be sent in the correct order, and timestamps MUST
- be non-decreasing. See also "Example" for Pm_OpenOutput() above.
-
- A sysex message will generally fill many #PmEvent structures. On
- output to a #PortMidiStream with non-zero latency, the first timestamp
- on sysex message data will determine the time to begin sending the
- message. PortMidi implementations may ignore timestamps for the
- remainder of the sysex message.
-
- On input, the timestamp ideally denotes the arrival time of the
- status byte of the message. The first timestamp on sysex message
- data will be valid. Subsequent timestamps may denote
- when message bytes were actually received, or they may be simply
- copies of the first timestamp.
-
- Timestamps for nested messages: If a real-time message arrives in
- the middle of some other message, it is enqueued immediately with
- the timestamp corresponding to its arrival time. The interrupted
- non-real-time message or 4-byte packet of sysex data will be enqueued
- later. The timestamp of interrupted data will be equal to that of
- the interrupting real-time message to insure that timestamps are
- non-decreasing.
- */
-typedef struct {
- PmMessage message;
- PmTimestamp timestamp;
-} PmEvent;
-
-/** @} */
-
-/** \defgroup grp_io Reading and Writing Midi Messages
- @{
-*/
-/** Retrieve midi data into a buffer.
-
- @param stream the open input stream.
-
- @return the number of events read, or, if the result is negative,
- a #PmError value will be returned.
-
- The Buffer Overflow Problem
-
- The problem: if an input overflow occurs, data will be lost,
- ultimately because there is no flow control all the way back to
- the data source. When data is lost, the receiver should be
- notified and some sort of graceful recovery should take place,
- e.g. you shouldn't resume receiving in the middle of a long sysex
- message.
-
- With a lock-free fifo, which is pretty much what we're stuck with
- to enable portability to the Mac, it's tricky for the producer and
- consumer to synchronously reset the buffer and resume normal
- operation.
-
- Solution: the entire buffer managed by PortMidi will be flushed
- when an overflow occurs. The consumer (Pm_Read()) gets an error
- message (#pmBufferOverflow) and ordinary processing resumes as
- soon as a new message arrives. The remainder of a partial sysex
- message is not considered to be a "new message" and will be
- flushed as well.
-*/
-PMEXPORT int Pm_Read(PortMidiStream *stream, PmEvent *buffer, int32_t length);
-
-/** Test whether input is available.
-
- @param stream an open input stream.
-
- @return TRUE, FALSE, or an error value.
-
- If there was an asynchronous error, pmHostError is returned and you must
- call again to determine if input is (also) available.
-
- You should probably *not* use this function. Call Pm_Read()
- instead. If it returns 0, then there is no data available. It is
- possible for Pm_Poll() to return TRUE before the complete message
- is available, so Pm_Read() could return 0 even after Pm_Poll()
- returns TRUE. Only call Pm_Poll() if you want to know that data is
- probably available even though you are not ready to receive data.
-*/
-PMEXPORT PmError Pm_Poll(PortMidiStream *stream);
-
-/** Write MIDI data from a buffer.
-
- @param stream an open output stream.
-
- @param buffer (address of) an array of MIDI event data.
-
- @param length the length of the \p buffer.
-
- @return TRUE, FALSE, or an error value.
-
- \b buffer may contain:
- - short messages
- - sysex messages that are converted into a sequence of PmEvent
- structures, e.g. sending data from a file or forwarding them
- from midi input, with 4 SysEx bytes per PmEvent message,
- low-order byte first, until the last message, which may
- contain from 1 to 4 bytes ending in MIDI EOX (0xF7).
- - PortMidi allows 1-byte real-time messages to be embedded
- within SysEx messages, but only on 4-byte boundaries so
- that SysEx data always uses a full 4 bytes (except possibly
- at the end). Each real-time message always occupies a full
- PmEvent (3 of the 4 bytes in the PmEvent's message are
- ignored) even when embedded in a SysEx message.
-
- Use Pm_WriteSysEx() to write a sysex message stored as a contiguous
- array of bytes.
-
- Sysex data may contain embedded real-time messages.
-
- \p buffer is managed by the caller. The buffer may be destroyed
- as soon as this call returns.
-*/
-PMEXPORT PmError Pm_Write(PortMidiStream *stream, PmEvent *buffer,
- int32_t length);
-
-/** Write a timestamped non-system-exclusive midi message.
-
- @param stream an open output stream.
-
- @param when timestamp for the event.
-
- @param msg the data for the event.
-
- @result #pmNoError or an error code.
-
- Messages are delivered in order, and timestamps must be
- non-decreasing. (But timestamps are ignored if the stream was
- opened with latency = 0, and otherwise, non-decreasing timestamps
- are "corrected" to the lowest valid value.)
-*/
-PMEXPORT PmError Pm_WriteShort(PortMidiStream *stream, PmTimestamp when,
- PmMessage msg);
-
-/** Write a timestamped system-exclusive midi message.
-
- @param stream an open output stream.
-
- @param when timestamp for the event.
-
- @param msg the sysex message, terminated with an EOX status byte.
-
- @result #pmNoError or an error code.
-
- \p msg is managed by the caller and may be destroyed when this
- call returns.
-*/
-PMEXPORT PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when,
- unsigned char *msg);
-
-/** @} */
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* PORTMIDI_PORTMIDI_H */
diff --git a/portmidi/pm_haiku/pmhaiku.cpp b/portmidi/pm_haiku/pmhaiku.cpp
deleted file mode 100644
index 0c592f1..0000000
--- a/portmidi/pm_haiku/pmhaiku.cpp
+++ /dev/null
@@ -1,473 +0,0 @@
-/* pmhaiku.cpp -- PortMidi os-dependent code */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <vector>
-#include <MidiConsumer.h>
-#include <MidiEndpoint.h>
-#include <MidiProducer.h>
-#include <MidiRoster.h>
-#include <MidiSynth.h>
-#include "portmidi.h"
-#include "pmutil.h"
-#include "pminternal.h"
-
-namespace {
- struct PmInputConsumer : BMidiLocalConsumer {
- PmInputConsumer(PmInternal *midi) :
- BMidiLocalConsumer("PortMidi input consumer"),
- midi(midi)
- {
- }
-
-
- void Data(uchar *data, size_t length, bool atomic, bigtime_t time)
- {
- if (!atomic)
- return; // should these be also supported?
-
- if (data[0] == B_SYS_EX_START) {
- pm_read_bytes(midi, data, length, time / 1000);
- } else {
- PmEvent event;
- switch (length) {
- case 1:
- event.message = Pm_Message(data[0], 0, 0);
- break;
- case 2:
- event.message = Pm_Message(data[0], data[1], 0);
- break;
- case 3:
- event.message = Pm_Message(data[0], data[1], data[2]);
- break;
- default:
- printf("Unexpected message length for short message, got %" B_PRIuSIZE "\n", length);
- break;
- }
- event.timestamp = time / 1000;
- pm_read_short(midi, &event);
- }
- }
-
- private:
- PmInternal *midi;
- };
-
- struct PmOutputInfo {
- BMidiLocalProducer *producer;
- std::vector<unsigned char> sysexBuffer;
- };
-
- struct PmSynthOutputInfo {
- BMidiSynth midiSynth;
- std::vector<unsigned char> sysexBuffer;
- };
-
-
- PmTimestamp synchronize(PmInternal *midi)
- {
- return 0;
- }
-
-
- PmError in_open(PmInternal *midi, void *driverInfo)
- {
- int32 endpointID = (int32)(intptr_t)pm_descriptors[midi->device_id].descriptor;
- BMidiProducer *producer = BMidiRoster::FindProducer(endpointID);
- if (!producer)
- return pmInvalidDeviceId;
- PmInputConsumer *consumer = new PmInputConsumer(midi);
- status_t status = producer->Connect(consumer);
- if (status != B_OK) {
- consumer->Release();
- producer->Release();
- strcpy(pm_hosterror_text, strerror(status));
- pm_hosterror = TRUE;
- return pmHostError;
- }
- midi->api_info = consumer;
- producer->Release();
- return pmNoError;
- }
-
-
- PmError in_abort(PmInternal *midi)
- {
- return pmNoError;
- }
-
-
- PmError in_close(PmInternal *midi)
- {
- int32 endpointID = (int32)(intptr_t)pm_descriptors[midi->device_id].descriptor;
- BMidiProducer *producer = BMidiRoster::FindProducer(endpointID);
- if (!producer)
- return pmInvalidDeviceId;
- PmInputConsumer *consumer = (PmInputConsumer*)midi->api_info;
- status_t status = producer->Disconnect(consumer);
- if (status != B_OK) {
- consumer->Release();
- producer->Release();
- strcpy(pm_hosterror_text, strerror(status));
- pm_hosterror = TRUE;
- return pmHostError;
- }
- consumer->Release();
- midi->api_info = NULL;
- producer->Release();
- return pmNoError;
- }
-
-
- PmError out_open(PmInternal *midi, void *driverInfo)
- {
- int32 endpointID = (int32)(intptr_t)pm_descriptors[midi->device_id].descriptor;
- BMidiConsumer *consumer = BMidiRoster::FindConsumer(endpointID);
- if (!consumer)
- return pmInvalidDeviceId;
- BMidiLocalProducer *producer = new BMidiLocalProducer("PortMidi output producer");
- status_t status = producer->Connect(consumer);
- if (status != B_OK) {
- consumer->Release();
- producer->Release();
- strcpy(pm_hosterror_text, strerror(status));
- pm_hosterror = TRUE;
- return pmHostError;
- }
- PmOutputInfo *info = new PmOutputInfo;
- info->producer = producer;
- midi->api_info = info;
- consumer->Release();
- return pmNoError;
- }
-
-
- PmError out_abort(PmInternal *midi)
- {
- return pmNoError;
- }
-
-
- PmError out_close(PmInternal *midi)
- {
- int32 endpointID = (int32)(intptr_t)pm_descriptors[midi->device_id].descriptor;
- BMidiConsumer *consumer = BMidiRoster::FindConsumer(endpointID);
- if (!consumer)
- return pmInvalidDeviceId;
- PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
- status_t status = info->producer->Disconnect(consumer);
- if (status != B_OK) {
- consumer->Release();
- midi->api_info = NULL;
- info->producer->Release();
- delete info;
- strcpy(pm_hosterror_text, strerror(status));
- pm_hosterror = TRUE;
- return pmHostError;
- }
- consumer->Release();
- midi->api_info = NULL;
- info->producer->Release();
- delete info;
- return pmNoError;
- }
-
-
- PmError write_short(PmInternal *midi, PmEvent *buffer)
- {
- PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
- uchar data[3];
- data[0] = Pm_MessageStatus(buffer->message);
- data[1] = Pm_MessageData1(buffer->message);
- data[2] = Pm_MessageData2(buffer->message);
- size_t length = pm_midi_length(data[0]);
-
- info->producer->SprayData(data, length, true, buffer->timestamp * 1000);
-
- // TODO: handle latency != 0
- return pmNoError;
- }
-
-
- PmError begin_sysex(PmInternal *midi, PmTimestamp timestamp)
- {
- PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
- info->sysexBuffer.clear();
- return pmNoError;
- }
-
-
- PmError end_sysex(PmInternal *midi, PmTimestamp timestamp)
- {
- PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
- info->producer->SpraySystemExclusive(&info->sysexBuffer[0], info->sysexBuffer.size(), timestamp * 1000);
- info->sysexBuffer.clear();
- return pmNoError;
- }
-
-
- PmError write_byte(PmInternal *midi, unsigned char byte, PmTimestamp timestamp)
- {
- PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
- info->sysexBuffer.push_back(byte);
- return pmNoError;
- }
-
-
- PmError write_realtime(PmInternal *midi, PmEvent *buffer)
- {
- PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
- info->producer->SpraySystemRealTime(Pm_MessageStatus(buffer->message), buffer->timestamp * 1000);
- return pmNoError;
- }
-
-
- PmError synth_open(PmInternal *midi, void *driverInfo)
- {
- PmSynthOutputInfo *info = new PmSynthOutputInfo;
- info->midiSynth.EnableInput(true, true);
- midi->api_info = info;
- return pmNoError;
- }
-
-
- PmError synth_abort(PmInternal *midi)
- {
- return pmNoError;
- }
-
-
- PmError synth_close(PmInternal *midi)
- {
- PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
- delete info;
- midi->api_info = NULL;
- return pmNoError;
- }
-
-
- PmError write_short_synth(PmInternal *midi, PmEvent *buffer)
- {
- PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
- uchar data[3];
- data[0] = Pm_MessageStatus(buffer->message);
- data[1] = Pm_MessageData1(buffer->message);
- data[2] = Pm_MessageData2(buffer->message);
-
- switch(data[0] & 0xf0) {
- case B_NOTE_OFF:
- info->midiSynth.NoteOff((data[0] & 0x0f) + 1, data[1], data[2], buffer->timestamp);
- break;
- case B_NOTE_ON:
- info->midiSynth.NoteOn((data[0] & 0x0f) + 1, data[1], data[2], buffer->timestamp);
- break;
- case B_KEY_PRESSURE:
- info->midiSynth.KeyPressure((data[0] & 0x0f + 1), data[1], data[2], buffer->timestamp);
- break;
- case B_CONTROL_CHANGE:
- info->midiSynth.ControlChange((data[0] & 0x0f) + 1, data[1], data[2], buffer->timestamp);
- break;
- case B_PROGRAM_CHANGE:
- info->midiSynth.ProgramChange((data[0] & 0x0f) + 1, data[1], buffer->timestamp);
- break;
- case B_CHANNEL_PRESSURE:
- info->midiSynth.ChannelPressure((data[0] & 0x0f) + 1, data[1], buffer->timestamp);
- break;
- case B_PITCH_BEND:
- info->midiSynth.PitchBend((data[0] & 0x0f) + 1, data[1], data[2], buffer->timestamp);
- break;
- }
-
- // TODO: handle latency != 0
- return pmNoError;
- }
-
-
- PmError begin_sysex_synth(PmInternal *midi, PmTimestamp timestamp)
- {
- PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
- info->sysexBuffer.clear();
- return pmNoError;
- }
-
-
- PmError end_sysex_synth(PmInternal *midi, PmTimestamp timestamp)
- {
- PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
- info->midiSynth.SystemExclusive(&info->sysexBuffer[0], info->sysexBuffer.size(), timestamp);
- info->sysexBuffer.clear();
- return pmNoError;
- }
-
-
- PmError write_byte_synth(PmInternal *midi, unsigned char byte, PmTimestamp timestamp)
- {
- PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
- info->sysexBuffer.push_back(byte);
- return pmNoError;
- }
-
-
- PmError write_realtime_synth(PmInternal *midi, PmEvent *buffer)
- {
- PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
- info->midiSynth.SystemRealTime(Pm_MessageStatus(buffer->message), buffer->timestamp);
- return pmNoError;
- }
-
-
- PmError write_flush(PmInternal *midi, PmTimestamp timestamp)
- {
- return pmNoError;
- }
-
-
- unsigned int check_host_error(PmInternal *midi)
- {
- return 0;
- }
-
-
- pm_fns_node pm_in_dictionary = {
- none_write_short,
- none_sysex,
- none_sysex,
- none_write_byte,
- none_write_short,
- none_write_flush,
- synchronize,
- in_open,
- in_abort,
- in_close,
- success_poll,
- check_host_error
- };
-
- pm_fns_node pm_out_dictionary = {
- write_short,
- begin_sysex,
- end_sysex,
- write_byte,
- write_realtime,
- write_flush,
- synchronize,
- out_open,
- out_abort,
- out_close,
- none_poll,
- check_host_error
- };
-
-
- pm_fns_node pm_synth_dictionary = {
- write_short_synth,
- begin_sysex_synth,
- end_sysex_synth,
- write_byte_synth,
- write_realtime_synth,
- write_flush,
- synchronize,
- synth_open,
- synth_abort,
- synth_close,
- none_poll,
- check_host_error
- };
-
-
- PmError create_virtual(int is_input, const char *name, void *driverInfo)
- {
- BMidiEndpoint *endpoint = is_input ? (BMidiEndpoint*)new BMidiLocalProducer(name) : new BMidiLocalConsumer(name);
- if (!endpoint->IsValid()) {
- endpoint->Release();
- strcpy(pm_hosterror_text, "Endpoint could not be created");
- pm_hosterror = TRUE;
- return pmHostError;
- }
- status_t status = endpoint->Register();
- if (status != B_OK) {
- endpoint->Release();
- strcpy(pm_hosterror_text, strerror(status));
- pm_hosterror = TRUE;
- return pmHostError;
- }
- return pm_add_device(const_cast<char*>("Haiku MIDI kit"), name, is_input, TRUE, (void*)(intptr_t)endpoint->ID(), is_input ? &pm_in_dictionary : &pm_out_dictionary);
- }
-
- PmError delete_virtual(PmDeviceID id)
- {
- int32 endpointID = (int32)(intptr_t)pm_descriptors[id].descriptor;
- BMidiEndpoint *endpoint = BMidiRoster::FindEndpoint(endpointID);
- //TODO: handle connected producers and consumers
- status_t status = endpoint->Unregister();
- // release twice to actually free the endpoint (FindEndpoint increases the ref-count)
- endpoint->Release();
- endpoint->Release();
- if (status != B_OK) {
- strcpy(pm_hosterror_text, strerror(status));
- pm_hosterror = TRUE;
- return pmHostError;
- }
- return pmNoError;
- }
-}
-
-extern "C" {
- void pm_init()
- {
- pm_add_interf(const_cast<char*>("Haiku MIDI kit"), create_virtual, delete_virtual);
-
- pm_add_device(const_cast<char*>("Haiku MIDI kit"), "Soft Synth", FALSE, FALSE, NULL, &pm_synth_dictionary);
-
- int32 id = 0;
- BMidiEndpoint *endpoint;
-
- while ((endpoint = BMidiRoster::NextEndpoint(&id)) != NULL) {
- bool isInput = endpoint->IsProducer();
- pm_add_device(const_cast<char*>("Haiku MIDI kit"), endpoint->Name(), isInput, FALSE, (void*)(intptr_t)id, isInput ? &pm_in_dictionary : &pm_out_dictionary);
- endpoint->Release();
- }
- }
-
-
- void pm_term()
- {
- int i;
- for (i = 0; i < pm_descriptor_len; i++) {
- PmInternal *midi = pm_descriptors[i].pm_internal;
- if (midi && midi->api_info) {
- // device is still open, close it
- (*midi->dictionary->close)(midi);
- }
- if (pm_descriptors[i].pub.is_virtual && !pm_descriptors[i].deleted) {
- delete_virtual(i);
- }
- }
- }
-
-
- PmDeviceID Pm_GetDefaultInputDeviceID()
- {
- Pm_Initialize();
- return pm_default_input_device_id;
- }
-
-
- PmDeviceID Pm_GetDefaultOutputDeviceID()
- {
- Pm_Initialize();
- return pm_default_output_device_id;
- }
-
-
- void *pm_alloc(size_t s)
- {
- return malloc(s);
- }
-
-
- void pm_free(void *ptr)
- {
- free(ptr);
- }
-}
diff --git a/portmidi/pm_java/CMakeLists.txt b/portmidi/pm_java/CMakeLists.txt
deleted file mode 100644
index 55a20f4..0000000
--- a/portmidi/pm_java/CMakeLists.txt
+++ /dev/null
@@ -1,56 +0,0 @@
-# pm_java/CMakeLists.txt -- builds pmjni
-
-find_package(Java)
-message(STATUS "Java_JAVA_EXECUTABLE is " ${Java_JAVA_EXECUTABLE})
-
-# Build pmjni
-# this CMakeLists.txt is only loaded if BUILD_JAVA_NATIVE_INTERFACE
-# This jni library includes portmidi sources to give just
-# one library for JPortMidi users to manage rather than two.
-if(UNIX)
- include(FindJNI)
- # message(STATUS "JAVA_JVM_LIB_PATH is " ${JAVA_JVM_LIB_PATH})
- # message(STATUS "JAVA_INCLUDE_PATH is " ${JAVA_INCLUDE_PATH})
- # note: should use JAVA_JVM_LIB_PATH, but it is not set properly
- # note: user might need to set JAVA_INCLUDE_PATH manually
- #
- # this will probably break on BSD and other Unix systems; the fix
- # depends on whether FindJNI can find Java or not. If yes, then
- # we should try to rely on automatically set JAVA_INCLUDE_PATH and
- # JAVA_INCLUDE_PATH2; if no, then we need to make both JAVA_INCLUDE_PATH
- # and JAVA_INCLUDE_PATH2 set by user (will need clear documentation
- # because JAVA_INCLUDE_PATH2 is pretty obscure)
- set(JAVA_INCLUDE_PATH ${JAVA_INCLUDE_PATH-UNKNOWN}
- CACHE STRING "where to find Java SDK include directory")
- # libjvm.so is found relative to JAVA_INCLUDE_PATH:
- if (HAIKU)
- set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/haiku)
- else()
- set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH}/linux)
- endif()
-elseif(WIN32)
- include(FindJNI)
- # note: should use JAVA_JVM_LIB_PATH, but it is not set properly
- set(JAVAVM_LIB ${JAVA_INCLUDE_PATH}/../lib/jvm.lib)
-
- set(JAVA_INCLUDE_PATHS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
- # message(STATUS "JAVA_INCLUDE_PATHS: " ${JAVA_INCLUDE_PATHS})
- # message(STATUS "JAVAVM_LIB: " ${JAVAVM_LIB})
-endif()
-
-add_library(pmjni SHARED pmjni/pmjni.c)
-target_sources(pmjni PRIVATE ${PM_LIB_PUBLIC_SRC} ${PM_LIB_PRIVATE_SRC})
-message(STATUS "Java paths ${JAVA_INCLUDE_PATHS}")
-# message(STATUS "Java pmjni src: pmjni/pmjni.c ${PM_LIB_SHARED_SRC} "
-# "${PM_LIB_PRIVATE_SRC}")
-target_include_directories(pmjni PUBLIC ${JAVA_INCLUDE_PATHS})
-target_link_libraries(pmjni ${PM_NEEDED_LIBS})
-set_target_properties(pmjni PROPERTIES
- VERSION ${LIBRARY_VERSION}
- SOVERSION ${LIBRARY_SOVERSION}
- LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
- RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
- ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
- EXECUTABLE_EXTENSION "jnilib"
- MACOSX_RPATH ON)
-
diff --git a/portmidi/pm_java/README.txt b/portmidi/pm_java/README.txt
deleted file mode 100644
index d1e5ad5..0000000
--- a/portmidi/pm_java/README.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-README.txt
-Roger B. Dannenberg
-16 Jun 2009
-updated 2021
-
-This directory implements a JNI library so that Java programs can use
-the PortMidi API. This was mainly created to implement PmDefaults, a
-program to set default input and output devices for PortMidi
-applications. Because it is rarely used, PmDefaults was dropped from
-PortMidi starting with v3. I recommend you implement per-application
-preferences and store default PortMidi device numbers for input and
-output there. (Or better yet, store device *names* since numbers can
-change if you plug in or remove USB devices.)
-
-Even without PmDefaults, a PortMidi API for Java is probably an
-improvement over other Java libraries, but there is very little MIDI
-development in Java, so I have not maintained this API. The only thing
-probably seriously wrong now is an interface to the
-Pm_CreateVirtualInput and Pm_CreateVirtualOutput functions, which are
-new additions.
-
-I will leave the code here, and if there is a demand, please either
-update it or let your needs be known. Perhaps I or someone can help.
-
-==================================================================
-
-BUILDING Java EXTERNAL LIBRARY
-
-You must have a JDK installed (Java development kit including javac
-(the Java compiler), jni.h, etc.
-
-Test java on the command line, e.g., type: javac -version
-
-Enable these options in the main CMakeLists.txt file (run CMake
-from your top-level repository directory):
- BUILD_JAVA_NATIVE_INTERFACE
-In my Ubuntu linux with jdk-15, ccmake was unable to find my JDK, so
-I have to manually set CMake variables as follows (type 't' to see
-these in ccmake):
- JAVA_AWT_INCLUDE_PATH /usr/lib/jvm/jdk-15/include
- JAVA_AWT_LIBRARY /usr/lib/jvm/jdk-15/lib
- JAVA_INCLUDE_PATH /usr/lib/jvm/jdk-15/include
- JAVA_INCLUDE_PATH2 /usr/lib/jvm/jdk-15/include
- JAVA_JVM_LIBRARY /usr/lib/jvm/jdk-15/lib
-Of course, your paths may differ.
-
-
----- old implementation notes ----
-
-For Windows, we use the free software JavaExe.exe. The copy here was
-downloaded from
-
-http://software.techrepublic.com.com/abstract.aspx?kw=javaexe&docid=767485
-
-I found this page by visiting http://software.techrepublic.com.com and
-searching in the "Software" category for "JavaExe"
-
-JavaExe works by placing the JavaExe.exe file in the directory with the
-Java application jar file and then *renaming* JavaExe.exe to the name
-of the jar file, but keeping the .exe extension. (See make.bat for this
-step.) Documentation for JavaExe can be obtained by downloading the
-whole program from the URL(s) above.
diff --git a/portmidi/pm_java/jportmidi/JPortMidi.java b/portmidi/pm_java/jportmidi/JPortMidi.java
deleted file mode 100644
index 7116e19..0000000
--- a/portmidi/pm_java/jportmidi/JPortMidi.java
+++ /dev/null
@@ -1,541 +0,0 @@
-package jportmidi;
-
-/* PortMidi is a general class intended for any Java program using
- the PortMidi library. It encapsulates JPortMidiApi with a more
- object-oriented interface. A single PortMidi object can manage
- up to one input stream and one output stream.
-
- This class is not safely callable from multiple threads. It
- is the client's responsibility to periodically call the Poll
- method which checks for midi input and handles it.
-*/
-
-import jportmidi.*;
-import jportmidi.JPortMidiApi.*;
-
-public class JPortMidi {
-
- // timecode to send message immediately
- public final int NOW = 0;
-
- // midi codes
- public final int MIDI_NOTE_OFF = 0x80;
- public final int MIDI_NOTE_ON = 0x90;
- public final int CTRL_ALL_OFF = 123;
- public final int MIDI_PITCH_BEND = 0xE0;
- public final int MIDI_CLOCK = 0xF8;
- public final int MIDI_CONTROL = 0xB0;
- public final int MIDI_PROGRAM = 0xC0;
- public final int MIDI_START = 0xFA;
- public final int MIDI_STOP = 0xFC;
- public final int MIDI_POLY_TOUCH = 0xA0;
- public final int MIDI_TOUCH = 0xD0;
-
- // error code -- cannot refresh device list while stream is open:
- public final int pmStreamOpen = -5000;
- public final int pmOutputNotOpen = -4999;
-
- // access to JPortMidiApi is through a single, global instance
- private static JPortMidiApi pm;
- // a reference count tracks how many objects have it open
- private static int pmRefCount = 0;
- private static int openCount = 0;
-
- public int error; // user can check here for error codes
- private PortMidiStream input;
- private PortMidiStream output;
- private PmEvent buffer;
- protected int timestamp; // remember timestamp from incoming messages
- protected boolean trace = false; // used to print midi msgs for debugging
-
-
- public JPortMidi() throws JPortMidiException {
- if (pmRefCount == 0) {
- pm = new JPortMidiApi();
- pmRefCount++;
- System.out.println("Calling Pm_Initialize");
- checkError(pm.Pm_Initialize());
- System.out.println("Called Pm_Initialize");
- }
- buffer = new PmEvent();
- }
-
- public boolean getTrace() { return trace; }
-
- // set the trace flag and return previous value
- public boolean setTrace(boolean flag) {
- boolean previous = trace;
- trace = flag;
- return previous;
- }
-
- // WARNING: you must not call this if any devices are open
- public void refreshDeviceLists()
- throws JPortMidiException
- {
- if (openCount > 0) {
- throw new JPortMidiException(pmStreamOpen,
- "RefreshDeviceLists called while stream is open");
- }
- if (trace) System.out.println("Pm_Terminate");
- checkError(pm.Pm_Terminate());
- if (trace) System.out.println("Pm_Initialize");
- checkError(pm.Pm_Initialize());
- }
-
- // there is no control over when/whether this is called, but it seems
- // to be a good idea to close things when this object is collected
- public void finalize() {
- if (input != null) {
- error = pm.Pm_Close(input);
- }
- if (input != null) {
- int rslt = pm.Pm_Close(output);
- // we may lose an error code from closing output, but don't
- // lose any real error from closing input...
- if (error == pm.pmNoError) error = rslt;
- }
- pmRefCount--;
- if (pmRefCount == 0) {
- error = pm.Pm_Terminate();
- }
- }
-
- int checkError(int err) throws JPortMidiException
- {
- // note that Pm_Read and Pm_Write return positive result values
- // which are not errors, so compare with >=
- if (err >= pm.pmNoError) return err;
- if (err == pm.pmHostError) {
- throw new JPortMidiException(err, pm.Pm_GetHostErrorText());
- } else {
- throw new JPortMidiException(err, pm.Pm_GetErrorText(err));
- }
- }
-
- // ******** ACCESS TO TIME ***********
-
- public void timeStart(int resolution) throws JPortMidiException {
- checkError(pm.Pt_TimeStart(resolution));
- }
-
- public void timeStop() throws JPortMidiException {
- checkError(pm.Pt_TimeStop());
- }
-
- public int timeGet() {
- return pm.Pt_Time();
- }
-
- public boolean timeStarted() {
- return pm.Pt_TimeStarted();
- }
-
- // ******* QUERY DEVICE INFORMATION *********
-
- public int countDevices() throws JPortMidiException {
- return checkError(pm.Pm_CountDevices());
- }
-
- public int getDefaultInputDeviceID() throws JPortMidiException {
- return checkError(pm.Pm_GetDefaultInputDeviceID());
- }
-
- public int getDefaultOutputDeviceID() throws JPortMidiException {
- return checkError(pm.Pm_GetDefaultOutputDeviceID());
- }
-
- public String getDeviceInterf(int i) {
- return pm.Pm_GetDeviceInterf(i);
- }
-
- public String getDeviceName(int i) {
- return pm.Pm_GetDeviceName(i);
- }
-
- public boolean getDeviceInput(int i) {
- return pm.Pm_GetDeviceInput(i);
- }
-
- public boolean getDeviceOutput(int i) {
- return pm.Pm_GetDeviceOutput(i);
- }
-
- // ********** MIDI INTERFACE ************
-
- public boolean isOpenInput() {
- return input != null;
- }
-
- public void openInput(int inputDevice, int bufferSize)
- throws JPortMidiException
- {
- openInput(inputDevice, "", bufferSize);
- }
-
- public void openInput(int inputDevice, String inputDriverInfo, int bufferSize)
- throws JPortMidiException
- {
- if (isOpenInput()) pm.Pm_Close(input);
- else input = new PortMidiStream();
- if (trace) {
- System.out.println("openInput " + getDeviceName(inputDevice));
- }
- checkError(pm.Pm_OpenInput(input, inputDevice,
- inputDriverInfo, bufferSize));
- // if no exception, then increase count of open streams
- openCount++;
- }
-
- public boolean isOpenOutput() {
- return output != null;
- }
-
- public void openOutput(int outputDevice, int bufferSize, int latency)
- throws JPortMidiException
- {
- openOutput(outputDevice, "", bufferSize, latency);
- }
-
- public void openOutput(int outputDevice, String outputDriverInfo,
- int bufferSize, int latency) throws JPortMidiException {
- if (isOpenOutput()) pm.Pm_Close(output);
- else output = new PortMidiStream();
- if (trace) {
- System.out.println("openOutput " + getDeviceName(outputDevice));
- }
- checkError(pm.Pm_OpenOutput(output, outputDevice, outputDriverInfo,
- bufferSize, latency));
- // if no exception, then increase count of open streams
- openCount++;
- }
-
- public void setFilter(int filters) throws JPortMidiException {
- if (input == null) return; // no effect if input not open
- checkError(pm.Pm_SetFilter(input, filters));
- }
-
- public void setChannelMask(int mask) throws JPortMidiException {
- if (input == null) return; // no effect if input not open
- checkError(pm.Pm_SetChannelMask(input, mask));
- }
-
- public void abort() throws JPortMidiException {
- if (output == null) return; // no effect if output not open
- checkError(pm.Pm_Abort(output));
- }
-
- // In keeping with the idea that this class represents an input and output,
- // there are separate Close methods for input and output streams, avoiding
- // the need for clients to ever deal directly with a stream object
- public void closeInput() throws JPortMidiException {
- if (input == null) return; // no effect if input not open
- checkError(pm.Pm_Close(input));
- input = null;
- openCount--;
- }
-
- public void closeOutput() throws JPortMidiException {
- if (output == null) return; // no effect if output not open
- checkError(pm.Pm_Close(output));
- output = null;
- openCount--;
- }
-
- // Poll should be called by client to process input messages (if any)
- public void poll() throws JPortMidiException {
- if (input == null) return; // does nothing until input is opened
- while (true) {
- int rslt = pm.Pm_Read(input, buffer);
- checkError(rslt);
- if (rslt == 0) return; // no more messages
- handleMidiIn(buffer);
- }
- }
-
- public void writeShort(int when, int msg) throws JPortMidiException {
- if (output == null)
- throw new JPortMidiException(pmOutputNotOpen,
- "Output stream not open");
- if (trace) {
- System.out.println("writeShort: " + Integer.toHexString(msg));
- }
- checkError(pm.Pm_WriteShort(output, when, msg));
- }
-
- public void writeSysEx(int when, byte msg[]) throws JPortMidiException {
- if (output == null)
- throw new JPortMidiException(pmOutputNotOpen,
- "Output stream not open");
- if (trace) {
- System.out.print("writeSysEx: ");
- for (int i = 0; i < msg.length; i++) {
- System.out.print(Integer.toHexString(msg[i]));
- }
- System.out.print("\n");
- }
- checkError(pm.Pm_WriteSysEx(output, when, msg));
- }
-
- public int midiChanMessage(int chan, int status, int data1, int data2) {
- return (((data2 << 16) & 0xFF0000) |
- ((data1 << 8) & 0xFF00) |
- (status & 0xF0) |
- (chan & 0xF));
- }
-
- public int midiMessage(int status, int data1, int data2) {
- return ((((data2) << 16) & 0xFF0000) |
- (((data1) << 8) & 0xFF00) |
- ((status) & 0xFF));
- }
-
- public void midiAllOff(int channel) throws JPortMidiException {
- midiAllOff(channel, NOW);
- }
-
- public void midiAllOff(int chan, int when) throws JPortMidiException {
- writeShort(when, midiChanMessage(chan, MIDI_CONTROL, CTRL_ALL_OFF, 0));
- }
-
- public void midiPitchBend(int chan, int value) throws JPortMidiException {
- midiPitchBend(chan, value, NOW);
- }
-
- public void midiPitchBend(int chan, int value, int when)
- throws JPortMidiException {
- writeShort(when,
- midiChanMessage(chan, MIDI_PITCH_BEND, value, value >> 7));
- }
-
- public void midiClock() throws JPortMidiException {
- midiClock(NOW);
- }
-
- public void midiClock(int when) throws JPortMidiException {
- writeShort(when, midiMessage(MIDI_CLOCK, 0, 0));
- }
-
- public void midiControl(int chan, int control, int value)
- throws JPortMidiException {
- midiControl(chan, control, value, NOW);
- }
-
- public void midiControl(int chan, int control, int value, int when)
- throws JPortMidiException {
- writeShort(when, midiChanMessage(chan, MIDI_CONTROL, control, value));
- }
-
- public void midiNote(int chan, int pitch, int vel)
- throws JPortMidiException {
- midiNote(chan, pitch, vel, NOW);
- }
-
- public void midiNote(int chan, int pitch, int vel, int when)
- throws JPortMidiException {
- writeShort(when, midiChanMessage(chan, MIDI_NOTE_ON, pitch, vel));
- }
-
- public void midiProgram(int chan, int program)
- throws JPortMidiException {
- midiProgram(chan, program, NOW);
- }
-
- public void midiProgram(int chan, int program, int when)
- throws JPortMidiException {
- writeShort(when, midiChanMessage(chan, MIDI_PROGRAM, program, 0));
- }
-
- public void midiStart()
- throws JPortMidiException {
- midiStart(NOW);
- }
-
- public void midiStart(int when)
- throws JPortMidiException {
- writeShort(when, midiMessage(MIDI_START, 0, 0));
- }
-
- public void midiStop()
- throws JPortMidiException {
- midiStop(NOW);
- }
-
- public void midiStop(int when)
- throws JPortMidiException {
- writeShort(when, midiMessage(MIDI_STOP, 0, 0));
- }
-
- public void midiPolyTouch(int chan, int key, int value)
- throws JPortMidiException {
- midiPolyTouch(chan, key, value, NOW);
- }
-
- public void midiPolyTouch(int chan, int key, int value, int when)
- throws JPortMidiException {
- writeShort(when, midiChanMessage(chan, MIDI_POLY_TOUCH, key, value));
- }
-
- public void midiTouch(int chan, int value)
- throws JPortMidiException {
- midiTouch(chan, value, NOW);
- }
-
- public void midiTouch(int chan, int value, int when)
- throws JPortMidiException {
- writeShort(when, midiChanMessage(chan, MIDI_TOUCH, value, 0));
- }
-
- // ****** now we implement the message handlers ******
-
- // an array for incoming sysex messages that can grow.
- // The downside is that after getting a message, we
-
- private byte sysexBuffer[] = null;
- private int sysexBufferIndex = 0;
-
- void sysexBufferReset() {
- sysexBufferIndex = 0;
- if (sysexBuffer == null) sysexBuffer = new byte[256];
- }
-
- void sysexBufferCheck() {
- if (sysexBuffer.length < sysexBufferIndex + 4) {
- byte bigger[] = new byte[sysexBuffer.length * 2];
- for (int i = 0; i < sysexBufferIndex; i++) {
- bigger[i] = sysexBuffer[i];
- }
- sysexBuffer = bigger;
- }
- // now we have space to write some bytes
- }
-
- // call this to insert Sysex and EOX status bytes
- // call sysexBufferAppendBytes to insert anything else
- void sysexBufferAppendStatus(byte status) {
- sysexBuffer[sysexBufferIndex++] = status;
- }
-
- void sysexBufferAppendBytes(int msg, int len) {
- for (int i = 0; i < len; i++) {
- byte b = (byte) msg;
- if ((msg & 0x80) != 0) {
- if (b == 0xF7) { // end of sysex
- sysexBufferAppendStatus(b);
- sysex(sysexBuffer, sysexBufferIndex);
- return;
- }
- // recursively handle embedded real-time messages
- PmEvent buffer = new PmEvent();
- buffer.timestamp = timestamp;
- buffer.message = b;
- handleMidiIn(buffer);
- } else {
- sysexBuffer[sysexBufferIndex++] = b;
- }
- msg = msg >> 8;
- }
- }
-
- void sysexBegin(int msg) {
- sysexBufferReset(); // start from 0, we have at least 256 bytes now
- sysexBufferAppendStatus((byte) (msg & 0xFF)); // first byte is special
- sysexBufferAppendBytes(msg >> 8, 3); // process remaining bytes
- }
-
- public void handleMidiIn(PmEvent buffer)
- {
- if (trace) {
- System.out.println("handleMidiIn: " +
- Integer.toHexString(buffer.message));
- }
- // rather than pass timestamps to every handler, where typically
- // timestamps are ignored, just save the timestamp as a member
- // variable where methods can access it if they want it
- timestamp = buffer.timestamp;
- int status = buffer.message & 0xFF;
- if (status < 0x80) {
- sysexBufferCheck(); // make enough space
- sysexBufferAppendBytes(buffer.message, 4); // process 4 bytes
- return;
- }
- int command = status & 0xF0;
- int channel = status & 0x0F;
- int data1 = (buffer.message >> 8) & 0xFF;
- int data2 = (buffer.message >> 16) & 0xFF;
- switch (command) {
- case MIDI_NOTE_OFF:
- noteOff(channel, data1, data2); break;
- case MIDI_NOTE_ON:
- if (data2 > 0) {
- noteOn(channel, data1, data2); break;
- } else {
- noteOff(channel, data1);
- }
- break;
- case MIDI_CONTROL:
- control(channel, data1, data2); break;
- case MIDI_POLY_TOUCH:
- polyTouch(channel, data1, data2); break;
- case MIDI_TOUCH:
- touch(channel, data1); break;
- case MIDI_PITCH_BEND:
- pitchBend(channel, (data1 + (data2 << 7)) - 8192); break;
- case MIDI_PROGRAM:
- program(channel, data1); break;
- case 0xF0:
- switch (channel) {
- case 0: sysexBegin(buffer.message); break;
- case 1: mtcQuarterFrame(data1);
- case 2: songPosition(data1 + (data2 << 7)); break;
- case 3: songSelect(data1); break;
- case 4: /* unused */ break;
- case 5: /* unused */ break;
- case 6: tuneRequest(); break;
- case 7: sysexBufferAppendBytes(buffer.message, buffer.message); break;
- case 8: clock(); break;
- case 9: tick(); break;
- case 0xA: clockStart(); break;
- case 0xB: clockContinue(); break;
- case 0xC: clockStop(); break;
- case 0xD: /* unused */ break;
- case 0xE: activeSense(); break;
- case 0xF: reset(); break;
- }
- }
- }
-
- // the value ranges from +8181 to -8192. The interpretation is
- // synthesizer dependent. Often the range is +/- one whole step
- // (two semitones), but the range is usually adjustable within
- // the synthesizer.
- void pitchBend(int channel, int value) { return; }
- void control(int channel, int control, int value) { return; }
- void noteOn(int channel, int pitch, int velocity) { return; }
- // you can handle velocity in note-off if you want, but the default
- // is to drop the velocity and call the simpler NoteOff handler
- void noteOff(int channel, int pitch, int velocity) {
- noteOff(channel, pitch);
- }
- // if the subclass wants to implement NoteOff with velocity, it
- // should override the following to make sure all NoteOffs are handled
- void noteOff(int channel, int pitch) { return; }
- void program(int channel, int program) { return; }
- // the byte array may be bigger than the message, length tells how
- // many bytes in the array are part of the message
- void sysex(byte[] msg, int length) { return; }
- void polyTouch(int channel, int key, int value) { return; }
- void touch(int channel, int value) { return; }
- void mtcQuarterFrame(int value) { return; }
- // the value is a 14-bit integer representing 16th notes
- void songPosition(int value) { return; }
- void songSelect(int value) { return; }
- void tuneRequest() { return; }
- void clock() { return; } // represents 1/24th of a quarter note
- void tick() { return; } // represents 10ms
- void clockStart() { return; }
- void clockStop() { return; }
- void clockContinue() { return; }
- void activeSense() { return; }
- void reset() { return; }
-}
diff --git a/portmidi/pm_java/jportmidi/JPortMidiApi.java b/portmidi/pm_java/jportmidi/JPortMidiApi.java
deleted file mode 100644
index 45dd9d9..0000000
--- a/portmidi/pm_java/jportmidi/JPortMidiApi.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package jportmidi;
-
-public class JPortMidiApi {
- public static class PortMidiStream {
- private long address;
- }
- public static class PmEvent {
- public int message;
- public int timestamp;
- }
-
- // PmError bindings
- public final int pmNoError = 0;
- public final int pmNoData = 0;
- public final int pmGotData = -1;
- public final int pmHostError = -10000;
- public final int pmInvalidDeviceId = -9999;
- public final int pmInsufficientMemory = -9998;
- public final int pmBufferTooSmall = -9997;
- public final int pmBufferOverflow = -9996;
- public final int pmBadPtr = -9995;
- public final int pmBadData = -9994;
- public final int pmInternalError = -9993;
- public final int pmBufferMaxSize = -9992;
-
- static public native int Pm_Initialize();
- static public native int Pm_Terminate();
- static public native int Pm_HasHostError(PortMidiStream stream);
- static public native String Pm_GetErrorText(int errnum);
- static public native String Pm_GetHostErrorText();
- final int pmNoDevice = -1;
- static public native int Pm_CountDevices();
- static public native int Pm_GetDefaultInputDeviceID();
- static public native int Pm_GetDefaultOutputDeviceID();
- static public native String Pm_GetDeviceInterf(int i);
- static public native String Pm_GetDeviceName(int i);
- static public native boolean Pm_GetDeviceInput(int i);
- static public native boolean Pm_GetDeviceOutput(int i);
- static public native int Pm_OpenInput(PortMidiStream stream,
- int inputDevice,
- String inputDriverInfo,
- int bufferSize);
- static public native int Pm_OpenOutput(PortMidiStream stream,
- int outputDevice,
- String outnputDriverInfo,
- int bufferSize,
- int latency);
- final static public int PM_FILT_ACTIVE = (1 << 0x0E);
- final static public int PM_FILT_SYSEX = (1 << 0x00);
- final static public int PM_FILT_CLOCK = (1 << 0x08);
- final static public int PM_FILT_PLAY =
- (1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B);
- final static public int PM_FILT_TICK = (1 << 0x09);
- final static public int PM_FILT_FD = (1 << 0x0D);
- final static public int PM_FILT_UNDEFINED = PM_FILT_FD;
- final static public int PM_FILT_RESET = (1 << 0x0F);
- final static public int PM_FILT_REALTIME =
- PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK;
- final static public int PM_FILT_NOTE = (1 << 0x19) | (1 << 0x18);
- final static public int PM_FILT_CHANNEL_AFTERTOUCH = (1 << 0x1D);
- final static public int PM_FILT_POLY_AFTERTOUCH = (1 << 0x1A);
- final static public int PM_FILT_AFTERTOUCH =
- (PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH);
- final static public int PM_FILT_PROGRAM = (1 << 0x1C);
- final static public int PM_FILT_CONTROL = (1 << 0x1B);
- final static public int PM_FILT_PITCHBEND = (1 << 0x1E);
- final static public int PM_FILT_MTC = (1 << 0x01);
- final static public int PM_FILT_SONG_POSITION = (1 << 0x02);
- final static public int PM_FILT_SONG_SELECT = (1 << 0x03);
- final static public int PM_FILT_TUNE = (1 << 0x06);
- final static public int PM_FILT_SYSTEMCOMMON =
- (PM_FILT_MTC | PM_FILT_SONG_POSITION |
- PM_FILT_SONG_SELECT | PM_FILT_TUNE);
- static public native int Pm_SetFilter(PortMidiStream stream, int filters);
- static public int Pm_Channel(int channel) { return 1 << channel; }
- final static public native int Pm_SetChannelMask(PortMidiStream stream,
- int mask);
- final static public native int Pm_Abort(PortMidiStream stream);
- final static public native int Pm_Close(PortMidiStream stream);
- static public int Pm_Message(int status, int data1, int data2) {
- return (((data2 << 16) & 0xFF0000) |
- ((data1 << 8) & 0xFF00) |
- (status & 0xFF));
- }
- static public int Pm_MessageStatus(int msg) {
- return msg & 0xFF;
- }
- static public int Pm_MessageData1(int msg) {
- return (msg >> 8) & 0xFF;
- }
- static public int Pm_MessageData2(int msg) {
- return (msg >> 16) & 0xFF;
- }
- // only supports reading one buffer at a time
- static public native int Pm_Read(PortMidiStream stream, PmEvent buffer);
- static public native int Pm_Poll(PortMidiStream stream);
- // only supports writing one buffer at a time
- static public native int Pm_Write(PortMidiStream stream, PmEvent buffer);
- static public native int Pm_WriteShort(PortMidiStream stream,
- int when, int msg);
- static public native int Pm_WriteSysEx(PortMidiStream stream,
- int when, byte msg[]);
-
- public final int ptNoError = 0;
- public final int ptAlreadyStarted = -10000;
- public final int ptAlreadyStopped = -9999;
- public final int PtInsufficientMemory = -9998;
- static public native int Pt_TimeStart(int resolution);
- static public native int Pt_TimeStop();
- static public native int Pt_Time();
- static public native boolean Pt_TimeStarted();
- static {
- System.out.println("Loading pmjni");
- System.loadLibrary("pmjni");
- System.out.println("done loading pmjni");
- }
-}
diff --git a/portmidi/pm_java/jportmidi/JPortMidiException.java b/portmidi/pm_java/jportmidi/JPortMidiException.java
deleted file mode 100644
index 9be8aaf..0000000
--- a/portmidi/pm_java/jportmidi/JPortMidiException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-// JPortMidiException -- thrown by JPortMidi methods
-
-package jportmidi;
-
-public class JPortMidiException extends Exception {
- public int error = 0;
- public JPortMidiException(int err, String msg) {
- super(msg);
- error = err;
- }
-}
-
diff --git a/portmidi/pm_java/make.bat b/portmidi/pm_java/make.bat
deleted file mode 100644
index ff15c2b..0000000
--- a/portmidi/pm_java/make.bat
+++ /dev/null
@@ -1,50 +0,0 @@
-@echo off
-
-rem This is an out-of-date script for Windows to build a Java application
-rem (PmDefaults) with PortMidi external library.xb
-
-rem Compile the java PortMidi interface classes.
-javac jportmidi/*.java
-
-rem Compile the pmdefaults application.
-javac -classpath . pmdefaults/*.java
-
-rem Temporarily copy the portmusic_logo.png file here to add to the jar file.
-copy pmdefaults\portmusic_logo.png . > nul
-
-rem Create a directory to hold the distribution.
-mkdir win32
-
-rem Attempt to copy the interface DLL to the distribution directory.
-
-if exist "..\release\pmjni.dll" goto have-dll
-
-echo "ERROR: pmjni.dll not found!"
-exit /b 1
-
-:have-dll
-copy "..\release\pmjni.dll" win32\pmjni.dll > nul
-
-rem Create a java archive (jar) file of the distribution.
-jar cmf pmdefaults\manifest.txt win32\pmdefaults.jar pmdefaults\*.class portmusic_logo.png jportmidi\*.class
-
-rem Clean up the temporary image file now that it is in the jar file.
-del portmusic_logo.png
-
-rem Copy the java execution code obtained from
-rem http://devwizard.free.fr/html/en/JavaExe.html to the distribution
-rem directory. The copy also renames the file to our desired executable
-rem name.
-copy JavaExe.exe win32\pmdefaults.exe > nul
-
-rem Integrate the icon into the executable using UpdateRsrcJavaExe from
-rem http://devwizard.free.fr
-UpdateRsrcJavaExe -run -exe=win32\pmdefaults.exe -ico=pmdefaults\pmdefaults.ico
-
-rem Copy the 32-bit windows read me file to the distribution directory.
-copy pmdefaults\readme-win32.txt win32\README.txt > nul
-
-rem Copy the license file to the distribution directory.
-copy pmdefaults\pmdefaults-license.txt win32\license.txt > nul
-
-echo "You can run pmdefaults.exe in win32"
diff --git a/portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h b/portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h
deleted file mode 100644
index 2208be6..0000000
--- a/portmidi/pm_java/pmjni/jportmidi_JportMidiApi.h
+++ /dev/null
@@ -1,293 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class jportmidi_JPortMidiApi */
-
-#ifndef _Included_jportmidi_JPortMidiApi
-#define _Included_jportmidi_JPortMidiApi
-#ifdef __cplusplus
-extern "C" {
-#endif
-#undef jportmidi_JPortMidiApi_PM_FILT_ACTIVE
-#define jportmidi_JPortMidiApi_PM_FILT_ACTIVE 16384L
-#undef jportmidi_JPortMidiApi_PM_FILT_SYSEX
-#define jportmidi_JPortMidiApi_PM_FILT_SYSEX 1L
-#undef jportmidi_JPortMidiApi_PM_FILT_CLOCK
-#define jportmidi_JPortMidiApi_PM_FILT_CLOCK 256L
-#undef jportmidi_JPortMidiApi_PM_FILT_PLAY
-#define jportmidi_JPortMidiApi_PM_FILT_PLAY 7168L
-#undef jportmidi_JPortMidiApi_PM_FILT_TICK
-#define jportmidi_JPortMidiApi_PM_FILT_TICK 512L
-#undef jportmidi_JPortMidiApi_PM_FILT_FD
-#define jportmidi_JPortMidiApi_PM_FILT_FD 8192L
-#undef jportmidi_JPortMidiApi_PM_FILT_UNDEFINED
-#define jportmidi_JPortMidiApi_PM_FILT_UNDEFINED 8192L
-#undef jportmidi_JPortMidiApi_PM_FILT_RESET
-#define jportmidi_JPortMidiApi_PM_FILT_RESET 32768L
-#undef jportmidi_JPortMidiApi_PM_FILT_REALTIME
-#define jportmidi_JPortMidiApi_PM_FILT_REALTIME 16641L
-#undef jportmidi_JPortMidiApi_PM_FILT_NOTE
-#define jportmidi_JPortMidiApi_PM_FILT_NOTE 50331648L
-#undef jportmidi_JPortMidiApi_PM_FILT_CHANNEL_AFTERTOUCH
-#define jportmidi_JPortMidiApi_PM_FILT_CHANNEL_AFTERTOUCH 536870912L
-#undef jportmidi_JPortMidiApi_PM_FILT_POLY_AFTERTOUCH
-#define jportmidi_JPortMidiApi_PM_FILT_POLY_AFTERTOUCH 67108864L
-#undef jportmidi_JPortMidiApi_PM_FILT_AFTERTOUCH
-#define jportmidi_JPortMidiApi_PM_FILT_AFTERTOUCH 603979776L
-#undef jportmidi_JPortMidiApi_PM_FILT_PROGRAM
-#define jportmidi_JPortMidiApi_PM_FILT_PROGRAM 268435456L
-#undef jportmidi_JPortMidiApi_PM_FILT_CONTROL
-#define jportmidi_JPortMidiApi_PM_FILT_CONTROL 134217728L
-#undef jportmidi_JPortMidiApi_PM_FILT_PITCHBEND
-#define jportmidi_JPortMidiApi_PM_FILT_PITCHBEND 1073741824L
-#undef jportmidi_JPortMidiApi_PM_FILT_MTC
-#define jportmidi_JPortMidiApi_PM_FILT_MTC 2L
-#undef jportmidi_JPortMidiApi_PM_FILT_SONG_POSITION
-#define jportmidi_JPortMidiApi_PM_FILT_SONG_POSITION 4L
-#undef jportmidi_JPortMidiApi_PM_FILT_SONG_SELECT
-#define jportmidi_JPortMidiApi_PM_FILT_SONG_SELECT 8L
-#undef jportmidi_JPortMidiApi_PM_FILT_TUNE
-#define jportmidi_JPortMidiApi_PM_FILT_TUNE 64L
-#undef jportmidi_JPortMidiApi_PM_FILT_SYSTEMCOMMON
-#define jportmidi_JPortMidiApi_PM_FILT_SYSTEMCOMMON 78L
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_Initialize
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Initialize
- (JNIEnv *, jclass);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_Terminate
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Terminate
- (JNIEnv *, jclass);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_HasHostError
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1HasHostError
- (JNIEnv *, jclass, jobject);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_GetErrorText
- * Signature: (I)Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetErrorText
- (JNIEnv *, jclass, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_GetHostErrorText
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetHostErrorText
- (JNIEnv *, jclass);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_CountDevices
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1CountDevices
- (JNIEnv *, jclass);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_GetDefaultInputDeviceID
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultInputDeviceID
- (JNIEnv *, jclass);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_GetDefaultOutputDeviceID
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultOutputDeviceID
- (JNIEnv *, jclass);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_GetDeviceInterf
- * Signature: (I)Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInterf
- (JNIEnv *, jclass, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_GetDeviceName
- * Signature: (I)Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceName
- (JNIEnv *, jclass, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_GetDeviceInput
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInput
- (JNIEnv *, jclass, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_GetDeviceOutput
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceOutput
- (JNIEnv *, jclass, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_OpenInput
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;ILjava/lang/String;I)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenInput
- (JNIEnv *, jclass, jobject, jint, jstring, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_OpenOutput
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;ILjava/lang/String;II)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenOutput
- (JNIEnv *, jclass, jobject, jint, jstring, jint, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_SetFilter
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetFilter
- (JNIEnv *, jclass, jobject, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_SetChannelMask
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetChannelMask
- (JNIEnv *, jclass, jobject, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_Abort
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Abort
- (JNIEnv *, jclass, jobject);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_Close
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Close
- (JNIEnv *, jclass, jobject);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_Read
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;Ljportmidi/JPortMidiApi/PmEvent;)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Read
- (JNIEnv *, jclass, jobject, jobject);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_Poll
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Poll
- (JNIEnv *, jclass, jobject);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_Write
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;Ljportmidi/JPortMidiApi/PmEvent;)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Write
- (JNIEnv *, jclass, jobject, jobject);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_WriteShort
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;II)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteShort
- (JNIEnv *, jclass, jobject, jint, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pm_WriteSysEx
- * Signature: (Ljportmidi/JPortMidiApi/PortMidiStream;I[B)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteSysEx
- (JNIEnv *, jclass, jobject, jint, jbyteArray);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pt_TimeStart
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStart
- (JNIEnv *, jclass, jint);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pt_TimeStop
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStop
- (JNIEnv *, jclass);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pt_Time
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1Time
- (JNIEnv *, jclass);
-
-/*
- * Class: jportmidi_JPortMidiApi
- * Method: Pt_TimeStarted
- * Signature: ()Z
- */
-JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStarted
- (JNIEnv *, jclass);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-/* Header for class jportmidi_JPortMidiApi_PmEvent */
-
-#ifndef _Included_jportmidi_JPortMidiApi_PmEvent
-#define _Included_jportmidi_JPortMidiApi_PmEvent
-#ifdef __cplusplus
-extern "C" {
-#endif
-#ifdef __cplusplus
-}
-#endif
-#endif
-/* Header for class jportmidi_JPortMidiApi_PortMidiStream */
-
-#ifndef _Included_jportmidi_JPortMidiApi_PortMidiStream
-#define _Included_jportmidi_JPortMidiApi_PortMidiStream
-#ifdef __cplusplus
-extern "C" {
-#endif
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/portmidi/pm_java/pmjni/pmjni.c b/portmidi/pm_java/pmjni/pmjni.c
deleted file mode 100644
index c60cffb..0000000
--- a/portmidi/pm_java/pmjni/pmjni.c
+++ /dev/null
@@ -1,354 +0,0 @@
-#include "portmidi.h"
-#include "porttime.h"
-#include "jportmidi_JportMidiApi.h"
-#include <stdio.h>
-
-// these macros assume JNIEnv *env is declared and valid:
-//
-#define CLASS(c, obj) jclass c = (*env)->GetObjectClass(env, obj)
-#define ADDRESS_FID(fid, c) \
- jfieldID fid = (*env)->GetFieldID(env, c, "address", "J")
-// Uses Java Long (64-bit) to make sure there is room to store a
-// pointer. Cast this to a C long (either 32 or 64 bit) to match
-// the size of a pointer. Finally cast int to pointer. All this
-// is supposed to avoid C compiler warnings and (worse) losing
-// address bits.
-#define PMSTREAM(obj, fid) ((PmStream *) (intptr_t) (*env)->GetLongField(env, obj, fid))
-// Cast stream to long to convert integer to pointer, then expand
-// integer to 64-bit jlong. This avoids compiler warnings.
-#define SET_PMSTREAM(obj, fid, stream) \
- (*env)->SetLongField(env, obj, fid, (jlong) (intptr_t) stream)
-
-
-/*
- * Method: Pm_Initialize
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Initialize
- (JNIEnv *env, jclass cl)
-{
- return Pm_Initialize();
-}
-
-
-/*
- * Method: Pm_Terminate
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Terminate
- (JNIEnv *env, jclass cl)
-{
- return Pm_Terminate();
-}
-
-
-/*
- * Method: Pm_HasHostError
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1HasHostError
- (JNIEnv *env, jclass cl, jobject jstream)
-{
- CLASS(c, jstream);
- ADDRESS_FID(fid, c);
- return Pm_HasHostError(PMSTREAM(jstream, fid));
-}
-
-
-/*
- * Method: Pm_GetErrorText
- */
-JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetErrorText
- (JNIEnv *env, jclass cl, jint i)
-{
- return (*env)->NewStringUTF(env, Pm_GetErrorText(i));
-}
-
-
-/*
- * Method: Pm_GetHostErrorText
- */
-JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetHostErrorText
- (JNIEnv *env, jclass cl)
-{
- char msg[PM_HOST_ERROR_MSG_LEN];
- Pm_GetHostErrorText(msg, PM_HOST_ERROR_MSG_LEN);
- return (*env)->NewStringUTF(env, msg);
-}
-
-
-/*
- * Method: Pm_CountDevices
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1CountDevices
- (JNIEnv *env, jclass cl)
-{
- return Pm_CountDevices();
-}
-
-
-/*
- * Method: Pm_GetDefaultInputDeviceID
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultInputDeviceID
- (JNIEnv *env, jclass cl)
-{
- return Pm_GetDefaultInputDeviceID();
-}
-
-
-/*
- * Method: Pm_GetDefaultOutputDeviceID
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDefaultOutputDeviceID
- (JNIEnv *env, jclass cl)
-{
- return Pm_GetDefaultOutputDeviceID();
-}
-
-
-/*
- * Method: Pm_GetDeviceInterf
- */
-JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInterf
- (JNIEnv *env, jclass cl, jint i)
-{
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (!info) return NULL;
- return (*env)->NewStringUTF(env, info->interf);
-}
-
-
-/*
- * Method: Pm_GetDeviceName
- */
-JNIEXPORT jstring JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceName
- (JNIEnv *env, jclass cl, jint i)
-{
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (!info) return NULL;
- return (*env)->NewStringUTF(env, info->name);
-}
-
-
-/*
- * Method: Pm_GetDeviceInput
- */
-JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceInput
- (JNIEnv *env, jclass cl, jint i)
-{
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (!info) return (jboolean) 0;
- return (jboolean) info->input;
-}
-
-
-/*
- * Method: Pm_GetDeviceOutput
- */
-JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pm_1GetDeviceOutput
- (JNIEnv *env, jclass cl, jint i)
-{
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (!info) return (jboolean) 0;
- return (jboolean) info->output;
-}
-
-
-/*
- * Method: Pm_OpenInput
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenInput
- (JNIEnv *env, jclass cl,
- jobject jstream, jint index, jstring extras, jint bufsiz)
-{
- PmError rslt;
- PortMidiStream *stream;
- CLASS(c, jstream);
- ADDRESS_FID(fid, c);
- rslt = Pm_OpenInput(&stream, index, NULL, bufsiz, NULL, NULL);
- SET_PMSTREAM(jstream, fid, stream);
- return rslt;
-}
-
-
-/*
- * Method: Pm_OpenOutput
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1OpenOutput
- (JNIEnv *env, jclass cl, jobject jstream, jint index, jstring extras,
- jint bufsiz, jint latency)
-{
- PmError rslt;
- PortMidiStream *stream;
- CLASS(c, jstream);
- ADDRESS_FID(fid, c);
- rslt = Pm_OpenOutput(&stream, index, NULL, bufsiz, NULL, NULL, latency);
- SET_PMSTREAM(jstream, fid, stream);
- return rslt;
-}
-
-
-/*
- * Method: Pm_SetFilter
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetFilter
- (JNIEnv *env, jclass cl, jobject jstream, jint filters)
-{
- CLASS(c, jstream);
- ADDRESS_FID(fid, c);
- return Pm_SetFilter(PMSTREAM(jstream, fid), filters);
-}
-
-
-/*
- * Method: Pm_SetChannelMask
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1SetChannelMask
- (JNIEnv *env, jclass cl, jobject jstream, jint mask)
-{
- CLASS(c, jstream);
- ADDRESS_FID(fid, c);
- return Pm_SetChannelMask(PMSTREAM(jstream, fid), mask);
-}
-
-
-/*
- * Method: Pm_Abort
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Abort
- (JNIEnv *env, jclass cl, jobject jstream)
-{
- CLASS(c, jstream);
- ADDRESS_FID(fid, c);
- return Pm_Abort(PMSTREAM(jstream, fid));
-}
-
-
-/*
- * Method: Pm_Close
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Close
- (JNIEnv *env, jclass cl, jobject jstream)
-{
- CLASS(c, jstream);
- ADDRESS_FID(fid, c);
- return Pm_Close(PMSTREAM(jstream, fid));
-}
-
-
-/*
- * Method: Pm_Read
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Read
- (JNIEnv *env, jclass cl, jobject jstream, jobject jpmevent)
-{
- CLASS(jstream_class, jstream);
- ADDRESS_FID(address_fid, jstream_class);
- jclass jpmevent_class = (*env)->GetObjectClass(env, jpmevent);
- jfieldID message_fid =
- (*env)->GetFieldID(env, jpmevent_class, "message", "I");
- jfieldID timestamp_fid =
- (*env)->GetFieldID(env, jpmevent_class, "timestamp", "I");
- PmEvent buffer;
- PmError rslt = Pm_Read(PMSTREAM(jstream, address_fid), &buffer, 1);
- (*env)->SetIntField(env, jpmevent, message_fid, buffer.message);
- (*env)->SetIntField(env, jpmevent, timestamp_fid, buffer.timestamp);
- return rslt;
-}
-
-
-/*
- * Method: Pm_Poll
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Poll
- (JNIEnv *env, jclass cl, jobject jstream)
-{
- CLASS(c, jstream);
- ADDRESS_FID(fid, c);
- return Pm_Poll(PMSTREAM(jstream, fid));
-}
-
-
-/*
- * Method: Pm_Write
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1Write
- (JNIEnv *env, jclass cl, jobject jstream, jobject jpmevent)
-{
- CLASS(jstream_class, jstream);
- ADDRESS_FID(address_fid, jstream_class);
- jclass jpmevent_class = (*env)->GetObjectClass(env, jpmevent);
- jfieldID message_fid =
- (*env)->GetFieldID(env, jpmevent_class, "message", "I");
- jfieldID timestamp_fid =
- (*env)->GetFieldID(env, jpmevent_class, "timestamp", "I");
- // note that we call WriteShort because it's simpler than constructing
- // a buffer and passing it to Pm_Write
- return Pm_WriteShort(PMSTREAM(jstream, address_fid),
- (*env)->GetIntField(env, jpmevent, timestamp_fid),
- (*env)->GetIntField(env, jpmevent, message_fid));
-}
-
-
-/*
- * Method: Pm_WriteShort
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteShort
- (JNIEnv *env, jclass cl, jobject jstream, jint when, jint msg)
-{
- CLASS(c, jstream);
- ADDRESS_FID(fid, c);
- return Pm_WriteShort(PMSTREAM(jstream, fid), when, msg);
-}
-
-
-/*
- * Method: Pm_WriteSysEx
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pm_1WriteSysEx
- (JNIEnv *env, jclass cl, jobject jstream, jint when, jbyteArray jmsg)
-{
- CLASS(c, jstream);
- ADDRESS_FID(fid, c);
- jbyte *bytes = (*env)->GetByteArrayElements(env, jmsg, 0);
- PmError rslt = Pm_WriteSysEx(PMSTREAM(jstream, fid), when,
- (unsigned char *) bytes);
- (*env)->ReleaseByteArrayElements(env, jmsg, bytes, 0);
- return rslt;
-}
-
-/*
- * Method: Pt_TimeStart
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStart
- (JNIEnv *env, jclass c, jint resolution)
-{
- return Pt_Start(resolution, NULL, NULL);
-}
-
-/*
- * Method: Pt_TimeStop
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStop
- (JNIEnv *env, jclass c)
- {
- return Pt_Stop();
- }
-
-/*
- * Method: Pt_Time
- */
-JNIEXPORT jint JNICALL Java_jportmidi_JPortMidiApi_Pt_1Time
- (JNIEnv *env, jclass c)
- {
- return Pt_Time();
- }
-
-/*
- * Method: Pt_TimeStarted
- */
-JNIEXPORT jboolean JNICALL Java_jportmidi_JPortMidiApi_Pt_1TimeStarted
- (JNIEnv *env, jclass c)
-{
- return Pt_Started();
-}
-
-
diff --git a/portmidi/pm_java/pmjni/pmjni.rc b/portmidi/pm_java/pmjni/pmjni.rc
deleted file mode 100644
index 1b7522b..0000000
--- a/portmidi/pm_java/pmjni/pmjni.rc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE
-BEGIN
- "#include ""afxres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
diff --git a/portmidi/pm_linux/README_LINUX.txt b/portmidi/pm_linux/README_LINUX.txt
deleted file mode 100755
index cfbc43f..0000000
--- a/portmidi/pm_linux/README_LINUX.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-README_LINUX.txt for PortMidi
-Roger Dannenberg
-6 Dec 2012, revised May 2022
-
-Contents:
- To make PortMidi
- The pmdefaults program
- Setting LD_LIBRARY_PATH
- A note about amd64
- Using autoconf
- Using configure
- Changelog
-
-
-See ../README.md for general instructions.
-
-THE pmdefaults PROGRAM
-
-(This may be obsolete. It is older than `../README.md` which
-also discusses pmdefaults, and Java support may be removed
-unless someone claims they use it... -RBD)
-
-You should install pmdefaults. It provides a graphical interface
-for selecting default MIDI IN and OUT devices so that you don't
-have to build device selection interfaces into all your programs
-and so users have a single place to set a preference.
-
-Follow the instructions above to run ccmake, making sure that
-CMAKE_BUILD_TYPE is Release. Run make as described above. Then:
-
-sudo make install
-
-This will install PortMidi libraries and the pmdefault program.
-You must alos have the environment variable LD_LIBRARY_PATH set
-to include /usr/local/lib (where libpmjni.so is installed).
-
-Now, you can run pmdefault.
-
-
-SETTING LD_LIBRARY_PATH
-
-pmdefaults will not work unless LD_LIBRARY_PATH includes a
-directory (normally /usr/local/lib) containing libpmjni.so,
-installed as described above.
-
-To set LD_LIBRARY_PATH, you might want to add this to your
-~/.profile (if you use the bash shell):
-
-LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
-export LD_LIBRARY_PATH
-
-
-A NOTE ABOUT AMD64:
-
-When compiling portmidi under linux on an AMD64, I had to add the -fPIC
-flag to the gcc flags.
-
-Reason: when trying to build John Harrison's pyPortMidi gcc bailed out
-with this error:
-
-./linux/libportmidi.a(pmlinux.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC
-./linux/libportmidi.a: could not read symbols: Bad value
-collect2: ld returned 1 exit status
-error: command 'gcc' failed with exit status 1
-
-What they said:
-http://www.gentoo.org/proj/en/base/amd64/howtos/index.xml?part=1&chap=3
-On certain architectures (AMD64 amongst them), shared libraries *must*
-be "PIC-enabled".
-
-CHANGELOG
-
-27-may-2022 Roger B. Dannenberg
- Some updates to this file.
-
-6-dec-2012 Roger B. Dannenberg
- Copied notes on Autoconf from Audacity sources
-
-22-jan-2010 Roger B. Dannenberg
- Updated instructions about Java paths
-
-14-oct-2009 Roger B. Dannenberg
- Using CMake now for building and configuration
-
-29-aug-2006 Roger B. Dannenberg
- Fixed PortTime to join with time thread for clean exit.
-
-28-aug-2006 Roger B. Dannenberg
- Updated this documentation.
-
-08-Jun-2004 Roger B. Dannenberg
- Updated code to use new system abstraction.
-
-12-Apr-2003 Roger B. Dannenberg
- Fixed pm_test/test.c to filter clocks and active messages.
- Integrated changes from Clemens Ladisch:
- cleaned up pmlinuxalsa.c
- record timestamp on sysex input
- deallocate some resources previously left open
diff --git a/portmidi/pm_linux/pmlinux.c b/portmidi/pm_linux/pmlinux.c
deleted file mode 100755
index 3766427..0000000
--- a/portmidi/pm_linux/pmlinux.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/* pmlinux.c -- PortMidi os-dependent code */
-
-/* This file only needs to implement pm_init(), which calls various
- routines to register the available midi devices. This file must
- be separate from the main portmidi.c file because it is system
- dependent, and it is separate from, pmlinuxalsa.c, because it
- might need to register non-alsa devices as well.
-
- NOTE: if you add non-ALSA support, you need to fix :alsa_poll()
- in pmlinuxalsa.c, which assumes all input devices are ALSA.
- */
-
-#include "stdlib.h"
-#include "portmidi.h"
-#include "pmutil.h"
-#include "pminternal.h"
-
-#ifdef PMALSA
- #include "pmlinuxalsa.h"
-#endif
-
-#ifdef PMNULL
- #include "pmlinuxnull.h"
-#endif
-
-#if !(defined(PMALSA) || defined(PMNULL))
-#error One of PMALSA or PMNULL must be defined
-#endif
-
-void pm_init()
-{
- /* Note: it is not an error for PMALSA to fail to initialize.
- * It may be a design error that the client cannot query what subsystems
- * are working properly other than by looking at the list of available
- * devices.
- */
-#ifdef PMALSA
- pm_linuxalsa_init();
-#endif
-#ifdef PMNULL
- pm_linuxnull_init();
-#endif
-}
-
-void pm_term(void)
-{
- #ifdef PMALSA
- pm_linuxalsa_term();
- #endif
- #ifdef PMNULL
- pm_linuxnull_term();
- #endif
-}
-
-PmDeviceID Pm_GetDefaultInputDeviceID() {
- Pm_Initialize();
- return pm_default_input_device_id;
-}
-
-PmDeviceID Pm_GetDefaultOutputDeviceID() {
- Pm_Initialize();
- return pm_default_output_device_id;
-}
-
-void *pm_alloc(size_t s) { return malloc(s); }
-
-void pm_free(void *ptr) { free(ptr); }
-
diff --git a/portmidi/pm_linux/pmlinuxalsa.c b/portmidi/pm_linux/pmlinuxalsa.c
deleted file mode 100755
index b2e43e1..0000000
--- a/portmidi/pm_linux/pmlinuxalsa.c
+++ /dev/null
@@ -1,893 +0,0 @@
-/*
- * pmlinuxalsa.c -- system specific definitions
- *
- * written by:
- * Roger Dannenberg (port to Alsa 0.9.x)
- * Clemens Ladisch (provided code examples and invaluable consulting)
- * Jason Cohen, Rico Colon, Matt Filippone (Alsa 0.5.x implementation)
- */
-
-/* omit this code if PMALSA is not defined -- this mechanism allows
- * selection of different MIDI interfaces (at compile time).
- */
-#ifdef PMALSA
-
-#include "stdlib.h"
-#include "portmidi.h"
-#include "pmutil.h"
-#include "pminternal.h"
-#include "pmlinuxalsa.h"
-#include "string.h"
-#include "porttime.h"
-
-#include <alsa/asoundlib.h>
-
-/* I used many print statements to debug this code. I left them in the
- * source, and you can turn them on by changing false to true below:
- */
-#define VERBOSE_ON 0
-#define VERBOSE if (VERBOSE_ON)
-
-#define MIDI_SYSEX 0xf0
-#define MIDI_EOX 0xf7
-
-#if SND_LIB_MAJOR == 0 && SND_LIB_MINOR < 9
-#error needs ALSA 0.9.0 or later
-#endif
-
-/* to store client/port in the device descriptor */
-#define MAKE_DESCRIPTOR(client, port) ((void*)(long)(((client) << 8) | (port)))
-#define GET_DESCRIPTOR_CLIENT(info) ((((long)(info)) >> 8) & 0xff)
-#define GET_DESCRIPTOR_PORT(info) (((long)(info)) & 0xff)
-
-#define BYTE unsigned char
-
-extern pm_fns_node pm_linuxalsa_in_dictionary;
-extern pm_fns_node pm_linuxalsa_out_dictionary;
-
-static snd_seq_t *seq = NULL; // all input comes here,
- // output queue allocated on seq
-static int queue, queue_used; /* one for all ports, reference counted */
-
-#define PORT_IS_CLOSED -999999
-
-typedef struct alsa_info_struct {
- int is_virtual;
- int client;
- int port;
- int this_port;
- int in_sysex;
- snd_midi_event_t *parser;
-} alsa_info_node, *alsa_info_type;
-
-
-/* get_alsa_error_text -- copy error text to potentially short string */
-/**/
-static void get_alsa_error_text(char *msg, int len, int err)
-{
- int errlen = strlen(snd_strerror(err));
- if (errlen > 0 && errlen < len) {
- strcpy(msg, snd_strerror(err));
- } else if (len > 20) {
- sprintf(msg, "Alsa error %d", err);
- } else {
- msg[0] = 0;
- }
-}
-
-
-static PmError check_hosterror(int err)
-{
- if (err < 0) {
- get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, err);
- pm_hosterror = TRUE;
- return pmHostError;
- }
- return pmNoError;
-}
-
-
-/* queue is shared by both input and output, reference counted */
-static PmError alsa_use_queue(void)
-{
- int err = 0;
- if (queue_used == 0) {
- snd_seq_queue_tempo_t *tempo;
-
- queue = snd_seq_alloc_queue(seq);
- if (queue < 0) {
- return check_hosterror(queue);
- }
- snd_seq_queue_tempo_alloca(&tempo);
- snd_seq_queue_tempo_set_tempo(tempo, 480000);
- snd_seq_queue_tempo_set_ppq(tempo, 480);
- err = snd_seq_set_queue_tempo(seq, queue, tempo);
- if (err < 0) {
- return check_hosterror(err);
- }
- snd_seq_start_queue(seq, queue, NULL);
- snd_seq_drain_output(seq);
- }
- ++queue_used;
- return pmNoError;
-}
-
-
-static void alsa_unuse_queue(void)
-{
- if (--queue_used == 0) {
- snd_seq_stop_queue(seq, queue, NULL);
- snd_seq_drain_output(seq);
- snd_seq_free_queue(seq, queue);
- VERBOSE printf("queue freed\n");
- }
-}
-
-
-/* midi_message_length -- how many bytes in a message? */
-static int midi_message_length(PmMessage message)
-{
- message &= 0xff;
- if (message < 0x80) {
- return 0;
- } else if (message < 0xf0) {
- static const int length[] = {3, 3, 3, 3, 2, 2, 3};
- return length[(message - 0x80) >> 4];
- } else {
- static const int length[] = {
- -1, 2, 3, 2, 0, 0, 1, -1, 1, 0, 1, 1, 1, 0, 1, 1};
- return length[message - 0xf0];
- }
-}
-
-
-static alsa_info_type alsa_info_create(int client_port, long id, int is_virtual)
-{
- alsa_info_type info = (alsa_info_type) pm_alloc(sizeof(alsa_info_node));
- info->is_virtual = is_virtual;
- info->this_port = id;
- info->client = GET_DESCRIPTOR_CLIENT(client_port);
- info->port = GET_DESCRIPTOR_PORT(client_port);
- info->in_sysex = 0;
- return info;
-}
-
-
-/* search system dependent extra parameters for string */
-static const char *get_sysdep_name(enum PmSysDepPropertyKey key,
- PmSysDepInfo *info)
-{
- /* the version where all current properties were introduced is 210 */
- if (info && info->structVersion >= 210) {
- int i;
- for (i = 0; i < info->length; i++) { /* search for key */
- if (info->properties[i].key == key) {
- return info->properties[i].value;
- }
- }
- }
- return NULL;
-}
-
-
-static void maybe_set_client_name(PmSysDepInfo *driverInfo)
-{
- if (!seq) { // make sure seq is created and we have info
- return;
- }
-
- const char *client_name = get_sysdep_name(pmKeyAlsaClientName,
- (PmSysDepInfo *) driverInfo);
- if (client_name) {
- snd_seq_set_client_name(seq, client_name);
- printf("maybe_set_client_name set client to %s\n", client_name);
- }
-}
-
-
-static PmError alsa_out_open(PmInternal *midi, void *driverInfo)
-{
- int id = midi->device_id;
- void *client_port = pm_descriptors[id].descriptor;
- alsa_info_type ainfo = alsa_info_create((long) client_port, id,
- pm_descriptors[id].pub.is_virtual);
- snd_seq_port_info_t *pinfo;
- int err = 0;
- int using_the_queue = 0;
-
- if (!ainfo) return pmInsufficientMemory;
- midi->api_info = ainfo;
-
- snd_seq_port_info_alloca(&pinfo);
- if (!ainfo->is_virtual) {
- snd_seq_port_info_set_port(pinfo, id);
- snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_WRITE |
- SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ);
- snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC |
- SND_SEQ_PORT_TYPE_APPLICATION);
- const char *port_name = get_sysdep_name(pmKeyAlsaPortName,
- (PmSysDepInfo *) driverInfo);
- if (port_name) {
- snd_seq_port_info_set_name(pinfo, port_name);
- }
- snd_seq_port_info_set_port_specified(pinfo, 1);
-
- err = snd_seq_create_port(seq, pinfo);
- if (err < 0) goto free_ainfo;
-
- }
-
- err = snd_midi_event_new(PM_DEFAULT_SYSEX_BUFFER_SIZE, &ainfo->parser);
- if (err < 0) goto free_this_port;
-
- if (midi->latency > 0) { /* must delay output using a queue */
- err = alsa_use_queue();
- if (err < 0) goto free_parser;
- using_the_queue++;
- }
-
- if (!ainfo->is_virtual) {
- err = snd_seq_connect_to(seq, ainfo->this_port, ainfo->client,
- ainfo->port);
- if (err < 0) goto unuse_queue; /* clean up and return on error */
- }
-
- maybe_set_client_name(driverInfo);
-
- return pmNoError;
-
- unuse_queue:
- if (using_the_queue > 0) /* only for latency>0 case */
- alsa_unuse_queue();
- free_parser:
- snd_midi_event_free(ainfo->parser);
- free_this_port:
- snd_seq_delete_port(seq, ainfo->this_port);
- free_ainfo:
- pm_free(ainfo);
- return check_hosterror(err);
-}
-
-
-static PmError alsa_write_byte(PmInternal *midi, unsigned char byte,
- PmTimestamp timestamp)
-{
- alsa_info_type info = (alsa_info_type) midi->api_info;
- snd_seq_event_t ev;
- int err = 0;
-
- snd_seq_ev_clear(&ev);
- if (snd_midi_event_encode_byte(info->parser, byte, &ev) == 1) {
- if (info->is_virtual) {
- snd_seq_ev_set_subs(&ev);
- } else {
- snd_seq_ev_set_dest(&ev, info->client, info->port);
- }
- snd_seq_ev_set_source(&ev, info->this_port);
- if (midi->latency > 0) {
- /* compute relative time of event = timestamp - now + latency */
- PmTimestamp now = (midi->time_proc ?
- midi->time_proc(midi->time_info) :
- Pt_Time());
- int when = timestamp;
- /* if timestamp is zero, send immediately */
- /* otherwise compute time delay and use delay if positive */
- if (when == 0) when = now;
- when = (when - now) + midi->latency;
- if (when < 0) when = 0;
- VERBOSE printf("timestamp %d now %d latency %d, ",
- (int) timestamp, (int) now, midi->latency);
- VERBOSE printf("scheduling event after %d\n", when);
- /* message is sent in relative ticks, where 1 tick = 1 ms */
- snd_seq_ev_schedule_tick(&ev, queue, 1, when);
- /* NOTE: for cases where the user does not supply a time function,
- we could optimize the code by not starting Pt_Time and using
- the alsa tick time instead. I didn't do this because it would
- entail changing the queue management to start the queue tick
- count when PortMidi is initialized and keep it running until
- PortMidi is terminated. (This should be simple, but it's not
- how the code works now.) -RBD */
- } else { /* send event out without queueing */
- VERBOSE printf("direct\n");
- /* ev.queue = SND_SEQ_QUEUE_DIRECT;
- ev.dest.client = SND_SEQ_ADDRESS_SUBSCRIBERS; */
- snd_seq_ev_set_direct(&ev);
- }
- VERBOSE printf("sending event, timestamp %d (%d+%dns) (%s, %s)\n",
- ev.time.tick, ev.time.time.tv_sec, ev.time.time.tv_nsec,
- (ev.flags & SND_SEQ_TIME_STAMP_MASK ? "real" : "tick"),
- (ev.flags & SND_SEQ_TIME_MODE_MASK ? "rel" : "abs"));
- err = snd_seq_event_output(seq, &ev);
- }
- return check_hosterror(err);
-}
-
-
-static PmError alsa_out_close(PmInternal *midi)
-{
- alsa_info_type info = (alsa_info_type) midi->api_info;
- int err = 0;
- int error2 = 0;
- if (!info) return pmBadPtr;
-
- if (info->this_port != PORT_IS_CLOSED) {
- if (!info->is_virtual) {
- err = snd_seq_disconnect_to(seq, info->this_port,
- info->client, info->port);
- /* even if there was an error, we still try to delete the port */
- error2 = snd_seq_delete_port(seq, info->this_port);
-
- if (!err) { /* retain original error if there was one */
- err = error2; /* otherwise, use port delete status */
- }
- }
- }
- if (midi->latency > 0) alsa_unuse_queue();
- snd_midi_event_free(info->parser);
- midi->api_info = NULL; /* destroy the pointer to signify "closed" */
- pm_free(info);
- return check_hosterror(err);
-}
-
-
-static PmError alsa_create_virtual(int is_input, const char *name,
- void *device_info)
-{
- snd_seq_port_info_t *pinfo;
- int err;
- int client, port;
-
- /* we need the id to set the port. */
- PmDeviceID id = pm_add_device("ALSA", name, is_input, TRUE, NULL,
- (is_input ? &pm_linuxalsa_in_dictionary :
- &pm_linuxalsa_out_dictionary));
- if (id < 0) { /* error -- out of memory? */
- return id;
- }
- snd_seq_port_info_alloca(&pinfo);
- snd_seq_port_info_set_capability(pinfo,
- (is_input ? SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE :
- SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ));
- snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC |
- SND_SEQ_PORT_TYPE_APPLICATION);
- snd_seq_port_info_set_name(pinfo, name);
- snd_seq_port_info_set_port(pinfo, id);
- snd_seq_port_info_set_port_specified(pinfo, 1);
- /* next 3 lines needed to generate timestamp - PaulLiu */
- snd_seq_port_info_set_timestamping(pinfo, 1);
- snd_seq_port_info_set_timestamp_real(pinfo, 0);
- snd_seq_port_info_set_timestamp_queue(pinfo, queue);
-
- err = snd_seq_create_port(seq, pinfo);
- if (err < 0) {
- pm_undo_add_device(id);
- return check_hosterror(err);
- }
-
- client = snd_seq_port_info_get_client(pinfo);
- port = snd_seq_port_info_get_port(pinfo);
- pm_descriptors[id].descriptor = MAKE_DESCRIPTOR(client, port);
- return id;
-}
-
-
- static PmError alsa_delete_virtual(PmDeviceID id)
- {
- int err = snd_seq_delete_port(seq, id);
- return check_hosterror(err);
- }
-
-
-static PmError alsa_in_open(PmInternal *midi, void *driverInfo)
-{
- int id = midi->device_id;
- void *client_port = pm_descriptors[id].descriptor;
- alsa_info_type ainfo = alsa_info_create((long) client_port, id,
- pm_descriptors[id].pub.is_virtual);
- snd_seq_port_info_t *pinfo;
- snd_seq_port_subscribe_t *sub;
- snd_seq_addr_t addr;
- int err = 0;
- int is_virtual = pm_descriptors[id].pub.is_virtual;
-
- if (!ainfo) return pmInsufficientMemory;
- midi->api_info = ainfo;
-
- err = alsa_use_queue();
- if (err < 0) goto free_ainfo;
-
- snd_seq_port_info_alloca(&pinfo);
- if (is_virtual) {
- ainfo->is_virtual = TRUE;
- if (snd_seq_get_port_info(seq, ainfo->port, pinfo)) {
- pinfo = NULL;
- goto free_ainfo;
- }
- } else {
- /* create a port for this alsa client (seq) where the port
- number matches the portmidi device ID of the input device */
- snd_seq_port_info_set_port(pinfo, id);
- snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_WRITE |
- SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_WRITE);
-
- snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC |
- SND_SEQ_PORT_TYPE_APPLICATION);
- snd_seq_port_info_set_port_specified(pinfo, 1);
-
- const char *port_name = get_sysdep_name(pmKeyAlsaPortName,
- (PmSysDepInfo *) driverInfo);
- if (port_name) {
- snd_seq_port_info_set_name(pinfo, port_name);
- }
-
- err = snd_seq_create_port(seq, pinfo);
- if (err < 0) goto free_queue;
-
- /* forward messages from input to this alsa client, so this
- * alsa client is the destination, and the destination port is the
- * port we just created using the device ID as port number
- */
- snd_seq_port_subscribe_alloca(&sub);
- addr.client = snd_seq_client_id(seq);
- addr.port = ainfo->this_port;
- snd_seq_port_subscribe_set_dest(sub, &addr);
-
- /* forward from the sender which is the device named by
- client and port */
- addr.client = ainfo->client;
- addr.port = ainfo->port;
- snd_seq_port_subscribe_set_sender(sub, &addr);
- snd_seq_port_subscribe_set_time_update(sub, 1);
- /* this doesn't seem to work: messages come in with real timestamps */
- snd_seq_port_subscribe_set_time_real(sub, 0);
- err = snd_seq_subscribe_port(seq, sub);
- if (err < 0) goto free_this_port; /* clean up and return on error */
- }
-
- maybe_set_client_name(driverInfo);
-
- return pmNoError;
- free_this_port:
- snd_seq_delete_port(seq, ainfo->this_port);
- free_queue:
- alsa_unuse_queue();
- free_ainfo:
- pm_free(ainfo);
- return check_hosterror(err);
-}
-
-static PmError alsa_in_close(PmInternal *midi)
-{
- int err = 0;
- alsa_info_type info = (alsa_info_type) midi->api_info;
- if (!info) return pmBadPtr;
- /* virtual ports stay open because the represent devices */
- if (!info->is_virtual && info->this_port != PORT_IS_CLOSED) {
- err = snd_seq_delete_port(seq, info->this_port);
- }
- alsa_unuse_queue();
- midi->api_info = NULL;
- pm_free(info);
- return check_hosterror(err);
-}
-
-
-static PmError alsa_abort(PmInternal *midi)
-{
- /* NOTE: ALSA documentation is vague. This is supposed to
- * remove any pending output messages. If you can test and
- * confirm this code is correct, please update this comment. -RBD
- */
- /* Unfortunately, I can't even compile it -- my ALSA version
- * does not implement snd_seq_remove_events_t, so this does
- * not compile. I'll try again, but it looks like I'll need to
- * upgrade my entire Linux OS -RBD
- */
- /*
- info_type info = (info_type) midi->api_info;
- snd_seq_remove_events_t info;
- snd_seq_addr_t addr;
- addr.client = info->client;
- addr.port = info->port;
- snd_seq_remove_events_set_dest(&info, &addr);
- snd_seq_remove_events_set_condition(&info, SND_SEQ_REMOVE_DEST);
- pm_hosterror = snd_seq_remove_events(seq, &info);
- if (pm_hosterror) {
- get_alsa_error_text(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN,
- pm_hosterror);
- return pmHostError;
- }
- */
- printf("WARNING: alsa_abort not implemented\n");
- return pmNoError;
-}
-
-
-static PmError alsa_write_flush(PmInternal *midi, PmTimestamp timestamp)
-{
- int err;
- alsa_info_type info = (alsa_info_type) midi->api_info;
- if (!info) return pmBadPtr;
- VERBOSE printf("snd_seq_drain_output: %p\n", seq);
- err = snd_seq_drain_output(seq);
- return check_hosterror(err);
-}
-
-
-static PmError alsa_write_short(PmInternal *midi, PmEvent *event)
-{
- int bytes = midi_message_length(event->message);
- PmMessage msg = event->message;
- int i;
- alsa_info_type info = (alsa_info_type) midi->api_info;
- if (!info) return pmBadPtr;
- for (i = 0; i < bytes; i++) {
- unsigned char byte = msg;
- VERBOSE printf("sending 0x%x\n", byte);
- alsa_write_byte(midi, byte, event->timestamp);
- if (pm_hosterror) break;
- msg >>= 8; /* shift next byte into position */
- }
- if (pm_hosterror) return pmHostError;
- return pmNoError;
-}
-
-
-/* alsa_sysex -- implements begin_sysex and end_sysex */
-PmError alsa_sysex(PmInternal *midi, PmTimestamp timestamp) {
- return pmNoError;
-}
-
-
-static PmTimestamp alsa_synchronize(PmInternal *midi)
-{
- return 0; /* linux implementation does not use this synchronize function */
- /* Apparently, Alsa data is relative to the time you send it, and there
- is no reference. If this is true, this is a serious shortcoming of
- Alsa. If not true, then PortMidi has a serious shortcoming -- it
- should be scheduling relative to Alsa's time reference. */
-}
-
-
-static void handle_event(snd_seq_event_t *ev)
-{
- int device_id = ev->dest.port;
- PmInternal *midi = pm_descriptors[device_id].pm_internal;
- // There is a race condition when closing a device and
- // continuing to poll other open devices. The closed device may
- // have outstanding events from before the close operation.
- if (!midi) {
- return;
- }
- PmEvent pm_ev;
- PmTimestamp timestamp = midi->time_proc(midi->time_info);
-
- /* time stamp should be in ticks, using our queue where 1 tick = 1ms */
- /* assert((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_TICK);
- * Currently, event timestamp is ignored. See long note below. */
-
- VERBOSE {
- /* translate time to time_proc basis */
- snd_seq_queue_status_t *queue_status;
- snd_seq_queue_status_alloca(&queue_status);
- snd_seq_get_queue_status(seq, queue, queue_status);
- printf("handle_event: alsa_now %d, "
- "event timestamp %d (%d+%dns) (%s, %s)\n",
- snd_seq_queue_status_get_tick_time(queue_status),
- ev->time.tick, ev->time.time.tv_sec, ev->time.time.tv_nsec,
- (ev->flags & SND_SEQ_TIME_STAMP_MASK ? "real" : "tick"),
- (ev->flags & SND_SEQ_TIME_MODE_MASK ? "rel" : "abs"));
- /* OLD: portmidi timestamp is (now - alsa_now) + alsa_timestamp */
- /* timestamp = (*time_proc)(midi->time_info) + ev->time.tick -
- snd_seq_queue_status_get_tick_time(queue_status); */
- }
- /* CURRENT: portmidi timestamp is "now". In a test, timestamps from
- * hardware (MIDI over USB) were timestamped with the current ALSA
- * time (snd_seq_queue_status_get_tick_time) and flags indicating
- * absolute ticks, but timestamps from another application's virtual
- * port, sent direct with 0 absolute ticks, were received with a
- * large value that is apparently the time since the start time of
- * the other application. Without any reference to our local time,
- * this seems useless. PortMidi is supposed to return the local
- * PortMidi time of the arrival of the message, so the best we can
- * do is set the timestamp to our local clock. This seems to be a
- * design flaw in ALSA -- I pointed this out a decade ago, but if
- * there is a workaround, I'd still like to know. Maybe there is a
- * way to use absolute real time and maybe that's sharable across
- * applications by referencing the system time?
- */
- pm_ev.timestamp = timestamp;
- switch (ev->type) {
- case SND_SEQ_EVENT_NOTEON:
- pm_ev.message = Pm_Message(0x90 | ev->data.note.channel,
- ev->data.note.note & 0x7f,
- ev->data.note.velocity & 0x7f);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_NOTEOFF:
- pm_ev.message = Pm_Message(0x80 | ev->data.note.channel,
- ev->data.note.note & 0x7f,
- ev->data.note.velocity & 0x7f);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_KEYPRESS:
- pm_ev.message = Pm_Message(0xa0 | ev->data.note.channel,
- ev->data.note.note & 0x7f,
- ev->data.note.velocity & 0x7f);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_CONTROLLER:
- pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel,
- ev->data.control.param & 0x7f,
- ev->data.control.value & 0x7f);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_PGMCHANGE:
- pm_ev.message = Pm_Message(0xc0 | ev->data.note.channel,
- ev->data.control.value & 0x7f, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_CHANPRESS:
- pm_ev.message = Pm_Message(0xd0 | ev->data.note.channel,
- ev->data.control.value & 0x7f, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_PITCHBEND:
- pm_ev.message = Pm_Message(0xe0 | ev->data.note.channel,
- (ev->data.control.value + 0x2000) & 0x7f,
- ((ev->data.control.value + 0x2000) >> 7) & 0x7f);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_CONTROL14:
- if (ev->data.control.param < 0x20) {
- pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel,
- ev->data.control.param,
- (ev->data.control.value >> 7) & 0x7f);
- pm_read_short(midi, &pm_ev);
- pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel,
- ev->data.control.param + 0x20,
- ev->data.control.value & 0x7f);
- pm_read_short(midi, &pm_ev);
- } else {
- pm_ev.message = Pm_Message(0xb0 | ev->data.note.channel,
- ev->data.control.param & 0x7f,
- ev->data.control.value & 0x7f);
-
- pm_read_short(midi, &pm_ev);
- }
- break;
- case SND_SEQ_EVENT_SONGPOS:
- pm_ev.message = Pm_Message(0xf2,
- ev->data.control.value & 0x7f,
- (ev->data.control.value >> 7) & 0x7f);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_SONGSEL:
- pm_ev.message = Pm_Message(0xf3,
- ev->data.control.value & 0x7f, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_QFRAME:
- pm_ev.message = Pm_Message(0xf1,
- ev->data.control.value & 0x7f, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_START:
- pm_ev.message = Pm_Message(0xfa, 0, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_CONTINUE:
- pm_ev.message = Pm_Message(0xfb, 0, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_STOP:
- pm_ev.message = Pm_Message(0xfc, 0, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_CLOCK:
- pm_ev.message = Pm_Message(0xf8, 0, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_TUNE_REQUEST:
- pm_ev.message = Pm_Message(0xf6, 0, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_RESET:
- pm_ev.message = Pm_Message(0xff, 0, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_SENSING:
- pm_ev.message = Pm_Message(0xfe, 0, 0);
- pm_read_short(midi, &pm_ev);
- break;
- case SND_SEQ_EVENT_SYSEX: {
- const BYTE *ptr = (const BYTE *) ev->data.ext.ptr;
- /* assume there is one sysex byte to process */
- pm_read_bytes(midi, ptr, ev->data.ext.len, timestamp);
- break;
- }
- case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: {
- /* this happens if you have an input port open and the
- * device or application with virtual ports closes. We
- * mark the port as closed to avoid closing a 2nd time
- * when Pm_Close() is called.
- */
- alsa_info_type info = (alsa_info_type) midi->api_info;
- /* printf("SND_SEQ_EVENT_UNSUBSCRIBE message\n"); */
- info->this_port = PORT_IS_CLOSED;
- break;
- }
- case SND_SEQ_EVENT_PORT_SUBSCRIBED:
- break; /* someone connected to a virtual output port, not reported */
- default:
- printf("portmidi handle_event: not handled type %x\n", ev->type);
- break;
- }
-}
-
-
-static PmError alsa_poll(PmInternal *midi)
-{
- if (!midi) {
- return pmBadPtr;
- }
- snd_seq_event_t *ev;
- /* expensive check for input data, gets data from device: */
- while (snd_seq_event_input_pending(seq, TRUE) > 0) {
- /* cheap check on local input buffer */
- while (snd_seq_event_input_pending(seq, FALSE) > 0) {
- /* check for and ignore errors, e.g. input overflow */
- /* note: if there's overflow, this should be reported
- * all the way through to client. Since input from all
- * devices is merged, we need to find all input devices
- * and set all to the overflow state.
- * NOTE: this assumes every input is ALSA based.
- */
- int rslt = snd_seq_event_input(seq, &ev);
- if (rslt >= 0) {
- handle_event(ev);
- } else if (rslt == -ENOSPC) {
- int i;
- for (i = 0; i < pm_descriptor_len; i++) {
- if (pm_descriptors[i].pub.input) {
- PmInternal *midi_i = pm_descriptors[i].pm_internal;
- /* careful, device may not be open! */
- if (midi_i) Pm_SetOverflow(midi_i->queue);
- }
- }
- }
- }
- }
- return pmNoError;
-}
-
-
-static unsigned int alsa_check_host_error(PmInternal *midi)
-{
- return FALSE;
-}
-
-
-pm_fns_node pm_linuxalsa_in_dictionary = {
- none_write_short,
- none_sysex,
- none_sysex,
- none_write_byte,
- none_write_short,
- none_write_flush,
- alsa_synchronize,
- alsa_in_open,
- alsa_abort,
- alsa_in_close,
- alsa_poll,
- alsa_check_host_error
-};
-
-pm_fns_node pm_linuxalsa_out_dictionary = {
- alsa_write_short,
- alsa_sysex,
- alsa_sysex,
- alsa_write_byte,
- alsa_write_short, /* short realtime message */
- alsa_write_flush,
- alsa_synchronize,
- alsa_out_open,
- alsa_abort,
- alsa_out_close,
- none_poll,
- alsa_check_host_error
-};
-
-
-/* pm_strdup -- copy a string to the heap. Use this rather than strdup so
- * that we call pm_alloc, not malloc. This allows portmidi to avoid
- * malloc which might cause priority inversion. Probably ALSA is going
- * to call malloc anyway, so this extra work here may be pointless.
- */
-char *pm_strdup(const char *s)
-{
- int len = strlen(s);
- char *dup = (char *) pm_alloc(len + 1);
- strcpy(dup, s);
- return dup;
-}
-
-
-PmError pm_linuxalsa_init(void)
-{
- int err;
- snd_seq_client_info_t *cinfo;
- snd_seq_port_info_t *pinfo;
- unsigned int caps;
-
- /* Register interface ALSA with create_virtual fn */
- pm_add_interf("ALSA", &alsa_create_virtual, &alsa_delete_virtual);
-
- /* Previously, the last parameter was SND_SEQ_NONBLOCK, but this
- * would cause messages to be dropped if the ALSA buffer fills up.
- * The correct behavior is for writes to block until there is
- * room to send all the data. The client should normally allocate
- * a large enough buffer to avoid blocking on output.
- * Now that blocking is enabled, the seq_event_input() will block
- * if there is no input data. This is not what we want, so must
- * call seq_event_input_pending() to avoid blocking.
- */
- err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
- if (err < 0) goto error_return;
-
- snd_seq_client_info_alloca(&cinfo);
- snd_seq_port_info_alloca(&pinfo);
-
- snd_seq_client_info_set_client(cinfo, -1);
- while (snd_seq_query_next_client(seq, cinfo) == 0) {
- snd_seq_port_info_set_client(pinfo,
- snd_seq_client_info_get_client(cinfo));
- snd_seq_port_info_set_port(pinfo, -1);
- while (snd_seq_query_next_port(seq, pinfo) == 0) {
- if (snd_seq_port_info_get_client(pinfo) == SND_SEQ_CLIENT_SYSTEM)
- continue; /* ignore Timer and Announce ports on client 0 */
- caps = snd_seq_port_info_get_capability(pinfo);
- if (!(caps & (SND_SEQ_PORT_CAP_SUBS_READ |
- SND_SEQ_PORT_CAP_SUBS_WRITE)))
- continue; /* ignore if you cannot read or write port */
- if (caps & SND_SEQ_PORT_CAP_SUBS_WRITE) {
- if (pm_default_output_device_id == -1)
- pm_default_output_device_id = pm_descriptor_len;
- pm_add_device("ALSA",
- pm_strdup(snd_seq_port_info_get_name(pinfo)),
- FALSE, FALSE,
- MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo),
- snd_seq_port_info_get_port(pinfo)),
- &pm_linuxalsa_out_dictionary);
- }
- if (caps & SND_SEQ_PORT_CAP_SUBS_READ) {
- if (pm_default_input_device_id == -1)
- pm_default_input_device_id = pm_descriptor_len;
- pm_add_device("ALSA",
- pm_strdup(snd_seq_port_info_get_name(pinfo)),
- TRUE, FALSE,
- MAKE_DESCRIPTOR(snd_seq_port_info_get_client(pinfo),
- snd_seq_port_info_get_port(pinfo)),
- &pm_linuxalsa_in_dictionary);
- }
- }
- }
- return pmNoError;
- error_return:
- pm_linuxalsa_term(); /* clean up */
- return check_hosterror(err);
-}
-
-
-void pm_linuxalsa_term(void)
-{
- if (seq) {
- snd_seq_close(seq);
- pm_free(pm_descriptors);
- pm_descriptors = NULL;
- pm_descriptor_len = 0;
- pm_descriptor_max = 0;
- }
-}
-
-#endif
diff --git a/portmidi/pm_linux/pmlinuxalsa.h b/portmidi/pm_linux/pmlinuxalsa.h
deleted file mode 100755
index d4bff16..0000000
--- a/portmidi/pm_linux/pmlinuxalsa.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/* pmlinuxalsa.h -- system-specific definitions */
-
-PmError pm_linuxalsa_init(void);
-void pm_linuxalsa_term(void);
-
-
diff --git a/portmidi/pm_linux/pmlinuxnull.c b/portmidi/pm_linux/pmlinuxnull.c
deleted file mode 100644
index 257f3d6..0000000
--- a/portmidi/pm_linux/pmlinuxnull.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * pmlinuxnull.c -- system specific definitions
- *
- * written by:
- * Roger Dannenberg
- *
- * If there is no ALSA, you can define PMNULL and build PortMidi. It will
- * not report any devices, so you will not be able to open any, but if
- * you wanted to disable MIDI from some application, this could be used.
- * Mainly, this code shows the possibility of supporting multiple
- * interfaces, e.g., ALSA and Sndio on BSD, or ALSA and Jack on Linux.
- * But as of Dec, 2021, the only supported MIDI API for Linux is ALSA.
- */
-
-#ifdef PMNULL
-
-#include "portmidi.h"
-#include "pmlinuxnull.h"
-
-
-PmError pm_linuxnull_init(void)
-{
- return pmNoError;
-}
-
-
-void pm_linuxnull_term(void)
-{
-}
-
-#endif
diff --git a/portmidi/pm_linux/pmlinuxnull.h b/portmidi/pm_linux/pmlinuxnull.h
deleted file mode 100644
index 9835825..0000000
--- a/portmidi/pm_linux/pmlinuxnull.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/* pmlinuxnull.h -- system-specific definitions */
-
-PmError pm_linuxnull_init(void);
-void pm_linuxnull_term(void);
-
-
diff --git a/portmidi/pm_mac/Makefile.osx b/portmidi/pm_mac/Makefile.osx
deleted file mode 100755
index 2044381..0000000
--- a/portmidi/pm_mac/Makefile.osx
+++ /dev/null
@@ -1,125 +0,0 @@
-# MAKEFILE FOR PORTMIDI
-
-# Roger B. Dannenberg
-# Sep 2009
-
-# NOTE: PortMidi is currently built and tested with CMake.
-# This makefile is probably broken, but if you want to
-# directly use make, start here, and please contribute any
-# fixes.
-
-# NOTE: you can use
-# make -f pm_mac/Makefile.osx configuration=Release
-# to override the default Debug configuration
-configuration=Release
-
-PF=/usr/local
-
-# For debugging, define PM_CHECK_ERRORS
-ifeq ($(configuration),Release)
- CONFIG = Release
-else
- CONFIG = Debug
-endif
-
-current: all
-
-all: $(CONFIG)/CMakeCache.txt
- cd $(CONFIG); make
-
-$(CONFIG)/CMakeCache.txt:
- rm -f $(CONFIG)/CMakeCache.txt
- mkdir -p $(CONFIG)
- cd $(CONFIG); cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=$(CONFIG)
-
-
-**** For instructions: make -f pm_mac/Makefile.osx help ****\n'
-
-help:
- echo $$'\n\n\
-This is help for portmidi/pm_mac/Makefile.osx\n\n\
-Installation path for dylib is $(PF)\n\
-To build Release version libraries and test applications,\n \
-make -f pm_mac/Makefile.osx\n\
-To build Debug version libraries and test applications,\n \
-make -f pm_mac/Makefile.osx configuration=Debug\n\
-To install universal dynamic library,\n \
-sudo make -f pm_mac/Makefile.osx install\n\
-To install universal dynamic library with xcode,\n \
-make -f pm_mac/Makefile.osx install-with-xcode\n\
-To make PmDefaults Java application,\n \
-make -f pm_mac/Makefile.osx pmdefaults\n\n \
-configuration = $(configuration)\n'
-
-
-clean:
- rm -f *.o *~ core* */*.o */*/*.o */*~ */core* pm_test/*/pm_dll.dll
- rm -f *.opt *.ncb *.plg pm_win/Debug/pm_dll.lib pm_win/Release/pm_dll.lib
- rm -f pm_test/*.opt pm_test/*.ncb
- rm -f pm_java/pmjni/*.o pm_java/pmjni/*~ pm_java/*.h
- rm -rf Release/CMakeFiles Debug/CMakeFiles
- rm -rf pm_mac/pmdefaults/lib pm_mac/pmdefaults/src
-
-cleaner: clean
- rm -rf pm_mac/build
- rm -rf pm_mac/Debug pm_mac/Release pm_test/Debug pm_test/Release
- rm -f Debug/*.dylib Release/*.dylib
- rm -f pm_java/pmjni/Debug/*.jnilib
- rm -f pm_java/pmjni/Release/*.jnilib
-
-cleanest: cleaner
- rm -f Debug/CMakeCache.txt Release/CMakeCache.txt
- rm -f CMakeCache.txt
- rm -f Debug/libportmidi_s.a Release/libportmidi_s.a
- rm -f pm_test/Debug/test pm_test/Debug/sysex pm_test/Debug/midithread
- rm -f pm_test/Debug/latency pm_test/Debug/midithru
- rm -f pm_test/Debug/qtest pm_test/Debug/mm
- rm -f pm_test/Release/test pm_test/Release/sysex pm_test/Release/midithread
- rm -f pm_test/Release/latency pm_test/Release/midithru
- rm -f pm_test/Release/qtest pm_test/Release/mm
- rm -f pm_java/*/*.class
- rm -f pm_java/pmjni/jportmidi_JPortMidiApi_PortMidiStream.h
-
-backup: cleanest
- cd ..; zip -r portmidi.zip portmidi
-
-install: porttime/porttime.h pm_common/portmidi.h \
- $(CONFIG)/libportmidi.dylib
- install porttime/porttime.h $(PF)/include/
- install pm_common/portmidi.h $(PF)/include
- install $(CONFIG)/libportmidi.dylib $(PF)/lib/
-
-# note - this uses xcode to build and install portmidi universal binaries
-install-with-xcode:
- sudo xcodebuild -project pm_mac/pm_mac.xcodeproj \
- -configuration Release install DSTROOT=/
-
-##### build pmdefault ######
-
-pm_java/pmjni/jportmidi_JPortMidiApi.h: pm_java/jportmidi/JPortMidiApi.class
- cd pm_java; javah jportmidi.JPortMidiApi
- mv pm_java/jportmidi_JportMidiApi.h pm_java/pmjni
-
-JAVASRC = pmdefaults/PmDefaultsFrame.java \
- pmdefaults/PmDefaults.java \
- jportmidi/JPortMidiApi.java jportmidi/JPortMidi.java \
- jportmidi/JPortMidiException.java
-
-# this compiles ALL of the java code
-pm_java/jportmidi/JPortMidiApi.class: $(JAVASRC:%=pm_java/%)
- cd pm_java; javac $(JAVASRC)
-
-$(CONFIG)/libpmjni.dylib:
- mkdir -p $(CONFIG)
- cd $(CONFIG); make -f ../pm_mac/$(MAKEFILE)
-
-pmdefaults: $(CONFIG)/libpmjni.dylib pm_java/jportmidi/JPortMidiApi.class
-ifeq ($(CONFIG),Debug)
- echo "Error: you cannot build pmdefaults in a Debug configuration \n\
- You should use configuration=Release in the Makefile command line. "
- @exit 2
-endif
- xcodebuild -project pm_mac/pm_mac.xcodeproj \
- -configuration Release -target PmDefaults
- echo "pmdefaults java application is made"
-
diff --git a/portmidi/pm_mac/README_MAC.txt b/portmidi/pm_mac/README_MAC.txt
deleted file mode 100644
index 41e8341..0000000
--- a/portmidi/pm_mac/README_MAC.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-README_MAC.txt for PortMidi
-Roger Dannenberg
-20 nov 2009
-
-revised Mar 2024 to remove pmdefaults references
-revised Jan 2022 for the PortMidi/portmidi repo on github.com
-revised 20 Sep 2010 for Xcode 4.3.2 and CMake 2.8.8
-
-This documents how I build PortMidi for macOS. It's not the only way,
-and command-line/scripting enthusiasts will say it's not even a good
-way. Feel free to contribute your approach if you are willing to
-describe it carefully and test it.
-
-Install Xcode and the CMake application, CMake.app. I use the GUI
-version of CMake which makes it easy to see/edit variables and
-options.
-
-==== USING CMAKE ====
-
-Run CMake.app and select your portmidi repo working directory as the
-location for source and build. (Yes, I use so called "in-tree"
-builds -- it doesn't hurt, but I don't think it is necessary.)
-
-Default settings should all be fine, but select options under BUILD if
-you wish:
-
-BUILD_NATIVE_JAVA_INTERFACE to build a Java interface (JNI) library.
-
-BUILD_PORTMIDI_TESTS to create some test programs. Of particular
-interest are test/mm, a handy command-line MIDI Input Monitor, and
-test/testio, a simple command-line program to send or receive some
-MIDI notes in case you need a quick test: What devices do I have? Does
-this input work? Does this output work?
-
-I disable BUILD_SHARED_LIBS and always link statically: Static linking only
-adds about 40KB to any application and then you don't have to worry
-about versions, instally, copying or finding the dynamic link library,
-etc.
-
-To make sure you link statically, I rename the library to
-libportmidi_static.a. To do this, set PM_STATIC_LIB_NAME (in CMake,
-under the "PM" group) to "portmidi_static", and of course your
-application will have to specify portmidi_static as the library to
-link to.
-
-If you are building simple command-line applications, you might want
-to enable PM_CHECK_ERRORS. If you do, then calls into the PortMidi
-library will print error messages and exit in the event of an error
-(such as trying to open a device that does not exist). This saves you
-from having to check for errors everytime you call a library function
-or getting confused when errors are detected but not reported. For
-high-quality applications, do NOT enable PM_CHECK_ERRORS -- any
-failure could immediately abort your whole application, which is not
-very friendly to users.
-
-Click on Configure (maybe a couple of times).
-
-Click on Generate and make an Xcode project.
-
-Open portmidi/portmidi.xcodeproj with Xcode and build what you
-need. The simplest thing is to build the ALL_BUILD target. Be careful
-to specify a Debug or Release depending on what you want. "ALL_BUILD"
-is a misnomer -- it only builds the version you select.
-
-
diff --git a/portmidi/pm_mac/pmmac.c b/portmidi/pm_mac/pmmac.c
deleted file mode 100755
index 48ac17a..0000000
--- a/portmidi/pm_mac/pmmac.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* pmmac.c -- PortMidi os-dependent code */
-
-/* This file only needs to implement:
-pm_init(), which calls various routines to register the
-available midi devices,
-Pm_GetDefaultInputDeviceID(), and
-Pm_GetDefaultOutputDeviceID().
-It is seperate from pmmacosxcm because we might want to register
-non-CoreMIDI devices.
-*/
-
-#include "stdlib.h"
-#include "portmidi.h"
-#include "pmutil.h"
-#include "pminternal.h"
-#include "pmmacosxcm.h"
-
-void pm_init(void)
-{
- pm_macosxcm_init();
-}
-
-
-void pm_term(void)
-{
- pm_macosxcm_term();
-}
-
-PmDeviceID Pm_GetDefaultInputDeviceID(void)
-{
- Pm_Initialize();
- return pm_default_input_device_id;
-}
-
-PmDeviceID Pm_GetDefaultOutputDeviceID(void) {
- Pm_Initialize();
- return pm_default_output_device_id;
-}
-
-void *pm_alloc(size_t s) { return malloc(s); }
-
-void pm_free(void *ptr) { free(ptr); }
-
-
diff --git a/portmidi/pm_mac/pmmacosxcm.c b/portmidi/pm_mac/pmmacosxcm.c
deleted file mode 100755
index e8b196c..0000000
--- a/portmidi/pm_mac/pmmacosxcm.c
+++ /dev/null
@@ -1,1179 +0,0 @@
-/*
- * Platform interface to the MacOS X CoreMIDI framework
- *
- * Jon Parise <jparise at cmu.edu>
- * and subsequent work by Andrew Zeldis and Zico Kolter
- * and Roger B. Dannenberg
- *
- * $Id: pmmacosx.c,v 1.17 2002/01/27 02:40:40 jon Exp $
- */
-
-/* Notes:
-
- Since the input and output streams are represented by
- MIDIEndpointRef values and almost no other state, we store the
- MIDIEndpointRef on pm_descriptors[midi->device_id].descriptor.
-
- OS X does not seem to have an error-code-to-text function, so we
- will just use text messages instead of error codes.
-
- Virtual device input synchronization: Once we create a virtual
- device, it is always "on" and receiving messages, but it must drop
- messages unless the device has been opened with Pm_OpenInput. To
- open, the main thread should create all the data structures, then
- call OSMemoryBarrier so that writes are observed, then set
- is_opened = TRUE. To close without locks, we need to get the
- callback to set is_opened to FALSE before we free data structures;
- otherwise, there's a race condition where closing could delete
- structures in use by the virtual_read_callback function. We send
- 8 MIDI resets (FF) in a single packet to our own port to signal
- the virtual_read_callback to close it. Then, we wait for the
- callback to recognize the "close" packet and reset is_opened.
-
- Device scanning is done when you first open an application.
- PortMIDI does not actively update the devices. Instead, you must
- Pm_Terminate() and Pm_Initialize(), basically starting over. But
- CoreMIDI does not have a way to shut down(!), and even
- MIDIClientDispose() somehow retains state (and docs say do not
- call it even if it worked). The solution, apparently, is to
- call CFRunLoopRunInMode(), which somehow updates CoreMIDI
- state.
-
- But when do we call CFRunLoopRunInMode()? I tried calling it
- in midi_in_poll() which is called when you call Pm_Read() since
- that is called often. I observed that this caused the program
- to block for as long as 50ms and fairly often for 2 or 3ms.
- What was Apple thinking? Is it really OK to design systems that
- can only function with a tricky multi-threaded, non-blocking
- priority-based solution, and then not provide a proof of concept
- or documentation? Or is Apple's design really flawed? If anyone
- at Apple reads this, please let me know -- I'm curious.
-
- But I digress... Here's the PortMidi approach: Since
- CFRunLoopRunInMode() is potentially a non-realtime operation,
- we only call it in Pm_Initialize(), where other calls to look
- up devices and device names are quite slow to begin with. Again,
- PortMidi does not actively scan for new or deleted devices, so
- if devices change, you won't see it until the next Pm_Terminate
- and Pm_Initialize.
-
- Calling CFRunLoopRunInMode() once is probably not enough. There
- might be better way, but it seems to work to just call it 100
- times and insert 20 1ms delays (in case some inter-process
- communication or synchronization is going on).
- This adds 20ms to the wall time of Pm_Initialize(), but it
- typically runs 30ms to much more (~4s), so this has little impact.
- */
-
-#include <stdlib.h>
-
-/* turn on lots of debugging print statements */
-#define CM_DEBUG if (0)
-/* #define CM_DEBUG if (1) */
-
-#include "portmidi.h"
-#include "pmutil.h"
-#include "pminternal.h"
-#include "porttime.h"
-#include "pmmacosxcm.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <CoreServices/CoreServices.h>
-#include <CoreMIDI/MIDIServices.h>
-#include <CoreAudio/HostTime.h>
-#include <unistd.h>
-#include <libkern/OSAtomic.h>
-
-#define PACKET_BUFFER_SIZE 1024
-/* maximum overall data rate (OS X limits MIDI rate in case there
- * is a cycle among IAC ports.
- */
-
-#define MAX_BYTES_PER_S 5400
-
-/* Apple reports that packets are dropped when the MIDI bytes/sec
- exceeds 15000. This is computed by "tracking the number of MIDI
- bytes scheduled into 1-second buckets over the last six seconds and
- averaging these counts." This was confirmed in measurements
- (2021) with pm_test/fast.c and pm_test/fastrcv.c Now, in 2022, with
- macOS 12, pm_test/fast{rcv}.c show problems begin at 6000 bytes/sec.
- Previously, we set MAX_BYTES_PER_S to 14000. This is reduced to
- 5400 based on testing (which shows 5700 is too high) to fix the
- packet loss problem that showed up with macOS 12.
-
- Experiments show this restriction applies to IAC bus MIDI, but not
- to hardware interfaces. (I measured 0.5 Mbps each way over USB to a
- Teensy 3.2 microcontroller implementing a USB MIDI loopback. Maybe
- it would get 1 Mbps one-way, which would make the CoreMIDI
- restriction 18x slower than USB. Maybe other USB MIDI
- implementations are faster -- USB top speed for other protocols is
- certainly higher than 1 Mbps!)
-
- This is apparently based on timestamps, not on real time, so we
- have to avoid constructing packets that schedule high speed output
- regardless of when writes occur. The solution is to alter
- timestamps to limit data rates. This adds a slight time
- distortion, e.g. an 11 note chord with all notes on the same
- timestamp will be altered so that the last message is delayed by
- 11 messages x 3 bytes/message / 5400 bytes/second = 6.1 ms.
- Note that this is about 2x MIDI speed, but at least 18x slower
- than USB MIDI.
-
- Altering timestamps creates another problem, which is that a sender
- that exceeds the maximum rate can queue up an unbounded number of
- messages. With non-USB MIDI devices, you could be writing 5x faster
- to CoreMIDI than the hardware interface can send, causing an
- unbounded backlog, not to mention that the output stream will be a
- steady byte stream (e.g., one 3-byte MIDI message every 0.55 ms),
- losing any original timing or rhythm. PortMidi does not guarantee
- delivery if, over the long run, you write faster than the hardware
- can send.
-
- The LIMIT_RATE symbol, if defined (which is the default), enables
- code to modify timestamps for output to an IAC device as follows:
-
- Before a packet is formed, the message timestamp is set to the
- maximum of the PortMidi timestamp (converted to CoreMIDI time)
- and min_next_time. After each send, min_next_time is updated to
- the packet time + packet length * delay_per_byte, which limits
- the scheduled bytes-per-second. Also, after each packet list
- flush, min_next_time is updated to the maximum of min_next_time
- and the real time, which prevents many bytes to be scheduled in
- the past. (We could more directly just say packets are never
- scheduled in the past, but we prefer to get the current time -- a
- system call -- only when we perform the more expensive operation
- of flushing packets, so that's when we update min_next_time to
- the current real time. If we are sending a lot, we have to flush
- a lot, so the time will be updated frequently when it matters.)
-
- This possible adjustment to timestamps can distort accurate
- timestamps by up to 0.556 us per 3-byte MIDI message.
-
- Nothing blocks the sender from queueing up an arbitrary number of
- messages. Timestamps should be used for accurate timing by sending
- timestamped messages a little ahead of real time, not for
- scheduling an entire MIDI sequence at once!
- */
-#define LIMIT_RATE 1
-
-#define SYSEX_BUFFER_SIZE 128
-/* What is the maximum PortMidi device number for an IAC device? A
- * cleaner design would be to not use the endpoint as our device
- * representation. Instead, we could have a private extensible struct
- * to keep all device information, including whether the device is
- * implemented with the AppleMIDIIACDriver, which we need because we
- * have to limit the data rate to this particular driver to avoid
- * dropping messages. Rather than rewrite a lot of code, I am just
- * allocating 64 bytes to flag which devices are IAC ones. If an IAC
- * device number is greater than 63, PortMidi will fail to limit
- * writes to it, but will not complain and will not access memory
- * outside the 64-element array of char.
- */
-#define MAX_IAC_NUM 63
-
-#define VERBOSE_ON 1
-#define VERBOSE if (VERBOSE_ON)
-
-#define MIDI_SYSEX 0xf0
-#define MIDI_EOX 0xf7
-#define MIDI_CLOCK 0xf8
-#define MIDI_STATUS_MASK 0x80
-
-// "Ref"s are pointers on 32-bit machines and ints on 64 bit machines
-// NULL_REF is our representation of either 0 or NULL
-#ifdef __LP64__
-#define NULL_REF 0
-#else
-#define NULL_REF NULL
-#endif
-
-static MIDIClientRef client = NULL_REF; /* Client handle to the MIDI server */
-static MIDIPortRef portIn = NULL_REF; /* Input port handle */
-static MIDIPortRef portOut = NULL_REF; /* Output port handle */
-static char isIAC[MAX_IAC_NUM + 1]; /* is device an IAC device */
-
-extern pm_fns_node pm_macosx_in_dictionary;
-extern pm_fns_node pm_macosx_out_dictionary;
-
-typedef struct coremidi_info_struct {
- int is_virtual; /* virtual device (TRUE) or actual device (FALSE)? */
- UInt64 delta; /* difference between stream time and real time in ns */
- int sysex_mode; /* middle of sending sysex */
- uint32_t sysex_word; /* accumulate data when receiving sysex */
- uint32_t sysex_byte_count; /* count how many received */
- char error[PM_HOST_ERROR_MSG_LEN];
- char callback_error[PM_HOST_ERROR_MSG_LEN];
- Byte packetBuffer[PACKET_BUFFER_SIZE];
- MIDIPacketList *packetList; /* a pointer to packetBuffer */
- MIDIPacket *packet;
- Byte sysex_buffer[SYSEX_BUFFER_SIZE]; /* temp storage for sysex data */
- MIDITimeStamp sysex_timestamp; /* host timestamp to use with sysex data */
- /* allow for running status (is running status possible here? -rbd): -cpr */
- UInt64 min_next_time; /* when can the next send take place? (host time) */
- int isIACdevice;
- Float64 us_per_host_tick; /* host clock frequency, units of min_next_time */
- UInt64 host_ticks_per_byte; /* host clock units per byte at maximum rate */
-} coremidi_info_node, *coremidi_info_type;
-
-/* private function declarations */
-MIDITimeStamp timestamp_pm_to_cm(PmTimestamp timestamp); // returns host time
-PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp); // returns ms
-
-char* cm_get_full_endpoint_name(MIDIEndpointRef endpoint, int *iac_flag);
-
-static PmError check_hosterror(OSStatus err, const char *msg)
-{
- if (err != noErr) {
- snprintf(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN, "Host error %ld: %s", (long) err, msg);
- pm_hosterror = TRUE;
- return pmHostError;
- }
- return pmNoError;
-}
-
-
-static PmTimestamp midi_synchronize(PmInternal *midi)
-{
- coremidi_info_type info = (coremidi_info_type) midi->api_info;
- UInt64 pm_stream_time_2 = // current time in ns
- AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
- PmTimestamp real_time; // in ms
- UInt64 pm_stream_time; // in ns
- /* if latency is zero and this is an output, there is no
- time reference and midi_synchronize should never be called */
- assert(midi->time_proc);
- assert(midi->is_input || midi->latency != 0);
- do {
- /* read real_time between two reads of stream time */
- pm_stream_time = pm_stream_time_2;
- real_time = (*midi->time_proc)(midi->time_info);
- pm_stream_time_2 = AudioConvertHostTimeToNanos(
- AudioGetCurrentHostTime());
- /* repeat if more than 0.5 ms has elapsed */
- } while (pm_stream_time_2 > pm_stream_time + 500000);
- info->delta = pm_stream_time - ((UInt64) real_time * (UInt64) 1000000);
- midi->sync_time = real_time;
- return real_time;
-}
-
-
-/* called when MIDI packets are received */
-static void read_callback(const MIDIPacketList *newPackets, PmInternal *midi)
-{
- PmTimestamp timestamp;
- MIDIPacket *packet;
- unsigned int packetIndex;
- uint32_t now;
- /* Retrieve the context for this connection */
- coremidi_info_type info = (coremidi_info_type) midi->api_info;
- assert(info);
-
- CM_DEBUG printf("read_callback: numPackets %d: ", newPackets->numPackets);
-
- /* synchronize time references every 100ms */
- now = (*midi->time_proc)(midi->time_info);
- if (midi->first_message || midi->sync_time + 100 /*ms*/ < now) {
- /* time to resync */
- now = midi_synchronize(midi);
- midi->first_message = FALSE;
- }
-
- packet = (MIDIPacket *) &newPackets->packet[0];
- /* hardware devices get untimed messages and apply timestamps. We
- * want to preserve them because they should be more accurate than
- * applying the current time here. virtual devices just pass on the
- * packet->timeStamp, which could be anything. PortMidi says the
- * PortMidi timestamp is the time the message is received. We do not
- * know if we are receiving from a device driver or a virtual device.
- * PortMidi sends to virtual devices get a current timestamp, so we
- * can treat them as the receive time. If the timestamp is zero,
- * suggested by CoreMIDI as the value to use for immediate delivery,
- * then we plug in `now` which is obtained above. If another
- * application sends bogus non-zero timestamps, we will convert them
- * to this port's reference time and pass them as event.timestamp.
- * Receiver beware.
- */
- CM_DEBUG printf("read_callback packet @ %lld ns (host %lld) "
- "status %x length %d\n",
- AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()),
- AudioGetCurrentHostTime(),
- packet->data[0], packet->length);
- for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) {
- /* Set the timestamp and dispatch this message */
- CM_DEBUG printf(" packet->timeStamp %lld ns %lld host\n",
- packet->timeStamp,
- AudioConvertHostTimeToNanos(packet->timeStamp));
- if (packet->timeStamp == 0) {
- timestamp = now;
- } else {
- timestamp = (PmTimestamp) /* explicit conversion */ (
- (AudioConvertHostTimeToNanos(packet->timeStamp) - info->delta) /
- (UInt64) 1000000);
- }
- pm_read_bytes(midi, packet->data, packet->length, timestamp);
- packet = MIDIPacketNext(packet);
- }
-}
-
-/* callback for real devices - redirects to read_callback */
-static void device_read_callback(const MIDIPacketList *newPackets,
- void *refCon, void *connRefCon)
-{
- read_callback(newPackets, (PmInternal *) connRefCon);
-}
-
-
-/* callback for virtual devices - redirects to read_callback */
-static void virtual_read_callback(const MIDIPacketList *newPackets,
- void *refCon, void *connRefCon)
-{
- /* this refCon is the device ID -- if there is a valid ID and
- the pm_descriptors table has a non-null pointer to a PmInternal,
- then then device is open and should receive this data */
- PmDeviceID id = (PmDeviceID) (size_t) refCon;
- if (id >= 0 && id < pm_descriptor_len) {
- if (pm_descriptors[id].pub.opened) {
- /* check for close request (7 reset status bytes): */
- if (newPackets->numPackets == 1 &&
- newPackets->packet[0].length == 8 &&
- /* CoreMIDI declares packets with 4-byte alignment, so we
- * should be safe to test for 8 0xFF's as 2 32-bit values: */
- *(SInt32 *) &newPackets->packet[0].data[0] == -1 &&
- *(SInt32 *) &newPackets->packet[0].data[4] == -1) {
- CM_DEBUG printf("got close request packet\n");
- pm_descriptors[id].pub.opened = FALSE;
- return;
- } else {
- read_callback(newPackets, pm_descriptors[id].pm_internal);
- }
- }
- }
-}
-
-
-/* allocate and initialize our internal coremidi connection info */
-static coremidi_info_type create_macosxcm_info(int is_virtual, int is_input)
-{
- coremidi_info_type info = (coremidi_info_type)
- pm_alloc(sizeof(coremidi_info_node));
- if (!info) {
- return NULL;
- }
- info->is_virtual = is_virtual;
- info->delta = 0;
- info->sysex_mode = FALSE;
- info->sysex_word = 0;
- info->sysex_byte_count = 0;
- info->packet = NULL;
- info->min_next_time = 0;
- info->isIACdevice = FALSE;
- info->us_per_host_tick = 1000000.0 / AudioGetHostClockFrequency();
- info->host_ticks_per_byte =
- (UInt64) (1000000.0 / (info->us_per_host_tick * MAX_BYTES_PER_S));
- info->packetList = (is_input ? NULL :
- (MIDIPacketList *) info->packetBuffer);
- return info;
-}
-
-
-static PmError midi_in_open(PmInternal *midi, void *driverInfo)
-{
- MIDIEndpointRef endpoint;
- coremidi_info_type info;
- OSStatus macHostError;
- int is_virtual = pm_descriptors[midi->device_id].pub.is_virtual;
-
- /* if this is an external device, descriptor is a MIDIEndpointRef.
- * if this is a virtual device for this application, descriptor is NULL.
- */
- if (!is_virtual) {
- endpoint = (MIDIEndpointRef) (intptr_t)
- pm_descriptors[midi->device_id].descriptor;
- if (endpoint == NULL_REF) {
- return pmInvalidDeviceId;
- }
- }
-
- info = create_macosxcm_info(is_virtual, TRUE);
- midi->api_info = info;
- if (!info) {
- return pmInsufficientMemory;
- }
- if (!is_virtual) {
- macHostError = MIDIPortConnectSource(portIn, endpoint, midi);
- if (macHostError != noErr) {
- midi->api_info = NULL;
- pm_free(info);
- return check_hosterror(macHostError,
- "MIDIPortConnectSource() in midi_in_open()");
- }
- }
- return pmNoError;
-}
-
-static PmError midi_in_close(PmInternal *midi)
-{
- MIDIEndpointRef endpoint;
- OSStatus macHostError;
- PmError err = pmNoError;
-
- coremidi_info_type info = (coremidi_info_type) midi->api_info;
-
- if (!info) return pmBadPtr;
-
- endpoint = (MIDIEndpointRef) (intptr_t)
- pm_descriptors[midi->device_id].descriptor;
- if (endpoint == NULL_REF) {
- return pmBadPtr;
- }
-
- if (!info->is_virtual) {
- /* shut off the incoming messages before freeing data structures */
- macHostError = MIDIPortDisconnectSource(portIn, endpoint);
- /* If the source closes, you get paramErr == -50 here. It seems
- * possible to monitor changes like sources closing by getting
- * notifications ALL changes, but the CoreMIDI documentation is
- * really terrible overall, and it seems easier to just ignore
- * this host error.
- */
- if (macHostError != noErr && macHostError != -50) {
- pm_hosterror = TRUE;
- err = check_hosterror(macHostError,
- "MIDIPortDisconnectSource() in midi_in_close()");
- }
- } else {
- /* make "close virtual port" message */
- SInt64 close_port_bytes = 0xFFFFFFFFFFFFFFFF;
- /* memory requirements: packet count (4), timestamp (8), length (2),
- * data (8). Total: 22, but we allocate plenty more:
- */
- Byte packetBuffer[64];
- MIDIPacketList *plist = (MIDIPacketList *) packetBuffer;
- MIDIPacket *packet = MIDIPacketListInit(plist);
- MIDIPacketListAdd(plist, 64, packet, 0, 8,
- (const Byte *) &close_port_bytes);
- macHostError = MIDISend(portOut, endpoint, plist);
- if (macHostError != noErr) {
- err = check_hosterror(macHostError, "MIDISend() (PortMidi close "
- "port packet) in midi_in_close()");
- }
- /* when packet is delivered, callback thread will clear opened;
- * we must wait for that before removing the input queues etc.
- * Maybe this could use signals of some kind, but if signals use
- * locks, locks can cause priority inversion problems, so we will
- * just sleep as needed. On the MIDI timescale, inserting a 0.5ms
- * latency should be OK, as the application has no business
- * opening/closing devices during time-critical moments.
- *
- * We expect the MIDI thread to close the device quickly (<0.5ms),
- * but we wait up to 50ms in case something terrible happens like
- * getting paged out in the middle of deliving packets to this
- * virtual device. If there is still no response, we time out and
- * force the close without the MIDI thread (even this will probably
- * succeed - the problem would be: this thread proceeds to delete
- * the input queues, and the freed memory is reallocated and
- * overwritten so that queues are no longer usable. Meanwhile,
- * the MIDI thread has already begun to deliver packets, so the
- * check for opened == TRUE passed, but MIDI thread does not insert
- * into queue until queue is freed, reallocated and overwritten.
- */
- for (int i = 0; i < 100; i++) { /* up to 50ms delay */
- if (!pm_descriptors[midi->device_id].pub.opened) {
- break;
- }
- usleep(500); /* 0.5ms */
- }
- pm_descriptors[midi->device_id].pub.opened = FALSE; /* force it */
- }
- midi->api_info = NULL;
- pm_free(info);
- return err;
-}
-
-
-static PmError midi_out_open(PmInternal *midi, void *driverInfo)
-{
- coremidi_info_type info;
- int is_virtual = pm_descriptors[midi->device_id].pub.is_virtual;
-
- info = create_macosxcm_info(is_virtual, FALSE);
- if (midi->device_id <= MAX_IAC_NUM) {
- info->isIACdevice = isIAC[midi->device_id];
- CM_DEBUG printf("midi_out_open isIACdevice %d\n", info->isIACdevice);
- }
- midi->api_info = info;
- if (!info) {
- return pmInsufficientMemory;
- }
- return pmNoError;
-}
-
-
-static PmError midi_out_close(PmInternal *midi)
-{
- coremidi_info_type info = (coremidi_info_type) midi->api_info;
- if (!info) return pmBadPtr;
- midi->api_info = NULL;
- pm_free(info);
- return pmNoError;
-}
-
-
-/* MIDIDestinationCreate apparently cannot create a virtual device
- * without a callback and a "refCon" parameter, but when we create
- * a virtual device, we do not want a PortMidi stream yet -- that
- * should wait for the user to open the stream. So, for the refCon,
- * use the PortMidi device ID. The callback will check if the
- * device is opened within PortMidi, and if so, use the pm_descriptors
- * table to locate the corresponding PmStream.
- */
-static PmError midi_create_virtual(int is_input, const char *name,
- void *device_info)
-{
- OSStatus macHostError;
- MIDIEndpointRef endpoint;
- CFStringRef nameRef;
- PmDeviceID id = pm_add_device("CoreMIDI", name, is_input, TRUE, NULL,
- (is_input ? &pm_macosx_in_dictionary :
- &pm_macosx_out_dictionary));
- if (id < 0) { /* error -- out of memory or name conflict? */
- return id;
- }
-
- nameRef = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
- if (is_input) {
- macHostError = MIDIDestinationCreate(client, nameRef,
- virtual_read_callback, (void *) (intptr_t) id, &endpoint);
- } else {
- macHostError = MIDISourceCreate(client, nameRef, &endpoint);
- }
- CFRelease(nameRef);
-
- if (macHostError != noErr) {
- /* undo the device we just allocated */
- pm_undo_add_device(id);
- return check_hosterror(macHostError, (is_input ?
- "MIDIDestinationCreateWithProtocol() in midi_create_virtual()" :
- "MIDISourceCreateWithProtocol() in midi_create_virtual()"));
- }
-
- /* Do we have a manufacturer name? If not, set to "PortMidi" */
- const char *mfr_name = "PortMidi";
- PmSysDepInfo *info = (PmSysDepInfo *) device_info;
- /* the version where pmKeyCoreMidiManufacturer was introduced is 210 */
- if (info && info->structVersion >= 210) {
- int i;
- for (i = 0; i < info->length; i++) { /* search for key */
- if (info->properties[i].key == pmKeyCoreMidiManufacturer) {
- mfr_name = info->properties[i].value;
- break;
- } /* no other keys are recognized; they are ignored */
- }
- }
- nameRef = CFStringCreateWithCString(NULL, mfr_name, kCFStringEncodingUTF8);
- MIDIObjectSetStringProperty(endpoint, kMIDIPropertyManufacturer, nameRef);
- CFRelease(nameRef);
-
- pm_descriptors[id].descriptor = (void *) (intptr_t) endpoint;
- return id;
-}
-
-
-static PmError midi_delete_virtual(PmDeviceID id)
-{
- MIDIEndpointRef endpoint;
- OSStatus macHostError;
-
- endpoint = (MIDIEndpointRef) (long) pm_descriptors[id].descriptor;
- if (endpoint == NULL_REF) {
- return pmBadPtr;
- }
- macHostError = MIDIEndpointDispose(endpoint);
- return check_hosterror(macHostError,
- "MIDIEndpointDispose() in midi_in_close()");
-}
-
-
-static PmError midi_abort(PmInternal *midi)
-{
- OSStatus macHostError;
- MIDIEndpointRef endpoint = (MIDIEndpointRef) (intptr_t)
- pm_descriptors[midi->device_id].descriptor;
- macHostError = MIDIFlushOutput(endpoint);
- return check_hosterror(macHostError,
- "MIDIFlushOutput() in midi_abort()");
-}
-
-
-static PmError midi_write_flush(PmInternal *midi, PmTimestamp timestamp)
-{
- OSStatus macHostError = 0;
- coremidi_info_type info = (coremidi_info_type) midi->api_info;
- MIDIEndpointRef endpoint = (MIDIEndpointRef) (intptr_t)
- pm_descriptors[midi->device_id].descriptor;
- assert(info);
- assert(endpoint);
- if (info->packet != NULL) {
- /* out of space, send the buffer and start refilling it */
- /* update min_next_time each flush to support rate limit */
- UInt64 host_now = AudioGetCurrentHostTime();
- if (host_now > info->min_next_time)
- info->min_next_time = host_now;
- if (info->is_virtual) {
- macHostError = MIDIReceived(endpoint, info->packetList);
- } else {
- macHostError = MIDISend(portOut, endpoint, info->packetList);
- }
- info->packet = NULL; /* indicate no data in packetList now */
- }
- return check_hosterror(macHostError, (info->is_virtual ?
- "MIDIReceived() in midi_write()" :
- "MIDISend() in midi_write()"));
-}
-
-
-static PmError send_packet(PmInternal *midi, Byte *message,
- unsigned int messageLength, MIDITimeStamp timestamp)
-{
- PmError err;
- coremidi_info_type info = (coremidi_info_type) midi->api_info;
- assert(info);
-
- CM_DEBUG printf("add %d to packet %p len %d timestamp %lld @ %lld ns "
- "(host %lld)\n",
- message[0], info->packet, messageLength, timestamp,
- AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()),
- AudioGetCurrentHostTime());
- info->packet = MIDIPacketListAdd(info->packetList,
- sizeof(info->packetBuffer), info->packet,
- timestamp, messageLength, message);
-#if LIMIT_SEND_RATE
- info->byte_count += messageLength;
-#endif
- if (info->packet == NULL) {
- /* out of space, send the buffer and start refilling it */
- /* make midi->packet non-null to fool midi_write_flush into sending */
- info->packet = (MIDIPacket *) 4;
- /* timestamp is 0 because midi_write_flush ignores timestamp since
- * timestamps are already in packets. The timestamp parameter is here
- * because other API's need it. midi_write_flush can be called
- * from system-independent code that must be cross-API.
- */
- if ((err = midi_write_flush(midi, 0)) != pmNoError) return err;
- info->packet = MIDIPacketListInit(info->packetList);
- assert(info->packet); /* if this fails, it's a programming error */
- info->packet = MIDIPacketListAdd(info->packetList,
- sizeof(info->packetBuffer), info->packet,
- timestamp, messageLength, message);
- assert(info->packet); /* can't run out of space on first message */
- }
- return pmNoError;
-}
-
-
-static PmError midi_write_short(PmInternal *midi, PmEvent *event)
-{
- PmTimestamp when = event->timestamp;
- PmMessage what = event->message;
- MIDITimeStamp timestamp;
- coremidi_info_type info = (coremidi_info_type) midi->api_info;
- Byte message[4];
- unsigned int messageLength;
-
- if (info->packet == NULL) {
- info->packet = MIDIPacketListInit(info->packetList);
- /* this can never fail, right? failure would indicate something
- unrecoverable */
- assert(info->packet);
- }
-
- /* PortMidi specifies that incoming timestamps are the receive
- * time. Devices attach their receive times, but virtual devices
- * do not. Instead, they pass along whatever timestamp was sent to
- * them. We do not know if we are connected to real or virtual
- * device. To avoid wild timestamps on the receiving end, we
- * consider 2 cases: PortMidi timestamp is zero or latency is
- * zero. Both mean send immediately, so we attach the current time
- * which will go out immediately and arrive with a sensible
- * timestamp (not zero and not zero mapped to the client's local
- * time). Otherwise, we assume the timestamp is reasonable. It
- * might be slighly in the past, but we pass it along after
- * translation to MIDITimeStamp units.
- *
- * Compute timestamp: use current time if timestamp is zero or
- * latency is zero. Both mean no timing and send immediately.
- */
- if (when == 0 || midi->latency == 0) {
- timestamp = AudioGetCurrentHostTime();
- } else { /* translate PortMidi time + latency to CoreMIDI time */
- timestamp = ((UInt64) (when + midi->latency) * (UInt64) 1000000) +
- info->delta;
- timestamp = AudioConvertNanosToHostTime(timestamp);
- }
-
- message[0] = Pm_MessageStatus(what);
- message[1] = Pm_MessageData1(what);
- message[2] = Pm_MessageData2(what);
- messageLength = pm_midi_length((int32_t) what);
-
-#ifdef LIMIT_RATE
- /* Make sure we go forward in time. */
- if (timestamp < info->min_next_time) {
- timestamp = info->min_next_time;
- }
- /* Note that if application is way behind and slowly catching up, then
- * timestamps could be increasing faster than real time, and since
- * timestamps are used to estimate data rate, our estimate could be
- * low, causing CoreMIDI to drop packets. This seems very unlikely.
- */
- if (info->isIACdevice || info->is_virtual) {
- info->min_next_time = timestamp + messageLength *
- info->host_ticks_per_byte;
- }
-#endif
- /* Add this message to the packet list */
- return send_packet(midi, message, messageLength, timestamp);
-}
-
-
-static PmError midi_begin_sysex(PmInternal *midi, PmTimestamp when)
-{
- UInt64 when_ns;
- coremidi_info_type info = (coremidi_info_type) midi->api_info;
- assert(info);
- info->sysex_byte_count = 0;
-
- /* compute timestamp */
- if (when == 0) when = midi->now;
- /* if latency == 0, midi->now is not valid. We will just set it to zero */
- if (midi->latency == 0) when = 0;
- when_ns = ((UInt64) (when + midi->latency) * (UInt64) 1000000) +
- info->delta;
- info->sysex_timestamp =
- (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns);
- UInt64 now; /* only make system time call when writing a virtual port */
- if (info->is_virtual && info->sysex_timestamp <
- (now = AudioGetCurrentHostTime())) {
- info->sysex_timestamp = now;
- }
-
- if (info->packet == NULL) {
- info->packet = MIDIPacketListInit(info->packetList);
- /* this can never fail, right? failure would indicate something
- unrecoverable */
- assert(info->packet);
- }
- return pmNoError;
-}
-
-
-static PmError midi_end_sysex(PmInternal *midi, PmTimestamp when)
-{
- PmError err;
- coremidi_info_type info = (coremidi_info_type) midi->api_info;
- assert(info);
-
-#ifdef LIMIT_RATE
- /* make sure we go foreward in time */
- if (info->sysex_timestamp < info->min_next_time)
- info->sysex_timestamp = info->min_next_time;
-
- if (info->isIACdevice) {
- info->min_next_time = info->sysex_timestamp + info->sysex_byte_count *
- info->host_ticks_per_byte;
- }
-#endif
-
- /* now send what's in the buffer */
- err = send_packet(midi, info->sysex_buffer, info->sysex_byte_count,
- info->sysex_timestamp);
- info->sysex_byte_count = 0;
- if (err != pmNoError) {
- info->packet = NULL; /* flush everything in the packet list */
- }
- return err;
-}
-
-
-static PmError midi_write_byte(PmInternal *midi, unsigned char byte,
- PmTimestamp timestamp)
-{
- coremidi_info_type info = (coremidi_info_type) midi->api_info;
- assert(info);
- if (info->sysex_byte_count >= SYSEX_BUFFER_SIZE) {
- PmError err = midi_end_sysex(midi, timestamp);
- if (err != pmNoError) return err;
- }
- info->sysex_buffer[info->sysex_byte_count++] = byte;
- return pmNoError;
-}
-
-
-static PmError midi_write_realtime(PmInternal *midi, PmEvent *event)
-{
- /* to send a realtime message during a sysex message, first
- flush all pending sysex bytes into packet list */
- PmError err = midi_end_sysex(midi, 0);
- if (err != pmNoError) return err;
- /* then we can just do a normal midi_write_short */
- return midi_write_short(midi, event);
-}
-
-
-static unsigned int midi_check_host_error(PmInternal *midi)
-{
- return FALSE;
-}
-
-
-MIDITimeStamp timestamp_pm_to_cm(PmTimestamp timestamp)
-{
- UInt64 nanos;
- if (timestamp <= 0) {
- return (MIDITimeStamp)0;
- } else {
- nanos = (UInt64)timestamp * (UInt64)1000000;
- return (MIDITimeStamp)AudioConvertNanosToHostTime(nanos);
- }
-}
-
-
-PmTimestamp timestamp_cm_to_pm(MIDITimeStamp timestamp)
-{
- UInt64 nanos;
- nanos = AudioConvertHostTimeToNanos(timestamp);
- return (PmTimestamp)(nanos / (UInt64)1000000);
-}
-
-
-//
-// Code taken from http://developer.apple.com/qa/qa2004/qa1374.html
-//////////////////////////////////////
-// Obtain the name of an endpoint without regard for whether it has connections.
-// The result should be released by the caller.
-CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal,
- int *iac_flag)
-{
- CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
- CFStringRef str;
- *iac_flag = FALSE;
-
- // begin with the endpoint's name
- str = NULL;
- MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &str);
- if (str != NULL) {
- CFStringAppend(result, str);
- CFRelease(str);
- }
- MIDIEntityRef entity = NULL_REF;
- MIDIEndpointGetEntity(endpoint, &entity);
- if (entity == NULL_REF) {
- // probably virtual
- return result;
- }
- if (!isExternal) { /* detect IAC devices */
- //extern const CFStringRef kMIDIPropertyDriverOwner;
- MIDIObjectGetStringProperty(entity, kMIDIPropertyDriverOwner, &str);
- if (str != NULL) {
- char s[32]; /* driver name may truncate, but that's OK */
- CFStringGetCString(str, s, 31, kCFStringEncodingUTF8);
- s[31] = 0; /* make sure it is terminated just to be safe */
- CM_DEBUG printf("driver %s\n", s);
- *iac_flag = (strcmp(s, "com.apple.AppleMIDIIACDriver") == 0);
- }
- }
-
- if (CFStringGetLength(result) == 0) {
- // endpoint name has zero length -- try the entity
- str = NULL;
- MIDIObjectGetStringProperty(entity, kMIDIPropertyName, &str);
- if (str != NULL) {
- CFStringAppend(result, str);
- CFRelease(str);
- }
- }
- // now consider the device's name
- MIDIDeviceRef device = NULL_REF;
- MIDIEntityGetDevice(entity, &device);
- if (device == NULL_REF)
- return result;
-
- str = NULL;
- MIDIObjectGetStringProperty(device, kMIDIPropertyName, &str);
- if (CFStringGetLength(result) == 0) {
- CFRelease(result);
- return str;
- }
- if (str != NULL) {
- // if an external device has only one entity, throw away
- // the endpoint name and just use the device name
- if (isExternal && MIDIDeviceGetNumberOfEntities(device) < 2) {
- CFRelease(result);
- return str;
- } else {
- if (CFStringGetLength(str) == 0) {
- CFRelease(str);
- return result;
- }
- // does the entity name already start with the device name?
- // (some drivers do this though they shouldn't)
- // if so, do not prepend
- if (CFStringCompareWithOptions(result, /* endpoint name */
- str, /* device name */
- CFRangeMake(0, CFStringGetLength(str)), 0) !=
- kCFCompareEqualTo) {
- // prepend the device name to the entity name
- if (CFStringGetLength(result) > 0)
- CFStringInsert(result, 0, CFSTR(" "));
- CFStringInsert(result, 0, str);
- }
- CFRelease(str);
- }
- }
- return result;
-}
-
-
-// Obtain the name of an endpoint, following connections.
-// The result should be released by the caller.
-static CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint,
- int *iac_flag)
-{
- CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
- CFStringRef str;
- OSStatus err;
- long i;
-
- // Does the endpoint have connections?
- CFDataRef connections = NULL;
- long nConnected = 0;
- bool anyStrings = false;
- err = MIDIObjectGetDataProperty(endpoint, kMIDIPropertyConnectionUniqueID,
- &connections);
- if (connections != NULL) {
- // It has connections, follow them
- // Concatenate the names of all connected devices
- nConnected = CFDataGetLength(connections) /
- (int32_t) sizeof(MIDIUniqueID);
- if (nConnected) {
- const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
- for (i = 0; i < nConnected; ++i, ++pid) {
- MIDIUniqueID id = EndianS32_BtoN(*pid);
- MIDIObjectRef connObject;
- MIDIObjectType connObjectType;
- err = MIDIObjectFindByUniqueID(id, &connObject,
- &connObjectType);
- if (err == noErr) {
- if (connObjectType == kMIDIObjectType_ExternalSource ||
- connObjectType == kMIDIObjectType_ExternalDestination) {
- // Connected to an external device's endpoint (>=10.3)
- str = EndpointName((MIDIEndpointRef)(connObject), true,
- iac_flag);
- } else {
- // Connected to an external device (10.2)
- // (or something else, catch-all)
- str = NULL;
- MIDIObjectGetStringProperty(connObject,
- kMIDIPropertyName, &str);
- }
- if (str != NULL) {
- if (anyStrings)
- CFStringAppend(result, CFSTR(", "));
- else anyStrings = true;
- CFStringAppend(result, str);
- CFRelease(str);
- }
- }
- }
- }
- CFRelease(connections);
- }
- if (anyStrings)
- return result; // caller should release result
-
- CFRelease(result);
-
- // Here, either the endpoint had no connections, or we failed to
- // obtain names for any of them.
- return EndpointName(endpoint, false, iac_flag);
-}
-
-
-char *cm_get_full_endpoint_name(MIDIEndpointRef endpoint, int *iac_flag)
-{
- /* Thanks to Dan Wilcox for fixes for Unicode handling */
- CFStringRef fullName = ConnectedEndpointName(endpoint, iac_flag);
- CFIndex utf16_len = CFStringGetLength(fullName) + 1;
- CFIndex max_byte_len = CFStringGetMaximumSizeForEncoding(
- utf16_len, kCFStringEncodingUTF8) + 1;
- char* pmname = (char *) pm_alloc(CFStringGetLength(fullName) + 1);
-
- /* copy the string into our buffer; note that there may be some wasted
- space, but the total waste is not large */
- CFStringGetCString(fullName, pmname, max_byte_len, kCFStringEncodingUTF8);
-
- /* clean up */
- if (fullName) CFRelease(fullName);
- return pmname;
-}
-
-
-pm_fns_node pm_macosx_in_dictionary = {
- none_write_short,
- none_sysex,
- none_sysex,
- none_write_byte,
- none_write_short,
- none_write_flush,
- none_synchronize,
- midi_in_open,
- midi_abort,
- midi_in_close,
- success_poll,
- midi_check_host_error
-};
-
-pm_fns_node pm_macosx_out_dictionary = {
- midi_write_short,
- midi_begin_sysex,
- midi_end_sysex,
- midi_write_byte,
- midi_write_realtime,
- midi_write_flush,
- midi_synchronize,
- midi_out_open,
- midi_abort,
- midi_out_close,
- success_poll,
- midi_check_host_error
-};
-
-
-/* We do nothing with callbacks, but generating the callbacks also
- * updates CoreMIDI state. Callback may not be essential, but calling
- * the CFRunLoopRunInMode is necessary.
- */
-void cm_notify(const MIDINotification *msg, void *refCon)
-{
- /* for debugging, trace change notifications:
- const char *descr[] = {
- "undefined (0)",
- "kMIDIMsgSetupChanged",
- "kMIDIMsgObjectAdded",
- "kMIDIMsgObjectRemoved",
- "kMIDIMsgPropertyChanged",
- "kMIDIMsgThruConnectionsChanged",
- "kMIDIMsgSerialPortOwnerChanged",
- "kMIDIMsgIOError"};
-
- printf("MIDI Notify, messageID %d (%s)\n", (int) msg->messageID,
- descr[(int) msg->messageID]);
- */
- return;
-}
-
-
-PmError pm_macosxcm_init(void)
-{
- ItemCount numInputs, numOutputs, numDevices;
- MIDIEndpointRef endpoint;
- OSStatus macHostError = noErr;
- char *error_text;
-
- memset(isIAC, 0, sizeof(isIAC)); /* initialize all FALSE */
-
- /* Register interface CoreMIDI with create_virtual fn */
- pm_add_interf("CoreMIDI", &midi_create_virtual, &midi_delete_virtual);
- /* no check for error return because this always succeeds */
-
- /* Determine the number of MIDI devices on the system */
- numDevices = MIDIGetNumberOfDevices();
-
- /* Return prematurely if no devices exist on the system
- Note that this is not an error. There may be no devices.
- Pm_CountDevices() will return zero, which is correct and
- useful information
- */
- if (numDevices <= 0) {
- return pmNoError;
- }
-
- /* Initialize the client handle */
- if (client == NULL_REF) {
- macHostError = MIDIClientCreate(CFSTR("PortMidi"), &cm_notify, NULL,
- &client);
- } else { /* see notes above on device scanning */
- for (int i = 0; i < 100; i++) {
- // look for any changes before scanning for devices
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
- if (i % 5 == 0) Pt_Sleep(1); /* insert 20 delays */
- }
- }
- if (macHostError != noErr) {
- error_text = "MIDIClientCreate() in pm_macosxcm_init()";
- goto error_return;
- }
- numInputs = MIDIGetNumberOfSources();
- numOutputs = MIDIGetNumberOfDestinations();
-
- /* Create the input port */
- macHostError = MIDIInputPortCreate(client, CFSTR("Input port"),
- device_read_callback, NULL, &portIn);
- if (macHostError != noErr) {
- error_text = "MIDIInputPortCreate() in pm_macosxcm_init()";
- goto error_return;
- }
-
- /* Create the output port */
- macHostError = MIDIOutputPortCreate(client, CFSTR("Output port"), &portOut);
- if (macHostError != noErr) {
- error_text = "MIDIOutputPortCreate() in pm_macosxcm_init()";
- goto error_return;
- }
-
- /* Iterate over the MIDI input devices */
- for (int i = 0; i < numInputs; i++) {
- int iac_flag;
- endpoint = MIDIGetSource(i);
- if (endpoint == NULL_REF) {
- continue;
- }
- /* Register this device with PortMidi */
- pm_add_device("CoreMIDI",
- cm_get_full_endpoint_name(endpoint, &iac_flag), TRUE, FALSE,
- (void *) (intptr_t) endpoint, &pm_macosx_in_dictionary);
- }
-
- /* Iterate over the MIDI output devices */
- for (int i = 0; i < numOutputs; i++) {
- int iac_flag;
- PmDeviceID id;
- endpoint = MIDIGetDestination(i);
- if (endpoint == NULL_REF) {
- continue;
- }
- /* Register this device with PortMidi */
- id = pm_add_device("CoreMIDI",
- cm_get_full_endpoint_name(endpoint, &iac_flag), FALSE, FALSE,
- (void *) (intptr_t) endpoint, &pm_macosx_out_dictionary);
- /* if this is an IAC device, tuck that info away for write functions */
- if (iac_flag && id <= MAX_IAC_NUM) {
- isIAC[id] = TRUE;
- }
- }
- return pmNoError;
-
-error_return:
- pm_macosxcm_term(); /* clear out any opened ports */
- return check_hosterror(macHostError, error_text);
-}
-
-void pm_macosxcm_term(void)
-{
- /* docs say do not explicitly dispose of client
- if (client != NULL_REF) MIDIClientDispose(client); */
- if (portIn != NULL_REF) MIDIPortDispose(portIn);
- if (portOut != NULL_REF) MIDIPortDispose(portOut);
-}
diff --git a/portmidi/pm_mac/pmmacosxcm.h b/portmidi/pm_mac/pmmacosxcm.h
deleted file mode 100755
index 166a0b7..0000000
--- a/portmidi/pm_mac/pmmacosxcm.h
+++ /dev/null
@@ -1,4 +0,0 @@
-/* system-specific definitions */
-
-PmError pm_macosxcm_init(void);
-void pm_macosxcm_term(void);
diff --git a/portmidi/pm_sndio/pmsndio.c b/portmidi/pm_sndio/pmsndio.c
deleted file mode 100644
index 0c1ea11..0000000
--- a/portmidi/pm_sndio/pmsndio.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/* pmsndio.c -- PortMidi os-dependent code */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <sndio.h>
-#include <string.h>
-#include <poll.h>
-#include <errno.h>
-#include <pthread.h>
-#include "portmidi.h"
-#include "pmutil.h"
-#include "pminternal.h"
-#include "porttime.h"
-
-#define NDEVS 9
-#define SYSEX_MAXLEN 1024
-
-#define SYSEX_START 0xf0
-#define SYSEX_END 0xf7
-
-extern pm_fns_node pm_sndio_in_dictionary;
-extern pm_fns_node pm_sndio_out_dictionary;
-
-/* length of voice and common messages (status byte included) */
-unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
-unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
-
-struct mio_dev {
- char name[16];
- struct mio_hdl *hdl;
- int mode;
- char errmsg[PM_HOST_ERROR_MSG_LEN];
- pthread_t thread;
-} devs[NDEVS];
-
-static void set_mode(struct mio_dev *, unsigned int);
-
-void pm_init()
-{
- int i, j, k = 0;
- char devices[][16] = {"midithru", "rmidi", "midi", "snd"};
-
- /* default */
- strcpy(devs[0].name, MIO_PORTANY);
- pm_add_device("SNDIO", devs[k].name, TRUE, FALSE, (void *) &devs[k],
- &pm_sndio_in_dictionary);
- pm_add_device("SNDIO", devs[k].name, FALSE, FALSE, (void *) &devs[k],
- &pm_sndio_out_dictionary);
- k++;
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 2; j++) {
- sprintf(devs[k].name, "%s/%d", devices[i], j);
- pm_add_device("SNDIO", devs[k].name, TRUE, FALSE, (void *) &devs[k],
- &pm_sndio_in_dictionary);
- pm_add_device("SNDIO", devs[k].name, FALSE, FALSE, (void *) &devs[k],
- &pm_sndio_out_dictionary);
- k++;
- }
- }
-
- // this is set when we return to Pm_Initialize, but we need it
- // now in order to (successfully) call Pm_CountDevices()
- pm_initialized = TRUE;
- pm_default_input_device_id = 0;
- pm_default_output_device_id = 1;
-}
-
-void pm_term(void)
-{
- int i;
- for(i = 0; i < NDEVS; i++) {
- if (devs[i].mode != 0) {
- set_mode(&devs[i], 0);
- if (devs[i].thread) {
- pthread_join(devs[i].thread, NULL);
- devs[i].thread = NULL;
- }
- }
- }
-}
-
-PmDeviceID Pm_GetDefaultInputDeviceID() {
- Pm_Initialize();
- return pm_default_input_device_id;
-}
-
-PmDeviceID Pm_GetDefaultOutputDeviceID() {
- Pm_Initialize();
- return pm_default_output_device_id;
-}
-
-void *pm_alloc(size_t s) { return malloc(s); }
-
-void pm_free(void *ptr) { free(ptr); }
-
-/* midi_message_length -- how many bytes in a message? */
-static int midi_message_length(PmMessage message)
-{
- unsigned char st = message & 0xff;
- if (st >= 0xf8)
- return 1;
- else if (st >= 0xf0)
- return common_len[st & 7];
- else if (st >= 0x80)
- return voice_len[(st >> 4) & 7];
- else
- return 0;
-}
-
-void* input_thread(void *param)
-{
- PmInternal *midi = (PmInternal*)param;
- struct mio_dev *dev = pm_descriptors[midi->device_id].descriptor;
- struct pollfd pfd[1];
- nfds_t nfds;
- unsigned char st = 0, c = 0;
- int rc, revents, idx = 0, len = 0;
- size_t todo = 0;
- unsigned char buf[0x200], *p;
- PmEvent pm_ev, pm_ev_rt;
- unsigned char sysex_data[SYSEX_MAXLEN];
-
- while(dev->mode & MIO_IN) {
- if (todo == 0) {
- nfds = mio_pollfd(dev->hdl, pfd, POLLIN);
- rc = poll(pfd, nfds, 100);
- if (rc < 0) {
- if (errno == EINTR)
- continue;
- break;
- }
- revents = mio_revents(dev->hdl, pfd);
- if (!(revents & POLLIN))
- continue;
-
- todo = mio_read(dev->hdl, buf, sizeof(buf));
- if (todo == 0)
- continue;
- p = buf;
- }
- c = *p++;
- todo--;
-
- if (c >= 0xf8) {
- pm_ev_rt.message = c;
- pm_ev_rt.timestamp = Pt_Time();
- pm_read_short(midi, &pm_ev_rt);
- } else if (c == SYSEX_END) {
- /* note: PortMidi is designed to avoid the need for SYSEX_MAXLEN.
- With the new implementation of pm_read_bytes, it would be
- better to simply call pm_read_bytes() and let it parse buf,
- which can contain any number of whole or partial messages with
- interleaved realtime messages. I did not change the code because
- I cannot test it. -RBD */
- if (st == SYSEX_START) {
- sysex_data[idx++] = c;
- pm_read_bytes(midi, sysex_data, idx, Pt_Time());
- }
- st = 0;
- idx = 0;
- } else if (c == SYSEX_START) {
- st = c;
- idx = 0;
- sysex_data[idx++] = c;
- } else if (c >= 0xf0) {
- pm_ev.message = c;
- len = common_len[c & 7];
- st = c;
- idx = 1;
- } else if (c >= 0x80) {
- pm_ev.message = c;
- len = voice_len[(c >> 4) & 7];
- st = c;
- idx = 1;
- } else if (st == SYSEX_START) {
- if (idx == SYSEX_MAXLEN) {
- fprintf(stderr, "the message is too long\n");
- idx = st = 0;
- } else {
- sysex_data[idx++] = c;
- }
- } else if (st) {
- if (idx == 0 && st != SYSEX_START)
- pm_ev.message |= (c << (8 * idx++));
- pm_ev.message |= (c << (8 * idx++));
- if (idx == len) {
- pm_read_short(midi, &pm_ev);
- if (st >= 0xf0)
- st = 0;
- idx = 0;
- }
- }
- }
-
- pthread_exit(NULL);
- return NULL;
-}
-
-static void set_mode(struct mio_dev *dev, unsigned int mode) {
- if (dev->mode != 0)
- mio_close(dev->hdl);
- dev->mode = 0;
- if (mode != 0)
- dev->hdl = mio_open(dev->name, mode, 0);
- if (dev->hdl)
- dev->mode = mode;
-}
-
-static PmError sndio_out_open(PmInternal *midi, void *driverInfo)
-{
- struct mio_dev *dev = pm_descriptors[midi->device_id].descriptor;
-
- if (dev->mode & MIO_OUT)
- return pmNoError;
-
- set_mode(dev, dev->mode | MIO_OUT);
- if (!(dev->mode & MIO_OUT)) {
- snprintf(dev->errmsg, PM_HOST_ERROR_MSG_LEN,
- "mio_open (output) failed: %s\n", dev->name);
- return pmHostError;
- }
-
- return pmNoError;
-}
-
-static PmError sndio_in_open(PmInternal *midi, void *driverInfo)
-{
- struct mio_dev *dev = pm_descriptors[midi->device_id].descriptor;
-
- if (dev->mode & MIO_IN)
- return pmNoError;
-
- set_mode(dev, dev->mode | MIO_IN);
- if (!(dev->mode & MIO_IN)) {
- snprintf(dev->errmsg, PM_HOST_ERROR_MSG_LEN,
- "mio_open (input) failed: %s\n", dev->name);
- return pmHostError;
- }
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_create(&dev->thread, &attr, input_thread, ( void* )midi);
- return pmNoError;
-}
-
-static PmError sndio_out_close(PmInternal *midi)
-{
- struct mio_dev *dev = pm_descriptors[midi->device_id].descriptor;
-
- if (dev->mode & MIO_OUT)
- set_mode(dev, dev->mode & ~MIO_OUT);
- return pmNoError;
-}
-
-static PmError sndio_in_close(PmInternal *midi)
-{
- struct mio_dev *dev = pm_descriptors[midi->device_id].descriptor;
-
- if (dev->mode & MIO_IN) {
- set_mode(dev, dev->mode & ~MIO_IN);
- pthread_join(dev->thread, NULL);
- dev->thread = NULL;
- }
- return pmNoError;
-}
-
-static PmError sndio_abort(PmInternal *midi)
-{
- return pmNoError;
-}
-
-static PmTimestamp sndio_synchronize(PmInternal *midi)
-{
- return 0;
-}
-
-static PmError do_write(struct mio_dev *dev, const void *addr, size_t nbytes)
-{
- size_t w = mio_write(dev->hdl, addr, nbytes);
-
- if (w != nbytes) {
- snprintf(dev->errmsg, PM_HOST_ERROR_MSG_LEN,
- "mio_write failed, bytes written:%zu\n", w);
- return pmHostError;
- }
- return pmNoError;
-}
-
-static PmError sndio_write_byte(PmInternal *midi, unsigned char byte,
- PmTimestamp timestamp)
-{
- struct mio_dev *dev = pm_descriptors[midi->device_id].descriptor;
-
- return do_write(dev, &byte, 1);
-}
-
-static PmError sndio_write_short(PmInternal *midi, PmEvent *event)
-{
- struct mio_dev *dev = pm_descriptors[midi->device_id].descriptor;
- int nbytes = midi_message_length(event->message);
-
- if (midi->latency > 0) {
- /* XXX the event should be queued for later playback */
- return do_write(dev, &event->message, nbytes);
- } else {
- return do_write(dev, &event->message, nbytes);
- }
- return pmNoError;
-}
-
-static PmError sndio_write_flush(PmInternal *midi, PmTimestamp timestamp)
-{
- return pmNoError;
-}
-
-PmError sndio_sysex(PmInternal *midi, PmTimestamp timestamp)
-{
- return pmNoError;
-}
-
-static unsigned int sndio_has_host_error(PmInternal *midi)
-{
- struct mio_dev *dev = pm_descriptors[midi->device_id].descriptor;
-
- return (dev->errmsg[0] != '\0');
-}
-
-static void sndio_get_host_error(PmInternal *midi, char *msg, unsigned int len)
-{
- struct mio_dev *dev = pm_descriptors[midi->device_id].descriptor;
-
- strlcpy(msg, dev->errmsg, len);
- dev->errmsg[0] = '\0';
-}
-
-pm_fns_node pm_sndio_in_dictionary = {
- none_write_short,
- none_sysex,
- none_sysex,
- none_write_byte,
- none_write_short,
- none_write_flush,
- sndio_synchronize,
- sndio_in_open,
- sndio_abort,
- sndio_in_close,
- success_poll,
- sndio_has_host_error,
-};
-
-pm_fns_node pm_sndio_out_dictionary = {
- sndio_write_short,
- sndio_sysex,
- sndio_sysex,
- sndio_write_byte,
- sndio_write_short,
- sndio_write_flush,
- sndio_synchronize,
- sndio_out_open,
- sndio_abort,
- sndio_out_close,
- none_poll,
- sndio_has_host_error,
-};
-
diff --git a/portmidi/pm_sndio/pmsndio.h b/portmidi/pm_sndio/pmsndio.h
deleted file mode 100644
index 4096d9b..0000000
--- a/portmidi/pm_sndio/pmsndio.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/* pmsndio.h */
-
-extern PmDeviceID pm_default_input_device_id;
-extern PmDeviceID pm_default_output_device_id;
-
diff --git a/portmidi/pm_test/CMakeLists.txt b/portmidi/pm_test/CMakeLists.txt
deleted file mode 100644
index ae0fe48..0000000
--- a/portmidi/pm_test/CMakeLists.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-# CMake file to build tests in this directory: pm_test
-
-# set the build directory to be in portmidi, not in portmidi/pm_test
-# this is required for Xcode:
-if(APPLE)
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
-endif(APPLE)
-
-# if(WIN32)
-# if(NOT BUILD_SHARED_LIBS)
- # /MDd is multithread debug DLL, /MTd is multithread debug
- # /MD is multithread DLL, /MT is multithread. Change to static:
-# include(../pm_win/static.cmake)
-# endif()
-# endif(WIN32)
-
-if(HAIKU)
- add_compile_options(-fPIC) # Haiku x86_64 needs this explicitly
-endif()
-
-macro(add_test name)
- add_executable(${name} ${name}.c)
- target_link_libraries(${name} PRIVATE portmidi)
- set_property(TARGET ${name} PROPERTY MSVC_RUNTIME_LIBRARY
- "MultiThreaded$<$<CONFIG:Debug>:Debug>${MSVCRT_DLL}")
-endmacro(add_test)
-
-add_test(testio)
-add_test(midithread)
-add_test(midithru)
-add_test(sysex)
-add_test(latency)
-add_test(mm)
-add_test(midiclock)
-add_test(qtest)
-add_test(fast)
-add_test(fastrcv)
-add_test(pmlist)
-if(WIN32)
-# windows does not implement Pm_CreateVirtualInput or Pm_CreateVirtualOutput
-else(WIN32)
-add_test(recvvirtual)
-add_test(sendvirtual)
-add_test(multivirtual)
-add_test(virttest)
-endif(WIN32)
diff --git a/portmidi/pm_test/README.txt b/portmidi/pm_test/README.txt
deleted file mode 100644
index 6c0c7ab..0000000
--- a/portmidi/pm_test/README.txt
+++ /dev/null
@@ -1,363 +0,0 @@
-README.txt - for pm_test directory
-
-These are all test programs for PortMidi
-
-Because device numbers depend on the system, there is no automated
-script to run all tests on PortMidi.
-
-To run the full set of tests manually:
-
-Note: everything is run from the ../Debug or ../Release directory.
-Actual or example input is marked with >>, e.g., >>0 means type 0<ENTER>
-Comments are shown in square brackets [like this]
-
-1. ./qtest -- output should show a bunch of tests and no error message.
-
-2. ./testio [test input]
-Latency in ms: >>0
-enter your choice... >>1
-Type input number: >>6 [pick a working input device]
-[play some notes, look for note-on (0x90) with pitch and velocity data]
-
-3. ./testio [test input (fail w/assert)]
-Latency in ms: >>0
-enter your choice... >>2
-Type input number: >>6 [pick a working input device]
-[play some notes, program will abort after 5 messages
-(this test only applies to a Debug build, otherwise
-the assert() macro is disabled.)]
-
-4. ./testio [test input (fail w/NULL assign)]
-Latency in ms: >>0
-enter your choice... >>3
-Type input number: >>6 [pick a working input device]
-[play some notes, program will Segmentation fault after 5 messages
-(this test may not Segfault in the Release build; if not
-try testing with a Debug build.)]
-
-5. ./testio [test output, no latency]
-Latency in ms: >>0
-enter your choice... >>4
-Type output number: >>2 [pick a working output device]
->> [type ENTER when prompted (7 times)]
-[hear note on, note off, note on, note off, chord]
-
-6. ./testio [test output, latency > 0]
-Latency in ms: >>300
-enter your choice... >>4
-Type output number: >>2 [pick a working output device]
->> [type ENTER when prompted (7 times)]
-[hear note on, note off, note on, note off, arpeggiated chord
- (delay of 300ms should be apparent)]
-
-7. ./testio [for both, no latency]
-Latency in ms: >>0
-enter your choice... >>5
-Type input number: >>6 [pick a working input device]
-Type output number: >>2 [pick a working output device]
-[play notes on input, hear them on output]
-
-8. ./testio [for both, latency > 0]
-Latency in ms: >>300
-enter your choice... >>5
-Type input number: >>6 [pick a working input device]
-Type output number: >>2 [pick a working output device]
-[play notes on input, hear them on output (delay of 300ms is apparent)]
-
-9. ./testio [stream test]
-Latency in ms: >>0 [does not matter]
-enter your choice... >>6
-Type output number: >>2 [pick a working output device]
->> [type ENTER to start]
-[hear 4 notes: C D E F# at one note per second, then all turn off]
-ready to close and terminate... (type ENTER) :>> [type ENTER (twice)]
-
-10. ./testio [isochronous out]
-Latency in ms: >>300
-enter your choice... >>7
-Type output number: >>2 [pick a working output device]
-ready to send program 1 change... (type ENTER): >> [type ENTER]
-[hear 80 notes, exactly 4 notes per second, no jitter]
-
-11. ./latency [no MIDI, histogram]
-Choose timer period (in ms, >= 1): >>1
-? >>1 [No MIDI traffic option]
-[wait about 10 seconds]
->> [type ENTER]
-[output should be something like ... Maximum latency: 1 milliseconds]
-
-12. ./latency [MIDI input, histogram]
-Choose timer period (in ms, >= 1): >>1
-? >>2 [MIDI input option]
-Midi input device number: >>6 [pick a working input device]
-[wait about 5 seconds, play input for 10 seconds ]
->> [type ENTER]
-[output should be something like ... Maximum latency: 3 milliseconds]
-
-13. ./latency [MIDI output, histogram]
-Choose timer period (in ms, >= 1): >>1
-? >>3 [MIDI output option]
-Midi output device number: >>2 [pick a working output device]
-Midi output should be sent every __ callback iterations: >>50
-[wait until you hear notes for 5 or 10 seconds]
->> [type ENTER to stop]
-[output should be something like ... Maximum latency: 2 milliseconds]
-
-14. ./latency [MIDI input and output, histogram]
-Choose timer period (in ms, >= 1): >>1
-? >>4 [MIDI input and output option]
-Midi input device number: >>6 [pick a working input device]
-Midi output device number: >>2 [pick a working output device]
-Midi output should be sent every __ callback iterations: >>50
-[wait until you hear notes, simultaneously play notes for 5 or 10 seconds]
->> [type ENTER to stop]
-[output should be something like ... Maximum latency: 1 milliseconds]
-
-15. ./mm [test with device input]
-Type input device number: >>6 [pick a working input device]
-[play some notes, see notes printed]
->>q [Type q ENTER when finished to exit]
-
-16. ./midithread -i 6 -o 2 [use working input/output device numbers]
->>5 [enter a transposition number]
-[play some notes, hear parallel 4ths]
->>q [quit after ENTER a couple of times]
-
-17. ./midiclock [in one shell]
- ./mm [in another shell]
-[Goal is send clock messages to MIDI monitor program. This requires
- either a hardware loopback (MIDI cable from OUT to IN on interface)
- or a software loopback (macOS IAC bus or ALSA MIDI Through Port)]
-[For midiclock application:]
- Type output device number: >>0 [pick a device with loopback]
- Type ENTER to start MIDI CLOCK: >> [type ENTER]
-[For mm application:]
- Type input device number: >>1 [pick device with loopback]
- [Wait a few seconds]
- >>s [to get Clock Count]
- >>s [expect to get a higher Clock Count]
-[For midiclock application:]
- >>c [turn off clocks]
-[For mm application:]
- >>s [to get Clock Count]
- >>s [expect to Clock Count stays the same]
-[For midiclock application:]
- >>t [turn on time code, see Time Code Quarter Frame messages from mm]
- >>q [to quit]
-[For mm application:]
- >>q [to quit]
-
-18. ./midithru -i 6 -o 2 [use working input/output device numbers]
-[Play notes on input evice; notes are sent immediately and also with a
- 2 sec delay to the output device; program terminates in 60 seconds or
- when you play B3 (B below Middle C)]
->> [ENTER to exit]
-
-19. ./recvvirtual -h [in one shell, macOS and Linux only]
- ./recvvirtual -m vvv [for mac, or -c vvv -p vvvport for linux]
- ./testio [in another shell]
-[For testio application:]
- Latency in ms: >>0
- enter your choice... >>4 [test output]
- Type output number: >>9 [select the "portmidi (output)" device]
- [type ENTER to each prompt, see that recvvirtual "Got message 0"
- through "Got message 9"]
- >> [ENTER to quit]
-[For recvvirtual application:]
- >> [ENTER to quit]
-
-20. ./sendvirtual -h [in one shell, macOS and Linux only]
- ./sendvirtual -m vvv [for mac, or -c vvv -p vvvport for linux]
- ./mm [in another shell]
-[For mm application:]
- Type input device number: >>10 [select the "portmidi" device]
-[For sendvirtual application:]
- Type ENTER to send messages: >> [type ENTER]
- [see NoteOn and off messages received by mm for Key 60-64]
- >> [ENTER to quit]
-[For mm application:]
- >>q [and ENTER twice to quit]
-
-21. ./sysex [no latency]
-[This requires either a hardware loopback (MIDI cable from OUT to IN
- on interface) or a software loopback (macOS IAC bus or ALSA MIDI
- Through Port)]
->>l [for loopback test]
-Type output device number: >>0 [pick output device to loopback]
-Latency in milliseconds: >>0
-Type input device number: >>0 [pick input device for loopback]
-[Program will send 100,000 bytes. After awhile, program will quit.
- You can read the Cummulative bytes/sec value.]
-
-22. ./sysex [latency > 0]
-[This requires either a hardware loopback (MIDI cable from OUT to IN
- on interface) or a software loopback (macOS IAC bus or ALSA MIDI
- Through Port)]
->>l [for loopback test]
-Type output device number: >>0 [pick output device to loopback]
-Latency in milliseconds: >>100
-Type input device number: >>0 [pick input device for loopback]
-[Program will send 100,000 bytes. After awhile, program will quit. You
- can read the Cummulative bytes/sec value; it is affected by latency.]
-
-23. ./fast [no latency]
- ./fastrcv [in another shell]
-[This is a speed check, especially for macOSX IAC bus connections,
- which are known to drop messages if you send messages too fast.
- fast and fastrcv must use a loopback to function.]
-[In fastrcv:]
- Input device number: >>1 [pick a non-hardware device if possible]
-[In fast:]
- Latency in ms: >>0
- Rate in messages per second: >>10000
- Duration in seconds: >>10
- Output device number: >>0 [pick a non-hardware device if possible]
- sending output...
-[see message counts and times; on Linux you should get about 10000
- messages/s; on macOS you should get about 1800 messages/s; Windows
- does not have software ports, so data rate might be limited by the
- loopback device you use.]
-
-Check output of fastrcv: there should be no errors, just msg/sec.]
-
-24. ./fast [latency > 0]
- ./fastrcv [in another shell]
-[This is a speed check, especially for macOSX IAC bus connections,
- which are known to drop messages if you send messages too fast.
- fast and fastrcv must use a loopback to function.]
-[In fastrcv:]
- Input device number: >>1 [pick a non-hardware device if possible]
-[In fast:]
- Latency in ms: >>30 [Note for ALSA, use latency * msgs/ms < 400]
- Rate in messages per second: >>10000
- Duration in seconds: >>10
- Output device number: >>0 [pick a non-hardware device if possible]
- sending output...
-[see message counts and times; on Linux you should get about 10000
- messages/s; on macOS you should get about 1800 messages/s; Windows
- does not have software ports, so data rate might be limited by the
- loopback device you use.]
-
-Check output of fastrcv: there should be no errors, just msg/sec.]
-
-25. ./fast [virtual output port, latency = 0, macOS and Linux only]
- ./fastrcv [in another shell]
-[Start fast first:]
- Latency in ms: >>0
- Rate in messages per second: >>10000
- Duration in seconds: >>10
- Output device number: >>9 [enter number listed for "Create virtual
- port named 'fast' (output)"]
- Pausing so you can connect a receiver to the newly created
- "fast" port. Type ENTER to proceed:
-[In fastrcv:]
- Input device number: >>3 [pick the device named "fast (input)"]
-[In fast:]
- >> [type ENTER to start]
-[see message counts and times as above ]
-
-Check output of fastrcv: there should be no errors, just msg/sec.]
-
-26. ./fast [virtual output port, latency > 0, macOS and Linux only]
- ./fastrcv [in another shell]
-[Start fast first:]
- Latency in ms: >>30 [Note for ALSA, use latency * msgs/ms < 400]
- Rate in messages per second: >>10000
- Duration in seconds: >>10
- Output device number: >>9 [enter number listed for "Create virtual
- port named 'fast' (output)"]
- Pausing so you can connect a receiver to the newly created
- "fast" port. Type ENTER to proceed:
-[In fastrcv:]
- Input device number: >>3 [pick the device named "fast (input)"]
-[In fast:]
- >> [type ENTER to start]
-[see message counts and times as above ]
-
-Check output of fastrcv: there should be no errors, just msg/sec.]
-
-27. ./fast [latency = 0, macOS and Linux only]
- ./fastrcv [virtual input port, in another shell]
-[In fastrcv:]
- Input device number: >>8 [enter number listed for "Create virtual
- port named 'fastrcv' (input)"]
-[In fast:]
- Latency in ms: >>0
- Rate in messages per second: >>10000
- Duration in seconds: >>10
- Output device number: >>7 [pick the device named "fastrcv (output)"]
- sending output...
-[see message counts and times as above ]
-
-Check output of fastrcv: there should be no errors, just msg/sec.]
-
-28. ./fast [latency > 0, macOS and Linux only]
- ./fastrcv [virtual input port, in another shell]
-[In fastrcv:]
- Input device number: >>8 [enter number listed for "Create virtual
- port named 'fastrcv' (input)"]
-[In fast:]
- Latency in ms: >>30 [Note for ALSA, use latency * msgs/ms < 400]
- Rate in messages per second: >>10000
- Duration in seconds: >>10
- Output device number: >>7 [pick the device named "fastrcv (output)"]
- sending output...
-[see message counts and times as above ]
-
-Check output of fastrcv: there should be no errors, just msg/sec.]
-
-29. ./midithru -v -n [virtual input and output, macOS and Linux only]
- ./fast [latency = 0]
- ./fastrcv [in another shell]
-[Start midithru first, it will run for 60 seconds]
-[In fastrcv:]
- Input device number: >>3 [pick the device named
- port named "midithru (input)"]
-[In fast:]
- Latency in ms: >>0
- Rate in messages per second: >>10000
- Duration in seconds: >>10
- Output device number: >>8 [pick the device named "midithru (output)"]
- sending output...
-[see message counts and times as above, on Mac, output from fast to
- midithru AND output from midithru to fastrcv are rate limited, so
- as in other tests, it will take more than 10s to receive all the
- messages and the receiving message rate will be about 1800 messages/second]
-
-30. ./multivirtual [macOS and Linux only]
- ./testio
- ./testio
-[Start multivirtual first]
-[In first testio:]
- Latency in ms: >>0
- enter your choice... >>5 [test both]
- Type input number: >>1 [pick portmidi1 (input)
- Type output number: >>4 [pick portmidi1 (output)
-[In second testio:]
- Latency in ms: >>10
- enter your choice... >>5 [test both]
- Type input number: >>2 [pick portmidi2 (input)
- Type output number: >>5 [pick portmidi2 (output)
-[In multivirtual:]
- Type ENTER to send messages: >> [type ENTER to start]
-[see that each testio gets 11 messages (0 to 10) at reasonable times
- (e.g. 2077 to 7580, and the "@" times (real times) should match the
- timestamps). multivirtual should also report reasonable times and
- line near the end of output should be "Got 11 messages from
- portmidi1 and 11 from portmidi2; expected 11."]
-
-31. ./multivirtual [macOS and Linux only]
- ./multivirtual
-[Second instance should report "PortMidi call failed...
- PortMidi: Cannot create virtual device: name is taken"]
-
-32. pmlist
- ./pmlist [check the output]
- [plug in or remove a device]
- >> [type RETURN]
- [check for changes in device list]
- >>q
-
-
-
-
diff --git a/portmidi/pm_test/fast.c b/portmidi/pm_test/fast.c
deleted file mode 100644
index 102697e..0000000
--- a/portmidi/pm_test/fast.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/* fast.c -- send many MIDI messages very fast.
- *
- * This is a stress test created to explore reports of
- * pm_write() call blocking (forever) on Linux when
- * sending very dense MIDI sequences.
- *
- * Modified 8 Aug 2017 with -n to send expired timestamps
- * to test a theory about why Linux ALSA hangs in Audacity.
- *
- * Modified 9 Aug 2017 with -m, -p to test when timestamps are
- * wrapping from negative to positive or positive to negative.
- *
- * Roger B. Dannenberg, Aug 2017
- */
-
-#include "portmidi.h"
-#include "porttime.h"
-#include "stdlib.h"
-#include "stdio.h"
-#include "string.h"
-#include "assert.h"
-
-#define DEVICE_INFO NULL
-#define DRIVER_INFO NULL
-#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
-
-#define STRING_MAX 80 /* used for console input */
-// need to get declaration for Sleep()
-#ifdef WIN32
-#include "windows.h"
-#else
-#include <unistd.h>
-#define Sleep(n) usleep(n * 1000)
-#endif
-
-
-int32_t latency = 0;
-int32_t msgrate = 0;
-int deviceno = -9999;
-int duration = 0;
-int expired_timestamps = FALSE;
-int use_timeoffset = 0;
-
-/* read a number from console */
-/**/
-int get_number(const char *prompt)
-{
- int n = 0, i;
- fputs(prompt, stdout);
- while (n != 1) {
- n = scanf("%d", &i);
- while (getchar() != '\n') ;
- }
- return i;
-}
-
-
-/* get_time -- the time reference. Normally, this will be the default
- * time, Pt_Time(), but if you use the -p or -m option, the time
- * reference will start at an offset of -10s for -m, or
- * maximum_time - 10s for -p, so that we can observe what happens
- * with negative time or when time changes sign or wraps (by
- * generating output for more than 10s).
- */
-PmTimestamp get_time(void *info)
-{
- PmTimestamp now = (PmTimestamp) (Pt_Time() + use_timeoffset);
- return now;
-}
-
-
-void fast_test()
-{
- PmStream *midi;
- char line[STRING_MAX];
- int pause = FALSE; /* pause if this is a virtual output port */
- PmError err = pmNoError;
- /* output buffer size should be a little more than
- msgrate * latency / 1000. PortMidi will guarantee
- a minimum of latency / 2 */
- int buffer_size = msgrate * latency / 900;
- PmTimestamp start, now;
- int msgcnt = 0;
- int polling_count = 0;
- int pitch = 60;
- int printtime = 1000;
-
- /* It is recommended to start timer before PortMidi */
- TIME_START;
-
- /* open output device */
- if (deviceno == Pm_CountDevices()) {
- deviceno = Pm_CreateVirtualOutput("fast", NULL, DEVICE_INFO);
- if (deviceno >= 0) {
- err = Pm_OpenOutput(&midi, deviceno, DRIVER_INFO, buffer_size,
- get_time, NULL, latency);
- pause = TRUE;
- }
- } else if (err >= pmNoError) {
- err = Pm_OpenOutput(&midi, deviceno, DRIVER_INFO, buffer_size,
- get_time, NULL, latency);
- }
- if (err == pmHostError) {
- Pm_GetHostErrorText(line, STRING_MAX);
- printf("PortMidi found host error...\n %s\n", line);
- goto done;
- } else if (err < 0) {
- printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err));
- goto done;
- }
- printf("Midi Output opened with %ld ms latency.\n", (long) latency);
- if (pause) {
- printf("Pausing so you can connect a receiver to the newly created\n"
- " \"fast\" port. Type ENTER to proceed: ");
- while (getchar() != '\n') ;
- }
- /* wait a sec after printing previous line */
- start = get_time(NULL) + 1000;
- while (start > get_time(NULL)) {
- Sleep(10);
- }
- printf("sending output...\n");
- fflush(stdout); /* make sure message goes to console */
-
- /* every 10ms send on/off pairs at timestamps set to current time */
- now = get_time(NULL);
- /* if expired_timestamps, we want to send timestamps that have
- * expired. They should be sent immediately, but there's a suggestion
- * that negative delay might cause problems in the ALSA implementation
- * so this is something we can test using the -n flag.
- */
- if (expired_timestamps) {
- now = now - 2 * latency;
- }
-
- while (((PmTimestamp) (now - start)) < duration * 1000 || pitch != 60) {
- /* how many messages do we send? Total should be
- * (elapsed * rate) / 1000
- */
- int send_total = (((PmTimestamp) ((now - start))) * msgrate) / 1000;
- /* always send until pitch would be 60 so if we run again, the
- next pitch (60) will be expected */
- if (msgcnt < send_total) {
- if ((msgcnt & 1) == 0) {
- Pm_WriteShort(midi, now, Pm_Message(0x90, pitch, 100));
- } else {
- Pm_WriteShort(midi, now, Pm_Message(0x90, pitch, 0));
- /* play 60, 61, 62, ... 71, then wrap back to 60, 61, ... */
- pitch = (pitch - 59) % 12 + 60;
- }
- msgcnt += 1;
- if (((PmTimestamp) (now - start)) >= printtime) {
- printf("%d at %dms, polling count %d\n", msgcnt, now - start,
- polling_count);
- fflush(stdout); /* make sure message goes to console */
- printtime += 1000; /* next msg in 1s */
- }
- }
- now = get_time(NULL);
- polling_count++;
- }
- /* close device (this not explicitly needed in most implementations) */
- printf("ready to close and terminate... (type RETURN):");
- while (getchar() != '\n') ;
-
- Pm_Close(midi);
- done:
- Pm_Terminate();
- printf("done closing and terminating...\n");
-}
-
-
-void show_usage()
-{
- printf("Usage: fast [-h] [-l latency] [-r rate] [-d device] [-s dur] "
- "[-n] [-p] [-m]\n"
- ", where latency is in ms,\n"
- " rate is messages per second,\n"
- " device is the PortMidi device number,\n"
- " dur is the length of the test in seconds,\n"
- " -n means send timestamps in the past,\n"
- " -p means use a large positive time offset,\n"
- " -m means use a large negative time offset, and\n"
- " -h means help.\n");
-}
-
-int main(int argc, char *argv[])
-{
- int default_in;
- int default_out;
- char *deflt;
- int i = 0;
- int latency_valid = FALSE;
- int rate_valid = FALSE;
- int device_valid = FALSE;
- int dur_valid = FALSE;
-
- if (sizeof(void *) == 8)
- printf("Apparently this is a 64-bit machine.\n");
- else if (sizeof(void *) == 4)
- printf ("Apparently this is a 32-bit machine.\n");
-
- if (argc <= 1) {
- show_usage();
- } else {
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-h") == 0) {
- show_usage();
- } else if (strcmp(argv[i], "-l") == 0 && (i + 1 < argc)) {
- i = i + 1;
- latency = atoi(argv[i]);
- printf("Latency will be %ld\n", (long) latency);
- latency_valid = TRUE;
- } else if (strcmp(argv[i], "-r") == 0) {
- i = i + 1;
- msgrate = atoi(argv[i]);
- printf("Rate will be %d messages/second\n", msgrate);
- rate_valid = TRUE;
- } else if (strcmp(argv[i], "-d") == 0) {
- i = i + 1;
- deviceno = atoi(argv[i]);
- printf("Device will be %d\n", deviceno);
- } else if (strcmp(argv[i], "-s") == 0) {
- i = i + 1;
- duration = atoi(argv[i]);
- printf("Duration will be %d seconds\n", duration);
- dur_valid = TRUE;
- } else if (strcmp(argv[i], "-n") == 0) {
- printf("Sending expired timestamps (-n)\n");
- expired_timestamps = TRUE;
- } else if (strcmp(argv[i], "-p") == 0) {
- printf("Time offset set to 2147473648 (-p)\n");
- use_timeoffset = 2147473648;
- } else if (strcmp(argv[i], "-m") == 0) {
- printf("Time offset set to -10000 (-m)\n");
- use_timeoffset = -10000;
- } else {
- show_usage();
- }
- }
- }
-
- if (!latency_valid) {
- // coerce to known size
- latency = (int32_t) get_number("Latency in ms: ");
- }
-
- if (!rate_valid) {
- // coerce from "%d" to known size
- msgrate = (int32_t) get_number("Rate in messages per second: ");
- }
-
- if (!dur_valid) {
- duration = get_number("Duration in seconds: ");
- }
-
- /* list device information */
- default_in = Pm_GetDefaultInputDeviceID();
- default_out = Pm_GetDefaultOutputDeviceID();
- for (i = 0; i < Pm_CountDevices(); i++) {
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (info->output) {
- printf("%d: %s, %s", i, info->interf, info->name);
- if (i == deviceno) {
- device_valid = TRUE;
- deflt = "selected ";
- } else if (i == default_out) {
- deflt = "default ";
- } else {
- deflt = "";
- }
- printf(" (%soutput)\n", deflt);
- }
- }
- printf("%d: Create virtual port named \"fast\"", i);
- if (i == deviceno) {
- device_valid = TRUE;
- deflt = "selected ";
- } else {
- deflt = "";
- }
- printf(" (%soutput)\n", deflt);
-
- if (!device_valid) {
- deviceno = get_number("Output device number: ");
- }
-
- fast_test();
- return 0;
-}
diff --git a/portmidi/pm_test/fastrcv.c b/portmidi/pm_test/fastrcv.c
deleted file mode 100644
index dabf9fa..0000000
--- a/portmidi/pm_test/fastrcv.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* fastrcv.c -- send many MIDI messages very fast.
- *
- * This is a stress test created to explore reports of
- * pm_write() call blocking (forever) on Linux when
- * sending very dense MIDI sequences.
- *
- * Modified 8 Aug 2017 with -n to send expired timestamps
- * to test a theory about why Linux ALSA hangs in Audacity.
- *
- * Roger B. Dannenberg, Aug 2017
- */
-
-#include "portmidi.h"
-#include "porttime.h"
-#include "stdlib.h"
-#include "stdio.h"
-#include "string.h"
-#include "assert.h"
-
-#define INPUT_BUFFER_SIZE 1000 /* big to avoid losing any input */
-#define DEVICE_INFO NULL
-#define DRIVER_INFO NULL
-#define TIME_PROC ((PmTimeProcPtr) Pt_Time)
-#define TIME_INFO NULL
-#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
-
-#define STRING_MAX 80 /* used for console input */
-// need to get declaration for Sleep()
-#ifdef WIN32
-#include "windows.h"
-#else
-#include <unistd.h>
-#define Sleep(n) usleep(n * 1000)
-#endif
-
-
-int deviceno = -9999;
-int verbose = FALSE;
-
-
-static void prompt_and_exit(void)
-{
- printf("type ENTER...");
- while (getchar() != '\n') ;
- /* this will clean up open ports: */
- exit(-1);
-}
-
-
-static PmError checkerror(PmError err)
-{
- if (err == pmHostError) {
- /* it seems pointless to allocate memory and copy the string,
- * so I will do the work of Pm_GetHostErrorText directly
- */
- char errmsg[80];
- Pm_GetHostErrorText(errmsg, 80);
- printf("PortMidi found host error...\n %s\n", errmsg);
- prompt_and_exit();
- } else if (err < 0) {
- printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err));
- prompt_and_exit();
- }
- return err;
-}
-
-
-/* read a number from console */
-/**/
-int get_number(const char *prompt)
-{
- int n = 0, i;
- fputs(prompt, stdout);
- while (n != 1) {
- n = scanf("%d", &i);
- while (getchar() != '\n') ;
- }
- return i;
-}
-
-
-void fastrcv_test()
-{
- PmStream * midi;
- PmError status, length;
- PmEvent buffer[1];
- PmTimestamp start;
- /* every 10ms read all messages, keep counts */
- /* every 1000ms, print report */
- int msgcnt = 0;
- /* expect repeating sequence of 60 through 71, alternating on/off */
- int expected_pitch = 60;
- int expected_on = TRUE;
- int report_time;
- PmTimestamp last_timestamp = -1;
- PmTimestamp last_delta = -1;
-
- /* It is recommended to start timer before PortMidi */
- TIME_START;
-
- /* open output device */
- if (deviceno == Pm_CountDevices()) {
- int id = Pm_CreateVirtualInput("fastrcv", NULL, DEVICE_INFO);
- if (id < 0) checkerror(id); /* error reporting */
- checkerror(Pm_OpenInput(&midi, id, DRIVER_INFO,
- INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO));
- } else {
- Pm_OpenInput(&midi, deviceno, DRIVER_INFO, INPUT_BUFFER_SIZE,
- TIME_PROC, TIME_INFO);
- }
- printf("Midi Input opened.\n");
-
- /* wait a sec after printing previous line */
- start = Pt_Time() + 1000;
- while (start > Pt_Time()) {
- Sleep(10);
- }
-
- report_time = Pt_Time() + 1000; /* report every 1s */
- while (TRUE) {
- PmTimestamp now = Pt_Time();
- status = Pm_Poll(midi);
- if (status == TRUE) {
- length = Pm_Read(midi, buffer, 1);
- if (length > 0) {
- int status = Pm_MessageStatus(buffer[0].message);
- if (status == 0x80) { /* convert NoteOff to NoteOn, vel=0 */
- status = 0x90;
- buffer[0].message = Pm_Message(status,
- Pm_MessageData1(buffer[0].message), 0);
- }
- /* only listen to NOTEON messages */
- if (status == 0x90) {
- int pitch = Pm_MessageData1(buffer[0].message);
- int vel = Pm_MessageData2(buffer[0].message);
- int is_on = (vel > 0);
- if (verbose) {
- printf("Note pitch %d vel %d\n", pitch, vel);
- }
- msgcnt++;
- if (pitch != expected_pitch || expected_on != is_on) {
- printf("Unexpected note-on: pitch %d vel %d, "
- "expected: pitch %d Note%s\n", pitch, vel,
- expected_pitch, (expected_on ? "On" : "Off"));
- }
- if (is_on) {
- expected_on = FALSE;
- expected_pitch = pitch;
- } else {
- expected_on = TRUE;
- expected_pitch = (pitch + 1) % 72;
- if (expected_pitch < 60) expected_pitch = 60;
- }
- if (last_timestamp >= 0) {
- last_delta = buffer[0].timestamp - last_timestamp;
- }
- last_timestamp = buffer[0].timestamp;
- }
- }
- }
- if (now >= report_time) {
- printf("%d msgs/sec", msgcnt);
- /* if available, print the last timestamp and last delta time */
- if (last_timestamp >= 0) {
- printf(" last timestamp %d", (int) last_timestamp);
- last_timestamp = -1;
- }
- if (last_delta >= 0) {
- printf(" last delta time %d", (int) last_delta);
- last_delta = -1;
- }
- printf("\n");
- report_time += 1000;
- msgcnt = 0;
- }
- }
-}
-
-
-void show_usage()
-{
- printf("Usage: fastrcv [-h] [-v] [-d device], where\n"
- "device is the PortMidi device number,\n"
- "-h means help,\n"
- "-v means verbose (print messages)\n");
-}
-
-int main(int argc, char *argv[])
-{
- int default_in;
- int default_out;
- char *deflt;
-
- int i = 0;
- int test_input = 0, test_output = 0, test_both = 0;
- int stream_test = 0;
- int device_valid = FALSE;
-
- if (sizeof(void *) == 8)
- printf("Apparently this is a 64-bit machine.\n");
- else if (sizeof(void *) == 4)
- printf ("Apparently this is a 32-bit machine.\n");
-
- if (argc <= 1) {
- show_usage();
- } else {
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-h") == 0) {
- show_usage();
- } else if (strcmp(argv[i], "-v") == 0) {
- verbose = TRUE;
- } else if (strcmp(argv[i], "-d") == 0) {
- i = i + 1;
- deviceno = atoi(argv[i]);
- printf("Device will be %d\n", deviceno);
- } else {
- show_usage();
- }
- }
- }
-
- /* list device information */
- default_in = Pm_GetDefaultInputDeviceID();
- default_out = Pm_GetDefaultOutputDeviceID();
- for (i = 0; i < Pm_CountDevices(); i++) {
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (!info->output) {
- printf("%d: %s, %s", i, info->interf, info->name);
- if (i == deviceno) {
- device_valid = TRUE;
- deflt = "selected ";
- } else if (i == default_out) {
- deflt = "default ";
- } else {
- deflt = "";
- }
- printf(" (%sinput)\n", deflt);
- }
- }
- printf("%d: Create virtual port named \"fastrcv\"", i);
- if (i == deviceno) {
- device_valid = TRUE;
- deflt = "selected ";
- } else {
- deflt = "";
- }
- printf(" (%sinput)\n", deflt);
-
- if (!device_valid) {
- deviceno = get_number("Input device number: ");
- }
-
- fastrcv_test();
- return 0;
-}
diff --git a/portmidi/pm_test/latency.c b/portmidi/pm_test/latency.c
deleted file mode 100755
index 06ea80d..0000000
--- a/portmidi/pm_test/latency.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/* latency.c -- measure latency of OS */
-
-#include "porttime.h"
-#include "portmidi.h"
-#include "stdlib.h"
-#include "stdio.h"
-#include "string.h"
-#include "assert.h"
-
-/* Latency is defined here to mean the time starting when a
- process becomes ready to run, and ending when the process
- actually runs. Latency is due to contention for the
- processor, usually due to other processes, OS activity
- including device drivers handling interrupts, and
- waiting for the scheduler to suspend the currently running
- process and activate the one that is waiting.
-
- Latency can affect PortMidi applications: if a process fails
- to wake up promptly, MIDI input may sit in the input buffer
- waiting to be handled, and MIDI output may not be generated
- with accurate timing. Using the latency parameter when
- opening a MIDI output port allows the caller to defer timing
- to PortMidi, which in most implementations will pass the
- data on to the OS. By passing timestamps and data to the
- OS kernel, device driver, or even hardware, there are fewer
- sources of latency that can affect the ultimate timing of
- the data. On the other hand, the application must generate
- and deliver the data ahead of the timestamp. The amount by
- which data is computed early must be at least as large as
- the worst-case latency to avoid timing problems.
-
- Latency is even more important in audio applications. If an
- application lets an audio output buffer underflow, an audible
- pop or click is produced. Audio input buffers can overflow,
- causing data to be lost. In general the audio buffers must
- be large enough to buffer the worst-case latency that the
- application will encounter.
-
- This program measures latency by recording the difference
- between the scheduled callback time and the current real time.
- We do not really know the scheduled callback time, so we will
- record the differences between the real time of each callback
- and the real time of the previous callback. Differences that
- are larger than the scheduled difference are recorded. Smaller
- differences indicate the system is recovering from an earlier
- latency, so these are ignored.
- Since printing by the callback process can cause all sorts of
- delays, this program records latency observations in a
- histogram. When the program is stopped, the histogram is
- printed to the console.
-
- Optionally the system can be tested under a load of MIDI input,
- MIDI output, or both. If MIDI input is selected, the callback
- thread will read any waiting MIDI events each iteration. You
- must generate events on this interface for the test to actually
- put any appreciable load on PortMidi. If MIDI output is
- selected, alternating note on and note off events are sent each
- X iterations, where you specify X. For example, with a timer
- callback period of 2ms and X=1, a MIDI event is sent every 2ms.
-
-
- INTERPRETING RESULTS: Time is quantized to 1ms, so there is
- some uncertainty due to rounding. A microsecond latency that
- spans the time when the clock is incremented will be reported
- as a latency of 1. On the other hand, a latency of almost
- 1ms that falls between two clock ticks will be reported as
- zero. In general, if the highest nonzero bin is numbered N,
- then the maximum latency is N+1.
-
-CHANGE LOG
-
-18-Jul-03 Mark Nelson -- Added code to generate MIDI or receive
- MIDI during test, and made period user-settable.
- */
-
-#define HIST_LEN 21 /* how many 1ms bins in the histogram */
-
-#define STRING_MAX 80 /* used for console input */
-
-#define INPUT_BUFFER_SIZE 100
-#define OUTPUT_BUFFER_SIZE 0
-
-#ifndef max
-#define max(a, b) ((a) > (b) ? (a) : (b))
-#endif
-#ifndef min
-#define min(a, b) ((a) <= (b) ? (a) : (b))
-#endif
-
-int get_number(const char *prompt);
-
-PtTimestamp previous_callback_time = 0;
-
-int period; /* milliseconds per callback */
-
-int histogram[HIST_LEN];
-int max_latency = 0; /* worst latency observed */
-int out_of_range = 0; /* how many points outside of HIST_LEN? */
-
-int test_in, test_out; /* test MIDI in and/or out? */
-int output_period; /* output MIDI every __ iterations if test_out true */
-int iteration = 0;
-PmStream *in, *out;
-int note_on = 0; /* is the note currently on? */
-
-/* callback function for PortTime -- computes histogram */
-void pt_callback(PtTimestamp timestamp, void *userData)
-{
- PtTimestamp difference = timestamp - previous_callback_time - period;
- previous_callback_time = timestamp;
-
- /* allow 5 seconds for the system to settle down */
- if (timestamp < 5000) return;
-
- iteration++;
- /* send a note on/off if user requested it */
- if (test_out && (iteration % output_period == 0)) {
- PmEvent buffer[1];
- buffer[0].timestamp = Pt_Time();
- if (note_on) {
- /* note off */
- buffer[0].message = Pm_Message(0x90, 60, 0);
- note_on = 0;
- } else {
- /* note on */
- buffer[0].message = Pm_Message(0x90, 60, 100);
- note_on = 1;
- }
- Pm_Write(out, buffer, 1);
- iteration = 0;
- }
-
- /* read all waiting events (if user requested) */
- if (test_in) {
- PmError status;
- PmEvent buffer[1];
- do {
- status = Pm_Poll(in);
- if (status == TRUE) {
- Pm_Read(in,buffer,1);
- }
- } while (status == TRUE);
- }
-
- if (difference < 0) return; /* ignore when system is "catching up" */
-
- /* update the histogram */
- if (difference < HIST_LEN) {
- histogram[difference]++;
- } else {
- out_of_range++;
- }
-
- if (max_latency < difference) max_latency = difference;
-}
-
-
-int main()
-{
- int i;
- int len;
- int choice;
- PtTimestamp stop;
- printf("Latency histogram.\n");
- period = 0;
- while (period < 1) {
- period = get_number("Choose timer period (in ms, >= 1): ");
- }
- printf("Benchmark with:\n\t%s\n\t%s\n\t%s\n\t%s\n",
- "1. No MIDI traffic",
- "2. MIDI input",
- "3. MIDI output",
- "4. MIDI input and output");
- choice = get_number("? ");
- switch (choice) {
- case 1: test_in = 0; test_out = 0; break;
- case 2: test_in = 1; test_out = 0; break;
- case 3: test_in = 0; test_out = 1; break;
- case 4: test_in = 1; test_out = 1; break;
- default: assert(0);
- }
- if (test_in || test_out) {
- /* list device information */
- for (i = 0; i < Pm_CountDevices(); i++) {
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if ((test_in && info->input) ||
- (test_out && info->output)) {
- printf("%d: %s, %s", i, info->interf, info->name);
- if (info->input) printf(" (input)");
- if (info->output) printf(" (output)");
- printf("\n");
- }
- }
- /* open stream(s) */
- if (test_in) {
- int i = get_number("MIDI input device number: ");
- Pm_OpenInput(&in,
- i,
- NULL,
- INPUT_BUFFER_SIZE,
- (PmTimestamp (*)(void *)) Pt_Time,
- NULL);
- /* turn on filtering; otherwise, input might overflow in the
- 5-second period before timer callback starts reading midi */
- Pm_SetFilter(in, PM_FILT_ACTIVE | PM_FILT_CLOCK);
- }
- if (test_out) {
- int i = get_number("MIDI output device number: ");
- PmEvent buffer[1];
- Pm_OpenOutput(&out,
- i,
- NULL,
- OUTPUT_BUFFER_SIZE,
- (PmTimestamp (*)(void *)) Pt_Time,
- NULL,
- 0); /* no latency scheduling */
-
- /* send a program change to force a status byte -- this fixes
- a problem with a buggy linux MidiSport driver, and shouldn't
- hurt anything else
- */
- buffer[0].timestamp = 0;
- buffer[0].message = Pm_Message(0xC0, 0, 0); /* program change */
- Pm_Write(out, buffer, 1);
-
- output_period = get_number(
- "MIDI out should be sent every __ callback iterations: ");
-
- assert(output_period >= 1);
- }
- }
-
- printf("Latency measurements will start in 5 seconds. "
- "Type return to stop: ");
- Pt_Start(period, &pt_callback, 0);
- while (getchar() != '\n') ;
- stop = Pt_Time();
- Pt_Stop();
-
- /* courteously turn off the last note, if necessary */
- if (note_on) {
- PmEvent buffer[1];
- buffer[0].timestamp = Pt_Time();
- buffer[0].message = Pm_Message(0x90, 60, 0);
- Pm_Write(out, buffer, 1);
- }
-
- /* print the histogram */
- printf("Duration of test: %g seconds\n\n", max(0, stop - 5000) * 0.001);
- printf("Latency(ms) Number of occurrences\n");
- /* avoid printing beyond last non-zero histogram entry */
- len = min(HIST_LEN, max_latency + 1);
- for (i = 0; i < len; i++) {
- printf("%2d %10d\n", i, histogram[i]);
- }
- printf("Number of points greater than %dms: %d\n",
- HIST_LEN - 1, out_of_range);
- printf("Maximum latency: %d milliseconds\n", max_latency);
- printf("\nNote that due to rounding, actual latency can be 1ms higher\n");
- printf("than the numbers reported here.\n");
- printf("Type return to exit...");
- while (getchar() != '\n') ;
-
- if(choice == 2)
- Pm_Close(in);
- else if(choice == 3)
- Pm_Close(out);
- else if(choice == 4)
- {
- Pm_Close(in);
- Pm_Close(out);
- }
- return 0;
-}
-
-
-/* read a number from console */
-int get_number(const char *prompt)
-{
- int n = 0, i;
- fputs(prompt, stdout);
- while (n != 1) {
- n = scanf("%d", &i);
- while (getchar() != '\n') ;
- }
- return i;
-}
diff --git a/portmidi/pm_test/midiclock.c b/portmidi/pm_test/midiclock.c
deleted file mode 100644
index f0a6897..0000000
--- a/portmidi/pm_test/midiclock.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/* miditime.c -- a test program that sends midi clock and MTC */
-
-#include "portmidi.h"
-#include "porttime.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-
-#ifndef false
-#define false 0
-#define true 1
-#endif
-
-#define private static
-typedef int boolean;
-
-#define MIDI_TIME_CLOCK 0xf8
-#define MIDI_START 0xfa
-#define MIDI_CONTINUE 0xfb
-#define MIDI_STOP 0xfc
-#define MIDI_Q_FRAME 0xf1
-
-#define OUTPUT_BUFFER_SIZE 0
-#define DRIVER_INFO NULL
-#define TIME_PROC ((PmTimeProcPtr) Pt_Time)
-#define TIME_INFO NULL
-#define LATENCY 0
-#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
-
-#define STRING_MAX 80 /* used for console input */
-
-/* to determine ms per clock:
- * time per beat in seconds = 60 / tempo
- * multiply by 1000 to get time per beat in ms: 60000 / tempo
- * divide by 24 CLOCKs per beat: (60000/24) / tempo
- * simplify: 2500 / tempo
- */
-#define TEMPO_TO_CLOCK 2500.0
-
-boolean done = false;
-PmStream *midi;
-/* shared flags to control callback output generation: */
-boolean clock_running = false;
-boolean send_start_stop = false;
-boolean time_code_running = false;
-boolean active = false; /* tells callback to do its thing */
-float tempo = 60.0F;
-/* protocol for handing off portmidi to callback thread:
- main owns portmidi
- main sets active = true: ownership transfers to callback
- main sets active = false: main requests ownership
- callback sees active == false, yields ownership back to main
- main waits 2ms to make sure callback has a chance to yield
- (stop making PortMidi calls), then assumes it can close
- PortMidi
- */
-
-/* timer_poll -- the timer callback function */
-/*
- * All MIDI sends take place here
- */
-void timer_poll(PtTimestamp timestamp, void *userData)
-{
- static int callback_owns_portmidi = false;
- static PmTimestamp clock_start_time = 0;
- static double next_clock_time = 0;
- /* SMPTE time */
- static int frames = 0;
- static int seconds = 0;
- static int minutes = 0;
- static int hours = 0;
- static int mtc_count = 0; /* where are we in quarter frame sequence? */
- static int smpte_start_time = 0;
- static double next_smpte_time = 0;
- #define QUARTER_FRAME_PERIOD (1.0 / 120.0) /* 30fps, 1/4 frame */
-
- if (callback_owns_portmidi && !active) {
- /* main is requesting (by setting active to false) that we shut down */
- callback_owns_portmidi = false;
- return;
- }
- if (!active) return; /* main still getting ready or it's closing down */
- callback_owns_portmidi = true; /* main is ready, we have portmidi */
- if (send_start_stop) {
- if (clock_running) {
- Pm_WriteShort(midi, 0, MIDI_STOP);
- } else {
- Pm_WriteShort(midi, 0, MIDI_START);
- clock_start_time = timestamp;
- next_clock_time = TEMPO_TO_CLOCK / tempo;
- }
- clock_running = !clock_running;
- send_start_stop = false; /* until main sets it again */
- /* note that there's a slight race condition here: main could
- set send_start_stop asynchronously, but we assume user is
- typing slower than the clock rate */
- }
- if (clock_running) {
- if ((timestamp - clock_start_time) > next_clock_time) {
- Pm_WriteShort(midi, 0, MIDI_TIME_CLOCK);
- next_clock_time += TEMPO_TO_CLOCK / tempo;
- }
- }
- if (time_code_running) {
- int data = 0; // initialization avoids compiler warning
- if ((timestamp - smpte_start_time) < next_smpte_time)
- return;
- switch (mtc_count) {
- case 0: /* frames low nibble */
- data = frames;
- break;
- case 1: /* frames high nibble */
- data = frames >> 4;
- break;
- case 2: /* frames seconds low nibble */
- data = seconds;
- break;
- case 3: /* frames seconds high nibble */
- data = seconds >> 4;
- break;
- case 4: /* frames minutes low nibble */
- data = minutes;
- break;
- case 5: /* frames minutes high nibble */
- data = minutes >> 4;
- break;
- case 6: /* hours low nibble */
- data = hours;
- break;
- case 7: /* hours high nibble */
- data = hours >> 4;
- break;
- }
- data &= 0xF; /* take only 4 bits */
- Pm_WriteShort(midi, 0,
- Pm_Message(MIDI_Q_FRAME, (mtc_count << 4) + data, 0));
- mtc_count = (mtc_count + 1) & 7; /* wrap around */
- if (mtc_count == 0) { /* update time by two frames */
- frames += 2;
- if (frames >= 30) {
- frames = 0;
- seconds++;
- if (seconds >= 60) {
- seconds = 0;
- minutes++;
- if (minutes >= 60) {
- minutes = 0;
- hours++;
- /* just let hours wrap if it gets that far */
- }
- }
- }
- }
- next_smpte_time += QUARTER_FRAME_PERIOD;
- } else { /* time_code_running is false */
- smpte_start_time = timestamp;
- /* so that when it finally starts, we'll be in sync */
- }
-}
-
-
-/* read a number from console */
-/**/
-int get_number(const char *prompt)
-{
- int n = 0, i;
- fputs(prompt, stdout);
- while (n != 1) {
- n = scanf("%d", &i);
- while (getchar() != '\n') ;
- }
- return i;
-}
-
-/****************************************************************************
-* showhelp
-* Effect: print help text
-****************************************************************************/
-
-private void showhelp()
-{
- printf("\n");
- printf("t toggles sending MIDI Time Code (MTC)\n");
- printf("c toggles sending MIDI CLOCK (initially on)\n");
- printf("m to set tempo (from 1bpm to 300bpm)\n");
- printf("q quits\n");
- printf("\n");
-}
-
-/****************************************************************************
-* doascii
-* Inputs:
-* char c: input character
-* Effect: interpret to control output
-****************************************************************************/
-
-private void doascii(char c)
-{
- if (isupper(c)) c = tolower(c);
- if (c == 'q') done = true;
- else if (c == 'c') {
- printf("%s MIDI CLOCKs\n", (clock_running ? "Stopping" : "Starting"));
- send_start_stop = true;
- } else if (c == 't') {
- printf("%s MIDI Time Code\n",
- (time_code_running ? "Stopping" : "Starting"));
- time_code_running = !time_code_running;
- } else if (c == 'm') {
- int input_tempo = get_number("Enter new tempo (bpm): ");
- if (input_tempo >= 1 && input_tempo <= 300) {
- printf("Changing tempo to %d\n", input_tempo);
- tempo = (float) input_tempo;
- } else {
- printf("Tempo range is 1 to 300, current tempo is %g bpm\n",
- tempo);
- }
- } else {
- showhelp();
- }
-}
-
-
-/* main - prompt for parameters, start processing */
-/*
- * Prompt user to type return.
- * Then send START and MIDI CLOCK for 60 beats/min.
- * Commands:
- * t - toggle sending MIDI Time Code (MTC)
- * c - toggle sending MIDI CLOCK
- * m - set tempo
- * q - quit
- */
-int main(int argc, char **argv)
-{
- int outp;
- PmError err;
- int i;
- if (argc > 1) {
- printf("Warning: command line arguments ignored\n");
- }
- showhelp();
- /* use porttime callback to send midi */
- Pt_Start(1, timer_poll, 0);
- /* list device information */
- printf("MIDI output devices:\n");
- for (i = 0; i < Pm_CountDevices(); i++) {
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (info->output) printf("%d: %s, %s\n", i, info->interf, info->name);
- }
- outp = get_number("Type output device number: ");
- err = Pm_OpenOutput(&midi, outp, DRIVER_INFO, OUTPUT_BUFFER_SIZE,
- TIME_PROC, TIME_INFO, LATENCY);
- if (err) {
- puts(Pm_GetErrorText(err));
- goto error_exit_no_device;
- }
- active = true;
-
- printf("Type ENTER to start MIDI CLOCK:\n");
- while (getchar() != '\n') ;
- send_start_stop = true; /* send START and then CLOCKs */
-
- while (!done) {
- doascii(getchar());
- while (getchar() != '\n') ;
- }
-
- active = false;
- Pt_Sleep(2); /* this is to allow callback to complete -- it's
- real time, so it's either ok and it runs on
- time, or there's no point to synchronizing
- with it */
- /* now we "own" portmidi again */
- Pm_Close(midi);
- error_exit_no_device:
- Pt_Stop();
- Pm_Terminate();
- exit(0);
-}
-
diff --git a/portmidi/pm_test/midithread.c b/portmidi/pm_test/midithread.c
deleted file mode 100755
index ea0613b..0000000
--- a/portmidi/pm_test/midithread.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/* midithread.c -- example program showing how to do midi processing
- in a preemptive thread
-
- Notes: if you handle midi I/O from your main program, there will be
- some delay before handling midi messages whenever the program is
- doing something like file I/O, graphical interface updates, etc.
-
- To handle midi with minimal delay, you should do all midi processing
- in a separate, high priority thread. A convenient way to get a high
- priority thread in windows is to use the timer callback provided by
- the PortTime library. That is what we show here.
-
- If the high priority thread writes to a file, prints to the console,
- or does just about anything other than midi processing, this may
- create delays, so all this processing should be off-loaded to the
- "main" process or thread. Communication between threads can be tricky.
- If one thread is writing at the same time the other is reading, very
- tricky race conditions can arise, causing programs to behave
- incorrectly, but only under certain timing conditions -- a terrible
- thing to debug. Advanced programmers know this as a synchronization
- problem. See any operating systems textbook for the complete story.
-
- To avoid synchronization problems, a simple, reliable approach is
- to communicate via messages. PortMidi offers a message queue as a
- datatype, and operations to insert and remove messages. Use two
- queues as follows: midi_to_main transfers messages from the midi
- thread to the main thread, and main_to_midi transfers messages from
- the main thread to the midi thread. Queues are safe for use between
- threads as long as ONE thread writes and ONE thread reads. You must
- NEVER allow two threads to write to the same queue.
-
- This program transposes incoming midi data by an amount controlled
- by the main program. To change the transposition, type an integer
- followed by return. The main program sends this via a message queue
- to the midi thread. To quit, type 'q' followed by return.
-
- The midi thread can also send a pitch to the main program on request.
- Type 'm' followed by return to wait for the next midi message and
- print the pitch.
-
- This program illustrates:
- Midi processing in a high-priority thread.
- Communication with a main process via message queues.
-
- */
-
-#include "stdio.h"
-#include "stdlib.h"
-#include "string.h"
-#include "assert.h"
-#include "portmidi.h"
-#include "pmutil.h"
-#include "porttime.h"
-
-/* if INPUT_BUFFER_SIZE is 0, PortMidi uses a default value */
-#define INPUT_BUFFER_SIZE 0
-
-#define OUTPUT_BUFFER_SIZE 100
-#define DRIVER_INFO NULL
-#define TIME_PROC NULL
-#define TIME_INFO NULL
-/* use zero latency because we want output to be immediate */
-#define LATENCY 0
-
-#define STRING_MAX 80
-
-/**********************************/
-/* DATA USED ONLY BY process_midi */
-/* (except during initialization) */
-/**********************************/
-
-int active = FALSE;
-int monitor = FALSE;
-int midi_thru = TRUE;
-
-int transpose;
-PmStream *midi_in;
-PmStream *midi_out;
-
-/****************************/
-/* END OF process_midi DATA */
-/****************************/
-
-/* shared queues */
-PmQueue *midi_to_main;
-PmQueue *main_to_midi;
-
-#define QUIT_MSG 1000
-#define MONITOR_MSG 1001
-#define THRU_MSG 1002
-
-/* timer interrupt for processing midi data */
-void process_midi(PtTimestamp timestamp, void *userData)
-{
- PmError result;
- PmEvent buffer; /* just one message at a time */
- int32_t msg;
-
- /* do nothing until initialization completes */
- if (!active)
- return;
-
- /* check for messages */
- do {
- result = Pm_Dequeue(main_to_midi, &msg);
- if (result) {
- if (msg >= -127 && msg <= 127)
- transpose = msg;
- else if (msg == QUIT_MSG) {
- /* acknowledge receipt of quit message */
- Pm_Enqueue(midi_to_main, &msg);
- active = FALSE;
- return;
- } else if (msg == MONITOR_MSG) {
- /* main has requested a pitch. monitor is a flag that
- * records the request:
- */
- monitor = TRUE;
- } else if (msg == THRU_MSG) {
- /* toggle Thru on or off */
- midi_thru = !midi_thru;
- }
- }
- } while (result);
-
- /* see if there is any midi input to process */
- do {
- result = Pm_Poll(midi_in);
- if (result) {
- int status, data1, data2;
- if (Pm_Read(midi_in, &buffer, 1) == pmBufferOverflow)
- continue;
- if (midi_thru)
- Pm_Write(midi_out, &buffer, 1);
- /* unless there was overflow, we should have a message now */
- status = Pm_MessageStatus(buffer.message);
- data1 = Pm_MessageData1(buffer.message);
- data2 = Pm_MessageData2(buffer.message);
- if ((status & 0xF0) == 0x90 ||
- (status & 0xF0) == 0x80) {
-
- /* this is a note-on or note-off, so transpose and send */
- data1 += transpose;
-
- /* keep within midi pitch range, keep proper pitch class */
- while (data1 > 127)
- data1 -= 12;
- while (data1 < 0)
- data1 += 12;
-
- /* send the message */
- buffer.message = Pm_Message(status, data1, data2);
- Pm_Write(midi_out, &buffer, 1);
-
- /* if monitor is set, send the pitch to the main thread */
- if (monitor) {
- Pm_Enqueue(midi_to_main, &data1);
- monitor = FALSE; /* only send one pitch per request */
- }
- }
- }
- } while (result);
-}
-
-void exit_with_message(char *msg)
-{
- printf("%s\n", msg);
- while (getchar() != '\n') ;
- exit(1);
-}
-
-int main(int argc, char *argv[])
-{
- int32_t n;
- const PmDeviceInfo *info;
- char line[STRING_MAX];
- int spin;
- int done = FALSE;
- int i;
- int input = -1, output = -1;
-
- printf("Usage: midithread [-i input] [-o output]\n"
- "where input and output are portmidi device numbers\n");
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-i") == 0) {
- i++;
- input = atoi(argv[i]);
- printf("Input device number: %d\n", input);
- } else if (strcmp(argv[i], "-o") == 0) {
- i++;
- output = atoi(argv[i]);
- printf("Output device number: %d\n", output);
- } else {
- return -1;
- }
- }
- printf("begin PortMidi multithread test...\n");
-
- /* note that it is safe to call PortMidi from the main thread for
- initialization and opening devices. You should not make any
- calls to PortMidi from this thread once the midi thread begins.
- to make PortMidi calls.
- */
-
- /* make the message queues */
- /* messages can be of any size and any type, but all messages in
- * a given queue must have the same size. We'll just use int32_t's
- * for our messages in this simple example
- */
- midi_to_main = Pm_QueueCreate(32, sizeof(int32_t));
- assert(midi_to_main != NULL);
- main_to_midi = Pm_QueueCreate(32, sizeof(int32_t));
- assert(main_to_midi != NULL);
-
- /* a little test of enqueue and dequeue operations. Ordinarily,
- * you would call Pm_Enqueue from one thread and Pm_Dequeue from
- * the other. Since the midi thread is not running, this is safe.
- */
- n = 1234567890;
- Pm_Enqueue(midi_to_main, &n);
- n = 987654321;
- Pm_Enqueue(midi_to_main, &n);
- Pm_Dequeue(midi_to_main, &n);
- if (n != 1234567890) {
- exit_with_message("Pm_Dequeue produced unexpected result.");
- }
- Pm_Dequeue(midi_to_main, &n);
- if(n != 987654321) {
- exit_with_message("Pm_Dequeue produced unexpected result.");
- }
-
- /* always start the timer before you start midi */
- Pt_Start(1, &process_midi, 0); /* start a timer with millisecond accuracy */
- /* the timer will call our function, process_midi() every millisecond */
-
- Pm_Initialize();
-
- output = (output < 0 ? Pm_GetDefaultOutputDeviceID() : output);
- info = Pm_GetDeviceInfo(output);
- if (info == NULL) {
- printf("Could not open output device (%d).", output);
- exit_with_message("");
- }
- printf("Opening output device %s %s\n", info->interf, info->name);
-
- /* use zero latency because we want output to be immediate */
- Pm_OpenOutput(&midi_out,
- output,
- DRIVER_INFO,
- OUTPUT_BUFFER_SIZE,
- TIME_PROC,
- TIME_INFO,
- LATENCY);
-
- input = (input < 0 ? Pm_GetDefaultInputDeviceID() : input);
- info = Pm_GetDeviceInfo(input);
- if (info == NULL) {
- printf("Could not open default input device (%d).", input);
- exit_with_message("");
- }
- printf("Opening input device %s %s\n", info->interf, info->name);
- Pm_OpenInput(&midi_in,
- input,
- DRIVER_INFO,
- INPUT_BUFFER_SIZE,
- TIME_PROC,
- TIME_INFO);
-
- active = TRUE; /* enable processing in the midi thread -- yes, this
- is a shared variable without synchronization, but
- this simple assignment is safe */
-
- printf("Enter midi input; it will be transformed as specified by...\n");
- printf("Type 'q' to quit, 'm' to monitor next pitch, t to toggle thru or\n"
- "type a number to specify transposition.\n"
- "Must terminate with [ENTER]\n");
-
- while (!done) {
- int32_t msg;
- int input;
- int len;
- if (!fgets(line, STRING_MAX, stdin)) break; /* no stdin? */
- /* remove the newline: */
- len = (int) strlen(line);
- if (len > 0) line[len - 1] = 0; /* overwrite the newline char */
- if (strcmp(line, "q") == 0) {
- msg = QUIT_MSG;
- Pm_Enqueue(main_to_midi, &msg);
- /* wait for acknowlegement */
- do {
- spin = Pm_Dequeue(midi_to_main, &msg);
- } while (spin == 0); /* spin */ ;
- done = TRUE; /* leave the command loop and wrap up */
- } else if (strcmp(line, "m") == 0) {
- msg = MONITOR_MSG;
- Pm_Enqueue(main_to_midi, &msg);
- printf("Waiting for note...\n");
- do {
- spin = Pm_Dequeue(midi_to_main, &msg);
- } while (spin == 0); /* spin */ ;
- // convert int32_t to long for safe printing
- printf("... pitch is %ld\n", (long) msg);
- } else if (strcmp(line, "t") == 0) {
- /* reading midi_thru asynchronously could give incorrect results,
- e.g. if you type "t" twice before the midi thread responds to
- the first one, but we'll do it this way anyway. Perhaps a more
- correct way would be to wait for an acknowledgement message
- containing the new state. */
- printf("Setting THRU %s\n", (midi_thru ? "off" : "on"));
- msg = THRU_MSG;
- Pm_Enqueue(main_to_midi, &msg);
- } else if (sscanf(line, "%d", &input) == 1) {
- if (input >= -127 && input <= 127) {
- /* send transposition value, make sur */
- printf("Transposing by %d\n", input);
- msg = (int32_t) input;
- Pm_Enqueue(main_to_midi, &msg);
- } else {
- printf("Transposition must be within -127...127\n");
- }
- } else {
- printf("%s\n%s\n",
- "Type 'q[ENTER]' to quit, 'm[ENTER]' to monitor next pitch, or",
- "enter a number to specify transposition.");
- }
- }
-
- /* at this point, midi thread is inactive and we need to shut down
- * the midi input and output
- */
- Pt_Stop(); /* stop the timer */
- Pm_QueueDestroy(midi_to_main);
- Pm_QueueDestroy(main_to_midi);
-
- /* Belinda! if close fails here, some memory is deleted, right??? */
- Pm_Close(midi_in);
- Pm_Close(midi_out);
-
- fputs("finished portMidi multithread test.\n"
- "type ENTER to quit:", stdout);
- while (getchar() != '\n') ;
- return 0;
-}
diff --git a/portmidi/pm_test/midithru.c b/portmidi/pm_test/midithru.c
deleted file mode 100755
index 94b4f13..0000000
--- a/portmidi/pm_test/midithru.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/* midithru.c -- example program implementing background thru processing */
-
-/* suppose you want low-latency midi-thru processing, but your
- application wants to take advantage of the input buffer and
- timestamped data so that it does not have to operate with very low
- latency.
-
- This program illustrates how to use a timer callback from PortTime
- to implement a low-latency process that handles midi thru,
- including correctly merging midi data from the application with
- midi data from the input port.
-
- The main application, which runs in the main program thread, will
- use an interface similar to that of PortMidi, but since PortMidi
- does not allow concurrent threads to share access to a stream, the
- application will call private methods that transfer MIDI messages
- to and from the timer thread using lock-free queues. All PortMidi
- API calls are made from the timer thread.
- */
-
-/* DESIGN
-
-All setup will be done by the main thread. Then, all direct access to
-PortMidi will be handed off to the timer callback thread.
-
-After this hand-off, the main thread will get/send messages via a queue.
-
-The goal is to send incoming messages to the midi output while merging
-any midi data generated by the application. Sysex is a problem here
-because you cannot insert (merge) a midi message while a sysex is in
-progress. There are at least three ways to implement midi thru with
-sysex messages:
-
-1) Turn them off. If your application does not need them, turn them off
- with Pm_SetFilter(midi_in, PM_FILT_ACTIVE | PM_FILT_SYSEX). You will
- not receive sysex (or active sensing messages), so you will not have
- to handle them.
-
-2) Make them atomic. As you receive sysex messages, copy the data into
- a (big) buffer. Ideally, expand the buffer as needed -- sysex messages
- do not have any maximum length. Even more ideally, use a list structure
- and real-time memory allocation to avoid latency in the timer thread.
- When a full sysex message is received, send it to the midi output all
- at once.
-
-3) Process sysex incrementally. Send sysex data to midi output as it
- arrives. Block any non-real-time messages from the application until
- the sysex message completes. There is the risk that an incomplete
- sysex message will block messages forever, so implement a 5-second
- timeout: if no sysex data is seen for 5 seconds, release the block,
- possibly losing the rest of the sysex message.
-
- Application messages must be processed similarly: once started, a
- sysex message will block MIDI THRU processing. We will assume that
- the application will not abort a sysex message, so timeouts are not
- necessary here.
-
-This code implements (3).
-
-Latency is also an issue. PortMidi requires timestamps to be in
-non-decreasing order. Since we'll be operating with a low-latency
-timer thread, we can just set the latency to zero meaning timestamps
-are ignored by PortMidi. This will allow thru to go through with
-minimal latency. The application, however, needs to use timestamps
-because we assume it is high latency (the whole purpose of this
-example is to illustrate how to get low-latency thru with a high-latency
-application.) So the callback thread will implement midi timing by
-observing timestamps. The current timestamp will be available in the
-global variable current_timestamp.
-
-*/
-
-
-#include "stdio.h"
-#include "stdlib.h"
-#include "string.h"
-#include "assert.h"
-#include "portmidi.h"
-#include "pmutil.h"
-#include "porttime.h"
-
-#define MIDI_SYSEX 0xf0
-#define MIDI_EOX 0xf7
-#define STRING_MAX 80 /* used for console input */
-
-/* active is set true when midi processing should start, must be
- * volatile to force thread to check for updates by other thread */
-int active = FALSE;
-/* process_midi_exit_flag is set when the timer thread shuts down;
- * must be volatile so it is re-read in the while loop that waits on it */
-volatile int process_midi_exit_flag;
-
-PmStream *midi_in;
-PmStream *midi_out;
-
-/* shared queues */
-#define IN_QUEUE_SIZE 1024
-#define OUT_QUEUE_SIZE 1024
-PmQueue *in_queue;
-PmQueue *out_queue;
-/* this is volatile because it is set in the process_midi callback and
- * the main thread reads it to sense elapsed time. Without volatile, the
- * optimizer can put it in a register and not see the updates.
- */
-volatile PmTimestamp current_timestamp = 0;
-int thru_sysex_in_progress = FALSE;
-int app_sysex_in_progress = FALSE;
-PmTimestamp last_timestamp = 0;
-
-
-static void prompt_and_exit(void)
-{
- printf("type ENTER...");
- while (getchar() != '\n') ;
- /* this will clean up open ports: */
- exit(-1);
-}
-
-
-static PmError checkerror(PmError err)
-{
- if (err == pmHostError) {
- /* it seems pointless to allocate memory and copy the string,
- * so I will do the work of Pm_GetHostErrorText directly
- */
- char errmsg[80];
- Pm_GetHostErrorText(errmsg, 80);
- printf("PortMidi found host error...\n %s\n", errmsg);
- prompt_and_exit();
- } else if (err < 0) {
- printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err));
- prompt_and_exit();
- }
- return err;
-}
-
-
-/* time proc parameter for Pm_MidiOpen */
-PmTimestamp midithru_time_proc(void *info)
-{
- return current_timestamp;
-}
-
-
-/* timer interrupt for processing midi data.
- Incoming data is delivered to main program via in_queue.
- Outgoing data from main program is delivered via out_queue.
- Incoming data from midi_in is copied with low latency to midi_out.
- Sysex messages from either source block messages from the other.
- */
-void process_midi(PtTimestamp timestamp, void *userData)
-{
- PmError result;
- PmEvent buffer; /* just one message at a time */
-
- current_timestamp++; /* update every millisecond */
-
- /* do nothing until initialization completes */
- if (!active) {
- /* this flag signals that no more midi processing will be done */
- process_midi_exit_flag = TRUE;
- return;
- }
-
- /* see if there is any midi input to process */
- if (!app_sysex_in_progress) {
- do {
- result = Pm_Poll(midi_in);
- if (result) {
- int status;
- PmError rslt = Pm_Read(midi_in, &buffer, 1);
- if (rslt == pmBufferOverflow)
- continue;
- assert(rslt == 1);
-
- /* record timestamp of most recent data */
- last_timestamp = current_timestamp;
-
- /* the data might be the end of a sysex message that
- has timed out, in which case we must ignore it.
- It's a continuation of a sysex message if status
- is actually a data byte (high-order bit is zero). */
- status = Pm_MessageStatus(buffer.message);
- if (((status & 0x80) == 0) && !thru_sysex_in_progress) {
- continue; /* ignore this data */
- }
-
- /* implement midi thru */
- /* note that you could output to multiple ports or do other
- processing here if you wanted
- */
- /* printf("thru: %x\n", buffer.message); */
- Pm_Write(midi_out, &buffer, 1);
-
- /* send the message to the application */
- /* you might want to filter clock or active sense messages here
- to avoid sending a bunch of junk to the application even if
- you want to send it to MIDI THRU
- */
- Pm_Enqueue(in_queue, &buffer);
-
- /* sysex processing */
- if (status == MIDI_SYSEX) thru_sysex_in_progress = TRUE;
- else if ((status & 0xF8) != 0xF8) {
- /* not MIDI_SYSEX and not real-time, so */
- thru_sysex_in_progress = FALSE;
- }
- if (thru_sysex_in_progress && /* look for EOX */
- (((buffer.message & 0xFF) == MIDI_EOX) ||
- (((buffer.message >> 8) & 0xFF) == MIDI_EOX) ||
- (((buffer.message >> 16) & 0xFF) == MIDI_EOX) ||
- (((buffer.message >> 24) & 0xFF) == MIDI_EOX))) {
- thru_sysex_in_progress = FALSE;
- }
- }
- } while (result);
- }
-
-
- /* see if there is application midi data to process */
- while (!Pm_QueueEmpty(out_queue)) {
- /* see if it is time to output the next message */
- PmEvent *next = (PmEvent *) Pm_QueuePeek(out_queue);
- assert(next); /* must be non-null because queue is not empty */
- if (next->timestamp <= current_timestamp) {
- /* time to send a message, first make sure it's not blocked */
- int status = Pm_MessageStatus(next->message);
- if ((status & 0xF8) == 0xF8) {
- ; /* real-time messages are not blocked */
- } else if (thru_sysex_in_progress) {
- /* maybe sysex has timed out (output becomes unblocked) */
- if (last_timestamp + 5000 < current_timestamp) {
- thru_sysex_in_progress = FALSE;
- } else break; /* output is blocked, so exit loop */
- }
- Pm_Dequeue(out_queue, &buffer);
- Pm_Write(midi_out, &buffer, 1);
-
- /* inspect message to update app_sysex_in_progress */
- if (status == MIDI_SYSEX) app_sysex_in_progress = TRUE;
- else if ((status & 0xF8) != 0xF8) {
- /* not MIDI_SYSEX and not real-time, so */
- app_sysex_in_progress = FALSE;
- }
- if (app_sysex_in_progress && /* look for EOX */
- (((buffer.message & 0xFF) == MIDI_EOX) ||
- (((buffer.message >> 8) & 0xFF) == MIDI_EOX) ||
- (((buffer.message >> 16) & 0xFF) == MIDI_EOX) ||
- (((buffer.message >> 24) & 0xFF) == MIDI_EOX))) {
- app_sysex_in_progress = FALSE;
- }
- } else break; /* wait until indicated timestamp */
- }
-}
-
-
-void exit_with_message(char *msg)
-{
-#define STRING_MAX 80
- printf("%s\nType ENTER...", msg);
- while (getchar() != '\n') ;
- exit(1);
-}
-
-
-void initialize(int input, int output, int virtual)
-/* set up midi processing thread and open midi streams */
-{
- /* note that it is safe to call PortMidi from the main thread for
- initialization and opening devices. You should not make any
- calls to PortMidi from this thread once the midi thread begins.
- to make PortMidi calls.
- */
-
- /* note that this routine provides minimal error checking. If
- you use the PortMidi library compiled with PM_CHECK_ERRORS,
- then error messages will be printed and the program will exit
- if an error is encountered. Otherwise, you should add some
- error checking to this code.
- */
-
- const PmDeviceInfo *info;
-
- /* make the message queues */
- in_queue = Pm_QueueCreate(IN_QUEUE_SIZE, sizeof(PmEvent));
- assert(in_queue != NULL);
- out_queue = Pm_QueueCreate(OUT_QUEUE_SIZE, sizeof(PmEvent));
- assert(out_queue != NULL);
-
- /* always start the timer before you start midi */
- Pt_Start(1, &process_midi, 0); /* start a timer with millisecond accuracy */
- /* the timer will call our function, process_midi() every millisecond */
-
- Pm_Initialize();
-
- if (output < 0) {
- if (!virtual) {
- output = Pm_GetDefaultOutputDeviceID();
- }
- }
- if (output >= 0) {
- info = Pm_GetDeviceInfo(output);
- if (info == NULL) {
- printf("Could not open default output device (%d).", output);
- exit_with_message("");
- }
-
- printf("Opening output device %s %s\n", info->interf, info->name);
-
- /* use zero latency because we want output to be immediate */
- Pm_OpenOutput(&midi_out,
- output,
- NULL /* driver info */,
- OUT_QUEUE_SIZE,
- &midithru_time_proc,
- NULL /* time info */,
- 0 /* Latency */);
- } else { /* send to virtual port */
- int id;
- printf("Opening virtual output device \"midithru\"\n");
- id = Pm_CreateVirtualOutput("midithru", NULL, NULL);
- if (id < 0) checkerror(id); /* error reporting */
- checkerror(Pm_OpenOutput(&midi_out, id, NULL, OUT_QUEUE_SIZE,
- &midithru_time_proc, NULL, 0));
- }
- if (input < 0) {
- if (!virtual) {
- input = Pm_GetDefaultInputDeviceID();
- }
- }
- if (input >= 0) {
- info = Pm_GetDeviceInfo(input);
- if (info == NULL) {
- printf("Could not open default input device (%d).", input);
- exit_with_message("");
- }
-
- printf("Opening input device %s %s\n", info->interf, info->name);
- Pm_OpenInput(&midi_in,
- input,
- NULL /* driver info */,
- 0 /* use default input size */,
- &midithru_time_proc,
- NULL /* time info */);
- } else { /* receive from virtual port */
- int id;
- printf("Opening virtual input device \"midithru\"\n");
- id = Pm_CreateVirtualInput("midithru", NULL, NULL);
- if (id < 0) checkerror(id); /* error reporting */
- checkerror(Pm_OpenInput(&midi_in, id, NULL, 0,
- &midithru_time_proc, NULL));
- }
- /* Note: if you set a filter here, then this will filter what goes
- to the MIDI THRU port. You may not want to do this.
- */
- Pm_SetFilter(midi_in, PM_FILT_ACTIVE | PM_FILT_CLOCK);
-
- active = TRUE; /* enable processing in the midi thread -- yes, this
- is a shared variable without synchronization, but
- this simple assignment is safe */
-
-}
-
-
-void finalize()
-{
- /* the timer thread could be in the middle of accessing PortMidi stuff */
- /* to detect that it is done, we first clear process_midi_exit_flag and
- then wait for the timer thread to set it
- */
- process_midi_exit_flag = FALSE;
- active = FALSE;
- /* busy wait for flag from timer thread that it is done */
- while (!process_midi_exit_flag) ;
- /* at this point, midi thread is inactive and we need to shut down
- * the midi input and output
- */
- Pt_Stop(); /* stop the timer */
- Pm_QueueDestroy(in_queue);
- Pm_QueueDestroy(out_queue);
-
- Pm_Close(midi_in);
- Pm_Close(midi_out);
-
- Pm_Terminate();
-}
-
-
-int main(int argc, char *argv[])
-{
- PmTimestamp last_time = 0;
- PmEvent buffer;
- int i;
- int input = -1, output = -1;
- int virtual = FALSE;
- int delay_enable = TRUE;
-
- printf("Usage: midithru [-i input] [-o output] [-v] [-n]\n"
- "where input and output are portmidi device numbers\n"
- "if -v and input and/or output are not specified,\n"
- "then virtual ports are created and used instead.\n"
- "-n turns off the default MIDI delay effect.\n");
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-i") == 0) {
- i++;
- input = atoi(argv[i]);
- printf("Input device number: %d\n", input);
- } else if (strcmp(argv[i], "-o") == 0) {
- i++;
- output = atoi(argv[i]);
- printf("Output device number: %d\n", output);
- } else if (strcmp(argv[i], "-v") == 0) {
- virtual = TRUE;
- } else if (strcmp(argv[i], "-n") == 0) {
- delay_enable = FALSE;
- printf("delay_effect is disabled\n");
- } else {
- return -1;
- }
- }
- printf("begin PortMidi midithru program...\n");
-
- initialize(input, output, virtual); /* set up and start midi processing */
-
- printf("This program will run for 60 seconds, "
- "or until you play B below middle C,\n"
- "All input is sent immediately, implementing software MIDI THRU.\n"
- "Also, all input is echoed with a 2 second delay.\n");
-
- while (current_timestamp < 60000) {
- /* just to make the point that this is not a low-latency process,
- spin until half a second has elapsed */
- last_time = last_time + 500;
- while (last_time > current_timestamp) ;
-
- /* now read data and send it after changing timestamps */
- while (Pm_Dequeue(in_queue, &buffer) == 1) {
- /* printf("timestamp %d\n", buffer.timestamp); */
- /* printf("message %x\n", buffer.message); */
- if (delay_enable) {
- buffer.timestamp = buffer.timestamp + 2000; /* delay */
- Pm_Enqueue(out_queue, &buffer);
- }
- /* play B3 to break out of loop */
- if (Pm_MessageStatus(buffer.message) == 0x90 &&
- Pm_MessageData1(buffer.message) == 59) {
- goto quit_now;
- }
- }
- }
-quit_now:
- finalize();
- exit_with_message("finished PortMidi midithru program.");
- return 0; /* never executed, but keeps the compiler happy */
-}
diff --git a/portmidi/pm_test/mm.c b/portmidi/pm_test/mm.c
deleted file mode 100755
index ab9d32e..0000000
--- a/portmidi/pm_test/mm.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/* mm.c -- midi monitor */
-
-/*****************************************************************************
-* Change Log
-* Date | Change
-*-----------+-----------------------------------------------------------------
-* 7-Apr-86 | Created changelog
-* 31-Jan-90 | GWL : use new cmdline
-* 5-Apr-91 | JDW : Further changes
-* 16-Feb-92 | GWL : eliminate label mmexit:; add error recovery
-* 18-May-92 | GWL : continuous clocks, etc.
-* 17-Jan-94 | GWL : option to display notes
-* 20-Nov-06 | RBD : port mm.c from CMU Midi Toolkit to PortMidi
-* | mm.c -- revealing MIDI secrets for over 20 years!
-*****************************************************************************/
-
-#include "stdlib.h"
-#include "ctype.h"
-#include "string.h"
-#include "stdio.h"
-#include "porttime.h"
-#include "portmidi.h"
-
-#define STRING_MAX 80
-
-#define MIDI_CODE_MASK 0xf0
-#define MIDI_CHN_MASK 0x0f
-/*#define MIDI_REALTIME 0xf8
- #define MIDI_CHAN_MODE 0xfa */
-#define MIDI_OFF_NOTE 0x80
-#define MIDI_ON_NOTE 0x90
-#define MIDI_POLY_TOUCH 0xa0
-#define MIDI_CTRL 0xb0
-#define MIDI_CH_PROGRAM 0xc0
-#define MIDI_TOUCH 0xd0
-#define MIDI_BEND 0xe0
-
-#define MIDI_SYSEX 0xf0
-#define MIDI_Q_FRAME 0xf1
-#define MIDI_SONG_POINTER 0xf2
-#define MIDI_SONG_SELECT 0xf3
-#define MIDI_TUNE_REQ 0xf6
-#define MIDI_EOX 0xf7
-#define MIDI_TIME_CLOCK 0xf8
-#define MIDI_START 0xfa
-#define MIDI_CONTINUE 0xfb
-#define MIDI_STOP 0xfc
-#define MIDI_ACTIVE_SENSING 0xfe
-#define MIDI_SYS_RESET 0xff
-
-#define MIDI_ALL_SOUND_OFF 0x78
-#define MIDI_RESET_CONTROLLERS 0x79
-#define MIDI_LOCAL 0x7a
-#define MIDI_ALL_OFF 0x7b
-#define MIDI_OMNI_OFF 0x7c
-#define MIDI_OMNI_ON 0x7d
-#define MIDI_MONO_ON 0x7e
-#define MIDI_POLY_ON 0x7f
-
-
-#define private static
-
-#ifndef false
-#define false 0
-#define true 1
-#endif
-
-typedef int boolean;
-
-int debug = false; /* never set, but referenced by userio.c */
-PmStream *midi_in; /* midi input */
-boolean active = false; /* set when midi_in is ready for reading */
-boolean in_sysex = false; /* we are reading a sysex message */
-boolean inited = false; /* suppress printing during command line parsing */
-boolean done = false; /* when true, exit */
-boolean notes = true; /* show notes? */
-boolean controls = true; /* show continuous controllers */
-boolean bender = true; /* record pitch bend etc.? */
-boolean excldata = true; /* record system exclusive data? */
-boolean verbose = true; /* show text representation? */
-boolean realdata = true; /* record real time messages? */
-boolean clksencnt = true; /* clock and active sense count on */
-boolean chmode = true; /* show channel mode messages */
-boolean pgchanges = true; /* show program changes */
-boolean flush = false; /* flush all pending MIDI data */
-
-uint32_t filter = 0; /* remember state of midi filter */
-
-uint32_t clockcount = 0; /* count of clocks */
-uint32_t actsensecount = 0; /* cout of active sensing bytes */
-uint32_t notescount = 0; /* #notes since last request */
-uint32_t notestotal = 0; /* total #notes */
-
-char val_format[] = " Val %d\n";
-
-/*****************************************************************************
-* Imported variables
-*****************************************************************************/
-
-extern int abort_flag;
-
-/*****************************************************************************
-* Routines local to this module
-*****************************************************************************/
-
-private void mmexit(int code);
-private void output(PmMessage data);
-private int put_pitch(int p);
-private void showhelp();
-private void showbytes(PmMessage data, int len, boolean newline);
-private void showstatus(boolean flag);
-private void doascii(char c);
-private int get_number(const char *prompt);
-
-
-/* read a number from console */
-/**/
-int get_number(const char *prompt)
-{
- int n = 0, i;
- fputs(prompt, stdout);
- while (n != 1) {
- n = scanf("%d", &i);
- while (getchar() != '\n') ;
- }
- return i;
-}
-
-
-void receive_poll(PtTimestamp timestamp, void *userData)
-{
- PmEvent event;
- int count;
- if (!active) return;
- while ((count = Pm_Read(midi_in, &event, 1))) {
- if (count == 1) output(event.message);
- else puts(Pm_GetErrorText(count));
- }
-}
-
-
-/****************************************************************************
-* main
-* Effect: prompts for parameters, starts monitor
-****************************************************************************/
-
-int main(int argc, char **argv)
-{
- char *argument;
- int inp;
- PmError err;
- int i;
- if (argc > 1) { /* first arg can change defaults */
- argument = argv[1];
- while (*argument) doascii(*argument++);
- }
- showhelp();
- /* use porttime callback to empty midi queue and print */
- Pt_Start(1, receive_poll, 0);
- /* list device information */
- puts("MIDI input devices:");
- for (i = 0; i < Pm_CountDevices(); i++) {
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (info->input) printf("%d: %s, %s\n", i, info->interf, info->name);
- }
- inp = get_number("Type input device number: ");
- err = Pm_OpenInput(&midi_in, inp, NULL, 512, NULL, NULL);
- if (err) {
- puts(Pm_GetErrorText(err));
- Pt_Stop();
- mmexit(1);
- }
- Pm_SetFilter(midi_in, filter);
- inited = true; /* now can document changes, set filter */
- printf("Midi Monitor ready.\n");
- active = true;
- while (!done) {
- doascii(getchar());
- while (getchar() != '\n') ;
- }
- active = false;
- Pm_Close(midi_in);
- Pt_Stop();
- Pm_Terminate();
- mmexit(0);
- return 0; // make the compiler happy be returning a value
-}
-
-
-/****************************************************************************
-* doascii
-* Inputs:
-* char c: input character
-* Effect: interpret to revise flags
-****************************************************************************/
-
-private void doascii(char c)
-{
- if (isupper(c)) c = tolower(c);
- if (c == 'q') done = true;
- else if (c == 'b') {
- bender = !bender;
- filter ^= PM_FILT_PITCHBEND;
- if (inited)
- printf("Pitch Bend, etc. %s\n", (bender ? "ON" : "OFF"));
- } else if (c == 'c') {
- controls = !controls;
- filter ^= PM_FILT_CONTROL;
- if (inited)
- printf("Control Change %s\n", (controls ? "ON" : "OFF"));
- } else if (c == 'h') {
- pgchanges = !pgchanges;
- filter ^= PM_FILT_PROGRAM;
- if (inited)
- printf("Program Changes %s\n", (pgchanges ? "ON" : "OFF"));
- } else if (c == 'n') {
- notes = !notes;
- filter ^= PM_FILT_NOTE;
- if (inited)
- printf("Notes %s\n", (notes ? "ON" : "OFF"));
- } else if (c == 'x') {
- excldata = !excldata;
- filter ^= PM_FILT_SYSEX;
- if (inited)
- printf("System Exclusive data %s\n", (excldata ? "ON" : "OFF"));
- } else if (c == 'r') {
- realdata = !realdata;
- filter ^= (PM_FILT_PLAY | PM_FILT_RESET | PM_FILT_TICK | PM_FILT_UNDEFINED);
- if (inited)
- printf("Real Time messages %s\n", (realdata ? "ON" : "OFF"));
- } else if (c == 'k') {
- clksencnt = !clksencnt;
- if (inited) {
- printf("Clock and Active Sense Counting %s\n", (clksencnt ? "ON" : "OFF"));
- printf("Resetting Clock and Active Sense counts.\n");
- clockcount = actsensecount = 0;
- }
- } else if (c == 's') {
- if (inited) {
- printf("Clock Count %ld\nActive Sense Count %ld\n",
- (long) clockcount, (long) actsensecount);
- }
- } else if (c == 't') {
- notestotal+=notescount;
- if (inited)
- printf("This Note Count %ld\nTotal Note Count %ld\n",
- (long) notescount, (long) notestotal);
- notescount=0;
- } else if (c == 'v') {
- verbose = !verbose;
- if (inited)
- printf("Verbose %s\n", (verbose ? "ON" : "OFF"));
- } else if (c == 'm') {
- chmode = !chmode;
- if (inited)
- printf("Channel Mode Messages %s", (chmode ? "ON" : "OFF"));
- } else {
- if (inited) {
- if (c == ' ') {
- PmEvent event;
- while (Pm_Read(midi_in, &event, 1)) ; /* flush midi input */
- printf("...FLUSHED MIDI INPUT\n\n");
- } else showhelp();
- }
- }
- if (inited) Pm_SetFilter(midi_in, filter);
-}
-
-
-
-private void mmexit(int code)
-{
- /* if this is not being run from a console, maybe we should wait for
- * the user to read error messages before exiting
- */
- exit(code);
-}
-
-
-/****************************************************************************
-* output
-* Inputs:
-* data: midi message buffer holding one command or 4 bytes of sysex msg
-* Effect: format and print midi data
-****************************************************************************/
-
-char vel_format[] = " Vel %d\n";
-
-private void output(PmMessage data)
-{
- int command; /* the current command */
- int chan; /* the midi channel of the current event */
- int len; /* used to get constant field width */
-
- /* printf("output data %8x; ", data); */
-
- command = Pm_MessageStatus(data) & MIDI_CODE_MASK;
- chan = Pm_MessageStatus(data) & MIDI_CHN_MASK;
-
- if (in_sysex || Pm_MessageStatus(data) == MIDI_SYSEX) {
-#define sysex_max 16
- int i;
- PmMessage data_copy = data;
- in_sysex = true;
- /* look for MIDI_EOX in first 3 bytes
- * if realtime messages are embedded in sysex message, they will
- * be printed as if they are part of the sysex message
- */
- for (i = 0; (i < 4) && ((data_copy & 0xFF) != MIDI_EOX); i++)
- data_copy >>= 8;
- if (i < 4) {
- in_sysex = false;
- i++; /* include the EOX byte in output */
- }
- showbytes(data, i, verbose);
- if (verbose) printf("System Exclusive\n");
- } else if (command == MIDI_ON_NOTE && Pm_MessageData2(data) != 0) {
- notescount++;
- if (notes) {
- showbytes(data, 3, verbose);
- if (verbose) {
- printf("NoteOn Chan %2d Key %3d ", chan, Pm_MessageData1(data));
- len = put_pitch(Pm_MessageData1(data));
- printf(vel_format + len, Pm_MessageData2(data));
- }
- }
- } else if ((command == MIDI_ON_NOTE /* && Pm_MessageData2(data) == 0 */ ||
- command == MIDI_OFF_NOTE)) {
- if (notes) {
- showbytes(data, 3, verbose);
- if (verbose) {
- printf("NoteOff Chan %2d Key %3d ", chan,
- Pm_MessageData1(data));
- len = put_pitch(Pm_MessageData1(data));
- printf(vel_format + len, Pm_MessageData2(data));
- }
- }
- } else if (command == MIDI_CH_PROGRAM) {
- if (pgchanges) {
- showbytes(data, 2, verbose);
- if (verbose) {
- printf(" ProgChg Chan %2d Prog %2d\n", chan,
- Pm_MessageData1(data) + 1);
- }
- }
- } else if (command == MIDI_CTRL) {
- /* controls 121 (MIDI_RESET_CONTROLLER) to 127 are channel
- * mode messages. */
- if (Pm_MessageData1(data) < MIDI_ALL_SOUND_OFF) {
- if (controls) {
- showbytes(data, 3, verbose);
- if (verbose) {
- printf("CtrlChg Chan %2d Ctrl %2d Val %2d\n",
- chan, Pm_MessageData1(data), Pm_MessageData2(data));
- }
- } else /* channel mode */ if (chmode) {
- showbytes(data, 3, verbose);
- if (verbose) {
- switch (Pm_MessageData1(data)) {
- case MIDI_ALL_SOUND_OFF:
- printf("All Sound Off, Chan %2d\n", chan);
- break;
- case MIDI_RESET_CONTROLLERS:
- printf("Reset All Controllers, Chan %2d\n", chan);
- break;
- case MIDI_LOCAL:
- printf("LocCtrl Chan %2d %s\n",
- chan, Pm_MessageData2(data) ? "On" : "Off");
- break;
- case MIDI_ALL_OFF:
- printf("All Off Chan %2d\n", chan);
- break;
- case MIDI_OMNI_OFF:
- printf("OmniOff Chan %2d\n", chan);
- break;
- case MIDI_OMNI_ON:
- printf("Omni On Chan %2d\n", chan);
- break;
- case MIDI_MONO_ON:
- printf("Mono On Chan %2d\n", chan);
- if (Pm_MessageData2(data))
- printf(" to %d received channels\n",
- Pm_MessageData2(data));
- else
- printf(" to all received channels\n");
- break;
- case MIDI_POLY_ON:
- printf("Poly On Chan %2d\n", chan);
- break;
- }
- }
- }
- }
- } else if (command == MIDI_POLY_TOUCH) {
- if (bender) {
- showbytes(data, 3, verbose);
- if (verbose) {
- printf("P.Touch Chan %2d Key %2d ", chan,
- Pm_MessageData1(data));
- len = put_pitch(Pm_MessageData1(data));
- printf(val_format + len, Pm_MessageData2(data));
- }
- }
- } else if (command == MIDI_TOUCH) {
- if (bender) {
- showbytes(data, 2, verbose);
- if (verbose) {
- printf(" A.Touch Chan %2d Val %2d\n", chan,
- Pm_MessageData1(data));
- }
- }
- } else if (command == MIDI_BEND) {
- if (bender) {
- showbytes(data, 3, verbose);
- if (verbose) {
- printf("P.Bend Chan %2d Val %2d\n", chan,
- (Pm_MessageData1(data) + (Pm_MessageData2(data)<<7)));
- }
- }
- } else if (Pm_MessageStatus(data) == MIDI_SONG_POINTER) {
- showbytes(data, 3, verbose);
- if (verbose) {
- printf(" Song Position %d\n",
- (Pm_MessageData1(data) + (Pm_MessageData2(data)<<7)));
- }
- } else if (Pm_MessageStatus(data) == MIDI_SONG_SELECT) {
- showbytes(data, 2, verbose);
- if (verbose) {
- printf(" Song Select %d\n", Pm_MessageData1(data));
- }
- } else if (Pm_MessageStatus(data) == MIDI_TUNE_REQ) {
- showbytes(data, 1, verbose);
- if (verbose) {
- printf(" Tune Request\n");
- }
- } else if (Pm_MessageStatus(data) == MIDI_Q_FRAME) {
- if (realdata) {
- showbytes(data, 2, verbose);
- if (verbose) {
- printf(" Time Code Quarter Frame Type %d Values %d\n",
- (Pm_MessageData1(data) & 0x70) >> 4,
- Pm_MessageData1(data) & 0xf);
- }
- }
- } else if (Pm_MessageStatus(data) == MIDI_START) {
- if (realdata) {
- showbytes(data, 1, verbose);
- if (verbose) {
- printf(" Start\n");
- }
- }
- } else if (Pm_MessageStatus(data) == MIDI_CONTINUE) {
- if (realdata) {
- showbytes(data, 1, verbose);
- if (verbose) {
- printf(" Continue\n");
- }
- }
- } else if (Pm_MessageStatus(data) == MIDI_STOP) {
- if (realdata) {
- showbytes(data, 1, verbose);
- if (verbose) {
- printf(" Stop\n");
- }
- }
- } else if (Pm_MessageStatus(data) == MIDI_SYS_RESET) {
- if (realdata) {
- showbytes(data, 1, verbose);
- if (verbose) {
- printf(" System Reset\n");
- }
- }
- } else if (Pm_MessageStatus(data) == MIDI_TIME_CLOCK) {
- clockcount++;
- if (clksencnt) {
- showbytes(data, 1, verbose);
- if (verbose) {
- printf(" Clock\n");
- }
- }
- } else if (Pm_MessageStatus(data) == MIDI_ACTIVE_SENSING) {
- actsensecount++;
- if (clksencnt) {
- showbytes(data, 1, verbose);
- if (verbose) {
- printf(" Active Sensing\n");
- }
- }
- } else showbytes(data, 3, verbose);
- fflush(stdout);
-}
-
-
-/****************************************************************************
-* put_pitch
-* Inputs:
-* int p: pitch number
-* Effect: write out the pitch name for a given number
-****************************************************************************/
-
-private int put_pitch(int p)
-{
- char result[8];
- static char *ptos[] = {
- "c", "cs", "d", "ef", "e", "f", "fs", "g",
- "gs", "a", "bf", "b" };
- /* note octave correction below */
- sprintf(result, "%s%d", ptos[p % 12], (p / 12) - 1);
- fputs(result, stdout);
- return (int) strlen(result);
-}
-
-
-/****************************************************************************
-* showbytes
-* Effect: print hex data, precede with newline if asked
-****************************************************************************/
-
-char nib_to_hex[] = "0123456789ABCDEF";
-
-private void showbytes(PmMessage data, int len, boolean newline)
-{
- int count = 0;
- int i;
-
-/* if (newline) {
- putchar('\n');
- count++;
- } */
- for (i = 0; i < len; i++) {
- putchar(nib_to_hex[(data >> 4) & 0xF]);
- putchar(nib_to_hex[data & 0xF]);
- count += 2;
- if (count > 72) {
- putchar('.');
- putchar('.');
- putchar('.');
- break;
- }
- data >>= 8;
- }
- putchar(' ');
-}
-
-
-
-/****************************************************************************
-* showhelp
-* Effect: print help text
-****************************************************************************/
-
-private void showhelp()
-{
- printf("\n");
- printf(" Item Reported Range Item Reported Range\n");
- printf(" ------------- ----- ------------- -----\n");
- printf(" Channels 1 - 16 Programs 1 - 128\n");
- printf(" Controllers 0 - 127 After Touch 0 - 127\n");
- printf(" Loudness 0 - 127 Pitch Bend 0 - 16383, "
- "center = 8192\n");
- printf(" Pitches 0 - 127, 60 = c4 = middle C\n");
- printf(" \n");
- printf("n toggles notes");
- showstatus(notes);
- printf("t displays noteon count since last t\n");
- printf("b toggles pitch bend, aftertouch");
- showstatus(bender);
- printf("c toggles continuous control");
- showstatus(controls);
- printf("h toggles program changes");
- showstatus(pgchanges);
- printf("x toggles system exclusive");
- showstatus(excldata);
- printf("k toggles clock and sense messages, clears counts");
- showstatus(clksencnt);
- printf("r toggles other real time messages & SMPTE");
- showstatus(realdata);
- printf("s displays clock and sense count since last k\n");
- printf("m toggles channel mode messages");
- showstatus(chmode);
- printf("v toggles verbose text");
- showstatus(verbose);
- printf("q quits\n");
- printf("\n");
-}
-
-/****************************************************************************
-* showstatus
-* Effect: print status of flag
-****************************************************************************/
-
-private void showstatus(boolean flag)
-{
- printf(", now %s\n", flag ? "ON" : "OFF");
-}
diff --git a/portmidi/pm_test/multivirtual.c b/portmidi/pm_test/multivirtual.c
deleted file mode 100644
index b90d860..0000000
--- a/portmidi/pm_test/multivirtual.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/* multivirtual.c -- test for creating two input and two output virtual ports */
-/*
- * Roger B. Dannenberg
- * Oct 2021
- */
-#include "portmidi.h"
-#include "porttime.h"
-#include "stdlib.h"
-#include "stdio.h"
-#include "string.h"
-#include "assert.h"
-
-#define OUTPUT_BUFFER_SIZE 0
-#define DEVICE_INFO NULL
-#define DRIVER_INFO NULL
-#define TIME_PROC ((PmTimeProcPtr) Pt_Time)
-#define TIME_INFO NULL
-#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
-
-int latency = 0;
-
-static void prompt_and_exit(void)
-{
- printf("type ENTER...");
- while (getchar() != '\n') ;
- /* this will clean up open ports: */
- exit(-1);
-}
-
-
-static PmError checkerror(PmError err)
-{
- if (err == pmHostError) {
- /* it seems pointless to allocate memory and copy the string,
- * so I will do the work of Pm_GetHostErrorText directly
- */
- char errmsg[80];
- Pm_GetHostErrorText(errmsg, 80);
- printf("PortMidi found host error...\n %s\n", errmsg);
- prompt_and_exit();
- } else if (err < 0) {
- printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err));
- prompt_and_exit();
- }
- return err;
-}
-
-static int msg_count[2] = {0, 0};
-
-void poll_input(PmStream *in, int which)
-{
- PmEvent buffer[1];
- int pitch, expected, length;
- PmError status = Pm_Poll(in);
- if (status == TRUE) {
- length = Pm_Read(in, buffer, 1);
- if (length > 0) {
- printf("Got message %d from portmidi%d: "
- "time %ld, %2x %2x %2x\n",
- msg_count[which], which + 1, (long) buffer[0].timestamp,
- (status = Pm_MessageStatus(buffer[0].message)),
- (pitch = Pm_MessageData1(buffer[0].message)),
- Pm_MessageData2(buffer[0].message));
- if (status == 0x90) { /* 1 & 2 are on/off 60, 3 & 4 are 61, etc. */
- expected = (((msg_count[which] - 1) / 2) % 12) + 60 +
- which * 12;
- if (pitch != expected) {
- printf("WARNING: expected pitch %d, got pitch %d\n",
- expected, pitch);
- }
- }
- msg_count[which]++;
- } else {
- assert(0);
- }
- }
-}
-
-
-void wait_until(PmTimestamp when, PmStream *in1, PmStream *in2)
-{
- while (when > Pt_Time()) {
- poll_input(in1, 0);
- poll_input(in2, 1);
- Pt_Sleep(10);
- }
-}
-
-
-/* create one virtual output device and one input device */
-void init(const char *name, PmStream **midi_out, PmStream **midi_in,
- int *id_out, int *id_in)
-{
- PmEvent buffer[1];
-
- *id_out = checkerror(Pm_CreateVirtualOutput(name, NULL, DEVICE_INFO));
- checkerror(Pm_OpenOutput(midi_out, *id_out, DRIVER_INFO, OUTPUT_BUFFER_SIZE,
- TIME_PROC, TIME_INFO, latency));
- printf("Virtual Output \"%s\" id %d created and opened.\n", name, *id_out);
-
- *id_in = checkerror(Pm_CreateVirtualInput(name, NULL, DRIVER_INFO));
- checkerror(Pm_OpenInput(midi_in, *id_in, NULL, 0, NULL, NULL));
- printf("Virtual Input \"%s\" id %d created and opened.\n", name, *id_in);
- Pm_SetFilter(*midi_in, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX);
- /* empty the buffer after setting filter, just in case anything
- got through */
- while (Pm_Read(*midi_in, buffer, 1)) ;
-}
-
-
-void main_test(int num)
-{
- PmStream *midi1_out;
- PmStream *midi2_out;
- PmStream *midi1_in;
- PmStream *midi2_in;
- int id1_out;
- int id2_out;
- int id1_in;
- int id2_in;
- int32_t next_time;
- PmEvent buffer[1];
- int pitch = 60;
- int expected_count = num + 1; /* add 1 for MIDI Program message */
-
- /* It is recommended to start timer before Midi; otherwise, PortMidi may
- start the timer with its (default) parameters
- */
- TIME_START;
-
- init("portmidi1", &midi1_out, &midi1_in, &id1_out, &id1_in);
- init("portmidi2", &midi2_out, &midi2_in, &id2_out, &id2_in);
-
- printf("Type ENTER to send messages: ");
- while (getchar() != '\n') ;
-
- buffer[0].timestamp = Pt_Time();
-#define PROGRAM 0
- buffer[0].message = Pm_Message(0xC0, PROGRAM, 0);
- Pm_Write(midi1_out, buffer, 1);
- Pm_Write(midi2_out, buffer, 1);
- next_time = Pt_Time() + 1000; /* wait 1s */
- while (num > 0) {
- wait_until(next_time, midi1_in, midi2_in);
- Pm_WriteShort(midi1_out, next_time, Pm_Message(0x90, pitch, 100));
- Pm_WriteShort(midi2_out, next_time, Pm_Message(0x90, pitch + 12, 100));
- printf("Note On pitch %d\n", pitch);
- num--;
- next_time += 500;
-
- wait_until(next_time, midi1_in, midi2_in);
- Pm_WriteShort(midi1_out, next_time, Pm_Message(0x90, pitch, 0));
- Pm_WriteShort(midi2_out, next_time, Pm_Message(0x90, pitch + 12, 0));
- printf("Note Off pitch %d\n", pitch);
- num--;
- pitch = (pitch + 1) % 12 + 60;
- next_time += 500;
- }
- wait_until(next_time, midi1_in, midi2_in); /* get final note-offs */
-
- printf("Got %d messages from portmidi1 and %d from portmidi2; "
- "expected %d.\n", msg_count[0], msg_count[1], expected_count);
-
- /* close devices (this not explicitly needed in most implementations) */
- printf("ready to close...");
- checkerror(Pm_Close(midi1_out));
- checkerror(Pm_Close(midi2_out));
- checkerror(Pm_Close(midi1_in));
- checkerror(Pm_Close(midi2_in));
- printf("done closing.\nNow delete the virtual devices...");
- checkerror(Pm_DeleteVirtualDevice(id1_out));
- checkerror(Pm_DeleteVirtualDevice(id1_in));
- checkerror(Pm_DeleteVirtualDevice(id2_out));
- checkerror(Pm_DeleteVirtualDevice(id2_in));
- printf("done deleting.\n");
-}
-
-
-void show_usage()
-{
- printf("Usage: multivirtual [-h] [-l latency-in-ms] [n]\n"
- " -h for this message,\n"
- " -l ms designates latency for precise timing (default 0),\n"
- " n is number of message to send each output, not counting\n"
- " initial program change.\n"
- "sends change program to 1, then one note per second with 0.5s on,\n"
- "0.5s off, for n/2 seconds to both output ports portmidi1 and\n"
- "portmidi2. portmidi1 gets pitches from C4 (60). portmidi2 gets\n"
- "pitches an octave higher. Latency >0 uses the device driver for \n"
- "precise timing (see PortMidi documentation). Inputs print what\n"
- "they get and print WARNING if they get something unexpected.\n"
- "The expected test is use two instances of testio to loop\n"
- "portmidi1 back to portmidi1 and portmidi2 back to portmidi2.\n");
- exit(0);
-}
-
-
-int main(int argc, char *argv[])
-{
- int num = 10;
- int i;
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-h") == 0) {
- show_usage();
- } else if (strcmp(argv[i], "-l") == 0 && (i + 1 < argc)) {
- i = i + 1;
- latency = atoi(argv[i]);
- printf("Latency will be %d\n", latency);
- } else {
- num = atoi(argv[1]);
- if (num <= 0) {
- show_usage();
- }
- printf("Sending %d messages.\n", num);
- }
- }
-
- main_test(num);
-
- printf("finished sendvirtual test...type ENTER to quit...");
- while (getchar() != '\n') ;
- return 0;
-}
diff --git a/portmidi/pm_test/pmlist.c b/portmidi/pm_test/pmlist.c
deleted file mode 100644
index 5e3d1db..0000000
--- a/portmidi/pm_test/pmlist.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* pmlist.c -- list portmidi devices and numbers
- *
- * This program lists devices. When you type return, it
- * restarts portmidi and lists devices again. It is mainly
- * a test for shutting down and restarting.
- *
- * Roger B. Dannenberg, Feb 2022
- */
-
-#include "portmidi.h"
-#include "porttime.h"
-#include "stdlib.h"
-#include "stdio.h"
-#include "string.h"
-#include "assert.h"
-
-#define DEVICE_INFO NULL
-#define DRIVER_INFO NULL
-#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
-
-#define STRING_MAX 80 /* used for console input */
-
-void show_usage()
-{
- printf("Usage: pmlist [-h]\n -h means help.\n"
- " Type return to rescan and list devices, q<ret> to quit\n");
-}
-
-
-int main(int argc, char *argv[])
-{
- if (argc > 1) {
- show_usage();
- exit(0);
- }
-
- while (1) {
- char input[STRING_MAX];
- const char *deflt;
- const char *in_or_out;
- int default_in, default_out, i;
-
- // Pm_Initialize();
- /* list device information */
- default_in = Pm_GetDefaultInputDeviceID();
- default_out = Pm_GetDefaultOutputDeviceID();
- for (i = 0; i < Pm_CountDevices(); i++) {
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- printf("%d: %s, %s", i, info->interf, info->name);
- deflt = "";
- if (i == default_out || i == default_in) {
- deflt = "default ";
- }
- in_or_out = (info->input ? "input" : "output");
- printf(" (%s%s)\n", deflt, in_or_out);
- }
- if (fgets(input, STRING_MAX, stdin) && input[0] == 'q') {
- return 0;
- }
- Pm_Terminate();
- }
- return 0;
-}
diff --git a/portmidi/pm_test/qtest.c b/portmidi/pm_test/qtest.c
deleted file mode 100644
index 14d803e..0000000
--- a/portmidi/pm_test/qtest.c
+++ /dev/null
@@ -1,174 +0,0 @@
-#include "portmidi.h"
-#include "pmutil.h"
-#include "stdlib.h"
-#include "stdio.h"
-
-
-/* make_msg -- make a psuedo-random message of length n whose content
- * is purely a function of i
- */
-void make_msg(long msg[], int n, int i)
-{
- int j;
- for (j = 0; j < n; j++) {
- msg[j] = i % (j + 5);
- }
-}
-
-
-/* print_msg -- print the content of msg of length n to stdout */
-/**/
-void print_msg(long msg[], int n)
-{
- int i;
- for (i = 0; i < n; i++) {
- printf(" %li", msg[i]);
- }
-}
-
-
-/* cmp_msg -- compare two messages of length n */
-/**/
-int cmp_msg(long msg[], long msg2[], int n, int i)
-{
- int j;
- for (j = 0; j < n; j++) {
- if (msg[j] != msg2[j]) {
- printf("Received message %d doesn't match sent message\n", i);
- printf("in: "); print_msg(msg, n); printf("\n");
- printf("out:"); print_msg(msg2, n); printf("\n");
- return FALSE;
- }
- }
- return TRUE;
-}
-
-
-int main()
-{
- int msg_len;
- for (msg_len = 4; msg_len < 100; msg_len += 5) {
- PmQueue *queue = Pm_QueueCreate(100, msg_len * sizeof(long));
- int i;
- long msg[100];
- long msg2[100];
-
- printf("msg_len = %d\n", msg_len);
- if (!queue) {
- printf("Could not allocate queue\n");
- return 1;
- }
-
- /* insert/remove 1000 messages */
- printf("test 1\n");
- for (i = 0; i < 1357; i++) {
- make_msg(msg, msg_len, i);
- if (Pm_Enqueue(queue, msg)) {
- printf("Pm_Enqueue error\n");
- return 1;
- }
- if (Pm_Dequeue(queue, msg2) != 1) {
- printf("Pm_Dequeue error\n");
- return 1;
- }
- if (!cmp_msg(msg, msg2, msg_len, i)) {
- return 1;
- }
- }
-
- /* make full */
- printf("test 2\n");
- for (i = 0; i < 100; i++) {
- make_msg(msg, msg_len, i);
- if (Pm_Enqueue(queue, msg)) {
- printf("Pm_Enqueue error\n");
- return 1;
- }
- }
-
- /* alternately remove and insert */
- for (i = 100; i < 1234; i++) {
- make_msg(msg, msg_len, i - 100); /* what we expect */
- if (Pm_Dequeue(queue, msg2) != 1) {
- printf("Pm_Dequeue error\n");
- return 1;
- }
- if (!cmp_msg(msg, msg2, msg_len, i)) {
- return 1;
- }
- make_msg(msg, msg_len, i);
- if (Pm_Enqueue(queue, msg)) {
- printf("Pm_Enqueue error\n");
- return 1;
- }
- }
-
- /* remove all */
- while (!Pm_QueueEmpty(queue)) {
- make_msg(msg, msg_len, i - 100); /* what we expect */
- if (Pm_Dequeue(queue, msg2) != 1) {
- printf("Pm_Dequeue error\n");
- return 1;
- }
- if (!cmp_msg(msg, msg2, msg_len, i)) {
- return 1;
- }
- i++;
- }
- if (i != 1334) {
- printf("Message count error\n");
- return 1;
- }
-
- /* now test overflow */
- printf("test 3\n");
- for (i = 0; i < 110; i++) {
- make_msg(msg, msg_len, i);
- if (Pm_Enqueue(queue, msg) == pmBufferOverflow) {
- break; /* this is supposed to execute after 100 messages */
- }
- }
- for (i = 0; i < 100; i++) {
- make_msg(msg, msg_len, i);
- if (Pm_Dequeue(queue, msg2) != 1) {
- printf("Pm_Dequeue error\n");
- return 1;
- }
- if (!cmp_msg(msg, msg2, msg_len, i)) {
- return 1;
- }
- }
- /* we should detect overflow after removing 100 messages */
- if (Pm_Dequeue(queue, msg2) != pmBufferOverflow) {
- printf("Pm_Dequeue overflow expected\n");
- return 1;
- }
-
- /* after overflow is detected (and cleared), sender can
- * send again
- */
- /* see if function is restored, also test peek */
- printf("test 4\n");
- for (i = 0; i < 1357; i++) {
- long *peek;
- make_msg(msg, msg_len, i);
- if (Pm_Enqueue(queue, msg)) {
- printf("Pm_Enqueue error\n");
- return 1;
- }
- peek = (long *) Pm_QueuePeek(queue);
- if (!cmp_msg(msg, peek, msg_len, i)) {
- return 1;
- }
- if (Pm_Dequeue(queue, msg2) != 1) {
- printf("Pm_Dequeue error\n");
- return 1;
- }
- if (!cmp_msg(msg, msg2, msg_len, i)) {
- return 1;
- }
- }
- Pm_QueueDestroy(queue);
- }
- return 0;
-}
diff --git a/portmidi/pm_test/recvvirtual.c b/portmidi/pm_test/recvvirtual.c
deleted file mode 100644
index f8d9848..0000000
--- a/portmidi/pm_test/recvvirtual.c
+++ /dev/null
@@ -1,175 +0,0 @@
-#include "portmidi.h"
-#include "porttime.h"
-#include "stdlib.h"
-#include "stdio.h"
-#include "string.h"
-#include "assert.h"
-
-#define INPUT_BUFFER_SIZE 100
-#define TIME_PROC ((PmTimeProcPtr) Pt_Time)
-#define TIME_INFO NULL
-#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
-
-#define STRING_MAX 80 /* used for console input */
-
-char *portname = "portmidi";
-
-PmSysDepInfo *sysdepinfo = NULL;
-char *port_name = "portmidi";
-
-static void set_sysdepinfo(char m_or_p, const char *name)
-{
- if (!sysdepinfo) {
- // allocate some space we will alias with open-ended PmDriverInfo:
- // there is space for 4 parameters:
- static char dimem[sizeof(PmSysDepInfo) + sizeof(void *) * 8];
- sysdepinfo = (PmSysDepInfo *) dimem;
- // build the driver info structure:
- sysdepinfo->structVersion = PM_SYSDEPINFO_VERS;
- sysdepinfo->length = 0;
- }
- if (sysdepinfo->length > 1) {
- printf("Error: sysdepinfo was allocated to hold 2 parameters\n");
- exit(1);
- }
- int i = sysdepinfo->length++;
- enum PmSysDepPropertyKey k = pmKeyNone;
- if (m_or_p == 'm') k = pmKeyCoreMidiManufacturer;
- else if (m_or_p == 'p') k = pmKeyAlsaPortName;
- else if (m_or_p == 'c') k = pmKeyAlsaClientName;
- sysdepinfo->properties[i].key = k;
- sysdepinfo->properties[i].value = name;
-}
-
-
-static void prompt_and_exit(void)
-{
- printf("type ENTER...");
- while (getchar() != '\n') ;
- /* this will clean up open ports: */
- exit(-1);
-}
-
-
-static PmError checkerror(PmError err)
-{
- if (err == pmHostError) {
- /* it seems pointless to allocate memory and copy the string,
- * so I will do the work of Pm_GetHostErrorText directly
- */
- char errmsg[80];
- Pm_GetHostErrorText(errmsg, 80);
- printf("PortMidi found host error...\n %s\n", errmsg);
- prompt_and_exit();
- } else if (err < 0) {
- printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err));
- prompt_and_exit();
- }
- return err;
-}
-
-
-void main_test_input(int num)
-{
- PmStream *midi;
- PmError status, length;
- PmEvent buffer[1];
- int id;
- int i = 0; /* count messages as they arrive */
- /* It is recommended to start timer before Midi; otherwise, PortMidi may
- start the timer with its (default) parameters
- */
- TIME_START;
-
- /* create a virtual input device */
- id = checkerror(Pm_CreateVirtualInput(port_name, NULL, sysdepinfo));
- checkerror(Pm_OpenInput(&midi, id, sysdepinfo, 0, NULL, NULL));
-
- printf("Midi Input opened. Reading %d Midi messages...\n", num);
- Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX);
- /* empty the buffer after setting filter, just in case anything
- got through */
- while (Pm_Poll(midi)) {
- Pm_Read(midi, buffer, 1);
- }
- /* now start paying attention to messages */
- while (i < num) {
- status = Pm_Poll(midi);
- if (status == TRUE) {
- length = Pm_Read(midi, buffer, 1);
- if (length > 0) {
- printf("Got message %d: time %ld, %2lx %2lx %2lx\n",
- i,
- (long) buffer[0].timestamp,
- (long) Pm_MessageStatus(buffer[0].message),
- (long) Pm_MessageData1(buffer[0].message),
- (long) Pm_MessageData2(buffer[0].message));
- i++;
- } else {
- assert(0);
- }
- }
- }
-
- /* close device (this not explicitly needed in most implementations) */
- printf("ready to close...");
- Pm_Close(midi);
- printf("done closing.\nNow delete the virtual device...");
- checkerror(Pm_DeleteVirtualDevice(id));
- printf("done deleting.\n");
-}
-
-
-void show_usage()
-{
- printf("Usage: recvvirtual [-h] [-m manufacturer] [-c clientname] "
- "[-p portname] [n]\n"
- " -h for this message,\n"
- " -m name designates a manufacturer name (macOS only),\n"
- " -c name designates a client name (linux only),\n"
- " -p name designates a port name (linux only),\n"
- " n is number of message to wait for.\n");
- exit(0);
-}
-
-
-int main(int argc, char *argv[])
-{
- char line[STRING_MAX];
- int num = 10;
- int i;
- if (argc <= 1) {
- show_usage();
- }
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-h") == 0) {
- show_usage();
- } else if (strcmp(argv[i], "-m") == 0 && (i + 1 < argc)) {
- i = i + 1;
- set_sysdepinfo('m', argv[i]);
- printf("Manufacturer name will be %s\n", argv[i]);
- } else if (strcmp(argv[i], "-p") == 0 && (i + 1 < argc)) {
- i = i + 1;
- port_name = argv[i];
- set_sysdepinfo('p', port_name);
- printf("Port name will be %s\n", port_name);
- } else if (strcmp(argv[i], "-c") == 0 && (i + 1 < argc)) {
- i = i + 1;
- set_sysdepinfo('c', argv[i]);
- printf("Client name will be %s\n", argv[i]);
- } else {
- num = atoi(argv[i]);
- if (num <= 0) {
- printf("Zero value or non-number for n\n");
- show_usage();
- }
- printf("Waiting for %d messages.\n", num);
- }
- }
-
- main_test_input(num);
-
- printf("finished portMidi test...type ENTER to quit...");
- while (getchar() != '\n') ;
- return 0;
-}
diff --git a/portmidi/pm_test/sendvirtual.c b/portmidi/pm_test/sendvirtual.c
deleted file mode 100644
index a60a48f..0000000
--- a/portmidi/pm_test/sendvirtual.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/* sendvirtual.c -- test for creating a virtual device and sending to it */
-/*
- * Roger B. Dannenberg
- * Sep 2021
- */
-#include "portmidi.h"
-#include "porttime.h"
-#include "stdlib.h"
-#include "stdio.h"
-#include "string.h"
-#include "assert.h"
-
-#define OUTPUT_BUFFER_SIZE 0
-#define TIME_PROC ((PmTimeProcPtr) Pt_Time)
-#define TIME_INFO NULL
-#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
-
-int latency = 0;
-PmSysDepInfo *sysdepinfo = NULL;
-char *port_name = "portmidi";
-
-static void set_sysdepinfo(char m_or_p, const char *name)
-{
- if (!sysdepinfo) {
- // allocate some space we will alias with open-ended PmDriverInfo:
- // there is space for 4 parameters:
- static char dimem[sizeof(PmSysDepInfo) + sizeof(void *) * 8];
- sysdepinfo = (PmSysDepInfo *) dimem;
- // build the driver info structure:
- sysdepinfo->structVersion = PM_SYSDEPINFO_VERS;
- sysdepinfo->length = 0;
- }
- if (sysdepinfo->length > 1) {
- printf("Error: sysdepinfo was allocated to hold 2 parameters\n");
- exit(1);
- }
- int i = sysdepinfo->length++;
- enum PmSysDepPropertyKey k = pmKeyNone;
- if (m_or_p == 'm') k = pmKeyCoreMidiManufacturer;
- else if (m_or_p == 'p') k = pmKeyAlsaPortName;
- else if (m_or_p == 'c') k = pmKeyAlsaClientName;
- sysdepinfo->properties[i].key = k;
- sysdepinfo->properties[i].value = name;
-}
-
-
-static void prompt_and_exit(void)
-{
- printf("type ENTER...");
- while (getchar() != '\n') ;
- /* this will clean up open ports: */
- exit(-1);
-}
-
-
-static PmError checkerror(PmError err)
-{
- if (err == pmHostError) {
- /* it seems pointless to allocate memory and copy the string,
- * so I will do the work of Pm_GetHostErrorText directly
- */
- char errmsg[80];
- Pm_GetHostErrorText(errmsg, 80);
- printf("PortMidi found host error...\n %s\n", errmsg);
- prompt_and_exit();
- } else if (err < 0) {
- printf("PortMidi call failed...\n %s\n", Pm_GetErrorText(err));
- prompt_and_exit();
- }
- return err;
-}
-
-
-void wait_until(PmTimestamp when)
-{
- PtTimestamp now = Pt_Time();
- if (when > now) {
- Pt_Sleep(when - now);
- }
-}
-
-
-void main_test_output(int num)
-{
- PmStream *midi;
- int32_t next_time;
- PmEvent buffer[1];
- PmTimestamp timestamp;
- int pitch = 60;
- int id;
-
- /* It is recommended to start timer before Midi; otherwise, PortMidi may
- start the timer with its (default) parameters
- */
- TIME_START;
-
- /* create a virtual output device */
- id = checkerror(Pm_CreateVirtualOutput(port_name, NULL, sysdepinfo));
- checkerror(Pm_OpenOutput(&midi, id, sysdepinfo, OUTPUT_BUFFER_SIZE,
- TIME_PROC, TIME_INFO, latency));
-
- printf("Midi Output Virtual Device \"%s\" created.\n", port_name);
- printf("Type ENTER to send messages: ");
- while (getchar() != '\n') ;
-
- buffer[0].timestamp = Pt_Time();
-#define PROGRAM 0
- buffer[0].message = Pm_Message(0xC0, PROGRAM, 0);
- Pm_Write(midi, buffer, 1);
- next_time = Pt_Time() + 1000; /* wait 1s */
- while (num > 0) {
- wait_until(next_time);
- Pm_WriteShort(midi, next_time, Pm_Message(0x90, pitch, 100));
- printf("Note On pitch %d\n", pitch);
- num--;
- next_time += 500;
-
- wait_until(next_time);
- Pm_WriteShort(midi, next_time, Pm_Message(0x90, pitch, 0));
- printf("Note Off pitch %d\n", pitch);
- num--;
- pitch = (pitch + 1) % 12 + 60;
- next_time += 500;
- }
-
- /* close device (this not explicitly needed in most implementations) */
- printf("ready to close...");
- Pm_Close(midi);
- printf("done closing.\nNow delete the virtual device...");
- checkerror(Pm_DeleteVirtualDevice(id));
- printf("done deleting.\n");
-}
-
-
-void show_usage()
-{
- printf("Usage: sendvirtual [-h] [-l latency-in-ms] [-m manufacturer] "
- "[-c clientname] [-p portname] [n]\n"
- " -h for this message,\n"
- " -l ms designates latency for precise timing (default 0),\n"
- " -m name designates a manufacturer name (macOS only),\n"
- " -c name designates a client name (linux only),\n"
- " -p name designates a port name (linux only),\n"
- " n is number of message to send.\n"
- "sends change program to 1, then one note per second with 0.5s on,\n"
- "0.5s off, for n/2 seconds. Latency >0 uses the device driver for \n"
- "precise timing (see PortMidi documentation).\n");
- exit(0);
-}
-
-
-int main(int argc, char *argv[])
-{
- int num = 10;
- int i;
- if (argc <= 1) {
- show_usage();
- }
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-h") == 0) {
- show_usage();
- } else if (strcmp(argv[i], "-l") == 0 && (i + 1 < argc)) {
- i = i + 1;
- latency = atoi(argv[i]);
- printf("Latency will be %d\n", latency);
- } else if (strcmp(argv[i], "-m") == 0 && (i + 1 < argc)) {
- i = i + 1;
- set_sysdepinfo('m', argv[i]);
- printf("Manufacturer name will be %s\n", argv[i]);
- } else if (strcmp(argv[i], "-p") == 0 && (i + 1 < argc)) {
- i = i + 1;
- port_name = argv[i];
- set_sysdepinfo('p', port_name);
- printf("Port name will be %s\n", port_name);
- } else if (strcmp(argv[i], "-c") == 0 && (i + 1 < argc)) {
- i = i + 1;
- set_sysdepinfo('c', argv[i]);
- printf("Client name will be %s\n", argv[i]);
- } else {
- num = atoi(argv[i]);
- if (num <= 0) {
- printf("Zero value or non-number for n\n");
- show_usage();
- }
- printf("Sending %d messages.\n", num);
- }
- }
-
- main_test_output(num);
-
- printf("finished sendvirtual test...type ENTER to quit...");
- while (getchar() != '\n') ;
- return 0;
-}
diff --git a/portmidi/pm_test/sysex.c b/portmidi/pm_test/sysex.c
deleted file mode 100755
index c2c7187..0000000
--- a/portmidi/pm_test/sysex.c
+++ /dev/null
@@ -1,556 +0,0 @@
-/* sysex.c -- example program showing how to send and receive sysex
- messages
-
- Messages are stored in a file using 2-digit hexadecimal numbers,
- one per byte, separated by blanks, with up to 32 numbers per line:
- F0 14 A7 4B ...
-
- */
-
-#include "stdio.h"
-#include "stdlib.h"
-#include "assert.h"
-#include "portmidi.h"
-#include "porttime.h"
-#include "string.h"
-#ifdef WIN32
-// need to get declaration for Sleep()
-#include "windows.h"
-#else
-#include <unistd.h>
-#define Sleep(n) usleep(n * 1000)
-#endif
-
-// enable some extra printing
-#ifndef VERBOSE
-#define VERBOSE 0
-#endif
-
-#define MIDI_SYSEX 0xf0
-#define MIDI_EOX 0xf7
-
-#define STRING_MAX 80
-
-#ifndef true
-#define true 1
-#define false 0
-#endif
-
-int latency = 0;
-
-/* read a number from console */
-/**/
-int get_number(const char *prompt)
-{
- int n = 0, i;
- fputs(prompt, stdout);
- while (n != 1) {
- n = scanf("%d", &i);
- while (getchar() != '\n') ;
- }
- return i;
-}
-
-
-/* loopback test -- send/rcv from 2 to 1000 bytes of random midi data */
-/**/
-void loopback_test()
-{
- int outp;
- int inp;
- PmStream *midi_in;
- PmStream *midi_out;
- unsigned char msg[1024];
- int32_t len;
- int i;
- int data;
- PmEvent event;
- int shift;
- long total_bytes = 0;
- int32_t begin_time;
-
- Pt_Start(1, 0, 0);
-
- printf("Connect a midi cable from an output port to an input port.\n");
- printf("This test will send random data via sysex message from output\n");
- printf("to input and check that the correct data was received.\n");
- outp = get_number("Type output device number: ");
- /* Open output with 1ms latency -- when latency is non-zero, the Win32
- implementation supports sending sysex messages incrementally in a
- series of buffers. This is nicer than allocating a big buffer for the
- message, and it also seems to work better. Either way works.
- */
- while ((latency = get_number(
- "Latency in milliseconds (0 to send data immediatedly,\n"
- " >0 to send timestamped messages): ")) < 0);
- Pm_OpenOutput(&midi_out, outp, NULL, 0, NULL, NULL, latency);
- inp = get_number("Type input device number: ");
- /* since we are going to send and then receive, make sure the input buffer
- is large enough for the entire message */
- Pm_OpenInput(&midi_in, inp, NULL, 512, NULL, NULL);
-
- srand((unsigned int) Pt_Time()); /* seed for random numbers */
-
- begin_time = Pt_Time();
- while (total_bytes < 100000) {
- PmError count;
- int32_t start_time;
- int error_position = -1; /* 0; -1; -1 for continuous */
- int expected = 0;
- int actual = 0;
- /* this modification will run until an error is detected */
- /* set error_position above to 0 for interactive, -1 for */
- /* continuous */
- if (error_position >= 0) {
- int c;
- printf("Type return to send message, q to quit: ");
- while ((c = getchar()) != '\n') {
- if (c == 'q') goto cleanup;
- }
- }
-
- /* compose the message */
- len = rand() % 998 + 2; /* len only counts data bytes */
- msg[0] = (char) MIDI_SYSEX; /* start of SYSEX message */
- /* data bytes go from 1 to len */
- for (i = 0; i < len; i++) {
-/* pick whether data is sequential or random... (docs say random) */
-#define DATA_EXPR (i+1)
-// #define DATA_EXPR rand()
- msg[i + 1] = DATA_EXPR & 0x7f; /* MIDI data */
- }
- /* final EOX goes in len+1, total of len+2 bytes in msg */
- msg[len + 1] = (char) MIDI_EOX;
-
- /* sanity check: before we send, there should be no queued data */
- count = Pm_Read(midi_in, &event, 1);
-
- if (count != 0) {
- printf("Before sending anything, a MIDI message was found in\n");
- printf("the input buffer. Please try again.\n");
- break;
- }
-
- /* send the message two ways: 1) Pm_WriteSysEx, 2) Pm_Write */
- if (total_bytes & 1) {
- printf("Sending %d byte sysex msg via Pm_WriteSysEx.\n", len + 2);
- Pm_WriteSysEx(midi_out, 0, msg);
- } else {
- PmEvent event = {0, 0};
- int bits = 0;
- printf("Sending %d byte sysex msg via Pm_Write(s).\n", len + 2);
- for (i = 0; i < len + 2; i++) {
- event.message |= (msg[i] << bits);
- bits += 8;
- if (bits == 32) { /* full message - send it */
- Pm_Write(midi_out, &event, 1);
- bits = 0;
- event.message = 0;
- }
- }
- if (bits > 0) { /* last message is partially full */
- Pm_Write(midi_out, &event, 1);
- }
- }
-
- /* receive the message and compare to msg[] */
- data = 0;
- shift = 0;
- i = 0;
- start_time = Pt_Time();
- if (VERBOSE) {
- printf("start_time %d\n", start_time);
- }
- error_position = -1;
- /* allow up to 2 seconds for transmission */
- while (data != MIDI_EOX && start_time + 2000 > Pt_Time()) {
- count = Pm_Read(midi_in, &event, 1);
- if (count == 0) {
- Sleep(1); /* be nice: give some CPU time to the system */
- continue; /* continue polling for input */
- }
- if (VERBOSE) {
- printf("read %08x ", event.message);
- fflush(stdout);
- }
- /* compare 4 bytes of data until you reach an eox */
- for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) {
- data = (event.message >> shift) & 0xFF;
- if (data != msg[i] && error_position < 0) {
- error_position = i;
- expected = msg[i];
- actual = data;
- }
- i++;
- }
- }
- if (error_position >= 0) {
- printf("Error at time %d byte %d: sent %x recd %x.\n", Pt_Time(),
- error_position, expected, actual);
- break;
- } else if (i != len + 2) {
- printf("Error at time %d: byte %d not received.\n", Pt_Time(), i);
- break;
- } else {
- int seconds = (Pt_Time() - begin_time) / 1000;
- if (seconds == 0) seconds = 1;
- printf("Correctly received %d byte sysex message.\n", i);
- total_bytes += i;
- printf("Cummulative bytes/sec: %d, %d%% done.\n",
- (int) (total_bytes / seconds),
- (int) (100 * total_bytes / 100000));
- }
- }
-cleanup:
- Pm_Close(midi_out);
- Pm_Close(midi_in);
- return;
-}
-
-
-/* send_multiple test -- send many sysex messages */
-/**/
-void send_multiple_test()
-{
- int outp;
- int length;
- int num_msgs;
- PmStream *midi_out;
- unsigned char msg[1024];
- int i;
- PtTimestamp start_time;
- PtTimestamp stop_time;
-
- Pt_Start(1, 0, 0);
-
- printf("This is for performance testing. You should be sending to this\n");
- printf("program running the receive multiple test. Do NOT send to\n");
- printf("a synthesizer or you risk reprogramming it\n");
- outp = get_number("Type output device number: ");
- while ((latency = get_number(
- "Latency in milliseconds (0 to send data immediatedly,\n"
- " >0 to send timestamped messages): ")) < 0);
- Pm_OpenOutput(&midi_out, outp, NULL, 0, NULL, NULL, latency);
- while ((length = get_number("Message length (7 - 1024): ")) < 7 ||
- length > 1024) ;
- while ((num_msgs = get_number("Number of messages: ")) < 1);
- /* latency, length, and num_msgs should now all be valid */
- /* compose the message except for sequence number in first 5 bytes */
- msg[0] = (char) MIDI_SYSEX;
- for (i = 6; i < length - 1; i++) {
- msg[i] = i % 128; /* this is just filler */
- }
- msg[length - 1] = (char) MIDI_EOX;
-
- start_time = Pt_Time();
- /* send the messages */
- for (i = num_msgs; i > 0; i--) {
- /* insert sequence number into first 5 data bytes */
- /* sequence counts down to zero */
- int j;
- int count = i;
- /* 7 bits of message count i goes into each data byte */
- for (j = 1; j <= 5; j++) {
- msg[j] = count & 127;
- count >>= 7;
- }
- /* send the message */
- Pm_WriteSysEx(midi_out, 0, msg);
- }
- stop_time = Pt_Time();
- Pm_Close(midi_out);
- return;
-}
-
-#define MAX_MSG_LEN 1024
-static unsigned char receive_msg[MAX_MSG_LEN];
-static int receive_msg_index;
-static int receive_msg_length;
-static int receive_msg_count;
-static int receive_msg_error;
-static int receive_msg_messages;
-static PmStream *receive_msg_midi_in;
-static int receive_poll_running;
-
-/* receive_poll -- callback function to check for midi input */
-/**/
-void receive_poll(PtTimestamp timestamp, void *userData)
-{
- PmError count;
- PmEvent event;
- int shift;
- int data = 0;
- int i;
-
- if (!receive_poll_running) return; /* wait until midi device is opened */
- shift = 0;
- while (data != MIDI_EOX) {
- count = Pm_Read(receive_msg_midi_in, &event, 1);
- if (count == 0) return;
-
- /* compare 4 bytes of data until you reach an eox */
- for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) {
- receive_msg[receive_msg_index++] = data =
- (event.message >> shift) & 0xFF;
- if (receive_msg_index >= MAX_MSG_LEN) {
- printf("error: incoming sysex too long\n");
- goto error;
- }
- }
- }
- /* check the message */
- if (receive_msg_length == 0) {
- receive_msg_length = receive_msg_index;
- }
- if (receive_msg_length != receive_msg_index) {
- printf("error: incoming sysex wrong length\n");
- goto error;
- }
- if (receive_msg[0] != MIDI_SYSEX) {
- printf("error: incoming sysex missing status byte\n");
- goto error;
- }
- /* get and check the count */
- count = 0;
- for (i = 0; i < 5; i++) {
- count += receive_msg[i + 1] << (7 * i);
- }
- if (receive_msg_count == -1) {
- receive_msg_count = count;
- receive_msg_messages = count;
- }
- if (receive_msg_count != count) {
- printf("error: incoming sysex has wrong count\n");
- goto error;
- }
- for (i = 6; i < receive_msg_index - 1; i++) {
- if (receive_msg[i] != i % 128) {
- printf("error: incoming sysex has bad data\n");
- goto error;
- }
- }
- if (receive_msg[receive_msg_length - 1] != MIDI_EOX) goto error;
- receive_msg_index = 0; /* get ready for next message */
- receive_msg_count--;
- return;
- error:
- receive_msg_error = 1;
- return;
-}
-
-
-/* receive_multiple_test -- send/rcv from 2 to 1000 bytes of random midi data */
-/**/
-void receive_multiple_test()
-{
- PmError err;
- int inp;
-
- printf("This test expects to receive data sent by the send_multiple test\n");
- printf("The test will check that correct data is received.\n");
-
- /* Important: start PortTime first -- if it is not started first, it will
- be started by PortMidi, and then our attempt to open again will fail */
- receive_poll_running = false;
- if ((err = Pt_Start(1, receive_poll, 0))) {
- printf("PortTime error code: %d\n", err);
- goto cleanup;
- }
- inp = get_number("Type input device number: ");
- Pm_OpenInput(&receive_msg_midi_in, inp, NULL, 512, NULL, NULL);
- receive_msg_index = 0;
- receive_msg_length = 0;
- receive_msg_count = -1;
- receive_msg_error = 0;
- receive_poll_running = true;
- while ((!receive_msg_error) && (receive_msg_count != 0)) {
-#ifdef WIN32
- Sleep(1000);
-#else
- sleep(1); /* block and wait */
-#endif
- }
- if (receive_msg_error) {
- printf("Receive_multiple test encountered an error\n");
- } else {
- printf("Receive_multiple test successfully received %d sysex messages\n",
- receive_msg_messages);
- }
-cleanup:
- receive_poll_running = false;
- Pm_Close(receive_msg_midi_in);
- Pt_Stop();
- return;
-}
-
-
-#define is_real_time_msg(msg) ((0xF0 & Pm_MessageStatus(msg)) == 0xF8)
-
-
-void receive_sysex()
-{
- char line[80];
- FILE *f;
- PmStream *midi;
- int shift = 0;
- int data = 0;
- int bytes_on_line = 0;
- PmEvent msg;
-
- /* determine which output device to use */
- int i = get_number("Type input device number: ");
-
- /* open input device */
- Pm_OpenInput(&midi, i, NULL, 512, NULL, NULL);
- printf("Midi Input opened, type file for sysex data: ");
-
- /* open file */
- if (!fgets(line, STRING_MAX, stdin)) return; /* no more stdin? */
- /* remove the newline character */
- if (strlen(line) > 0) line[strlen(line) - 1] = 0;
- f = fopen(line, "w");
- if (!f) {
- printf("Could not open %s\n", line);
- Pm_Close(midi);
- return;
- }
-
- printf("Ready to receive a sysex message\n");
-
- /* read data and write to file */
- while (data != MIDI_EOX) {
- PmError count;
- count = Pm_Read(midi, &msg, 1);
- /* CAUTION: this causes busy waiting. It would be better to
- be in a polling loop to avoid being compute bound. PortMidi
- does not support a blocking read since this is so seldom
- useful.
- */
- if (count == 0) continue;
- /* ignore real-time messages */
- if (is_real_time_msg(Pm_MessageStatus(msg.message))) continue;
-
- /* write 4 bytes of data until you reach an eox */
- for (shift = 0; shift < 32 && (data != MIDI_EOX); shift += 8) {
- data = (msg.message >> shift) & 0xFF;
- /* if this is a status byte that's not MIDI_EOX, the sysex
- message is incomplete and there is no more sysex data */
- if (data & 0x80 && data != MIDI_EOX) break;
- fprintf(f, "%2x ", data);
- if (++bytes_on_line >= 16) {
- fprintf(f, "\n");
- bytes_on_line = 0;
- }
- }
- }
- fclose(f);
- Pm_Close(midi);
-}
-
-
-void send_sysex()
-{
- char line[80];
- FILE *f;
- PmStream *midi;
- int data;
- int shift = 0;
- PmEvent msg;
-
- /* determine which output device to use */
- int i = get_number("Type output device number: ");
- while ((latency = get_number(
- "Latency in milliseconds (0 to send data immediatedly,\n"
- " >0 to send timestamped messages): ")) < 0);
-
- msg.timestamp = 0; /* no need for timestamp */
-
- /* open output device */
- Pm_OpenOutput(&midi, i, NULL, 0, NULL, NULL, latency);
- printf("Midi Output opened, type file with sysex data: ");
-
- /* open file */
- if (!fgets(line, STRING_MAX, stdin)) return; /* no more stdin? */
- /* remove the newline character */
- if (strlen(line) > 0) line[strlen(line) - 1] = 0;
- f = fopen(line, "r");
- if (!f) {
- printf("Could not open %s\n", line);
- Pm_Close(midi);
- return;
- }
-
- /* read file and send data */
- msg.message = 0;
- while (1) {
- /* get next byte from file */
-
- if (fscanf(f, "%x", &data) == 1) {
- /* printf("read %x, ", data); */
- /* OR byte into message at proper offset */
- msg.message |= (data << shift);
- shift += 8;
- }
- /* send the message if it's full (shift == 32) or if we are at end */
- if (shift == 32 || data == MIDI_EOX) {
- /* this will send sysex data 4 bytes at a time -- it would
- be much more efficient to send multiple PmEvents at once
- but this method is simpler. See Pm_WriteSysEx for a more
- efficient code example.
- */
- Pm_Write(midi, &msg, 1);
- msg.message = 0;
- shift = 0;
- }
- if (data == MIDI_EOX) { /* end of message */
- fclose(f);
- Pm_Close(midi);
- return;
- }
- }
-}
-
-
-int main()
-{
- int i;
-
- /* list device information */
- for (i = 0; i < Pm_CountDevices(); i++) {
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- printf("%d: %s, %s", i, info->interf, info->name);
- if (info->input) printf(" (input)");
- if (info->output) printf(" (output)");
- printf("\n");
- }
- while (1) {
- char cmd;
- printf("Type r to receive sysex, s to send,"
- " l for loopback test, m to send multiple,"
- " n to receive multiple, q to quit: ");
- cmd = getchar();
- while (getchar() != '\n') ;
- switch (cmd) {
- case 'r':
- receive_sysex();
- break;
- case 's':
- send_sysex();
- break;
- case 'l':
- loopback_test();
- break;
- case 'm':
- send_multiple_test();
- break;
- case 'n':
- receive_multiple_test();
- break;
- case 'q':
- exit(0);
- default:
- break;
- }
- }
- return 0;
-}
diff --git a/portmidi/pm_test/testio.c b/portmidi/pm_test/testio.c
deleted file mode 100755
index 2711286..0000000
--- a/portmidi/pm_test/testio.c
+++ /dev/null
@@ -1,594 +0,0 @@
-#include "portmidi.h"
-#include "porttime.h"
-#include "stdlib.h"
-#include "stdio.h"
-#include "string.h"
-#include "assert.h"
-
-#define INPUT_BUFFER_SIZE 100
-#define OUTPUT_BUFFER_SIZE 0
-#define TIME_PROC ((int32_t (*)(void *)) Pt_Time)
-#define TIME_INFO NULL
-#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
-
-#define WAIT_FOR_ENTER while (getchar() != '\n') ;
-
-int32_t latency = 0;
-int verbose = FALSE;
-PmSysDepInfo *sysdepinfo = NULL;
-
-/* crash the program to test whether midi ports are closed */
-/**/
-void doSomethingReallyStupid() {
- int * tmp = NULL;
- *tmp = 5;
-}
-
-
-/* exit the program without any explicit cleanup */
-/**/
-void doSomethingStupid() {
- assert(0);
-}
-
-
-/* read a number from console */
-/**/
-int get_number(const char *prompt)
-{
- int n = 0, i;
- fputs(prompt, stdout);
- while (n != 1) {
- n = scanf("%d", &i);
- WAIT_FOR_ENTER
- }
- return i;
-}
-
-
-static void set_sysdepinfo(char m_or_p, const char *name)
-{
- if (!sysdepinfo) {
- // allocate some space we will alias with open-ended PmDriverInfo:
- // there is space for 4 parameters:
- static char dimem[sizeof(PmSysDepInfo) + sizeof(void *) * 8];
- sysdepinfo = (PmSysDepInfo *) dimem;
- // build the driver info structure:
- sysdepinfo->structVersion = PM_SYSDEPINFO_VERS;
- sysdepinfo->length = 0;
- }
- if (sysdepinfo->length > 1) {
- printf("Error: sysdepinfo was allocated to hold 2 parameters\n");
- exit(1);
- }
- int i = sysdepinfo->length++;
- enum PmSysDepPropertyKey k = pmKeyNone;
- if (m_or_p == 'm') k = pmKeyCoreMidiManufacturer;
- else if (m_or_p == 'p') k = pmKeyAlsaPortName;
- else if (m_or_p == 'c') k = pmKeyAlsaClientName;
- sysdepinfo->properties[i].key = k;
- sysdepinfo->properties[i].value = name;
-}
-
-
-/*
- * the somethingStupid parameter can be set to simulate a program crash.
- * We want PortMidi to close Midi ports automatically in the event of a
- * crash because Windows does not (and this may cause an OS crash)
- */
-void main_test_input(unsigned int somethingStupid) {
- PmStream * midi;
- PmError status, length;
- PmEvent buffer[1];
- int num = 10;
- int i = get_number("Type input number: ");
- /* It is recommended to start timer before Midi; otherwise, PortMidi may
- start the timer with its (default) parameters
- */
- TIME_START;
-
- /* open input device */
- Pm_OpenInput(&midi,
- i,
- sysdepinfo,
- INPUT_BUFFER_SIZE,
- TIME_PROC,
- TIME_INFO);
-
- printf("Midi Input opened. Reading %d Midi messages...\n", num);
- Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX);
- /* empty the buffer after setting filter, just in case anything
- got through */
- while (Pm_Poll(midi)) {
- Pm_Read(midi, buffer, 1);
- }
- /* now start paying attention to messages */
- i = 0; /* count messages as they arrive */
- while (i < num) {
- status = Pm_Poll(midi);
- if (status == TRUE) {
- length = Pm_Read(midi, buffer, 1);
- if (length > 0) {
- printf("Got message %d @ time %ld: timestamp %ld, "
- "%2lx %2lx %2lx\n", i, (long) Pt_Time(),
- (long) buffer[0].timestamp,
- (long) Pm_MessageStatus(buffer[0].message),
- (long) Pm_MessageData1(buffer[0].message),
- (long) Pm_MessageData2(buffer[0].message));
- i++;
- } else {
- assert(0);
- }
- }
- /* simulate crash if somethingStupid is 1 or 2 */
- if ((i > (num/2)) && (somethingStupid == 1)) {
- doSomethingStupid();
- } else if ((i > (num/2)) && (somethingStupid == 2)) {
- doSomethingReallyStupid();
- }
- }
-
- /* close device (this not explicitly needed in most implementations) */
- printf("ready to close...");
-
- Pm_Close(midi);
- printf("done closing...");
-}
-
-
-
-void main_test_output(int isochronous_test)
-{
- PmStream * midi;
- int32_t off_time;
- int chord[] = { 60, 67, 76, 83, 90 };
- #define chord_size 5
- PmEvent buffer[chord_size];
- PmTimestamp timestamp;
-
- /* determine which output device to use */
- int i = get_number("Type output number: ");
-
- /* It is recommended to start timer before PortMidi */
- TIME_START;
-
- /* open output device -- since PortMidi avoids opening a timer
- when latency is zero, we will pass in a NULL timer pointer
- for that case. If PortMidi tries to access the time_proc,
- we will crash, so this test will tell us something. */
- Pm_OpenOutput(&midi,
- i,
- sysdepinfo,
- OUTPUT_BUFFER_SIZE,
- (latency == 0 ? NULL : TIME_PROC),
- (latency == 0 ? NULL : TIME_INFO),
- latency);
- printf("Midi Output opened with %ld ms latency.\n", (long) latency);
-
- /* output note on/off w/latency offset; hold until user prompts */
- printf("ready to send program 1 change... (type ENTER):");
- WAIT_FOR_ENTER
- /* if we were writing midi for immediate output, we could always use
- timestamps of zero, but since we may be writing with latency, we
- will explicitly set the timestamp to "now" by getting the time.
- The source of timestamps should always correspond to the TIME_PROC
- and TIME_INFO parameters used in Pm_OpenOutput(). */
- buffer[0].timestamp = Pt_Time();
- /* Send a program change to increase the chances we will hear notes */
- /* Program 0 is usually a piano, but you can change it here: */
-#define PROGRAM 0
- buffer[0].message = Pm_Message(0xC0, PROGRAM, 0);
- Pm_Write(midi, buffer, 1);
-
- if (isochronous_test) { // play 4 notes per sec for 20s
- int count;
- PmTimestamp start;
- if (latency < 100) {
- printf("Warning: latency < 100, but this test sends messages"
- " at times that are jittered by up to 100ms, so you"
- " may hear uneven timing\n");
- }
- printf("Starting in 1s..."); fflush(stdout);
- Pt_Sleep(1000);
- start = Pt_Time();
- for (count = 0; count < 80; count++) {
- PmTimestamp next_time;
- buffer[0].timestamp = start + count * 250;
- buffer[0].message = Pm_Message(0x90, 69, 100);
- buffer[1].timestamp = start + count * 250 + 200;
- buffer[1].message = Pm_Message(0x90, 69, 0);
- Pm_Write(midi, buffer, 2);
- next_time = start + (count + 1) * 250;
- // sleep for a random time up to 100ms to add jitter to
- // the times at which we send messages. PortMidi timing
- // should remove the jitter if latency > 100
- while (Pt_Time() < next_time) {
- Pt_Sleep(rand() % 100);
- }
- }
- printf("Done sending 80 notes at 4 notes per second.\n");
- } else {
- PmError err = 0;
- printf("ready to note-on... (type ENTER):");
- WAIT_FOR_ENTER
- buffer[0].timestamp = Pt_Time();
- buffer[0].message = Pm_Message(0x90, 60, 100);
- if ((err = Pm_Write(midi, buffer, 1))) {
- printf("Pm_Write returns error: %d (%s)\n",
- err, Pm_GetErrorText(err));
- if (err == pmHostError) {
- char errmsg[128];
- Pm_GetHostErrorText(errmsg, 127);
- printf(" Host error: %s\n", errmsg);
- }
- }
- printf("ready to note-off... (type ENTER):");
- WAIT_FOR_ENTER
- buffer[0].timestamp = Pt_Time();
- buffer[0].message = Pm_Message(0x90, 60, 0);
- if ((err = Pm_Write(midi, buffer, 1))) {
- printf("Pm_Write returns error: %d (%s)\n",
- err, Pm_GetErrorText(err));
- if (err == pmHostError) {
- char errmsg[128];
- Pm_GetHostErrorText(errmsg, 127);
- printf(" Host error: %s\n", errmsg);
- }
- }
-
- /* output short note on/off w/latency offset; hold until user prompts */
- printf("ready to note-on (short form)... (type ENTER):");
- WAIT_FOR_ENTER
- Pm_WriteShort(midi, Pt_Time(),
- Pm_Message(0x90, 60, 100));
- printf("ready to note-off (short form)... (type ENTER):");
- WAIT_FOR_ENTER
- Pm_WriteShort(midi, Pt_Time(),
- Pm_Message(0x90, 60, 0));
-
- /* output several note on/offs to test timing.
- Should be 1s between notes */
- if (latency == 0) {
- printf("chord should not arpeggiate, latency == 0\n");
- } else {
- printf("chord should arpeggiate (latency = %ld > 0\n",
- (long) latency);
- }
- printf("ready to chord-on/chord-off... (type ENTER):");
- WAIT_FOR_ENTER
- timestamp = Pt_Time();
- printf("starting timestamp %ld\n", (long) timestamp);
- for (i = 0; i < chord_size; i++) {
- buffer[i].timestamp = timestamp + 1000 * i;
- buffer[i].message = Pm_Message(0x90, chord[i], 100);
- }
- Pm_Write(midi, buffer, chord_size);
-
- off_time = timestamp + 1000 + chord_size * 1000;
- while (Pt_Time() < off_time)
- /* There was a report that Pm_Write with zero length sent last
- * message again, so call Pm_Write here to see if note repeats
- */
- Pm_Write(midi, buffer, 0);
- Pt_Sleep(20); /* wait */
-
- for (i = 0; i < chord_size; i++) {
- buffer[i].timestamp = timestamp + 1000 * i;
- buffer[i].message = Pm_Message(0x90, chord[i], 0);
- }
- Pm_Write(midi, buffer, chord_size);
- }
-
- /* close device (this not explicitly needed in most implementations) */
- printf("ready to close and terminate... (type ENTER):");
- WAIT_FOR_ENTER
-
- Pm_Close(midi);
- Pm_Terminate();
- printf("done closing and terminating...\n");
-}
-
-
-void main_test_both()
-{
- int i = 0;
- int in, out;
- PmStream * midi, * midiOut;
- PmEvent buffer[1];
- PmError status, length;
- int num = 11;
-
- in = get_number("Type input number: ");
- out = get_number("Type output number: ");
-
- /* In is recommended to start timer before PortMidi */
- TIME_START;
-
- Pm_OpenOutput(&midiOut,
- out,
- sysdepinfo,
- OUTPUT_BUFFER_SIZE,
- TIME_PROC,
- TIME_INFO,
- latency);
- printf("Midi Output opened with %ld ms latency.\n", (long) latency);
- /* open input device */
- Pm_OpenInput(&midi,
- in,
- sysdepinfo,
- INPUT_BUFFER_SIZE,
- TIME_PROC,
- TIME_INFO);
- printf("Midi Input opened. Reading %d Midi messages...\n", num);
- Pm_SetFilter(midi, PM_FILT_ACTIVE | PM_FILT_CLOCK);
- /* empty the buffer after setting filter, just in case anything
- got through */
- while (Pm_Poll(midi)) {
- Pm_Read(midi, buffer, 1);
- }
- i = 0;
- while (i < num) {
- status = Pm_Poll(midi);
- if (status == TRUE) {
- length = Pm_Read(midi,buffer,1);
- if (length > 0) {
- Pm_Write(midiOut, buffer, 1);
- printf("Got message %d @ time %ld: timestamp %ld, "
- "%2lx %2lx %2lx\n", i, (long) Pt_Time(),
- (long) buffer[0].timestamp,
- (long) Pm_MessageStatus(buffer[0].message),
- (long) Pm_MessageData1(buffer[0].message),
- (long) Pm_MessageData2(buffer[0].message));
- i++;
- } else {
- assert(0);
- }
- }
- }
- /* allow time for last message to go out */
- Pt_Sleep(100 + latency);
-
- /* close midi devices */
- Pm_Close(midi);
- Pm_Close(midiOut);
- Pm_Terminate();
-}
-
-
-/* main_test_stream exercises windows winmm API's stream mode */
-/* The winmm stream mode is used for latency>0, and sends
- timestamped messages. The timestamps are relative (delta)
- times, whereas PortMidi times are absolute. Since peculiar
- things happen when messages are not always sent in advance,
- this function allows us to exercise the system and test it.
- */
-void main_test_stream() {
- PmStream * midi;
- PmEvent buffer[16];
-
- /* determine which output device to use */
- int i = get_number("Type output number: ");
-
- latency = 500; /* ignore LATENCY for this test and
- fix the latency at 500ms */
-
- /* It is recommended to start timer before PortMidi */
- TIME_START;
-
- /* open output device */
- Pm_OpenOutput(&midi,
- i,
- sysdepinfo,
- OUTPUT_BUFFER_SIZE,
- TIME_PROC,
- TIME_INFO,
- latency);
- printf("Midi Output opened with %ld ms latency.\n", (long) latency);
-
- /* output note on/off w/latency offset; hold until user prompts */
- printf("ready to send output... (type ENTER):");
- WAIT_FOR_ENTER
-
- /* if we were writing midi for immediate output, we could always use
- timestamps of zero, but since we may be writing with latency, we
- will explicitly set the timestamp to "now" by getting the time.
- The source of timestamps should always correspond to the TIME_PROC
- and TIME_INFO parameters used in Pm_OpenOutput(). */
- buffer[0].timestamp = Pt_Time();
- buffer[0].message = Pm_Message(0xC0, 0, 0);
- buffer[1].timestamp = buffer[0].timestamp;
- buffer[1].message = Pm_Message(0x90, 60, 100);
- buffer[2].timestamp = buffer[0].timestamp + 1000;
- buffer[2].message = Pm_Message(0x90, 62, 100);
- buffer[3].timestamp = buffer[0].timestamp + 2000;
- buffer[3].message = Pm_Message(0x90, 64, 100);
- buffer[4].timestamp = buffer[0].timestamp + 3000;
- buffer[4].message = Pm_Message(0x90, 66, 100);
- buffer[5].timestamp = buffer[0].timestamp + 4000;
- buffer[5].message = Pm_Message(0x90, 60, 0);
- buffer[6].timestamp = buffer[0].timestamp + 4000;
- buffer[6].message = Pm_Message(0x90, 62, 0);
- buffer[7].timestamp = buffer[0].timestamp + 4000;
- buffer[7].message = Pm_Message(0x90, 64, 0);
- buffer[8].timestamp = buffer[0].timestamp + 4000;
- buffer[8].message = Pm_Message(0x90, 66, 0);
-
- Pm_Write(midi, buffer, 9);
-#ifdef SEND8
- /* Now, we're ready for the real test.
- Play 4 notes at now, now+500, now+1000, and now+1500
- Then wait until now+2000.
- Play 4 more notes as before.
- We should hear 8 evenly spaced notes. */
- now = Pt_Time();
- for (i = 0; i < 4; i++) {
- buffer[i * 2].timestamp = now + (i * 500);
- buffer[i * 2].message = Pm_Message(0x90, 60, 100);
- buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
- buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
- }
- Pm_Write(midi, buffer, 8);
-
- while (Pt_Time() < now + 2500)
- Pt_Sleep(10);
- /* now we are 500 ms behind schedule, but since the latency
- is 500, the delay should not be audible */
- now += 2000;
- for (i = 0; i < 4; i++) {
- buffer[i * 2].timestamp = now + (i * 500);
- buffer[i * 2].message = Pm_Message(0x90, 60, 100);
- buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
- buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
- }
- Pm_Write(midi, buffer, 8);
-#endif
- /* close device (this not explicitly needed in most implementations) */
- printf("ready to close and terminate... (type ENTER):");
- WAIT_FOR_ENTER
-
- Pm_Close(midi);
- Pm_Terminate();
- printf("done closing and terminating...\n");
-}
-
-
-void show_usage()
-{
- printf("Usage: test [-h] [-l latency-in-ms] [-c clientname] "
- "[-p portname] [-v]\n"
- " -h for this help message (only)\n"
- " -l for latency\n"
- " -c name designates a client name (linux only),\n"
- " -p name designates a port name (linux only),\n"
- " -v for verbose (enables more output)\n");
-}
-
-int main(int argc, char *argv[])
-{
- int default_in;
- int default_out;
- int i = 0, n = 0;
- int test_input = 0, test_output = 0, test_both = 0, somethingStupid = 0;
- int isochronous_test = 0;
- int stream_test = 0;
- int latency_valid = FALSE;
-
- show_usage();
- if (sizeof(void *) == 8)
- printf("Apparently this is a 64-bit machine.\n");
- else if (sizeof(void *) == 4)
- printf ("Apparently this is a 32-bit machine.\n");
-
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-h") == 0) {
- exit(0);
- } else if (strcmp(argv[i], "-p") == 0 && (i + 1 < argc)) {
- i = i + 1;
- const char *port_name = argv[i];
- set_sysdepinfo('p', port_name);
- printf("Port name will be %s\n", port_name);
- } else if (strcmp(argv[i], "-c") == 0 && (i + 1 < argc)) {
- i = i + 1;
- set_sysdepinfo('c', argv[i]);
- printf("Client name will be %s\n", argv[i]);
- } else if (strcmp(argv[i], "-l") == 0 && (i + 1 < argc)) {
- i = i + 1;
- latency = atoi(argv[i]);
- printf("Latency will be %ld\n", (long) latency);
- latency_valid = TRUE;
- } else if (strcmp(argv[i], "-v") == 0) {
- printf("Verbose is now TRUE\n");
- verbose = TRUE; /* not currently used for anything */
- } else {
- show_usage();
- exit(0);
- }
- }
-
- while (!latency_valid) {
- int lat; // declared int to match "%d"
- printf("Latency in ms: ");
- if (scanf("%d", &lat) == 1) {
- latency = (int32_t) lat; // coerce from "%d" to known size
- latency_valid = TRUE;
- }
- }
-
- /* determine what type of test to run */
- printf("begin portMidi test...\n");
- printf("enter your choice...\n 1: test input\n"
- " 2: test input (fail w/assert)\n"
- " 3: test input (fail w/NULL assign)\n"
- " 4: test output\n 5: test both\n"
- " 6: stream test (for WinMM)\n"
- " 7. isochronous out\n");
- while (n != 1) {
- n = scanf("%d", &i);
- WAIT_FOR_ENTER
- switch(i) {
- case 1:
- test_input = 1;
- break;
- case 2:
- test_input = 1;
- somethingStupid = 1;
- break;
- case 3:
- test_input = 1;
- somethingStupid = 2;
- break;
- case 4:
- test_output = 1;
- break;
- case 5:
- test_both = 1;
- break;
- case 6:
- stream_test = 1;
- break;
- case 7:
- test_output = 1;
- isochronous_test = 1;
- break;
- default:
- printf("got %d (invalid input)\n", n);
- break;
- }
- }
-
- /* list device information */
- default_in = Pm_GetDefaultInputDeviceID();
- default_out = Pm_GetDefaultOutputDeviceID();
- for (i = 0; i < Pm_CountDevices(); i++) {
- char *deflt;
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (((test_input | test_both) & info->input) |
- ((test_output | test_both | stream_test) & info->output)) {
- printf("%d: %s, %s", i, info->interf, info->name);
- if (info->input) {
- deflt = (i == default_in ? "default " : "");
- printf(" (%sinput)", deflt);
- }
- if (info->output) {
- deflt = (i == default_out ? "default " : "");
- printf(" (%soutput)", deflt);
- }
- printf("\n");
- }
- }
-
- /* run test */
- if (stream_test) {
- main_test_stream();
- } else if (test_input) {
- main_test_input(somethingStupid);
- } else if (test_output) {
- main_test_output(isochronous_test);
- } else if (test_both) {
- main_test_both();
- }
-
- printf("finished portMidi test...type ENTER to quit...");
- WAIT_FOR_ENTER
- return 0;
-}
diff --git a/portmidi/pm_test/txdata.syx b/portmidi/pm_test/txdata.syx
deleted file mode 100755
index 1e06e5a..0000000
--- a/portmidi/pm_test/txdata.syx
+++ /dev/null
@@ -1,257 +0,0 @@
-20 0 1d 4 c 6 0 34 1 4d 4 d 1f 7 3 6
- c 5e 4 4d d b 18 5 3 6 0 3d 1 4a 16 18
-1f 8 3 6 d 0 1 63 4 13 3a 23 0 0 0 2
- c 2 4 0 63 32 0 0 0 32 0 47 72 61 6e 64
-50 69 61 6e 6f 63 63 63 32 32 32 0 0 0 0 0
-10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 9 9 f c 27 2 35 37 10 1f 4 3 4
- d 19 4 56 5 16 1f f 8 d c 0 43 60 4 e
-1f c 3 7 e 0 43 63 5 10 3c 14 8 2 1b 56
- 5 2 4 0 63 32 0 0 0 32 0 4c 6f 54 69 6e
-65 38 31 5a 20 63 63 63 32 32 32 0 7f 0 1 0
-18 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f e f e 9 0 3 43 2d e 1f f 5 7
- f 16 43 5a 0 0 1f 12 6 8 d 0 3 63 4 0
-1f 12 6 8 f 0 2 63 4 6 34 14 0 1 2 4e
-18 2 4 0 63 32 0 32 0 32 0 44 79 6e 6f 6d
-69 74 65 45 50 63 63 63 32 32 32 0 70 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f b 1 b 8 18 40 5f a e 1f 1f 0 a
- f 0 40 5f 4 0 1f 1f 0 a f 0 40 63 5 6
-1f 1f 0 a f 0 40 5f 0 8 1f 20 0 3 0 5a
-18 4 4 0 63 32 32 0 0 32 0 50 65 72 63 4f
-72 67 61 6e 20 63 63 63 32 32 32 0 0 0 0 0
- 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f b 7 f 9 0 4 49 13 13 1f 8 7 5
- e 0 2 58 0 c 1f 6 4 6 f 23 3 46 10 a
-1f 7 8 c d 0 2 63 8 b 2 1c 0 0 0 52
-18 4 4 0 63 32 0 32 0 32 0 54 68 69 6e 20
-43 6c 61 76 20 63 63 63 32 32 32 0 70 0 20 0
-10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f c 0 6 1 a 4 50 20 e 1f c 0 6
- 1 a 4 50 1f 8 1f b 9 5 e 0 2 63 5 e
-1f b 9 5 e 0 3 63 4 8 4 1a 0 0 0 52
-1d 2 4 0 63 32 0 32 0 32 0 42 72 69 74 65
-43 65 6c 73 74 63 63 63 32 32 32 0 20 0 26 0
- 1 0 8 4 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 f 1f 4 8 f 0 3a 51 4 b e 1f 0 8
- f 0 22 4b 4 3 f 1a b 8 d 0 3b 36 9 3
-12 1f 0 8 f 0 22 5d 4 b 3a 1e 19 5 0 52
-18 4 4 0 63 32 0 0 0 32 0 54 72 75 6d 70
-65 74 38 31 5a 63 63 63 32 32 32 0 0 0 50 0
-51 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 c 5 0 8 0 0 2 4a 4 b f 1f 0 8
- f 0 2 3f 4 3 1f f 0 8 0 23 3 44 b 3
-10 1f 0 9 f 0 2 5e 4 c 3a 1f 19 7 0 52
-18 4 4 0 63 32 0 0 0 32 0 46 6c 75 67 65
-6c 68 6f 72 6e 63 63 63 32 32 32 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 10 1f 0 8 f 0 42 4a 0 3 11 1f 0 8
- f a 43 51 0 3 11 9 0 8 d 0 42 2b 16 6
-10 1f 0 9 f 0 42 63 4 b 3a 1e 9 9 0 5a
-24 4 4 0 63 32 31 0 0 32 0 52 61 73 70 41
-6c 74 6f 20 20 63 63 63 32 32 32 0 10 0 20 0
-54 0 20 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 10 9 2 6 d 0 41 3e 4 15 c b 2 3
- e 0 41 4f 4 12 c e 2 8 d 0 42 4b a 1c
- d b 1 9 e 0 3 63 a 14 0 23 f 2 1b 5e
-18 4 5 0 63 28 50 32 0 32 0 48 61 72 6d 6f
-6e 69 63 61 20 63 63 63 32 32 32 0 50 10 50 0
-50 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1c 2 0 4 e 63 0 4e 4 3 d 5 0 6
- e 63 1 56 a 8 12 7 0 6 9 63 2 47 1b e
- a a 0 5 f 0 1 63 4 b 32 1a 8 d 0 52
- c 4 4 0 63 32 0 0 0 32 0 44 6f 75 62 6c
-65 42 61 73 73 63 63 63 32 32 32 0 10 0 0 0
- 3 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 b 4 0 4 f 14 2 49 9 6 a 7 0 4
- f 14 2 51 a 0 8 1f 0 5 f 0 1 63 9 6
- a 1f 0 5 f 0 1 63 a 0 3c 1f 6 9 0 52
- 5 4 4 0 63 32 0 0 0 32 0 48 69 53 74 72
-69 6e 67 20 31 63 63 63 32 32 32 0 2 0 30 0
-32 0 10 5 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 10 13 f 4 a 0 3 3b 14 14 1f e 8 7
- 9 0 2 42 5 e 18 13 d 9 c 0 2 3c 13 8
-1f 11 7 4 f 0 42 63 4 10 3a 1b 0 0 0 52
-1d 4 4 0 63 32 0 0 0 32 0 48 61 72 70 20
-20 20 20 20 20 63 63 63 32 32 32 8 0 0 21 0
- 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 6 6 4 f 0 40 48 5 0 c 8 7 5
- f 5 0 52 4 0 f 7 3 7 e 8 3 63 4 6
- f 8 4 5 f 0 3 63 4 6 7c 1f 0 6 0 4a
-11 2 4 0 63 32 0 0 0 32 0 46 61 6e 66 61
-72 54 70 74 73 63 63 63 32 32 32 6 1 0 38 0
- 8 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 d b 0 1 c 0 2 2c 3d 3 d 7 0 1
- c 0 2 1f 3c 3 d 1f 0 5 f 0 2 63 5 6
- d 1f 0 5 f 0 2 63 4 0 3c 63 0 2f 0 53
-11 4 4 0 63 32 0 0 0 32 0 42 72 65 61 74
-68 4f 72 67 6e 63 63 63 32 32 32 4 30 5 50 0
-11 0 18 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 9 0 6 0 27 2 51 19 b 1c 6 0 8
- 0 37 2 47 a 3 1f a 0 9 0 3d 2 4d a e
-1f 12 8 8 f 0 3 61 4 b 28 1f 0 3 0 52
- c 3 4 0 63 32 1 32 0 32 0 4e 79 6c 6f 6e
-47 75 69 74 20 63 63 63 32 32 32 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f e e f f 0 3 48 2d 6 1f f 4 f
- f 25 3 5b 0 0 1f 12 6 c e 1c 3 55 0 10
-1f 13 7 8 e 6 4 62 4 e 3b 14 0 0 0 42
-18 2 4 0 63 32 0 32 0 32 0 47 75 69 74 61
-72 20 23 31 20 63 63 63 32 32 32 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 19 8 a 3 0 3 63 10 18 1f c 5 b
- 5 0 3 52 0 b 1f 19 6 b 5 0 3 63 a 16
-1f f 11 9 7 0 4 63 4 3 3a 14 0 0 0 42
-18 2 4 0 63 32 0 32 0 32 0 46 75 6e 6b 79
-20 50 69 63 6b 63 63 63 32 32 32 0 30 0 0 0
- 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 1 0 8 4 0 3 3d a 1e 1f 1 0 8
- 0 0 0 43 0 10 1f 9 6 8 c 1b 7 46 1c 1e
-1f 9 0 9 9 0 1 63 4 3 3a 1c 0 0 0 52
- c 4 5 0 63 4b 0 0 0 32 0 45 6c 65 63 42
-61 73 73 20 31 63 63 63 32 32 32 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f f f e 9 0 3 46 1d 16 1f f 5 e
- e d 3 63 0 b 1f 13 6 5 d 1c 3 63 0 0
-1f 13 6 8 f 0 4 63 4 6 3b 1f 0 0 0 42
- c 4 4 0 63 32 0 32 0 32 0 53 79 6e 46 75
-6e 6b 42 61 73 63 63 63 32 32 32 d 6c 0 0 0
-70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 10 7 8 3 0 3 4f 4 3 1f 9 0 8
- 0 0 1 4a 0 b 1f 11 0 8 0 0 1 47 4 8
-1f 9 0 8 0 0 0 63 0 b 39 19 0 7 0 52
- c 2 4 0 63 32 0 32 0 32 0 4c 61 74 65 6c
-79 42 61 73 73 63 63 63 32 32 32 2 0 0 0 0
-40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 13 12 0 9 d 22 0 51 0 b 1f 14 0 5
- 8 24 40 5c 0 3 1f 11 0 6 c 2c 0 53 9 0
-10 1f 0 b f 0 0 5c a e 3a 22 11 e 1e 5e
-18 7 4 0 63 32 0 32 0 32 0 53 79 6e 63 20
-4c 65 61 64 20 63 63 63 32 32 32 0 70 0 40 0
- 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 13 1e 0 9 e 0 0 63 3f b 1f 14 0 5
- e 24 1 51 4 3 1f 14 0 f 1 0 41 4d 8 3
- f 1f 0 b f 0 2 63 4 b 3b 20 11 12 33 56
-18 4 4 0 63 37 e 0 0 32 0 4a 61 7a 7a 20
-46 6c 75 74 65 63 63 63 32 32 32 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 15 13 d 3 d 1e 2 50 18 e 15 14 9 4
- c 1e 2 56 11 8 1b 1f f 7 f 0 1 63 4 6
-1a 1f e 6 f 0 2 63 4 0 7c b 0 8 0 62
-18 4 4 0 63 32 0 0 0 32 0 4a 61 76 61 20
-4a 69 76 65 20 63 63 63 32 32 32 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 0 0 4 f 0 40 63 3c 0 b 8 7 7
- f 5 0 63 4 6 f 5 3 7 f 8 0 3b 5 6
- e 8 4 5 f 0 3 63 3 0 7e 1d 6 f 0 4a
-11 0 4 0 63 32 0 0 0 32 0 42 61 61 64 42
-72 65 61 74 68 63 63 63 32 32 32 6 30 0 38 0
- 1 0 46 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 0 0 4 f 0 40 47 2f 0 e 8 7 7
- f 5 0 4c 0 6 13 1c d c 6 8 0 63 5 6
-14 11 d b 0 0 3 63 4 0 7a 10 0 51 0 68
-17 0 4 0 63 32 0 0 0 32 0 56 6f 63 61 6c
-4e 75 74 73 20 63 63 63 32 32 32 6 30 0 30 0
- 1 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 1f 0 5 f 0 0 41 32 3 1f 14 10 5
- 5 1 2 63 7 3 1f b 12 8 f 0 1 63 c 3
-1f 1f f 8 f 0 1 63 4 3 39 23 0 0 0 62
-18 7 4 0 63 32 0 0 0 32 0 57 61 74 65 72
-47 6c 61 73 73 63 63 63 32 32 32 0 0 0 0 0
- 0 0 0 7 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 16 2 0 4 6 9 1 4f 8 0 19 e 1 4
- 0 20 1 43 19 0 1f 12 10 6 7 0 0 54 3d 3
-16 d 6 6 2 1e 3 61 8 e 3a 20 1 14 0 42
- c 2 4 2 63 63 63 0 0 32 0 46 75 7a 7a 79
-20 4b 6f 74 6f 63 63 63 32 32 32 0 0 0 0 b
-50 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1c 8 0 3 e 0 1 55 12 3 1c 7 0 1
- e 2e 1 58 27 b e 4 0 2 a 0 2 63 4 a
- d 9 0 2 c 1 2 63 10 b 4 54 0 47 0 53
-18 7 4 0 63 32 0 0 0 32 0 42 72 74 68 62
-65 6c 6c 73 20 63 63 63 32 32 32 0 4 0 40 0
-40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1a 4 1 1 b 16 0 47 5 3 15 e 0 1
- d 0 0 4c 5 16 1c 6 4 2 7 0 0 63 4 16
-18 18 3 1 e 0 0 5e 4 10 24 7 0 4 0 62
-24 4 4 0 63 32 0 0 0 32 0 54 75 62 65 20
-42 65 6c 6c 73 63 63 63 32 32 32 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 1f 13 3 0 0 0 5f 3d 6 1f 12 13 2
- 0 0 1 52 5 2 1f 14 13 3 0 0 1 56 28 5
-1e b 13 f 9 0 0 63 6 3 3b 63 0 63 0 73
-23 7 4 0 63 32 0 0 0 32 0 4e 6f 69 73 65
-20 53 68 6f 74 63 63 63 32 32 32 8 0 0 0 8
- 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 1f 16 0 3 7 0 1 50 0 3 1f 18 3 3
- 3 22 0 63 0 14 1d 7 6 3 6 0 1 3c 8 3
-1f 5 7 3 0 0 1 63 4 1b 39 23 0 8 0 42
-18 4 4 0 63 32 0 0 0 32 0 48 61 6e 64 20
-44 72 75 6d 20 63 63 63 32 32 32 0 1 0 3 0
- 1 0 1 3 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- 0 0 7d f7 \ No newline at end of file
diff --git a/portmidi/pm_test/virttest.c b/portmidi/pm_test/virttest.c
deleted file mode 100644
index 1aeb09b..0000000
--- a/portmidi/pm_test/virttest.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/* virttest.c -- test for creating/deleting virtual ports */
-/*
- * Roger B. Dannenberg
- * Oct 2021
-
-This test is performed by running 2 instances of the program. The
-first instance makes input and output ports named portmidi and waits
-for a message. The second tries to do the same, but will fail because
-portmidi already exists. It then opens portmidi (both input and
-output). In greater detail:
-
-FIRST INSTANCE SECOND INSTANCE
--------------- ---------------
-
-initialize PortMidi initialize PortMidi
-create portmidi in
-create portmidi out
-wait for input
- create portmidi in -> fails
- open portmidi in/out
- send to portmidi
-recv from portmidi
-send to portmidi
-wait 1s recv from portmidi
- close portmidi in and out
- terminate PortMidi
-list all devices:
- - check for correct number
- - check for good description of portmidi in port (open)
- - check for good description of portmidi out port (open)
-close portmidi in
-list all devices:
- - check for correct number
- - check for good description of portmidi in port (closed)
- - check for good description of portmidi out port (open)
-close portmidi out
-list all devices:
- - check for correct number
- - check for good description of portmidi in port (closed)
- - check for good description of portmidi out port (closed)
-delete portmidi in
- - check for correct number
- - check for NULL description of portmidi in port
- - check for good description of portmidi out port (closed)
-delete portmidi out
- - check for correct number
- - check for NULL description of portmidi in port
- - check for NULL description of portmidi out port
-terminate portmidi
-REPEAT 3 TIMES wait 2 seconds to give head start to other instance
- REPEAT 3 TIMES
- */
-
-#include "portmidi.h"
-#include "porttime.h"
-#include "stdlib.h"
-#include "stdio.h"
-#include "string.h"
-#include "assert.h"
-
-#define OUTPUT_BUFFER_SIZE 0
-#define INPUT_BUFFER_SIZE 10
-#define DEVICE_INFO NULL
-#define DRIVER_INFO NULL
-#define TIME_PROC ((PmTimeProcPtr) Pt_Time)
-#define TIME_INFO NULL
-#define TIME_START Pt_Start(1, 0, 0) /* timer started w/millisecond accuracy */
-
-
-static void prompt_and_exit(void)
-{
- printf("type ENTER...");
- while (getchar() != '\n') ;
- /* this will clean up open ports: */
- exit(-1);
-}
-
-
-static PmError printerror(PmError err, const char *msg)
-{
- if (err == pmHostError) {
- /* it seems pointless to allocate memory and copy the string,
- * so I will do the work of Pm_GetHostErrorText directly
- */
- char errmsg[80];
- Pm_GetHostErrorText(errmsg, 80);
- printf("%s\n %s\n", msg, errmsg);
- } else if (err < 0) {
- printf("%s\n %s\n", msg, Pm_GetErrorText(err));
- }
- return err;
-}
-
-
-static PmError checkerror(PmError err)
-{
- if (err < 0) {
- printerror(err, "PortMidi call failed...");
- prompt_and_exit();
- }
- return err;
-}
-
-
-void wait_until(PmTimestamp when)
-{
- PtTimestamp now = Pt_Time();
- if (when > now) {
- Pt_Sleep(when - now);
- }
-}
-
-
-void show_usage()
-{
- printf("Usage: virttest\n"
- " run two instances to test virtual port create/delete\n");
-}
-
-
-void check_info(int id, char stat, int input, int virtual)
-{
- const PmDeviceInfo *info = Pm_GetDeviceInfo(id);
- if (stat == 'd') {
- if (info) {
- printf("Expected device %d to be deleted.\n", id);
- prompt_and_exit();
- }
- return;
- }
- if (!info) {
- printf("Expected device %d to not be deleted.\n", id);
- prompt_and_exit();
- }
- if (strcmp("portmidi", info->name) != 0) {
- printf("Device %d name is %s, not \"portmidi\".\n", id, info->name);
- prompt_and_exit();
- }
- if (info->input != input || (!info->output) != input) {
- printf("Device %d input/output fields are wrong.\n", id);
- prompt_and_exit();
- }
- if ((!info->opened && stat == 'o') || (info->opened && stat == 'c')) {
- printf("Device %d opened==%d, status should be %c.\n", id,
- info->opened, stat);
- prompt_and_exit();
- }
- if (info->is_virtual != virtual) {
- printf("Expected device %d to be virtual.\n", id);
- prompt_and_exit();
- }
-}
-
-
-/* stat is 'o' for open, 'c' for closed, 'd' for deleted device */
-void check_ports(int cnt, int in_id, char in_stat,
- int out_id, char out_stat, int virtual)
-{
- if (cnt != Pm_CountDevices()) {
- printf("Device count changed from %d to %d.\n", cnt, Pm_CountDevices());
- prompt_and_exit();
- }
- check_info(in_id, in_stat, TRUE, virtual);
- check_info(out_id, out_stat, FALSE, virtual);
-}
-
-
-void devices_list()
-{
- int i;
- for (i = 0; i < Pm_CountDevices(); i++) {
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (info) {
- printf("%d: %s %s %s %s\n", i, info->name,
- (info->input ? "input" : "output"),
- (info->is_virtual ? "virtual" : "real_device"),
- (info->opened ? "opened" : "closed"));
- }
- }
-}
-
-
-void test2()
-{
- PmStream *out = NULL;
- PmStream *in = NULL;
- int out_id;
- int in_id;
- PmEvent buffer[1];
- PmTimestamp timestamp;
- int pitch = 60;
- int device_count = 0;
- int i;
-
- printf("This must be virttest instance #2\n");
-
- /* find and open portmidi in and out */
- device_count = Pm_CountDevices();
- for (i = 0; i < device_count; i++) {
- const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
- if (info && strcmp(info->name, "portmidi") == 0) {
- if (info->input) {
- checkerror(Pm_OpenInput(&in, i, DRIVER_INFO,
- INPUT_BUFFER_SIZE, TIME_PROC, TIME_INFO));
- in_id = i;
- } else {
- checkerror(Pm_OpenOutput(&out, i, DRIVER_INFO,
- OUTPUT_BUFFER_SIZE, NULL, NULL, 0));
- out_id = i;
- }
- }
- }
- if (!in) {
- printf("Did not open portmidi as input (virtual output).\n");
- prompt_and_exit();
- }
- if (!out) {
- printf("Did not open portmidi as output (virtual input).\n");
- prompt_and_exit();
- }
- printf("Input device %d and output device %d are open.\n", in_id, out_id);
-
- /* send a message */
- buffer[0].timestamp = 0;
- buffer[0].message = Pm_Message(0x90, pitch, 100);
- checkerror(Pm_Write(out, buffer, 1));
-
- /* wait for reply */
- printf("Sent message, waiting for reply...\n");
- while (Pm_Read(in, buffer, 1) < 1) Pt_Sleep(10);
-
- printf("********** GOT THE MESSAGE, SHUTTING DOWN ************\n");
-
- /* close in */
- checkerror(Pm_Close(in));
- check_ports(device_count, in_id, 'c', out_id, 'o', FALSE);
- printf("Closed input %d\n", in_id);
-
- /* close out */
- checkerror(Pm_Close(out));
- check_ports(device_count, in_id, 'c', out_id, 'c', FALSE);
- printf("Closed output %d\n", out_id);
-
- Pt_Sleep(1000);
- /* wrap it up */
- Pm_Terminate();
- printf("Got reply and terminated...\n");
- Pt_Sleep(2000); /* 2 seconds because other is waiting 1s. */
- /* 1 more second to make sure other shuts down before test repeats. */
-}
-
-extern int pm_check_errors;
-
-void test()
-{
- PmStream *out;
- PmStream *in;
- int out_id;
- int in_id;
- PmEvent buffer[1];
- PmTimestamp timestamp;
- int device_count = 0;
-
- TIME_START;
-
- printf("******** INITIALIZING PORTMIDI ***********\n");
- timestamp = Pt_Time();
- Pm_Initialize();
- printf("Pm_Initialize took %dms\n", Pt_Time() - timestamp);
- devices_list();
-
- pm_check_errors = FALSE; /* otherwise, PM_CHECK_ERRORS, if defined, */
- /* can cause this program to report an error and exit on pmNameConflict. */
- in_id = Pm_CreateVirtualInput("portmidi", NULL, DEVICE_INFO);
- pm_check_errors = TRUE; /* there should be no other errors */
- if (in_id < 0) {
- printerror(in_id, "Pm_CreateVirtualInput failed...");
- test2();
- return;
- }
- printf("Created portmidi virtual input; this is virttest instance #1\n");
- out_id = checkerror(Pm_CreateVirtualOutput("portmidi", NULL, DRIVER_INFO));
- device_count = Pm_CountDevices();
-
- checkerror(Pm_OpenInput(&in, in_id, NULL, 0, NULL, NULL));
- checkerror(Pm_OpenOutput(&out, out_id, DRIVER_INFO, OUTPUT_BUFFER_SIZE,
- TIME_PROC, TIME_INFO, 0));
- printf("Created/Opened input %d and output %d\n", in_id, out_id);
- Pm_SetFilter(in, PM_FILT_ACTIVE | PM_FILT_CLOCK | PM_FILT_SYSEX);
- /* empty the buffer after setting filter, just in case anything
- got through */
- while (Pm_Read(in, buffer, 1)) ;
-
- /* wait for input */
- printf("Waiting for input...\n");
- while (Pm_Read(in, buffer, 1) < 1) Pt_Sleep(10);
-
- /* send two replies (only one would be fine) */
- checkerror(Pm_Write(out, buffer, 1));
- printf("Received input, writing output...\n");
-
- /* wait 1s so receiver can get the message before we shut down */
- Pt_Sleep(1000);
- printf("****** Closing everything and shutting down...\n");
-
- /* expect 2 open ports */
- check_ports(device_count, in_id, 'o', out_id, 'o', TRUE);
- /* close in */
- checkerror(Pm_Close(in));
- check_ports(device_count, in_id, 'c', out_id, 'o', TRUE);
-
- /* close out */
- checkerror(Pm_Close(out));
- check_ports(device_count, in_id, 'c', out_id, 'c', TRUE);
-
- /* delete in */
- checkerror(Pm_DeleteVirtualDevice(in_id));
- check_ports(device_count, in_id, 'd', out_id, 'c', TRUE);
-
- /* delete out */
- checkerror(Pm_DeleteVirtualDevice(out_id));
- check_ports(device_count, in_id, 'd', out_id, 'd', TRUE);
-
- /* we are done */
- Pm_Terminate();
-}
-
-
-int main(int argc, char *argv[])
-{
- int i;
- show_usage();
- for (i = 0; i < 3; i++) {
- test();
- }
- printf("finished virttest (SUCCESS). Type ENTER to quit...");
- while (getchar() != '\n') ;
- return 0;
-}
diff --git a/portmidi/pm_win/README_WIN.txt b/portmidi/pm_win/README_WIN.txt
deleted file mode 100755
index 8bfb467..0000000
--- a/portmidi/pm_win/README_WIN.txt
+++ /dev/null
@@ -1,174 +0,0 @@
-File: PortMidi Win32 Readme
-Author: Belinda Thom, June 16 2002
-Revised by: Roger Dannenberg, June 2002, May 2004, June 2007,
- Umpei Kurokawa, June 2007
- Roger Dannenberg Sep 2009, May 2022
-
-Contents:
- Using Portmidi
- To Install Portmidi
- To Compile Portmidi
- About Cmake
- Using other versions of Visual C++
- To Create Your Own Portmidi Client Application
-
-
-
-=============================================================================
-USING PORTMIDI:
-=============================================================================
-
-I recommend building a static library and linking with your
-application. PortMidi is not large. See ../README.md for
-basic compiling instructions.
-
-The Windows version has a couple of extra switches: You can define
-DEBUG and MMDEBUG for a few extra messages (see the code).
-
-If PM_CHECK_ERRORS is defined, PortMidi reports and exits on any
-error. This requires terminal output to see, and aborts your
-application, so it's only intended for quick command line programs
-where you do not care to check return values and handle errors
-more robustly.
-
-PortMidi is designed to run without a console and should work perfectly
-well within a graphical user interface application.
-
-Read the portmidi.h file for PortMidi API details on using the PortMidi API.
-See <...>\pm_test\testio.c and other files in pm_test for usage examples.
-
-There are many other programs in pm_test, including a MIDI monitor.
-
-
-============================================================================
-DESIGN NOTES
-============================================================================
-
-Orderly cleanup after errors are encountered is based on a fixed order of
-steps and state changes to reflect each step. Here's the order:
-
-To open input:
- initialize return value to NULL
- - allocate the PmInternal strucure (representation of PortMidiStream)
- return value is (non-null) PmInternal structure
- - allocate midi buffer
- set buffer field of PmInternal structure
- - call system-dependent open code
- - allocate midiwinmm_type for winmm dependent data
- set descriptor field of PmInternal structure
- - open device
- set handle field of midiwinmm_type structure
- - allocate buffers
- - start device
- - return
- - return
-
-SYSEX HANDLING
-
-There are three cases: simple output, stream output, input
-Each must deal with:
- 1. Buffer Initialization (creating buffers)
- 2. Buffer Allocation (finding a free buffer)
- 3. Buffer Fill (putting bytes in the buffer)
- 4. Buffer Preparation (midiOutPrepare, etc.)
- 5. Buffer Send (to Midi device)
- 6. Buffer Receive (in callback)
- 7. Buffer Empty (removing bytes from buffer)
- 8. Buffer Free (returning to the buffer pool)
- 9. Buffer Finalization (returning to heap)
-
-Here's how simple output handles sysex:
- 1. Buffer Initialization (creating buffers)
- allocated when code tries to write first byte to a buffer
- the test is "if (!m->sysex_buffers[0]) { ... }"
- this field is initialized to NULL when device is opened
- the size is SYSEX_BYTES_PER_BUFFER
- allocate_sysex_buffers() does the initialization
- note that the actual size of the allocation includes
- additional space for a MIDIEVENT (3 longs) which are
- not used in this case
- 2. Buffer Allocation (finding a free buffer)
- see get_free_sysex_buffer()
- cycle through m->sysex_buffers[] using m->next_sysex_buffer
- to determine where to look next
- if nothing is found, wait by blocking on m->sysex_buffer_signal
- this is signaled by the callback every time a message is
- received
- 3. Buffer Fill (putting bytes in the buffer)
- essentially a state machine approach
- hdr->dwBytesRecorded is a position in message pointed to by m->hdr
- keep appending bytes until dwBytesRecorded >= SYSEX_BYTES_PER_BUFFER
- then send the message, reseting the state to initial values
- 4. Buffer Preparation (midiOutPrepare, etc.)
- just before sending in winmm_end_sysex()
- 5. Buffer Send (to Midi device)
- message is padded with zero at end (since extra space was allocated
- this is ok) -- the zero works around a bug in (an old version of)
- MIDI YOKE drivers
- dwBufferLength gets dwBytesRecorded, and dwBytesRecorded gets 0
- uses midiOutLongMsg()
- 6. Buffer Receive (in callback)
- 7. Buffer Empty (removing bytes from buffer)
- not applicable for output
- 8. Buffer Free (returning to the buffer pool)
- unprepare message to indicate that it is free
- SetEvent on m->buffer_signal in case client is waiting
- 9. Buffer Finalization (returning to heap)
- when device is closed, winmm_out_delete frees all sysex buffers
-
-Here's how stream output handles sysex:
- 1. Buffer Initialization (creating buffers)
- same code as simple output (see above)
- 2. Buffer Allocation (finding a free buffer)
- same code as simple output (see above)
- 3. Buffer Fill (putting bytes in the buffer)
- essentially a state machine approach
- m->dwBytesRecorded is a position in message
- keep appending bytes until buffer is full (one byte to spare)
- 4. Buffer Preparation (midiOutPrepare, etc.)
- done before sending message
- dwBytesRecorded and dwBufferLength are set in winmm_end_sysex
- 5. Buffer Send (to Midi device)
- uses midiStreamOutMsg()
- 6. Buffer Receive (in callback)
- 7. Buffer Empty (removing bytes from buffer)
- not applicable for output
- 8. Buffer Free (returning to the buffer pool)
- unprepare message to indicate that it is free
- SetEvent on m->buffer_signal in case client is waiting
- 9. Buffer Finalization (returning to heap)
- when device is closed, winmm_out_delete frees all sysex buffers
-
-
-Here's how input handles sysex:
- 1. Buffer Initialization (creating buffers)
- two buffers are allocated in winmm_in_open
- 2. Buffer Allocation (finding a free buffer)
- same code as simple output (see above)
- 3. Buffer Fill (putting bytes in the buffer)
- not applicable for input
- 4. Buffer Preparation (midiOutPrepare, etc.)
- done before sending message -- in winmm_in_open and in callback
- 5. Buffer Send (to Midi device)
- uses midiInAddbuffer in allocate_sysex_input_buffer (called from
- winmm_in_open) and callback
- 6. Buffer Receive (in callback)
- 7. Buffer Empty (removing bytes from buffer)
- done without pause in loop in callback
- 8. Buffer Free (returning to the buffer pool)
- done by midiInAddBuffer in callback, no pointer to buffers
- is retained except by device
- 9. Buffer Finalization (returning to heap)
- when device is closed, empty buffers are delivered to callback,
- which frees them
-
-IMPORTANT: In addition to the above, PortMidi now has
-"shortcuts" to optimize the transfer of sysex data. To enable
-the optimization for sysex output, the system-dependent code
-sets fields in the pmInternal structure: fill_base, fill_offset_ptr,
-and fill_length. When fill_base is non-null, the system-independent
-part of PortMidi is allowed to directly copy sysex bytes to
-"fill_base[*fill_offset_ptr++]" until *fill_offset_ptr reaches
-fill_length. See the code for details.
-
-
diff --git a/portmidi/pm_win/debugging_dlls.txt b/portmidi/pm_win/debugging_dlls.txt
deleted file mode 100755
index 82b81a5..0000000
--- a/portmidi/pm_win/debugging_dlls.txt
+++ /dev/null
@@ -1,145 +0,0 @@
-========================================================================================================================
-Methods for Debugging DLLs
-========================================================================================================================
-If you have the source for both the DLL and the calling program, open the project for the calling executable file and
-debug the DLL from there. If you load a DLL dynamically, you must specify it in the Additional DLLs category of the
-Debug tab in the Project Settings dialog box.
-
-If you have the source for the DLL only, open the project that builds the DLL. Use the Debug tab in the Project
-Settings dialog box to specify the executable file that calls the DLL.
-
-You can also debug a DLL without a project. For example, maybe you just picked up a DLL and source code but you
-don’t have an associated project or workspace. You can use the Open command on the File menu to select the .DLL
-file you want to debug. The debug information should be in either the .DLL or the related .PDB file. After
-Visual C++ opens the file, on the Build menu click Start Debug and Go to begin debugging.
-
-To debug a DLL using the project for the executable file
-
-From the Project menu, click Settings.
-The Project Settings dialog box appears.
-
-Choose the Debug tab.
-
-
-In the Category drop-down list box, select General.
-
-
-In the Program Arguments text box, type any command-line arguments required by the executable file.
-
-
-In the Category drop-down list box, select Additional DLLs.
-
-
-In the Local Name column, type the names of DLLs to debug.
-If you are debugging remotely, the Remote Name column appears. In this column, type the complete path for the
-remote module to map to the local module name.
-
-In the Preload column, select the check box if you want to load the module before debugging begins.
-
-
-Click OK to store the information in your project.
-
-
-From the Build menu, click Start Debug and Go to start the debugger.
-You can set breakpoints in the DLL or the calling program. You can open a source file for the DLL and set breakpoints
-in that file, even though it is not a part of the executable file’s project.
-
-To debug a DLL using the project for the DLL
-
-From the Project menu, click Settings.
-The Project Settings dialog box appears.
-
-Choose the Debug tab.
-
-
-In the Category drop-down list box, select General.
-
-
-In the Executable For Debug Session text box, type the name of the executable file that calls the DLL.
-
-
-In the Category list box, select Additional DLLs.
-
-
-In the Local Module Name column, type the name of the DLLs you want to debug.
-
-
-Click OK to store the information in your project.
-
-
-Set breakpoints as required in your DLL source files or on function symbols in the DLL.
-
-
-From the Build menu, click Start Debug and Go to start the debugger.
-To debug a DLL created with an external project
-
-From the Project menu, click Settings.
-The Project Settings dialog box appears.
-
-Choose the Debug tab.
-
-
-In the Category drop-down list box, select General.
-
-
-In the Executable For Debug Session text box, type the name of the DLL that your external makefile builds.
-
-
-Click OK to store the information in your project.
-
-
-Build a debug version of the DLL with symbolic debugging information, if you don’t already have one.
-
-
-Follow one of the two procedures immediately preceding this one to debug the DLL.
-
-========================================================================================================================
-Why Don’t My DLL Breakpoints Work?
-========================================================================================================================
-Some reasons why your breakpoints don’t work as expected are listed here, along with solutions or work-arounds for each.
-If you follow the instructions in one topic and are still having breakpoint problems, look at some of the other topics.
-Often breakpoint problems result from a combination of conditions.
-
-You can't set a breakpoint in a source file when the corresponding symbolic information isn't loaded into memory by
-the debugger.
-You cannot set a breakpoint in any source file when the corresponding symbolic information will not be loaded into memory
-by the debugger.
-Symptoms include messages such as "the breakpoint cannot be set" or a simple, noninformational beep.
-
-When setting breakpoints before the code to be debugged has been started, the debugger uses a breakpoint list to keep
-track of how and where to set breakpoints. When you actually begin the debugging session, the debugger loads the symbolic
-information for all the code to be debugged and then walks through its breakpoint list, attempting to set the
-breakpoints.
-
-However, if one or more of the code modules have not been designated to the debugger, there will be no symbolic
-information for the debugger to use when walking through its breakpoint list. Situations where this is likely to
-occur include:
-
-Attempts to set breakpoints in a DLL before the call to LoadLibrary.
-
-Setting a breakpoint in an ActiveX server before the container has started the server.
-
-Other similar cases.
-
-To prevent this behavior in Visual C++, specify all additional DLLs and COM servers in the Additional DLLs field
-in the Debug/Options dialog box to notify the debugger that you want it to load symbolic debug information for
-additional .DLL files. When this has been done, breakpoints set in code that has not yet been loaded into memory
-will be "virtual" breakpoints. When the code is actually loaded into memory by the loader, these become physical
-breakpoints. Make sure that these additional debugging processes are not already running when you start your
-debugging session. The debugging process and these additional processes must be sychronized at the same beginning
-point to work correctly, hitting all breakpoints.
-
-Breakpoints are missed when more than one copy of a DLL is on your hard disk.
-Having more than one copy of a DLL on your hard drive, especially if it is in your Windows directory, can cause
-debugger confusion. The debugger will load the symbolic information for the DLL specified to it at run time (with the
-Additional DLLs field in the Debug/Options dialog box), while Windows has actually loaded a different copy of the
-DLL itself into memory. Because there is no way to force the debugger to load a specific DLL, it is a good idea to
-keep only one version of a DLL at a time in your path, current directory, and Windows directory.
-
-You can’t set "Break When Expression Has Changed" breakpoints on a variable local to a DLL.
-Setting a "Break When Expression Has Changed" breakpoint on a variable local to a DLL function before the call
-to LoadLibrary causes the breakpoint to be virtual (there are no physical addresses for the DLL in memory yet).
-Virtual breakpoints involving expressions pose a special problem. The DLL must be specified to the debugger at
-startup (causing its symbolic information to be loaded). In addition, the DLL's executable code must also be loaded
-into memory before this kind of breakpoint can be set. This means that the calling application's code must be
-executed to the point after its call to LoadLibrary before the debugger will allow this type of breakpoint to be set.
diff --git a/portmidi/pm_win/pmwin.c b/portmidi/pm_win/pmwin.c
deleted file mode 100755
index 5cb73b0..0000000
--- a/portmidi/pm_win/pmwin.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/* pmwin.c -- PortMidi os-dependent code */
-
-/* This file only needs to implement:
- pm_init(), which calls various routines to register the
- available midi devices,
- Pm_GetDefaultInputDeviceID(), and
- Pm_GetDefaultOutputDeviceID().
- This file must
- be separate from the main portmidi.c file because it is system
- dependent, and it is separate from, say, pmwinmm.c, because it
- might need to register devices for winmm, directx, and others.
-
- */
-
-#include "stdlib.h"
-#include "portmidi.h"
-#include "pmutil.h"
-#include "pminternal.h"
-#include "pmwinmm.h"
-#ifdef DEBUG
-#include "stdio.h"
-#endif
-#include <windows.h>
-
-/* pm_exit is called when the program exits.
- It calls pm_term to make sure PortMidi is properly closed.
- If DEBUG is on, we prompt for input to avoid losing error messages.
- */
-static void pm_exit(void) {
- pm_term();
-}
-
-
-static BOOL WINAPI ctrl_c_handler(DWORD fdwCtrlType)
-{
- exit(1); /* invokes pm_exit() */
- ExitProcess(1); /* probably never called */
- return TRUE;
-}
-
-/* pm_init is the windows-dependent initialization.*/
-void pm_init(void)
-{
- atexit(pm_exit);
- SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
-#ifdef DEBUG
- printf("registered pm_exit with atexit()\n");
-#endif
- pm_winmm_init();
- /* initialize other APIs (DirectX?) here */
-}
-
-
-void pm_term(void) {
- pm_winmm_term();
-}
-
-
-static PmDeviceID pm_get_default_device_id(int is_input, char *key) {
-#define PATTERN_MAX 256
- /* Find first input or device -- this is the default. */
- PmDeviceID id = pmNoDevice;
- int i;
- Pm_Initialize(); /* make sure descriptors exist! */
- for (i = 0; i < pm_descriptor_len; i++) {
- if (pm_descriptors[i].pub.input == is_input) {
- id = i;
- break;
- }
- }
- return id;
-}
-
-
-PmDeviceID Pm_GetDefaultInputDeviceID() {
- return pm_get_default_device_id(TRUE,
- "/P/M_/R/E/C/O/M/M/E/N/D/E/D_/I/N/P/U/T_/D/E/V/I/C/E");
-}
-
-
-PmDeviceID Pm_GetDefaultOutputDeviceID() {
- return pm_get_default_device_id(FALSE,
- "/P/M_/R/E/C/O/M/M/E/N/D/E/D_/O/U/T/P/U/T_/D/E/V/I/C/E");
-}
-
-
-#include "stdio.h"
-
-void *pm_alloc(size_t s) {
- return malloc(s);
-}
-
-
-void pm_free(void *ptr) {
- free(ptr);
-}
-
-
diff --git a/portmidi/pm_win/pmwinmm.c b/portmidi/pm_win/pmwinmm.c
deleted file mode 100755
index 6f4b6f3..0000000
--- a/portmidi/pm_win/pmwinmm.c
+++ /dev/null
@@ -1,1196 +0,0 @@
-/* pmwinmm.c -- system specific definitions */
-
-#ifndef _WIN32_WINNT
- /* without this define, InitializeCriticalSectionAndSpinCount is
- * undefined. This version level means "Windows 2000 and higher"
- */
- #define _WIN32_WINNT 0x0500
-#endif
-
-#define UNICODE 1
-#include <wchar.h>
-#include "windows.h"
-#include "mmsystem.h"
-#include "portmidi.h"
-#include "pmutil.h"
-#include "pminternal.h"
-#include "pmwinmm.h"
-#include <string.h>
-#include "porttime.h"
-#ifndef UNICODE
-#error Expected UNICODE to be defined
-#endif
-
-
-/* asserts used to verify portMidi code logic is sound; later may want
- something more graceful */
-#include <assert.h>
-#ifdef MMDEBUG
-/* this printf stuff really important for debugging client app w/host errors.
- probably want to do something else besides read/write from/to console
- for portability, however */
-#define STRING_MAX 80
-#include "stdio.h"
-#endif
-
-#define streql(x, y) (strcmp(x, y) == 0)
-
-#define MIDI_SYSEX 0xf0
-#define MIDI_EOX 0xf7
-
-/* callback routines */
-static void CALLBACK winmm_in_callback(HMIDIIN hMidiIn,
- UINT wMsg, DWORD_PTR dwInstance,
- DWORD_PTR dwParam1, DWORD_PTR dwParam2);
-static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,
- DWORD_PTR dwInstance,
- DWORD_PTR dwParam1,
- DWORD_PTR dwParam2);
-
-extern pm_fns_node pm_winmm_in_dictionary;
-extern pm_fns_node pm_winmm_out_dictionary;
-
-static void winmm_out_delete(PmInternal *midi); /* forward reference */
-
-/*
-A note about buffers: WinMM seems to hold onto buffers longer than
-one would expect, e.g. when I tried using 2 small buffers to send
-long sysex messages, at some point WinMM held both buffers. This problem
-was fixed by making buffers bigger. Therefore, it seems that there should
-be enough buffer space to hold a whole sysex message.
-
-The bufferSize passed into Pm_OpenInput (passed into here as buffer_len)
-will be used to estimate the largest sysex message (= buffer_len * 4 bytes).
-Call that the max_sysex_len = buffer_len * 4.
-
-For simple midi output (latency == 0), allocate 3 buffers, each with half
-the size of max_sysex_len, but each at least 256 bytes.
-
-For stream output, there will already be enough space in very short
-buffers, so use them, but make sure there are at least 16.
-
-For input, use many small buffers rather than 2 large ones so that when
-there are short sysex messages arriving frequently (as in control surfaces)
-there will be more free buffers to fill. Use max_sysex_len / 64 buffers,
-but at least 16, of size 64 bytes each.
-
-The following constants help to represent these design parameters:
-*/
-#define NUM_SIMPLE_SYSEX_BUFFERS 3
-#define MIN_SIMPLE_SYSEX_LEN 256
-
-#define MIN_STREAM_BUFFERS 16
-#define STREAM_BUFFER_LEN 24
-
-#define INPUT_SYSEX_LEN 64
-#define MIN_INPUT_BUFFERS 16
-
-/* if we run out of space for output (assume this is due to a sysex msg,
- expand by up to NUM_EXPANSION_BUFFERS in increments of EXPANSION_BUFFER_LEN
- */
-#define NUM_EXPANSION_BUFFERS 128
-#define EXPANSION_BUFFER_LEN 1024
-
-/* A sysex buffer has 3 DWORDS as a header plus the actual message size */
-#define MIDIHDR_SYSEX_BUFFER_LENGTH(x) ((x) + sizeof(long)*3)
-/* A MIDIHDR with a sysex message is the buffer length plus the header size */
-#define MIDIHDR_SYSEX_SIZE(x) (MIDIHDR_SYSEX_BUFFER_LENGTH(x) + sizeof(MIDIHDR))
-
-/*
-==============================================================================
-win32 mmedia system specific structure passed to midi callbacks
-==============================================================================
-*/
-
-/* global winmm device info */
-MIDIINCAPS *midi_in_caps = NULL;
-MIDIINCAPS midi_in_mapper_caps;
-UINT midi_num_inputs = 0;
-MIDIOUTCAPS *midi_out_caps = NULL;
-MIDIOUTCAPS midi_out_mapper_caps;
-UINT midi_num_outputs = 0;
-
-/* per device info */
-typedef struct winmm_info_struct {
- union {
- HMIDISTRM stream; /* windows handle for stream */
- HMIDIOUT out; /* windows handle for out calls */
- HMIDIIN in; /* windows handle for in calls */
- } handle;
-
- /* midi output messages are sent in these buffers, which are allocated
- * in a round-robin fashion, using next_buffer as an index
- */
- LPMIDIHDR *buffers; /* pool of buffers for midi in or out data */
- int max_buffers; /* length of buffers array */
- int buffers_expanded; /* buffers array expanded for extra msgs? */
- int num_buffers; /* how many buffers allocated in buffers array */
- int next_buffer; /* index of next buffer to send */
- HANDLE buffer_signal; /* used to wait for buffer to become free */
- unsigned long last_time; /* last output time */
- int first_message; /* flag: treat first message differently */
- int sysex_mode; /* middle of sending sysex */
- unsigned long sysex_word; /* accumulate data when receiving sysex */
- unsigned int sysex_byte_count; /* count how many received */
- LPMIDIHDR hdr; /* the message accumulating sysex to send */
- unsigned long sync_time; /* when did we last determine delta? */
- long delta; /* difference between stream time and
- real time */
- CRITICAL_SECTION lock; /* prevents reentrant callbacks (input only) */
-} winmm_info_node, *winmm_info_type;
-
-
-/*
-=============================================================================
-general MIDI device queries
-=============================================================================
-*/
-
-/* add a device after converting device (product) name to UTF-8 */
-static void pm_add_device_w(char *api, WCHAR *device_name, int is_input,
- int is_virtual, void *descriptor, pm_fns_type dictionary)
-{
- char utf8name[4 * MAXPNAMELEN];
- WideCharToMultiByte(CP_UTF8, 0, device_name, -1,
- utf8name, 4 * MAXPNAMELEN - 1, NULL, NULL);
- /* ignore errors here -- if pm_descriptor_max is exceeded,
- some devices will not be accessible. */
- pm_add_device(api, utf8name, is_input, is_virtual, descriptor, dictionary);
-}
-
-
-static void pm_winmm_general_inputs()
-{
- UINT i;
- WORD wRtn;
- midi_num_inputs = midiInGetNumDevs();
- midi_in_caps = (MIDIINCAPS *) pm_alloc(sizeof(MIDIINCAPS) *
- midi_num_inputs);
- if (midi_in_caps == NULL) {
- /* if you can't open a particular system-level midi interface
- * (such as winmm), we just consider that system or API to be
- * unavailable and move on without reporting an error.
- */
- return;
- }
-
- for (i = 0; i < midi_num_inputs; i++) {
- wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) & midi_in_caps[i],
- sizeof(MIDIINCAPS));
- if (wRtn == MMSYSERR_NOERROR) {
- pm_add_device_w("MMSystem", midi_in_caps[i].szPname, TRUE, FALSE,
- (void *) (intptr_t) i, &pm_winmm_in_dictionary);
- }
- }
-}
-
-
-static void pm_winmm_mapper_input()
-{
- WORD wRtn;
- /* Note: if MIDIMAPPER opened as input (documentation implies you
- can, but current system fails to retrieve input mapper
- capabilities) then you still should retrieve some form of
- setup info. */
- wRtn = midiInGetDevCaps((UINT) MIDIMAPPER,
- (LPMIDIINCAPS) & midi_in_mapper_caps,
- sizeof(MIDIINCAPS));
- if (wRtn == MMSYSERR_NOERROR) {
- pm_add_device_w("MMSystem", midi_in_mapper_caps.szPname, TRUE, FALSE,
- (void *) (intptr_t) MIDIMAPPER,
- &pm_winmm_in_dictionary);
- }
-}
-
-
-static void pm_winmm_general_outputs()
-{
- UINT i;
- DWORD wRtn;
- midi_num_outputs = midiOutGetNumDevs();
- midi_out_caps = pm_alloc(sizeof(MIDIOUTCAPS) * midi_num_outputs);
-
- if (midi_out_caps == NULL) {
- /* no error is reported -- see pm_winmm_general_inputs */
- return ;
- }
-
- for (i = 0; i < midi_num_outputs; i++) {
- wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) & midi_out_caps[i],
- sizeof(MIDIOUTCAPS));
- if (wRtn == MMSYSERR_NOERROR) {
- pm_add_device_w("MMSystem", midi_out_caps[i].szPname, FALSE, FALSE,
- (void *) (intptr_t) i, &pm_winmm_out_dictionary);
- }
- }
-}
-
-
-static void pm_winmm_mapper_output()
-{
- WORD wRtn;
- /* Note: if MIDIMAPPER opened as output (pseudo MIDI device
- maps device independent messages into device dependant ones,
- via NT midimapper program) you still should get some setup info */
- wRtn = midiOutGetDevCaps((UINT) MIDIMAPPER, (LPMIDIOUTCAPS)
- & midi_out_mapper_caps, sizeof(MIDIOUTCAPS));
- if (wRtn == MMSYSERR_NOERROR) {
- pm_add_device_w("MMSystem", midi_out_mapper_caps.szPname, FALSE, FALSE,
- (void *) (intptr_t) MIDIMAPPER,
- &pm_winmm_out_dictionary);
- }
-}
-
-
-/*
-============================================================================
-host error handling
-============================================================================
-*/
-
-static unsigned int winmm_check_host_error(PmInternal *midi)
-{
- return FALSE;
-}
-
-
-/*
-=============================================================================
-buffer handling
-=============================================================================
-*/
-static MIDIHDR *allocate_buffer(long data_size)
-{
- LPMIDIHDR hdr = (LPMIDIHDR) pm_alloc(MIDIHDR_SYSEX_SIZE(data_size));
- MIDIEVENT *evt;
- if (!hdr) return NULL;
- evt = (MIDIEVENT *) (hdr + 1); /* place MIDIEVENT after header */
- hdr->lpData = (LPSTR) evt;
- hdr->dwBufferLength = MIDIHDR_SYSEX_BUFFER_LENGTH(data_size);
- hdr->dwBytesRecorded = 0;
- hdr->dwFlags = 0;
- hdr->dwUser = hdr->dwBufferLength;
- return hdr;
-}
-
-
-static PmError allocate_buffers(winmm_info_type info, long data_size,
- long count)
-{
- int i;
- /* buffers is an array of count pointers to MIDIHDR/MIDIEVENT struct */
- info->num_buffers = 0; /* in case no memory can be allocated */
- info->buffers = (LPMIDIHDR *) pm_alloc(sizeof(LPMIDIHDR) * count);
- if (!info->buffers) return pmInsufficientMemory;
- info->max_buffers = count;
- for (i = 0; i < count; i++) {
- LPMIDIHDR hdr = allocate_buffer(data_size);
- if (!hdr) { /* free everything allocated so far and return */
- for (i = i - 1; i >= 0; i--) pm_free(info->buffers[i]);
- pm_free(info->buffers);
- info->max_buffers = 0;
- return pmInsufficientMemory;
- }
- info->buffers[i] = hdr; /* this may be NULL if allocation fails */
- }
- info->num_buffers = count;
- return pmNoError;
-}
-
-
-static LPMIDIHDR get_free_output_buffer(PmInternal *midi)
-{
- LPMIDIHDR r = NULL;
- winmm_info_type info = (winmm_info_type) midi->api_info;
- while (TRUE) {
- int i;
- for (i = 0; i < info->num_buffers; i++) {
- /* cycle through buffers, modulo info->num_buffers */
- info->next_buffer++;
- if (info->next_buffer >= info->num_buffers) info->next_buffer = 0;
- r = info->buffers[info->next_buffer];
- if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_buffer;
- }
- /* after scanning every buffer and not finding anything, block */
- if (WaitForSingleObject(info->buffer_signal, 1000) == WAIT_TIMEOUT) {
-#ifdef MMDEBUG
- printf("PortMidi warning: get_free_output_buffer() "
- "wait timed out after 1000ms\n");
-#endif
- /* if we're trying to send a sysex message, maybe the
- * message is too big and we need more message buffers.
- * Expand the buffer pool by 128KB using 1024-byte buffers.
- */
- /* first, expand the buffers array if necessary */
- if (!info->buffers_expanded) {
- LPMIDIHDR *new_buffers = (LPMIDIHDR *) pm_alloc(
- (info->num_buffers + NUM_EXPANSION_BUFFERS) *
- sizeof(LPMIDIHDR));
- /* if no memory, we could return a no-memory error, but user
- * probably will be unprepared to deal with it. Maybe the
- * MIDI driver is temporarily hung so we should just wait.
- * I don't know the right answer, but waiting is easier.
- */
- if (!new_buffers) continue;
- /* copy buffers to new_buffers and replace buffers */
- memcpy(new_buffers, info->buffers,
- info->num_buffers * sizeof(LPMIDIHDR));
- pm_free(info->buffers);
- info->buffers = new_buffers;
- info->max_buffers = info->num_buffers + NUM_EXPANSION_BUFFERS;
- info->buffers_expanded = TRUE;
- }
- /* next, add one buffer and return it */
- if (info->num_buffers < info->max_buffers) {
- r = allocate_buffer(EXPANSION_BUFFER_LEN);
- /* again, if there's no memory, we may not really be
- * dead -- maybe the system is temporarily hung and
- * we can just wait longer for a message buffer */
- if (!r) continue;
- info->buffers[info->num_buffers++] = r;
- goto found_buffer; /* break out of 2 loops */
- }
- /* else, we've allocated all NUM_EXPANSION_BUFFERS buffers,
- * and we have no free buffers to send. We'll just keep
- * polling to see if any buffers show up.
- */
- }
- }
-found_buffer:
- r->dwBytesRecorded = 0;
- /* actual buffer length is saved in dwUser field */
- r->dwBufferLength = (DWORD) r->dwUser;
- return r;
-}
-
-/*
-============================================================================
-begin midi input implementation
-============================================================================
-*/
-
-
-static unsigned int allocate_input_buffer(HMIDIIN h, long buffer_len)
-{
- LPMIDIHDR hdr = allocate_buffer(buffer_len);
- if (!hdr) return pmInsufficientMemory;
- /* note: pm_hosterror is normally a boolean, but here, we store Win
- * error code. The caller must test the value for nonzero, set
- * pm_hosterror_text, and then set pm_hosterror to TRUE */
- pm_hosterror = midiInPrepareHeader(h, hdr, sizeof(MIDIHDR));
- if (pm_hosterror) {
- pm_free(hdr);
- return pm_hosterror;
- }
- pm_hosterror = midiInAddBuffer(h, hdr, sizeof(MIDIHDR));
- return pm_hosterror;
-}
-
-
-static winmm_info_type winmm_info_create()
-{
- winmm_info_type info = (winmm_info_type) pm_alloc(sizeof(winmm_info_node));
- info->handle.in = NULL;
- info->handle.out = NULL;
- info->buffers = NULL; /* not used for input */
- info->num_buffers = 0; /* not used for input */
- info->max_buffers = 0; /* not used for input */
- info->buffers_expanded = FALSE; /* not used for input */
- info->next_buffer = 0; /* not used for input */
- info->buffer_signal = 0; /* not used for input */
- info->last_time = 0;
- info->first_message = TRUE; /* not used for input */
- info->sysex_mode = FALSE;
- info->sysex_word = 0;
- info->sysex_byte_count = 0;
- info->hdr = NULL; /* not used for input */
- info->sync_time = 0;
- info->delta = 0;
- return info;
-}
-
-
-static void report_hosterror(LPWCH error_msg)
-{
- WideCharToMultiByte(CP_UTF8, 0, error_msg, -1, pm_hosterror_text,
- sizeof(pm_hosterror_text), NULL, NULL);
- if (pm_hosterror == MMSYSERR_NOMEM) {
- /* add explanation to Window's confusing error message */
- /* if there's room: */
- if (PM_HOST_ERROR_MSG_LEN - strlen(pm_hosterror_text) > 60) {
- strcat_s(pm_hosterror_text, PM_HOST_ERROR_MSG_LEN,
- " Probably this MIDI device is open "
- "in another application.");
- }
- }
- pm_hosterror = TRUE;
-}
-
-
-static void report_hosterror_in()
-{
- WCHAR error_msg[PM_HOST_ERROR_MSG_LEN];
- int err = midiInGetErrorText(pm_hosterror, error_msg,
- PM_HOST_ERROR_MSG_LEN);
- assert(err == MMSYSERR_NOERROR);
- report_hosterror(error_msg);
-}
-
-
-static void report_hosterror_out()
-{
- WCHAR error_msg[PM_HOST_ERROR_MSG_LEN];
- int err = midiOutGetErrorText(pm_hosterror, error_msg,
- PM_HOST_ERROR_MSG_LEN);
- assert(err == MMSYSERR_NOERROR);
- report_hosterror(error_msg);
-}
-
-
-static PmError winmm_in_open(PmInternal *midi, void *driverInfo)
-{
- DWORD dwDevice;
- int i = midi->device_id;
- int max_sysex_len = midi->buffer_len * 4;
- int num_input_buffers = max_sysex_len / INPUT_SYSEX_LEN;
- winmm_info_type info;
-
- dwDevice = (DWORD) (intptr_t) pm_descriptors[i].descriptor;
-
- /* create system dependent device data */
- info = winmm_info_create();
- midi->api_info = info;
- if (!info) goto no_memory;
- /* 4000 is based on Windows documentation -- that's the value used
- in the memory manager. It's small enough that it should not
- hurt performance even if it's not optimal.
- */
- InitializeCriticalSectionAndSpinCount(&info->lock, 4000);
- /* open device */
- pm_hosterror = midiInOpen(
- &(info->handle.in), /* input device handle */
- dwDevice, /* device ID */
- (DWORD_PTR) winmm_in_callback, /* callback address */
- (DWORD_PTR) midi, /* callback instance data */
- CALLBACK_FUNCTION); /* callback is a procedure */
- if (pm_hosterror) goto free_descriptor;
-
- if (num_input_buffers < MIN_INPUT_BUFFERS)
- num_input_buffers = MIN_INPUT_BUFFERS;
- for (i = 0; i < num_input_buffers; i++) {
- if (allocate_input_buffer(info->handle.in, INPUT_SYSEX_LEN)) {
- /* either pm_hosterror was set, or the proper return code
- is pmInsufficientMemory */
- goto close_device;
- }
- }
- /* start device */
- pm_hosterror = midiInStart(info->handle.in);
- if (!pm_hosterror) {
- return pmNoError;
- }
-
- /* undo steps leading up to the detected error */
-
- /* ignore return code (we already have an error to report) */
- midiInReset(info->handle.in);
-close_device:
- midiInClose(info->handle.in); /* ignore return code */
-free_descriptor:
- midi->api_info = NULL;
- pm_free(info);
-no_memory:
- if (pm_hosterror) {
- report_hosterror_in();
- return pmHostError;
- }
- /* if !pm_hosterror, then the error must be pmInsufficientMemory */
- return pmInsufficientMemory;
- /* note: if we return an error code, the device will be
- closed and memory will be freed. It's up to the caller
- to free the parameter midi */
-}
-
-
-/* winmm_in_close -- close an open midi input device */
-/*
- * assume midi is non-null (checked by caller)
- */
-static PmError winmm_in_close(PmInternal *midi)
-{
- winmm_info_type info = (winmm_info_type) midi->api_info;
- if (!info) return pmBadPtr;
- /* device to close */
- if ((pm_hosterror = midiInStop(info->handle.in))) {
- midiInReset(info->handle.in); /* try to reset and close port */
- midiInClose(info->handle.in);
- } else if ((pm_hosterror = midiInReset(info->handle.in))) {
- midiInClose(info->handle.in); /* best effort to close midi port */
- } else {
- pm_hosterror = midiInClose(info->handle.in);
- }
- midi->api_info = NULL;
- DeleteCriticalSection(&info->lock);
- pm_free(info); /* delete */
- if (pm_hosterror) {
- report_hosterror_in();
- return pmHostError;
- }
- return pmNoError;
-}
-
-
-/* Callback function executed via midiInput SW interrupt (via midiInOpen). */
-static void FAR PASCAL winmm_in_callback(
- HMIDIIN hMidiIn, /* midiInput device Handle */
- UINT wMsg, /* midi msg */
- DWORD_PTR dwInstance, /* application data */
- DWORD_PTR dwParam1, /* MIDI data */
- DWORD_PTR dwParam2) /* device timestamp (wrt most recent midiInStart) */
-{
- PmInternal *midi = (PmInternal *) dwInstance;
- winmm_info_type info = (winmm_info_type) midi->api_info;
-
- /* NOTE: we do not just EnterCriticalSection() here because an
- * MIM_CLOSE message arrives when the port is closed, but then
- * the info->lock has been destroyed.
- */
-
- switch (wMsg) {
- case MIM_DATA: {
- /* if this callback is reentered with data, we're in trouble.
- * It's hard to imagine that Microsoft would allow callbacks
- * to be reentrant -- isn't the model that this is like a
- * hardware interrupt? -- but I've seen reentrant behavior
- * using a debugger, so it happens.
- */
- EnterCriticalSection(&info->lock);
-
- /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of
- message LOB;
- dwParam2 is time message received by input device driver, specified
- in [ms] from when midiInStart called.
- each message is expanded to include the status byte */
-
- if ((dwParam1 & 0x80) == 0) {
- /* not a status byte -- ignore it. This happened running the
- sysex.c test under Win2K with MidiMan USB 1x1 interface,
- but I can't reproduce it. -RBD
- */
- /* printf("non-status byte found\n"); */
- } else { /* data to process */
- PmEvent event;
- if (midi->time_proc)
- dwParam2 = (*midi->time_proc)(midi->time_info);
- event.timestamp = (PmTimestamp)dwParam2;
- event.message = (PmMessage)dwParam1;
- pm_read_short(midi, &event);
- }
- LeaveCriticalSection(&info->lock);
- break;
- }
- case MIM_LONGDATA: {
- MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1;
- unsigned char *data = (unsigned char *) lpMidiHdr->lpData;
- unsigned int processed = 0;
- int remaining = lpMidiHdr->dwBytesRecorded;
-
- EnterCriticalSection(&info->lock);
- /* printf("midi_in_callback -- lpMidiHdr %x, %d bytes, %2x...\n",
- lpMidiHdr, lpMidiHdr->dwBytesRecorded, *data); */
- if (midi->time_proc)
- dwParam2 = (*midi->time_proc)(midi->time_info);
- /* can there be more than one message in one buffer? */
- /* assume yes and iterate through them */
- pm_read_bytes(midi, data + processed, remaining, (PmTimestamp)dwParam2);
-
- /* when a device is closed, the pending MIM_LONGDATA buffers are
- returned to this callback with dwBytesRecorded == 0. In this
- case, we do not want to send them back to the interface (if
- we do, the interface will not close, and Windows OS may hang). */
- if (lpMidiHdr->dwBytesRecorded > 0) {
- MMRESULT rslt;
- lpMidiHdr->dwBytesRecorded = 0;
- lpMidiHdr->dwFlags = 0;
-
- /* note: no error checking -- can this actually fail? */
- rslt = midiInPrepareHeader(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
- assert(rslt == MMSYSERR_NOERROR);
- /* note: I don't think this can fail except possibly for
- * MMSYSERR_NOMEM, but the pain of reporting this
- * unlikely but probably catastrophic error does not seem
- * worth it.
- */
- rslt = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR));
- assert(rslt == MMSYSERR_NOERROR);
- LeaveCriticalSection(&info->lock);
- } else {
- midiInUnprepareHeader(hMidiIn,lpMidiHdr,sizeof(MIDIHDR));
- LeaveCriticalSection(&info->lock);
- pm_free(lpMidiHdr);
- }
- break;
- }
- case MIM_OPEN:
- break;
- case MIM_CLOSE:
- break;
- case MIM_ERROR:
- /* printf("MIM_ERROR\n"); */
- break;
- case MIM_LONGERROR:
- /* printf("MIM_LONGERROR\n"); */
- break;
- default:
- break;
- }
-}
-
-/*
-===========================================================================
-begin midi output implementation
-===========================================================================
-*/
-
-/* begin helper routines used by midiOutStream interface */
-
-/* add_to_buffer -- adds timestamped short msg to buffer, returns fullp */
-static int add_to_buffer(winmm_info_type m, LPMIDIHDR hdr,
- unsigned long delta, unsigned long msg)
-{
- unsigned long *ptr = (unsigned long *)
- (hdr->lpData + hdr->dwBytesRecorded);
- *ptr++ = delta; /* dwDeltaTime */
- *ptr++ = 0; /* dwStream */
- *ptr++ = msg; /* dwEvent */
- hdr->dwBytesRecorded += 3 * sizeof(long);
- /* if the addition of three more words (a message) would extend beyond
- the buffer length, then return TRUE (full)
- */
- return hdr->dwBytesRecorded + 3 * sizeof(long) > hdr->dwBufferLength;
-}
-
-
-static PmTimestamp pm_time_get(winmm_info_type info)
-{
- MMTIME mmtime;
- MMRESULT wRtn;
- mmtime.wType = TIME_TICKS;
- mmtime.u.ticks = 0;
- wRtn = midiStreamPosition(info->handle.stream, &mmtime, sizeof(mmtime));
- assert(wRtn == MMSYSERR_NOERROR);
- return mmtime.u.ticks;
-}
-
-
-/* end helper routines used by midiOutStream interface */
-
-
-static PmError winmm_out_open(PmInternal *midi, void *driverInfo)
-{
- DWORD dwDevice;
- int i = midi->device_id;
- winmm_info_type info;
- MIDIPROPTEMPO propdata;
- MIDIPROPTIMEDIV divdata;
- int max_sysex_len = midi->buffer_len * 4;
- int output_buffer_len;
- int num_buffers;
- dwDevice = (DWORD) (intptr_t) pm_descriptors[i].descriptor;
-
- /* create system dependent device data */
- info = winmm_info_create();
- midi->api_info = info;
- if (!info) goto no_memory;
- /* create a signal */
- info->buffer_signal = CreateEvent(NULL, FALSE, FALSE, NULL);
- /* this should only fail when there are very serious problems */
- assert(info->buffer_signal);
- /* open device */
- if (midi->latency == 0) {
- /* use simple midi out calls */
- pm_hosterror = midiOutOpen(
- (LPHMIDIOUT) & info->handle.out, /* device Handle */
- dwDevice, /* device ID */
- /* note: same callback fn as for StreamOpen: */
- (DWORD_PTR) winmm_streamout_callback, /* callback fn */
- (DWORD_PTR) midi, /* callback instance data */
- CALLBACK_FUNCTION); /* callback type */
- } else {
- /* use stream-based midi output (schedulable in future) */
- pm_hosterror = midiStreamOpen(
- &info->handle.stream, /* device Handle */
- (LPUINT) & dwDevice, /* device ID pointer */
- 1, /* reserved, must be 1 */
- (DWORD_PTR) winmm_streamout_callback,
- (DWORD_PTR) midi, /* callback instance data */
- CALLBACK_FUNCTION);
- }
- if (pm_hosterror != MMSYSERR_NOERROR) {
- goto free_descriptor;
- }
-
- if (midi->latency == 0) {
- num_buffers = NUM_SIMPLE_SYSEX_BUFFERS;
- output_buffer_len = max_sysex_len / num_buffers;
- if (output_buffer_len < MIN_SIMPLE_SYSEX_LEN)
- output_buffer_len = MIN_SIMPLE_SYSEX_LEN;
- } else {
- num_buffers = max(midi->buffer_len, midi->latency / 2);
- if (num_buffers < MIN_STREAM_BUFFERS)
- num_buffers = MIN_STREAM_BUFFERS;
- output_buffer_len = STREAM_BUFFER_LEN;
-
- propdata.cbStruct = sizeof(MIDIPROPTEMPO);
- propdata.dwTempo = 480000; /* microseconds per quarter */
- pm_hosterror = midiStreamProperty(info->handle.stream,
- (LPBYTE) & propdata,
- MIDIPROP_SET | MIDIPROP_TEMPO);
- if (pm_hosterror) goto close_device;
-
- divdata.cbStruct = sizeof(MIDIPROPTEMPO);
- divdata.dwTimeDiv = 480; /* divisions per quarter */
- pm_hosterror = midiStreamProperty(info->handle.stream,
- (LPBYTE) & divdata,
- MIDIPROP_SET | MIDIPROP_TIMEDIV);
- if (pm_hosterror) goto close_device;
- }
- /* allocate buffers */
- if (allocate_buffers(info, output_buffer_len, num_buffers))
- goto free_buffers;
- /* start device */
- if (midi->latency != 0) {
- pm_hosterror = midiStreamRestart(info->handle.stream);
- if (pm_hosterror != MMSYSERR_NOERROR) goto free_buffers;
- }
- return pmNoError;
-
-free_buffers:
- /* buffers are freed below by winmm_out_delete */
-close_device:
- midiOutClose(info->handle.out);
-free_descriptor:
- midi->api_info = NULL;
- winmm_out_delete(midi); /* frees buffers and m */
-no_memory:
- if (pm_hosterror) {
- report_hosterror_out();
- return pmHostError;
- }
- return pmInsufficientMemory;
-}
-
-
-/* winmm_out_delete -- carefully free data associated with midi */
-/**/
-static void winmm_out_delete(PmInternal *midi)
-{
- int i;
- /* delete system dependent device data */
- winmm_info_type info = (winmm_info_type) midi->api_info;
- if (info) {
- if (info->buffer_signal) {
- /* don't report errors -- better not to stop cleanup */
- CloseHandle(info->buffer_signal);
- }
- /* if using stream output, free buffers */
- for (i = 0; i < info->num_buffers; i++) {
- if (info->buffers[i]) pm_free(info->buffers[i]);
- }
- info->num_buffers = 0;
- pm_free(info->buffers);
- info->max_buffers = 0;
- }
- midi->api_info = NULL;
- pm_free(info); /* delete */
-}
-
-
-/* see comments for winmm_in_close */
-static PmError winmm_out_close(PmInternal *midi)
-{
- winmm_info_type info = (winmm_info_type) midi->api_info;
- if (info->handle.out) {
- /* device to close */
- if (midi->latency == 0) {
- pm_hosterror = midiOutClose(info->handle.out);
- } else {
- pm_hosterror = midiStreamClose(info->handle.stream);
- }
- /* regardless of outcome, free memory */
- winmm_out_delete(midi);
- }
- if (pm_hosterror) {
- report_hosterror_out();
- return pmHostError;
- }
- return pmNoError;
-}
-
-
-static PmError winmm_out_abort(PmInternal *midi)
-{
- winmm_info_type info = (winmm_info_type) midi->api_info;
-
- /* only stop output streams */
- if (midi->latency > 0) {
- pm_hosterror = midiStreamStop(info->handle.stream);
- if (pm_hosterror) {
- report_hosterror_out();
- return pmHostError;
- }
- }
- return pmNoError;
-}
-
-
-static PmError winmm_write_flush(PmInternal *midi, PmTimestamp timestamp)
-{
- winmm_info_type info = (winmm_info_type) midi->api_info;
- assert(info);
- if (info->hdr) {
- pm_hosterror = midiOutPrepareHeader(info->handle.out, info->hdr,
- sizeof(MIDIHDR));
- if (pm_hosterror) {
- /* do not send message */
- } else if (midi->latency == 0) {
- /* As pointed out by Nigel Brown, 20Sep06, dwBytesRecorded
- * should be zero. This is set in get_free_sysex_buffer().
- * The msg length goes in dwBufferLength in spite of what
- * Microsoft documentation says (or doesn't say). */
- info->hdr->dwBufferLength = info->hdr->dwBytesRecorded;
- info->hdr->dwBytesRecorded = 0;
- pm_hosterror = midiOutLongMsg(info->handle.out, info->hdr,
- sizeof(MIDIHDR));
- } else {
- pm_hosterror = midiStreamOut(info->handle.stream, info->hdr,
- sizeof(MIDIHDR));
- }
- midi->fill_base = NULL;
- info->hdr = NULL;
- if (pm_hosterror) {
- report_hosterror_out();
- return pmHostError;
- }
- }
- return pmNoError;
-}
-
-
-static PmError winmm_write_short(PmInternal *midi, PmEvent *event)
-{
- winmm_info_type info = (winmm_info_type) midi->api_info;
- PmError rslt = pmNoError;
- assert(info);
-
- if (midi->latency == 0) { /* use midiOut interface, ignore timestamps */
- pm_hosterror = midiOutShortMsg(info->handle.out, event->message);
- if (pm_hosterror) {
- if (info->hdr) { /* device disconnect may delete hdr */
- info->hdr->dwFlags = 0; /* release the buffer */
- }
- report_hosterror_out();
- return pmHostError;
- }
- } else { /* use midiStream interface -- pass data through buffers */
- unsigned long when = event->timestamp;
- unsigned long delta;
- int full;
- if (when == 0) when = midi->now;
- /* when is in real_time; translate to intended stream time */
- when = when + info->delta + midi->latency;
- /* make sure we don't go backward in time */
- if (when < info->last_time) when = info->last_time;
- delta = when - info->last_time;
- info->last_time = when;
- /* before we insert any data, we must have a buffer */
- if (info->hdr == NULL) {
- /* stream interface: buffers allocated when stream is opened */
- info->hdr = get_free_output_buffer(midi);
- }
- full = add_to_buffer(info, info->hdr, delta, event->message);
- /* note: winmm_write_flush sets pm_hosterror etc. on host error */
- if (full) rslt = winmm_write_flush(midi, when);
- }
- return rslt;
-}
-
-#define winmm_begin_sysex winmm_write_flush
-#ifndef winmm_begin_sysex
-static PmError winmm_begin_sysex(PmInternal *midi, PmTimestamp timestamp)
-{
- winmm_info_type m = (winmm_info_type) midi->api_info;
- PmError rslt = pmNoError;
-
- if (midi->latency == 0) {
- /* do nothing -- it's handled in winmm_write_byte */
- } else {
- /* sysex expects an empty sysex buffer, so send whatever is here */
- rslt = winmm_write_flush(midi);
- }
- return rslt;
-}
-#endif
-
-static PmError winmm_end_sysex(PmInternal *midi, PmTimestamp timestamp)
-{
- /* could check for callback_error here, but I haven't checked
- * what happens if we exit early and don't finish the sysex msg
- * and clean up
- */
- winmm_info_type info = (winmm_info_type) midi->api_info;
- PmError rslt = pmNoError;
- LPMIDIHDR hdr = info->hdr;
- if (!hdr) return rslt; /* something bad happened earlier,
- do not report an error because it would have been
- reported (at least) once already */
- /* a(n old) version of MIDI YOKE requires a zero byte after
- * the sysex message, but do not increment dwBytesRecorded: */
- hdr->lpData[hdr->dwBytesRecorded] = 0;
- if (midi->latency == 0) {
-#ifdef DEBUG_PRINT_BEFORE_SENDING_SYSEX
- /* DEBUG CODE: */
- { int i; int len = info->hdr->dwBufferLength;
- printf("OutLongMsg %d ", len);
- for (i = 0; i < len; i++) {
- printf("%2x ", (unsigned char) (info->hdr->lpData[i]));
- }
- }
-#endif
- } else {
- /* Using stream interface. There are accumulated bytes in info->hdr
- to send using midiStreamOut
- */
- /* add bytes recorded to MIDIEVENT length, but don't
- count the MIDIEVENT data (3 longs) */
- MIDIEVENT *evt = (MIDIEVENT *) (hdr->lpData);
- evt->dwEvent += hdr->dwBytesRecorded - 3 * sizeof(long);
- /* round up BytesRecorded to multiple of 4 */
- hdr->dwBytesRecorded = (hdr->dwBytesRecorded + 3) & ~3;
- }
- rslt = winmm_write_flush(midi, timestamp);
- return rslt;
-}
-
-
-static PmError winmm_write_byte(PmInternal *midi, unsigned char byte,
- PmTimestamp timestamp)
-{
- /* write a sysex byte */
- PmError rslt = pmNoError;
- winmm_info_type info = (winmm_info_type) midi->api_info;
- LPMIDIHDR hdr = info->hdr;
- unsigned char *msg_buffer;
- assert(info);
- if (!hdr) {
- info->hdr = hdr = get_free_output_buffer(midi);
- assert(hdr);
- midi->fill_base = (unsigned char *) info->hdr->lpData;
- midi->fill_offset_ptr = (uint32_t *) &(hdr->dwBytesRecorded);
- /* when buffer fills, Pm_WriteSysEx will revert to calling
- * pmwin_write_byte, which expect to have space, so leave
- * one byte free for pmwin_write_byte. Leave another byte
- * of space for zero after message to make early version of
- * MIDI YOKE driver happy -- therefore dwBufferLength - 2 */
- midi->fill_length = hdr->dwBufferLength - 2;
- if (midi->latency != 0) {
- unsigned long when = (unsigned long) timestamp;
- unsigned long delta;
- unsigned long *ptr;
- if (when == 0) when = midi->now;
- /* when is in real_time; translate to intended stream time */
- when = when + info->delta + midi->latency;
- /* make sure we don't go backward in time */
- if (when < info->last_time) when = info->last_time;
- delta = when - info->last_time;
- info->last_time = when;
-
- ptr = (unsigned long *) hdr->lpData;
- *ptr++ = delta;
- *ptr++ = 0;
- *ptr = MEVT_F_LONG;
- hdr->dwBytesRecorded = 3 * sizeof(long);
- /* data will be added at an offset of dwBytesRecorded ... */
- }
- }
- /* add the data byte */
- msg_buffer = (unsigned char *) (hdr->lpData);
- msg_buffer[hdr->dwBytesRecorded++] = byte;
-
- /* see if buffer is full, leave one byte extra for pad */
- if (hdr->dwBytesRecorded >= hdr->dwBufferLength - 1) {
- /* write what we've got and continue */
- rslt = winmm_end_sysex(midi, timestamp);
- }
- return rslt;
-}
-
-
-static PmTimestamp winmm_synchronize(PmInternal *midi)
-{
- winmm_info_type info;
- unsigned long pm_stream_time_2;
- unsigned long real_time;
- unsigned long pm_stream_time;
-
- /* only synchronize if we are using stream interface */
- if (midi->latency == 0) return 0;
-
- /* figure out the time */
- info = (winmm_info_type) midi->api_info;
- pm_stream_time_2 = pm_time_get(info);
-
- do {
- /* read real_time between two reads of stream time */
- pm_stream_time = pm_stream_time_2;
- real_time = (*midi->time_proc)(midi->time_info);
- pm_stream_time_2 = pm_time_get(info);
- /* repeat if more than 1ms elapsed */
- } while (pm_stream_time_2 > pm_stream_time + 1);
- info->delta = pm_stream_time - real_time;
- info->sync_time = real_time;
- return real_time;
-}
-
-
-/* winmm_streamout_callback -- unprepare (free) buffer header */
-static void CALLBACK winmm_streamout_callback(HMIDIOUT hmo, UINT wMsg,
- DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
-{
- PmInternal *midi = (PmInternal *) dwInstance;
- winmm_info_type info = (winmm_info_type) midi->api_info;
- LPMIDIHDR hdr = (LPMIDIHDR) dwParam1;
- int err;
-
- /* Even if an error is pending, I think we should unprepare msgs and
- signal their arrival
- */
- /* printf("streamout_callback: hdr %x, wMsg %x, MOM_DONE %x\n",
- hdr, wMsg, MOM_DONE); */
- if (wMsg == MOM_DONE) {
- MMRESULT ret = midiOutUnprepareHeader(info->handle.out, hdr,
- sizeof(MIDIHDR));
- assert(ret == MMSYSERR_NOERROR);
- } else if (wMsg == MOM_CLOSE) {
- /* The streaming API gets a callback when the device is closed.
- * The non-streaming API gets a callback when the device is
- * removed or closed. It is misleading to set is_removed when
- * the device is closed normally, but in that case, midi itself
- * will be freed immediately, so there should be no way to
- * observe is_removed == TRUE. On the other hand, if the device
- * is removed, setting is_removed will cause PortMidi to return
- * the pmDeviceRemoved error on attempts to output to the device.
- * In the case of normal closing, due to midiOutClose(),
- * the call below is reentrant (!), but for some reason this does
- * not cause an error or infinite recursion, so we are not taking
- * any precautions to flag midi as "in the process of closing."
- */
- midi->is_removed = TRUE;
- midiOutClose(info->handle.out);
- }
- /* signal client in case it is blocked waiting for buffer */
- err = SetEvent(info->buffer_signal);
- assert(err); /* false -> error */
-}
-
-
-/*
-===========================================================================
-begin exported functions
-===========================================================================
-*/
-
-#define winmm_in_abort pm_fail_fn
-pm_fns_node pm_winmm_in_dictionary = {
- none_write_short,
- none_sysex,
- none_sysex,
- none_write_byte,
- none_write_short,
- none_write_flush,
- winmm_synchronize,
- winmm_in_open,
- winmm_in_abort,
- winmm_in_close,
- success_poll,
- winmm_check_host_error
- };
-
-pm_fns_node pm_winmm_out_dictionary = {
- winmm_write_short,
- winmm_begin_sysex,
- winmm_end_sysex,
- winmm_write_byte,
- /* short realtime message: */ winmm_write_short,
- winmm_write_flush,
- winmm_synchronize,
- winmm_out_open,
- winmm_out_abort,
- winmm_out_close,
- none_poll,
- winmm_check_host_error
- };
-
-
-/* initialize winmm interface. Note that if there is something wrong
- with winmm (e.g. it is not supported or installed), it is not an
- error. We should simply return without having added any devices to
- the table. Hence, no error code is returned. Furthermore, this init
- code is called along with every other supported interface, so the
- user would have a very hard time figuring out what hardware and API
- generated the error. Finally, it would add complexity to pmwin.c to
- remember where the error code came from in order to convert to text.
- */
-void pm_winmm_init( void )
-{
- pm_winmm_mapper_input();
- pm_winmm_mapper_output();
- pm_winmm_general_inputs();
- pm_winmm_general_outputs();
-}
-
-
-/* no error codes are returned, even if errors are encountered, because
- there is probably nothing the user could do (e.g. it would be an error
- to retry.
- */
-void pm_winmm_term( void )
-{
- int i;
-#ifdef MMDEBUG
- int doneAny = 0;
- printf("pm_winmm_term called\n");
-#endif
- for (i = 0; i < pm_descriptor_len; i++) {
- PmInternal *midi = pm_descriptors[i].pm_internal;
- if (midi) {
- winmm_info_type info = (winmm_info_type) midi->api_info;
- if (info->handle.out) {
- /* close next open device*/
-#ifdef MMDEBUG
- if (doneAny == 0) {
- printf("begin closing open devices...\n");
- doneAny = 1;
- }
-#endif
- /* close all open ports */
- (*midi->dictionary->close)(midi);
- }
- }
- }
- if (midi_in_caps) {
- pm_free(midi_in_caps);
- midi_in_caps = NULL;
- }
- if (midi_out_caps) {
- pm_free(midi_out_caps);
- midi_out_caps = NULL;
- }
-#ifdef MMDEBUG
- if (doneAny) {
- printf("warning: devices were left open. They have been closed.\n");
- }
- printf("pm_winmm_term exiting\n");
-#endif
- pm_descriptor_len = 0;
-}
diff --git a/portmidi/pm_win/pmwinmm.h b/portmidi/pm_win/pmwinmm.h
deleted file mode 100755
index 4a353e2..0000000
--- a/portmidi/pm_win/pmwinmm.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/* pmwinmm.h -- system-specific definitions for windows multimedia API */
-
-void pm_winmm_init( void );
-void pm_winmm_term( void );
-
diff --git a/portmidi/pm_win/static.cmake b/portmidi/pm_win/static.cmake
deleted file mode 100644
index 7fdad18..0000000
--- a/portmidi/pm_win/static.cmake
+++ /dev/null
@@ -1,24 +0,0 @@
-# static.cmake -- change flags to link with static runtime libraries
-#
-# Even when BUILD_SHARED_LIBS is OFF, CMake specifies linking wtih
-# multithread DLL, so you give inconsistent linking instructions
-# resulting in warning messages from MS Visual Studio. If you want
-# a static binary, I've found this approach works to eliminate
-# warnings and make everything static:
-#
-# Changes /MD (multithread DLL) to /MT (multithread static)
-
-if(MSVC)
- foreach(flag_var
- CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
- CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO
- CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
- CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
- if(${flag_var} MATCHES "/MD")
- string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
- endif(${flag_var} MATCHES "/MD")
- endforeach(flag_var)
-
- message(STATUS
- "Note: overriding CMAKE_*_FLAGS_* to use Visual C static multithread library")
-endif(MSVC)
diff --git a/portmidi/portmusic_logo.png b/portmidi/portmusic_logo.png
deleted file mode 100644
index 17a063a..0000000
--- a/portmidi/portmusic_logo.png
+++ /dev/null
Binary files differ
diff --git a/portmidi/porttime/porttime.c b/portmidi/porttime/porttime.c
deleted file mode 100755
index 71b06f4..0000000
--- a/portmidi/porttime/porttime.c
+++ /dev/null
@@ -1,3 +0,0 @@
-/* porttime.c -- portable API for millisecond timer */
-
-/* There is no machine-independent implementation code to put here */
diff --git a/portmidi/porttime/porttime.h b/portmidi/porttime/porttime.h
deleted file mode 100755
index 0a61c5c..0000000
--- a/portmidi/porttime/porttime.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/** @file porttime.h portable interface to millisecond timer. */
-
-/* CHANGE LOG FOR PORTTIME
- 10-Jun-03 Mark Nelson & RBD
- boost priority of timer thread in ptlinux.c implementation
- */
-
-#ifndef PORTMIDI_PORTTIME_H
-#define PORTMIDI_PORTTIME_H
-
-/* Should there be a way to choose the source of time here? */
-
-#ifdef WIN32
-#ifndef INT32_DEFINED
-// rather than having users install a special .h file for windows,
-// just put the required definitions inline here. portmidi.h uses
-// these too, so the definitions are (unfortunately) duplicated there
-typedef int int32_t;
-typedef unsigned int uint32_t;
-#define INT32_DEFINED
-#endif
-#else
-#include <stdint.h> // needed for int32_t
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef PMEXPORT
-#ifdef _WINDLL
-#define PMEXPORT __declspec(dllexport)
-#else
-#define PMEXPORT
-#endif
-#endif
-
-/** @defgroup grp_porttime PortTime: Millisecond Timer
- @{
-*/
-
-typedef enum {
- ptNoError = 0, /* success */
- ptHostError = -10000, /* a system-specific error occurred */
- ptAlreadyStarted, /* cannot start timer because it is already started */
- ptAlreadyStopped, /* cannot stop timer because it is already stopped */
- ptInsufficientMemory /* memory could not be allocated */
-} PtError; /**< @brief @enum PtError PortTime error code; a common return type.
- * No error is indicated by zero; errors are indicated by < 0.
- */
-
-/** real time or time offset in milliseconds. */
-typedef int32_t PtTimestamp;
-
-/** a function that gets a current time */
-typedef void (PtCallback)(PtTimestamp timestamp, void *userData);
-
-/** start a real-time clock service.
-
- @param resolution the timer resolution in ms. The time will advance every
- \p resolution ms.
-
- @param callback a function pointer to be called every resolution ms.
-
- @param userData is passed to \p callback as a parameter.
-
- @return #ptNoError on success. See #PtError for other values.
-*/
-PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData);
-
-/** stop the timer.
-
- @return #ptNoError on success. See #PtError for other values.
-*/
-PMEXPORT PtError Pt_Stop(void);
-
-/** test if the timer is running.
-
- @return TRUE or FALSE
-*/
-PMEXPORT int Pt_Started(void);
-
-/** get the current time in ms.
-
- @return the current time
-*/
-PMEXPORT PtTimestamp Pt_Time(void);
-
-/** pauses the current thread, allowing other threads to run.
-
- @param duration the length of the pause in ms. The true duration
- of the pause may be rounded to the nearest or next clock tick
- as determined by resolution in #Pt_Start().
-*/
-PMEXPORT void Pt_Sleep(int32_t duration);
-
-/** @} */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // PORTMIDI_PORTTIME_H
diff --git a/portmidi/porttime/pthaiku.cpp b/portmidi/porttime/pthaiku.cpp
deleted file mode 100644
index 9d8de14..0000000
--- a/portmidi/porttime/pthaiku.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-// pthaiku.cpp - portable timer implementation for Haiku
-
-#include "porttime.h"
-#include <Looper.h>
-#include <MessageRunner.h>
-#include <OS.h>
-
-namespace {
- const uint32 timerMessage = 'PTTM';
-
- struct TimerLooper : BLooper {
- TimerLooper() : BLooper() {
- }
-
-
- virtual void MessageReceived(BMessage *message)
- {
- PtCallback *callback;
- void *userData;
- if (message->what == timerMessage && message->FindPointer("callback", (void**)&callback) == B_OK && message->FindPointer("userData", &userData) == B_OK) {
- (*callback)(Pt_Time(), userData);
- }
- BLooper::MessageReceived(message);
- }
- };
-
- bool time_started_flag = false;
- bigtime_t time_offset;
- TimerLooper *timerLooper;
- BMessageRunner *timerRunner;
-}
-
-extern "C" {
- PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
- {
- if (time_started_flag) return ptAlreadyStarted;
- time_offset = system_time();
- if (callback) {
- timerLooper = new TimerLooper;
- timerLooper->Run();
- BMessenger target(timerLooper);
- BMessage message(timerMessage);
- message.AddPointer("callback", (void*)callback);
- message.AddPointer("userData", userData);
- bigtime_t interval = resolution * 1000;
- timerRunner = new BMessageRunner(target, &message, interval);
- if(timerRunner->InitCheck() != B_OK) {
- delete timerRunner;
- timerRunner = NULL;
- timerLooper->PostMessage(B_QUIT_REQUESTED);
- timerLooper = NULL;
- return ptHostError;
- }
- }
- time_started_flag = true;
- return ptNoError;
- }
-
-
- PtError Pt_Stop()
- {
- if (!time_started_flag) return ptAlreadyStopped;
- time_started_flag = false;
- delete timerRunner;
- timerRunner = NULL;
- timerLooper->PostMessage(B_QUIT_REQUESTED);
- timerLooper = NULL;
- return ptNoError;
- }
-
-
- int Pt_Started()
- {
- return time_started_flag;
- }
-
-
- PtTimestamp Pt_Time()
- {
- return (system_time() - time_offset) / 1000;
- }
-
-
- void Pt_Sleep(int32_t duration)
- {
- snooze(duration * 1000);
- }
-}
diff --git a/portmidi/porttime/ptlinux.c b/portmidi/porttime/ptlinux.c
deleted file mode 100755
index c4af5c1..0000000
--- a/portmidi/porttime/ptlinux.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* ptlinux.c -- portable timer implementation for linux */
-
-
-/* IMPLEMENTATION NOTES (by Mark Nelson):
-
-Unlike Windows, Linux has no system call to request a periodic callback,
-so if Pt_Start() receives a callback parameter, it must create a thread
-that wakes up periodically and calls the provided callback function.
-If running as superuser, use setpriority() to renice thread to -20.
-One could also set the timer thread to a real-time priority (SCHED_FIFO
-and SCHED_RR), but this is dangerous for This is necessary because
-if the callback hangs it'll never return. A more serious reason
-is that the current scheduler implementation busy-waits instead
-of sleeping when realtime threads request a sleep of <=2ms (as a way
-to get around the 10ms granularity), which means the thread would never
-let anyone else on the CPU.
-
-CHANGE LOG
-
-18-Jul-03 Roger Dannenberg -- Simplified code to set priority of timer
- thread. Simplified implementation notes.
-
-*/
-/* stdlib, stdio, unistd, and sys/types were added because they appeared
- * in a Gentoo patch, but I'm not sure why they are needed. -RBD
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "porttime.h"
-#include "time.h"
-#include "sys/resource.h"
-#include "pthread.h"
-
-#define TRUE 1
-#define FALSE 0
-
-#ifndef CLOCK_MONOTONIC_RAW
-#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
-#endif
-
-static int time_started_flag = FALSE;
-static struct timespec time_offset = {0, 0};
-static pthread_t pt_thread_pid;
-static int pt_thread_created = FALSE;
-
-/* note that this is static data -- we only need one copy */
-typedef struct {
- int id;
- int resolution;
- PtCallback *callback;
- void *userData;
-} pt_callback_parameters;
-
-static int pt_callback_proc_id = 0;
-
-static void *Pt_CallbackProc(void *p)
-{
- pt_callback_parameters *parameters = (pt_callback_parameters *) p;
- int mytime = 1;
- /* to kill a process, just increment the pt_callback_proc_id */
- /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id,
- parameters->id); */
- if (geteuid() == 0) setpriority(PRIO_PROCESS, 0, -20);
- while (pt_callback_proc_id == parameters->id) {
- /* wait for a multiple of resolution ms */
- struct timeval timeout;
- int delay = mytime++ * parameters->resolution - Pt_Time();
- if (delay < 0) delay = 0;
- timeout.tv_sec = 0;
- timeout.tv_usec = delay * 1000;
- select(0, NULL, NULL, NULL, &timeout);
- (*(parameters->callback))(Pt_Time(), parameters->userData);
- }
- /* printf("Pt_CallbackProc exiting\n"); */
- // free(parameters);
- return NULL;
-}
-
-
-PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
-{
- if (time_started_flag) return ptNoError;
- /* need this set before process runs: */
- clock_gettime(CLOCK_MONOTONIC_RAW, &time_offset);
- if (callback) {
- int res;
- pt_callback_parameters *parms = (pt_callback_parameters *)
- malloc(sizeof(pt_callback_parameters));
- if (!parms) return ptInsufficientMemory;
- parms->id = pt_callback_proc_id;
- parms->resolution = resolution;
- parms->callback = callback;
- parms->userData = userData;
- res = pthread_create(&pt_thread_pid, NULL,
- Pt_CallbackProc, parms);
- if (res != 0) return ptHostError;
- pt_thread_created = TRUE;
- }
- time_started_flag = TRUE;
- return ptNoError;
-}
-
-
-PtError Pt_Stop()
-{
- /* printf("Pt_Stop called\n"); */
- pt_callback_proc_id++;
- if (pt_thread_created) {
- pthread_join(pt_thread_pid, NULL);
- pt_thread_created = FALSE;
- }
- time_started_flag = FALSE;
- return ptNoError;
-}
-
-
-int Pt_Started()
-{
- return time_started_flag;
-}
-
-
-PtTimestamp Pt_Time()
-{
- long seconds, ms;
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC_RAW, &now);
- seconds = now.tv_sec - time_offset.tv_sec;
- ms = (now.tv_nsec - time_offset.tv_nsec) / 1000000; /* round down */
- return seconds * 1000 + ms;
-}
-
-
-void Pt_Sleep(int32_t duration)
-{
- usleep(duration * 1000);
-}
diff --git a/portmidi/porttime/ptmacosx_cf.c b/portmidi/porttime/ptmacosx_cf.c
deleted file mode 100755
index a174c86..0000000
--- a/portmidi/porttime/ptmacosx_cf.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/* ptmacosx.c -- portable timer implementation for mac os x */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <pthread.h>
-#include <CoreFoundation/CoreFoundation.h>
-
-#import <mach/mach.h>
-#import <mach/mach_error.h>
-#import <mach/mach_time.h>
-#import <mach/clock.h>
-
-#include "porttime.h"
-
-#define THREAD_IMPORTANCE 30
-#define LONG_TIME 1000000000.0
-
-static int time_started_flag = FALSE;
-static CFAbsoluteTime startTime = 0.0;
-static CFRunLoopRef timerRunLoop;
-
-typedef struct {
- int resolution;
- PtCallback *callback;
- void *userData;
-} PtThreadParams;
-
-
-void Pt_CFTimerCallback(CFRunLoopTimerRef timer, void *info)
-{
- PtThreadParams *params = (PtThreadParams*)info;
- (*params->callback)(Pt_Time(), params->userData);
-}
-
-static void* Pt_Thread(void *p)
-{
- CFTimeInterval timerInterval;
- CFRunLoopTimerContext timerContext;
- CFRunLoopTimerRef timer;
- PtThreadParams *params = (PtThreadParams*)p;
- //CFTimeInterval timeout;
-
- /* raise the thread's priority */
- kern_return_t error;
- thread_extended_policy_data_t extendedPolicy;
- thread_precedence_policy_data_t precedencePolicy;
-
- extendedPolicy.timeshare = 0;
- error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY,
- (thread_policy_t)&extendedPolicy,
- THREAD_EXTENDED_POLICY_COUNT);
- if (error != KERN_SUCCESS) {
- mach_error("Couldn't set thread timeshare policy", error);
- }
-
- precedencePolicy.importance = THREAD_IMPORTANCE;
- error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY,
- (thread_policy_t)&precedencePolicy,
- THREAD_PRECEDENCE_POLICY_COUNT);
- if (error != KERN_SUCCESS) {
- mach_error("Couldn't set thread precedence policy", error);
- }
-
- /* set up the timer context */
- timerContext.version = 0;
- timerContext.info = params;
- timerContext.retain = NULL;
- timerContext.release = NULL;
- timerContext.copyDescription = NULL;
-
- /* create a new timer */
- timerInterval = (double)params->resolution / 1000.0;
- timer = CFRunLoopTimerCreate(NULL, startTime+timerInterval, timerInterval,
- 0, 0, Pt_CFTimerCallback, &timerContext);
-
- timerRunLoop = CFRunLoopGetCurrent();
- CFRunLoopAddTimer(timerRunLoop, timer, CFSTR("PtTimeMode"));
-
- /* run until we're told to stop by Pt_Stop() */
- CFRunLoopRunInMode(CFSTR("PtTimeMode"), LONG_TIME, false);
-
- CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, CFSTR("PtTimeMode"));
- CFRelease(timer);
- free(params);
-
- return NULL;
-}
-
-PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
-{
- PtThreadParams *params = (PtThreadParams*)malloc(sizeof(PtThreadParams));
- pthread_t pthread_id;
-
- printf("Pt_Start() called\n");
-
- // /* make sure we're not already playing */
- if (time_started_flag) return ptAlreadyStarted;
- startTime = CFAbsoluteTimeGetCurrent();
-
- if (callback) {
-
- params->resolution = resolution;
- params->callback = callback;
- params->userData = userData;
-
- pthread_create(&pthread_id, NULL, Pt_Thread, params);
- }
-
- time_started_flag = TRUE;
- return ptNoError;
-}
-
-
-PtError Pt_Stop()
-{
- printf("Pt_Stop called\n");
-
- CFRunLoopStop(timerRunLoop);
- time_started_flag = FALSE;
- return ptNoError;
-}
-
-
-int Pt_Started()
-{
- return time_started_flag;
-}
-
-
-PtTimestamp Pt_Time()
-{
- CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
- return (PtTimestamp) ((now - startTime) * 1000.0);
-}
-
-
-void Pt_Sleep(int32_t duration)
-{
- usleep(duration * 1000);
-}
diff --git a/portmidi/porttime/ptmacosx_mach.c b/portmidi/porttime/ptmacosx_mach.c
deleted file mode 100755
index 1390af8..0000000
--- a/portmidi/porttime/ptmacosx_mach.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/* ptmacosx.c -- portable timer implementation for mac os x */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <CoreAudio/HostTime.h>
-
-#import <mach/mach.h>
-#import <mach/mach_error.h>
-#import <mach/mach_time.h>
-#import <mach/clock.h>
-#include <unistd.h>
-#include <AvailabilityMacros.h>
-
-#include "porttime.h"
-#include "sys/time.h"
-#include "pthread.h"
-
-#ifndef NSEC_PER_MSEC
-#define NSEC_PER_MSEC 1000000
-#endif
-#define THREAD_IMPORTANCE 63
-
-// QOS headers are available as of macOS 10.10
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
-#include "sys/qos.h"
-#define HAVE_APPLE_QOS 1
-#else
-#undef HAVE_APPLE_QOS
-#endif
-
-static int time_started_flag = FALSE;
-static UInt64 start_time;
-static pthread_t pt_thread_pid;
-
-/* note that this is static data -- we only need one copy */
-typedef struct {
- int id;
- int resolution;
- PtCallback *callback;
- void *userData;
-} pt_callback_parameters;
-
-static int pt_callback_proc_id = 0;
-
-static void *Pt_CallbackProc(void *p)
-{
- pt_callback_parameters *parameters = (pt_callback_parameters *) p;
- int mytime = 1;
-
- kern_return_t error;
- thread_extended_policy_data_t extendedPolicy;
- thread_precedence_policy_data_t precedencePolicy;
-
- extendedPolicy.timeshare = 0;
- error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY,
- (thread_policy_t)&extendedPolicy,
- THREAD_EXTENDED_POLICY_COUNT);
- if (error != KERN_SUCCESS) {
- mach_error("Couldn't set thread timeshare policy", error);
- }
-
- precedencePolicy.importance = THREAD_IMPORTANCE;
- error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY,
- (thread_policy_t)&precedencePolicy,
- THREAD_PRECEDENCE_POLICY_COUNT);
- if (error != KERN_SUCCESS) {
- mach_error("Couldn't set thread precedence policy", error);
- }
-
- // Most important, set real-time constraints.
-
- // Define the guaranteed and max fraction of time for the audio thread.
- // These "duty cycle" values can range from 0 to 1. A value of 0.5
- // means the scheduler would give half the time to the thread.
- // These values have empirically been found to yield good behavior.
- // Good means that audio performance is high and other threads won't starve.
- const double kGuaranteedAudioDutyCycle = 0.75;
- const double kMaxAudioDutyCycle = 0.85;
-
- // Define constants determining how much time the audio thread can
- // use in a given time quantum. All times are in milliseconds.
-
- // About 128 frames @44.1KHz
- const double kTimeQuantum = 2.9;
-
- // Time guaranteed each quantum.
- const double kAudioTimeNeeded = kGuaranteedAudioDutyCycle * kTimeQuantum;
-
- // Maximum time each quantum.
- const double kMaxTimeAllowed = kMaxAudioDutyCycle * kTimeQuantum;
-
- // Get the conversion factor from milliseconds to absolute time
- // which is what the time-constraints call needs.
- mach_timebase_info_data_t tb_info;
- mach_timebase_info(&tb_info);
- double ms_to_abs_time =
- ((double)tb_info.denom / (double)tb_info.numer) * 1000000;
-
- thread_time_constraint_policy_data_t time_constraints;
- time_constraints.period = (uint32_t)(kTimeQuantum * ms_to_abs_time);
- time_constraints.computation = (uint32_t)(kAudioTimeNeeded * ms_to_abs_time);
- time_constraints.constraint = (uint32_t)(kMaxTimeAllowed * ms_to_abs_time);
- time_constraints.preemptible = 0;
-
- error = thread_policy_set(mach_thread_self(),
- THREAD_TIME_CONSTRAINT_POLICY,
- (thread_policy_t)&time_constraints,
- THREAD_TIME_CONSTRAINT_POLICY_COUNT);
- if (error != KERN_SUCCESS) {
- mach_error("Couldn't set thread precedence policy", error);
- }
-
- /* to kill a process, just increment the pt_callback_proc_id */
- /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id,
- parameters->id); */
- while (pt_callback_proc_id == parameters->id) {
- /* wait for a multiple of resolution ms */
- UInt64 wait_time;
- int delay = mytime++ * parameters->resolution - Pt_Time();
- PtTimestamp timestamp;
- if (delay < 0) delay = 0;
- wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC);
- wait_time += AudioGetCurrentHostTime();
- mach_wait_until(wait_time);
- timestamp = Pt_Time();
- (*(parameters->callback))(timestamp, parameters->userData);
- }
- free(parameters);
- return NULL;
-}
-
-
-PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
-{
- if (time_started_flag) return ptAlreadyStarted;
- start_time = AudioGetCurrentHostTime();
-
- if (callback) {
- int res;
- pt_callback_parameters *parms;
-
- parms = (pt_callback_parameters *) malloc(sizeof(pt_callback_parameters));
- if (!parms) return ptInsufficientMemory;
- parms->id = pt_callback_proc_id;
- parms->resolution = resolution;
- parms->callback = callback;
- parms->userData = userData;
-
-#ifdef HAVE_APPLE_QOS
- pthread_attr_t qosAttribute;
- pthread_attr_init(&qosAttribute);
- pthread_attr_set_qos_class_np(&qosAttribute,
- QOS_CLASS_USER_INTERACTIVE, 0);
-
- res = pthread_create(&pt_thread_pid, &qosAttribute, Pt_CallbackProc,
- parms);
-#else
- res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms);
-#endif
-
- struct sched_param sp;
- memset(&sp, 0, sizeof(struct sched_param));
- sp.sched_priority = sched_get_priority_max(SCHED_RR);
- if (pthread_setschedparam(pthread_self(), SCHED_RR, &sp) == -1) {
- return ptHostError;
- }
-
- if (res != 0) return ptHostError;
- }
-
- time_started_flag = TRUE;
- return ptNoError;
-}
-
-
-PtError Pt_Stop(void)
-{
- /* printf("Pt_Stop called\n"); */
- pt_callback_proc_id++;
- pthread_join(pt_thread_pid, NULL);
- time_started_flag = FALSE;
- return ptNoError;
-}
-
-
-int Pt_Started(void)
-{
- return time_started_flag;
-}
-
-
-PtTimestamp Pt_Time(void)
-{
- UInt64 clock_time, nsec_time;
- clock_time = AudioGetCurrentHostTime() - start_time;
- nsec_time = AudioConvertHostTimeToNanos(clock_time);
- return (PtTimestamp)(nsec_time / NSEC_PER_MSEC);
-}
-
-
-void Pt_Sleep(int32_t duration)
-{
- usleep(duration * 1000);
-}
diff --git a/portmidi/porttime/ptwinmm.c b/portmidi/porttime/ptwinmm.c
deleted file mode 100755
index 5204659..0000000
--- a/portmidi/porttime/ptwinmm.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* ptwinmm.c -- portable timer implementation for win32 */
-
-
-#include "porttime.h"
-#include "windows.h"
-#include "time.h"
-
-
-TIMECAPS caps;
-
-static long time_offset = 0;
-static int time_started_flag = FALSE;
-static long time_resolution;
-static MMRESULT timer_id;
-static PtCallback *time_callback;
-
-void CALLBACK winmm_time_callback(UINT uID, UINT uMsg, DWORD_PTR dwUser,
- DWORD_PTR dw1, DWORD_PTR dw2)
-{
- (*time_callback)(Pt_Time(), (void *) dwUser);
-}
-
-
-PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
-{
- if (time_started_flag) return ptAlreadyStarted;
- timeBeginPeriod(resolution);
- time_resolution = resolution;
- time_offset = timeGetTime();
- time_started_flag = TRUE;
- time_callback = callback;
- if (callback) {
- timer_id = timeSetEvent(resolution, 1, winmm_time_callback,
- (DWORD_PTR) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
- if (!timer_id) return ptHostError;
- }
- return ptNoError;
-}
-
-
-PMEXPORT PtError Pt_Stop()
-{
- if (!time_started_flag) return ptAlreadyStopped;
- if (time_callback && timer_id) {
- timeKillEvent(timer_id);
- time_callback = NULL;
- timer_id = 0;
- }
- time_started_flag = FALSE;
- timeEndPeriod(time_resolution);
- return ptNoError;
-}
-
-
-PMEXPORT int Pt_Started()
-{
- return time_started_flag;
-}
-
-
-PMEXPORT PtTimestamp Pt_Time()
-{
- return timeGetTime() - time_offset;
-}
-
-
-PMEXPORT void Pt_Sleep(int32_t duration)
-{
- Sleep(duration);
-}