source: buchla-68k/orig/BUCHLA/THTEST.C

Last change on this file was 3ae31e9, checked in by Thomas Lopatic <thomas@…>, 7 years ago

Imported original source code.

  • Property mode set to 100755
File size: 16.6 KB
Line 
1/*
2 =============================================================================
3 thtest.c -- send, capture, and display MIDI data for Thunder checkout
4 See VERMSG below for version and date.
5
6 Environment: Atari 1040ST, GEMDOS, Alcyon C.
7 =============================================================================
8*/
9
10#define VERMSG "thtest -- Version 4.01 -- 1990-04-25 -- D.N. Lynx Crowe"
11
12#include "stdio.h"
13#include "osbind.h"
14#include "ctype.h"
15
16#include "stddefs.h"
17
18#define void int /* 'cause we ain't got no steenking voids */
19
20#define MBUFSZ (unsigned short)(31*1024) /* MIDI buffer size */
21
22#define DEFUNIT 0 /* default Thunder unit number */
23#define DEFCHAN 0 /* default Thunder base channel */
24
25#define MMCODE1 0x007F /* Buchla MIDI manufacturer ID byte 1 */
26#define MMCODE2 0x007F /* Buchla MIDI manufacturer ID byte 2 */
27
28#define PRODUCT 0x0001 /* Buchla product code for Thunder */
29
30#define SNAPFILE "THTEST.TMP" /* snap file name */
31#define FILE_1 "THTEST.FFF" /* config file name */
32#define FILE_2 "THTEST.GGG" /* library file name */
33
34#define MAXNOL 16 /* max number of data bytes on a line */
35
36#define FORMAT1 "\n%5u %02.02x"
37#define FORMAT2 " %02.02x"
38#define FORMAT3 "\n%5u"
39
40struct iorec { /* structure for MIDI buffer description */
41
42 char *ibuf; /* base address of buffer */
43 short ibufsz; /* buffer size in bytes */
44 short ibufhd; /* head index */
45 short ibuftl; /* tail index */
46 short ibuflo; /* low water mark index */
47 short ibufhi; /* high water mark index */
48};
49
50extern char *malloc();
51
52void PrMIDI(); /* forward reference */
53void cleanbf(); /* forward reference */
54
55int SetMBuf(); /* forward reference */
56int midi_in(); /* forward reference */
57int m_stat(); /* forward reference */
58
59FILE *ifp; /* input file pointer */
60FILE *ofp; /* output file pointer */
61FILE *sfp; /* snap file pointer */
62
63char *newbuf; /* expanded MIDI buffer pointer */
64char *oldbuf; /* old MIDI buffer pointer */
65
66char sxhead[32]; /* SysEx message header buffer */
67
68unsigned short indx; /* MIDI input byte number */
69unsigned short thsum; /* Thunder SysEx checksum */
70unsigned short Addr; /* address input temporary */
71unsigned short Chan; /* channel number input temporary */
72unsigned short Ctrl; /* controller number input temporary */
73unsigned short Data; /* data input temporary */
74unsigned short Prog; /* program input temporary */
75unsigned short Unit; /* unit number input temporary */
76unsigned short Valu; /* value input temporary */
77
78short feseen; /* MIDI active sensing seen */
79short mstate; /* output monitor state */
80short nol; /* number of MIDI data bytes on the line */
81short oldbsz; /* old MIDI buffer size */
82short oldbhi; /* old MIDI buffer high water mark */
83short oldblo; /* old MIDI buffer low water mark */
84short thunit; /* Thunder unit number */
85short thchan; /* Thunder base channel */
86
87struct iorec *m_buff; /* MIDI iorec pointer */
88
89char *helpms[] = {
90
91 "\n",
92 "Escape exit this program\n",
93 "space pause output\n",
94 "/ clear buffer and screen\n",
95 "b set base channel\n",
96 "c request current Thunder config\n",
97 "e examine a word in the current Thunder config\n",
98 "f write THTEST.FFF to MIDI\n",
99 "g write THTEST.GGG to MIDI\n",
100 "h display this help message\n",
101 "l request Thunder library\n",
102 "m toggle output monitor state\n",
103 "p send program change\n",
104 "s set a word in the current Thunder config\n",
105 "u set Thunder unit number\n",
106 "v send control change\n",
107 "w write MIDI input buffer to snap file\n",
108 "\n",
109 (char *)NULL
110};
111
112/*
113
114*/
115
116/*
117 =============================================================================
118 SendB() -- send a byte to the MIDI port and update the checksum
119 =============================================================================
120*/
121
122void
123SendB(byte)
124unsigned short byte;
125{
126 Bconout(3, 0x00FF & byte);
127 thsum = 0x00FF & (thsum + byte);
128
129 if (mstate)
130 printf("<%02.2x> ", 0x00FF & byte);
131}
132
133/*
134 =============================================================================
135 SendM() -- send a byte string to the MIDI port -- Checksum NOT updated.
136 =============================================================================
137*/
138
139void
140SendM(nb, adr)
141unsigned short nb;
142char *adr;
143{
144 short c;
145
146 while (nb-- > 0) {
147
148 Bconout(3, c = 0x00FF & *adr++);
149
150 if (mstate)
151 printf("<%02.2x> ", c);
152 }
153}
154
155/*
156 =============================================================================
157 SendW() -- send a 16 bit word out to MIDI and update the checksum
158 =============================================================================
159*/
160
161void
162SendW(wrd)
163unsigned short wrd;
164{
165 SendB(0x000F & (wrd >> 12)); /* send MS bits */
166 SendB(0x003F & (wrd >> 6)); /* send middle bits */
167 SendB(0x003F & wrd); /* send LS bits */
168}
169
170/*
171
172*/
173
174/*
175 =============================================================================
176 ThSysEx() -- send a Thunder SysEx message
177 =============================================================================
178*/
179
180void
181ThSysEx(mt, mp1, mp2)
182unsigned short mt, mp1, mp2;
183{
184 /* setup the SysEx header */
185
186 sxhead[0] = 0x00F0;
187 sxhead[1] = 0x0000;
188 sxhead[2] = MMCODE1;
189 sxhead[3] = MMCODE2;
190 sxhead[4] = PRODUCT;
191 sxhead[5] = thunit;
192 sxhead[6] = mt;
193 thsum = mt & 0x00FF;
194
195 switch (mt) {
196
197 case 0: /* write word */
198 case 3: /* send word */
199 case 4: /* send current config */
200 case 5: /* send library */
201
202 SendM(7, sxhead); /* send the header */
203
204 if ((0 EQ mt) OR (3 EQ mt)) /* optional Address */
205 SendW(Addr);
206
207 if (0 EQ mt) /* optional Data */
208 SendW(Data);
209
210 Bconout(3, -thsum & 0x007F); /* checksum */
211 Bconout(3, 0x00F7); /* EOX */
212
213 if (mstate)
214 printf("<%02.2x> <F7>", -thsum & 0x007F);
215
216 break;
217
218 case 1: /* write current config */
219 case 2: /* write library */
220 default:
221
222 break;
223 }
224
225 if (mstate)
226 printf("\n");
227}
228
229/*
230
231*/
232
233/*
234 =============================================================================
235 GetUInt() -- get an unsigned integer parameter from the console
236 =============================================================================
237*/
238
239short
240GetUInt(msg, parm)
241char *msg;
242unsigned short *parm;
243{
244 register long iv;
245 register int ten;
246 register unsigned short ch;
247
248 iv = 0L;
249 ten = 10;
250
251 if ((char *)NULL NE msg)
252 printf("%s", msg);
253
254 while (0x000D NE (ch = 0x00FF & Bconin(2))) {
255
256 if (isdigit(ch)) { /* see if it's a digit */
257
258 Bconout(2, ch); /* echo the character */
259
260 iv = (iv * ten) + (ch - '0');
261
262 if (iv > 65535L) { /* check for overflow */
263
264 Bconout(2, '\r'); /* output CR/LF */
265 Bconout(2, '\n');
266
267 return(FAILURE);
268 }
269
270 } else { /* wasn't a digit */
271
272 Bconout(2, '\r'); /* output CR/LF */
273 Bconout(2, '\n');
274
275 return(FAILURE);
276 }
277 }
278
279 Bconout(2, '\r'); /* output CR/LF */
280 Bconout(2, '\n');
281
282 if (iv > 65535L) /* check for overflow */
283 return(FAILURE);
284
285 *parm = (unsigned short)iv; /* update the parameter */
286
287 return(SUCCESS);
288}
289
290/*
291
292*/
293
294/*
295 =============================================================================
296 SetMBuf() -- set up MIDI buffer
297 =============================================================================
298*/
299
300int
301SetMBuf()
302{
303 unsigned short size;
304
305 size = MBUFSZ; /* MIDI buffer */
306
307 m_buff = (struct iorec *)Iorec(2); /* pointer to buffer descriptor */
308
309 oldbuf = m_buff->ibuf;
310 oldbsz = m_buff->ibufsz;
311 oldbhi = m_buff->ibufhi;
312 oldblo = m_buff->ibuflo;
313
314 if ((char *)NULL EQ (newbuf = (char *)malloc(size))) {
315
316 printf ("ERROR -- unable to allocate MIDI buffer.\n");
317 return(FAILURE);
318 }
319
320 /* clear out the buffer */
321
322 m_buff->ibufhd = 0; /* reset the head index */
323 m_buff->ibuftl = 0; /* reset the tail index */
324
325 /* we do this twice because we aren't disabling interrupts ... */
326
327 m_buff->ibufhd = 0; /* reset the head index */
328 m_buff->ibuftl = 0; /* reset the tail index */
329
330 m_buff->ibuf = newbuf; /* change address of buffer */
331 m_buff->ibufsz = size; /* change size of buffer */
332
333 indx = 0; /* reset the byte index */
334
335 return(SUCCESS);
336}
337
338/*
339 =============================================================================
340 midi_in() -- get MIDI byte
341 =============================================================================
342*/
343
344int
345midi_in()
346{
347 return((int)Bconin(3) & 0x00FF);
348}
349
350
351/*
352 =============================================================================
353 PrMIDI() -- print a MIDI data byte
354 =============================================================================
355*/
356
357void
358PrMIDI(M_Byte)
359unsigned int M_Byte;
360{
361 if ((0x00FF & M_Byte) EQ 0x00FE) {
362
363 if (NOT feseen) {
364
365 printf("\nActive sense is active\n");
366
367 if ((FILE *)NULL NE ofp)
368 fprintf(ofp, "\nActive sense is active\n");
369 }
370
371 nol = 0;
372 feseen = TRUE;
373
374 } else {
375
376 ++indx;
377
378 if (0x0080 & M_Byte) { /* new status byte */
379
380 printf(FORMAT1, indx, M_Byte);
381 nol = 0;
382
383 if ((FILE *)NULL NE ofp)
384 fprintf(ofp, FORMAT1, indx, M_Byte);
385
386 } else { /* data byte */
387
388 if (++nol > MAXNOL) {
389
390 printf(FORMAT3, indx);
391 nol = 1;
392
393 if ((FILE *)NULL NE ofp)
394 fprintf(ofp, FORMAT3, indx);
395 }
396
397 printf(FORMAT2, M_Byte);
398
399 if ((FILE *)NULL NE ofp)
400 fprintf(ofp, FORMAT2, M_Byte);
401 }
402 }
403
404 fflush(stdout);
405
406 if ((FILE *)NULL NE ofp)
407 fflush(ofp);
408}
409
410
411/*
412 =============================================================================
413 m_stat() -- check midi status
414 =============================================================================
415*/
416
417int
418m_stat()
419{
420 return((int)Bconstat(3) ? TRUE : FALSE);
421}
422
423
424/*
425 =============================================================================
426 cleanbf() -- clean out MIDI buffer
427 =============================================================================
428*/
429
430void
431cleanbf()
432{
433 int mstat;
434
435 printf("Clearing MIDI input buffer ...\n");
436 feseen = FALSE;
437
438 /* clear out the buffer by resetting the head and tail indices */
439
440 m_buff->ibufhd = 0; /* reset the head index */
441 m_buff->ibuftl = 0; /* reset the tail index */
442
443 /* we do this twice because we aren't disabling interrupts ... */
444
445 m_buff->ibufhd = 0; /* reset the head index */
446 m_buff->ibuftl = 0; /* reset the tail index */
447
448 /* make sure it's really drained */
449
450 mstat = m_stat();
451
452 while (mstat) {
453
454 midi_in();
455 mstat = m_stat();
456 }
457
458 indx = 0;
459}
460
461/*
462
463*/
464
465/*
466 =============================================================================
467 thtest -- send, capture, and display MIDI data for Thunder checkout
468 =============================================================================
469*/
470
471void
472main(argc, argv)
473int argc;
474char *argv[];
475{
476 unsigned short ch, runtag;
477 char **s;
478
479 ofp = (FILE *)NULL;
480 thunit = DEFUNIT;
481 thchan = DEFCHAN;
482
483 printf("\033E%s\n\n", VERMSG);
484 printf("Typing h gets you a list of commands\n\n");
485
486 if (SetMBuf()) /* move MIDI buffer & increase its size */
487 exit(2);
488
489 printf("%u byte MIDI buffer allocated at 0x%08.8lx\n",
490 MBUFSZ, (long)newbuf);
491
492 cleanbf(); /* clear out MIDI buffer */
493
494 if (argc EQ 2) {
495
496 if ((FILE *)NULL EQ (ofp = fopen(argv[1], "w"))) {
497
498 printf("\nERROR -- Unable to open \"%s\" for output.\n",
499 argv[1]);
500
501 exit(2);
502
503 } else {
504
505 printf("Writing log to file \"%s\".\n", argv[1]);
506 }
507 }
508
509 printf("\nReady.\n");
510 runtag = TRUE;
511
512 while (runtag) {
513
514 if (Bconstat(2)) {
515
516 ch = 0x00FF & Bconin(2);
517
518 switch (ch) {
519
520 case '\033': /* escape */
521
522 runtag = FALSE;
523 break;
524
525 case ' ': /* space = pause */
526
527 printf("PAUSED");
528 Bconin(2);
529 printf("\b\b\b\b\b\b \b\b\b\b\b\b");
530
531 break;
532
533 case '/': /* / = clear buffer and screen */
534
535 cleanbf();
536 printf("\033E");
537 printf("Ready.\n");
538
539 if ((FILE *)NULL NE ofp) {
540
541 fprintf(ofp, "\n\nMIDI buffer flushed.\n\n");
542 fflush(ofp);
543 }
544
545 break;
546
547 case 'B':
548 case 'b': /* b = set base channel */
549
550 if (SUCCESS EQ GetUInt("\nChan: ", &Chan)) {
551
552 if ((Chan > 0) AND (Chan < 17))
553 thchan = Chan - 1;
554 else
555 printf("\nERROR: out of range (1..16)\n");
556 }
557
558 printf("\nThunder base channel = %u\n",
559 1 + thchan);
560
561 break;
562
563 case 'C':
564 case 'c': /* c = request current Thunder config */
565
566 ThSysEx(4, 0, 0);
567 break;
568
569 case 'E':
570 case 'e': /* e = examine a word in a Thunder config */
571
572 if (SUCCESS EQ GetUInt("\nAddr: ", &Addr))
573 ThSysEx(3, Addr, 0);
574
575 break;
576
577 case 'F':
578 case 'f': /* f = write THTEST.FFF to MIDI */
579
580 if ((FILE *)NULL EQ (ifp = fopenb(FILE_1, "r"))) {
581
582 printf("\nERROR: Unable to open \"%s\" for input\n",
583 FILE_1);
584
585 break;
586
587 } else {
588
589 while (0 EQ feof(ifp))
590 Bconout(3, 0x00FF & getc(ifp));
591
592 fclose(ifp);
593
594 printf("\nFile \"%s\" written to MIDI\n",
595 FILE_1);
596 }
597
598 break;
599
600 case 'G':
601 case 'g': /* g = write THTEST.GGG to MIDI */
602
603 if ((FILE *)NULL EQ (ifp = fopenb(FILE_2, "r"))) {
604
605 printf("\nERROR: Unable to open \"%s\" for input\n",
606 FILE_2);
607
608 break;
609
610 } else {
611
612 while (0 EQ feof(ifp))
613 Bconout(3, 0x00FF & getc(ifp));
614
615 fclose(ifp);
616
617 printf("\nFile \"%s\" written to MIDI\n",
618 FILE_2);
619 }
620
621 break;
622
623 case 'H':
624 case 'h': /* h = display on-line help */
625
626 s = helpms;
627
628 while (*s)
629 printf("%s", *s++);
630
631 break;
632
633 case 'L':
634 case 'l': /* l = request Thunder library */
635
636 ThSysEx(5, 0, 0);
637 break;
638
639 case 'M':
640 case 'm': /* m = toggle output monitor state */
641
642 mstate = NOT mstate;
643 break;
644
645 case 'P':
646 case 'p': /* p = send program change */
647
648 if (SUCCESS EQ GetUInt("\nProg: ", &Prog)) {
649
650 if ((Prog GE 0) AND (Prog < 128)) {
651
652 Bconout(3, 0x00C0 | (thchan & 0x000F));
653 Bconout(3, 0x007F & Prog);
654
655 } else {
656
657 printf("\nERROR: out of range (0..127)\n");
658 }
659 }
660
661 break;
662
663 case 'S':
664 case 's': /* s = set a word in a Thunder config */
665
666 if (SUCCESS EQ GetUInt("\nAddr: ", &Addr)) {
667
668 if (SUCCESS EQ GetUInt("Data: ", &Data))
669 ThSysEx(0, Addr, Data);
670 }
671
672 break;
673
674 case 'U':
675 case 'u': /* u = set Thunder unit number */
676
677 if (SUCCESS EQ GetUInt("\nUnit: ", &Unit)) {
678
679 if ((Unit > 0) AND (Unit < 10))
680 thunit = Unit - 1;
681 else
682 printf("\nERROR: out of range (1..9)\n");
683 }
684
685 printf("\nThunder unit number = %u\n",
686 1 + thunit);
687
688 break;
689
690 case 'v':
691 case 'V': /* v = send control change */
692
693 if (SUCCESS EQ GetUInt("\nCtrl: ", &Ctrl)) {
694
695 if ((Ctrl GE 0) AND (Ctrl < 128)) {
696
697 if (SUCCESS EQ GetUInt("\nValue: ", &Valu)) {
698
699 if ((Valu GE 0) AND (Valu < 128)) {
700
701 Bconout(3, 0x00B0 | (thchan & 0x000F));
702 Bconout(3, 0x007F & Ctrl);
703 Bconout(3, 0x007F & Valu);
704
705 } else {
706
707 printf("\nERROR: out of range (0..127)\n");
708 }
709 }
710
711 } else {
712
713 printf("\nERROR: out of range (0..127)\n");
714 }
715 }
716
717 break;
718
719 case 'W':
720 case 'w': /* w = write to SNAPFILE */
721
722 if ((FILE *)NULL EQ (sfp = fopenb(SNAPFILE, "w"))) {
723
724 printf("ERROR -- Unable to open \"%s\" for output.\n",
725 SNAPFILE);
726
727 exit(2);
728
729 } else {
730
731 printf("\n\nWriting to file \"%s\".\n", SNAPFILE);
732 }
733
734 fwrite(newbuf + 1, indx, 1, sfp);
735
736 fflush(sfp);
737 fclose(sfp);
738
739 printf("\nFile written and closed.\n\n");
740 break;
741 }
742 }
743
744 if (m_stat())
745 PrMIDI(midi_in());
746
747 if ((FILE *)NULL NE ofp)
748 fflush(ofp);
749 }
750
751 if ((FILE *)NULL NE ofp) { /* close the log file if it's open */
752
753 fprintf(ofp, "\n");
754 fflush(ofp);
755 fclose(ofp);
756 }
757
758 /* clear out the buffer */
759
760 m_buff->ibufhd = 0; /* reset the head index */
761 m_buff->ibuftl = 0; /* reset the tail index */
762
763 /* we do this twice because we aren't disabling interrupts ... */
764
765 m_buff->ibufhd = 0; /* reset the head index */
766 m_buff->ibuftl = 0; /* reset the tail index */
767
768 m_buff->ibufsz = oldbsz; /* restore the old buffer size */
769 m_buff->ibuf = oldbuf; /* restore the old buffer address */
770
771 free(newbuf); /* give back the big MIDI buffer */
772
773 /* close up shop and exit */
774
775 printf("\n");
776 fflush(stdout);
777 exit(0);
778}
Note: See TracBrowser for help on using the repository browser.