1 /* Copyright (c) 1997-1999 Miller Puckette and others.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5 /* Clock functions (which should move, but where?) and MIDI queueing */
19 #include <sys/types.h>
20 #include <sys/timeb.h>
27 typedef struct _midiqelem
31 unsigned char q_onebyte
;
32 unsigned char q_byte1
;
33 unsigned char q_byte2
;
34 unsigned char q_byte3
;
37 #define MIDIQSIZE 1024
39 t_midiqelem midi_outqueue
[MIDIQSIZE
];
40 int midi_outhead
, midi_outtail
;
41 t_midiqelem midi_inqueue
[MIDIQSIZE
];
42 int midi_inhead
, midi_intail
;
43 static double sys_midiinittime
;
45 /* this is our current estimate for at what "system" real time the
46 current logical time's output should occur. */
47 static double sys_dactimeminusrealtime
;
48 /* same for input, should be schduler advance earlier. */
49 static double sys_adctimeminusrealtime
;
51 static double sys_newdactimeminusrealtime
= -1e20
;
52 static double sys_newadctimeminusrealtime
= -1e20
;
53 static double sys_whenupdate
;
55 void sys_initmidiqueue( void)
57 sys_midiinittime
= clock_getlogicaltime();
58 sys_dactimeminusrealtime
= sys_adctimeminusrealtime
= 0;
61 /* this is called from the OS dependent code from time to time when we
62 think we know the delay (outbuftime) in seconds, at which the last-output
63 audio sample will go out the door. */
64 void sys_setmiditimediff(double inbuftime
, double outbuftime
)
66 double dactimeminusrealtime
=
67 .001 * clock_gettimesince(sys_midiinittime
)
68 - outbuftime
- sys_getrealtime();
69 double adctimeminusrealtime
=
70 .001 * clock_gettimesince(sys_midiinittime
)
71 + inbuftime
- sys_getrealtime();
72 if (dactimeminusrealtime
> sys_newdactimeminusrealtime
)
73 sys_newdactimeminusrealtime
= dactimeminusrealtime
;
74 if (adctimeminusrealtime
> sys_newadctimeminusrealtime
)
75 sys_newadctimeminusrealtime
= adctimeminusrealtime
;
76 if (sys_getrealtime() > sys_whenupdate
)
78 sys_dactimeminusrealtime
= sys_newdactimeminusrealtime
;
79 sys_adctimeminusrealtime
= sys_newadctimeminusrealtime
;
80 sys_newdactimeminusrealtime
= -1e20
;
81 sys_newadctimeminusrealtime
= -1e20
;
82 sys_whenupdate
= sys_getrealtime() + 1;
86 /* return the logical time of the DAC sample we believe is currently
87 going out, based on how much "system time" has elapsed since the
88 last time sys_setmiditimediff got called. */
89 static double sys_getmidioutrealtime( void)
91 return (sys_getrealtime() + sys_dactimeminusrealtime
);
94 static double sys_getmidiinrealtime( void)
96 return (sys_getrealtime() + sys_adctimeminusrealtime
);
99 static void sys_putnext( void)
101 int portno
= midi_outqueue
[midi_outtail
].q_portno
;
102 if (midi_outqueue
[midi_outtail
].q_onebyte
)
103 sys_putmidibyte(portno
, midi_outqueue
[midi_outtail
].q_byte1
);
104 else sys_putmidimess(portno
, midi_outqueue
[midi_outtail
].q_byte1
,
105 midi_outqueue
[midi_outtail
].q_byte2
,
106 midi_outqueue
[midi_outtail
].q_byte3
);
107 midi_outtail
= (midi_outtail
+ 1 == MIDIQSIZE
? 0 : midi_outtail
+ 1);
110 /* #define TEST_DEJITTER */
112 void sys_pollmidioutqueue( void)
117 double midirealtime
= sys_getmidioutrealtime();
119 if (midi_outhead
== midi_outtail
)
122 while (midi_outhead
!= midi_outtail
)
127 post("out: del %f, midiRT %f logicaltime %f, RT %f dacminusRT %f",
128 (midi_outqueue
[midi_outtail
].q_time
- midirealtime
),
129 midirealtime
, .001 * clock_gettimesince(sys_midiinittime
),
130 sys_getrealtime(), sys_dactimeminusrealtime
);
134 if (midi_outqueue
[midi_outtail
].q_time
<= midirealtime
)
140 static void sys_queuemidimess(int portno
, int onebyte
, int a
, int b
, int c
)
142 t_midiqelem
*midiqelem
;
143 int newhead
= midi_outhead
+1;
144 if (newhead
== MIDIQSIZE
)
146 /* if FIFO is full flush an element to make room */
147 if (newhead
== midi_outtail
)
149 midi_outqueue
[midi_outhead
].q_portno
= portno
;
150 midi_outqueue
[midi_outhead
].q_onebyte
= onebyte
;
151 midi_outqueue
[midi_outhead
].q_byte1
= a
;
152 midi_outqueue
[midi_outhead
].q_byte2
= b
;
153 midi_outqueue
[midi_outhead
].q_byte3
= c
;
154 midi_outqueue
[midi_outhead
].q_time
=
155 .001 * clock_gettimesince(sys_midiinittime
);
156 midi_outhead
= newhead
;
157 sys_pollmidioutqueue();
160 #define MIDI_NOTEON 144
161 #define MIDI_POLYAFTERTOUCH 160
162 #define MIDI_CONTROLCHANGE 176
163 #define MIDI_PROGRAMCHANGE 192
164 #define MIDI_AFTERTOUCH 208
165 #define MIDI_PITCHBEND 224
167 void outmidi_noteon(int portno
, int channel
, int pitch
, int velo
)
169 if (pitch
< 0) pitch
= 0;
170 else if (pitch
> 127) pitch
= 127;
171 if (velo
< 0) velo
= 0;
172 else if (velo
> 127) velo
= 127;
173 sys_queuemidimess(portno
, 0, MIDI_NOTEON
+ (channel
& 0xf), pitch
, velo
);
176 void outmidi_controlchange(int portno
, int channel
, int ctl
, int value
)
178 if (ctl
< 0) ctl
= 0;
179 else if (ctl
> 127) ctl
= 127;
180 if (value
< 0) value
= 0;
181 else if (value
> 127) value
= 127;
182 sys_queuemidimess(portno
, 0, MIDI_CONTROLCHANGE
+ (channel
& 0xf),
186 void outmidi_programchange(int portno
, int channel
, int value
)
188 if (value
< 0) value
= 0;
189 else if (value
> 127) value
= 127;
190 sys_queuemidimess(portno
, 0,
191 MIDI_PROGRAMCHANGE
+ (channel
& 0xf), value
, 0);
194 void outmidi_pitchbend(int portno
, int channel
, int value
)
196 if (value
< 0) value
= 0;
197 else if (value
> 16383) value
= 16383;
198 sys_queuemidimess(portno
, 0, MIDI_PITCHBEND
+ (channel
& 0xf),
199 (value
& 127), ((value
>>7) & 127));
202 void outmidi_aftertouch(int portno
, int channel
, int value
)
204 if (value
< 0) value
= 0;
205 else if (value
> 127) value
= 127;
206 sys_queuemidimess(portno
, 0, MIDI_AFTERTOUCH
+ (channel
& 0xf), value
, 0);
209 void outmidi_polyaftertouch(int portno
, int channel
, int pitch
, int value
)
211 if (pitch
< 0) pitch
= 0;
212 else if (pitch
> 127) pitch
= 127;
213 if (value
< 0) value
= 0;
214 else if (value
> 127) value
= 127;
215 sys_queuemidimess(portno
, 0, MIDI_POLYAFTERTOUCH
+ (channel
& 0xf),
219 void outmidi_mclk(int portno
)
221 sys_queuemidimess(portno
, 1, 0xf8, 0,0);
224 /* ------------------------- MIDI input queue handling ------------------ */
225 typedef struct midiparser
232 #define MIDINOTEOFF 0x80 /* 2 following 'data bytes' */
233 #define MIDINOTEON 0x90 /* 2 */
234 #define MIDIPOLYTOUCH 0xa0 /* 2 */
235 #define MIDICONTROLCHANGE 0xb0 /* 2 */
236 #define MIDIPROGRAMCHANGE 0xc0 /* 1 */
237 #define MIDICHANNELTOUCH 0xd0 /* 1 */
238 #define MIDIPITCHBEND 0xe0 /* 2 */
239 #define MIDISTARTSYSEX 0xf0 /* (until F7) */
240 #define MIDITIMECODE 0xf1 /* 1 */
241 #define MIDISONGPOS 0xf2 /* 2 */
242 #define MIDISONGSELECT 0xf3 /* 1 */
243 #define MIDIRESERVED1 0xf4 /* ? */
244 #define MIDIRESERVED2 0xf5 /* ? */
245 #define MIDITUNEREQUEST 0xf6 /* 0 */
246 #define MIDIENDSYSEX 0xf7 /* 0 */
247 #define MIDICLOCK 0xf8 /* 0 */
248 #define MIDITICK 0xf9 /* 0 */
249 #define MIDISTART 0xfa /* 0 */
250 #define MIDICONT 0xfb /* 0 */
251 #define MIDISTOP 0xfc /* 0 */
252 #define MIDIACTIVESENSE 0xfe /* 0 */
253 #define MIDIRESET 0xff /* 0 */
255 /* functions in x_midi.c */
256 void inmidi_realtimein(int portno
, int cmd
);
257 void inmidi_byte(int portno
, int byte
);
258 void inmidi_sysex(int portno
, int byte
);
259 void inmidi_noteon(int portno
, int channel
, int pitch
, int velo
);
260 void inmidi_controlchange(int portno
, int channel
, int ctlnumber
, int value
);
261 void inmidi_programchange(int portno
, int channel
, int value
);
262 void inmidi_pitchbend(int portno
, int channel
, int value
);
263 void inmidi_aftertouch(int portno
, int channel
, int value
);
264 void inmidi_polyaftertouch(int portno
, int channel
, int pitch
, int value
);
266 static void sys_dispatchnextmidiin( void)
268 static t_midiparser parser
[MAXMIDIINDEV
], *parserp
;
269 int portno
= midi_inqueue
[midi_intail
].q_portno
,
270 byte
= midi_inqueue
[midi_intail
].q_byte1
;
271 if (!midi_inqueue
[midi_intail
].q_onebyte
)
272 bug("sys_dispatchnextmidiin");
273 if (portno
< 0 || portno
>= MAXMIDIINDEV
)
274 bug("sys_dispatchnextmidiin 2");
275 parserp
= parser
+ portno
;
276 outlet_setstacklim();
279 inmidi_realtimein(portno
, byte
);
282 inmidi_byte(portno
, byte
);
285 if (byte
== MIDITUNEREQUEST
|| byte
== MIDIRESERVED1
||
286 byte
== MIDIRESERVED2
)
287 parserp
->mp_status
= 0;
288 else if (byte
== MIDISTARTSYSEX
)
290 inmidi_sysex(portno
, byte
);
291 parserp
->mp_status
= byte
;
293 else if (byte
== MIDIENDSYSEX
)
295 inmidi_sysex(portno
, byte
);
296 parserp
->mp_status
= 0;
300 parserp
->mp_status
= byte
;
302 parserp
->mp_gotbyte1
= 0;
306 int cmd
= (parserp
->mp_status
>= 0xf0 ? parserp
->mp_status
:
307 (parserp
->mp_status
& 0xf0));
308 int chan
= (parserp
->mp_status
& 0xf);
309 int byte1
= parserp
->mp_byte1
, gotbyte1
= parserp
->mp_gotbyte1
;
314 inmidi_noteon(portno
, chan
, byte1
, 0),
315 parserp
->mp_gotbyte1
= 0;
316 else parserp
->mp_byte1
= byte
, parserp
->mp_gotbyte1
= 1;
320 inmidi_noteon(portno
, chan
, byte1
, byte
),
321 parserp
->mp_gotbyte1
= 0;
322 else parserp
->mp_byte1
= byte
, parserp
->mp_gotbyte1
= 1;
326 inmidi_polyaftertouch(portno
, chan
, byte1
, byte
),
327 parserp
->mp_gotbyte1
= 0;
328 else parserp
->mp_byte1
= byte
, parserp
->mp_gotbyte1
= 1;
330 case MIDICONTROLCHANGE
:
332 inmidi_controlchange(portno
, chan
, byte1
, byte
),
333 parserp
->mp_gotbyte1
= 0;
334 else parserp
->mp_byte1
= byte
, parserp
->mp_gotbyte1
= 1;
336 case MIDIPROGRAMCHANGE
:
337 inmidi_programchange(portno
, chan
, byte
);
339 case MIDICHANNELTOUCH
:
340 inmidi_aftertouch(portno
, chan
, byte
);
344 inmidi_pitchbend(portno
, chan
, ((byte
<< 7) + byte1
)),
345 parserp
->mp_gotbyte1
= 0;
346 else parserp
->mp_byte1
= byte
, parserp
->mp_gotbyte1
= 1;
349 inmidi_sysex(portno
, byte
);
352 /* other kinds of messages are just dropped here. We'll
353 need another status byte before we start letting MIDI in
354 again (no running status across "system" messages). */
355 case MIDITIMECODE
: /* 1 data byte*/
357 case MIDISONGPOS
: /* 2 */
359 case MIDISONGSELECT
: /* 1 */
364 midi_intail
= (midi_intail
+ 1 == MIDIQSIZE
? 0 : midi_intail
+ 1);
367 void sys_pollmidiinqueue( void)
372 double logicaltime
= .001 * clock_gettimesince(sys_midiinittime
);
374 if (midi_inhead
== midi_intail
)
377 while (midi_inhead
!= midi_intail
)
382 post("in del %f, logicaltime %f, RT %f adcminusRT %f",
383 (midi_inqueue
[midi_intail
].q_time
- logicaltime
),
384 logicaltime
, sys_getrealtime(), sys_adctimeminusrealtime
);
389 if (midi_inqueue
[midi_intail
].q_time
<= logicaltime
- 0.007)
391 1000 * (logicaltime
- midi_inqueue
[midi_intail
].q_time
));
393 if (midi_inqueue
[midi_intail
].q_time
<= logicaltime
)
397 1000* (logicaltime
- midi_inqueue
[midi_intail
].q_time
));
399 sys_dispatchnextmidiin();
405 /* this should be called from the system dependent MIDI code when a byte
406 comes in, as a result of our calling sys_poll_midi. We stick it on a
407 timetag queue and dispatch it at the appropriate logical time. */
410 void sys_midibytein(int portno
, int byte
)
412 static int warned
= 0;
413 t_midiqelem
*midiqelem
;
414 int newhead
= midi_inhead
+1;
415 if (newhead
== MIDIQSIZE
)
417 /* if FIFO is full flush an element to make room */
418 if (newhead
== midi_intail
)
422 post("warning: MIDI timing FIFO overflowed");
425 sys_dispatchnextmidiin();
427 midi_inqueue
[midi_inhead
].q_portno
= portno
;
428 midi_inqueue
[midi_inhead
].q_onebyte
= 1;
429 midi_inqueue
[midi_inhead
].q_byte1
= byte
;
430 midi_inqueue
[midi_inhead
].q_time
= sys_getmidiinrealtime();
431 midi_inhead
= newhead
;
432 sys_pollmidiinqueue();
435 void sys_pollmidiqueue( void)
438 static double lasttime
;
439 double newtime
= sys_getrealtime();
440 if (newtime
- lasttime
> 0.007)
441 post("delay %d", (int)(1000 * (newtime
- lasttime
)));
444 sys_poll_midi(); /* OS dependent poll for MIDI input */
445 sys_pollmidioutqueue();
446 sys_pollmidiinqueue();
449 /******************** dialog window and device listing ********************/
452 void midi_oss_init( void);
455 /* last requested parameters */
456 static int midi_nmidiindev
;
457 static int midi_midiindev
[MAXMIDIINDEV
];
458 static int midi_nmidioutdev
;
459 static int midi_midioutdev
[MAXMIDIOUTDEV
];
461 static void sys_get_midi_params(int *pnmidiindev
, int *pmidiindev
,
462 int *pnmidioutdev
, int *pmidioutdev
)
465 *pnmidiindev
= midi_nmidiindev
;
466 for (i
= 0; i
< MAXMIDIINDEV
; i
++)
467 pmidiindev
[i
] = midi_midiindev
[i
];
468 *pnmidioutdev
= midi_nmidioutdev
;
469 for (i
= 0; i
< MAXMIDIOUTDEV
; i
++)
470 pmidioutdev
[i
] = midi_midioutdev
[i
];
473 static void sys_save_midi_params(
474 int nmidiindev
, int *midiindev
,
475 int nmidioutdev
, int *midioutdev
)
478 midi_nmidiindev
= nmidiindev
;
479 for (i
= 0; i
< MAXMIDIINDEV
; i
++)
480 midi_midiindev
[i
] = midiindev
[i
];
481 midi_nmidioutdev
= nmidioutdev
;
482 for (i
= 0; i
< MAXMIDIOUTDEV
; i
++)
483 midi_midioutdev
[i
] = midioutdev
[i
];
486 void sys_open_midi(int nmidiindev
, int *midiindev
,
487 int nmidioutdev
, int *midioutdev
)
492 sys_do_open_midi(nmidiindev
, midiindev
, nmidioutdev
, midioutdev
);
493 sys_save_midi_params(nmidiindev
, midiindev
,
494 nmidioutdev
, midioutdev
);
497 /* open midi using whatever parameters were last used */
498 void sys_reopen_midi( void)
500 int nmidiindev
, midiindev
[MAXMIDIINDEV
];
501 int nmidioutdev
, midioutdev
[MAXMIDIOUTDEV
];
502 sys_get_midi_params(&nmidiindev
, midiindev
, &nmidioutdev
, midioutdev
);
503 sys_open_midi(nmidiindev
, midiindev
, nmidioutdev
, midioutdev
);
507 #define DEVDESCSIZE 80
510 #define DEVONSET 0 /* microsoft device list starts at 0 (the "mapper"). */
511 #else /* (see also MSW ifdef in sys_parsedevlist(), s_main.c) */
512 #define DEVONSET 1 /* To agree with command line flags, normally start at 1 */
515 void sys_listmididevs(void )
517 char indevlist
[MAXNDEV
*DEVDESCSIZE
], outdevlist
[MAXNDEV
*DEVDESCSIZE
];
518 int nindevs
= 0, noutdevs
= 0, i
;
520 midi_getdevs(indevlist
, &nindevs
, outdevlist
, &noutdevs
,
521 MAXNDEV
, DEVDESCSIZE
);
524 post("no midi input devices found");
527 post("input devices:");
528 for (i
= 0; i
< nindevs
; i
++)
529 post("%d. %s", i
+1, indevlist
+ i
* DEVDESCSIZE
);
532 post("no midi output devices found");
535 post("output devices:");
536 for (i
= 0; i
< noutdevs
; i
++)
537 post("%d. %s", i
+DEVONSET
, outdevlist
+ i
* DEVDESCSIZE
);
541 extern t_class
*glob_pdobject
;
543 /* start an midi settings dialog window */
544 void glob_midi_properties(t_pd
*dummy
, t_floatarg flongform
)
546 char buf
[1024 + 2 * MAXNDEV
*(DEVDESCSIZE
+4)];
547 /* these are the devices you're using: */
548 int nindev
, midiindev
[MAXMIDIINDEV
];
549 int noutdev
, midioutdev
[MAXMIDIOUTDEV
];
550 int midiindev1
, midiindev2
, midiindev3
, midiindev4
,
551 midioutdev1
, midioutdev2
, midioutdev3
, midioutdev4
;
553 /* these are all the devices on your system: */
554 char indevlist
[MAXNDEV
*DEVDESCSIZE
], outdevlist
[MAXNDEV
*DEVDESCSIZE
];
555 int nindevs
= 0, noutdevs
= 0, i
;
557 char indevliststring
[MAXNDEV
*(DEVDESCSIZE
+4)+80],
558 outdevliststring
[MAXNDEV
*(DEVDESCSIZE
+4)+80];
560 midi_getdevs(indevlist
, &nindevs
, outdevlist
, &noutdevs
,
561 MAXNDEV
, DEVDESCSIZE
);
563 strcpy(indevliststring
, "{ {none} ");
564 for (i
= 0; i
< nindevs
; i
++)
566 strcat(indevliststring
, "\"");
567 strcat(indevliststring
, indevlist
+ i
* DEVDESCSIZE
);
568 strcat(indevliststring
, "\" ");
570 strcat(indevliststring
, "}");
572 strcpy(outdevliststring
, "{ {none} ");
573 for (i
= 0; i
< noutdevs
; i
++)
575 strcat(outdevliststring
, "\"");
576 strcat(outdevliststring
, outdevlist
+ i
* DEVDESCSIZE
);
577 strcat(outdevliststring
, "\" ");
579 strcat(outdevliststring
, "}");
581 sys_get_midi_params(&nindev
, midiindev
, &noutdev
, midioutdev
);
583 if (nindev
> 1 || noutdev
> 1)
586 midiindev1
= (nindev
> 0 && midiindev
[0]>= 0 ? midiindev
[0]+1 : 0);
587 midiindev2
= (nindev
> 1 && midiindev
[1]>= 0 ? midiindev
[1]+1 : 0);
588 midiindev3
= (nindev
> 2 && midiindev
[2]>= 0 ? midiindev
[2]+1 : 0);
589 midiindev4
= (nindev
> 3 && midiindev
[3]>= 0 ? midiindev
[3]+1 : 0);
590 midioutdev1
= (noutdev
> 0 && midioutdev
[0]>=0 ? midioutdev
[0]+1 : 0);
591 midioutdev2
= (noutdev
> 1 && midioutdev
[1]>=0 ? midioutdev
[1]+1 : 0);
592 midioutdev3
= (noutdev
> 2 && midioutdev
[2]>=0 ? midioutdev
[2]+1 : 0);
593 midioutdev4
= (noutdev
> 3 && midioutdev
[3]>=0 ? midioutdev
[3]+1 : 0);
596 "pdtk_midi_dialog %%s \
597 %s %d %d %d %d %s %d %d %d %d \
600 midiindev1
, midiindev2
, midiindev3
, midiindev4
,
602 midioutdev1
, midioutdev2
, midioutdev3
, midioutdev4
,
604 gfxstub_deleteforkey(0);
605 gfxstub_new(&glob_pdobject
, glob_midi_properties
, buf
);
608 /* new values from dialog window */
609 void glob_midi_dialog(t_pd
*dummy
, t_symbol
*s
, int argc
, t_atom
*argv
)
611 int nmidiindev
, midiindev
[MAXMIDIINDEV
];
612 int nmidioutdev
, midioutdev
[MAXMIDIOUTDEV
];
613 int i
, nindev
, noutdev
;
614 int newmidiindev
[4], newmidioutdev
[4];
616 for (i
= 0; i
< 4; i
++)
618 newmidiindev
[i
] = atom_getintarg(i
, argc
, argv
);
619 newmidioutdev
[i
] = atom_getintarg(i
+4, argc
, argv
);
622 for (i
= 0, nindev
= 0; i
< 4; i
++)
624 if (newmidiindev
[i
] > 0)
626 newmidiindev
[nindev
] = newmidiindev
[i
]-1;
630 for (i
= 0, noutdev
= 0; i
< 4; i
++)
632 if (newmidioutdev
[i
] > 0)
634 newmidioutdev
[noutdev
] = newmidioutdev
[i
]-1;
640 sys_open_midi(nindev
, newmidiindev
, noutdev
, newmidioutdev
);