1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-10-10 16:43:33 +02:00

Extensive changes to improve NoteTrack display and (some) editing, NoteTrack playback via MIDI, and Midi-to-Audio alignment.

This commit is contained in:
rbdannenberg
2010-09-18 21:02:36 +00:00
parent f6327602e8
commit a1f0e5ed5b
96 changed files with 5679 additions and 3566 deletions

View File

@@ -95,7 +95,7 @@ extern int pm_descriptor_max;
extern descriptor_type descriptors;
extern int pm_descriptor_index;
typedef unsigned long (*time_get_proc_type)(void *time_info);
typedef uint32_t (*time_get_proc_type)(void *time_info);
typedef struct pm_internal_struct {
int device_id; /* which device is open (index to descriptors) */
@@ -103,10 +103,10 @@ typedef struct pm_internal_struct {
PmTimeProcPtr time_proc; /* where to get the time */
void *time_info; /* pass this to get_time() */
long buffer_len; /* how big is the buffer or queue? */
int32_t buffer_len; /* how big is the buffer or queue? */
PmQueue *queue;
long latency; /* time delay in ms between timestamps and actual output */
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 */
@@ -122,8 +122,8 @@ typedef struct pm_internal_struct {
PmMessage sysex_message; /* buffer for 4 bytes of sysex data */
int sysex_message_count; /* how many bytes in sysex_message so far */
long filters; /* flags that filter incoming message classes */
int channel_mask; /* flter incoming messages based on channel */
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 */
@@ -137,8 +137,8 @@ typedef struct pm_internal_struct {
* important
*/
unsigned char *fill_base; /* addr of ptr to sysex data */
unsigned long *fill_offset_ptr; /* offset of next sysex byte */
int fill_length; /* how many sysex bytes to write */
uint32_t *fill_offset_ptr; /* offset of next sysex byte */
int32_t fill_length; /* how many sysex bytes to write */
} PmInternal;
@@ -157,7 +157,7 @@ PmError pm_fail_timestamp_fn(PmInternal *midi, PmTimestamp timestamp);
PmError pm_success_fn(PmInternal *midi);
PmError pm_add_device(char *interf, char *name, int input, void *descriptor,
pm_fns_type dictionary);
unsigned int pm_read_bytes(PmInternal *midi, unsigned char *data, int len,
uint32_t pm_read_bytes(PmInternal *midi, const unsigned char *data, int len,
PmTimestamp timestamp);
void pm_read_short(PmInternal *midi, PmEvent *event);

View File

@@ -1,7 +1,7 @@
/* pmutil.c -- some helpful utilities for building midi
applications that use PortMidi
*/
//#include <stdlib.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "portmidi.h"
@@ -17,42 +17,37 @@
#include "stdio.h"
#endif
/* code is based on 4-byte words -- it should work on a 64-bit machine
as long as a "long" has 4 bytes. This code could be generalized to
be independent of the size of "long" */
typedef long int32;
typedef struct {
long head;
long tail;
long len;
long msg_size; /* number of int32 in a message including extra word */
long overflow;
long peek_overflow;
int32 *buffer;
int32 *peek;
int peek_flag;
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;
PmQueue *Pm_QueueCreate(long num_msgs, long bytes_per_msg)
PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg)
{
int int32s_per_msg = ((bytes_per_msg + sizeof(int32) - 1) &
~(sizeof(int32) - 1)) / sizeof(int32);
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 *) pm_alloc(queue->len * sizeof(int32));
bzero(queue->buffer, queue->len * sizeof(int32));
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 *) pm_alloc(int32s_per_msg * sizeof(int32));
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);
@@ -60,7 +55,7 @@ PmQueue *Pm_QueueCreate(long num_msgs, long bytes_per_msg)
return NULL;
}
}
bzero(queue->buffer, queue->len * sizeof(int32));
bzero(queue->buffer, queue->len * sizeof(int32_t));
queue->head = 0;
queue->tail = 0;
/* msg_size is in words */
@@ -72,7 +67,7 @@ PmQueue *Pm_QueueCreate(long num_msgs, long bytes_per_msg)
}
PmError Pm_QueueDestroy(PmQueue *q)
PMEXPORT PmError Pm_QueueDestroy(PmQueue *q)
{
PmQueueRep *queue = (PmQueueRep *) q;
@@ -87,12 +82,12 @@ PmError Pm_QueueDestroy(PmQueue *q)
}
PmError Pm_Dequeue(PmQueue *q, void *msg)
PMEXPORT PmError Pm_Dequeue(PmQueue *q, void *msg)
{
long head;
PmQueueRep *queue = (PmQueueRep *) q;
int i;
int32 *msg_as_int32 = (int32 *) msg;
int32_t *msg_as_int32 = (int32_t *) msg;
/* arg checking */
if (!queue)
@@ -106,7 +101,7 @@ PmError Pm_Dequeue(PmQueue *q, void *msg)
return pmBufferOverflow;
}
if (queue->peek_flag) {
memcpy(msg, queue->peek, (queue->msg_size - 1) * sizeof(int32));
memcpy(msg, queue->peek, (queue->msg_size - 1) * sizeof(int32_t));
queue->peek_flag = FALSE;
return pmGotData;
}
@@ -144,18 +139,18 @@ PmError Pm_Dequeue(PmQueue *q, void *msg)
}
}
memcpy(msg, (char *) &queue->buffer[head + 1],
sizeof(int32) * (queue->msg_size - 1));
sizeof(int32_t) * (queue->msg_size - 1));
/* fix up zeros */
i = queue->buffer[head];
while (i < queue->msg_size) {
int32 j;
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) * queue->msg_size);
bzero((char *) &queue->buffer[head], sizeof(int32_t) * queue->msg_size);
/* update head */
head += queue->msg_size;
@@ -166,7 +161,7 @@ PmError Pm_Dequeue(PmQueue *q, void *msg)
PmError Pm_SetOverflow(PmQueue *q)
PMEXPORT PmError Pm_SetOverflow(PmQueue *q)
{
PmQueueRep *queue = (PmQueueRep *) q;
long tail;
@@ -181,14 +176,14 @@ PmError Pm_SetOverflow(PmQueue *q)
}
PmError Pm_Enqueue(PmQueue *q, void *msg)
PMEXPORT PmError Pm_Enqueue(PmQueue *q, void *msg)
{
PmQueueRep *queue = (PmQueueRep *) q;
long tail;
int i;
int32 *src = (int32 *) msg;
int32 *ptr;
int32 *dest;
int32_t *src = (int32_t *) msg;
int32_t *ptr;
int32_t *dest;
int rslt;
if (!queue)
return pmBadPtr;
@@ -206,7 +201,7 @@ PmError Pm_Enqueue(PmQueue *q, void *msg)
ptr = &queue->buffer[tail];
dest = ptr + 1;
for (i = 1; i < queue->msg_size; i++) {
int32 j = src[i - 1];
int32_t j = src[i - 1];
if (!j) {
*ptr = i;
ptr = dest;
@@ -223,7 +218,7 @@ PmError Pm_Enqueue(PmQueue *q, void *msg)
}
int Pm_QueueEmpty(PmQueue *q)
PMEXPORT int Pm_QueueEmpty(PmQueue *q)
{
PmQueueRep *queue = (PmQueueRep *) q;
return (!queue) || /* null pointer -> return "empty" */
@@ -231,9 +226,9 @@ int Pm_QueueEmpty(PmQueue *q)
}
int Pm_QueueFull(PmQueue *q)
PMEXPORT int Pm_QueueFull(PmQueue *q)
{
int tail;
long tail;
int i;
PmQueueRep *queue = (PmQueueRep *) q;
/* arg checking */
@@ -250,10 +245,10 @@ int Pm_QueueFull(PmQueue *q)
}
void *Pm_QueuePeek(PmQueue *q)
PMEXPORT void *Pm_QueuePeek(PmQueue *q)
{
PmError rslt;
long temp;
int32_t temp;
PmQueueRep *queue = (PmQueueRep *) q;
/* arg checking */
if (!queue)

View File

@@ -44,8 +44,8 @@ typedef void PmQueue;
Pm_QueueDestroy() destroys the queue and frees its storage.
*/
PmQueue *Pm_QueueCreate(long num_msgs, long bytes_per_msg);
PmError Pm_QueueDestroy(PmQueue *queue);
PMEXPORT PmQueue *Pm_QueueCreate(long num_msgs, int32_t bytes_per_msg);
PMEXPORT PmError Pm_QueueDestroy(PmQueue *queue);
/*
Pm_Dequeue() removes one item from the queue, copying it into msg.
@@ -56,7 +56,7 @@ PmError Pm_QueueDestroy(PmQueue *queue);
overflow report. This protocol ensures that the reader will be
notified when data is lost due to overflow.
*/
PmError Pm_Dequeue(PmQueue *queue, void *msg);
PMEXPORT PmError Pm_Dequeue(PmQueue *queue, void *msg);
/*
@@ -64,7 +64,7 @@ PmError Pm_Dequeue(PmQueue *queue, void *msg);
Returns pmNoError if successful and pmBufferOverflow if the queue was
already full. If pmBufferOverflow is returned, the overflow flag is set.
*/
PmError Pm_Enqueue(PmQueue *queue, void *msg);
PMEXPORT PmError Pm_Enqueue(PmQueue *queue, void *msg);
/*
@@ -82,8 +82,8 @@ PmError Pm_Enqueue(PmQueue *queue, void *msg);
Error conditions: Pm_QueueFull() returns pmBadPtr if queue is NULL.
Pm_QueueEmpty() returns FALSE if queue is NULL.
*/
int Pm_QueueFull(PmQueue *queue);
int Pm_QueueEmpty(PmQueue *queue);
PMEXPORT int Pm_QueueFull(PmQueue *queue);
PMEXPORT int Pm_QueueEmpty(PmQueue *queue);
/*
@@ -109,7 +109,7 @@ int Pm_QueueEmpty(PmQueue *queue);
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.
*/
void *Pm_QueuePeek(PmQueue *queue);
PMEXPORT void *Pm_QueuePeek(PmQueue *queue);
/*
Pm_SetOverflow() allows the writer (enqueuer) to signal an overflow
@@ -120,7 +120,7 @@ void *Pm_QueuePeek(PmQueue *queue);
is NULL, returns pmBufferOverflow if buffer is already in an overflow
state, returns pmNoError if successfully set overflow state.
*/
PmError Pm_SetOverflow(PmQueue *queue);
PMEXPORT PmError Pm_SetOverflow(PmQueue *queue);
#ifdef __cplusplus
}

View File

@@ -173,14 +173,14 @@ portmidi implementation
====================================================================
*/
int Pm_CountDevices( void ) {
PMEXPORT int Pm_CountDevices( void ) {
Pm_Initialize();
/* no error checking -- Pm_Initialize() does not fail */
return pm_descriptor_index;
}
const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) {
PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) {
Pm_Initialize(); /* no error check needed */
if (id >= 0 && id < pm_descriptor_index) {
return &descriptors[id].pub;
@@ -217,7 +217,7 @@ static PmError none_open(PmInternal *midi, void *driverInfo) {
return pmBadPtr;
}
static void none_get_host_error(PmInternal * midi, char * msg, unsigned int len) {
strcpy(msg, "");
*msg = 0; // empty string
}
static unsigned int none_has_host_error(PmInternal * midi) {
return FALSE;
@@ -246,7 +246,7 @@ pm_fns_node pm_none_dictionary = {
};
const char *Pm_GetErrorText( PmError errnum ) {
PMEXPORT const char *Pm_GetErrorText( PmError errnum ) {
const char *msg;
switch(errnum)
@@ -292,7 +292,7 @@ const char *Pm_GetErrorText( PmError errnum ) {
/* This can be called whenever you get a pmHostError return value.
* The error will always be in the global pm_hosterror_text.
*/
void Pm_GetHostErrorText(char * msg, unsigned int len) {
PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len) {
assert(msg);
assert(len > 0);
if (pm_hosterror) {
@@ -307,7 +307,7 @@ void Pm_GetHostErrorText(char * msg, unsigned int len) {
}
int Pm_HasHostError(PortMidiStream * stream) {
PMEXPORT int Pm_HasHostError(PortMidiStream * stream) {
if (pm_hosterror) return TRUE;
if (stream) {
PmInternal * midi = (PmInternal *) stream;
@@ -323,7 +323,7 @@ int Pm_HasHostError(PortMidiStream * stream) {
}
PmError Pm_Initialize( void ) {
PMEXPORT PmError Pm_Initialize( void ) {
if (!pm_initialized) {
pm_hosterror = FALSE;
pm_hosterror_text[0] = 0; /* the null string */
@@ -334,7 +334,7 @@ PmError Pm_Initialize( void ) {
}
PmError Pm_Terminate( void ) {
PMEXPORT PmError Pm_Terminate( void ) {
if (pm_initialized) {
pm_term();
// if there are no devices, descriptors might still be NULL
@@ -350,11 +350,11 @@ PmError Pm_Terminate( void ) {
}
/* Pm_Read -- read up to length longs from source into buffer */
/* Pm_Read -- read up to length messages from source into buffer */
/*
* returns number of longs actually read, or error code
* returns number of messages actually read, or error code
*/
int Pm_Read(PortMidiStream *stream, PmEvent *buffer, long length) {
PMEXPORT int Pm_Read(PortMidiStream *stream, PmEvent *buffer, int32_t length) {
PmInternal *midi = (PmInternal *) stream;
int n = 0;
PmError err = pmNoError;
@@ -395,7 +395,7 @@ int Pm_Read(PortMidiStream *stream, PmEvent *buffer, long length) {
return n;
}
PmError Pm_Poll( PortMidiStream *stream )
PMEXPORT PmError Pm_Poll( PortMidiStream *stream )
{
PmInternal *midi = (PmInternal *) stream;
PmError err;
@@ -445,7 +445,7 @@ static PmError pm_end_sysex(PmInternal *midi)
Pm_WriteSysEx all operate a state machine that "outputs" calls to
write_short, begin_sysex, write_byte, end_sysex, and write_realtime */
PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length)
PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length)
{
PmInternal *midi = (PmInternal *) stream;
PmError err = pmNoError;
@@ -489,7 +489,7 @@ PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length)
* sysex messages in a partially transmitted state.
*/
for (i = 0; i < length; i++) {
unsigned long msg = buffer[i].message;
uint32_t msg = buffer[i].message;
bits = 0;
/* is this a sysex message? */
if (Pm_MessageStatus(msg) == MIDI_SYSEX) {
@@ -541,7 +541,7 @@ PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length)
unsigned char *ptr = midi->fill_base +
*(midi->fill_offset_ptr);
ptr[0] = msg; ptr[1] = msg >> 8;
ptr[2] = msg >> 18; ptr[3] = msg >> 24;
ptr[2] = msg >> 16; ptr[3] = msg >> 24;
(*midi->fill_offset_ptr) += 4;
continue;
}
@@ -578,7 +578,7 @@ error_exit:
}
PmError Pm_WriteShort(PortMidiStream *stream, long when, long msg)
PMEXPORT PmError Pm_WriteShort(PortMidiStream *stream, PmTimestamp when, PmMessage msg)
{
PmEvent event;
@@ -588,12 +588,12 @@ PmError Pm_WriteShort(PortMidiStream *stream, long when, long msg)
}
PmError Pm_WriteSysEx(PortMidiStream *stream, PmTimestamp when,
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 (PM_DEFAULT_SYSEX_BUFFER_SIZE / sizeof(PmMessage))
#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;
@@ -666,10 +666,10 @@ end_of_sysex:
PmError Pm_OpenInput(PortMidiStream** stream,
PMEXPORT PmError Pm_OpenInput(PortMidiStream** stream,
PmDeviceID inputDevice,
void *inputDriverInfo,
long bufferSize,
int32_t bufferSize,
PmTimeProcPtr time_proc,
void *time_info)
{
@@ -706,7 +706,7 @@ PmError Pm_OpenInput(PortMidiStream** stream,
system-specific midi_out_open() method.
*/
if (bufferSize <= 0) bufferSize = 256; /* default buffer size */
midi->queue = Pm_QueueCreate(bufferSize, sizeof(PmEvent));
midi->queue = Pm_QueueCreate(bufferSize, (int32_t) sizeof(PmEvent));
if (!midi->queue) {
/* free portMidi data */
*stream = NULL;
@@ -749,13 +749,13 @@ error_return:
}
PmError Pm_OpenOutput(PortMidiStream** stream,
PMEXPORT PmError Pm_OpenOutput(PortMidiStream** stream,
PmDeviceID outputDevice,
void *outputDriverInfo,
long bufferSize,
int32_t bufferSize,
PmTimeProcPtr time_proc,
void *time_info,
long latency )
int32_t latency )
{
PmInternal *midi;
PmError err = pmNoError;
@@ -828,7 +828,7 @@ error_return:
}
PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
{
PmInternal *midi = (PmInternal *) stream;
PmError err = pmNoError;
@@ -842,7 +842,7 @@ PmError Pm_SetChannelMask(PortMidiStream *stream, int mask)
}
PmError Pm_SetFilter(PortMidiStream *stream, long filters) {
PMEXPORT PmError Pm_SetFilter(PortMidiStream *stream, int32_t filters) {
PmInternal *midi = (PmInternal *) stream;
PmError err = pmNoError;
@@ -857,7 +857,7 @@ PmError Pm_SetFilter(PortMidiStream *stream, long filters) {
}
PmError Pm_Close( PortMidiStream *stream ) {
PMEXPORT PmError Pm_Close( PortMidiStream *stream ) {
PmInternal *midi = (PmInternal *) stream;
PmError err = pmNoError;
@@ -889,8 +889,21 @@ error_return:
return pm_errmsg(err);
}
PmError Pm_Synchronize( PortMidiStream* stream ) {
PmInternal *midi = (PmInternal *) stream;
PmError err = pmNoError;
if (midi == NULL)
err = pmBadPtr;
else if (!descriptors[midi->device_id].pub.output)
err = pmBadPtr;
else if (!descriptors[midi->device_id].pub.opened)
err = pmBadPtr;
else
midi->first_message = TRUE;
return err;
}
PmError Pm_Abort( PortMidiStream* stream ) {
PMEXPORT PmError Pm_Abort( PortMidiStream* stream ) {
PmInternal *midi = (PmInternal *) stream;
PmError err;
/* arg checking */
@@ -1039,7 +1052,7 @@ void pm_read_short(PmInternal *midi, PmEvent *event)
/*
* returns how many bytes processed
*/
unsigned int pm_read_bytes(PmInternal *midi, unsigned char *data,
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 (!) */
@@ -1084,10 +1097,10 @@ unsigned int pm_read_bytes(PmInternal *midi, unsigned char *data,
*/
while (i < len && midi->sysex_in_progress) {
if (midi->sysex_message_count == 0 && i <= len - 4 &&
((event.message = (((long) data[i]) |
(((long) data[i+1]) << 8) |
(((long) data[i+2]) << 16) |
(((long) data[i+3]) << 24))) &
((event.message = (((PmMessage) data[i]) |
(((PmMessage) data[i+1]) << 8) |
(((PmMessage) data[i+2]) << 16) |
(((PmMessage) data[i+3]) << 24))) &
0x80808080) == 0) { /* all data, no status */
if (Pm_Enqueue(midi->queue, &event) == pmBufferOverflow) {
midi->sysex_in_progress = FALSE;

View File

@@ -90,7 +90,27 @@ extern "C" {
* 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.
*/
*/
#ifndef WIN32
// Linux and OS X have stdint.h
#include <stdint.h>
#else
#ifndef INT32_DEFINED
// rather than having users install a special .h file for windows,
// just put the required definitions inline here. porttime.h uses
// these too, so the definitions are (unfortunately) duplicated there
typedef int int32_t;
typedef unsigned int uint32_t;
#define INT32_DEFINED
#endif
#endif
#ifdef _WINDLL
#define PMEXPORT __declspec(dllexport)
#else
#define PMEXPORT
#endif
#ifndef FALSE
#define FALSE 0
@@ -130,13 +150,13 @@ typedef enum {
Pm_Initialize() is the library initialisation function - call this before
using the library.
*/
PmError Pm_Initialize( void );
PMEXPORT PmError Pm_Initialize( void );
/**
Pm_Terminate() is the library termination function - call this after
using the library.
*/
PmError Pm_Terminate( void );
PMEXPORT PmError Pm_Terminate( void );
/** A single PortMidiStream is a descriptor for an open MIDI device.
*/
@@ -157,20 +177,20 @@ typedef void PortMidiStream;
the stream, e.g. an input or output operation. Until the error is cleared,
no new error codes will be obtained, even for a different stream.
*/
int Pm_HasHostError( PortMidiStream * stream );
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
*/
const char *Pm_GetErrorText( PmError errnum );
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.
*/
void Pm_GetHostErrorText(char * msg, unsigned int len);
PMEXPORT void Pm_GetHostErrorText(char * msg, unsigned int len);
#define HDRLENGTH 50
#define PM_HOST_ERROR_MSG_LEN 256u /* any host error msg will occupy less
@@ -195,7 +215,7 @@ typedef struct {
} PmDeviceInfo;
/** Get devices count, ids range from 0 to Pm_CountDevices()-1. */
int Pm_CountDevices( void );
PMEXPORT int Pm_CountDevices( void );
/**
Pm_GetDefaultInputDeviceID(), Pm_GetDefaultOutputDeviceID()
@@ -238,15 +258,15 @@ int Pm_CountDevices( void );
On Linux,
*/
PmDeviceID Pm_GetDefaultInputDeviceID( void );
PMEXPORT PmDeviceID Pm_GetDefaultInputDeviceID( void );
/** see PmDeviceID Pm_GetDefaultInputDeviceID() */
PmDeviceID Pm_GetDefaultOutputDeviceID( void );
PMEXPORT PmDeviceID Pm_GetDefaultOutputDeviceID( void );
/**
PmTimestamp is used to represent a millisecond clock with arbitrary
start time. The type is used for all MIDI timestampes and clocks.
*/
typedef long PmTimestamp;
typedef int32_t PmTimestamp;
typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
/** TRUE if t1 before t2 */
@@ -264,7 +284,7 @@ typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
not be manipulated or freed. The pointer is guaranteed to be valid
between calls to Pm_Initialize() and Pm_Terminate().
*/
const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );
PMEXPORT const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );
/**
Pm_OpenInput() and Pm_OpenOutput() open devices.
@@ -330,20 +350,20 @@ const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );
by calling Pm_Close().
*/
PmError Pm_OpenInput( PortMidiStream** stream,
PMEXPORT PmError Pm_OpenInput( PortMidiStream** stream,
PmDeviceID inputDevice,
void *inputDriverInfo,
long bufferSize,
int32_t bufferSize,
PmTimeProcPtr time_proc,
void *time_info );
PmError Pm_OpenOutput( PortMidiStream** stream,
PMEXPORT PmError Pm_OpenOutput( PortMidiStream** stream,
PmDeviceID outputDevice,
void *outputDriverInfo,
long bufferSize,
int32_t bufferSize,
PmTimeProcPtr time_proc,
void *time_info,
long latency );
int32_t latency );
/** @} */
/**
@@ -351,7 +371,7 @@ PmError Pm_OpenOutput( PortMidiStream** stream,
@{
*/
/* \function PmError Pm_SetFilter( PortMidiStream* stream, long filters )
/* \function PmError Pm_SetFilter( PortMidiStream* stream, int32_t filters )
Pm_SetFilter() sets filters on an open input stream to drop selected
input types. By default, only active sensing messages are filtered.
To prohibit, say, active sensing and sysex messages, call
@@ -411,21 +431,25 @@ PmError Pm_OpenOutput( PortMidiStream** stream,
#define PM_FILT_SYSTEMCOMMON (PM_FILT_MTC | PM_FILT_SONG_POSITION | PM_FILT_SONG_SELECT | PM_FILT_TUNE)
PmError Pm_SetFilter( PortMidiStream* stream, long filters );
PMEXPORT PmError Pm_SetFilter( PortMidiStream* stream, int32_t filters );
#define Pm_Channel(channel) (1<<(channel))
/**
Pm_SetChannelMask() filters incoming messages based on channel.
The mask is a 16-bit bitfield corresponding to appropriate channels
The mask is a 16-bit bitfield corresponding to appropriate channels.
The Pm_Channel macro can assist in calling this function.
i.e. to set 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
*/
PmError Pm_SetChannelMask(PortMidiStream *stream, int mask);
PMEXPORT PmError Pm_SetChannelMask(PortMidiStream *stream, int mask);
/**
Pm_Abort() terminates outgoing messages immediately
@@ -435,21 +459,47 @@ PmError Pm_SetChannelMask(PortMidiStream *stream, int mask);
ignore messages in the buffer and close an input device at
any time.
*/
PmError Pm_Abort( PortMidiStream* stream );
PMEXPORT PmError Pm_Abort( PortMidiStream* stream );
/**
Pm_Close() closes a midi stream, flushing any pending buffers.
(PortMidi attempts to close open streams when the application
exits -- this is particularly difficult under Windows.)
*/
PmError Pm_Close( PortMidiStream* stream );
PMEXPORT PmError Pm_Close( PortMidiStream* stream );
/**
Pm_Message() encodes a short Midi message into a long word. If data1
Pm_Synchronize() instructs PortMidi to (re)synchronize to the
time_proc passed when the stream was opened. 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.
*/
PmError Pm_Synchronize( PortMidiStream* stream );
/**
Pm_Message() encodes a short Midi message into a 32-bit word. If data1
and/or data2 are not present, use zero.
Pm_MessageStatus(), Pm_MessageData1(), and
Pm_MessageData2() extract fields from a long-encoded midi message.
Pm_MessageData2() extract fields from a 32-bit midi message.
*/
#define Pm_Message(status, data1, data2) \
((((data2) << 16) & 0xFF0000) | \
@@ -459,7 +509,7 @@ PmError Pm_Close( PortMidiStream* stream );
#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)
typedef long PmMessage; /**< see PmEvent */
typedef int32_t PmMessage; /**< 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
@@ -560,13 +610,13 @@ typedef struct {
message" and will be flushed as well.
*/
int Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length );
PMEXPORT int Pm_Read( PortMidiStream *stream, PmEvent *buffer, int32_t length );
/**
Pm_Poll() tests whether input is available,
returning TRUE, FALSE, or an error value.
*/
PmError Pm_Poll( PortMidiStream *stream);
PMEXPORT PmError Pm_Poll( PortMidiStream *stream);
/**
Pm_Write() writes midi data from a buffer. This may contain:
@@ -581,7 +631,7 @@ PmError Pm_Poll( PortMidiStream *stream);
Sysex data may contain embedded real-time messages.
*/
PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length );
PMEXPORT PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, int32_t length );
/**
Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
@@ -589,12 +639,12 @@ PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length );
non-decreasing. (But timestamps are ignored if the stream was opened
with latency = 0.)
*/
PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, long msg);
PMEXPORT PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, int32_t msg);
/**
Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
*/
PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, unsigned char *msg);
PMEXPORT PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, unsigned char *msg);
/** @} */