CAPTURING MUSIC ON THE ST
A MIDI SEQUENCERby Tom Jeffries
Take advantage of your ST's built-in MIDI interface. This Simple Sequencer lets you record, save to disk, and playback music created on your synthesizer. Creates music files compatible with MiDIMagic, from Q-R-S Music Rolls. Pertinent files may be found on your START disk within the folder labeled MIDISEQR
I'll admit it-I laughed when Antic Publishing called to ask if I could write a MIDI sequencer program for the first issue of START, the ST Quarterly. Sequencers are notoriously difficult to write. Besides, I was already late on a deadline for another program.
If you're not actively involved with MIDI music, you might ask two questions: what is a sequencer and what is MIDI?
MIDI, which stands for Musical Instrument Digital Interface, is a communications standard for musical instruments. To conform to the MIDI standard a musical instrument must have certain hardware (like the MIDI ports on your ST) and respond to certain software signals. MIDI was invented so that one synthesizer could drive another. However, it is also possible to use the MIDI standard to connect a PC to a synthesizer. The ST is the only personal computer to include the built-in MIDI hardware. Other micros require an additional $50 to $400 for MIDI hardware. That's one reason so many music software companies are interested in the ST.
And a sequencer? Well, it's a little like a digital tape recorder.
The idea was tempting, however, and I'm a sucker for challenges, so I decided to try. I got even less sleep than usual and turned into a complete stranger to my family but it was, I think, all in a good cause.
The resulting program is not the most advanced sequencer ever built, but it is fun to use and will illustrate the basic principles of a sequencer. It is compatible with at least one commercial program that will provide better graphics, or you can add your own graphics routines. More on all that later.
SEQUENCERS
Many kinds of information can be sent over MIDI, but the most important is note data: a steady stream of bytes specifying which keys are being pressed and released. A MIDI instrument can also receive such data and behave as though the data's source is the keyboard. In other words, it plays the notes being sent to it over MIDI just as though someone was playing the notes on the keyboard.
A sequencer can either save the data stream as it comes from the synthesizer (adding some kind of time code so that it knows note lengths) or send a previously saved stream of data to a synth to be played. You can buy a stand-alone dedicated sequencer with both hardware and software built-in, or you can use software to turn your micro into a sequencer.
In some ways a sequencer is like a tape recorder. You can play into it and save the result, or you can play back previously created music. However, there are some important differences. A tape recorder (at least a conventional analog tape recorder) reproduces in analog (infinitely varying) format any sounds that are sent to it. A MIDI sequencer can only record certain limited kinds of data: note on, note off, volume, etc. It cannot store a voice, for example, because vocal chords do not send MIDI information. Pitches are stored as note numbers with a range of 0 to 127.
There are, however, some things you can do with a MIDI sequencer that you cannot do with a tape recorder. For example, with a tape recorder you cannot change the speed of a piece without changing the pitch. A good professional sequencer can change the speed without changing the pitch-or change the pitch (transpose) without changing the speed. You can also change the sound on playback. Maybe you like the keyboard on one synthesizer but the sounds on another. With a sequencer you can record a sequence (a song or part of a song) using the keyboard you like, then play it back through the synthesizer that has the sounds you want. The only real limitation is that both synths must be MIDI-equipped.
Sequencers for professional use have some incredible features. Some of them take months to learn how to use, and took years to write. The Simple Sequencer I have written does not have lots of fancy features, but it can provide a lot of entertainment, and you can add your own features to suit your needs. With this sequencer you can play music on your MIDI-equipped synthesizer, "record" your playing in the memory of your ST, and, if you wish, save it on disk. You can play back anything you have previously entered, and change the tempo during playback.
COMPATIBILITY WITH MIDIMAGIC
Our modern digital sequencers are not the first method of storing note data for later playback. The player piano was enormously popular near the beginning of this century. Composers like Scott Joplin or George Gershwin could cut a piano roll of one of their compositions and everyone with a player piano could buy a copy of the roll and listen to the music at home.
Q-R-S (Buffalo, NY) is the company that owns the rights to the old piano rolls. Many of these old, paper rolls are now being translated to MIDI-compatible disk files and distributed by a company called Micro-W (Butler, NJ), along with a program called MiDIMagic, which displays the songs on a graphic screen similar to that of the old player pianos.
I wrote the ST version of MIDIMagic, and since I knew I wouldn't have time to add fancy graphics to the Simple Sequencer, I made the files that the Simple Sequencer produces compatible with the files that MIDIMagic reads. If you own MIDIMagic, you can play the music you create with the Simple Sequencer with the MIDIMagic program and see what a piano roll created from your playing would look like. The piano roll offers an all-too-good display of keyboard technique, and, if you hold on to a note a little too long, you will be able to see it as well as hear it.
(Editor's note: Your START disk contains two MiDiMagic songs, compliments of Micro-W, which may be played on the Simple Sequencer. Although the songs themselves are public domain, the actual performances are copyrighted and, therefore, may not be reproduced or resold. Any songs you create with Simple Sequencer are yours to do with as you like. You may not sell, copy, or distribute disks of your songs that use the MiDiMagic graphic driver program, which is copyrighted by Micro-W However, Micro-W informs us that it would be interested in hearing any unusual compositions you create, for possible marketing.)
THE PROGRAM
To use the Simple Sequencer first make sure your synthesizer is plugged in properly (one cable from the OUT socket of your synth to the IN socket of your ST, and a second cable from the IN socket of your synth to the OUT socket of your ST). Make sure your audio connections are all set and your synthesizer is on.
Alert boxes should guide you through the program fairly easily. Recording will not start until you press a key on your synth, so you can wait as long as you want before starting.
The program is a fairly standard GEM application and has lots of comments, so I will not bore you with a line-by-line analysis. There are five main sections: Program Control (initialization, Main Loop, User I/O), MIDI Input, MIDI Output, Disk I/O, and Screen Displays.
SCREEN DISPLAYS AND PROGRAM CONTROL
If you have been following Antic magazine's articles on the ST the screen display routines will not have any surprises for you. Note that, either by design or by accident, the screen resolution (as represented by the number returned by the Getrez() call early in the program) can be used to make automatic adjustments in the Y values for v_gtext calls as long as you are in either medium or high resolution. If you are using this program entirely on a monochrome monitor you may want to change to larger letters and reposition the text appropriately
There is one point to note about the Init() function. I have arbitrarily set the maximum song file size to 37,000 bytes, which happens, for reasons unrelated to the ST, to be the maximum size for MIDIMagic song files. You can create larger files: just change the number #defined near the beginning of the program as MAXSONG. Malloc(-1L) will return the maximum amount of memory available. To maintain compatibility with different compilers (more on that subject later) I have used a temporary variable and a cast operation to set the pointer notebuffer. Alcyon C should allow you to eliminate the extra step; Megamax is stricter about data types and will only accept the syntax as is, since all bios and xbios functions are defined as returning a long word.
MIDI INPUT
The MIDI input and output routines are the real meat of this program. In_loop() sets up the beginning of the file in MIDIMagic compatible format- tempo indication at byte 56, and note and time data starting at byte 64. It puts a short rest at the beginning (it sounds better that way), then calls a routine that reads the 200Hz timer to get a beginning time; all note timing data uses this as a reference point. The timer routine does not return to In_loop() until something comes in on the MIDI channel.
In_loop() then gets all available MIDI data and then does a little parsing to make sure that the contents of the file will work properly with the MIDIMagic display routines. Then it calls the timer again and waits for the next MIDI data. The note length is derived from the length of time between the first note data's beginning and the second note data. $FF signals timing data, unless it is followed by another $FF, signaling the piece's end. Because of the sign-extending which many C compilers perform on 8-bit numbers, the highest number that can be used for a note length is $7F If the note is longer, the program will keep repeating $FF 7F until the variable notelength is below $7F.
When you press [Esc] to signal your recording's end, the timer routine tells In_loop() you are done by returning a 0. Three $FFs are added to the file's end to signal the end, and control is passed back to the Loop() in the Program Control section.
You will notice something rather odd in the way that the timer function reads location $04BA. $04BA, where the 200Hz click is stored, is in protected memory so you cannot read it from the 68000 chip's user mode. (*pter)() has to be defined as a pointer to a function so that the XBIOS function Supexec can be used to go into supervisor mode to read the time.
$04BA, where the 200Hz click is stored, is in protected memory so you can't read it from the 68000 chips's uset mode. The XBIOS function Supexec allows you to go into supervisor mode, execute the function designated by your call to Supexec, and return to user mode. (*pter)() is therefore defined as a pointer to the time-reading function to be passed to Supexec.
In_Timer() is a weak link in this program since the timings returned are not as accurate as a full scale professional sequencer would require. The solution, I think, would be to use one of the 68901 timers while shutting off as many of the other interrupts as possible.
I do not recommend using the evnt_timer() function in GEM: it seems to fail fairly often, especially when there is lots of I/O going on.
MIDI OUTPUT
The output routine reverses the input routine. In this case I used simple nested counting loops for timing. Note that I keep checking for -1 for a timing byte or the end of the song. Many compilers will turn $FF into $FFFFFFFF or something equally obnoxious, so -1 avoids lots of problems. Allnotesoff() prevents notes from staying on when you quit in mid-song, by sending a MIDI "note off" signal to every possible note. MIDI does provide a special code for all notes off, but not every synthesizer implements it.
DISK I/O
If you find fsel_input() or many of the other GEM gems confusing, I highly recommend studying DOODLE, which was written by Tom Rolander and Tim Oren and is the property of Digital Research, Inc. I borrowed Setpath() from DOODLE; you can do the same since they explicitly grant permission to do so as long as proper credit is given.
I also included two functions that can be found in the standard C libraries of most compilers: Strien() and Strcat(). I did so in consideration for Alcyon C users, who, in order to use these two short functions, would otherwise have to link in 20,480 bytes of LIBF.
I want to point out one "undocumented feature" (some people call them bugs) of fsel_input(), since it caused me an inordinate amount of grief. fsel_input() sets the clipping rectangle for its own purposes and doesn't reset it on exit. If you are writing a program without windows and therefore don't expect to have to worry about clipping, this "feature" can cause a bug that is difficult to track down.
I have tried to make this program as compatible as possible with different compilers. If you are using Megamax, delete or comment out the line #define of Supexec.
POSSIBLE ADDITIONS TO THE SIMPLE SEQUENCER
One of the nice things about having a program published in START is that you, the reader, can enhance the program. The Simple Sequencer could use several additions, some mentioned above. For example, fancy graphics would be nice. There are several small routines I did not put in; an available memory indicator, for example, or some code allowing the user to preset the playback tempo instead of having to wait until the song starts. (Of course you can use a disk editor to change the tempo byte before loading the song, but that's not exactly elegant.) A file mixing program could take several tracks recorded with the Sequencer and mix them down to a single track for playback.
For those of us who are real klutzes at the keyboard, a good step editor- permitting composition one note at a time-would be nice so that we could compose a song on the computer keyboard at our leisure and have it sound like we had performed it on the synthesizer.
If you really want to write some music without playing it on your sequencer and cannot wait to get (or write) a step editor, you can use any program that allows you to construct a file one byte at a time (like the SID.PRG that comes with the developer's kit). Make sure you allow the proper header space and put the tempo byte in the right place (byte 56 with the first byte being byte 0), and start your music data at byte 64, preferably with a short rest ($FF $14 works well). Each note requires three bytes to start, $90, the note number (see figure 1), and a key velocity (unless you know what you are doing use $40). There are several ways to turn off a note, but for compatibility with MIDIMagic use $90, the note number, and 0. Good luck.
MORE ABOUT MIDI
MIDI is a complex and sometimes problematic tool. Each instrument maker seems to have implemented the MIDI standard a little differently, so things that work on one synthesizer may not work on another. By the time you see this, the Simple Sequencer will have been tested on a variety of synths, but if you run into problems please let me know through START Magazine.
One further note: do not try to send program change messages or Channel Pressure messages to the ST without changing the parsing routine in In_ loop() appropriately. These status bytes are used so rarely I decided not to include the extra code, if you use them you'll have to make the necessary adjustments.
I hope that the Simple Sequencer is as much fun for you to use as it was for me to write. I'm really looking forward to seeing what people come up with as enhancements.
Reference:
- ANTIC magazine, Play it Again, Atari, June 1985; Midi Driver, March 1986.
- Digital Research, Inc., 60 Garden Court, P0. Box DRI, Monterey, CA 93942, (408) 649-3896.
- The International MIDI Association, 11857 Hartsook St., North Hollywood, CA 91607. (818) 505-8964.
- KEYBOARD magazine, 20085 Stevens Creek Boulevard, Cupertino, CA 95014-9967, (408) 446-1105.
- Micro-W Distributing, 1342B Route 23, Butler, NJ 07405, (201) 838-9027.
- Q-R-S, 1026 Niagra Street, Buffalo, NY 14213, (716) 885-4600.