Classic Computer Magazine Archive ANTIC VOL. 4, NO. 11 / MARCH 1986


Program ST's Musical Instrument Digital Interface


The AY3-8910 sound chip built into the 520ST is perfectly adequate for the usual computer sound requirements- game noises, alert sounds in application programs, etc. (See Antic, November 1985 for a detailed examination of the AY3-8910.) But the ST is also one of the very first personal computers with the new MIDI interface built in. MIDI can control the sounds of a whole electronic combo of synthesizers, drum machines, sequencers and other professional musical equipment. The following article demonstrates how to program the 520STMIDIport. You can read it simply for the theory, but if you want to use the type-in program you will need a MIDI-equipped sound synthesizer and connecting cable. Antic used the Casio CZ-1O1 reviewed here in June 1985. Also, Haba Hippo-C owners rejoice, this program will work under both Hippo and Alcyon C.-ANTIC ED

MIDI (Musical Instrument Digital Interface) is a standard for communication between electronic musical instruments and computers. It consists of a hardware specification (something like the RS-232 standard) that dictates the exact nature of the hardware connecting the instruments to the computer, and a software specification that spells out the meaning of the signals that are passed, somewhat like the ASCII codes that control your printer.
   Until the 520ST came along, you had to pay $100 or more to add MIDI capabilities to your computer. With the ST, MIDI hardware is already built-in. It can be used for music, or as an extremely inexpensive approach to Local Area Networking (LAN), which is as hot in the business field as MIDI is in music.
   We will concentrate here on the musical uses of the MIDI port, but you can use the information and the driver program as the basis for your own LAN program. (If you come up with anything hot, let us know.-ANTIC ED.)
   Listing 1 is a simple MIDI driver that will enable you to use your ST to play a melody on virtually any MIDIequipped synthesizer. Your ST can produce multiple-voice (polyphonic) music. But for simplicity, I have provided a single-voice (monophonic) driver.

You will be sending two kinds of signals with this driver: "status" and "data." Status signals tell their recipient how to use the data signals that follow. For example a NOTEON message tells your synthesizer to use the next two bytes to turn on a note-at the pitch given by the first of the following bytes and the key velocity given by the second following byte.
   There are several kinds of status signals. They can address the whole system, which may consist of several synthesizers, drum machines, sequencers and computers. They can address only those receivers that are on a particular channel (there can be up sixteen different channels). They can give timing information. Or they can address only machines made by one manufacturer. Fortunately we only have to deal with a few of these possibilities in the driver program at hand.
   The data signals following the status signals can carry such information as note pitch, key velocity, pitch wheel changes, patch (sound control) changes, position within a song, and more. Their use is made clear to the receiver by the preceding status signals.

MIDI transmitters and receivers can operate in four different modes: Omni On Poly, Omni On Mono, Omni Off Poly, and Omni Off Mono. Omni is just a fancy way of determining whether a receiver is receiving signals from all sixteen channels (Omni On) or from a limited number of channels, usually one.
   Omni On/Off is a very powerful feature of MIDI. In Omni Off mode you could have sixteen sets of Midi-equipped instruments, each on a different channel, playing different things at the same time. In practice this is difficult to achieve, since the slight time delays inherent in MIDI's 31,250 baud transmission rate add up to an audible lag when many instruments are daisy-chained together. But special splitter boxes eliminate of much of the time problem, and some very complex systems exist.
   Most polyphonic synthesizers power up in Mode 1, Omni On Poly. So one of the first things the driver program has to do is switch to Mode 2, Omni On Mono.

We're now going to describe how to type in and compile the program in both Haba Hippo C and Alcyon C. You'll notice there are two listings. Listing 1 is the MIDI program. Listing 2 is assembly language source code that will create a link file so that Hippo-C owners can use Midiws(), which is an ST XBIOS function. Alcyon owners do not need to type this in.
   Antic Disk subscribers will find the object code on their disk as MIDI.PRG. If there is enough disk space, the source code will be included as well. With the proper equipment, you can port the programs from an Atari 8-bit computer to your 520ST. See the January 1986 Antic for instructions.

Mcyon people can skip to the next section. Hippo owners, type in both Listing 1 and 2. In Listing 1, be sure to put the char midistring[ ] on a line of its own. Also, watch for the remarks. Don't type in the include# files that are meant for the Alcyon C people.
   Save Listing 1 under the filename MIDI.C. Save Listing 2 under the filename SMIDI.S. Both files should be saved within the USR folder.
   From the A: prompt, type c midi [RETURN] to compile Listing 1. With luck, this should create a file called MIDI.O.
   Again, from the A: prompt, type ASM SMIDI.S [RETURN]. Hippo-C will quickly assemble the source code into a file called SMIDI.O which can be linked with any C program you write to provide the XBIOS MIDI call.
   Now, let's put the whole thing together. Type 1d -S midi.o smidi.o [RETURN]. When the A: prompt appears, type logout to get to the desktop, rename the A.PRG file, if you wish, then skip down to the section called HOOKING IT UP.

