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:
@@ -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);
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
Reference in New Issue
Block a user