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