1 /*****************************************************************************
2 * midifns.c
3 * Copyright 1989 Carnegie Mellon University
4 * Date | Change
5 *-----------+-----------------------------------------------------------------
6 * 29-Mar-88 | Created from IBM PC version of mpu.c
7 * | Added settime()
8 * 02-May-88 | AMIGA 2000 version. portable version.
9 * 12-Oct-88 | JCD : Exclusive AMIGA Version.
10 * 13-Apr-89 | JCD : New portable version.
11 * 19-Apr-89 | JCD : Amiga CAMD Version added.
12 * 5-Apr-91 | JDW : Further modification
13 * 17-Feb-92 | GWL : incorporate JMN's new mpu.c
14 * 8-Jun-92 | JDZ : add support for ITC midi interface
15 * 16-Dec-92 | RBD : replace JMN's mpu.c with LMS's mpu.c
16 * 11-Mar-94 | PLu : port to IRIX
17 * 25-Apr-97 | RBD : it looks like SGI changed their interface. I
18 * | made it compile again, but MIDI does not work, so
19 * | took out calls to actually send/recv MIDI data
20 * 28-Apr-03 | DM : Renamed random -> cmtrand, true->TRUE, false->FALSE
21 * | Use features rather than system names in #ifdef's
22 *****************************************************************************/
23
24 #include "switches.h"
25
26 #ifdef UNIX
27 #include <sys/resource.h>
28 #include <sys/param.h>
29 #ifndef OPEN_MAX
30 /* this is here for compiling the UNIX version under AIX. This is a BSDism */
31 #define OPEN_MAX 2000
32 #endif /* OPEN_MAX */
33 #endif /* UNIX */
34
35 #ifdef UNIX_MACH
36 #include "machmidi.h"
37 #endif
38
39
40 #ifdef AMIGA
41 #ifdef AZTEC
42 #include "functions.h"
43 #endif /* AZTEC */
44 #include "midi/camd.h"
45 #include "clib/camd_protos.h"
46 /* note: azt_camd_pragmas.h was produced by running MAPFD on the
47 * lib/camd_lib.fd file included in the CAMD disk from Commodore.
48 * The "CamdClient" calls are manually removed from
49 */
50 #ifdef AZTEC
51 #include "pragmas/azt_camd_pragmas.h"
52 #else /* !AZTEC */
53 #include "pragmas/lat_camd_pragmas.h"
54 #endif /* AZTEC */
55 #include "camdmidi.h"
56 #include "ctype.h"
57 #endif /* AMIGA */
58
59 #ifdef UNIX_IRIX
60 /* #define UNIX_IRIX_MIDIFNS -- this would enable actual midi I/O
61 * if the actual midi I/O code worked
62 */
63 /* IRIX changed the MIDI interface,
64 * retain this for older systems:
65 */
66 #ifdef UNIX_IRIX_MIDIFNS
67 #include <dmedia/midi.h>
68 #endif
69 #endif
70
71 #include "stdio.h"
72 #include "cext.h"
73 #include "midicode.h"
74 #include "cmdline.h"
75 #include "pitch.h"
76 #include "midifns.h"
77 #include "userio.h"
78 #include "string.h"
79 #ifdef MACINTOSH_OR_DOS
80 #ifndef WINDOWS
81 #include "midibuff.h"
82 #endif
83 #endif
84
85 #ifdef UNIX_ITC /* was ITC */
86 #include "sys/param.h"
87 /* since boolean is defined, block its definition in midistruct.h.
88 * CMT defines boolean as ushort, but midistruct.h uses int.
89 * This is not a problem on RS/6000s, but beware!
90 */
91 /* the following would be included if we had the BSD switch set. I think
92 we should try to avoid BSDisms; when fixed, the following should be
93 removed
94 */
95 #define NBBY 8
96 #include "sys/select.h" /* defines fd_set */
97 #define MIDI_HAS_BOOLEAN
98 #include "midistruct.h"
99 #include "cmtio.h"
100 #endif /* UNIX_ITC */
101
102 #ifdef DOS
103 #ifndef WINDOWS
104 #include "timer.h"
105 #include "mpu.h"
106 #endif /* ifndef WINDOWS */
107 #endif /* ifdef DOS */
108
109 #ifndef BREAKTEST
110 #define BREAKTEST
111 #endif
112
113 #ifdef UNIX_MACH
114 #include <sys/types.h>
115 #include <sys/time.h>
116 #include <errno.h>
117 #else
118 #ifdef UNIX
119 #ifndef UNIX_IRIX
120 #include "sys/time.h"
121 #include "sys/timeb.h"
122 #include "cmtio.h"
123 #else
124 #include <sys/types.h>
125 #include <sys/time.h>
126 #include <errno.h>
127
128 #ifdef UNIX_IRIX_MIDIFNS
129 #include <midi.h>
130 #include <midiio.h>
131 #endif /* UNIX_IRIX_MIDIFNS */
132 #endif /* UNIX_IRIX */
133 #endif /* UNIX */
134 #endif /* UNIX_MACH */
135
136 #ifdef ITC
137 static int ignore_realtime = 0;
138 #endif /* ITC */
139
140 #ifdef MACINTOSH
141
142 /* added for ThinkC 7: */
143 #include <OSUtils.h>
144
145 /* port numbers are in the range 0..MAX_PORTS-1 */
146 #define CHANNELS_PER_PORT 16
147 #define MAX_PORTS ((MAX_CHANNELS + CHANNELS_PER_PORT - 1) / CHANNELS_PER_PORT)
148
149 /* here are some MIDIMGR specific definitions */
150 #ifdef MIDIMGR
151 #include "MIDI.h"
152 #include "midimgr.h"
153
154 #define TICKS_TO_MS(t) t
155 #define MS_TO_TICKS(t) t
156
157 #else
158 /* here are some non-MIDIMGR definitions for the Mac */
159 /****************************************************************************
160 *
161 * DMH: constants from macmidi.c
162 *
163 ****************************************************************************/
164
165 /* the modem port, also called port A */
166 #define portA 0
167
168 /* the printer port, also called port B */
169 #define portB 1
170
171 /* a tick is 1/60 of a second
172 *
173 * the following tables and routines are used to convert
174 * between ticks and milliseconds
175 */
176 #define TICKS_TO_MS(t) (((t) * 50) / 3)
177 #define MS_TO_TICKS(t) (((t) * 3) / 50)
178 #endif /* def MIDIMGR */
179 #endif /* def MACINTOSH */
180
181 #ifdef WINDOWS
182 #define huge
183 #endif
184
185 /****************************************************************************
186 *
187 * exported flags
188 *
189 ****************************************************************************/
190
191 boolean miditrace = FALSE; /* enables printed trace of MIDI output */
192 boolean musictrace = FALSE; /* enables printed trace of commands */
193 #ifdef MACINTOSH_OR_DOS
194 boolean ctrlFilter = TRUE; /* suppress continuous controller data */
195 boolean exclFilter = TRUE; /* suppress exclusive messages */
196 boolean realFilter = TRUE; /* suppress realtime messages */
197 #endif
198
199 /****************************************************************************
200 *
201 * exported variables
202 *
203 ****************************************************************************/
204
205 public int keyloud; /* set to velocity of last getkey event */
206 /* public long error; */
207 public short midi_error_flags = 0;
208
209 /* The following midifns_syntax lists command line switches and options.
210 Since these are machine dependent, use conditional compilation.
211 Conditional compilation within a string is a bit tricky: you want to
212 write "\" for line continuation within the string, but "\" gets eaten
213 by the macro preprocessor.
214 That's why we define macros like AMIGAINPORT.
215 Regretably it doesn't work for all compilers.
216 */
217
218
219 /* Lattice and RT/Unix aren't happy expanding the embedded macros below, so
220 I made a separate declaration of midifns_syntax for Unix
221 */
222 #ifdef UNIX
223 public char *midifns_syntax = "block<s>Turn off midi THRU;\
224 miditrace<s>Trace low-level midi functions;\
225 noalloff<s>Do not send alloff message when done;\
226 trace<s>Trace music operations;\
227 tune<o>Load a tuning file";
228 #else
229 #ifdef MACINTOSH
230 #ifdef MIDIMGR
231 public char *midifns_syntax = "miditrace<s>Trace low-level midi functions;\
232 noalloff<s>Do not send alloff message when done;\
233 patch<s>Remember/reuse Midi Mgr patches;\
234 trace<s>Trace music operations;\
235 keep<s>Keep other processes running;\
236 tune<o>Load a tuning file";
237 #else /* no MIDIMGR */
238 public char *midifns_syntax = "miditrace<s>Trace low-level midi functions;\
239 noalloff<s>Do not send alloff message when done;\
240 patch<s>Remember/reuse Midi Mgr patches;\
241 trace<s>Trace music operations;\
242 tune<o>Load a tuning file";
243 #endif /* MIDIMGR */
244 #else
245 #ifdef AMIGA
246 public char *midifns_syntax = "block<s>Turn off midi THRU;\
247 inport<o>Inpur port number;\
248 miditrace<s>Trace low-level midi functions;\
249 noalloff<s>Do not send alloff message when done;\
250 outport<o>Output port number;\
251 trace<s>Trace music operations;\
252 tune<o>Load a tuning file";
253 #else /* not UNIX or MACINTOSH or MIDIMGR or AMIGA */
254 #ifdef DOS
255 public char *midifns_syntax = "miditrace<s>Trace low-level midi functions;\
256 noalloff<s>Do not send alloff message when done;\
257 trace<s>Trace music operations;\
258 tune<o>Load a tuning file";
259 #endif /* DOS */
260 #endif /* AMIGA */
261 #endif /* MACINTOSH */
262 #endif /* UNIX */
263
264 #ifdef MACINTOSH
265 boolean do_midi_thru = FALSE; /* exported: copy midi in to midi out */
266 #endif
267
268
269 /****************************************************************************
270 *
271 * local module variables
272 *
273 ****************************************************************************/
274
275 private int initialized = FALSE; /* set by musicinit, cleared by musicterm */
276 private boolean tune_flag = FALSE; /* set by musicinit, never cleared */
277 #ifdef DOS
278 private boolean metroflag = FALSE; /* flag to turn on metronome */
279 #endif
280 private int user_scale = FALSE; /* TRUE if user-defined scale */
281 private int bend[MAX_CHANNELS]; /* current pitch bend on channel */
282 short cur_midi_prgm[MAX_CHANNELS];
283 private pitch_table pit_tab[128]; /* scale definition */
284
285 #ifdef DOS
286 private ulong timeoffset = 0;
287 public boolean exclerr = FALSE;
288 public byte xcodemask; /* mask (00 or FF) */
289 public byte xcode; /* mfr code */
290 #endif
291
292 #ifdef MACINTOSH_OR_DOS
293 boolean sysex_pending = FALSE;
294 #endif
295
296 #ifdef AMIGA
297
298 #define CONTCONT ((CMF_Ctrl & ~CMF_CtrlSwitch) | CMF_PitchBend | \
299 CMF_ChanPress)
300 #endif /* def AMIGA */
301
302 #ifdef UNIX
303 private ulong timeoffset = 0;
304 #endif
305
306 #ifdef UNIX_IRIX_MIDIFNS
307 static MIport *miport;
308 static int ignore_realtime = 0;
309
310 private byte *sysex_p;
311 private int sysex_n;
312 #endif
313
314 #ifdef ITC
315 mi_id midiconn;
316 #endif
317
318 #ifdef MACINTOSH
319 private ulong ticksAtStart = 0L;
320 /* clock ticks at time of last musicinit or timereset
321 * ASSUME: tick clock never wraps. this is a good assumption, since
322 * the tick clock is set to zero when the power is turned on and the
323 * tick counter is 32 bits. the Macintosh would need to be on for
324 * 828.5 days for the tick counter to wrap around! */
325
326 #endif /* def MACINTOSH */
327
328 /****************************************************************************
329 *
330 * functions declared in this module
331 *
332 ****************************************************************************/
333
334 private void fixup(void);
335 private void midi_init(void);
336 extern boolean check_ascii(void); /*userio.c*/
337 private void musicterm(void);
338
339
340 /****************************************************************************
341 * alloff
342 * Inputs:
343 * none
344 * Effect:
345 * Sends MIDI all notes off command on every channel.
346 ****************************************************************************/
347
348 #define ALL_NOTES_OFF 0x7B /*DMH: from macmidi.c*/
349
alloff(void)350 void alloff(void)
351 {
352 int c;
353
354 if (!initialized) fixup();
355 if (musictrace)
356 gprintf(TRANS,"alloff()\n");
357 for (c = 1; c <= MAX_CHANNELS; c++) {
358 midi_write(3, MIDI_PORT(c), (byte) (0xb0 | MIDI_CHANNEL(c)), ALL_NOTES_OFF, 0);
359 }
360 }
361
362
363
364 /***************************************************************
365 * eventwait
366 *
367 * Input : wakeup time, -1 means forever
368 * Output : none
369 * Return: none
370 * Effect: waits until ascii or midi input or timeout
371 ***************************************************************/
372
373 #ifdef UNIX_ITC
eventwait(long timeout)374 void eventwait(long timeout)
375 {
376 struct timeval unix_timeout;
377 struct timeval *waitspec = NULL;
378 fd_set readfds;
379 struct rlimit file_limit;
380
381 FD_ZERO(&readfds);
382 FD_SET(MI_CONNECTION(midiconn), &readfds);
383 FD_SET(fileno(stdin), &readfds);
384 if (timeout >= 0) {
385 timeout -= gettime(); /* convert to millisecond delay */
386 unix_timeout.tv_sec = timeout / 1000;
387 /* remainder become microsecs: */
388 unix_timeout.tv_usec = (timeout - (unix_timeout.tv_sec * 1000)) * 1000;
389 waitspec = &unix_timeout;
390 }
391 getrlimit(RLIMIT_NOFILE, &file_limit);
392 select(file_limit.rlim_max+1, &readfds, 0, 0, waitspec);
393 return;
394 }
395 #else /* !UNIX_ITC */
396 #ifdef UNIX
397 /* see machmidi.c for UNIX_MACH (OS X) implementation */
398 #ifndef UNIX_MACH
399 #ifdef UNIX_IRIX_MIDIFNS
eventwait(timeout)400 void eventwait(timeout)
401 long timeout;
402 {
403 struct timeval unix_timeout;
404 struct timeval *waitspec = NULL;
405 fd_set readfds;
406
407 FD_ZERO(&readfds);
408 FD_SET(mdGetFd(miport), &readfds);
409 FD_SET(fileno(stdin), &readfds);
410 if (timeout >= 0) {
411
412 timeout -= gettime(); /* convert to millisecond delay */
413 unix_timeout.tv_sec = timeout / 1000;
414 /* remainder become microsecs: */
415 unix_timeout.tv_usec = (timeout - (unix_timeout.tv_sec * 1000)) * 1000;
416 waitspec = &unix_timeout;
417 }
418 select(FD_SETSIZE, &readfds, 0, 0, waitspec);
419
420 return;
421 }
422 #else
423 #ifdef BUFFERED_SYNCHRONOUS_INPUT
eventwait(long timeout)424 void eventwait(long timeout)
425 {
426 struct timeval unix_timeout;
427 struct timeval *waitspec = NULL;
428 struct rlimit file_limit;
429
430 if (timeout >= 0) {
431 timeout -= gettime(); /* convert to millisecond delay */
432 unix_timeout.tv_sec = timeout / 1000;
433 /* remainder become microsecs: */
434 unix_timeout.tv_usec = (int)
435 (timeout - (unix_timeout.tv_sec * 1000)) * 1000;
436 waitspec = &unix_timeout;
437 getrlimit(RLIMIT_NOFILE, &file_limit);
438 select((int) (file_limit.rlim_max+1), 0, 0, 0, waitspec);
439 } else {
440 int c = getc(stdin);
441 ungetc(c, stdin);
442 }
443 return;
444 }
445 #else
eventwait(long timeout)446 void eventwait(long timeout)
447 {
448 struct timeval unix_timeout;
449 struct timeval *waitspec = NULL;
450 int readfds = 1 << IOinputfd;
451 struct rlimit file_limit;
452
453 if (timeout >= 0) {
454 timeout -= gettime(); /* convert to millisecond delay */
455 unix_timeout.tv_sec = timeout / 1000;
456 /* remainder become microsecs: */
457 unix_timeout.tv_usec = (timeout - (unix_timeout.tv_sec * 1000)) * 1000;
458 waitspec = &unix_timeout;
459 }
460 getrlimit(RLIMIT_NOFILE, &file_limit);
461 select(file_limit.rlim_max+1, &readfds, 0, 0, waitspec);
462 return;
463 }
464 #endif /* BUFFERED_SYNCHRONOUS_INPUT */
465 #endif /* UNIX_IRIX */
466 #endif /* UNIX_MACH */
467 #endif /* UNIX */ /* I wanted to put an else here, but this confused a Unix C compiler */
468 #endif /* UNIX_ITC */
469 #ifdef AMIGA
470 /* see camdmidi.c for Amiga implementation */
471 #else
472 #ifndef UNIX /* since I couldn't use an else above, have to check UNIX here */
473 #ifdef WINDOWS
eventwait(long timeout)474 void eventwait(long timeout)
475 {
476 if (timeout >= 0) {
477 gprintf(TRANS, "eventwait: not implemented\n");
478 return;
479 } else {
480 int c = getc(stdin);
481 ungetc(c, stdin);
482 }
483 return;
484 }
485 #else
eventwait(timeout)486 void eventwait(timeout)
487 long timeout;
488 {
489 while (timeout > gettime() || timeout == -1) {
490 if (check_ascii() || check_midi()) return;
491 }
492 }
493 #endif /* WINDOWS */
494 #endif /* UNIX */
495 #endif /* AMIGA */
496
497
498 /****************************************************************************
499 * exclusive
500 * Inputs:
501 * boolean onflag -- set to TRUE to receive midi exclusive data
502 * Effect:
503 * Tells module to read exclusive messages into buffer
504 ****************************************************************************/
505
exclusive(boolean onflag)506 void exclusive(boolean onflag)
507 {
508 if (!initialized) fixup();
509 if (musictrace) gprintf(TRANS, "exclusive: %d\n", onflag);
510 #ifdef AMIGA
511 if (onflag) SetMidiFilters(cmt_mi,
512 cmt_mi->PortFilter, cmt_mi->TypeFilter | CMF_SysEx, cmt_mi->ChanFilter);
513 else SetMidiFilters(cmt_mi,
514 cmt_mi->PortFilter, cmt_mi->TypeFilter & ~CMF_SysEx, cmt_mi->ChanFilter);
515 #endif
516 #ifdef MACINTOSH_OR_DOS
517 exclFilter = !onflag;
518 #endif
519 }
520
521
522 /****************************************************************************
523 * fixup
524 * Effect:
525 * Print error message and call musicinit
526 ****************************************************************************/
527
fixup(void)528 private void fixup(void)
529 {
530 gprintf(ERROR, "You forgot to call musicinit. I'll do it for you.\n");
531 musicinit();
532 }
533
534 #ifdef UNIX_IRIX_MIDIFNS
535 private void flush_sysex(void);
536 #endif
537
get_excl(byte * buffer,long len)538 long get_excl(byte *buffer, long len)
539 {
540 long ret = 0;
541 #ifdef UNIX_IRIX_MIDIFNS
542 byte *sxp = sysex_p;
543 long l = len;
544 #endif
545 #ifdef UNIX_ITC /* was ITC */
546 ret = mi_getx(midiconn, FALSE, len, (char *) buffer);
547 #endif
548 #ifdef UNIX_MACH
549 ret = mi_getx(midiconn, FALSE, len, (unsigned char *)buffer);
550 #endif
551 #ifdef UNIX_IRIX_MIDIFNS
552 if (!sysex_p) return 0;
553 if (len > sysex_n) len = sysex_n;
554 while (l--)
555 {
556 *buffer = *(sxp++);
557 if (*(buffer++) == CMT_MIDI_EOX)
558 {
559 flush_sysex();
560 break;
561 }
562 }
563 ret = len - l - 1;
564 #endif
565 #ifdef AMIGA
566 ret = GetSysEx(cmt_mi, (UBYTE *) buffer, len);
567 AMIGA_ERROR_CHECK;
568 #endif
569 #ifdef MACINTOSH_OR_DOS
570 #ifndef WINDOWS
571 /* I'm not sure the following line is a good thing: it forces the
572 * caller to wait until a full sysex message is received and the
573 * 1st 4 bytes are fetched via getbuf() before a sysex message can
574 * be read via get_excl(). Without this, both mm.c and exget.c
575 * were fetching ahead and getting out of sync with getbuf(). I
576 * fixed mm.c and exget.c to work (by checking for EOX), but I added
577 * this line (which should never have any effect) just to make the
578 * DOS interface behave more like the Amiga and Mac interfaces. The
579 * drawback is that you can't fetch bytes until the EOX is seen,
580 * because nothing goes into the getbuf() buffer until then.
581 */
582 if (!sysex_pending) return 0;
583 while (len-- && (xbufhead != xbuftail)) {
584 *buffer = xbuff[xbufhead++];
585 ret++;
586 if (*buffer == MIDI_EOX) {
587 sysex_pending = FALSE;
588 break;
589 }
590 buffer++;
591 xbufhead &= xbufmask;
592 }
593 #endif
594 #endif
595 return ret;
596 }
597
598 /****************************************************************************
599 * getbuf
600 * Inputs:
601 * boolean waitflag: TRUE if routine should wait for data
602 * byte * p: Pointer to data destination
603 * Result: boolean
604 * TRUE if data was written to *p
605 * FALSE if data not written to *p
606 * Effect:
607 * copies data from buffer to *p
608 * will wait for buffer to become nonempty if waitflag is TRUE
609 *
610 * Modified 24 May 1988 for AMIGA (JCD)
611 ****************************************************************************/
612
613 #ifdef UNIX_IRIX_MIDIFNS
614 private void setup_sysex(MDevent *event, u_char *buffer);
615 #endif /* UNIX_IRIX */
getbuf(boolean waitflag,unsigned char * p)616 boolean getbuf(boolean waitflag, unsigned char * p)
617 {
618 #ifdef UNIX_IRIX_MIDIFNS
619 MDevent event;
620 int ret;
621 #endif /* UNIX_IRIX */
622
623 if (!initialized) fixup();
624 #ifdef UNIX
625 #ifdef UNIX_IRIX_MIDIFNS
626 /* current IRIX version ignores the waitflag (it never waits) */
627
628 if (sysex_p) flush_sysex();
629 if (ignore_realtime == 0) {
630 ret = mdReceive(miport, &event, 1);
631 if (ret) {
632 if (event.msg[0] != 0xF0) {
633 *((u_long*) p) = *((u_long*) event.msg);
634 } else {
635 setup_sysex(&event, p);
636 }
637 }
638 return ret;
639 } else {
640 do /* skip realtime messages */
641 {
642 ret = mdReceive(miport, &event, 1);
643 if (ret == -1) return ret;
644 } while (event.msg[0] == 0xf8);
645 if (event.msg[0] != 0xF0) {
646 *((u_long*) p) = *((u_long*) event.msg);
647 } else {
648 setup_sysex(&event, p);
649 }
650 return ret;
651 }
652 #endif /* UNIX_IRIX */
653 #ifdef UNIX_ITC
654 if (ignore_realtime == 0) {
655 return(mi_get(midiconn, waitflag, (char *) p));
656 }
657 else {
658 boolean ret=false;
659 /* filter out realtime msgs */
660 do {
661 ret = mi_get(midiconn, waitflag, (char *) p);
662 if (ret == FALSE)
663 return(ret);
664 } while(p[0] == 0xf8);
665 return(ret);
666 }
667 #else /* UNIX_ITC */
668 #ifndef UNIX_IRIX
669 if (waitflag) {
670 gprintf(ERROR, "getbuf called with waitflag!");
671 EXIT(1);
672 }
673 return FALSE;
674 #endif /* UNIX_IRIX */
675 #endif /* UNIX_ITC */
676 #endif /* UNIX */
677
678 #ifdef MACINTOSH_OR_DOS
679 #ifndef WINDOWS
680 if (sysex_pending) { /* flush sysex to keep buffers in sync */
681 while (xbuff[xbufhead++] != MIDI_EOX) {
682 xbufhead &= xbufmask;
683 if (xbufhead == xbuftail) break;
684 }
685 sysex_pending = FALSE;
686 }
687 if (waitflag) while (buffhead == bufftail) /* wait */ ;
688 else if (buffhead == bufftail) return(false);
689 *(long *)p = *(long *)(((char *)buff)+buffhead);
690 buffhead = (buffhead + 4) & BUFF_MASK;
691 if (*p == MIDI_SYSEX) { /* if sys-ex, remember to fetch from xbuff */
692 sysex_pending = TRUE;
693 }
694 return(true);
695 #else
696 return FALSE;
697 #endif /* WINDOWS */
698 #endif /* MACINTOSH_OR_DOS */
699
700 #ifdef AMIGA
701 if (waitflag) {
702 do {
703 WaitMidi(cmt_mi, &cmt_msg);
704 AMIGA_ERROR_CHECK;
705 } while (amigaerrflags);
706 } else {
707 AMIGA_ERROR_CHECK;
708 if (!GetMidi(cmt_mi, &cmt_msg)) return(false);
709 }
710 *(long *)p = *(long *)&cmt_msg;
711 clearmsg(cmt_msg);
712 return(true);
713 #endif /* AMIGA */
714 }
715
716 #ifdef UNIX_IRIX_MIDIFNS
717
setup_sysex(MDevent * event,u_char * buffer)718 private void setup_sysex(MDevent *event, u_char *buffer)
719 /* N.B. do not leak memory remember to call free(sysex_p) */
720 {
721 u_char *sxp = (u_char *) event->sysexmsg;
722 int i;
723
724 for (i=0;i<4;i++)
725 *(buffer++) = *(sxp++);
726 sysex_p = event->sysexmsg;
727 sysex_n = event->msglen;
728 }
729
flush_sysex(void)730 private void flush_sysex(void)
731 {
732 mdFree(sysex_p);
733 sysex_p = 0;
734 sysex_n = 0;
735 }
736 #endif
737
738 #ifdef MACINTOSH_OR_DOS
739 #ifndef WINDOWS
check_midi(void)740 public boolean check_midi(void)
741 {
742 if (buffhead == bufftail) return FALSE;
743 else return TRUE;
744 }
745 #endif
746 #endif
747
748
749 /****************************************************************************
750 * getkey
751 * Inputs:
752 * boolean waitflag: TRUE if wait until key depression, FALSE if
753 * return immediately
754 * Result: int
755 * key number of key which has been depressed
756 * It returns -1 if waitflag is FALSE and no key has been pressed
757 * If waitflag is TRUE this routine will block until a key is pressed
758 * Effect:
759 * reads a key
760 ****************************************************************************/
761
762 /*DMH: in previous version, macmidi.c subtracted 12 from msg to get key at each occurence...*/
763
getkey(boolean waitflag)764 short getkey(boolean waitflag)
765 {
766 byte msg[4];
767 short k;
768
769 if (!initialized) fixup();
770
771 while (TRUE) { /* process data until you find a note */
772 /* look for data and exit if none found */
773 /* NOTE: waitflag will force waiting until data arrives */
774 if (!getbuf(waitflag, msg)) { /* nothing there */
775 k = -1;
776 break;
777 } else if ((msg[0] & MIDI_CODE_MASK) == MIDI_ON_NOTE) {
778 if (msg[2] == 0) { /* velocity 0 -> note off */
779 keyloud = 0;
780 k = msg[1] + 128;
781 } else {
782 keyloud = msg[2];
783 k = msg[1];
784 }
785 break;
786 } else if ((msg[0] & MIDI_CODE_MASK) == MIDI_OFF_NOTE) {
787 keyloud = 0;
788 k = msg[1] + 128;
789 break;
790 }
791 }
792 if (musictrace) {
793 if (k != -1) gprintf(TRANS,"getkey got %d\n", k);
794 }
795 return k;
796 }
797
798
799 /****************************************************************************
800 * gettime
801 * Result: ulong
802 * current timestamp since the last call to
803 * musicinit or timereset
804 * Effect:
805 * fakes it
806 ****************************************************************************/
807
gettime(void)808 ulong gettime(void) /*DMH: ulong is from mpu->midifns conversion, for Mac*/
809 {
810 #if HAS_GETTIMEOFDAY
811 struct timeval timeval;
812 #endif
813 #if HAS_FTIME
814 struct timeb ftime_res;
815 #endif
816 register ulong ticks = 0L;
817
818 BREAKTEST /* abort if user typed Ctrl Break */
819 if (!initialized) fixup();
820
821 #ifdef MACINTOSH
822 #ifdef MIDIMGR
823 ticks = MIDIGetCurTime(OutputRefNum) - ticksAtStart;
824 #else
825 ticks = TickCount() - ticksAtStart;
826 #endif
827 if (initialized) abort_check(); /* give user a chance to abort */
828 ticks = TICKS_TO_MS(ticks);
829 #endif
830
831 #ifdef AMIGA
832 ticks = (*camdtime - timeoffset) << 1; /* return milliseconds */
833 #endif
834
835 #ifdef DOS
836 #ifndef WINDOWS
837 ticks = elapsedtime(timeoffset, readtimer()); /* return milliseconds */
838 /* gprintf(TRANS, "currtime = %ld, timeoffset = %ld\n", currtime, timeoffset); */
839 #endif
840 #endif /* ifdef DOS */
841
842 #if HAS_GETTIMEOFDAY
843 gettimeofday(&timeval, 0);
844 ticks = timeval.tv_sec * 1000 + timeval.tv_usec / 1000 - timeoffset;
845 #endif
846 #if HAS_FTIME
847 ftime(&ftime_res);
848 ticks = ((ftime_res.time - timeoffset) * 1000) + ftime_res.millitm;
849 #endif
850
851 /* if (miditrace) gprintf(TRANS, "."); */
852 return(ticks);
853 }
854
855
856 /****************************************************************************
857 * l_rest
858 * Inputs:
859 * long time: Amount of time to rest
860 * Effect:
861 * Waits until the amount of time specified has lapsed
862 ****************************************************************************/
863
l_rest(long time)864 void l_rest(long time)
865 {
866 if (!initialized) fixup();
867 l_restuntil(time + gettime());
868 }
869
870 /****************************************************************************
871 * l_restuntil
872 * Inputs:
873 * long time: Event time to rest until
874 * Effect:
875 * Waits until the specified time has been reached (absolute time)
876 ****************************************************************************/
877
l_restuntil(long time)878 void l_restuntil(long time)
879 {
880 #ifdef MACINTOSH
881 ulong now = gettime();
882 ulong junk; /* changed from ulong for ThinkC 7, back to ulong for CW5 */
883 #endif
884
885 #ifdef AMIGA
886 while (time > gettime()) eventwait(time);
887 #else
888 for(; (time_type) time > gettime(););
889 #endif
890
891 #ifdef MACINTOSH
892 now = gettime();
893
894 if (time > now) Delay(MS_TO_TICKS(time - now), &junk);
895 /* else time <= now, so return immediately */
896 #endif
897
898 }
899
900 /****************************************************************************
901 * metronome
902 * Inputs:
903 * boolean onflag: TRUE or FALSE
904 * Effect:
905 * enables (true) or disables (false) MPU-401 metronome function.
906 * must be called before musicinit
907 ****************************************************************************/
908
metronome(boolean onflag)909 void metronome(boolean onflag)
910 {
911 #ifdef DOS
912 metroflag = onflag;
913 #endif
914 }
915
916
917 /****************************************************************************
918 * midi_bend
919 * Inputs:
920 * int channel: midi channel on which to send data
921 * int value: pitch bend value
922 * Effect:
923 * Sends a midi pitch bend message
924 ****************************************************************************/
925
midi_bend(int channel,int value)926 void midi_bend(int channel, int value)
927 {
928 if (!initialized) fixup();
929 if (musictrace)
930 gprintf(TRANS,"midi_bend: ch %d, val %d\n", channel, value - (1 << 13));
931 bend[MIDI_CHANNEL(channel)] = value;
932
933 midi_write(3, MIDI_PORT(channel), (byte) (MIDI_BEND | MIDI_CHANNEL(channel)),
934 (byte) MIDI_DATA(value), (byte) MIDI_DATA(value >> 7));
935 }
936
937
938 /****************************************************************************
939 * midi_buffer
940 * Inputs:
941 * byte * buffer: the buffer address
942 * int size: number of bytes in buffer
943 * Returns:
944 * FALSE if size is less than 16 or buffer is NULL, otherwise TRUE
945 * Effect: DOS, MAC:
946 * tells interrupt routine to store system exclusive messages in
947 * buffer. The largest power of 2 bytes less than size will be
948 * used. xbufhead and xbuftail will be initialized to zero,
949 * and xbuftail will be one greater than the index of the last
950 * system exclusive byte read. Since there may already be a buffer
951 * and therefore the normal midi message buffer may have the first
952 * 4 bytes of some sysex messages, clear the normal midi buffer too.
953 * AMIGA:
954 * adds buffer to midi interface
955 *
956 ****************************************************************************/
957
midi_buffer(byte huge * buffer,ulong size)958 boolean midi_buffer(byte huge *buffer, ulong size)
959 {
960 if (!buffer) return FALSE;
961 #ifdef AMIGA
962 if (!SetSysExQueue(cmt_mi, (UBYTE *) buffer, (ULONG) size)) return(false);
963 cu_register(remove_sysex_buffer, buffer);
964 #endif
965
966 #ifdef MACINTOSH_OR_DOS
967 #ifndef WINDOWS
968 {
969 int mask = 0x000F;
970
971 if (size < 16) return(false);
972 while (mask < size && mask > 0) mask = ((mask << 1) | 1);
973 midi_flush();
974 xbuff = NULL; /* turn off buffering */
975 xbufmask = mask >> 1;
976 xbufhead = xbuftail = 0;
977 xbuff = buffer; /* set buffer, turn on buffering */
978 }
979 #endif
980 #endif
981 #ifdef UNIX
982 return FALSE;
983 #else
984 exclusive(TRUE);
985 return TRUE;
986 #endif
987 }
988
989
990 /* midi_clock -- send a midi time clock message */
991 /**/
midi_clock()992 void midi_clock()
993 {
994 if (!initialized) fixup();
995 if (musictrace) gprintf(TRANS, "+");
996 midi_write(1, 0, MIDI_TIME_CLOCK, 0, 0);
997 }
998
999
1000 /****************************************************************************
1001 * midi_cont
1002 * Inputs:
1003 * boolean onflag: TRUE or FALSE
1004 * Effect:
1005 * enables (true) or disables (false) continuous control
1006 ****************************************************************************/
1007
midi_cont(boolean onflag)1008 void midi_cont(boolean onflag)
1009 {
1010 if (!initialized) fixup();
1011 if (onflag) {
1012 #ifdef AMIGA
1013 SetMidiFilters(cmt_mi, cmt_mi->PortFilter,
1014 cmt_mi->TypeFilter | CONTCONT, cmt_mi->ChanFilter);
1015 #endif
1016 #ifdef DOS
1017 #ifndef WINDOWS
1018 mPutCmd(BENDERON);
1019 #endif
1020 #endif
1021 } else {
1022 #ifdef AMIGA
1023 SetMidiFilters(cmt_mi, cmt_mi->PortFilter,
1024 cmt_mi->TypeFilter & ~CONTCONT, cmt_mi->ChanFilter);
1025 #endif
1026 }
1027 #ifdef MACINTOSH_OR_DOS
1028 ctrlFilter = !onflag;
1029 #endif
1030 if (musictrace) gprintf(TRANS,"midi_cont: %d\n", onflag);
1031 }
1032
1033
1034 /****************************************************************************
1035 * midi_ctrl
1036 * Inputs:
1037 * int channel: midi channel on which to send data
1038 * int control: control number
1039 * int value: control value
1040 * Effect:
1041 * Sends a midi control change message
1042 ****************************************************************************/
1043
midi_ctrl(int channel,int control,int value)1044 void midi_ctrl(int channel, int control, int value)
1045 {
1046 if (!initialized) fixup();
1047 if (musictrace)
1048 gprintf(TRANS,"midi_ctrl: ch %d, ctrl %d, val %d\n",
1049 channel, control, value);
1050
1051 midi_write(3, MIDI_PORT(channel), (byte) (MIDI_CTRL | MIDI_CHANNEL(channel)),
1052 (byte) MIDI_DATA(control), (byte) MIDI_DATA(value));
1053 }
1054
1055
1056 /****************************************************************************
1057 * midi_exclusive
1058 * Inputs:
1059 * byte *msg: pointer to a midi exclusive message, terminated by 0xF7
1060 * Effect:
1061 * Sends a midi exclusive message
1062 * Bugs:
1063 * 18-mar-94 PLu : This function does not know which port to send to in
1064 * case of multiple midi-ports (MAC, IRIX)
1065 ****************************************************************************/
1066
1067 #ifdef MACINTOSH
1068 #define INTERBYTE_DELAY 10
1069 #endif
1070
midi_exclusive(msg)1071 void midi_exclusive(msg)
1072 unsigned char *msg; /* the data to be sent */
1073 {
1074 #ifdef ITC
1075 int count, done, tosend, willsend;
1076 unsigned char *m;
1077 mi_status ret;
1078 #endif
1079 #ifdef UNIX_IRIX_MIDIFNS
1080 unsigned char *m;
1081 MDevent mdevent;
1082 #endif
1083
1084 #ifdef MACINTOSH
1085 #ifndef NYQUIST
1086 int i; /* for DX7 delay loop */
1087 int count = 0; /* counter for formatting midi byte trace */
1088 MIDIPacket TheMIDIPacket;
1089 unsigned char prev = 0;
1090 boolean first_packet = TRUE;
1091 #endif
1092 #endif
1093
1094 /*
1095 * if user mistakenly called midi_exclusive instead of exclusive,
1096 * the argument will be TRUE or FALSE, both of which are highly
1097 * unlikely valid arguments for midi_exclusive:
1098 */
1099
1100 if (msg == (byte *) FALSE || msg == (byte *) TRUE) {
1101 gprintf(ERROR,"midi_exclusive: invalid argument %u.\n", msg);
1102 EXIT(1);
1103 }
1104 if (!initialized) fixup();
1105 if (musictrace) gprintf(TRANS,"midi_exclusive\n");
1106
1107 #ifdef AMIGA
1108 PutSysEx(cmt_mi, msg);
1109 #endif
1110 #ifdef MACINTOSH
1111 #ifndef NYQUIST /* if NYQUIST, do nothing */
1112 #ifdef MIDIMGR
1113 while (prev != MIDI_EOX) {
1114 int len = 0;
1115 while (prev != MIDI_EOX && len < 249) {
1116 TheMIDIPacket.data[len++] = prev = *msg++;
1117 }
1118 TheMIDIPacket.len = 6 + len;
1119 TheMIDIPacket.tStamp = 0;
1120 if (first_packet && (prev != MIDI_EOX)) {
1121 TheMIDIPacket.flags = midiTimeStampCurrent + midiStartCont;
1122 first_packet = FALSE;
1123 } else if (first_packet) {
1124 TheMIDIPacket.flags = midiTimeStampCurrent + midiNoCont;
1125 } else if (prev == MIDI_EOX) {
1126 TheMIDIPacket.flags = midiTimeStampCurrent + midiEndCont;
1127 } else {
1128 TheMIDIPacket.flags = midiTimeStampCurrent + midiMidCont;
1129 }
1130 MIDIWritePacket(OutputRefNum, &TheMIDIPacket);
1131 }
1132 #else
1133 while (*msg != MIDI_EOX) {
1134 Xmit(0, *msg);
1135 msg++;
1136 count++;
1137 /* this is a delay loop, without which your DX7 will crash */
1138 for (i = INTERBYTE_DELAY; i > 0; i--)
1139 abort_check();
1140 }
1141 Xmit(0, MIDI_EOX);
1142 #endif /* MIDIMGR */
1143 #endif /* NYQUIST */
1144 #endif /* MACINTOSH */
1145
1146 #ifdef DOS
1147 #ifndef WINDOWS
1148 do {
1149 mPutData(*msg);
1150 } while (*msg++ != MIDI_EOX);
1151 #endif
1152 #endif
1153 #ifdef ITC
1154 for (m = msg, tosend = 1; (*m) != MIDI_EOX; m++, tosend++);
1155 for (count = 0; count < tosend; count += done) {
1156 willsend = min(16384, tosend);
1157 ret = mi_exclusive(midiconn, 1, msg, (short) willsend);
1158 if (ret != MI_SUCCESS) {
1159 gprintf(GWARN, "Got %d from mi_exclusive\n", ret);
1160 }
1161 done = willsend;
1162 }
1163 #endif
1164 #ifdef UNIX_IRIX_MIDIFNS
1165 /* we don't know which device to sent SYSEX messages to so port zero is
1166 assumed. */
1167 for (m = msg, mdevent.msglen = 1; (*m) != CMT_MIDI_EOX; m++, mdevent.msglen++);
1168 mdevent.sysexmsg = msg;
1169 if (mdSend(miport, &mdevent, 1) == -1) {
1170 gprintf(GWARN, "could not send SYSEX message\n");
1171 }
1172 #endif
1173
1174 if (miditrace) {
1175 do { gprintf(TRANS, "~%2x", *msg);
1176 #ifdef UNIX_IRIX_MIDIFNS
1177 } while (*msg++ != CMT_MIDI_EOX);
1178 #else
1179 } while (*msg++ != MIDI_EOX);
1180 #endif
1181 }
1182 }
1183
1184
1185 /****************************************************************************
1186 * midi_note
1187 * Inputs:
1188 * int channel: midi channel on which to send data
1189 * int pitch: midi pitch code
1190 * int velocity: velocity with which to sound it (0=> release)
1191 * Effect:
1192 * Sends a midi note-play request out
1193 ****************************************************************************/
1194
midi_note(int channel,int pitch,int velocity)1195 void midi_note(int channel, int pitch, int velocity)
1196 {
1197 if (!initialized) fixup();
1198 if (musictrace) gprintf(TRANS,"midi_note: ch %d, key %d, vel %d\n",
1199 channel, pitch, velocity);
1200 if (user_scale) {
1201 /* check for correct pitch bend */
1202 if ((pit_tab[pitch].pbend != bend[MIDI_CHANNEL(channel)])
1203 && (velocity != 0)) {
1204 midi_bend(channel, pit_tab[pitch].pbend);
1205 bend[channel] = pit_tab[pitch].pbend;
1206 }
1207 pitch = pit_tab[pitch].ppitch;
1208 }
1209 midi_write(3, MIDI_PORT(channel), (byte) (MIDI_ON_NOTE | MIDI_CHANNEL(channel)),
1210 (byte) MIDI_DATA(pitch), (byte) MIDI_DATA(velocity));
1211 }
1212
1213
1214 /****************************************************************************
1215 * midi_program
1216 * Inputs:
1217 * int channel: Channel on which to send midi program change request
1218 * int program: Program number to send (decremented by 1 before
1219 * being sent as midi data)
1220 * Effect:
1221 * Sends a program change request out the channel
1222 ****************************************************************************/
1223
midi_program(int channel,int program)1224 void midi_program(int channel, int program)
1225 {
1226 #ifdef MACINTOSH
1227 int port, midi_chan;
1228 #endif
1229
1230 if (!initialized) fixup();
1231 if (musictrace) gprintf(TRANS,"midi_program: ch %d, prog %d\n",
1232 channel, program);
1233 channel = MIDI_CHANNEL(channel);
1234 if (cur_midi_prgm[channel] != program) {
1235 midi_write(2, MIDI_PORT(channel), (byte) (MIDI_CH_PROGRAM | channel),
1236 (byte) (MIDI_PROGRAM(program)), 0);
1237 cur_midi_prgm[channel] = program;
1238 }
1239 }
1240
1241
1242 /****************************************************************************
1243 * midi_real
1244 * Inputs:
1245 * boolean onflag: TRUE or FALSE
1246 * Effect:
1247 * enables (true) or disables (false) midi realtime messages F8-FF
1248 ****************************************************************************/
1249
midi_real(boolean onflag)1250 void midi_real(boolean onflag)
1251 {
1252 if (!initialized) fixup();
1253 #ifdef UNIX_ITC
1254 {
1255 mi_status ret;
1256
1257 ret = mi_realtime(midiconn, onflag);
1258 if (ret != MI_SUCCESS) {
1259 gprintf(ERROR, "Warning: bad ret = %d in midi_real\n", ret);
1260 }
1261 }
1262 #endif /* UNIX_ITC */
1263 #ifdef ITC
1264 ignore_realtime = !onflag;
1265 #endif /* ITC */
1266 #ifdef AMIGA
1267 if (onflag) {
1268 SetMidiFilters(cmt_mi, cmt_mi->PortFilter,
1269 cmt_mi->TypeFilter | CMF_RealTime, cmt_mi->ChanFilter);
1270 } else {
1271 SetMidiFilters(cmt_mi, cmt_mi->PortFilter,
1272 cmt_mi->TypeFilter & ~CMF_RealTime, cmt_mi->ChanFilter);
1273 }
1274 #endif
1275 #ifdef MACINTOSH_OR_DOS
1276 realFilter = !onflag;
1277 #endif
1278
1279 if (musictrace) gprintf(TRANS,"midi_real: %d\n", onflag);
1280 }
1281
1282
1283 /* midi_start -- send a midi start message */
1284 /**/
midi_start()1285 void midi_start()
1286 {
1287 if (!initialized) fixup();
1288 if (musictrace) gprintf(TRANS, "`");
1289 midi_write(1, 0, MIDI_START, 0, 0);
1290 }
1291
1292
1293 /* midi_stop -- send a midi stop message */
1294 /**/
midi_stop()1295 void midi_stop()
1296 {
1297 if (!initialized) fixup();
1298 if (musictrace) gprintf(TRANS, "'");
1299 midi_write(1, 0 /* ignored */, MIDI_STOP, 0, 0);
1300 }
1301
1302
1303 /****************************************************************************
1304 * midi_thru
1305 * Inputs:
1306 * boolean onflag: TRUE or FALSE
1307 * Effect:
1308 * DOS: enables (true) or disables (false) midi thru info from
1309 * MPU-401 to host. (Default is set; reset with cmdline -block.)
1310 * AMIGA: enables (true) or disables (false) midi route from AMIGA
1311 * midi input to AMIGA midi output.
1312 ****************************************************************************/
1313
midi_thru(boolean onflag)1314 void midi_thru(boolean onflag) /* DMH: midi thru is not supported on the MAC or DOS */
1315 {
1316 if (!initialized) fixup();
1317 #ifndef MIDI_THRU
1318 gprintf(ERROR, "midi_thru called but not implemented\n");
1319 #else
1320 #ifdef AMIGA
1321 MidiThru(0L, (long) onflag);
1322 #endif
1323 #ifdef MACINTOSH
1324 /* this currently does not do anything - Mac driver doesn't
1325 * support THRU
1326 */
1327 do_midi_thru = onflag;
1328 #endif
1329 #endif
1330
1331 if (musictrace) gprintf(TRANS,"midi_thru: %d\n", onflag);
1332 }
1333
1334
1335 /****************************************************************************
1336 * midi_touch
1337 * Inputs:
1338 * int channel: midi channel on which to send data
1339 * int value: control value
1340 * Effect:
1341 * Sends a midi after touch message
1342 ****************************************************************************/
1343
midi_touch(int channel,int value)1344 void midi_touch(int channel, int value)
1345 {
1346 if (!initialized) fixup();
1347 if (musictrace) gprintf(TRANS,"midi_touch: ch %d, val %d\n",channel,value);
1348 midi_write(2, MIDI_PORT(channel), (byte) (MIDI_TOUCH | MIDI_CHANNEL(channel)),
1349 (byte) MIDI_DATA(value), 0);
1350 }
1351
1352
1353 /****************************************************************************
1354 * midi_write
1355 * Inputs:
1356 * UBYTE n: number of characters to send (1, 2 or 3);
1357 int port: the port number (usually 0), on MAC, this may be 1
1358 * char c1,c2,c3: Character(s) to write to MIDI data port
1359 * Effect:
1360 * Writes the data to the serial interface designated by port
1361 ****************************************************************************
1362 * Change log
1363 * Date | Change
1364 *-----------+----------------------------------------------------------------
1365 * 15-Mar-94 | PLu : Added IRIX version
1366 ****************************************************************************/
1367
1368 #ifdef UNIX
1369 #ifdef UNIX_IRIX_MIDIFNS
midi_write(int n,int port,unsigned char c1,unsigned char c2,unsigned char c3)1370 void midi_write(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3)
1371 {
1372 MDevent event;
1373
1374 if (port < 0) return;
1375
1376 * ((u_long *) event.msg) = 0xe0000000 | ((port & 0x1f) << 24) | (c1 << 16) |
1377 (c2 << 8) | c3;
1378 if (mdSend(miport, &event, 1) == -1)
1379 gprintf(ERROR, "Can not send midi message in midi_write");
1380
1381 midi_write_trace(n, port, c1, c2, c3);
1382 }
1383 #else
1384
1385 #ifdef ITC
midi_write(int n,int port,unsigned char c1,unsigned char c2,unsigned char c3)1386 void midi_write(int n, int port,
1387 unsigned char c1, unsigned char c2, unsigned char c3)
1388 {
1389 unsigned char outb[3];
1390 mi_channel mch;
1391 mi_status ret;
1392
1393 if (port < 0) return;
1394 outb[0] = c1;
1395 outb[1] = c2;
1396 outb[2] = c3;
1397 mch = (16*port)+((int)MI_CHANNEL(c1));
1398 ret = mi_put(midiconn, mch, outb);
1399 if (ret != MI_SUCCESS)
1400 gprintf(ERROR, "Warning: bad ret = %d in midi_write\n", (int)ret);
1401 midi_write_trace(n, port, c1, c2, c3);
1402 }
1403 #else
midi_write(int n,int port,unsigned char c1,unsigned char c2,unsigned char c3)1404 void midi_write(int n, int port,
1405 unsigned char c1, unsigned char c2, unsigned char c3)
1406 {
1407 /* no output */
1408 midi_write_trace(n, port, c1, c2, c3);
1409 }
1410 #endif /* ITC */
1411 #endif /* UNIX_IRIX */
1412 #endif /* UNIX */
1413
1414 #ifdef DOS
1415 #ifndef WINDOWS
midi_write(int n,int port,unsigned char c1,unsigned char c2,unsigned char c3)1416 void midi_write(int n, int port,
1417 unsigned char c1, unsigned char c2, unsigned char c3)
1418 {
1419 if (n >= 1) mPutData(c1);
1420 if (n >= 2) mPutData(c2);
1421 if (n >= 3) mPutData(c3);
1422 midi_write_trace(n, port, c1, c2, c3);
1423 }
1424 #else
midi_write(int n,int port,unsigned char c1,unsigned char c2,unsigned char c3)1425 void midi_write(int n, int port,
1426 unsigned char c1, unsigned char c2, unsigned char c3)
1427 {
1428 midi_write_trace(n, port, c1, c2, c3);
1429 }
1430 #endif
1431 #endif
1432
1433 #ifdef MACINTOSH
1434 #ifdef MIDIMGR
midi_write(int n,int port,unsigned char c1,unsigned char c2,unsigned char c3)1435 void midi_write(int n, int port,
1436 unsigned char c1, unsigned char c2, unsigned char c3)
1437 {
1438 MIDIPacket TheMIDIPacket;
1439
1440 TheMIDIPacket.flags = midiTimeStampCurrent;
1441 TheMIDIPacket.len = 6 + n;
1442 TheMIDIPacket.tStamp = 0;
1443 TheMIDIPacket.data[0] = c1;
1444 TheMIDIPacket.data[1] = c2;
1445 TheMIDIPacket.data[2] = c3;
1446 MIDIWritePacket(OutputRefNum, &TheMIDIPacket);
1447 midi_write_trace(n, port, c1, c2, c3);
1448 }
1449 #else
midi_write(int n,int port,unsigned char c1,unsigned char c2,unsigned char c3)1450 void midi_write(int n, int port, unsigned char c1, unsigned char c2, unsigned char c3)
1451 {
1452 #ifndef NYQUIST
1453 Xmit(port, c1);
1454 if (n >= 2) Xmit(port, c2);
1455 if (n >= 3) Xmit(port, c3);
1456 #endif
1457 midi_write_trace(n, port, c1, c2, c3);
1458 }
1459 #endif
1460 #endif
1461
midi_write_trace(int n,int port,unsigned char c1,unsigned char c2,unsigned char c3)1462 void midi_write_trace(int n, int port,
1463 unsigned char c1, unsigned char c2, unsigned char c3)
1464 {
1465 if (miditrace) {
1466 /* to indicate bytes going out on port 1, put message in brackets
1467 * with the port number, e.g. [1:~90~3c~64]
1468 */
1469 if (port > 0) gprintf(TRANS, "[%d:", port);
1470 if (n >= 1) gprintf(TRANS, "~%2x", c1);
1471 if (n >= 2) gprintf(TRANS, "~%2x", c2);
1472 if (n >= 3) gprintf(TRANS, "~%2x", c3);
1473 if (port > 0) gprintf(TRANS, "]", port);
1474 }
1475 }
1476
1477
1478
1479 /*****************************************************************
1480 * set_pitch_default
1481 *****************************************************************/
1482
set_pitch_default()1483 private void set_pitch_default()
1484 {
1485 int i;
1486
1487 for (i = 0; i < 128; i++) {
1488 pit_tab[i].pbend = 8192;
1489 pit_tab[i].ppitch = i;
1490 }
1491 }
1492
1493 /*****************************************************************
1494 * read_tuning
1495 *****************************************************************/
1496
read_tuning(filename)1497 void read_tuning(filename)
1498 char *filename;
1499 {
1500 int index, pit, lineno = 0;
1501 float bend;
1502 FILE *fpp;
1503
1504 user_scale = TRUE;
1505 set_pitch_default();
1506
1507 fpp = fileopen(filename, "tun", "r", "Tuning definition file");
1508 while ((fscanf(fpp, "%d %d %f\n", &index, &pit, &bend) > 2) &&
1509 (lineno < 128)) {
1510 lineno++;
1511 if (index >= 0 && index <= 127) {
1512 pit_tab[index].pbend = (int)(8192 * bend/100 + 8192);
1513 pit_tab[index].ppitch = pit;
1514 }
1515 }
1516 }
1517
1518
1519 /****************************************************************************
1520 * musicinit
1521 * Effect:
1522 ****************************************************************************/
1523
musicinit()1524 void musicinit()
1525 {
1526 int i;
1527 char *filename;
1528
1529 if (!tune_flag) { /* do this code only once */
1530 miditrace = cl_switch("miditrace");
1531 musictrace = cl_switch("trace");
1532 }
1533
1534 if (!initialized) {
1535 cu_register((cu_fn_type) musicterm, NULL);
1536 midi_init();
1537 }
1538 initialized = TRUE;
1539 /* this does some random cleanup activity */
1540
1541 #ifndef APPLICATION
1542 if (!tune_flag) { /* do this code only once */
1543 #ifdef DOS
1544 #ifndef WINDOWS
1545 #if 0
1546 version = mPutGetCmd(GETMPUVER);
1547 revision = mPutGetCmd(GETMPUREV);
1548 gprintf(TRANS, "MPU version %d.%d%c\n", version >> 4, version & 0x0f,
1549 revision + 'A' - 1);
1550 #endif
1551 mPutCmd(UARTMODE);
1552 mPutCmd(NOREALTIME); /* initially prevent Real Time MIDI info */
1553 mPutCmd(EXCLUSIVOFF); /* initially prevent Sys-Ex data */
1554 #endif
1555 #endif
1556 tune_flag = TRUE;
1557 filename = cl_option("tune");
1558 if (filename != NULL) read_tuning(filename);
1559 }
1560 /* now that flags are set, print the trace message */
1561 if (musictrace) gprintf(TRANS, "musicinit()\n");
1562
1563 if (user_scale) {
1564 for (i = 0; i < MAX_CHANNELS; i++) {
1565 midi_bend(i, 8192);
1566 bend[i] = 8192;
1567 }
1568 }
1569 #endif /* ifndef APPLICATION */
1570
1571 for (i = 0; i < MAX_CHANNELS; i++) {
1572 /* initialize to impossible values so that the
1573 * next call to midi_bend or midi_program will
1574 * not match and therefore send an output:
1575 */
1576 bend[i] = -1;
1577 cur_midi_prgm[i] = -1;
1578 }
1579 #ifdef MIDI_THRU
1580 midi_thru(!(cl_switch("block"))); /* set MIDI thru */
1581 #endif
1582 timereset(); /* Reset clock */
1583 #ifdef AMIGA
1584 event_mask |= (1L << ascii_signal()) | (1L << cmt_mi->AlarmSigBit) |
1585 (1L << cmt_mi->RecvSigBit);
1586 #endif
1587 }
1588
1589
1590 /****************************************************************************
1591 * musicterm
1592 * Effect:
1593 * Miscellaneous cleanup of things done by musicinit.
1594 ****************************************************************************/
1595
musicterm(void)1596 private void musicterm(void)
1597 {
1598 if (musictrace) gprintf(TRANS, "musicterm()\n");
1599 initialized = FALSE;
1600 }
1601
1602
1603 /****************************************************************************
1604 * cmtrand
1605 * Inputs:
1606 * int lo: Lower limit of value
1607 * int hi: Upper limit of value
1608 * Result: int
1609 * random number (lo <= result <= hi)
1610 ****************************************************************************/
1611
1612 /* to avoid confusion and dead code, take this out */
1613 #ifdef ALL_CMT
1614 long randseed = 1534781L;
1615
cmtrand(short lo,short hi)1616 short cmtrand(short lo, short hi)
1617 {
1618 randseed *= 13L;
1619 randseed += 1874351L;
1620 return((short)(lo + (((hi + 1 - lo) * ((0x00ffff00 & randseed) >> 8)) >> 16)));
1621 }
1622
1623
1624 #ifdef AMIGA
1625 /* remove_sysex_buffer -- a cleanup procedure for the Amiga */
1626 /**/
remove_sysex_buffer(void * obj)1627 void remove_sysex_buffer(void *obj)
1628 {
1629 ClearSysExQueue(cmt_mi);
1630 }
1631 #endif /* AMIGA */
1632
1633
1634 /****************************************************************************
1635 * settime
1636 * Inputs: new time
1637 * Effect:
1638 * Sets the current time to the new time.
1639 * DMH: for MAC, sets the clock to absTime
1640 * implemented by adjusting ticksATStart
1641 ****************************************************************************/
1642
settime(newtime)1643 void settime(newtime)
1644 time_type newtime;
1645 {
1646 if (musictrace) gprintf(TRANS, "settime(%lu)\n", newtime);
1647 #ifdef AMIGA
1648 timeoffset = *camdtime - (newtime >> 1);
1649 #endif
1650
1651 #ifdef MACINTOSH
1652 #ifdef MIDIMGR
1653 ticksAtStart = MIDIGetCurTime(OutputRefNum);
1654 #else
1655 ticksAtStart = TickCount() - MS_TO_TICKS(newtime);
1656 #endif
1657 #endif
1658 }
1659 #endif //ALL_CMT
1660
1661
1662 /****************************************************************************
1663 * timereset
1664 * Effect:
1665 * Resets the time.
1666 * DMH: for MAC, implemented by setting ticksAtStart to
1667 * current value of system tick counter
1668 * JMN: for DOS, resets the time on the MPU-401. Ticks is reset to 0
1669 ****************************************************************************/
1670
timereset()1671 void timereset()
1672 {
1673 #if HAS_GETTIMEOFDAY
1674 struct timeval timeval;
1675 #endif
1676 #if HAS_FTIME
1677 struct timeb ftime_res;
1678 #endif
1679
1680 if (!initialized) fixup();
1681 if (musictrace) gprintf(TRANS,"timereset()\n");
1682
1683 #ifdef AMIGA
1684 timeoffset = *camdtime;
1685 #endif
1686
1687 #ifdef DOS
1688 #ifndef WINDOWS
1689 timeoffset = (ulong) readtimer();
1690 #endif
1691 #endif
1692
1693 #ifdef MACINTOSH
1694 #ifdef MIDIMGR
1695 ticksAtStart = MIDIGetCurTime(OutputRefNum);
1696 #else
1697 ticksAtStart = TickCount();
1698 #endif
1699 #endif
1700
1701 #if HAS_GETTIMEOFDAY
1702 gettimeofday(&timeval, 0);
1703 timeoffset = timeval.tv_sec * 1000 + timeval.tv_usec / 1000 - timeoffset;
1704 #endif
1705 #if HAS_FTIME
1706 ftime(&ftime_res);
1707 timeoffset = ftime_res.time;
1708 #endif
1709 }
1710
1711
1712 /****************************************************************************
1713 * trace
1714 * Inputs:
1715 * boolean flag: TRUE for trace on
1716 * Effect:
1717 * turns tracing on (flag == TRUE) or off (flag == FALSE)
1718 ****************************************************************************/
1719
trace(boolean flag)1720 void trace(boolean flag)
1721 {
1722 musictrace = flag;
1723 }
1724
1725 /****************************************************************************
1726 * tracemidi
1727 * Inputs:
1728 * boolean flag: TRUE for trace on
1729 * Effect:
1730 * turns midi tracing on (flag == TRUE) or off (flag == FALSE)
1731 ****************************************************************************/
1732
tracemidi(boolean flag)1733 void tracemidi(boolean flag)
1734 {
1735 miditrace = flag;
1736 }
1737
1738
1739
1740 /***********************************************************************
1741 *
1742 * midi and timer initialization
1743 *
1744 ***********************************************************************/
1745
1746 #ifdef DOS
1747 #include <ctype.h>
1748 /* binary value of hex char */
1749
xval(int c)1750 private int xval(int c)
1751 {
1752 int i;
1753 static char t[]="0123456789abcdef";
1754
1755 for (i=0; i<16; i++)
1756 if (tolower(c)==t[i]) return(i);
1757 return (-1);
1758 }
1759
1760 /* binary value of hex string */
1761
atox(char * t)1762 private int atox(char *t)
1763 {
1764 int i=0;
1765 int x;
1766 while(*t)
1767 {
1768 if ((x=xval(*t++))<0)return (0);
1769 i=(i<<4)+x;
1770 }
1771 return (i);
1772 }
1773 #endif /* def DOS */
1774
1775
midi_init(void)1776 private void midi_init(void)
1777 {
1778 #ifdef UNIX_IRIX_MIDIFNS
1779 #define PBUFLEN 4
1780 MIconfig *config;
1781 static u_int pbuf[] = { MI_STAMPING, MINOSTAMP, MI_BLOCKING, MINONBLOCKING};
1782 #endif
1783
1784 #ifdef UNIX_MACH
1785 mach_midi_init();
1786 #else
1787 #ifdef ITC
1788 midiconn = mi_open(NULL);
1789 if (midiconn == NULL) {
1790 gprintf(FATAL, "could not open a MIDI device\n");
1791 EXIT(1);
1792 }
1793 cu_register((cu_fn_type) mi_close, (void *) midiconn);
1794 #endif
1795 #endif
1796 #ifdef AMIGA
1797 amiga_midi_init();
1798 #endif /* def AMIGA */
1799 #ifdef DOS
1800 #ifndef WINDOWS
1801 int err;
1802 int irq=SEARCHIRQ;
1803 int base=MPUBASEADDR;
1804 char *t;
1805
1806 if (t=getenv("MPUIRQ")) {
1807 if (musictrace)
1808 gprintf(TRANS,"MPUIRQ %s\n",t);
1809 irq=atoi(t);
1810 }
1811 if (t=getenv("MPUBASE")) {
1812 if (musictrace)
1813 gprintf(TRANS,"MPUBASE %s\n",t);
1814 base=atox(t);
1815 }
1816 if (err = mOpen(base, irq)) {
1817 mClose(err);
1818 EXIT(1);
1819 }
1820 cu_register((cu_fn_type) mClose, 0);
1821 cu_register((cu_fn_type) mPutCmd, (cu_parm_type) MPURESET);
1822 initializetimer();
1823 cu_register((cu_fn_type) restoretimer, NULL);
1824 #endif
1825 #endif
1826
1827 #ifdef MACINTOSH
1828 #ifndef NYQUIST /* if NYQUIST, do nothing */
1829 #ifdef MIDIMGR
1830 setup_midimgr(); /* this registers itself for cleanup */
1831 #else
1832 init_abort_handler();
1833 cu_register(cleanup_abort_handler, NULL);
1834 setupMIDI(portA, 0x80);
1835 cu_register(restoreMIDI, (long) portA);
1836 /* only initialize portB if necessary */
1837 if (MAX_CHANNELS > CHANNELS_PER_PORT) {
1838 setupMIDI(portB, 0x80);
1839 cu_register(restoreMIDI, (long) portB);
1840 }
1841 #endif
1842 #endif /* NYQUIST */
1843 #ifdef MIDIMGR
1844 ticksAtStart = MIDIGetCurTime(OutputRefNum);
1845 #else
1846 ticksAtStart = TickCount(); /* reset the clock */
1847 #endif
1848 #endif /* def MACINTOSH */
1849
1850 if (!(cl_switch("noalloff")))
1851 cu_register((cu_fn_type) alloff, NULL);
1852 }
1853
1854 #ifdef DOS
1855 /****************************************************************************
1856 * set_x_mfr
1857 * Inputs:
1858 * unsigned char mfr: Manufacturer ID for MIDI
1859 * Result: void
1860 *
1861 * Effect:
1862 * Sets the xcode and xcodemask to allow only these sysex messages
1863 ****************************************************************************/
1864
set_x_mfr(mfr)1865 void set_x_mfr(mfr)
1866 unsigned char mfr;
1867 {
1868 xcode = mfr;
1869 xcodemask = 0xFF;
1870 }
1871
1872 /****************************************************************************
1873 * clear_x_mfr
1874 * Result: void
1875 *
1876 * Effect:
1877 * Clears sysex manufacturer code filter; accepts all sysex messages
1878 ****************************************************************************/
1879
clear_x_mfr()1880 void clear_x_mfr()
1881 {
1882 xcode = 0;
1883 xcodemask = 0;
1884 }
1885 #endif /* DOS */
1886