/* 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 "desire.h" #include #ifdef UNISTD #include #include #include #endif #include #include #include #include #include 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; iinput) { 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; ioutput) { 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= 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 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; iinterf, 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; iinterf, 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; }