From 9c0e19a3be2288db79e2502e5fa450c3e20a668d Mon Sep 17 00:00:00 2001 From: Guenter Geiger Date: Fri, 9 May 2003 16:04:00 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r610, which included commits to RCS files with non-trunk default branches. svn path=/trunk/; revision=611 --- pd/portmidi_osx/pmmacosx.c | 336 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 pd/portmidi_osx/pmmacosx.c (limited to 'pd/portmidi_osx/pmmacosx.c') diff --git a/pd/portmidi_osx/pmmacosx.c b/pd/portmidi_osx/pmmacosx.c new file mode 100644 index 00000000..7fe8adc4 --- /dev/null +++ b/pd/portmidi_osx/pmmacosx.c @@ -0,0 +1,336 @@ +/* + * Platform interface to the MacOS X CoreMIDI framework + * + * Jon Parise + * + * $Id: pmmacosx.c,v 1.1.1.1 2003-05-09 16:04:00 ggeiger Exp $ + */ + +#include "portmidi.h" +#include "pminternal.h" +#include "porttime.h" +#include "pmmacosx.h" + +#include +#include + +#include +#include + +#define PACKET_BUFFER_SIZE 1024 + +static MIDIClientRef client = NULL; /* Client handle to the MIDI server */ +static MIDIPortRef portIn = NULL; /* Input port handle */ +static MIDIPortRef portOut = NULL; /* Output port handle */ + +extern pm_fns_node pm_macosx_in_dictionary; +extern pm_fns_node pm_macosx_out_dictionary; + +static int +midi_length(long msg) +{ + int status, high, low; + static int high_lengths[] = { + 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 through 0x70 */ + 3, 3, 3, 3, 2, 2, 3, 1 /* 0x80 through 0xf0 */ + }; + static int low_lengths[] = { + 1, 1, 3, 2, 1, 1, 1, 1, /* 0xf0 through 0xf8 */ + 1, 1, 1, 1, 1, 1, 1, 1 /* 0xf9 through 0xff */ + }; + + status = msg & 0xFF; + high = status >> 4; + low = status & 15; + + return (high != 0xF0) ? high_lengths[high] : low_lengths[low]; +} + +static PmTimestamp +get_timestamp(PmInternal *midi) +{ + PmTimeProcPtr time_proc; + + /* Set the time procedure accordingly */ + time_proc = midi->time_proc; + if (time_proc == NULL) { + time_proc = Pt_Time; + } + + return (*time_proc)(midi->time_info); +} + +/* called when MIDI packets are received */ +static void +readProc(const MIDIPacketList *newPackets, void *refCon, void *connRefCon) +{ + PmInternal *midi; + PmEvent event; + MIDIPacket *packet; + unsigned int packetIndex; + + /* Retrieve the context for this connection */ + midi = (PmInternal *) connRefCon; + + packet = (MIDIPacket *) &newPackets->packet[0]; + for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) { + + /* Build the PmMessage for the PmEvent structure */ + switch (packet->length) { + case 1: + event.message = Pm_Message(packet->data[0], 0, 0); + break; + case 2: + event.message = Pm_Message(packet->data[0], packet->data[1], 0); + break; + case 3: + event.message = Pm_Message(packet->data[0], packet->data[1], + packet->data[2]); + break; + default: + /* Skip packets that are too large to fit in a PmMessage */ + continue; + } + + /* Set the timestamp and dispatch this message */ + event.timestamp = get_timestamp(midi); + pm_enqueue(midi, &event); + + /* Advance to the next packet in the packet list */ + packet = MIDIPacketNext(packet); + } +} + +static PmError +midi_in_open(PmInternal *midi, void *driverInfo) +{ + MIDIEndpointRef endpoint; + + endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor; + if (endpoint == NULL) { + return pmInvalidDeviceId; + } + + if (MIDIPortConnectSource(portIn, endpoint, midi) != noErr) { + return pmHostError; + } + + return pmNoError; +} + +static PmError +midi_in_close(PmInternal *midi) +{ + MIDIEndpointRef endpoint; + + endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor; + if (endpoint == NULL) { + return pmInvalidDeviceId; + } + + if (MIDIPortDisconnectSource(portIn, endpoint) != noErr) { + return pmHostError; + } + + return pmNoError; +} + +static PmError +midi_out_open(PmInternal *midi, void *driverInfo) +{ + /* + * MIDISent() only requires an output port (portOut) and a valid MIDI + * endpoint (which we've already created and stored in the PmInternal + * structure). Therefore, no additional work needs to be done here to + * open the device for output. + */ + + return pmNoError; +} + +static PmError +midi_out_close(PmInternal *midi) +{ + return pmNoError; +} + +static PmError +midi_abort(PmInternal *midi) +{ + return pmNoError; +} + +static PmError +midi_write(PmInternal *midi, PmEvent *events, long length) +{ + Byte packetBuffer[PACKET_BUFFER_SIZE]; + MIDIEndpointRef endpoint; + MIDIPacketList *packetList; + MIDIPacket *packet; + MIDITimeStamp timestamp; + PmTimeProcPtr time_proc; + PmEvent event; + unsigned int pm_time; + unsigned int eventIndex; + unsigned int messageLength; + Byte message[3]; + + endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor; + if (endpoint == NULL) { + return pmInvalidDeviceId; + } + + /* Make sure the packetBuffer is large enough */ + if (length > PACKET_BUFFER_SIZE) { + return pmHostError; + } + + /* + * Initialize the packet list. Each packet contains bytes that are to + * be played at the same time. + */ + packetList = (MIDIPacketList *) packetBuffer; + if ((packet = MIDIPacketListInit(packetList)) == NULL) { + return pmHostError; + } + + /* Set the time procedure accordingly */ + time_proc = midi->time_proc; + if (time_proc == NULL) { + time_proc = Pt_Time; + } + + /* Extract the event data and pack it into the message buffer */ + for (eventIndex = 0; eventIndex < length; eventIndex++) { + event = events[eventIndex]; + + /* Compute the timestamp */ + pm_time = (*time_proc)(midi->time_info); + timestamp = pm_time + midi->latency; + + messageLength = midi_length(event.message); + message[0] = Pm_MessageStatus(event.message); + message[1] = Pm_MessageData1(event.message); + message[2] = Pm_MessageData2(event.message); + + /* Add this message to the packet list */ + packet = MIDIPacketListAdd(packetList, sizeof(packetBuffer), packet, + timestamp, messageLength, message); + if (packet == NULL) { + return pmHostError; + } + } + + if (MIDISend(portOut, endpoint, packetList) != noErr) { + return pmHostError; + } + + return pmNoError; +} + +pm_fns_node pm_macosx_in_dictionary = { + none_write, + midi_in_open, + midi_abort, + midi_in_close +}; + +pm_fns_node pm_macosx_out_dictionary = { + midi_write, + midi_out_open, + midi_abort, + midi_out_close +}; + +PmError +pm_macosx_init(void) +{ + OSStatus status; + ItemCount numDevices, numInputs, numOutputs; + MIDIEndpointRef endpoint; + CFStringEncoding defaultEncoding; + CFStringRef deviceName; + char nameBuf[256]; + int i; + + /* Determine the number of MIDI devices on the system */ + numDevices = MIDIGetNumberOfDevices(); + numInputs = MIDIGetNumberOfSources(); + numOutputs = MIDIGetNumberOfDestinations(); + + /* Return prematurely if no devices exist on the system */ + if (numDevices <= 0) { + return pmHostError; + } + + /* Determine the default system character encording */ + defaultEncoding = CFStringGetSystemEncoding(); + + /* Iterate over the MIDI input devices */ + for (i = 0; i < numInputs; i++) { + endpoint = MIDIGetSource(i); + if (endpoint == NULL) { + continue; + } + + /* Get the name of this device */ + MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &deviceName); + CFStringGetCString(deviceName, nameBuf, 256, defaultEncoding); + CFRelease(deviceName); + + /* Register this device with PortMidi */ + pm_add_device("CoreMIDI", nameBuf, TRUE, (void *)endpoint, + &pm_macosx_in_dictionary); + } + + /* Iterate over the MIDI output devices */ + for (i = 0; i < numOutputs; i++) { + endpoint = MIDIGetDestination(i); + if (endpoint == NULL) { + continue; + } + + /* Get the name of this device */ + MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &deviceName); + CFStringGetCString(deviceName, nameBuf, 256, defaultEncoding); + CFRelease(deviceName); + + /* Register this device with PortMidi */ + pm_add_device("CoreMIDI", nameBuf, FALSE, (void *)endpoint, + &pm_macosx_out_dictionary); + } + + /* Initialize the client handle */ + status = MIDIClientCreate(CFSTR("PortMidi"), NULL, NULL, &client); + if (status != noErr) { + fprintf(stderr, "Could not initialize client: %d\n", (int)status); + return pmHostError; + } + + /* Create the input port */ + status = MIDIInputPortCreate(client, CFSTR("Input port"), readProc, NULL, + &portIn); + if (status != noErr) { + fprintf(stderr, "Could not create input port: %d\n", (int)status); + return pmHostError; + } + + /* Create the output port */ + status = MIDIOutputPortCreate(client, CFSTR("Output port"), &portOut); + if (status != noErr) { + fprintf(stderr, "Could not create output port: %d\n", (int)status); + return pmHostError; + } + + return pmNoError; +} + +PmError +pm_macosx_term(void) +{ + if (client != NULL) MIDIClientDispose(client); + if (portIn != NULL) MIDIPortDispose(portIn); + if (portOut != NULL) MIDIPortDispose(portOut); + + return pmNoError; +} -- cgit v1.2.1