As we said, Alcyon C owners can ignore Listing 2. Type in Listing 1 and save it as MIDI.C. Include the include# files, but don't type in the extern Midiws();. As with last month's instructions, we will assume a single drive system. You may reconfigure the following files for your own system.
   You will need a compiler disk and a linker disk. The compiler disk must contain the following files: AS68.PRG, AS68INIT, AS68SYMB.DAT, C068.PRG, C168.PRG, CP68.PRG, OSBIND.H, STDIO.H, BATCH.TTP, RM.PRG, WAIT.PRG, C.BAT The last file, C.BAT, is user defined below.
   The C.BAT file contains:

CP68 %1.c %1.i
C068 %l.i %1.l %1.2 %l.3 -f
RM %l.l
C168 %1.1 %1.2 %l.s
RM %1.1
RM %l.2
AS68 -l -u %l.s
RM %l.s

   On your linker disk, you will need: GEMS, GEMLIB, OSBIND.O, BATCH.TTP, RM.PRG, WAIT.PRG, LINK.BAT.

   LINK.BAT contains:

LINK68 [u,s] % 1.68K = gems, % 1 ,gemlib,osbind,libf
RM %l.o
RELMOD %1.68K %l.prg
RM %1.68k

   Insert your compiler disk with the C source code on it. From the Desktop, double-click on BATCH.TTP. In the parameter box that appears, enter a c, one space, and your source code filename without the ".c" extender. Cross your fingers and double click on OK. You should end up with a file called MIDI.O. Transfer this file to your linker disk.
   With the linker disk in the drive, double-click on BATCH.TTP. In the parameter box, type in LINK MIDI, again without the ".o" extender. You should now have an executable file called MIDI.PRG.

Once the program is compiled and linked you are set to go. Plug a MIDI cable into the MIDI OUT port of your ST and the MIDI IN port of your synthesizer, set the synthesizer to channel 1, and run the program. It should play a short musical phrase in whichever patch you've chosen. I tested this program on an Oberheim OB-8 but it should work on any synthesizer with MIDI capabilities.

Now look at Listing 1. There are a series of #define statements that tell the compiler what some of the MIDI terms mean. Two of these, TEMPO and NUMBER_NOTES, may be adjusted to fit your own music.
   TEMPO sets the length of a timing loop that determines how quickly the music moves. NUMBER_NOTES limits the length of your piece. If it is too high, you waste memory (not a major problem on the ST). If it is too low the program will not read all of your notes.
   The actual program, beginning at main(), is divided into two parts. The first part takes the string you write, musicstring, and converts it into MIDI key codes- midistring-and the lengths for notes and rests- notelength and restlength. Figure 1 shows the relationship between the musical notes and the MIDI key codes.

I put a sample musical phrase in the program so you can run it as is the first time through.
   To put your own melody into musicstring, first enter the note name (which must be lower case or the program will reject it). If you want a sharped note, follow the note name with a "#." Note names and '#' characters must be enclosed in single quotation marks. This program does not understand flats, so you will have to express all chromatics with sharps.
   Follow the note instruction with the octave in which you want the note to sound (See Figure 1), followed in turn by the length you want the note to sound, and then the length of the rest after the note, if any. If you want legato (connected) notes, use zero for the rest length. Figure 2 gives a sample set of length values.
   Repeat this process until you have entered all of the notes you want. Then write an "x" after the last rest length, in the place where the next note name would be.
   When the program runs, it checks for letters or numbers it doesn't understand. If there are any errors, a message is printed and no MIDI data is sent to your synthesizer.
   I cheated a bit when it came to printing on the screen. The proper way to deal with such things in GEM is to open a window and use the GEM function calls. To save

Figure 1

