summaryrefslogtreecommitdiff
path: root/src/sys/macosx/midi-macosx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys/macosx/midi-macosx.c')
-rw-r--r--src/sys/macosx/midi-macosx.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/src/sys/macosx/midi-macosx.c b/src/sys/macosx/midi-macosx.c
new file mode 100644
index 0000000..3342e2c
--- /dev/null
+++ b/src/sys/macosx/midi-macosx.c
@@ -0,0 +1,222 @@
+/*
+ * Schism Tracker - a cross-platform Impulse Tracker clone
+ * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
+ * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
+ * copyright (c) 2009 Storlek & Mrs. Brisby
+ * copyright (c) 2010-2012 Storlek
+ * URL: http://schismtracker.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "headers.h"
+
+#include "midi.h"
+
+#include "util.h"
+
+#ifdef MACOSX
+
+#include <CoreServices/CoreServices.h>
+#include <CoreMIDI/MIDIServices.h>
+#include <CoreAudio/HostTime.h>
+
+static MIDIClientRef client = NULL;
+static MIDIPortRef portIn = NULL;
+static MIDIPortRef portOut = NULL;
+
+static int max_outputs = 0;
+static int max_inputs = 0;
+
+struct macosx_midi {
+ char *name;
+ MIDIEndpointRef ep;
+ unsigned char packet[1024];
+ MIDIPacketList *pl;
+ MIDIPacket *x;
+};
+
+static void readProc(const MIDIPacketList *np, UNUSED void *rc, void *crc)
+{
+ struct midi_port *p;
+ struct macosx_midi *m;
+ MIDIPacket *x;
+ unsigned long i;
+
+ p = (struct midi_port *)crc;
+ m = (struct macosx_midi *)p->userdata;
+
+ x = (MIDIPacket*)&np->packet[0];
+ for (i = 0; i < np->numPackets; i++) {
+ midi_received_cb(p, x->data, x->length);
+ x = MIDIPacketNext(x);
+ }
+}
+static void _macosx_send(struct midi_port *p, const unsigned char *data,
+ unsigned int len, unsigned int delay)
+{
+ struct macosx_midi *m;
+
+ m = (struct macosx_midi *)p->userdata;
+ if (!m->x) {
+ m->x = MIDIPacketListInit(m->pl);
+ }
+
+ /* msec to nsec? */
+ m->x = MIDIPacketListAdd(m->pl, sizeof(m->packet),
+ m->x, (MIDITimeStamp)AudioConvertNanosToHostTime(
+ AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()) + (1000000*delay)),
+ len, data);
+}
+static void _macosx_drain(struct midi_port *p)
+{
+ struct macosx_midi *m;
+
+ m = (struct macosx_midi *)p->userdata;
+ if (m->x) {
+ MIDISend(portOut, m->ep, m->pl);
+ m->x = NULL;
+ }
+}
+
+/* lifted from portmidi */
+static char *get_ep_name(MIDIEndpointRef ep)
+{
+ MIDIEntityRef entity;
+ MIDIDeviceRef device;
+ CFStringRef endpointName = NULL, deviceName = NULL, fullName = NULL;
+ CFStringEncoding defaultEncoding;
+ char* newName;
+
+ /* get the default string encoding */
+ defaultEncoding = CFStringGetSystemEncoding();
+
+ /* get the entity and device info */
+ MIDIEndpointGetEntity(ep, &entity);
+ MIDIEntityGetDevice(entity, &device);
+
+ /* create the nicely formated name */
+ MIDIObjectGetStringProperty(ep, kMIDIPropertyName, &endpointName);
+ MIDIObjectGetStringProperty(device, kMIDIPropertyName, &deviceName);
+ if (deviceName != NULL) {
+ fullName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@: %@"),
+ deviceName, endpointName);
+ } else {
+ fullName = endpointName;
+ }
+
+ /* copy the string into our buffer */
+ newName = (char*)mem_alloc(CFStringGetLength(fullName) + 1);
+ CFStringGetCString(fullName, newName, CFStringGetLength(fullName) + 1,
+ defaultEncoding);
+
+ /* clean up */
+ if (endpointName) CFRelease(endpointName);
+ if (deviceName) CFRelease(deviceName);
+ if (fullName) CFRelease(fullName);
+
+ return newName;
+}
+
+static int _macosx_start(struct midi_port *p)
+{
+ struct macosx_midi *m;
+ m = (struct macosx_midi *)p->userdata;
+
+ if (p->io & MIDI_INPUT
+ && MIDIPortConnectSource(portIn, m->ep, (void*)p) != noErr) {
+ return 0;
+ }
+
+ if (p->io & MIDI_OUTPUT) {
+ m->pl = (MIDIPacketList*)m->packet;
+ m->x = NULL;
+ }
+ return 1;
+}
+static int _macosx_stop(struct midi_port *p)
+{
+ struct macosx_midi *m;
+ m = (struct macosx_midi *)p->userdata;
+ if (p->io & MIDI_INPUT
+ && MIDIPortDisconnectSource(portIn, m->ep) != noErr) {
+ return 0;
+ }
+ return 1;
+}
+
+static void _macosx_poll(struct midi_provider *p)
+{
+ struct macosx_midi *data;
+ MIDIEndpointRef ep;
+ int i;
+
+ int num_out, num_in;
+
+ num_out = MIDIGetNumberOfDestinations();
+ num_in = MIDIGetNumberOfSources();
+
+ for (i = max_outputs; i < num_out; i++) {
+ ep = MIDIGetDestination(i);
+ if (!ep) continue;
+ data = mem_alloc(sizeof(struct macosx_midi));
+ memcpy(&data->ep, &ep, sizeof(ep));
+ data->name = get_ep_name(ep);
+ midi_port_register(p, MIDI_OUTPUT, data->name, data, 1);
+ }
+ max_outputs = i;
+
+
+ for (i = max_inputs; i < num_in; i++) {
+ ep = MIDIGetSource(i);
+ if (!ep) continue;
+ data = mem_alloc(sizeof(struct macosx_midi));
+ memcpy(&data->ep, &ep, sizeof(ep));
+ data->name = get_ep_name(ep);
+ midi_port_register(p, MIDI_INPUT, data->name, data, 1);
+ }
+ max_inputs = i;
+
+}
+
+int macosx_midi_setup(void)
+{
+ static struct midi_driver driver;
+
+ memset(&driver,0,sizeof(driver));
+ driver.flags = MIDI_PORT_CAN_SCHEDULE;
+ driver.poll = _macosx_poll;
+ driver.thread = NULL;
+ driver.enable = _macosx_start;
+ driver.disable = _macosx_stop;
+ driver.send = _macosx_send;
+ driver.drain = _macosx_drain;
+
+ if (MIDIClientCreate(CFSTR("Schism Tracker"), NULL, NULL, &client) != noErr) {
+ return 0;
+ }
+ if (MIDIInputPortCreate(client, CFSTR("Input port"), readProc, NULL, &portIn) != noErr) {
+ return 0;
+ }
+ if (MIDIOutputPortCreate(client, CFSTR("Output port"), &portOut) != noErr) {
+ return 0;
+ }
+
+ if (!midi_provider_register("Mac OS X", &driver)) return 0;
+
+ return 1;
+}
+
+#endif
© All Rights Reserved