MIDI DRIVER
Program ST's Musical Instrument Digital Interface
by TOM JEFFRIESThe 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.
STATUS AND DATA
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.
OPERATION MODES
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.
THE PROGRAM
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.
HIPPO TYPE-IN
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.
ALCYON TYPE-IN
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
WAIT
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
WAIT
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.
HOOKING IT UP
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.
PROGRAM ANALYSIS
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.
YOU CALL THE TUNES
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.
FURTHER ANALYSIS
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