note   octave   MIDI#
  c      0        0
  c#     0        1
  d      0        2
  d#     0        3
  e      0        4
  f      0        5
  f#     0        6
  g      0        7
  g#     0        8
  a      0        9
  a#     0       10
  b      0       11
  c      1       12
  c#     1       13
  d      1       14
  d#     1       15
  e      1       16
  f      1       17
  f#     1       18
  g      1       19
  g#     1       20
  a      1       21
  a#     1       22
  b      1       23
  c      2       24
  c#     2       25
  d      2       26
  d#     2       27
  e      2       28
  f      2       29
  f#     2       30
  g      2       31
  g#     2       32
  a      2       33
  a#     2       34
  b      2       35
  c      3       36
  c#     3       37
  d      3       38
  d#     3       39
  e      3       40
  f      3       41
  f#     3       42
  g      3       43
  g#     3       44
  a      3       45
  a#     3       46
  b      3       47
  c      4       48
  c#     4       49
  d      4       50
  d#     4       51
  e      4       52
  f      4       53
  f#     4       54
  g      4       55
  g#     4       56
  a      4       57
  a#     4       58
  b      4       59
 *c      5       60
  c#     5       61
  d      5       62
  d#     5       63
  e      5       64
  f      5       65
  f#     5       66
  g      5       67
  g#     5       68
  a      5       69
  a#     5       70
  b      5       71
  c      6       72
  c#     6       73
  d      6       74
  d#     6       75
  e      6       76
  f      6       77
  f#     6       78
  g      6       79
  g#     6       80
  a      6       81
  a#     6       82
  b      6       83
  c      7       84
  c#     7       85
  d      7       86
  d#     7       87
  e      7       88
  f      7       89
  f#     7       90
  g      7       91
  g#     7       92
  a      7       93
  a#     7       94
  b      7       95
  c      8       96
  c#     8       97
  d      8       98
  d#     8       99
  e      8      100
  f      8      101
  f#     8      102
  g      8      103
  g#     8      104
  a      8      105
  a#     8      106
  b      8      107
  c      9      108
  c#     9      109
  d      9      110
  d#     9      111
  e      9      112
  f      9      113
  f#     9      114
  g      9      115
  g#     9      116
  a      9      117
  a#     9      118
  b      9      119
  c     10      120
  c#    10      121
  d     10      122
  d#    10      123
  e     10      124
  f     10      125
  f#    10      126
  g     10      127
Highest allowable MIDI note number.

*"middle" c on the piano

program space, since so little printing to the screen is required. I used a standard C function, printf().
   Thus, you will see your note names and any error messages printed up at the top of the screen. Those of you who have been following Antic's previous ST articles on the ST should have no trouble adding a proper window and some fancy visual effects to go along with the music.

The second part of the program is the real meat of the driver, so we will go over it a section at a time.
   After checking to see if there were any errors-if (!merror ) means "if the merror flag has not been set"- the second part of the program starts sending MIDI data. midistring was initialized to Mode 2 near the beginning of the program.
   To send a string of data to the MIDI handler, called Midiws(), put the number of items to be sent, minus one, and the name of the array that holds them in parentheses after the word Midiws(). The compiler inserts the proper instruction to call the Midiws() function, and, at run time, the Midiws() code pulls the information from the stack and goes to work. It's impressively simple and easy to use.
   To send the note data, the first byte of the midistring is set to the NOTEON signal, which occupies the upper four bits of the first byte of the next string. The lower four bits must give the channel number. And since you will set your synthesizer to receive on channel 1, the program adds the proper value for channel 1.
   That sets things up for the main program loop. Each time the program passes through the loop, a counter is incremented. The counter is used to reference the correct place in each of the arrays.
   The first line within the loop causes he MIDI note number to be printed to the screen which gives you a visual check on the operation of the program.
   Each NOTEON in MIDI must be followed by a note number-given by notestring[i]-and then a key velocity (FULLVELOCITY) in case your system has a touch-sensitive keyboard.
   Since only three numbers must be read by Midiws() this time the number in the parentheses is changed to a 2 (number of bytes minus one).
   Nested FOR loops give a time delay determined by notelength and TEMPO.

Figure 2

Whole note              192
Dotted half note        144
Half note                96
Quarter note             48
Dotted quarter note      36
Eighth note              24
Sixteenth note           12
Eighth note triplet      16
Sixteenth note triplet    8
Quintuplet               10

   There are at least two ways to shut the note off. The NOTEOFF command works, but by sending a NOVELOCITY command it is possible to take advantage of one of MIDI's features and cut down the number of bytes that have to be sent.
   Think of it this way: a key pressed with no velocity won't produce a sound. Once a NOTEON is sent, you can play a string of notes of any length by simply sending a series of note number and FULLVELOCITY when you want a note to sound and NOVELOCITY when you want the note to end. This is called "Running Status", and will stay in effect until a status byte is sent.
   This program does not take advantage of the reduction in the number of signals sent that Running Status offers. In order to keep the program as clear as possible, the midistring array keeps NOTEON as its first member and maintains a length of three bytes. A more sophsticated program could save one byte each time around except the first time by eliminating the NOTEON.
   Another set of nested FOR loops gives the rest length. Note that a rest value of zero results in an immediate exit from the loop.
   Technically every NOTEON eventually has to have a corresponding NOTEOFF, so when the main loop is finished this chore is taken care of.
   Ths program is only a small sample of what MIDI can do. For more information, contact the manufacturer of your synthesizer.
   There is also an International MIDI Association at 11857 Hartsook Street, North Hollywood, CA 91607. (818) 505-896. They publish an informative newsletter and you can get a copy of the complete MIDI specification from them. Or if you want something a little easier to understand they are publishing a book on MIDI that includes the MIDI spec with an explanatory section. The price is $35.

Toni Jeffries of Oakland, CA is a professional musician and programmer He is currently writing or translating soundtracks for computer games and writing music-related software.

Listing 1   MIDI.C
Listing 2   SMIDI.S