aboutsummaryrefslogtreecommitdiff
path: root/desiredata/src/s_midi_pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'desiredata/src/s_midi_pm.c')
-rw-r--r--desiredata/src/s_midi_pm.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/desiredata/src/s_midi_pm.c b/desiredata/src/s_midi_pm.c
new file mode 100644
index 00000000..d51badf7
--- /dev/null
+++ b/desiredata/src/s_midi_pm.c
@@ -0,0 +1,239 @@
+/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+ this file calls portmidi to do MIDI I/O for MSW and Mac OSX.
+ applied sysexin/midiin patch by Nathaniel Dose, july 2007.
+
+*/
+
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#ifdef UNISTD
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <portaudio.h>
+#include <portmidi.h>
+#include <porttime.h>
+
+static PmStream *mac_midiindevlist[MAXMIDIINDEV];
+static PmStream *mac_midioutdevlist[MAXMIDIOUTDEV];
+static int mac_nmidiindev;
+static int mac_nmidioutdev;
+
+void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {
+ PmError err;
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ mac_nmidiindev = 0;
+ for (int i=0; i<nmidiin; i++) {
+ int found = 0,count = Pm_CountDevices();
+ for (int j=0, devno=0; j<count && !found; j++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(j);
+ if (info->input) {
+ if (devno == midiinvec[i]) {
+ err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev],j,NULL,100,NULL,NULL);
+ if (err != pmNoError) post("could not open midi input %d (%s): %s", j, info->name, Pm_GetErrorText(err));
+ else {mac_nmidiindev++; if (sys_verbose) post("Midi Input (%s) opened.", info->name);}
+ found = 1;
+ }
+ devno++;
+ }
+ }
+ if (!found) post("could not find midi device %d",midiinvec[i]);
+ }
+ mac_nmidioutdev = 0;
+ for (int i=0; i<nmidiout; i++) {
+ int found = 0,count = Pm_CountDevices();
+ for (int j=0, devno=0; j<count && !found; j++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(j);
+ if (info->output) {
+ if (devno == midioutvec[i]) {
+ err = Pm_OpenOutput(&mac_midioutdevlist[mac_nmidioutdev],j,NULL,0,NULL,NULL,0);
+ if (err != pmNoError) post("could not open midi output %d (%s): %s",j,info->name,Pm_GetErrorText(err));
+ else {mac_nmidioutdev++; if (sys_verbose) post("Midi Output (%s) opened.",info->name);}
+ found = 1;
+ }
+ devno++;
+ }
+ }
+ if (!found) post("could not find midi device %d",midioutvec[i]);
+ }
+}
+
+void sys_close_midi () {
+ for (int i=0; i< mac_nmidiindev; i++) Pm_Close(mac_midiindevlist[i]);
+ mac_nmidiindev = 0;
+ for (int i=0; i<mac_nmidioutdev; i++) Pm_Close(mac_midioutdevlist[i]);
+ mac_nmidioutdev = 0;
+}
+
+void sys_putmidimess(int portno, int a, int b, int c) {
+ PmEvent buffer;
+ /* post("put 1 msg %d %d", portno, mac_nmidioutdev); */
+ if (portno >= 0 && portno < mac_nmidioutdev) {
+ buffer.message = Pm_Message(a, b, c);
+ buffer.timestamp = 0;
+ /* post("put msg"); */
+ Pm_Write(mac_midioutdevlist[portno], &buffer, 1);
+ }
+}
+
+static void writemidi4(PortMidiStream* stream, int a, int b, int c, int d) {
+ PmEvent buffer;
+ buffer.timestamp = 0;
+ buffer.message = ((a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16) | ((d & 0xff) << 24));
+ Pm_Write(stream, &buffer, 1);
+}
+
+void sys_putmidibyte(int portno, int byte) {
+ /* try to parse the bytes into MIDI messages so they can fit into PortMidi buffers. */
+ static int mess[4];
+ static int nbytes = 0, sysex = 0, i;
+ if (byte >= 0xf8) /* MIDI real time */
+ writemidi4(mac_midioutdevlist[portno], byte, 0, 0, 0);
+ else if (byte == 0xf0) {
+ mess[0] = 0xf0;
+ nbytes = 1;
+ sysex = 1;
+ } else if (byte == 0xf7) {
+ mess[nbytes] = byte;
+ for (i = nbytes+1; i<4; i++) mess[i] = 0;
+ writemidi4(mac_midioutdevlist[portno], mess[0], mess[1], mess[2], mess[3]);
+ sysex = 0;
+ nbytes = 0;
+ } else if (byte >= 0x80) {
+ sysex = 0;
+ if (byte == 0xf4 || byte == 0xf5 || byte == 0xf6) {
+ writemidi4(mac_midioutdevlist[portno], byte, 0, 0, 0);
+ nbytes = 0;
+ } else {
+ mess[0] = byte;
+ nbytes = 1;
+ }
+ } else if (sysex) {
+ mess[nbytes] = byte;
+ nbytes++;
+ if (nbytes == 4) {
+ writemidi4(mac_midioutdevlist[portno], mess[0], mess[1], mess[2], mess[3]);
+ nbytes = 0;
+ }
+ } else if (nbytes) {
+ int status = mess[0];
+ if (status < 0xf0) status &= 0xf0;
+ /* 2 byte messages: */
+ if (status == 0xc0 || status == 0xd0 || status == 0xf1 || status == 0xf3) {
+ writemidi4(mac_midioutdevlist[portno], mess[0], byte, 0, 0);
+ nbytes = (status < 0xf0 ? 1 : 0);
+ } else {
+ if (nbytes == 1) {
+ mess[1] = byte;
+ nbytes = 2;
+ } else {
+ writemidi4(mac_midioutdevlist[portno],
+ mess[0], mess[1], byte, 0);
+ nbytes = (status < 0xf0 ? 1 : 0);
+ }
+ }
+ }
+}
+
+/* this is non-zero if we are in the middle of transmitting sysex */
+int nd_sysex_mode=0;
+
+/* send in 4 bytes of sysex data. if one of the bytes is 0xF7 (sysex end) stop and unset nd_sysex_mode */
+void nd_sysex_inword(int midiindev, int status, int data1, int data2, int data3) {
+ if (nd_sysex_mode) {sys_midibytein(midiindev, status); if (status == 0xF7) nd_sysex_mode = 0;}
+ if (nd_sysex_mode) {sys_midibytein(midiindev, data1); if (data1 == 0xF7) nd_sysex_mode = 0;}
+ if (nd_sysex_mode) {sys_midibytein(midiindev, data2); if (data2 == 0xF7) nd_sysex_mode = 0;}
+ if (nd_sysex_mode) {sys_midibytein(midiindev, data3); if (data3 == 0xF7) nd_sysex_mode = 0;}
+}
+
+void sys_poll_midi() {
+ PmEvent buffer;
+ for (int i=0; i<mac_nmidiindev; i++) {
+ int nmess = Pm_Read(mac_midiindevlist[i], &buffer, 1);
+ if (nmess > 0) {
+ PmMessage msg = buffer.message;
+ int status = Pm_MessageStatus(msg);
+ if(status == 0xf0 || !(status&0x80)) {
+ /* sysex header or data */
+ for(int j=0; j<4; ++j,msg >>= 8) {
+ int data = msg&0xff;
+ sys_midibytein(i, data);
+ if(data == 0xf7) break; /* sysex end */
+ }
+ } else {
+ int data1 = Pm_MessageData1(msg);
+ int data2 = Pm_MessageData2(msg);
+ /* non-sysex */
+ sys_midibytein(i, status);
+ switch(status>>4) {
+ case 0x8: /* note off */
+ case 0x9: /* note on */
+ case 0xa: /* poly pressure */
+ case 0xb: /* control change */
+ case 0xe: /* pitch bend */
+ sys_midibytein(i,data1);
+ sys_midibytein(i,data2);
+ break;
+ case 0xc: /* program change */
+ case 0xd: /* channel pressure */
+ sys_midibytein(i,data1);
+ break;
+ case 0xf: /* system common/realtime messages */
+ switch(status) {
+ case 0xf1: /* time code */
+ case 0xf3: /* song select */
+ case 0xf6: /* tune request */
+ sys_midibytein(i,data1);
+ break;
+ case 0xf2: /* song position pointer */
+ sys_midibytein(i,data1);
+ sys_midibytein(i,data2);
+ break;
+ case 0xf7: // from Nathaniel; don't know whether it'll work in this context.
+ nd_sysex_mode=1;
+ nd_sysex_inword(i,status,data1,data2,((msg>>24)&0xFF));
+ break;
+ default: // from Nathaniel too.
+ if (nd_sysex_mode) nd_sysex_inword(i,status,data1,data2,((msg>>24)&0xFF));
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+#if 0
+/* lifted from pa_devs.c in portaudio */
+void sys_listmididevs() {
+ for (int i=0; i<Pm_CountDevices(); i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ printf("%d: %s, %s", i, info->interf, info->name);
+ if (info->input) printf(" (input)");
+ if (info->output) printf(" (output)");
+ printf("\n");
+ }
+}
+#endif
+
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int nindev=0, noutdev=0;
+ for (int i=0; i<Pm_CountDevices(); i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ /* post("%d: %s, %s (%d,%d)", i, info->interf, info->name,info->input, info->output); */
+ if (info->input && nindev < maxndev) {strcpy(indevlist + nindev * devdescsize, info->name); nindev++;}
+ if (info->output && noutdev < maxndev) {strcpy(outdevlist + noutdev * devdescsize, info->name); noutdev++;}
+ }
+ *nindevs = nindev;
+ *noutdevs = noutdev;
+}