diff options
Diffstat (limited to 'portmidi/pm_common/portmidi.h')
| -rwxr-xr-x | portmidi/pm_common/portmidi.h | 974 |
1 files changed, 0 insertions, 974 deletions
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 */ |
