summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/s_midi.c
diff options
context:
space:
mode:
authorPeter D'Hoye <peter.dhoye@gmail.com>2009-05-22 21:58:48 +0000
committerPeter D'Hoye <peter.dhoye@gmail.com>2009-05-22 21:58:48 +0000
commit513389b4c1bc8afe4b2dc9947c534bfeb105e3da (patch)
tree10e673b35651ac567fed2eda0c679c7ade64cbc6 /apps/plugins/pdbox/PDa/src/s_midi.c
parent95fa7f6a2ef466444fbe3fe87efc6d5db6b77b36 (diff)
downloadrockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.zip
rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.tar.gz
rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.tar.bz2
rockbox-513389b4c1bc8afe4b2dc9947c534bfeb105e3da.tar.xz
Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin project of Wincent Balin. Stripped some non-sourcefiles and added a rockbox readme that needs a bit more info from Wincent. Is added to CATEGORIES and viewers, but not yet to SUBDIRS (ie doesn't build yet)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21044 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/s_midi.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/s_midi.c1282
1 files changed, 1282 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/s_midi.c b/apps/plugins/pdbox/PDa/src/s_midi.c
new file mode 100644
index 0000000..4338b49
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/s_midi.c
@@ -0,0 +1,1282 @@
+/* Copyright (c) 1997-1999 Miller Puckette and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Clock functions (which should move, but where?) and MIDI queueing */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include "m_imp.h"
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/time.h>
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#endif
+#ifdef MSW
+#include <winsock.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <wtypes.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+typedef struct _midiqelem
+{
+ double q_time;
+ int q_portno;
+ unsigned char q_onebyte;
+ unsigned char q_byte1;
+ unsigned char q_byte2;
+ unsigned char q_byte3;
+} t_midiqelem;
+
+#define MIDIQSIZE 1024
+
+t_midiqelem midi_outqueue[MIDIQSIZE];
+int midi_outhead, midi_outtail;
+t_midiqelem midi_inqueue[MIDIQSIZE];
+int midi_inhead, midi_intail;
+static double sys_midiinittime;
+
+ /* this is our current estimate for at what "system" real time the
+ current logical time's output should occur. */
+static double sys_dactimeminusrealtime;
+ /* same for input, should be schduler advance earlier. */
+static double sys_adctimeminusrealtime;
+
+static double sys_newdactimeminusrealtime = -1e20;
+static double sys_newadctimeminusrealtime = -1e20;
+static double sys_whenupdate;
+
+void sys_initmidiqueue( void)
+{
+ sys_midiinittime = clock_getlogicaltime();
+ sys_dactimeminusrealtime = sys_adctimeminusrealtime = 0;
+}
+
+ /* this is called from the OS dependent code from time to time when we
+ think we know the delay (outbuftime) in seconds, at which the last-output
+ audio sample will go out the door. */
+void sys_setmiditimediff(double inbuftime, double outbuftime)
+{
+ double dactimeminusrealtime =
+ .001 * clock_gettimesince(sys_midiinittime)
+ - outbuftime - sys_getrealtime();
+ double adctimeminusrealtime =
+ .001 * clock_gettimesince(sys_midiinittime)
+ + inbuftime - sys_getrealtime();
+ if (dactimeminusrealtime > sys_newdactimeminusrealtime)
+ sys_newdactimeminusrealtime = dactimeminusrealtime;
+ if (adctimeminusrealtime > sys_newadctimeminusrealtime)
+ sys_newadctimeminusrealtime = adctimeminusrealtime;
+ if (sys_getrealtime() > sys_whenupdate)
+ {
+ sys_dactimeminusrealtime = sys_newdactimeminusrealtime;
+ sys_adctimeminusrealtime = sys_newadctimeminusrealtime;
+ sys_newdactimeminusrealtime = -1e20;
+ sys_newadctimeminusrealtime = -1e20;
+ sys_whenupdate = sys_getrealtime() + 1;
+ }
+}
+
+ /* return the logical time of the DAC sample we believe is currently
+ going out, based on how much "system time" has elapsed since the
+ last time sys_setmiditimediff got called. */
+static double sys_getmidioutrealtime( void)
+{
+ return (sys_getrealtime() + sys_dactimeminusrealtime);
+}
+
+static double sys_getmidiinrealtime( void)
+{
+ return (sys_getrealtime() + sys_adctimeminusrealtime);
+}
+
+static void sys_putnext( void)
+{
+ int portno = midi_outqueue[midi_outtail].q_portno;
+ if (midi_outqueue[midi_outtail].q_onebyte)
+ sys_putmidibyte(portno, midi_outqueue[midi_outtail].q_byte1);
+ else sys_putmidimess(portno, midi_outqueue[midi_outtail].q_byte1,
+ midi_outqueue[midi_outtail].q_byte2,
+ midi_outqueue[midi_outtail].q_byte3);
+ midi_outtail = (midi_outtail + 1 == MIDIQSIZE ? 0 : midi_outtail + 1);
+}
+
+/* #define TEST_DEJITTER */
+
+void sys_pollmidioutqueue( void)
+{
+#ifdef TEST_DEJITTER
+ static int db = 0;
+#endif
+ double midirealtime = sys_getmidioutrealtime();
+#ifdef TEST_DEJITTER
+ if (midi_outhead == midi_outtail)
+ db = 0;
+#endif
+ while (midi_outhead != midi_outtail)
+ {
+#ifdef TEST_DEJITTER
+ if (!db)
+ {
+ post("out: del %f, midiRT %f logicaltime %f, RT %f dacminusRT %f",
+ (midi_outqueue[midi_outtail].q_time - midirealtime),
+ midirealtime, .001 * clock_gettimesince(sys_midiinittime),
+ sys_getrealtime(), sys_dactimeminusrealtime);
+ db = 1;
+ }
+#endif
+ if (midi_outqueue[midi_outtail].q_time <= midirealtime)
+ sys_putnext();
+ else break;
+ }
+}
+
+static void sys_queuemidimess(int portno, int onebyte, int a, int b, int c)
+{
+ t_midiqelem *midiqelem;
+ int newhead = midi_outhead +1;
+ if (newhead == MIDIQSIZE)
+ newhead = 0;
+ /* if FIFO is full flush an element to make room */
+ if (newhead == midi_outtail)
+ sys_putnext();
+ midi_outqueue[midi_outhead].q_portno = portno;
+ midi_outqueue[midi_outhead].q_onebyte = onebyte;
+ midi_outqueue[midi_outhead].q_byte1 = a;
+ midi_outqueue[midi_outhead].q_byte2 = b;
+ midi_outqueue[midi_outhead].q_byte3 = c;
+ midi_outqueue[midi_outhead].q_time =
+ .001 * clock_gettimesince(sys_midiinittime);
+ midi_outhead = newhead;
+ sys_pollmidioutqueue();
+}
+
+#define MIDI_NOTEON 144
+#define MIDI_POLYAFTERTOUCH 160
+#define MIDI_CONTROLCHANGE 176
+#define MIDI_PROGRAMCHANGE 192
+#define MIDI_AFTERTOUCH 208
+#define MIDI_PITCHBEND 224
+
+void outmidi_noteon(int portno, int channel, int pitch, int velo)
+{
+ if (pitch < 0) pitch = 0;
+ else if (pitch > 127) pitch = 127;
+ if (velo < 0) velo = 0;
+ else if (velo > 127) velo = 127;
+ sys_queuemidimess(portno, 0, MIDI_NOTEON + (channel & 0xf), pitch, velo);
+}
+
+void outmidi_controlchange(int portno, int channel, int ctl, int value)
+{
+ if (ctl < 0) ctl = 0;
+ else if (ctl > 127) ctl = 127;
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_CONTROLCHANGE + (channel & 0xf),
+ ctl, value);
+}
+
+void outmidi_programchange(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0,
+ MIDI_PROGRAMCHANGE + (channel & 0xf), value, 0);
+}
+
+void outmidi_pitchbend(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 16383) value = 16383;
+ sys_queuemidimess(portno, 0, MIDI_PITCHBEND + (channel & 0xf),
+ (value & 127), ((value>>7) & 127));
+}
+
+void outmidi_aftertouch(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_AFTERTOUCH + (channel & 0xf), value, 0);
+}
+
+void outmidi_polyaftertouch(int portno, int channel, int pitch, int value)
+{
+ if (pitch < 0) pitch = 0;
+ else if (pitch > 127) pitch = 127;
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_POLYAFTERTOUCH + (channel & 0xf),
+ pitch, value);
+}
+
+void outmidi_mclk(int portno)
+{
+ sys_queuemidimess(portno, 1, 0xf8, 0,0);
+}
+
+/* ------------------------- MIDI input queue handling ------------------ */
+typedef struct midiparser
+{
+ int mp_status;
+ int mp_gotbyte1;
+ int mp_byte1;
+} t_midiparser;
+
+#define MIDINOTEOFF 0x80 /* 2 following 'data bytes' */
+#define MIDINOTEON 0x90 /* 2 */
+#define MIDIPOLYTOUCH 0xa0 /* 2 */
+#define MIDICONTROLCHANGE 0xb0 /* 2 */
+#define MIDIPROGRAMCHANGE 0xc0 /* 1 */
+#define MIDICHANNELTOUCH 0xd0 /* 1 */
+#define MIDIPITCHBEND 0xe0 /* 2 */
+#define MIDISTARTSYSEX 0xf0 /* (until F7) */
+#define MIDITIMECODE 0xf1 /* 1 */
+#define MIDISONGPOS 0xf2 /* 2 */
+#define MIDISONGSELECT 0xf3 /* 1 */
+#define MIDIRESERVED1 0xf4 /* ? */
+#define MIDIRESERVED2 0xf5 /* ? */
+#define MIDITUNEREQUEST 0xf6 /* 0 */
+#define MIDIENDSYSEX 0xf7 /* 0 */
+#define MIDICLOCK 0xf8 /* 0 */
+#define MIDITICK 0xf9 /* 0 */
+#define MIDISTART 0xfa /* 0 */
+#define MIDICONT 0xfb /* 0 */
+#define MIDISTOP 0xfc /* 0 */
+#define MIDIACTIVESENSE 0xfe /* 0 */
+#define MIDIRESET 0xff /* 0 */
+
+ /* functions in x_midi.c */
+void inmidi_realtimein(int portno, int cmd);
+void inmidi_byte(int portno, int byte);
+void inmidi_sysex(int portno, int byte);
+void inmidi_noteon(int portno, int channel, int pitch, int velo);
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+void inmidi_programchange(int portno, int channel, int value);
+void inmidi_pitchbend(int portno, int channel, int value);
+void inmidi_aftertouch(int portno, int channel, int value);
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+
+static void sys_dispatchnextmidiin( void)
+{
+ static t_midiparser parser[MAXMIDIINDEV], *parserp;
+ int portno = midi_inqueue[midi_intail].q_portno,
+ byte = midi_inqueue[midi_intail].q_byte1;
+ if (!midi_inqueue[midi_intail].q_onebyte)
+ bug("sys_dispatchnextmidiin");
+ if (portno < 0 || portno >= MAXMIDIINDEV)
+ bug("sys_dispatchnextmidiin 2");
+ parserp = parser + portno;
+ outlet_setstacklim();
+
+ if (byte >= 0xf8)
+ inmidi_realtimein(portno, byte);
+ else
+ {
+ inmidi_byte(portno, byte);
+ if (byte & 0x80)
+ {
+ if (byte == MIDITUNEREQUEST || byte == MIDIRESERVED1 ||
+ byte == MIDIRESERVED2)
+ parserp->mp_status = 0;
+ else if (byte == MIDISTARTSYSEX)
+ {
+ inmidi_sysex(portno, byte);
+ parserp->mp_status = byte;
+ }
+ else if (byte == MIDIENDSYSEX)
+ {
+ inmidi_sysex(portno, byte);
+ parserp->mp_status = 0;
+ }
+ else
+ {
+ parserp->mp_status = byte;
+ }
+ parserp->mp_gotbyte1 = 0;
+ }
+ else
+ {
+ int cmd = (parserp->mp_status >= 0xf0 ? parserp->mp_status :
+ (parserp->mp_status & 0xf0));
+ int chan = (parserp->mp_status & 0xf);
+ int byte1 = parserp->mp_byte1, gotbyte1 = parserp->mp_gotbyte1;
+ switch (cmd)
+ {
+ case MIDINOTEOFF:
+ if (gotbyte1)
+ inmidi_noteon(portno, chan, byte1, 0),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDINOTEON:
+ if (gotbyte1)
+ inmidi_noteon(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDIPOLYTOUCH:
+ if (gotbyte1)
+ inmidi_polyaftertouch(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDICONTROLCHANGE:
+ if (gotbyte1)
+ inmidi_controlchange(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDIPROGRAMCHANGE:
+ inmidi_programchange(portno, chan, byte);
+ break;
+ case MIDICHANNELTOUCH:
+ inmidi_aftertouch(portno, chan, byte);
+ break;
+ case MIDIPITCHBEND:
+ if (gotbyte1)
+ inmidi_pitchbend(portno, chan, ((byte << 7) + byte1)),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDISTARTSYSEX:
+ inmidi_sysex(portno, byte);
+ break;
+
+ /* other kinds of messages are just dropped here. We'll
+ need another status byte before we start letting MIDI in
+ again (no running status across "system" messages). */
+ case MIDITIMECODE: /* 1 data byte*/
+ break;
+ case MIDISONGPOS: /* 2 */
+ break;
+ case MIDISONGSELECT: /* 1 */
+ break;
+ }
+ }
+ }
+ midi_intail = (midi_intail + 1 == MIDIQSIZE ? 0 : midi_intail + 1);
+}
+
+void sys_pollmidiinqueue( void)
+{
+#ifdef TEST_DEJITTER
+ static int db = 0;
+#endif
+ double logicaltime = .001 * clock_gettimesince(sys_midiinittime);
+#ifdef TEST_DEJITTER
+ if (midi_inhead == midi_intail)
+ db = 0;
+#endif
+ while (midi_inhead != midi_intail)
+ {
+#ifdef TEST_DEJITTER
+ if (!db)
+ {
+ post("in del %f, logicaltime %f, RT %f adcminusRT %f",
+ (midi_inqueue[midi_intail].q_time - logicaltime),
+ logicaltime, sys_getrealtime(), sys_adctimeminusrealtime);
+ db = 1;
+ }
+#endif
+#if 0
+ if (midi_inqueue[midi_intail].q_time <= logicaltime - 0.007)
+ post("late %f",
+ 1000 * (logicaltime - midi_inqueue[midi_intail].q_time));
+#endif
+ if (midi_inqueue[midi_intail].q_time <= logicaltime)
+ {
+#if 0
+ post("diff %f",
+ 1000* (logicaltime - midi_inqueue[midi_intail].q_time));
+#endif
+ sys_dispatchnextmidiin();
+ }
+ else break;
+ }
+}
+
+ /* this should be called from the system dependent MIDI code when a byte
+ comes in, as a result of our calling sys_poll_midi. We stick it on a
+ timetag queue and dispatch it at the appropriate logical time. */
+
+
+void sys_midibytein(int portno, int byte)
+{
+ static int warned = 0;
+ t_midiqelem *midiqelem;
+ int newhead = midi_inhead +1;
+ if (newhead == MIDIQSIZE)
+ newhead = 0;
+ /* if FIFO is full flush an element to make room */
+ if (newhead == midi_intail)
+ {
+ if (!warned)
+ {
+ post("warning: MIDI timing FIFO overflowed");
+ warned = 1;
+ }
+ sys_dispatchnextmidiin();
+ }
+ midi_inqueue[midi_inhead].q_portno = portno;
+ midi_inqueue[midi_inhead].q_onebyte = 1;
+ midi_inqueue[midi_inhead].q_byte1 = byte;
+ midi_inqueue[midi_inhead].q_time = sys_getmidiinrealtime();
+ midi_inhead = newhead;
+ sys_pollmidiinqueue();
+}
+
+void sys_pollmidiqueue( void)
+{
+#if 0
+ static double lasttime;
+ double newtime = sys_getrealtime();
+ if (newtime - lasttime > 0.007)
+ post("delay %d", (int)(1000 * (newtime - lasttime)));
+ lasttime = newtime;
+#endif
+ sys_poll_midi(); /* OS dependent poll for MIDI input */
+ sys_pollmidioutqueue();
+ sys_pollmidiinqueue();
+}
+
+/******************** dialog window and device listing ********************/
+
+#ifdef USEAPI_OSS
+void midi_oss_init( void);
+#endif
+
+ /* last requested parameters */
+static int midi_nmidiindev;
+static int midi_midiindev[MAXMIDIINDEV];
+static int midi_nmidioutdev;
+static int midi_midioutdev[MAXMIDIOUTDEV];
+
+static void sys_get_midi_params(int *pnmidiindev, int *pmidiindev,
+ int *pnmidioutdev, int *pmidioutdev)
+{
+ int i;
+ *pnmidiindev = midi_nmidiindev;
+ for (i = 0; i < MAXMIDIINDEV; i++)
+ pmidiindev[i] = midi_midiindev[i];
+ *pnmidioutdev = midi_nmidioutdev;
+ for (i = 0; i < MAXMIDIOUTDEV; i++)
+ pmidioutdev[i] = midi_midioutdev[i];
+}
+
+static void sys_save_midi_params(
+ int nmidiindev, int *midiindev,
+ int nmidioutdev, int *midioutdev)
+{
+ int i;
+ midi_nmidiindev = nmidiindev;
+ for (i = 0; i < MAXMIDIINDEV; i++)
+ midi_midiindev[i] = midiindev[i];
+ midi_nmidioutdev = nmidioutdev;
+ for (i = 0; i < MAXMIDIOUTDEV; i++)
+ midi_midioutdev[i] = midioutdev[i];
+}
+
+void sys_open_midi(int nmidiindev, int *midiindev,
+ int nmidioutdev, int *midioutdev)
+{
+#ifdef USEAPI_OSS
+ midi_oss_init();
+#endif
+ sys_do_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
+ sys_save_midi_params(nmidiindev, midiindev,
+ nmidioutdev, midioutdev);
+}
+
+ /* open midi using whatever parameters were last used */
+void sys_reopen_midi( void)
+{
+ int nmidiindev, midiindev[MAXMIDIINDEV];
+ int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
+ sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev);
+ sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
+}
+
+#define MAXNDEV 20
+#define DEVDESCSIZE 80
+
+#ifdef MSW
+#define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */
+#else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */
+#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */
+#endif
+
+void sys_listmididevs(void )
+{
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0, i;
+
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs,
+ MAXNDEV, DEVDESCSIZE);
+
+ if (!nindevs)
+ post("no midi input devices found");
+ else
+ {
+ post("input devices:");
+ for (i = 0; i < nindevs; i++)
+ post("%d. %s", i+1, indevlist + i * DEVDESCSIZE);
+ }
+ if (!noutdevs)
+ post("no midi output devices found");
+ else
+ {
+ post("output devices:");
+ for (i = 0; i < noutdevs; i++)
+ post("%d. %s", i+DEVONSET, outdevlist + i * DEVDESCSIZE);
+ }
+}
+
+extern t_class *glob_pdobject;
+
+ /* start an midi settings dialog window */
+void glob_midi_properties(t_pd *dummy, t_floatarg flongform)
+{
+ char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)];
+ /* these are the devices you're using: */
+ int nindev, midiindev[MAXMIDIINDEV];
+ int noutdev, midioutdev[MAXMIDIOUTDEV];
+ int midiindev1, midiindev2, midiindev3, midiindev4,
+ midioutdev1, midioutdev2, midioutdev3, midioutdev4;
+
+ /* these are all the devices on your system: */
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0, i;
+
+ char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80],
+ outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80];
+
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs,
+ MAXNDEV, DEVDESCSIZE);
+
+ strcpy(indevliststring, "{ {none} ");
+ for (i = 0; i < nindevs; i++)
+ {
+ strcat(indevliststring, "\"");
+ strcat(indevliststring, indevlist + i * DEVDESCSIZE);
+ strcat(indevliststring, "\" ");
+ }
+ strcat(indevliststring, "}");
+
+ strcpy(outdevliststring, "{ {none} ");
+ for (i = 0; i < noutdevs; i++)
+ {
+ strcat(outdevliststring, "\"");
+ strcat(outdevliststring, outdevlist + i * DEVDESCSIZE);
+ strcat(outdevliststring, "\" ");
+ }
+ strcat(outdevliststring, "}");
+
+ sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
+
+ if (nindev > 1 || noutdev > 1)
+ flongform = 1;
+
+ midiindev1 = (nindev > 0 && midiindev[0]>= 0 ? midiindev[0]+1 : 0);
+ midiindev2 = (nindev > 1 && midiindev[1]>= 0 ? midiindev[1]+1 : 0);
+ midiindev3 = (nindev > 2 && midiindev[2]>= 0 ? midiindev[2]+1 : 0);
+ midiindev4 = (nindev > 3 && midiindev[3]>= 0 ? midiindev[3]+1 : 0);
+ midioutdev1 = (noutdev > 0 && midioutdev[0]>=0 ? midioutdev[0]+1 : 0);
+ midioutdev2 = (noutdev > 1 && midioutdev[1]>=0 ? midioutdev[1]+1 : 0);
+ midioutdev3 = (noutdev > 2 && midioutdev[2]>=0 ? midioutdev[2]+1 : 0);
+ midioutdev4 = (noutdev > 3 && midioutdev[3]>=0 ? midioutdev[3]+1 : 0);
+
+ sprintf(buf,
+"pdtk_midi_dialog %%s \
+%s %d %d %d %d %s %d %d %d %d \
+%d\n",
+ indevliststring,
+ midiindev1, midiindev2, midiindev3, midiindev4,
+ outdevliststring,
+ midioutdev1, midioutdev2, midioutdev3, midioutdev4,
+ (flongform != 0));
+ gfxstub_deleteforkey(0);
+ gfxstub_new(&glob_pdobject, glob_midi_properties, buf);
+}
+
+ /* new values from dialog window */
+void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+ int nmidiindev, midiindev[MAXMIDIINDEV];
+ int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
+ int i, nindev, noutdev;
+ int newmidiindev[4], newmidioutdev[4];
+
+ for (i = 0; i < 4; i++)
+ {
+ newmidiindev[i] = atom_getintarg(i, argc, argv);
+ newmidioutdev[i] = atom_getintarg(i+4, argc, argv);
+ }
+
+ for (i = 0, nindev = 0; i < 4; i++)
+ {
+ if (newmidiindev[i] > 0)
+ {
+ newmidiindev[nindev] = newmidiindev[i]-1;
+ nindev++;
+ }
+ }
+ for (i = 0, noutdev = 0; i < 4; i++)
+ {
+ if (newmidioutdev[i] > 0)
+ {
+ newmidioutdev[noutdev] = newmidioutdev[i]-1;
+ noutdev++;
+ }
+ }
+
+ sys_close_midi();
+ sys_open_midi(nindev, newmidiindev, noutdev, newmidioutdev);
+}
+/* Copyright (c) 1997-1999 Miller Puckette and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Clock functions (which should move, but where?) and MIDI queueing */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include "m_imp.h"
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/time.h>
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#endif
+#ifdef MSW
+#include <winsock.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <wtypes.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+typedef struct _midiqelem
+{
+ double q_time;
+ int q_portno;
+ unsigned char q_onebyte;
+ unsigned char q_byte1;
+ unsigned char q_byte2;
+ unsigned char q_byte3;
+} t_midiqelem;
+
+#define MIDIQSIZE 1024
+
+t_midiqelem midi_outqueue[MIDIQSIZE];
+int midi_outhead, midi_outtail;
+t_midiqelem midi_inqueue[MIDIQSIZE];
+int midi_inhead, midi_intail;
+static double sys_midiinittime;
+
+ /* this is our current estimate for at what "system" real time the
+ current logical time's output should occur. */
+static double sys_dactimeminusrealtime;
+ /* same for input, should be schduler advance earlier. */
+static double sys_adctimeminusrealtime;
+
+static double sys_newdactimeminusrealtime = -1e20;
+static double sys_newadctimeminusrealtime = -1e20;
+static double sys_whenupdate;
+
+void sys_initmidiqueue( void)
+{
+ sys_midiinittime = clock_getlogicaltime();
+ sys_dactimeminusrealtime = sys_adctimeminusrealtime = 0;
+}
+
+ /* this is called from the OS dependent code from time to time when we
+ think we know the delay (outbuftime) in seconds, at which the last-output
+ audio sample will go out the door. */
+void sys_setmiditimediff(double inbuftime, double outbuftime)
+{
+ double dactimeminusrealtime =
+ .001 * clock_gettimesince(sys_midiinittime)
+ - outbuftime - sys_getrealtime();
+ double adctimeminusrealtime =
+ .001 * clock_gettimesince(sys_midiinittime)
+ + inbuftime - sys_getrealtime();
+ if (dactimeminusrealtime > sys_newdactimeminusrealtime)
+ sys_newdactimeminusrealtime = dactimeminusrealtime;
+ if (adctimeminusrealtime > sys_newadctimeminusrealtime)
+ sys_newadctimeminusrealtime = adctimeminusrealtime;
+ if (sys_getrealtime() > sys_whenupdate)
+ {
+ sys_dactimeminusrealtime = sys_newdactimeminusrealtime;
+ sys_adctimeminusrealtime = sys_newadctimeminusrealtime;
+ sys_newdactimeminusrealtime = -1e20;
+ sys_newadctimeminusrealtime = -1e20;
+ sys_whenupdate = sys_getrealtime() + 1;
+ }
+}
+
+ /* return the logical time of the DAC sample we believe is currently
+ going out, based on how much "system time" has elapsed since the
+ last time sys_setmiditimediff got called. */
+static double sys_getmidioutrealtime( void)
+{
+ return (sys_getrealtime() + sys_dactimeminusrealtime);
+}
+
+static double sys_getmidiinrealtime( void)
+{
+ return (sys_getrealtime() + sys_adctimeminusrealtime);
+}
+
+static void sys_putnext( void)
+{
+ int portno = midi_outqueue[midi_outtail].q_portno;
+ if (midi_outqueue[midi_outtail].q_onebyte)
+ sys_putmidibyte(portno, midi_outqueue[midi_outtail].q_byte1);
+ else sys_putmidimess(portno, midi_outqueue[midi_outtail].q_byte1,
+ midi_outqueue[midi_outtail].q_byte2,
+ midi_outqueue[midi_outtail].q_byte3);
+ midi_outtail = (midi_outtail + 1 == MIDIQSIZE ? 0 : midi_outtail + 1);
+}
+
+/* #define TEST_DEJITTER */
+
+void sys_pollmidioutqueue( void)
+{
+#ifdef TEST_DEJITTER
+ static int db = 0;
+#endif
+ double midirealtime = sys_getmidioutrealtime();
+#ifdef TEST_DEJITTER
+ if (midi_outhead == midi_outtail)
+ db = 0;
+#endif
+ while (midi_outhead != midi_outtail)
+ {
+#ifdef TEST_DEJITTER
+ if (!db)
+ {
+ post("out: del %f, midiRT %f logicaltime %f, RT %f dacminusRT %f",
+ (midi_outqueue[midi_outtail].q_time - midirealtime),
+ midirealtime, .001 * clock_gettimesince(sys_midiinittime),
+ sys_getrealtime(), sys_dactimeminusrealtime);
+ db = 1;
+ }
+#endif
+ if (midi_outqueue[midi_outtail].q_time <= midirealtime)
+ sys_putnext();
+ else break;
+ }
+}
+
+static void sys_queuemidimess(int portno, int onebyte, int a, int b, int c)
+{
+ t_midiqelem *midiqelem;
+ int newhead = midi_outhead +1;
+ if (newhead == MIDIQSIZE)
+ newhead = 0;
+ /* if FIFO is full flush an element to make room */
+ if (newhead == midi_outtail)
+ sys_putnext();
+ midi_outqueue[midi_outhead].q_portno = portno;
+ midi_outqueue[midi_outhead].q_onebyte = onebyte;
+ midi_outqueue[midi_outhead].q_byte1 = a;
+ midi_outqueue[midi_outhead].q_byte2 = b;
+ midi_outqueue[midi_outhead].q_byte3 = c;
+ midi_outqueue[midi_outhead].q_time =
+ .001 * clock_gettimesince(sys_midiinittime);
+ midi_outhead = newhead;
+ sys_pollmidioutqueue();
+}
+
+#define MIDI_NOTEON 144
+#define MIDI_POLYAFTERTOUCH 160
+#define MIDI_CONTROLCHANGE 176
+#define MIDI_PROGRAMCHANGE 192
+#define MIDI_AFTERTOUCH 208
+#define MIDI_PITCHBEND 224
+
+void outmidi_noteon(int portno, int channel, int pitch, int velo)
+{
+ if (pitch < 0) pitch = 0;
+ else if (pitch > 127) pitch = 127;
+ if (velo < 0) velo = 0;
+ else if (velo > 127) velo = 127;
+ sys_queuemidimess(portno, 0, MIDI_NOTEON + (channel & 0xf), pitch, velo);
+}
+
+void outmidi_controlchange(int portno, int channel, int ctl, int value)
+{
+ if (ctl < 0) ctl = 0;
+ else if (ctl > 127) ctl = 127;
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_CONTROLCHANGE + (channel & 0xf),
+ ctl, value);
+}
+
+void outmidi_programchange(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0,
+ MIDI_PROGRAMCHANGE + (channel & 0xf), value, 0);
+}
+
+void outmidi_pitchbend(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 16383) value = 16383;
+ sys_queuemidimess(portno, 0, MIDI_PITCHBEND + (channel & 0xf),
+ (value & 127), ((value>>7) & 127));
+}
+
+void outmidi_aftertouch(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_AFTERTOUCH + (channel & 0xf), value, 0);
+}
+
+void outmidi_polyaftertouch(int portno, int channel, int pitch, int value)
+{
+ if (pitch < 0) pitch = 0;
+ else if (pitch > 127) pitch = 127;
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_POLYAFTERTOUCH + (channel & 0xf),
+ pitch, value);
+}
+
+void outmidi_mclk(int portno)
+{
+ sys_queuemidimess(portno, 1, 0xf8, 0,0);
+}
+
+/* ------------------------- MIDI input queue handling ------------------ */
+typedef struct midiparser
+{
+ int mp_status;
+ int mp_gotbyte1;
+ int mp_byte1;
+} t_midiparser;
+
+#define MIDINOTEOFF 0x80 /* 2 following 'data bytes' */
+#define MIDINOTEON 0x90 /* 2 */
+#define MIDIPOLYTOUCH 0xa0 /* 2 */
+#define MIDICONTROLCHANGE 0xb0 /* 2 */
+#define MIDIPROGRAMCHANGE 0xc0 /* 1 */
+#define MIDICHANNELTOUCH 0xd0 /* 1 */
+#define MIDIPITCHBEND 0xe0 /* 2 */
+#define MIDISTARTSYSEX 0xf0 /* (until F7) */
+#define MIDITIMECODE 0xf1 /* 1 */
+#define MIDISONGPOS 0xf2 /* 2 */
+#define MIDISONGSELECT 0xf3 /* 1 */
+#define MIDIRESERVED1 0xf4 /* ? */
+#define MIDIRESERVED2 0xf5 /* ? */
+#define MIDITUNEREQUEST 0xf6 /* 0 */
+#define MIDIENDSYSEX 0xf7 /* 0 */
+#define MIDICLOCK 0xf8 /* 0 */
+#define MIDITICK 0xf9 /* 0 */
+#define MIDISTART 0xfa /* 0 */
+#define MIDICONT 0xfb /* 0 */
+#define MIDISTOP 0xfc /* 0 */
+#define MIDIACTIVESENSE 0xfe /* 0 */
+#define MIDIRESET 0xff /* 0 */
+
+ /* functions in x_midi.c */
+void inmidi_realtimein(int portno, int cmd);
+void inmidi_byte(int portno, int byte);
+void inmidi_sysex(int portno, int byte);
+void inmidi_noteon(int portno, int channel, int pitch, int velo);
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+void inmidi_programchange(int portno, int channel, int value);
+void inmidi_pitchbend(int portno, int channel, int value);
+void inmidi_aftertouch(int portno, int channel, int value);
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+
+static void sys_dispatchnextmidiin( void)
+{
+ static t_midiparser parser[MAXMIDIINDEV], *parserp;
+ int portno = midi_inqueue[midi_intail].q_portno,
+ byte = midi_inqueue[midi_intail].q_byte1;
+ if (!midi_inqueue[midi_intail].q_onebyte)
+ bug("sys_dispatchnextmidiin");
+ if (portno < 0 || portno >= MAXMIDIINDEV)
+ bug("sys_dispatchnextmidiin 2");
+ parserp = parser + portno;
+ outlet_setstacklim();
+
+ if (byte >= 0xf8)
+ inmidi_realtimein(portno, byte);
+ else
+ {
+ inmidi_byte(portno, byte);
+ if (byte & 0x80)
+ {
+ if (byte == MIDITUNEREQUEST || byte == MIDIRESERVED1 ||
+ byte == MIDIRESERVED2)
+ parserp->mp_status = 0;
+ else if (byte == MIDISTARTSYSEX)
+ {
+ inmidi_sysex(portno, byte);
+ parserp->mp_status = byte;
+ }
+ else if (byte == MIDIENDSYSEX)
+ {
+ inmidi_sysex(portno, byte);
+ parserp->mp_status = 0;
+ }
+ else
+ {
+ parserp->mp_status = byte;
+ }
+ parserp->mp_gotbyte1 = 0;
+ }
+ else
+ {
+ int cmd = (parserp->mp_status >= 0xf0 ? parserp->mp_status :
+ (parserp->mp_status & 0xf0));
+ int chan = (parserp->mp_status & 0xf);
+ int byte1 = parserp->mp_byte1, gotbyte1 = parserp->mp_gotbyte1;
+ switch (cmd)
+ {
+ case MIDINOTEOFF:
+ if (gotbyte1)
+ inmidi_noteon(portno, chan, byte1, 0),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDINOTEON:
+ if (gotbyte1)
+ inmidi_noteon(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDIPOLYTOUCH:
+ if (gotbyte1)
+ inmidi_polyaftertouch(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDICONTROLCHANGE:
+ if (gotbyte1)
+ inmidi_controlchange(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDIPROGRAMCHANGE:
+ inmidi_programchange(portno, chan, byte);
+ break;
+ case MIDICHANNELTOUCH:
+ inmidi_aftertouch(portno, chan, byte);
+ break;
+ case MIDIPITCHBEND:
+ if (gotbyte1)
+ inmidi_pitchbend(portno, chan, ((byte << 7) + byte1)),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDISTARTSYSEX:
+ inmidi_sysex(portno, byte);
+ break;
+
+ /* other kinds of messages are just dropped here. We'll
+ need another status byte before we start letting MIDI in
+ again (no running status across "system" messages). */
+ case MIDITIMECODE: /* 1 data byte*/
+ break;
+ case MIDISONGPOS: /* 2 */
+ break;
+ case MIDISONGSELECT: /* 1 */
+ break;
+ }
+ }
+ }
+ midi_intail = (midi_intail + 1 == MIDIQSIZE ? 0 : midi_intail + 1);
+}
+
+void sys_pollmidiinqueue( void)
+{
+#ifdef TEST_DEJITTER
+ static int db = 0;
+#endif
+ double logicaltime = .001 * clock_gettimesince(sys_midiinittime);
+#ifdef TEST_DEJITTER
+ if (midi_inhead == midi_intail)
+ db = 0;
+#endif
+ while (midi_inhead != midi_intail)
+ {
+#ifdef TEST_DEJITTER
+ if (!db)
+ {
+ post("in del %f, logicaltime %f, RT %f adcminusRT %f",
+ (midi_inqueue[midi_intail].q_time - logicaltime),
+ logicaltime, sys_getrealtime(), sys_adctimeminusrealtime);
+ db = 1;
+ }
+#endif
+#if 0
+ if (midi_inqueue[midi_intail].q_time <= logicaltime - 0.007)
+ post("late %f",
+ 1000 * (logicaltime - midi_inqueue[midi_intail].q_time));
+#endif
+ if (midi_inqueue[midi_intail].q_time <= logicaltime)
+ {
+#if 0
+ post("diff %f",
+ 1000* (logicaltime - midi_inqueue[midi_intail].q_time));
+#endif
+ sys_dispatchnextmidiin();
+ }
+ else break;
+ }
+}
+
+ /* this should be called from the system dependent MIDI code when a byte
+ comes in, as a result of our calling sys_poll_midi. We stick it on a
+ timetag queue and dispatch it at the appropriate logical time. */
+
+
+void sys_midibytein(int portno, int byte)
+{
+ static int warned = 0;
+ t_midiqelem *midiqelem;
+ int newhead = midi_inhead +1;
+ if (newhead == MIDIQSIZE)
+ newhead = 0;
+ /* if FIFO is full flush an element to make room */
+ if (newhead == midi_intail)
+ {
+ if (!warned)
+ {
+ post("warning: MIDI timing FIFO overflowed");
+ warned = 1;
+ }
+ sys_dispatchnextmidiin();
+ }
+ midi_inqueue[midi_inhead].q_portno = portno;
+ midi_inqueue[midi_inhead].q_onebyte = 1;
+ midi_inqueue[midi_inhead].q_byte1 = byte;
+ midi_inqueue[midi_inhead].q_time = sys_getmidiinrealtime();
+ midi_inhead = newhead;
+ sys_pollmidiinqueue();
+}
+
+void sys_pollmidiqueue( void)
+{
+#if 0
+ static double lasttime;
+ double newtime = sys_getrealtime();
+ if (newtime - lasttime > 0.007)
+ post("delay %d", (int)(1000 * (newtime - lasttime)));
+ lasttime = newtime;
+#endif
+ sys_poll_midi(); /* OS dependent poll for MIDI input */
+ sys_pollmidioutqueue();
+ sys_pollmidiinqueue();
+}
+
+/******************** dialog window and device listing ********************/
+
+#ifdef USEAPI_OSS
+void midi_oss_init( void);
+#endif
+
+ /* last requested parameters */
+static int midi_nmidiindev;
+static int midi_midiindev[MAXMIDIINDEV];
+static int midi_nmidioutdev;
+static int midi_midioutdev[MAXMIDIOUTDEV];
+
+static void sys_get_midi_params(int *pnmidiindev, int *pmidiindev,
+ int *pnmidioutdev, int *pmidioutdev)
+{
+ int i;
+ *pnmidiindev = midi_nmidiindev;
+ for (i = 0; i < MAXMIDIINDEV; i++)
+ pmidiindev[i] = midi_midiindev[i];
+ *pnmidioutdev = midi_nmidioutdev;
+ for (i = 0; i < MAXMIDIOUTDEV; i++)
+ pmidioutdev[i] = midi_midioutdev[i];
+}
+
+static void sys_save_midi_params(
+ int nmidiindev, int *midiindev,
+ int nmidioutdev, int *midioutdev)
+{
+ int i;
+ midi_nmidiindev = nmidiindev;
+ for (i = 0; i < MAXMIDIINDEV; i++)
+ midi_midiindev[i] = midiindev[i];
+ midi_nmidioutdev = nmidioutdev;
+ for (i = 0; i < MAXMIDIOUTDEV; i++)
+ midi_midioutdev[i] = midioutdev[i];
+}
+
+void sys_open_midi(int nmidiindev, int *midiindev,
+ int nmidioutdev, int *midioutdev)
+{
+#ifdef USEAPI_OSS
+ midi_oss_init();
+#endif
+ sys_do_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
+ sys_save_midi_params(nmidiindev, midiindev,
+ nmidioutdev, midioutdev);
+}
+
+ /* open midi using whatever parameters were last used */
+void sys_reopen_midi( void)
+{
+ int nmidiindev, midiindev[MAXMIDIINDEV];
+ int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
+ sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev);
+ sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
+}
+
+#define MAXNDEV 20
+#define DEVDESCSIZE 80
+
+#ifdef MSW
+#define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */
+#else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */
+#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */
+#endif
+
+void sys_listmididevs(void )
+{
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0, i;
+
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs,
+ MAXNDEV, DEVDESCSIZE);
+
+ if (!nindevs)
+ post("no midi input devices found");
+ else
+ {
+ post("input devices:");
+ for (i = 0; i < nindevs; i++)
+ post("%d. %s", i+1, indevlist + i * DEVDESCSIZE);
+ }
+ if (!noutdevs)
+ post("no midi output devices found");
+ else
+ {
+ post("output devices:");
+ for (i = 0; i < noutdevs; i++)
+ post("%d. %s", i+DEVONSET, outdevlist + i * DEVDESCSIZE);
+ }
+}
+
+extern t_class *glob_pdobject;
+
+ /* start an midi settings dialog window */
+void glob_midi_properties(t_pd *dummy, t_floatarg flongform)
+{
+ char buf[1024 + 2 * MAXNDEV*(DEVDESCSIZE+4)];
+ /* these are the devices you're using: */
+ int nindev, midiindev[MAXMIDIINDEV];
+ int noutdev, midioutdev[MAXMIDIOUTDEV];
+ int midiindev1, midiindev2, midiindev3, midiindev4,
+ midioutdev1, midioutdev2, midioutdev3, midioutdev4;
+
+ /* these are all the devices on your system: */
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0, i;
+
+ char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80],
+ outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80];
+
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs,
+ MAXNDEV, DEVDESCSIZE);
+
+ strcpy(indevliststring, "{ {none} ");
+ for (i = 0; i < nindevs; i++)
+ {
+ strcat(indevliststring, "\"");
+ strcat(indevliststring, indevlist + i * DEVDESCSIZE);
+ strcat(indevliststring, "\" ");
+ }
+ strcat(indevliststring, "}");
+
+ strcpy(outdevliststring, "{ {none} ");
+ for (i = 0; i < noutdevs; i++)
+ {
+ strcat(outdevliststring, "\"");
+ strcat(outdevliststring, outdevlist + i * DEVDESCSIZE);
+ strcat(outdevliststring, "\" ");
+ }
+ strcat(outdevliststring, "}");
+
+ sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
+
+ if (nindev > 1 || noutdev > 1)
+ flongform = 1;
+
+ midiindev1 = (nindev > 0 && midiindev[0]>= 0 ? midiindev[0]+1 : 0);
+ midiindev2 = (nindev > 1 && midiindev[1]>= 0 ? midiindev[1]+1 : 0);
+ midiindev3 = (nindev > 2 && midiindev[2]>= 0 ? midiindev[2]+1 : 0);
+ midiindev4 = (nindev > 3 && midiindev[3]>= 0 ? midiindev[3]+1 : 0);
+ midioutdev1 = (noutdev > 0 && midioutdev[0]>=0 ? midioutdev[0]+1 : 0);
+ midioutdev2 = (noutdev > 1 && midioutdev[1]>=0 ? midioutdev[1]+1 : 0);
+ midioutdev3 = (noutdev > 2 && midioutdev[2]>=0 ? midioutdev[2]+1 : 0);
+ midioutdev4 = (noutdev > 3 && midioutdev[3]>=0 ? midioutdev[3]+1 : 0);
+
+ sprintf(buf,
+"pdtk_midi_dialog %%s \
+%s %d %d %d %d %s %d %d %d %d \
+%d\n",
+ indevliststring,
+ midiindev1, midiindev2, midiindev3, midiindev4,
+ outdevliststring,
+ midioutdev1, midioutdev2, midioutdev3, midioutdev4,
+ (flongform != 0));
+ gfxstub_deleteforkey(0);
+ gfxstub_new(&glob_pdobject, glob_midi_properties, buf);
+}
+
+ /* new values from dialog window */
+void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+ int nmidiindev, midiindev[MAXMIDIINDEV];
+ int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
+ int i, nindev, noutdev;
+ int newmidiindev[4], newmidioutdev[4];
+
+ for (i = 0; i < 4; i++)
+ {
+ newmidiindev[i] = atom_getintarg(i, argc, argv);
+ newmidioutdev[i] = atom_getintarg(i+4, argc, argv);
+ }
+
+ for (i = 0, nindev = 0; i < 4; i++)
+ {
+ if (newmidiindev[i] > 0)
+ {
+ newmidiindev[nindev] = newmidiindev[i]-1;
+ nindev++;
+ }
+ }
+ for (i = 0, noutdev = 0; i < 4; i++)
+ {
+ if (newmidioutdev[i] > 0)
+ {
+ newmidioutdev[noutdev] = newmidioutdev[i]-1;
+ noutdev++;
+ }
+ }
+
+ sys_close_midi();
+ sys_open_midi(nindev, newmidiindev, noutdev, newmidioutdev);
+}