From 57045df5fe3ec557e57dc7434ac1a07b5521bffc Mon Sep 17 00:00:00 2001 From: Guenter Geiger Date: Mon, 29 Jul 2002 17:06:19 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r58, which included commits to RCS files with non-trunk default branches. svn path=/trunk/; revision=59 --- pd/portaudio/portmidi-macosx/portmidi.c | 358 ++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 pd/portaudio/portmidi-macosx/portmidi.c (limited to 'pd/portaudio/portmidi-macosx/portmidi.c') diff --git a/pd/portaudio/portmidi-macosx/portmidi.c b/pd/portaudio/portmidi-macosx/portmidi.c new file mode 100644 index 00000000..c2a32ae7 --- /dev/null +++ b/pd/portaudio/portmidi-macosx/portmidi.c @@ -0,0 +1,358 @@ +#include "stdlib.h" +#include "portmidi.h" +#include "pminternal.h" + +#define is_empty(midi) ((midi)->tail == (midi)->head) + +static int pm_initialized = FALSE; + +int descriptor_index = 0; +descriptor_node descriptors[pm_descriptor_max]; + + +/* pm_add_device -- describe interface/device pair to library + * + * This is called at intialization time, once for each + * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1) + * The strings are retained but NOT COPIED, so do not destroy them! + * + * returns pmInvalidDeviceId if device memory is exceeded + * otherwise returns pmNoError + */ +PmError pm_add_device(char *interf, char *name, int input, + void *descriptor, pm_fns_type dictionary) +{ + if (descriptor_index >= pm_descriptor_max) { + return pmInvalidDeviceId; + } + descriptors[descriptor_index].pub.interf = interf; + descriptors[descriptor_index].pub.name = name; + descriptors[descriptor_index].pub.input = input; + descriptors[descriptor_index].pub.output = !input; + descriptors[descriptor_index].descriptor = descriptor; + descriptors[descriptor_index].dictionary = dictionary; + descriptor_index++; + return pmNoError; +} + + +PmError Pm_Initialize( void ) +{ + if (!pm_initialized) { + PmError err = pm_init(); /* defined by implementation specific file */ + if (err) return err; + pm_initialized = TRUE; + } + return pmNoError; +} + + +PmError Pm_Terminate( void ) +{ + PmError err = pmNoError; + if (pm_initialized) { + err = pm_term(); /* defined by implementation specific file */ + /* note that even when pm_term() fails, we mark portmidi as + not initialized */ + pm_initialized = FALSE; + } + return err; +} + + +int Pm_CountDevices( void ) +{ + PmError err = Pm_Initialize(); + if (err) return err; + + return descriptor_index; +} + + +const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id ) +{ + PmError err = Pm_Initialize(); + if (err) return NULL; + + if (id >= 0 && id < descriptor_index) { + return &descriptors[id].pub; + } + return NULL; +} + + +/* failure_fn -- "noop" function pointer */ +/**/ +PmError failure_fn(PmInternal *midi) +{ + return pmBadPtr; +} + + +/* pm_success_fn -- "noop" function pointer */ +/**/ +PmError pm_success_fn(PmInternal *midi) +{ + return pmNoError; +} + + +PmError none_write(PmInternal *midi, PmEvent *buffer, long length) +{ + return length; /* if we return 0, caller might get into a loop */ +} + +PmError pm_fail_fn(PmInternal *midi) +{ + return pmBadPtr; +} + +static PmError none_open(PmInternal *midi, void *driverInfo) +{ + return pmBadPtr; +} + +#define none_abort pm_fail_fn + +#define none_close pm_fail_fn + + +pm_fns_node pm_none_dictionary = { + none_write, none_open, + none_abort, none_close }; + + +/* Pm_Read -- read up to length longs from source into buffer */ +/* + * returns number of longs actually read, or error code + When the reader wants data: + if overflow_flag: + do not get anything + empty the buffer (read_ptr = write_ptr) + clear overflow_flag + return pmBufferOverflow + get data + return number of messages + + + */ +PmError Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length) +{ + PmInternal *midi = (PmInternal *) stream; + int n = 0; + long head = midi->head; + while (head != midi->tail && n < length) { + *buffer++ = midi->buffer[head++]; + if (head == midi->buffer_len) head = 0; + n++; + } + midi->head = head; + if (midi->overflow) { + midi->head = midi->tail; + midi->overflow = FALSE; + return pmBufferOverflow; + } + return n; +} + + +PmError Pm_Poll( PortMidiStream *stream ) +{ + PmInternal *midi = (PmInternal *) stream; + return midi->head != midi->tail; +} + + +PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length) +{ + PmInternal *midi = (PmInternal *) stream; + return (*midi->dictionary->write)(midi, buffer, length); +} + + +PmError Pm_WriteShort( PortMidiStream *stream, long when, long msg) +{ + PmEvent event; + event.timestamp = when; + event.message = msg; + return Pm_Write(stream, &event, 1); +} + + +PmError Pm_OpenInput( PortMidiStream** stream, + PmDeviceID inputDevice, + void *inputDriverInfo, + long bufferSize, + PmTimeProcPtr time_proc, + void *time_info, + PmStream *thru) +{ + PmInternal *midi; + + PmError err = Pm_Initialize(); + if (err) return err; + + if (inputDevice < 0 || inputDevice >= descriptor_index) { + return pmInvalidDeviceId; + } + + if (!descriptors[inputDevice].pub.input) { + return pmInvalidDeviceId; + } + + midi = (PmInternal *) malloc(sizeof(PmInternal)); + *stream = midi; + if (!midi) return pmInsufficientMemory; + + midi->head = 0; + midi->tail = 0; + midi->dictionary = &pm_none_dictionary; + midi->overflow = FALSE; + midi->flush = FALSE; + midi->sysex_in_progress = FALSE; + midi->buffer_len = bufferSize; + midi->buffer = (PmEvent *) pm_alloc(sizeof(PmEvent) * midi->buffer_len); + if (!midi->buffer) return pmInsufficientMemory; + midi->latency = 0; + midi->thru = thru; + midi->time_proc = time_proc; + midi->time_info = time_info; + midi->device_id = inputDevice; + midi->dictionary = descriptors[inputDevice].dictionary; + midi->write_flag = FALSE; + err = (*midi->dictionary->open)(midi, inputDriverInfo); + if (err) { + pm_free(midi->buffer); + *stream = NULL; + } + return err; +} + + +PmError Pm_OpenOutput( PortMidiStream** stream, + PmDeviceID outputDevice, + void *outputDriverInfo, + long bufferSize, + PmTimeProcPtr time_proc, + void *time_info, + long latency ) +{ + PmInternal *midi; + + PmError err = Pm_Initialize(); + if (err) return err; + + if (outputDevice < 0 || outputDevice >= descriptor_index) { + return pmInvalidDeviceId; + } + + if (!descriptors[outputDevice].pub.output) { + return pmInvalidDeviceId; + } + + midi = (PmInternal *) pm_alloc(sizeof(PmInternal)); + *stream = midi; + if (!midi) return pmInsufficientMemory; + + midi->head = 0; + midi->tail = 0; + midi->buffer_len = bufferSize; + midi->buffer = NULL; + midi->device_id = outputDevice; + midi->dictionary = descriptors[outputDevice].dictionary; + midi->time_proc = time_proc; + midi->time_info = time_info; + midi->latency = latency; + midi->write_flag = TRUE; + err = (*midi->dictionary->open)(midi, outputDriverInfo); + if (err) { + *stream = NULL; + pm_free(midi); // Fixed by Ning Hu, Sep.2001 + } + return err; +} + + +PmError Pm_Abort( PortMidiStream* stream ) +{ + PmInternal *midi = (PmInternal *) stream; + return (*midi->dictionary->abort)(midi); +} + + +PmError Pm_Close( PortMidiStream *stream ) +{ + PmInternal *midi = (PmInternal *) stream; + return (*midi->dictionary->close)(midi); +} + + +const char *Pm_GetErrorText( PmError errnum ) +{ + const char *msg; + + switch(errnum) + { + case pmNoError: msg = "Success"; break; + case pmHostError: msg = "Host error."; break; + case pmInvalidDeviceId: msg = "Invalid device ID."; break; + case pmInsufficientMemory: msg = "Insufficient memory."; break; + case pmBufferTooSmall: msg = "Buffer too small."; break; + case pmBadPtr: msg = "Bad pointer."; break; + case pmInternalError: msg = "Internal PortMidi Error."; break; + default: msg = "Illegal error number."; break; + } + return msg; +} + + +long pm_next_time(PmInternal *midi) +{ + return midi->buffer[midi->head].timestamp; +} + + +/* source should not enqueue data if overflow is set */ +/* + When producer has data to enqueue: + if buffer is full: + set overflow_flag and flush_flag + return + else if overflow_flag: + return + else if flush_flag: + if sysex message is in progress: + return + else: + clear flush_flag + // fall through to enqueue data + enqueue the data + + */ +void pm_enqueue(PmInternal *midi, PmEvent *event) +{ + long tail = midi->tail; + midi->buffer[tail++] = *event; + if (tail == midi->buffer_len) tail = 0; + if (tail == midi->head || midi->overflow) { + midi->overflow = TRUE; + midi->flush = TRUE; + return; + } + if (midi->flush) { + if (midi->sysex_in_progress) return; + else midi->flush = FALSE; + } + midi->tail = tail; +} + + +int pm_queue_full(PmInternal *midi) +{ + long tail = midi->tail + 1; + if (tail == midi->buffer_len) tail = 0; + return tail == midi->head; +} + + + -- cgit v1.2.1