add directory study

This commit is contained in:
gohigh
2024-02-19 00:25:23 -05:00
parent b1306b38b1
commit f3774e2f8c
4001 changed files with 2285787 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
ANSI Music - The Technical Details
ANSI is an acronym for "American National Standards Institute" and
actually has little to do with this "ANSI music" stuff. However, the
American National Standards Institute defined a set of codes for
terminals to provide a standard for cursor control. This was expanded to
include graphics modes and color with the release of the ANSI.SYS device
driver. It wasn't actually ANSI who expanded the set of codes to include
the graphics, which are specific to IBM compatible computers with
certain video adapters, but the name ANSI stuck. The original purpose of
ANSI cursor control was to give mainframes a way to control the cursor
on various terminals connected to them. The purpose of the ANSI.SYS
driver was to give programs a simple and compatible way of controlling
the video screen. However, it seems that the only real use for ANSI has
been to give BBS's the ability to control the screen colors and cursor
positioning. This even led to a new artform, but let's not even think
about that. It's too much like Art Deco. In CGA color, no less.
The ANSI.SYS driver also includes provisions for redefining keys
on the keyboard. This can be used for character translation or to create
simple macros. It has even been used to create trojan text files that
redefined your keys to destroy data (i.e. your enter key becomes "DEL
*.* <return> Y <return>"). Watch out for this kind of thing. It's not
hard to do.
Now I said that the actual "ANSI" organization had little to do
with "ANSI music." The reason that the music codes were given the name
"ANSI" is because they start with the same escape sequences. All ANSI
codes start with <esc>[ as do the music codes. What I mean by <esc>[ is
the escape character (27 decimal, 1E hex) and the open-bracket
character. Now, on to the REAL details of ANSI music.
As I just got through saying, ANSI music starts with the
characters <esc><open-bracket>. An ANSI music sequence ends with the
character <control-N> (14 decimal, 0E hex). In between, the commands are
exactly the same as those used for the "PLAY" command in BASIC. Now you
can just look up the PLAY command and you know most everything you need
to know about ANSI music. But for those of you still confused, I'll
summarize the PLAY commands and give a few examples and pointers. Here
we go:
The PLAY commands are pretty simple. This info was taken from the Tandy
BASIC reference manual, but the Tandy-specific commands are not
recognized by ANSI music and will be left out. Here we go again:
A - G Plays the notes corresponding to the notes A-G on the musical
scale. A # or + after the note makes it sharp, and a - makes
it flat.
Ln Sets the duration of the notes that follow. n is a number from
1 to 64. 1 is a whole note, 2 is a half note, 4 is a quarter
note, 8 is an eighth note, etc.
On Sets the current octave. There are 7 octaves, 0 through 6. The
default octave is 4. Each octave starts with C and ends with B.
Octave 3 starts with middle C.
Nn Plays a note. n is in the range 0 to 84. Instead of specifying
the note's letter and octave, you may specify the note's number.
Note zero is a rest.
Pn Plays a rest (if that's the right terminology). n is the same as
for the L command, but specifies the length of the rest.
. Plays the note as a dotted note. You music buffs know that means
that the note is one half it's length longer when dotted. Place
the dot after the note, not before it. More than one dot may be
used after a note, and dots may be specified for rests.
MF, MB I'm not sure these options work. Music Foreground and Music
Background. Supposedly these options will let you specify
MF and have the computer stop whatever it's doing and play
the note, while MB lets the computer do whatever it was doing
and play the note at the same time, kind of lo-tech multitasking.
The default (for BASIC anyway, and it seems for ANSI-music) is
Music Background.
MN "Music Normal." Each note plays 7/8 of the duration set by the
L command.
ML "Music Legato." Each note plays the full duration as set by the
L command.
MS "Music Staccato." Each note plays 3/4 of the duration set by the
L command.
That's it for the basic set of commands. There are other options
in BASIC that are unusuable in the ANSI music, such as the X command
which lets you include a variable name in the play command, where a
string variable name is given and the string contains a series of play
commands. Another command which is usable only on a Tandy or other
computer with the TI sound chip (the PCjr, for instance) is the V
command, for setting the volume of the sound. Now for some examples.
<esc>[cdefgab<control-n> plays the notes "cdefgab" (the entire octave) on
the default octave 4.
<esc>[l4al2cl8e<control-n> plays a quarter-note A, a half note C, and an
eighth-note E. Not too musical, but an
example nonetheless.
I'm not one for giving too many examples, I think that's plenty
for you to get the basic idea. Try it in BASIC before you try it as an
ANSI code in a message/picture. Just type PLAY "ABCDE" <return> and put
whatever you like in the quotes. That's the easiest way to work out the
notes and get the timing right before you blast it up to your favorite
BBS.
*********** Closing Comments ***********
I only know of two major comm programs that support ANSI music:
TeliMate and Qmodem. I personally prefer TeliMate. If we (the collective
we, that is) spread the use of ANSI music, hopefully the makers of other
comm programs will incorporate this feature. If the makers of Telix and
Procomm included this, that would cover 95% of IBM compatible BBS'ers. A
new version of Telix is due out in a few months and I'm hoping this new
version will add ANSI music. I gave up Procomm years ago, so I don't
really know when a new version of that's due out, but it still seems to
be the most common terminal program around. Still, TeliMate is gaining
popularity for its mouse support and multitasking ablility (I wrote most
of this document while downloading a 371k file at 1200 baud), and Qmodem
is pretty popular already.

View File

@@ -0,0 +1,252 @@
**** Brief Overview of Proposed General MIDI Level 1 Spec ****
The heart of General MIDI (GM) is the _Instrument Patch Map_, shown in
Table 1 (see below). This is a list of 128 sounds, with corresponding
MIDI program numbers. Most of these are imitative sounds, though the
list includes synth sounds, ethnic instruments and a handful of sound
effects.
The sounds fall roughtly into sixteen families of eight variations
each. Grouping sounds makes it easy to re-orchestrate a piece using
similar sounds. The Instrument Map isn't the final word on musical
instruments of the world, but it's pretty complete
General MIDI also includes a _Percusssion Key Map_, show in Table 2
(see below). This mapping derives from the Roland/Sequential mapping
used on early drum machines. As with the Instrument Map, it doesn't
cover every percussive instrument in the world, but it's more than
adequate as a basic set.
To avoid concerns with channels, GM restricts percussion to MIDI
Channel 10. Theoretically, the lower nine channels are for the
instruments, but the GM spec states that a sound module must respond
to all sixteen MIDI channels, with dynamic voice allocation and a
minimum of 24 voices.
General MIDI doesn't mention sound quality of synthesis methods.
Discussions are under way on standardizing sound parameters such as
playable range and envelope times. This will ensure that an arrangement
that relies on phrsing and balance can play back on a variety of
modules.
Other requirements for a GM sound module include response to velocity,
mod wheel, aftertouch, sustain and expression pedal, main volume and
pan, and the All Notes Off and Reset All Controllers messages. The
module also must respond to both Pitch Bend and Pitch Bend Sensitivity
(a MIDI registered parameter). The default pitch bend range is +-2
semitones.
Middle C (C3) corresponds to MIDI key 60, and master tuning must be
adjustable. Finally, the MIDI Manufacturers Association (MMA) created a
new Universal System Exclusive message to turn General MIDI on and off
(for devices that might have "consumer" and "programmable" settings).
Table 3 (see below) summarizes these requirements.
General MIDI has room for future expansion, including additional drum
and instrument assignments and more required controllers. Also under
discussion is an "authorizing document" that would standardize things
such as channel assignments (e.g., lead on 1, bass on 2, etc.) and setup
information in a MIDI file.
Copies of the Level 1 Specification documents for General MIDI ($5 each
at last notice) are available from the Internation MIDI Association,
5316 West 57th Street Los Angeles, CA 90056, (213) 649-6434. The first
issue of the Journal of the MMA (back issues, $15 each) contains an
article by PassPort Designs and Stanley Junglieb about General MIDI.
Roland's GS Standard
When Warner New Media first proposed a General MIDI standard, most MMA
members gave it little thought. As discussions proceeded, Roland
listened and developed a sound module to meet the proposed
specification. At the same NAMM show where the MMA ratified General MIDI
Level 1, Roland showed their Sound Brush and Sound Canvas, a Standard
MIDI File player and GM-compatible sound module.
Some companies feel that General MIDI doesn't go far enough, so Roland
created a superset of General MIDI Level 1, which they call GS Standard.
It obeys all the protocols and sound maps of General MIDI and adds many
extra controllers and sounds. Some of the controllers use Unregistered
Parameter Numbers to give macro control over synth parameters such as
envelope attack and decay rates.
The new MIDI Bank Select message provides access to extra sounds
(including variations on the stock sounds and a re-creation of the MT-32
factory patches). The programs in each bank align with the original 128
in General MIDI's Instrument Patch Map, with eight banks housing related
families. The GS Standard includes a "fall back" system. If the Sound
Canvas receives a request for a bank/program number combination that
does not exist, it will reassign it to the master instrument in that
family. A set of Roland System Exclusive messages allows reconfiguration
and customization of the sound module.
This means that a Roland GS Standard sound module will correctly play
back any song designed for General MIDI. In addition, if the song's
creator wants to create some extra nuance, they can include the GS
Standard extensions in their sequence. None of these extensions are so
radical as to make the song unplayable on a normal GM sound module.
After all, compatibility is what MIDI - and especially General MIDI - is
all about.
Music authors interested in the GS Standard should contact Tom White
at RolandCorp USA, 7200 Dominion Circle, Los Angeles, CA 90040, (213)
685-5141.
**** TABLE 1 - General MIDI Instrument Patch Map ****
(groups sounds into sixteen families, w/8 instruments in each family)
Prog# Instrument Prog# Instrument
(1-8 PIANO) (9-16 CHROM PERCUSSION)
1 Acoustic Grand 9 Celesta
2 Bright Acoustic 10 Glockenspiel
3 Electric Grand 11 Music Box
4 Honky-Tonk 12 Vibraphone
5 Electric Piano 1 13 Marimba
6 Electric Piano 2 14 Xylophone
7 Harpsichord 15 Tubular Bells
8 Clav 16 Dulcimer
(17-24 ORGAN) (25-32 GUITAR)
17 Drawbar Organ 25 Acoustic Guitar(nylon)
18 Percussive Organ 26 Acoustic Guitar(steel)
19 Rock Organ 27 Electric Guitar(jazz)
20 Church Organ 28 Electric Guitar(clean)
21 Reed Organ 29 Electric Guitar(muted)
22 Accoridan 30 Overdriven Guitar
23 Harmonica 31 Distortion Guitar
24 Tango Accordian 32 Guitar Harmonics
(33-40 BASS) (41-48 STRINGS)
33 Acoustic Bass 41 Violin
34 Electric Bass(finger) 42 Viola
35 Electric Bass(pick) 43 Cello
36 Fretless Bass 44 Contrabass
37 Slap Bass 1 45 Tremolo Strings
38 Slap Bass 2 46 Pizzicato Strings
39 Synth Bass 1 47 Orchestral Strings
40 Synth Bass 2 48 Timpani
(49-56 ENSEMBLE) (57-64 BRASS)
49 String Ensemble 1 57 Trumpet
50 String Ensemble 2 58 Trombone
51 SynthStrings 1 59 Tuba
52 SynthStrings 2 60 Muted Trumpet
53 Choir Aahs 61 French Horn
54 Voice Oohs 62 Brass Section
55 Synth Voice 63 SynthBrass 1
56 Orchestra Hit 64 SynthBrass 2
(65-72 REED) (73-80 PIPE)
65 Soprano Sax 73 Piccolo
66 Alto Sax 74 Flute
67 Tenor Sax 75 Recorder
68 Baritone Sax 76 Pan Flute
69 Oboe 77 Blown Bottle
70 English Horn 78 Skakuhachi
71 Bassoon 79 Whistle
72 Clarinet 80 Ocarina
(81-88 SYNTH LEAD) (89-96 SYNTH PAD)
81 Lead 1 (square) 89 Pad 1 (new age)
82 Lead 2 (sawtooth) 90 Pad 2 (warm)
83 Lead 3 (calliope) 91 Pad 3 (polysynth)
84 Lead 4 (chiff) 92 Pad 4 (choir)
85 Lead 5 (charang) 93 Pad 5 (bowed)
86 Lead 6 (voice) 94 Pad 6 (metallic)
87 Lead 7 (fifths) 95 Pad 7 (halo)
88 Lead 8 (bass+lead) 96 Pad 8 (sweep)
(97-104 SYNTH EFFECTS) (105-112 ETHNIC)
97 FX 1 (rain) 105 Sitar
98 FX 2 (soundtrack) 106 Banjo
99 FX 3 (crystal) 107 Shamisen
100 FX 4 (atmosphere) 108 Koto
101 FX 5 (brightness) 109 Kalimba
102 FX 6 (goblins) 110 Bagpipe
103 FX 7 (echoes) 111 Fiddle
104 FX 8 (sci-fi) 112 Shanai
(113-120 PERCUSSIVE) (121-128 SOUND EFFECTS)
113 Tinkle Bell 121 Guitar Fret Noise
114 Agogo 122 Breath Noise
115 Steel Drums 123 Seashore
116 Woodblock 124 Bird Tweet
117 Taiko Drum 125 Telephone Ring
118 Melodic Tom 126 Helicopter
119 Synth Drum 127 Applause
120 Reverse Cymbal 128 Gunshot
**** TABLE 2 - General MIDI Percussion Key Map ****
(assigns drum sounds to note numbers. MIDI Channel 10 is for percussion)
MIDI Drum Sound MIDI Drum Sound
Key Key
35 Acoustic Bass Drum 59 Ride Cymbal 2
36 Bass Drum 1 60 Hi Bongo
37 Side Stick 61 Low Bongo
38 Acoustic Snare 62 Mute Hi Conga
39 Hand Clap 63 Open Hi Conga
40 Electric Snare 64 Low Conga
41 Low Floor Tom 65 High Timbale
42 Closed Hi-Hat 66 Low Timbale
43 High Floor Tom 67 High Agogo
44 Pedal Hi-Hat 68 Low Agogo
45 Low Tom 69 Cabasa
46 Open Hi-Hat 70 Maracas
47 Low-Mid Tom 71 Short Whistle
48 Hi-Mid Tom 72 Long Whistle
49 Crash Cymbal 1 73 Short Guiro
50 High Tom 74 Long Guiro
51 Ride Cymbal 1 75 Claves
52 Chinese Cymbal 76 Hi Wood Block
53 Ride Bell 77 Low Wood Block
54 Tambourine 78 Mute Cuica
55 Splash Cymbal 79 Open Cuica
56 Cowbell 80 Mute Triangle
57 Crash Cymbal 2 81 Open Triangle
58 Vibraslap
**** TABLE 3 - General MIDI minimum sound module specs ****
Voices:
A minimum of either 24 fully dynamically allocated voices
available simultaneously for both melodic and percussive sounds or 16
dynamically allocated voices for melody plus eight for percussion.
Channels:
General MIDI mode supports all sixteen MIDI channels. Each channel can
play a variable number of voices (polyphony). Each channel can play a
different instrument (timbre). Keybased Percussion is always on
Channel 10.
Instruments:
A minimum of sixteen different timbres playing various instrument
sounds. A minimum of 128 preset for Intruments (MIDI program numbers).
Note on/Note off:
Octabe Registration: Middle C(C3) = MIDI key 60. All Voices including
percussion respond to velocity.
Controllers:
Controller # Description
1 Modulation
7 Main Volume
10 Pan
11 Expression
64 Sustain
121 Reset All Controllers
123 All Notes Off
Registered Description
Parameter #
0 Pitch Bend Sensitivity
1 Fine Tuning
2 Coarse Tuning
Additional Channel Messages:
Channel Pressure (Aftertouch)
Pitch Bend
Power-Up Defaults:
Pitch Bend Amount = 0
Pitch Bend Sensitivity = +-2 semitones
Volume = 90
All Other Controllers = reset

View File

@@ -0,0 +1,214 @@
MIDI SAMPLE DUMP STANDARD
1) INTRODUCTION
The MIDI SDS was adopted in January 1986 by the MIDI
Manufacturers Association and the Japanese MIDI Standards Committee.
The SDS defines the standard method for transfer of sound sample data
between MIDI-equipped devices. Sample dumps may be accomplished with
either an 'open loop' or 'closed loop' system. The open loop method
simply involves the straight dump of all sample data from its source
to the destination, with no timeouts, packet acknowledgements, or any
other form of handshaking, much as in the manner of a sysex bulk dump,
usually intiated at the source. The closed loop method allows the use
of handshaking messages between the dump source and destination, and
usually places the dump process under the control of the slave, to
allow it time to process the incoming data as necessary. As with any
standard, it can not be assumed that a device adheres to it unless the
accompanying documentation specifically indicates it. Even then, it is
best to check its conformity with non-critical data.
2) SPEC: SAMPLE DUMP FORMATS
DUMP HEADER:
F0 7E cc 01 ss ss ee ff ff ff gg gg gg hh hh hh ii ii ii jj F7
where
cc = channel number
ss ss = sample number (LSB first)
ee = sample format (number of significant bits; 8->28)
ff ff ff = sample period (1/sample rate) in nanoseconds (LSB first)
gg gg gg = sample length, in words
hh hh hh = sustain loop start point (word number) (LSB first)
ii ii ii = sustain loop end point (word number) (LSB first)
jj = loop type (00:forwards only; 01:alternating)
DATA PACKET:
F0 7E cc 02 kk <120 bytes> mm F7
where
cc = channel number
kk = running packet count (00->7F)
mm = checksum (XOR of 7E, cc, 02, kk <120 bytes>)
The total size of a data packet is 127 bytes. This is to avoid
overflow of the MIDI input buffer of a device that may want to receive
an entire packet before processing it.
A data packet consists of its own header, a packet number, 120
bytes of data, a checksum, and an EOX. The packet number begins at 00
and increments with each new packet. It resets to 00 after it reaches
7F, and continues counting. The packet number is used by the receiver
to distinguish between a new data packet, or a resend of a previous
packet. The packet number is followed by 120 bytes of data, which form
60, 40, or 30 words (MSB first for multiword samples), depending on
the length of a single data sample.
Each data byte hold seven bits, with the msb in each byte set to
0, in order to conform to the requirements of MIDI data transmission.
Information is left justified within the 7-bit bytes, and unused bits
are filled with 0.
Example: Assume a data point in the memory of a 16-bit sampler,
with the value 87E5. In binary, that would be
1000 0111 1110 0101
and would be encoded as the following MIDI data stream:
01000011 01111001 00100000
The checksum is the running XOR of all the data after the SYSEX
byte, up to but not including the checksum itself.
3) SPEC: SAMPLE DUMP MESSAGES
DUMP REQUEST:
F0 7E cc 03 ss ss F7
where
cc = channel number
ss ss = sample number requested (LSB first)
Upon receiving the request, the sampler checks the sample number
to see if it is within legal range. If it is not, the request is
ignored. If it is, the sample dump is started. One packet at a time is
sent, under control of the handshaking messages outlined below.
HANDSHAKING MESSAGES:
For all below:
cc = channel number
pp = packet number
Packet numbers are included in the handshaking messages to
accomodate machines that have the intelligence to re-transmit specific
packets after an entire dump is finished, or if synchronization is
lost.
ACK : F0 7E cc 7F pp F7
Means last packet was recieved correctly (checksum OK, etc),
please send next one. Packet number is packet being acknowledged as
correct.
NAK : F0 7E cc 7E pp F7
Means last packet not received correctly, please send again.
Packet number is packet being rejected.
CANCEL : F0 7E cc 7D pp F7
Means abort dump immediately. Packet number is packet on which
abort occurs.
WAIT : F0 7E cc 7C pp F7
Means pause dump indefinitely, until next message is sent. Allows
the unit recieving the dump to perform other functions (disk access,
etc), before receiving the remainder of the dump. The next message it
sends (eg ACK, ABORT) will determine if the dump continues or aborts.
4) DUMP PROCEDURE: MASTER (DUMP SOURCE)
Once a dump has been requested, either via MIDI or through the
front panel, the DUMP HEADER is sent. After sending the header, the
master must time out for at least two seconds, to allow the receiver
to decide if it will accept this sample (has enough memory, etc).
If it receives a CANCEL, within this time, it should abort
immediately. If it receives an CAK, it will start sending packets
immediately. If it receives a WAIT, it pauses until another message is
received, and then processes that mesage normally. If nothing is
recieved within the timeout, an open loop is assumed, and the dump
starts with the first packet.
After sending each packet, the master should time out for at
least 20 milliseconds and watch its MIDI In. If an ACK is received, it
sends the next packet immediately. If it receives an NAK, and the
packet number matches the number of the last packet sent, it resend
that packet If the packet numbers don't match, and the device is
incapable of sending packets out of order, the NAK will be ignored.
If a WAIT is received, the master should watch its MIDI In port
indefinitely for another ACK, NAK, or CANCEL message, which it should
then process normally.
If no messages are received within 20 milliseconds of the
transmission of a packet, the master may assume an open loop
configuration, and send the next packet.
This process continues until there are less than 121 data bytes
to send. The final packet will still consist of 120n bytes, regardless
of how many significant bytes actually remain, and the unused bytes
will be filled with zeroes. The receiver should handshake after
receiving the last packet.
5) DUMP PROCEDURE: SLAVE (DUMP DESTINATION)
When receiving a sample dump, a device should keep a running
checksum during reception. If its checksum matches the checksum in the
data packet, it will send an ACK and wait for the next packet. If it
does not match, it will send an NAK containing the number of the
packet that caused the error, and wait for the next packet. If, after
sending an NAK, the packet number of the next packet doesn't match the
previous packet number (the one that was NAK'd), and the unit is not
capable of accepting packets out of order, the error is ignored and
the dump continues as if the checksums had matched.
If a receiver runs out of memory before the dumpo is completed,
it should send a CANCEL to stop the dump.
6) SDS OVERVIEW
SAMPLE DUMP DATA FORMAT: DUMP HEADER:
Sysex
ID: Universal Non-Real Time
Channel Number
Sub ID: Header
Sample Number (2 bytes, LSB first)
Sample Format
Sample Period (3 bytes, LSB first)
Sample Length (3 bytes, LSB first)
Sustain Loop Start Point (3 bytes, LSB first)
Sustain Loop End Point (3 bytes, LSB first)
Loop Type
Eox
SAMPLE DUMP DATA FORMAT: DATA PACKET:
Sysex
ID: Universal Non-Real Time
Channel Number
Sub ID: Data Packet
Packet Number
Sample Data (120 bytes)
Checksum
Eox
SAMPLE DUMP MESSAGES: DUMP REQUEST:
Sysex
ID: Universal Non-Real Time
Channel Number
Sub ID: Dump Request
Sample Number (2 bytes, LSB first)
Eox
SAMPLE DUMP MESSAGES: HANDSHAKING FLAGS:
Sysex
ID: Universal Non-Real Time
Channel Number
Sub ID: ACK or NAK or CANCEL or WAIT
Packet Number
Eox

View File

@@ -0,0 +1,171 @@
MIDI 1.0 Specification:
Status Data Byte(s) Description
D7----D0 D7----D0
-------------------------------------------------------------------------
Channel Voice Messages
-------------------------------------------------------------------------
1000cccc 0nnnnnnn Note Off event.
0vvvvvvv This message is sent when a
note is released (ended).
(nnnnnnn) is the note number.
(vvvvvvv) is the velocity.
1001cccc 0nnnnnnn Note On event.
0vvvvvvv This message is sent when a
note is depressed (start).
(nnnnnnn) is the note number.
(vvvvvvv) is the velocity.
1010cccc 0nnnnnnn Polyphonic Key Pressure (After-touch).
0vvvvvvv This message is sent when the pressure
(velocity) of a previously
triggered note changes.
(nnnnnnn) is the note number.
(vvvvvvv) is the new velocity.
1011cccc 0ccccccc Control Change.
0vvvvvvv This message is sent when a controller
value changes. Controllers include devices
such as pedals and levers.
Certain controller numbers are reserved
for specific purposes. See Channel Mode Messages.
(ccccccc) is the controller number.
(vvvvvvv) is the new value.
1100cccc 0ppppppp Program Change.
This message sent when the patch number changes.
(ppppppp) is the new program number.
1101nnnn 0ccccccc Channel Pressure (After-touch).
This message is sent when the channel pressure
changes. Some velocity-sensing keyboards do not
support polyphonic after-touch. Use this
message to send the single greatest velocity
(of all te current depressed keys).
(ccccccc) is the channel number.
1110nnnn 0lllllll Pitch Wheel Change.
0mmmmmmm This message is sent to indicate a change in the
pitch wheel. The pitch wheel is measured by a
fourteen bit value. Center (no pitch change) is
2000H. Sensitivity is a function of the
transmitter.
(llllll) are the least significant 7 bits.
(mmmmmm) are the most significant 7 bits.
-------------------------------------------------------------------------
Channel Mode Messages (See also Control Change, above)
-------------------------------------------------------------------------
1011nnnn 0ccccccc Channel Mode Messages.
0vvvvvvv This the same code as the Control
Change (above), but implements Mode
control by using reserved controller
numbers. The numbers are:
Local Control.
When Local Control is Off, all devices
on a given channel will respond only to
data received over MIDI. Played data, etc.
will be ignored. Local Control On
restores the functions of the normal
controllers.
c = 122, v = 0: Local Control Off
c = 122, v = 127: Local Control On
All Notes Off.
When an All Notes Off is received,
all oscillators will turn off.
c = 123, v = 0: All Notes Off
(See text for description of actual
mode commands.)
c = 124, v = 0: Omni Mode Off
c = 125, v = 0: Omni Mode On
c = 126, v = M: Mono Mode On (Poly Off)
where M is the number of channels
(Omni Off) or 0 (Omni On)
c = 127, v = 0: Poly Mode On (Mono Off)
(Note: These four messages also cause
All Notes Off)
.pa
-------------------------------------------------------------------------
System Common Messages
-------------------------------------------------------------------------
11110000 0iiiiiii System Exclusive.
0ddddddd This message makes up for all that MIDI
.. doesn't support. (iiiiiii) is a seven
.. bit Manufacturer's I.D. code. If the
0ddddddd synthesizer recognizes the I.D. code as
11110111 its own, it will listen to the rest of
the message (ddddddd). Otherwise, the
message will be ignored. System Exclusive
is used to send bulk dumps such as patch
parameters and other non-spec data.
(Note: Real-Time messages ONLY may be
interleaved with a System Exclusive.)
11110001 Undefined.
11110010 0lllllll Song Position Pointer.
0mmmmmmm This is an internal 14 bit register that
holds the number of MIDI beats (1 beat=
six MIDI clocks) since the start of
the song. l is the LSB, m the MSB.
11110011 0sssssss Song Select.
The Song Select specifies which sequence
or song is to be played.
11110100 Undefined.
11110101 Undefined.
11110110 Tune Request.
Upon receiving a Tune Request, all analog
sythesizers should tune their oscillators.
11110111 End of Exclusive.
Used to terminate a System Exclusive
dump (see above).
.pa
-------------------------------------------------------------------------
System Real-Time Messages
-------------------------------------------------------------------------
11111000 Timing Clock.
Sent 24 times per quarter note when
synchronization is required (see text).
11111001 Undefined.
11111010 Start.
Start the current sequence playing.
(This message will be followed with
Timing Clocks).
11111011 Continue.
Continue at the point the sequence was
Stopped.
11111100 Stop.
Stop the current sequence.
11111101 Undefined.
11111110 Active Sensing.
Use of this message is optional. When
initially sent, the receiver will expect
to receive another Active Sensing message
each 300ms (max), or it will be assume
that the connection has been terminated.
At termination, the receiver will turn off
all voices and return to normal (non-
active sensing) operation.
11111111 Reset.
Reset all receivers in the system to
power-up status. This should be used
sparingly, preferably under manual
control. In particular, it should not
be sent on power-up.
-- Greg, lee@uhccux.uhcc.hawaii.edu

View File

@@ -0,0 +1,689 @@
Standard MIDI-File Format Spec. 1.1
1 - Sequences, Tracks, Chunks: File Block Structure
CONVENTIONS
Some numbers in MIDI Files are represented is a form called VARIABLE-LENGTH
QUANTITY. These numbers are represented 7 bits per byte, most significant
bits first. All bytes except the last have bit 7 set, and the last byte has
bit 7 clear. If the number is between 0 and 127, it is thus represented
exactly as one byte.
Here are some examples of numbers represented as variable-length
quantities:
00000000 00
00000040 40
0000007F 7F
00000080 81 00
00002000 C0 00
00003FFF FF 7F
00004000 81 80 00
00100000 C0 80 00
001FFFFF FF FF 7F
00200000 81 80 80 00
08000000 C0 80 80 00
0FFFFFFF FF FF FF 7F
The largest number which is allowed is 0FFFFFFF so that the variable-length
representations must fit in 32 bits in a routine to write variable-length
numbers. Theoretically, larger numbers are possible, but 2 x 10^8 96ths of
a beat at a fast tempo of 500 beats per minute is four days, long enough
for any delta-time!
FILES
To any file system, a MIDI File is simply a series of 8-bit bytes. On the
Macintosh, this byte stream is stored in the data fork of a file (with file
type 'MIDI'), or on the Clipboard (with data type 'MIDI'). Most other
computers store 8-bit byte streams in files -- naming or storage
conventions for those computers will be defined as required.
CHUNKS
MIDI Files are made up of -chunks-. Each chunk has a 4-character type and a
32-bit length, which is the number of bytes in the chunk. This structure
allows future chunk types to be designed which may be easily be ignored if
encountered by a program written before teh chunk type is introduced. Your
programs should EXPECT alien chunks and treat them as if they weren't
there.
Each chunk begins with a 4-character ASCII type. It is followed by a 32-bit
length, most significant byte first (a length of 6 is stored as 00 00 00
06). This length refers to the number of bytes of data which follow: the
eight bytes of type and length are not included. Therefore, a chunk with a
length of 6 would actually occupy 14 bytes in the disk file.
This chunk architecture is similar to that used by Electronic Arts' IFF
format, and the chunks described herin could easily be placed in an IFF
file. The MIDI File itself is not an IFF file: it contains no nested
chunks, and chunks are not constrained to be an even number of bytes long.
Converting it to an IFF file is as easy as padding odd length chunks, and
sticking the whole thing inside a FORM chunk.
MIDI Files contain two types of chunks: header chunks and track chunks. A
-header- chunk provides a minimal amount of information pertaining to the
entire MIDI file. A -track- chunk contains a sequential stream of MIDI data
which may contain information for up to 16 MIDI channels. The concepts of
multiple tracks, multiple MIDI outputs, patterns, sequences, and songs may
all be implemented using several track chunks.
A MIDI File always starts with a header chunk, and is followed by one or
more track chunks.
MThd <length of header data>
<header data>
MTrk <length of track data>
<track data>
MTrk <length of track data>
<track data>
. . .
2 - Chunk Descriptions
HEADER CHUNKS
The header chunk at the beginning of the file specifies some basic
information about the data in the file. Here's the syntax of the complete
chunk:
<Header Chunk> = <chunk type><length><format><ntrks><division>
As described above, <chunk type> is the four ASCII characters 'MThd';
<length> is a 32-bit representation of the number 6 (high byte first).
The data section contains three 16-bit words, stored most-significant byte
first.
The first word, <format>, specifies the overall organization of the file.
Only three values of <format> are specified:
0-the file contains a single multi-channel track
1-the file contains one or more simultanious tracks (or MIDI outputs) of a
sequence
2-the file contains one or more sequentially independant single-track
patterns
More information about these formats is provided below.
The next word, <ntrks>, is the number of track chunks in the file. It will
always be 1 for a format 0 file.
The third word, <division>, specifies the meaning of the delta-times. It
has two formats, one for metrical time, and one for time-code-based time:
+---+-----------------------------------------+
| 0 | ticks per quarter-note |
==============================================|
| 1 | negative SMPTE format | ticks per frame |
+---+-----------------------+-----------------+
|15 |14 8 |7 0 |
If bit 15 of <division> is zero, the bits 14 thru 0 represent the number of
delta time "ticks" which make up a quarter-note. For instance, if division
is 96, then a time interval of an eighth-note between two events in the
file would be 48.
If bit 15 of <division> is a one, delta times in a file correspond to
subdivisions of a second, in a way consistent with SMPTE and MIDI Time
Code. Bits 14 thru 8 contain one of the four values -24, -25, -29, or -30,
corresponding to the four standard SMPTE and MIDI Time Code formats (-29
corresponds to 30 drop frome), and represents the number of frames per
second. These negative numbers are stored in two's compliment form. The
second byte (stored positive) is the resolution within a frame: typical
values may be 4 (MIDI Time Code resolution), 8, 10, 80 (bit resolution), or
100. This stream allows exact specifications of time-code-based tracks, but
also allows milisecond-based tracks by specifying 25|frames/sec and a
resolution of 40 units per frame. If the events in a file are stored with a
bit resolution of thirty-framel time code, the division word would be E250
hex.
FORMATS 0, 1, AND 2
A Format 0 file has a header chunk followed by one track chunk. It is the
most interchangable representation of data. It is very useful for a simple
single-track player in a program which needs to make synthesizers make
sounds, but which is primarily concerened with something else such as
mixers or sound effect boxes. It is very desirable to be able to produce
such a format, even if your program is track-based, in order to work with
these simple programs. On the other hand, perhaps someone will write a
format conversion from format 1 to format 0 which might be so easy to use
in some setting that it would save you the trouble of putting it into your
program.
A Format 1 or 2 file has a header chunk followed by one or more track
chunks. programs which support several simultanious tracks should be able
to save and read data in format 1, a vertically one-dementional form, that
is, as a collection of tracks. Programs which support several independant
patterns should be able to save and read data in format 2, a horizontally
one-dementional form. Providing these minimum capabilities will ensure
maximum interchangability.
In a MIDI system with a computer and a SMPTE synchronizer which uses Song
Pointer and Timing Clock, tempo maps (which describe the tempo throughout
the track, and may also include time signature information, so that the bar
number may be derived) are generally created on the computer. To use them
with the synchronizer, it is necessary to transfer them from the computer.
To make it easy for the synchronizer to extract this data from a MIDI File,
tempo information should always be stored in the first MTrk chunk. For a
format 0 file, the tempo will be scattered through the track and the tempo
map reader should ignore the intervening events; for a format 1 file, the
tempo map must be stored as the first track. It is polite to a tempo map
reader to offerr your user the ability to make a format 0 file with just
the tempo, unless you can use format 1.
All MIDI Files should specify tempo and time signature. If they donn't, the
time signature is assumed to be 4/4, and the tempo 120 beats per minute. In
format 0, these meta-events should occur at least at the beginning of the
single multi-channel track. In format 1, these meta-events should be
contained i| the first track. In format 2, each of the temporally
independant patterns should contain at least initial time signature and
tempo information.
We may decide to define other format IDs to support other structures. A
program encountering an unknown format ID may still read other MTrk chunks
it finds from the file, as format 1 or 2, if its user can make sense of
them and arrange them into some other structure if appropriate. Also, more
parameters may be added to the MThd chunk in the future: it is important to
read and honor the length, even if it is longer than 6.
TRACK CHUNKS
The track chunks (type MTrk) are where actual song data is stored. Each
track chunk is simply a stream of MIDI events (and non-MIDI events),
preceded by delta-time values. The format for Track Chunks (described
below) is exactly the same for all three formats (0, 1, and 2: see "Header
Chunk" above) of MIDI Files.
Here is the syntax of an MTrk chunk (the + means "one or more": at least
one MTrk event must be present):
<Track Chunk> = <chunk type><length><MTrk event>+
The syntax of an MTrk event is very simple:
<MTrk event> = <delta-time><event>
<delta-time> is stored as a variable-length quantity. It represents the
amount of time before the following event. If the first event in a track
occurs at the very beginning of a track, or if two events occur
simultaineously, a delta-time of zero is used. Delta-times are always
present. (Not storing delta-times of 0 requires at least two bytes for any
other value, and most delta-times aren't zero.) Delta-time is in some
fraction of a beat (or a second, for recording a track with SMPTE times),
as specified in the header chunk.
<event> = <MIDI event> | <sysex event> | <meta-event>
<MIDI event> is any MIDI channel message. Running status is used: status
bytes of MIDI channel messages may be omitted if the preceding event is a
MIDI channel message with the same status. The first event in each MTrk
chunk must specifyy status. Delta-time is not considered an event itself:
it is an integral part of the syntax for an MTrk event. Notice that running
status occurs across delta-times.
<sysex event> is used to specify a MIDI system exclusive message, either as
one unit or in packets, or as an "escape" to specify any arbitrary bytes to
be transmitted. A normal complete system exclusive message is stored in a
MIDI File in this way:
F0 <length> <bytes to be transmitted after F0>
The length is stored as a variable-length quantity. It specifies the number
of bytes which follow it, not including the F0 or the length itself. For
instance, the transmitted message F0 43 12 00 07 F7 would be stored in a
MIDI File as F0 05 43 12 00 07 F7. It is required to include the F7 at the
end so that the reader of the MIDI File knows that it has read the entire
message.
Another form of sysex event is provided which does not imply that an F0
should be transmitted. This may be used as an "escape" to provide for the
transmission of things which would not otherwise be legal, including system
realtime messages, song pointer or select, MIDI Time Code, etc. This uses
the F7 code:
F7 <length> <all bytes to be transmitted>
Unfortunately, some synthesizer manufacturers specify that their system
exclusive messages are to be transmitted as little packets. Each packet is
only part of an entire syntactical system exclusive message, but the times
they are transmitted are important. Examples of this are the bytes sent in
a CZ patch dump, or the FB-01's "system exclusive mode" in which microtonal
data can be transmitted. The F0 and F7 sysex events may be used together to
break up syntactically complete system exclusive messages into timed
packets.
An F0 sysex event is used for the first packet in a series -- it is a
message in which the F0 should be transmitted. An F7 sysex event is used
for the remainder of the packets, which do not begin with F0. (Of course,
the F7 is not considered part of the system exclusive message).
A syntactic system exclusive message must always end with an F7, even if
the real-life device didn't send one, so that you know when you've reached
the end of an entire sysex message without looking ahead to the next event
in the MIDI File. If it's stored in one compllete F0 sysex event, the last
byte must be an F7. There also must not be any transmittable MIDI events in
between the packets of a multi-packet system exclusive message. This
principle is illustrated in the paragraph below.
Here is a MIDI File of a multi-packet system exclusive message: suppose the
bytes F0 43 12 00 were to be sent, followed by a 200-tick delay, followed
by the bytes 43 12 00 43 12 00, followed by a 100-tick delay, followed by
the bytes 43 12 00 F7, this would be in the MIDI File:
F0 03 43 12 00
81 48 200-tick delta time
F7 06 43 12 00 43 12 00
64 100-tick delta time
F7 04 43 12 00 F7
When reading a MIDI File, and an F7 sysex event is encountered without a
preceding F0 sysex event to start a multi-packet system exclusive message
sequence, it should be presumed that the F7 event is being used as an
"escape". In this case, it is not necessary that it end with an F7, unless
it is desired that the F7 be transmitted.
<meta-event> specifies non-MIDI information useful to this format or to
sequencers, with this syntax:
FF <type> <length> <bytes>
All meta-events begin with FF, then have an event type byte (which is
always less than 128), and then have the length of the data stored as a
variable-length quantity, and then the data itself. If there is no data,
the length is 0. As with chunks, future meta-events may be designed which
may not be known to existing programs, so programs must properly ignore
meta-events which they do not recognize, and indeed should expect to see
them. Programs must never ignore the length of a meta-event which they do
not recognize, and they shouldn't be surprized if it's bigger than
expected. If so, they must ignore everything past what they know about.
However, they must not add anything of their own to the end of the meta-
event.
Sysex events and meta events cancel any running status which was in effect.
Running status does not apply to and may not be used for these messages.
3 - Meta-Events
A few meta-events are defined herin. It is not required for every program
to support every meta-event.
In the syntax descriptions for each of the meta-events a set of conventions
is used to describe parameters of the events. The FF which begins each
event, the type of each event, and the lengths of events which do not have
a variable amount of data are given directly in hexadecimal. A notation
such as dd or se, which consists of two lower-case letters, mnemonically
represents an 8-bit value. Four identical lower-case letters such as wwww
mnemonically refer to a 16-bit value, stored most-significant-byte first.
Six identical lower-case letters such as tttttt refer to a 24-bit value,
stored most-significan-byte first. The notation len refers to teh length
portion of the meta-event syntax, that is, a number, stored as a variable-
length quantity, which specifies how many bytes (possibly text) data were
just specified by the length.
In general, meta-events in a track which occur at the same time may occur
in any order. If a copyright event is used, it should be placed as early as
possible in the file, so it will be noticed easily. Sequence Number and
Sequence/Track Name events, if present, must appear at time 0. An end-of-
track event must occur as the last event in the track.
Meta-events initially defined include:
FF 00 02 Sequence Number
This optional event, which must occur at the beginning of a track,
before any nonzero delta-times, and before any transmittable MIDI
events, specifies the number of a sequence. In a format 2 MIDI File, it
is used to identify each "pattern" so that a "song" sequence using the
Cue message to refer to the patterns. If the ID numbers are omitted,
the sequences' lacations in order in the file are used as defaults. In
a format 0 or 1 MIDI File, which only contain one sequence, this number
should be contained in the first (or only) track. If transfer of
several multitrack sequences is required, this must be done as a group
of format 1 files, each with a different sequence number.
FF 01 len text Text Event
Any amount of text describing anything. It is a good idea to put a text
event right at the beginning of a track, with the name of the track, a
description of its intended orchestration, and any other information
which the user wants to put there. Text events may also occur at other
times in a track, to be used as lyrics, or descriptions of cue points.
The text in this event should be printable ASCII characters for maximum
interchange. However, other characters codes using the high-order bit
may be used for interchange of files between different programs on the
same computer which supports an extended character set. Programs on a
computer which does not support non-ASCII characters should ignore
those characters.
Meta-event types 01 through 0F are reserved for various types of text
events, each of which meets the specification of text events (above)
but is used for a different purpose:
FF 02 len text Copyright Notice
Contains a copyright notice as printable ASCII text. The notice should
contain the characters (C), the year of the copyright, and the owner of
the copyright. If several pieces of music are in the same MIDI File,
all of the copyright notices should be placed together in this event so
that it will be at the beginning of the file. This event should be the
first event in the track chunk, at time 0.
FF 03 len text Sequence/Track Name
If in a format 0 track, or the first track in a format 1 file, the name
of the sequence. Otherwise, the name of the track.
FF 04 len text Instrument Name
A description of the type of instrumentation to be used in that track.
May be used with the MIDI Prefix meta-event to specify which MIDI
channel the description applies to, or the channel may be specified as
text in the event itself.
FF 05 len text Lyric
A lyric to be sung. Generally, each syllable will be a seperate lyric
event which begins at the event's time.
FF 06 len text Marker
Normally in a format 0 track, or the first track in a format 1 file.
The name of that point in the sequence, such as a rehersal letter or
section name ("First Verse", etc.)
FF 07 len text Cue Point
A description of something happening on a film or video screen or stage
at that point in the musical score ("Car crashes into house",
"curtain opens", "she slaps his face", etc.)
FF 20 01 cc MIDI Channeel Prefix
The MIDI channel (0-15) containted in this event may be used to
associate a MIDI channel with all events which follow, including System
exclusive and meta-events. This channel is "effective" until the next
normal MIDI event (which contains a channel) or the next MIDI Channel
Prefix meta-event. If MIDI channels refer to "tracks", this message may
into a format 0 file, keeping their non-MIDI data associated with a
track. This capability is also present in Yamaha's ESEQ file format.
FF 2F 00 End of Track
This event is not optional. It is included so that an exact ending
point may be specified for the track, so that an exect length, which is
necessary for tracks which are looped or concatenated.
FF 51 03 tttttt Set Tempo
(in microseconds per MIDI quarter-note)
This event indicates a tempo change. Another way of putting
"microseconds per quarter-note" is "24ths of a microsecond per MIDI
clock". Repersenting tempos as time per beat instead of beat per time
allows absolutly exact long-term synchronization with a time-based sync
protocol such as SMPTE time code or MIDI time code. This amount of
accuracy provided by this tempo resolution allows a four-minute piece
at 120 beats per minute to be accurate within 500 usec at the end of
the piece. Ideally, these events should only occur where MIDI clocks
would be located -- this convention is intended to guarntee, or at
least increase the liklihood, of compatibility with other
synchronization devices so that a time signature/tempo map stored in
this format may easily be transfered to another device.
FF 54 05 hr mn se fr ff SMPTE Offset
This event, if present, designates the SMPTE time at which the track
chunk is supposed to start. It should be present at the beginning of
the track, that is, before any nonzero delta-times, and before any
transmittable MIDI events. the hour must be encoded with the SMPTE
format, just as it is in MIDI Time Code. In a format 1 file, the SMPTE
Offset must be stored with the tempo map, and has no meaning in any of
the other tracks. The ff field contains fractional frames, in 100ths of
a frame, even in SMPTE-based tracks which specify a different frame
subdivision for delta-times.
FF 58 04 nn dd cc bb Time Signature
The time signature is expressed as four numbers. nn and dd represent
the numerator and denominator of the time signature as it would be
notated. The denominator is a neqative power of two: 2 represents a
quarter-note, 3 represents an eighth-note, etc. The cc parameter
expresses the number of MIDI clocks in a metronome click. The bb
parameter expresses the number of notated 32nd-notes in a MIDI
quarter-note (24 MIDI clocks). This was added because there are already
multiple programs which allow a user to specify that what MIDI thinks
of as a quarter-note (24 clocks) is to be notated as, or related to in
terms of, something else.
Therefore, the complete event for 6/8 time, where the metronome clicks
every three eighth-notes, but there are 24 clocks per quarter-note, 72
to the bar, would be (in hex):
FF 58 04 06 03 24 08
That is, 6/8 time (8 is 2 to the 3rd power, so this is 06 03), 36 MIDI
clocks per dotted-quarter (24 hex!), and eight notated 32nd-notes per
quarter-note.
FF 59 02 sf mi Key Signature
sf = -7: 7 flats
sf = -1: 1 flat
sf = 0: key of C
sf = 1: 1 sharp
sf = 7: 7 sharps
mi = 0: major key
mi = 1: minor key
FF 7F len data Sequencer Specific Meta-Event
Special requirements for particular sequencers may use this event type:
the first byte or bytes of data is a manufacturer ID (these are one
byte, or if the first byte is 00, three bytes). As with MIDI System
Exclusive, manufacturers who define something using this meta-event
should publish it so that others may be used by a sequencer which
elects to use this as its only file format; sequencers with their
established feature-specific formats should probably stick to the
standard features when using this format.
4 - Program Fragments and Example MIDI Files
Here are some of the routines to read and write variable-length numbers in
MIDI Files. These routines are in C, and use getc and putc, which read and
write single 8-bit characters from/to the files infile and outfile.
WriteVarLen (value)
register long value;
(
register long buffer;
buffer = value & 0x7f;
while ((value >>= 7) > 0)
(
buffer <<= 8;
buffer |= 0x80;
buffer += (value & 0x7f);
)
while (TRUE)
(
putc(buffer,outfile);
if (buffer & 0x80)
buffer >>= 8;
else
break;
)
)
doubleword ReadVarLen ()
(
register doubleword value;
register byte c;
if ((value = getc(infile)) & 0x80)
(
value &= 0x7f;
do
(
value = (value << 7) + ((c = getc(infile))) & 0x7f);
) while (c & 0x80);
)
return (value);
)
As an example, MIDI Files for the following excerpt are shown below. First,
a format 0 file is shown, with all information intermingled; then, a format
1 file is shown with all data seperated into four tracks: one for tempo and
time signature, and three for the notes. A resolution of 96 "ticks" per
quarter note is used. A time signature of 4/4 and a tempo of 120, though
implied, are explicitly stated.
|\
---- | > ---------------------------------------
|/ ____ O
Channel 1 ---- X --------------------------------|--------
/ |
Preset 5 -- / | --------------------------------|--------
/ ____ |
-| | \ --------------------------------------
\ | |
-- \_|__/ --------------------------------------
_|
|\
---- | > ---------------------------------------
|/ \
Channel 2 ---- X ------------>----------|-----------------
/ / |
Preset 46 -- / | ----------<------------|-----------------
/ ____ \ | .
-| | \ --------->---------O------------------
\ | | (
-- \_|__/ --------\-----------------------------
_| \
--O--
----__ -----------------------------------------
/ \ .
Channel 3 - / | ---------------------------------------
| .
Preset 70 ------ | ---------------------------------------
/ O
---- / -----------------------------------------
/
-- / -------------------------------------------
The contents of the MIDI stream represented by this example are broken down
here:
Delta-Time Event-Code Other Bytes Comment
(decimal) (hex) (decimal)
---------- ---------- ----------- -----------------------------
0 FF 58 04 04 02 24 08 4 bytes; 4/4 time; 24 MIDI
clocks/click, 8 32nd notes/
24 MIDI clocks
0 FF 51 03 500000 3 bytes: 500,000 usec/
quarter note
0 C0 5 Ch.1 Program Change 5
0 C1 46 Ch.2 Program Change 46
0 C2 70 Ch.3 Program Change 70
0 92 48 96 Ch.3 Note On C2, forte
0 92 60 96 Ch.3 Note On C3, forte
96 91 67 64 Ch.2 Note On G3, mezzo-forte
96 90 76 32 Ch.1 Note On E4, piano
192 82 48 64 Ch.3 Note Off C2, standard
0 82 60 64 Ch.3 Note Off C3, standard
0 81 67 64 Ch.2 Note Off G3, standard
0 80 76 64 Ch.1 Note Off E4, standard
0 FF 2F 00 Track End
The entire format 0 MIDI file contents in hex follow. First, the header
chunk:
40 54 68 64 MThd
00 00 00 06 chunk length
00 00 format 0
00 01 one track
00 60 96 per quarter-note
Then the track chunk. Its header followed by the events (notice the running
status is used in places):
4D 54 72 6B MTrk
00 00 00 3B chunk length (59)
Delta-Time Event Comments
---------- ----------------------- -------------------------------
00 FF 58 04 04 02 18 08 time signature
00 FF 51 03 07 A1 20 tempo
00 C0 05
00 C1 2E
00 C2 46
00 92 30 60
00 3C 60 running status
60 91 43 40
60 90 4C 20
81 40 82 30 40 two-byte delta-time
00 3C 40 running status
00 81 43 40
00 80 4C 40
00 FF 2F 00 end of track
A format 1 representation of the file is slightly different. Its header
chunk:
4D 54 68 64 MThd
00 00 00 06 chunk length
00 01 format 1
00 04 four tracks
00 60 96 per quarter note
First, the track chunk for the time signature/tempo track. Its header,
followed by the events:
4D 54 72 6B MTrk
00 00 00 14 chunk length (20)
Delta-Time Event Comments
---------- ----------------------- -------------------------------
00 FF 58 04 04 02 18 08 time signature
00 FF 51 03 07 A1 20 tempo
83 00 FF 2F 00 end of track
Then, the track chunk for the first music track. The MIDI convention for
note on/off running status is used in this example:
4D 54 72 6B MTrk
00 00 00 10 chunk length (16)
Delta-Time Event Comments
---------- ----------------------- -------------------------------
00 C0 05
81 40 90 4C 20
81 40 4C 00 Running status: note on, vel=0
00 FF 2F 00
Then, the track chunk for the second music track:
4D 54 72 6B MTrk
00 00 00 0F chunk length (15)
Delta-Time Event Comments
---------- ----------------------- -------------------------------
00 C1 2E
60 91 43 40
82 20 43 00 running status
00 FF 2F 00 end of track
Then, the track chunk for the third music track:
4D 54 72 6B MTrk
00 00 00 15 chunk length (21)
Delta-Time Event Comments
---------- ----------------------- -------------------------------
00 C2 46
00 92 30 60
00 3C 60 running status
83 00 30 00 two-byte delta-time, running status
00 3C 00 running status
00 FF 2F 00 end of track

View File

@@ -0,0 +1,405 @@
Standard MIDI File Format
Dustin Caldwell
The standard MIDI file format is a very strange beast. When viewed as a
whole, it can be quite overwhelming. Of course, no matter how you look at it,
describing a piece of music in enough detail to be able to reproduce it
accurately is no small task. So, while complicated, the structure of the midi
file format is fairly intuitive when understood.
I must insert a disclaimer here that I am by no means an expert with
midi nor midi files. I recently obtained a Gravis UltraSound board for my PC,
and upon hearing a few midi files (.MID) thought, "Gee, I'd like to be able to
make my own .MID files." Well, many aggravating hours later, I discovered that
this was no trivial task. But, I couldn't let a stupid file format stop me.
(besides, I once told my wife that computers aren't really that hard to use,
and I'd hate to be a hypocrite) So if any errors are found in this
information, please let me know and I will fix it. Also, this document's scope
does not extend to EVERY type of midi command and EVERY possible file
configuration. It is a basic guide that should enable the reader (with a
moderate investment in time) to generate a quality midi file.
1. Overview
A midi (.MID) file contains basically 2 things, Header chunks and Track
chunks. Section 2 explains the header chunks, and Section 3 explains the track
chunks. A midi file contains ONE header chunk describing the file format,
etc., and any number of track chunks. A track may be thought of in the same
way as a track on a multi-track tape deck. You may assign one track to each
voice, each staff, each instrument or whatever you want.
2. Header Chunk
The header chunk appears at the beginning of the file, and describes the
file in three ways. The header chunk always looks like:
4D 54 68 64 00 00 00 06 ff ff nn nn dd dd
The ascii equivalent of the first 4 bytes is MThd. After MThd comes the 4-byte
size of the header. This will always be 00 00 00 06, because the actual header
information will always be 6 bytes.
ff ff is the file format. There are 3 formats:
0 - single-track
1 - multiple tracks, synchronous
2 - multiple tracks, asynchronous
Single track is fairly self-explanatory - one track only. Synchronous multiple
tracks means that the tracks will all be vertically synchronous, or in other
words, they all start at the same time, and so can represent different parts
in one song. Asynchronous multiple tracks do not necessarily start at the same
time, and can be completely asynchronous.
nn nn is the number of tracks in the midi file.
dd dd is the number of delta-time ticks per quarter note. (More about this
later)
3. Track Chunks
The remainder of the file after the header chunk consists of track chunks.
Each track has one header and may contain as many midi commands as you like.
The header for a track is very similar to the one for the file:
4D 54 72 6B xx xx xx xx
As with the header, the first 4 bytes has an ascii equivalent. This one is
MTrk. The 4 bytes after MTrk give the length of the track (not including the
track header) in bytes.
Following the header are midi events. These events are identical to the
actual data sent and received by MIDI ports on a synth with one addition. A
midi event is preceded by a delta-time. A delta time is the number of ticks
after which the midi event is to be executed. The number of ticks per quarter
note was defined previously in the file header chunk. This delta-time is a
variable-length encoded value. This format, while confusing, allows large
numbers to use as many bytes as they need, without requiring small numbers to
waste bytes by filling with zeros. The number is converted into 7-bit bytes,
and the most-significant bit of each byte is 1 except for the last byte of the
number, which has a msb of 0. This allows the number to be read one byte at a
time, and when you see a msb of 0, you know that it was the last (least
significant) byte of the number. According to the MIDI spec, the entire delta-
time should be at most 4 bytes long.
Following the delta-time is a midi event. Each midi event (except a
running midi event) has a command byte which will always have a msb of 1 (the
value will be >= 128). A list of most of these commands is in appendix A. Each
command has different parameters and lengths, but the data that follows the
command will have a msb of 0 (less than 128). The exception to this is a meta-
event, which may contain data with a msb of 1. However, meta-events require a
length parameter which alleviates confusion.
One subtlety which can cause confusion is running mode. This is where
the actual midi command is omitted, and the last midi command issued is
assumed. This means that the midi event will consist of a delta-time and the
parameters that would go to the command if it were included.
4. Conclusion
If this explanation has only served to confuse the issue more, the
appendices contain examples which may help clarify the issue. Also, 2
utilities and a graphic file should have been included with this document:
DEC.EXE - This utility converts a binary file (like .MID) to a tab-delimited
text file containing the decimal equivalents of each byte.
REC.EXE - This utility converts a tab-delimited text file of decimal values
into a binary file in which each byte corresponds to one of the decimal
values.
MIDINOTE.PS - This is the postscript form of a page showing note numbers with
a keyboard and with the standard grand staff.
Appendix A
1. MIDI Event Commands
Each command byte has 2 parts. The left nybble (4 bits) contains the actual
command, and the right nybble contains the midi channel number on which the
command will be executed. There are 16 midi channels, and 8 midi commands (the
command nybble must have a msb of 1).
In the following table, x indicates the midi channel number. Note that all
data bytes will be <128 (msb set to 0).
Hex Binary Data Description
8x 1000xxxx nn vv Note off (key is released)
nn=note number
vv=velocity
9x 1001xxxx nn vv Note on (key is pressed)
nn=note number
vv=velocity
Ax 1010xxxx nn vv Key after-touch
nn=note number
vv=velocity
Bx 1011xxxx cc vv Control Change
cc=controller number
vv=new value
Cx 1100xxxx pp Program (patch) change
pp=new program number
Dx 1101xxxx cc Channel after-touch
cc=channel number
Ex 1110xxxx bb tt Pitch wheel change (2000H is normal or no
change)
bb=bottom (least sig) 7 bits of value
tt=top (most sig) 7 bits of value
The following table lists meta-events which have no midi channel number. They
are of the format:
FF xx nn dd
All meta-events start with FF followed by the command (xx), the length, or
number of bytes that will contain data (nn), and the actual data (dd).
Hex Binary Data Description
00 00000000 nn ssss Sets the track's sequence number.
nn=02 (length of 2-byte sequence number)
ssss=sequence number
01 00000001 nn tt .. Text event- any text you want.
nn=length in bytes of text
tt=text characters
02 00000010 nn tt .. Same as text event, but used for
copyright info.
nn tt=same as text event
03 00000011 nn tt .. Sequence or Track name
nn tt=same as text event
04 00000100 nn tt .. Track instrument name
nn tt=same as text event
05 00000101 nn tt .. Lyric
nn tt=same as text event
06 00000110 nn tt .. Marker
nn tt=same as text event
07 00000111 nn tt .. Cue point
nn tt=same as text event
2F 00101111 00 This event must come at the end of each
track
51 01010001 03 tttttt Set tempo
tttttt=microseconds/quarter note
58 01011000 04 nn dd ccbb Time Signature
nn=numerator of time sig.
dd=denominator of time sig. 2=quarter
3=eighth, etc.
cc=number of ticks in metronome click
bb=number of 32nd notes to the quarter
note
59 01011001 02 sf mi Key signature
sf=sharps/flats (-7=7 flats, 0=key of C,
7=7 sharps)
mi=major/minor (0=major, 1=minor)
7F 01111111 xx dd .. Sequencer specific information
xx=number of bytes to be sent
dd=data
The following table lists system messages which control the entire system.
These have no midi channel number. (these will generally only apply to
controlling a midi keyboard, etc.)
Hex Binary Data Description
F8 11111000 Timing clock used when synchronization is
required.
FA 11111010 Start current sequence
FB 11111011 Continue a stopped sequence where left
off
FC 11111100 Stop a sequence
The following table lists the numbers corresponding to notes for use in note
on and note off commands.
Octave|| Note Numbers
# ||
|| C | C# | D | D# | E | F | F# | G | G# | A | A# | B
-----------------------------------------------------------------------------
0 || 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
1 || 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23
2 || 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35
3 || 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47
4 || 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59
5 || 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71
6 || 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83
7 || 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95
8 || 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107
9 || 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119
10 || 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 |
BIBLIOGRAPHY
"MIDI Systems and Control" Francis Rumsey 1990 Focal Press
"MIDI and Sound Book for the Atari ST" Bernd Enders and Wolfgang Klemme
1989 M&T Publishing, Inc.
MIDI file specs and general MIDI specs were also obtained by sending e-mail
to LISTSERV@AUVM.AMERICAN.EDU with the phrase GET MIDISPEC PACKAGE
in the message.
------------------------------- DEC.CPP ------------------------------------
/* file dec.cpp
by Dustin Caldwell (dustin@gse.utah.edu)
*/
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
void helpdoc();
main()
{
FILE *fp;
unsigned char ch, c;
if((fp=fopen(_argv[1], "rb"))==NULL) /* open file to read */
{
printf("cannot open file %s\n",_argv[1]);
helpdoc();
exit(-1);
}
c=0;
ch=fgetc(fp);
while(!feof(fp)) /* loop for whole file */
{
printf("%u\t", ch); /* print every byte's decimal equiv. */
c++;
if(c>8) /* print 8 numbers to a line */
{
c=0;
printf("\n");
}
ch=fgetc(fp);
}
fclose(fp); /* close up */
}
void helpdoc() /* print help message */
{
printf("\n Binary File Decoder\n\n");
printf("\n Syntax: dec binary_file_name\n\n");
printf("by Dustin Caldwell (dustin@gse.utah.edu)\n\n");
printf("This is a filter program that reads a binary file\n");
printf("and prints the decimal equivalent of each byte\n");
printf("tab-separated. This is mostly useful when piped \n");
printf("into another file to be edited manually. eg:\n\n");
printf("c:\>dec sonata3.mid > son3.txt\n\n");
printf("This will create a file called son3.txt which can\n");
printf("be edited with any ascii editor. \n\n");
printf("(rec.exe may also be useful, as it reencodes the \n");
printf("ascii text file).\n\n");
printf("Have Fun!!\n");
}
---------------------------- REC.CPP ----------------------------------
/* File rec.cpp
by Dustin Caldwell (dustin@gse.utah.edu)
*/
#include <dos.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
void helpdoc();
main()
{
FILE *rfp, *wfp;
unsigned char ch, c;
char s[20];
if((rfp=fopen(_argv[1], "r"))==NULL) /* open the read file */
{
printf("cannot open file %s \n",_argv[1]);
helpdoc();
exit(-1);
}
if((wfp=fopen(_argv[2], "wb"))==NULL) /* open the write file */
{
printf("cannot open file %s \n",_argv[1]);
helpdoc();
exit(-1);
}
c=0;
ch=fgetc(rfp);
while(!feof(rfp)) /* loop for whole file */
{
if(isalnum(ch)) /* only 'see' valid ascii chars */
{
c=0;
while(isdigit(ch)) /* only use decimal digits (0-9) */
{
s[c]=ch; /* build a string containing the number */
c++;
ch=fgetc(rfp);
}
s[c]=NULL; /* must have NULL terminator */
fputc(atoi(s), wfp);/* write the binary equivalent to file */
}
ch=fgetc(rfp); /* loop until next number starts */
}
fclose(rfp); /* close up */
fclose(wfp);
}
void helpdoc() /* print help message */
{
printf("\n Text File Encoder\n\n");
printf("\n Syntax: rec text_file_name binary_file_name\n\n");
printf("by Dustin Caldwell (dustin@gse.utah.edu)\n\n");
printf("This is a program that reads an ascii tab-\n");
printf("delimited file and builds a binary file where\n");
printf("each byte of the binary file is one of the decimal\n");
printf("digits in the text file.\n");
printf(" eg:\n\n");
printf("c:\>rec son3.txt son3.mid\n\n");
printf("(This will create a file called son3.mid which is\n");
printf("a valid binary file)\n\n");
printf("(dec.exe may also be useful, as it decodes binary files)\n\n");
printf("Have Fun!!\n");
}

View File

@@ -0,0 +1,641 @@
To get your copy of the 1.0 spec, send a $2 check to:
International Midi Association
5316 West 57th Street
Los Angeles, CA 90056
(415) 321-MIDI
Make your checks payable to the IMA. BYW, the 1.0 spec is technically
identical to the .06 spec, but the description has been re-written.
Since the spec has been offically approved, there shouldn't be any
problem with posting this summary of the .06 spec:
[This document is Dave Oppenheim's current version of the MIDI file
specification, as sent to those who have participated in its
development. The consensus seems to be to submit this to the MIDI
Manufacturers' Association as version 1.0. I apologize for any loss of
clarity that might have occurred in the conversion from a Microsoft Word
document to this pure text file. I have removed some of the discussion
about recent changes to the specification in order to keep the file size
reasonable.--Doug Wyatt]
Standard MIDI Files 0.06 March 1, 1988
0 Introduction
This describes a proposed standard MIDI file format. MIDI files contain
one or more MIDI streams, with time information for each event. Song,
sequence, and track structures, tempo and time signature information,
are all supported. Track names and other descriptive information may be
stored with the MIDI data. This format supports multiple tracks and
multiple sequences so that if the user of a program which supports
multiple tracks intends to move a file to another one, this format can
allow that to happen.
This spec defines the 8-bit binary data stream used in the file. The
data can be stored in a binary file, nibbleized, 7-bit-ized for
efficient MIDI transmission, converted to Hex ASCII, or translated
symbolically to a printable text file. This spec addresses what's in
the 8-bit stream.
1 Sequences, Tracks, Chunks: File Block Structure
Sequence files are made up of chunks. Each chunk has a 4-character type
and a 32-bit length, which is the number of bytes in the chunk. On the
Macintosh, data is passed either in the data fork of a file, or on the
Clipboard. (The file type on the Macintosh for a file in this format
will be "Midi".) On any other computer, the data is simply the contents
of the file. This structure allows future chunk types to be designed
which may easily be ignored if encountered by a program written before
the chunk type is introduced. Your programs should expect alien chunks
and treat them as if they weren't there.
This proposal defines two types of chunks: a header chunk and a track
chunk. A header chunk provides a minimal amount of information
pertaining to the entire MIDI file. A track chunk contains a sequential
stream of MIDI data which may contain information for up to 16 MIDI
channels. The concepts of multiple tracks, multiple MIDI outputs,
patterns, sequences, and songs may all be implemented using several
track chunks.
A MIDI file always starts with a header chunk, and is followed by one or
more track chunks.
MThd <length of header data>
<header data>
MTrk <length of track data>
<track data>
MTrk <length of track data>
<track data>
...
Track Data Format (MTrk chunk type)
The MTrk chunk type is where actual song data is stored. It is simply a
stream of MIDI events (and non-MIDI events), preceded by delta-time
values.
Some numbers in MTrk chunks are represented in a form called a variable-
length quantity. These numbers are represented 7 bits per byte, most
significant bits first. All bytes except the last have bit 7 set, and
the last byte has bit 7 clear. If the number is between 0 and 127, it
is thus represented exactly as one byte.
Here are some examples of numbers represented as variable-length
quantities:
Number (hex) Representation (hex)
00000000 00
00000040 40
0000007F 7F
00000080 81 00
00002000 C0 00
00003FFF FF 7F
00004000 81 80 00
00100000 C0 80 00
001FFFFF FF FF 7F
00200000 81 80 80 00
08000000 C0 80 80 00
0FFFFFFF FF FF FF 7F
The largest number which is allowed is 0FFFFFFF so that the variable-
length representation must fit in 32 bits in a routine to write
variable-length numbers. Theoretically, larger numbers are possible,
but 2 x 108 96ths of a beat at a fast tempo of 500 beats per minute is
four days, long enough for any delta-time!
Here is the syntax of an MTrk chunk:
<track data> = <MTrk event>+
<MTrk event> = <delta-time> <event>
<delta-time> is stored as a variable-length quantity. It represents the
amount of time before the following event. If the first event in a
track occurs at the very beginning of a track, or if two events occur
simultaneously, a delta-time of zero is used. Delta-times are always
present. (Not storing delta-times of 0 requires at least two bytes for
any other value, and most delta-times aren't zero.) Delta-time is in
some fraction of a beat (or a second, for recording a track with SMPTE
times), as specified in the header chunk.
<event> = <MIDI event> | <sysex event> | <meta-event>
<MIDI event> is any MIDI channel message. Running status is used:
status bytes may be omitted after the first byte. The first event in a
file must specify status. Delta-time is not considered an event
itself: it is an integral part of the specification. Notice that
running status occurs across delta-times.
<meta-event> specifies non-MIDI information useful to this format or to
sequencers, with this syntax:
FF <type> <length> <bytes>
All meta-events begin with FF, then have an event type byte (which is
always less than 128), and then have the length of the data stored as a
variable-length quantity, and then the data itself. If there is no
data, the length is 0. As with sysex events, running status is not
allowed. As with chunks, future meta-events may be designed which may
not be known to existing programs, so programs must properly ignore
meta-events which they do not recognize, and indeed, should expect to
see them. New for 0.06: programs must never ignore the length of a
meta-event which they do recognize, and they shouldn't be surprised if
it's bigger than they expected. If so, they must ignore everything past
what they know about. However, they must not add anything of their own
to the end of a meta-event.
<sysex event> is used to specify a MIDI system exclusive message, or as
an "escape" to specify any arbitrary bytes to be transmitted.
Unfortunately, some synthesizer manufacturers specify that their system
exclusive messages are to be transmitted as little packets. Each packet
is only part of an entire syntactical system exclusive message, but the
times they are transmitted at are important. Examples of this are the
bytes sent in a CZ patch dump, or the FB-01's "system exclusive mode" in
which microtonal data can be transmitted. To be able to handle
situations like these, two forms of <sysex event> are provided:
F0 <length> <bytes to be transmitted after F0>
F7 <length> <all bytes to be transmitted>
In both cases, <length> is stored as a variable-length quantity. It is
equal to the number of bytes following it, not including itself or the
message type (F0 or F7), but all the bytes which follow, including any
F7 at the end which is intended to be transmitted. The first form, with
the F0 code, is used for syntactically complete system exclusive
messages, or the first packet an a series Q that is, messages in which
the F0 should be transmitted. The second form is used for the remainder
of the packets within a syntactic sysex message, which do not begin with
F0. Of course, the F7 is not considered part of the system exclusive
message. Of course, just as in MIDI, running status is not allowed, in
this case because the length is stored as a variable-length quantity
which may or may not start with bit 7 set.
(New to 0.06) A syntactic system exclusive message must always end with
an F7, even if the real-life device didn't send one, so that you know
when you've reached the end of an entire sysex message without looking
ahead to the next event in the MIDI file. This principle is repeated
and illustrated in the paragraphs below.
The vast majority of system exclusive messages will just use the F0
format. For instance, the transmitted message F0 43 12 00 07 F7 would
be stored in a MIDI file as F0 05 43 12 00 07 F7. As mentioned above,
it is required to include the F7 at the end so that the reader of the
MIDI file knows that it has read the entire message.
For special situations when a single system exclusive message is split
up, with parts of it being transmitted at different times, such as in a
Casio CZ patch transfer, or the FB-01's "system exclusive mode", the F7
form of sysex event is used for each packet except the first. None of
the packets would end with an F7 except the last one, which must end
with an F7. There also must not be any transmittable MIDI events in-
between the packets of a multi-packet system exclusive message. Here is
an example: suppose the bytes F0 43 12 00 were to be sent, followed by
a 200-tick delay, followed by the bytes 43 12 00 43 12 00, followed by
a 100-tick delay, followed by the bytes 43 12 00 F7, this would be in
the MIDI File:
F0 03 43 12 00
81 48 200-tick delta-time
F7 06 43 12 00 43 12 00
64 100-tick delta-time
F7 04 43 12 00 F7
The F7 event may also be used as an "escape" to transmit any bytes
whatsoever, including real-time bytes, song pointer, or MIDI Time Code,
which are not permitted normally in this specification. No effort
should be made to interpret the bytes used in this way. Since a system
exclusive message is not being transmitted, it is not necessary or
appropriate to end the F7 event with an F7 in this case.
2 Header Chunk
The header chunk at the beginning of the file specifies some basic
information about the data in the file. The data section contains three
16-bit words, stored high byte first (of course). Here's the syntax of
the complete chunk:
<chunk type> <length> <format> <ntrks> <division>
As described above, <chunk type> is the four ASCII characters 'MThd';
<length> is a 32-bit representation of the number 6 (high byte first).
The first word, format, specifies the overall organization of the file.
Only three values of format are specified:
0 the file contains a single multi-channel track
1 the file contains one or more simultaneous tracks (or MIDI
outputs) of a sequence
2 the file contains one or more sequentially independent
single-track patterns
The next word, ntrks, is the number of track chunks in the file. The
third word, division, is the division of a quarter-note represented by
the delta-times in the file. (If division is negative, it represents
the division of a second represented by the delta-times in the file, so
that the track can represent events occurring in actual time instead of
metrical time. It is represented in the following way: the upper byte
is one of the four values -24, -25, -29, or -30, corresponding to the
four standard SMPTE and MIDI time code formats, and represents the
number of frames per second. The second byte (stored positive) is the
resolution within a frame: typical values may be 4 (MIDI time code
resolution), 8, 10, 80 (bit resolution), or 100. This system allows
exact specification of time-code-based tracks, but also allows
millisecond-based tracks by specifying 25 frames/sec and a resolution of
40 units per frame.)
Format 0, that is, one multi-channel track, is the most interchangeable
representation of data. One application of MIDI files is a simple
single-track player in a program which needs to make synthesizers make
sounds, but which is primarily concerned with something else such as
mixers or sound effect boxes. It is very desirable to be able to
produce such a format, even if your program is track-based, in order to
work with these simple programs. On the other hand, perhaps someone
will write a format conversion from format 1 to format 0 which might be
so easy to use in some setting that it would save you the trouble of
putting it into your program.
Programs which support several simultaneous tracks should be able to
save and read data in format 1, a vertically one-dimensional form, that
is, as a collection of tracks. Programs which support several
independent patterns should be able to save and read data in format 2, a
horizontally one-dimensional form. Providing these minimum capabilities
will ensure maximum interchangeability.
MIDI files can express tempo and time signature, and they have been
chosen to do so for transferring tempo maps from one device to another.
For a format 0 file, the tempo will be scattered through the track and
the tempo map reader should ignore the intervening events; for a format
1 file, the tempo map must (starting in 0.04) be stored as the first
track. It is polite to a tempo map reader to offer your user the
ability to make a format 0 file with just the tempo, unless you can use
format 1.
All MIDI files should specify tempo and time signature. If they don't,
the time signature is assumed to be 4/4, and the tempo 120 beats per
minute. In format 0, these meta-events should occur at least at the
beginning of the single multi-channel track. In format 1, these meta-
events should be contained in the first track. In format 2, each of the
temporally independent patterns should contain at least initial time
signature and tempo information.
We may decide to define other format IDs to support other structures. A
program reading an unfamiliar format ID should return an error to the
user rather than trying to read further.
3 Meta-Events
A few meta-events are defined herein. It is not required for every
program to support every meta-event. Meta-events initially defined
include:
FF 00 02 ssss Sequence Number
This optional event, which must occur at the beginning of a track,
before any nonzero delta-times, and before any transmittable MIDI
events, specifies the number of a sequence. The number in this track
corresponds to the sequence number in the new Cue message discussed at
the summer 1987 MMA meeting. In a format 2 MIDI file, it is used to
identify each "pattern" so that a "song" sequence using the Cue message
to refer to the patterns. If the ID numbers are omitted, the sequences'
locations in order in the file are used as defaults. In a format 0 or 1
MIDI file, which only contain one sequence, this number should be
contained in the first (or only) track. If transfer of several
multitrack sequences is required, this must be done as a group of format
1 files, each with a different sequence number.
FF 01 len text Text Event
Any amount of text describing anything. It is a good idea to put a text
event right at the beginning of a track, with the name of the track, a
description of its intended orchestration, and any other information
which the user wants to put there. Text events may also occur at other
times in a track, to be used as lyrics, or descriptions of cue points.
The text in this event should be printable ASCII characters for maximum
interchange. However, other character codes using the high-order bit
may be used for interchange of files between different programs on the
same computer which supports an extended character set. Programs on a
computer which does not support non-ASCII characters should ignore those
characters.
(New for 0.06 ). Meta event types 01 through 0F are reserved for
various types of text events, each of which meets the specification of
text events(above) but is used for a different purpose:
FF 02 len text Copyright Notice
Contains a copyright notice as printable ASCII text. The notice should
contain the characters (C), the year of the copyright, and the owner of
the copyright. If several pieces of music are in the same MIDI file,
all of the copyright notices should be placed together in this event so
that it will be at the beginning of the file. This event should be the
first event in the first track chunk, at time 0.
FF 03 len text Sequence/Track Name
If in a format 0 track, or the first track in a format 1 file, the name
of the sequence. Otherwise, the name of the track.
FF 04 len text Instrument Name
A description of the type of instrumentation to be used in that track.
May be used with the MIDI Prefix meta-event to specify which MIDI
channel the description applies to, or the channel may be specified as
text in the event itself.
FF 05 len text Lyric
A lyric to be sung. Generally, each syllable will be a separate lyric
event which begins at the event's time.
FF 06 len text Marker
Normally in a format 0 track, or the first track in a format 1 file.
The name of that point in the sequence, such as a rehearsal letter or
section name ("First Verse", etc.).
FF 07 len text Cue Point
A description of something happening on a film or video screen or stage
at that point in the musical score ("Car crashes into house", "curtain
opens", "she slaps his face", etc.)
FF 2F 00 End of Track
This event is not optional. It is included so that an exact ending
point may be specified for the track, so that it has an exact length,
which is necessary for tracks which are looped or concatenated.
FF 51 03 tttttt Set Tempo, in microseconds per MIDI quarter-note
This event indicates a tempo change. Another way of putting
"microseconds per quarter-note" is "24ths of a microsecond per MIDI
clock". Representing tempos as time per beat instead of beat per time
allows absolutely exact long-term synchronization with a time-based sync
protocol such as SMPTE time code or MIDI time code. This amount of
accuracy provided by this tempo resolution allows a four-minute piece at
120 beats per minute to be accurate within 500 usec at the end of the
piece. Ideally, these events should only occur where MIDI clocks would
be located Q this convention is intended to guarantee, or at least
increase the likelihood, of compatibility with other synchronization
devices so that a time signature/tempo map stored in this format may
easily be transferred to another device.
FF 54 05 hr mn se fr ff SMPTE Offset (New in 0.06 - SMPTE Format
specification)
This event, if present, designates the SMPTE time at which the track
chunk is supposed to start. It should be present at the beginning of
the track, that is, before any nonzero delta-times, and before any
transmittable MIDI events. The hour must be encoded with the SMPTE
format, just as it is in MIDI Time Code. In a format 1 file, the SMPTE
Offset must be stored with the tempo map, and has no meaning in any of
the other tracks. The ff field contains fractional frames, in 100ths of
a frame, even in SMPTE-based tracks which specify a different frame
subdivision for delta-times.
FF 58 04 nn dd cc bb Time Signature
The time signature is expressed as four numbers. nn and dd represent
the numerator and denominator of the time signature as it would be
notated. The denominator is a negative power of two: 2 represents a
quarter-note, 3 represents an eighth-note, etc. The cc parameter
expresses the number of MIDI clocks in a metronome click. The bb
parameter expresses the number of notated 32nd-notes in a MIDI quarter-
note (24 MIDI Clocks). This was added because there are already
multiple programs which allow the user to specify that what MIDI thinks
of as a quarter-note (24 clocks) is to be notated as, or related to in
terms of, something else.
Therefore, the complete event for 6/8 time, where the metronome clicks
every three eighth-notes, but there are 24 clocks per quarter-note, 72
to the bar, would be (in hex):
FF 58 04 06 03 24 08
That is, 6/8 time (8 is 2 to the 3rd power, so this is 06 03), 32 MIDI
clocks per dotted-quarter (24 hex!), and eight notated 32nd-notes per
MIDI quarter note.
FF 59 02 sf mi Key Signature
sf = -7: 7 flats
sf = -1: 1 flat
sf = 0: key of C
sf = 1: 1 sharp
sf = 7: 7 sharps
mi = 0: major key
mi = 1: minor key
FF 7F len data Sequencer-Specific Meta-Event
Special requirements for particular sequencers may use this
event type: the first byte or bytes of data is a manufacturer ID.
However, as this is an interchange format, growth of the spec proper is
preferred to use of this event type. This type of event may be used by
a sequencer which elects to use this as its only file format;
sequencers with their established feature-specific formats should
probably stick to the standard features when using this format.
4 Program Fragments and Example MIDI Files
Here are some of the routines to read and write variable-length numbers
in MIDI Files. These routines are in C, and use getc and putc, which
read and write single 8-bit characters from/to the files infile and
outfile.
WriteVarLen (value)
register long value;
{
register long buffer;
buffer = value & 0x7f;
while ((value >>= 7) > 0)
{
buffer <<= 8;
buffer |= 0x80;
buffer += (value & 0x7f);
}
while (TRUE)
{
putc(buffer,outfile);
if (buffer & 0x80)
buffer >>= 8;
else
break;
}
}
doubleword ReadVarLen ()
{
register doubleword value;
register byte c;
if ((value = getc(infile)) & 0x80)
{
value &= 0x7f;
do
{
value = (value << 7) + ((c = getc(infile)) & 0x7f);
} while (c & 0x80);
}
return (value);
}
As an example, MIDI Files for the following excerpt are shown below.
First, a format 0 file is shown, with all information intermingled;
then, a format 1 file is shown with all data separated into four tracks:
one for tempo and time signature, and three for the notes. A resolution
of 96 "ticks" per quarter note is used. A time signature of 4/4 and a
tempo of 120, though implied, are explicitly stated.
The contents of the MIDI stream represented by this example are broken
down here:
Delta Time(decimal) Event Code (hex) Other Bytes (decimal)
Comment
0 FF 58 04 04 02 24 08 4 bytes: 4/4 time, 24 MIDI
clocks/click,
8 32nd notes/24 MIDI clocks
0 FF 51 03 500000 3 bytes: 500,000 5sec per quarter-note
0 C0 5 Ch. 1, Program Change 5
0 C0 5 Ch. 1, Program Change 5
0 C1 46 Ch. 2, Program Change 46
0 C2 70 Ch. 3, Program Change 70
0 92 48 96 Ch. 3 Note On C2, forte
0 92 60 96 Ch. 3 Note On C3, forte
96 91 67 64 Ch. 2 Note On G3, mezzo-forte
96 90 76 32 Ch. 1 Note On E4, piano
192 82 48 64 Ch. 3 Note Off C2, standard
0 82 60 64 Ch. 3 Note Off C3, standard
0 81 67 64 Ch. 2 Note Off G3, standard
0 80 76 64 Ch. 1 Note Off E4, standard
0 FF 2F 00 Track End
The entire format 0 MIDI file contents in hex follow. First, the header
chunk:
4D 54 68 64 MThd
00 00 00 06 chunk length
00 00 format 0
00 01 one track
00 60 96 per quarter-note
Then, the track chunk. Its header, followed by the events (notice that
running status is used in places):
4D 54 72 6B MTrk
00 00 00 3B chunk length (59)
Delta-time Event Comments
00 FF 58 04 04 02 18 08 time signature
00 FF 51 03 07 A1 20 tempo
00 C0 05
00 C1 2E
00 C2 46
00 92 30 60
00 3C 60 running status
60 91 43 40
60 90 4C 20
81 40 82 30 40 two-byte delta-time
00 3C 40 running status
00 81 43 40
00 80 4C 40
00 FF 2F 00 end of track
A format 1 representation of the file is slightly different. Its header
chunk:
4D 54 68 64 MThd
00 00 00 06 chunk length
00 01 format 1
00 04 four tracks
00 60 96 per quarter-note
First, the track chunk for the time signature/tempo track. Its header,
followed by the events:
4D 54 72 6B MTrk
00 00 00 14 chunk length (20)
Delta-time Event Comments
00 FF 58 04 04 02 18 08 time signature
00 FF 51 03 07 A1 20 tempo
83 00 FF 2F 00 end of track
Then, the track chunk for the first music track. The MIDI convention
for note on/off running status is used in this example:
4D 54 72 6B MTrk
00 00 00 10 chunk length (16)
Delta-time Event Comments
00 C0 05
81 40 90 4C 20
81 40 4C 00 Running status: note on, vel = 0
00 FF 2F 00 end of track
Then, the track chunk for the second music track:
4D 54 72 6B MTrk
00 00 00 0F chunk length (15)
Delta-time Event Comments
00 C1 2E
60 91 43 40
82 20 43 00 running status
00 FF 2F 00 end of track
Then, the track chunk for the third music track:
4D 54 72 6B MTrk
00 00 00 15 chunk length (21)
Delta-time Event Comments
00 C2 46
00 92 30 60
00 3C 60 running status
83 00 30 00 two-byte delta-time, running status
00 3C 00 running status
00 FF 2F 00 end of track
5 MIDI Transmission of MIDI Files
Since it is inconvenient to exchange disks between different computers,
and since many computers which will use this format will have a MIDI
interface anyway, MIDI seems like a perfect way to send these files from
one computer to another. And, while we're going through all the trouble
to make a way of sending MIDI Files, it would be nice if they could send
any files (like sampled sound files, text files, etc.)
Goals
The transmission protocol for MIDI files should be reasonably efficient,
should support fast transmission for computers which are capable of it,
and slower transmission for less powerful ones. It should not be
impossible to convert a MIDI File to or from an arbitrary internal
representation on the fly as it is transmitted, but, as long as it is
not too difficult, it is very desirable to use a generic method so that
any file type could be accommodated.
To make the protocol efficient, the MIDI transmission of these files
will take groups of seven 8-bit bytes and transmit them as eight 7-bit
MIDI data bytes. This is certainly in the spirit of the rest of this
format (keep it small, because it's not that hard to do). To
accommodate a wide range of transmission speeds, files will be
transmitted in packets with acknowledge -- this allows data to be stored
to disk as it is received. If the sender does not receive a response
from a reader in a certain amount of time, it can assume an open-loop
situation, and then just continue.
The last edition of MIDI Files contained a specialized protocol for
sending just MIDI Files. To meet a deadline, unfortunately I don't have
time right now to propose a new generalized protocol. This will be done
within the next couple of months. I would welcome any proposals anyone
else has, and would direct your attention to the proposal from Ralph
Muha of Kurzweil, available in a recent MMA bulletin, and also directly
from him.
--
Michael S. Czeiszperger | "The only good composer is a dead composer"
Systems Analyst | Snail: 2015 Neil Avenue (614)
The Ohio State University | Columbus, OH 43210 292-
ARPA:czei@accelerator.eng.ohio-state.edu PAN:CZEI 0161

View File

@@ -0,0 +1,601 @@
The USENET MIDI Primer
Bob McQueer
PURPOSE
It seems as though many people in the USENET community have an interest
in the Musical Instrument Digital Interface (MIDI), but for one reason
or another have only obtained word of mouth or fragmentary descriptions
of the specification. Basic questions such as "what's the baud rate?",
"is it EIA?" and the like seem to keep surfacing in about half a dozen
newsgroups. This article is an attempt to provide the basic data to
the readers of the net.
REFERENCE
The major written reference for this article is version 1.0 of the MIDI
specification, published by the International MIDI Association, copyright
1983. There exists an expanded document. This document, which I have not
seen, is simply an expansion of the 1.0 spec. to contain more explanatory
material, and fill in some areas of hazy explanation. There are no
radical departures from 1.0 in it. I have also heard of a "2.0" spec.,
but the IMA claims no such animal exists. In any event, backwards
compatibility with the information I am presenting here should be
maintained.
CONVENTIONS
I will give constants in C syntax, ie. 0x for hexadecimal. If I
refer to bits by number, I number them starting with 0 for the low
order (1's place) bit. The following notation:
>>
text
<<
will be used to delimit commentary which is not part of the "bare-
bones" specification. A sentence or paragraph marked with a question
mark in column 1 is a point I would kind of like to hear something
about myself.
OK, let's give it a shot.
PHYSICAL CONNECTOR SPECIFICATION
The standard connectors used for MIDI are 5 pin DIN. Separate sockets
are used for input and output, clearly marked on a given device. The
spec. gives 50 feet as the maximum cable length. Cables are to be
shielded twisted pair, with the shield connecting pin 2 at both ends.
The pair is pins 4 and 5, pins 1 and 3 being unconnected:
2
5 4
3 1
A device may also be equipped with a "MIDI-THRU" socket which is used
to pass the input of one device directly to output.
>>
I think this arrangement shows some of the original conception
of MIDI more as a way of allowing keyboardists to control
multiple boxes than an instrument to computer interface. The
"daisy-chain" arrangement probably has advantages for a performing
musician who wants to play "stacked" synthesizers for a desired
sound, and has to be able to set things up on the road.
<<
ELECTRICAL SPECIFICATION
Asynchronous serial interface. The baud rate is 31.25 Kbaud (+/- 1%).
There are 8 data bits, with 1 start bit and 1 stop bit, for 320 microseconds
per serial byte.
MIDI is current loop, 5 mA. Logic 0 is current ON. The specification
states that input is to be opto-isolated, and points out that Sharp
PC-900 and HP 6N138 optoisolators are satisfactory devices. Rise and
fall time for the optoisolator should be less than 2 microseconds.
The specification shows a little circuit diagram for the connections
to a UART. I am not going to reproduce it here. There's not much
to it - I think the important thing it shows is +5 volt connection
to pin 4 of the MIDI out with pin 5 going to the UART, through 220
ohm load resistors. It also shows that you're supposed to connect
to the "in" side of the UART through an optoisolator, and to the
MIDI-THRU on the UART side of the isolator.
>>
I'm not much of a hardware person, and don't really know what
I'm talking about in paragraphs like the three above. I DO
recognize that this is a "non-standard" specification, which
won't work over serial ports intended for anything else. People
who do know about such things seem to either have giggling
or gagging fits when they see it, depending on their dispos-
itions, saying things like "I haven't seen current loop since
the days of the old teletypes". I also know the fast 31.25
Kbaud pushes the edge for clocking commonly available UART's.
<<
DATA FORMAT
For standard MIDI messages, there is a clear concept that one device
is a "transmitter" or "master", and the other a "receiver" or "slave".
Messages take the form of opcode bytes, followed by data bytes.
Opcode bytes are commonly called "status" bytes, so we shall use
this term.
>>
very similar to handling a terminal via escape sequences. There
aren't ACK's or other handshaking mechanisms in the protocol.
<<
Status bytes are marked by bit 7 being 1. All data bytes must
contain a 0 in bit 7, and thus lie in the range 0 - 127.
MIDI has a logical channel concept. There are 16 logical channels,
encoded into bits 0 - 3 of the status bytes of messages for
which a channel number is significant. Since bit 7 is taken over
for marking the status byte, this leaves 3 opcode bits for message
types with a logical channel. 7 of the possible 8 opcodes are
used in this fashion, reserving the status bytes containing all
1's in the high nibble for "system" messages which don't have a
channel number. The low order nibble in these remaining messages
is really further opcode.
>>
If you are interested in receiving MIDI input, look over the
SYSTEM messages even if you wish to ignore them. Especially the
"system exclusive" and "real time" messages. The real time
messages may be legally inserted in the middle of other data,
and you should be aware of them, even though many devices won't
use them.
<<
VOICE MESSAGES
I will cover the message with channel numbers first. The opcode determines
the number of data bytes for a single message (see "running status byte",
below). The specification divides these into "voice" and "mode" messages.
The "mode" messages are for control of the logical channels, and the control
opcodes are piggybacked onto the data bytes for the "parameter" message. I
will go into this after describing the "voice messages". These messages are:
status byte meaning data bytes
0x80-0x8f note off 2 - 1 byte pitch, followed by 1 byte velocity
0x90-0x9f note on 2 - 1 byte pitch, followed by 1 byte velocity
0xa0-0xaf key pressure 2 - 1 byte pitch, 1 byte pressure (after-touch)
0xb0-0xbf parameter 2 - 1 byte parameter number, 1 byte setting
0xc0-0xcf program 1 byte program selected
0xd0-0xdf chan. pressure 1 byte channel pressure (after-touch)
0xe0-0xef pitch wheel 2 bytes giving a 14 bit value, least
significant 7 bits first
Many explanations are necessary here:
For all of these messages, a convention called the "running status
byte" may be used. If the transmitter wishes to send another message
of the same type on the same channel, thus the same status byte, the
status byte need not be resent.
Also, a "note on" message with a velocity of zero is to be synonymous
with a "note off". Combined with the previous feature, this is intended
to allow long strings of notes to be sent without repeating status bytes.
>>
From what I've seen, the "zero velocity note on" feature is very
heavily used. My six-trak sends these, even though it sends
status bytes on every note anyway. Roland stuff uses it.
<<
The pitch bytes of notes are simply number of half-steps, with
middle C = 60.
>>
On keyboard synthesizers, this usually simply means which
physical key corresponds, since the patch selection will
change the actual pitch range of the keyboard. Most keyboards
have one C key which is unmistakably in the middle of the
keyboard. This is probably note 60.
<<
The velocity bytes for velocity sensing keyboards are supposed
to represent a logarithmic scale. "advisable" in the words
of the spec. Non-velocity sensing devices are supposed to
send velocity 64.
The pitch wheel value is an absolute setting, 0 - 0x3FFF. The
1.0 spec. says that the increment is determined by the receiver.
0x2000 is to correspond to a centered pitch wheel (unmodified
notes)
>>
I believe standard scale steps are one of the things discussed
in expansions. The six-trak pitch wheel is up/down about a third.
I believe several makers have used this value, but I may be
wrong.
The "pressure" messages are for keyboards which sense the amount
of pressure placed on an already depressed key, as opposed to
velocity, which is how fast it is depressed or released.
? I'm not really certain of how "channel" pressure works. Yamaha
is one maker that uses these messages, I know.
<<
Now, about those parameter messages.
Instruments are so fundamentally different in the various controls
they have that no attempt was made to define a standard set, like
say 9 for "Filter Resonance". Instead, it was simply assumed that
these messages allow you to set "controller" dials, whose purposes
are left to the given device, except as noted below. The first data
bytes correspond to these "controllers" as follows:
data byte
0 - 31 continuous controllers 0 - 31, most significant byte
32 - 63 continuous controllers 0 - 31, least significant byte
64 - 95 on / off switches
96 - 121 unspecified, reserved for future.
122 - 127 the "channel mode" messages I alluded to above. See
below.
The second data byte contains the seven bit setting for the controller.
The switches have data byte 0 = OFF, 127 = ON with 1 - 126 undefined.
If a controller only needs seven bits of resolution, it is supposed to
use the most significant byte. If both are needed, the order is
specified as most significant followed by least significant. With a
14 bit controller, it is to be legal to send only the least significant
byte if the most significant doesn't need to be changed.
>>
This may of, course, wind up stretched a bit by a given manufacturer.
The Six-Trak, for instance, uses only single byte values (LEFT
justified within the 7 bits at that), and recognizes >32 parameters
<<
Controller number 1 IS standardized to be the modulation wheel.
? Are there any other standardizations which are being followed by most
manufacturers?
MODE MESSAGES
These are messages with status bytes 0xb0 through 0xbf, and leading data
bytes 122 - 127. In reality, these data bytes function as further
opcode data for a group of messages which control the combination of
voices and channels to be accepted by a receiver.
An important point is that there is an implicit "basic" channel over which
a given device is to receive these messages. The receiver is to ignore
mode messages over any other channels, no matter what mode it might be in.
The basic channel for a given device may be fixed or set in some manner
outside the scope of the MIDI standard.
The meaning of the values 122 through 127 is as follows:
data byte second data byte
122 local control 0 = local control off, 127 = on
123 all notes off 0
124 omni mode off 0
125 omni mode on 0
126 monophonic mode number of monophonic channels, or 0
for a number equal to receivers voices
127 polyphonic mode 0
124 - 127 also turn all notes off.
Local control refers to whether or not notes played on an instruments
keyboard play on the instrument or not. With local control off, the
host is still supposed to be able to read input data if desired, as
well as sending notes to the instrument. Very much like "local echo"
on a terminal, or "half duplex" vs. "full duplex".
The mode setting messages control what channels / how many voices the
receiver recognizes. The "basic channel" must be kept in mind. "Omni"
refers to the ability to receive voice messages on all channels. "Mono"
and "Poly" refer to whether multiple voices are allowed. The rub is
that the omni on/off state and the mono/poly state interact with each
other. We will go over each of the four possible settings, called "modes"
and given numbers in the specification:
mode 1 - Omni on / Poly - voice messages received on all channels and
assigned polyphonically. Basically, any notes it gets, it
plays, up to the number of voices it's capable of.
mode 2 - Omni on / Mono - monophonic instrument which will receive
notes to play in one voice on all channels.
mode 3 - Omni off / Poly - polyphonic instrument which will receive
voice messages on only the basic channel.
mode 4 - Omni off / Mono - A useful mode, but "mono" is a misnomer.
To operate in this mode a receiver is supposed to receive
one voice per channel. The number channels recognized will be
given by the second data byte, or the maximum number of possible
voices if this byte is zero. The set of channels thus defined
is a sequential set, starting with the basic channel.
The spec. states that a receiver may ignore any mode that it cannot
honor, or switch to an alternate - "usually" mode 1. Receivers are
supposed to default to mode 1 on power up. It is also stated that
power up conditions are supposed to place a receiver in a state where
it will only respond to note on / note off messages, requiring a
setting of some sort to enable the other message types.
>>
I think this shows the desire to "daisy-chain" devices for
performance from a single master again. We can set a series
of instruments to different basic channels, tie 'em together,
and let them pass through the stuff they're not supposed to
play to someone down the line.
This suffers greatly from lack of acknowledgement concerning
modes and usable channels by a receiver. You basically have
to know your device, what it can do, and what channels it can
do it on.
I think most makers have used the "system exclusive" message
(see below) to handle channels in a more sophisticated manner,
as well as changing "basic channel" and enabling receipt of
different message types under host control rather than by
adjustment on the device alone.
The "parameters" may also be usurped by a manufacturer for
mode control, since their purposes are undefined.
Another HUGE problem with the "daisy-chain" mental set of MIDI
is that most devices ALWAYS shovel whatever they play to their
MIDI outs, whether they got it from the keyboard or MIDI in.
This means that you have to cope with the instrument echoing
input back at you if you're trying to do an interactive session
with the synthesizer. There is DRASTIC need for some MIDI flag
which specifically means that only locally generated data is to
go to MIDI out. From device to device there are ways of coping
with this, none of them good.
<<
SYSTEM MESSAGES
The status bytes 0x80 - 0x8f do not have channel numbers in the
lower nibble. These bytes are used as follows:
byte purpose data bytes
0xf0 system exclusive variable length
0xf1 undefined
0xf2 song position 2 - 14 bit value, least significant byte
first
0xf3 song select 1 - song number
0xf4 undefined
0xf5 undefined
0xf6 tune request 0
0xf7 EOX (terminator) 0
The status bytes 0xf8 - 0xff are the so-called "real-time" messages.
I will discuss these after the accumulated notes concerning the
first bunch.
Song position / song select are for control of sequencers. The
song position is in beats, which are to be interpreted as every
6 MIDI clock pulses. These messages determine what is to be played
upon receipt of a "start" real-time message (see below).
The "tune request" is a command to analog synthesizers to tune their
oscillators.
The system exclusive message is intended for manufacturers to use
to insert any specific messages they want to which apply to their
own product. The following data bytes are all to be "data" bytes,
that is they are all to be in the range 0 - 127. The system exclusive
is to be terminated by the 0xf7 terminator byte. The first data byte
is also supposed to be a "manufacturer's id", assigned by a MIDI
standards committee. THE TERMINATOR BYTE IS OPTIONAL - a system
exclusive may also be "terminated" by the status byte of the next
message.
>>
Yamaha, in particular, caused problems by not sending terminator
bytes. As I understand it, the DX-7 sends a system exclusive
at something like 80 msec. intervals when it has nothing better
to do, just so you know it's still there, I guess. The messages
aren't explicitly terminated, so if you want to handle the
protocol (esp. in hardware), you should be aware that a DX-7
will leave you in "waiting for EOX" state a lot, and be sending
data even when it isn't doing anything. This is all word of
mouth, since I've never personally played with a DX-7.
<<
some MIDI ID's:
Sequential Circuits 1 Bon Tempi 0x20 Kawai 0x40
Big Briar 2 S.I.E.L. 0x21 Roland 0x41
Octave / Plateau 3 Korg 0x42
Moog 4 SyntheAxe 0x23 Yamaha 0x43
Passport Designs 5
Lexicon 6
PAIA 0x11
Simmons 0x12
Gentle Electric 0x13
Fairlight 0x14
>>
Note the USA / Europe / Japan grouping of codes. Also note
that Sequential Circuits snarfed id number 1 - Sequential
Circuits was one of the earliest participators in MIDI, some
people claim its originator.
Two large makers missing from the original lineup were Casio
and Oberheim. I know Oberheim is on the bandwagon now, and
Casio also, I believe. Oberheim had their own protocol previous
to MIDI, and when MIDI first came out they were reluctant to
? go along with it. I wonder what we'd be looking at if Oberheim
had pushed their ideas and made them the standard. From what I
understand they thought THEIRS was better, and kind of sulked
for a while until the market forced them to go MIDI.
? Nobody seems to care much about these ID numbers. I can only
imagine them becoming useful if additions to the standard message
set are placed into system exclusives, with the ID byte to let
you know what added protocol is being used. Are any groups of
manufacturers considering consolidating their efforts in a
standard extension set via system exclusives?
<<
REAL TIME MESSAGES.
This is the final group of status bytes, 0xf8 - 0xff. These bytes
are reserved for messages which are called "real-time" messages
because they are allowed to be sent ANYPLACE. This includes in
between data bytes of other messages. A receiver is supposed to
be able to receive and process (or ignore) these messages and
resume collection of the remaining data bytes for the message
which was in progress. Realtime messages do not affect the
"running status byte" which might be in effect.
? Do any devices REALLY insert these things in the middle of
other messages?
All of these messages have no data bytes following (or they could
get interrupted themselves, obviously). The messages:
0xf8 timing clock
0xf9 undefined
0xfa start
0xfb continue
0xfc stop
0xfd undefined
0xfe active sensing
0xff system reset
The timing clock message is to be sent at the rate of 24 clocks
per quarter note, and is used to sync. devices, especially drum
machines.
Start / continue / stop are for control of sequencers and drum
machines. The continue message causes a device to pick up at the
next clock mark.
>>
These things are also designed for performance, allowing control
of sequencers and drum machines from a "master" unit which
sends the messages down the line when its buttons are pushed.
I can't tell you much about the trials and tribulations of drum
machines. Other folks can, I am sure.
<<
The active sensing byte is to be sent every 300 ms. or more often,
if it is used. Its purpose is to implement a timeout mechanism
for a receiver to revert to a default state. A receiver is to
operate normally if it never gets one of these, activating the
timeout mechanism from the receipt of the first one.
>>
My impression is that active sensing is largely unused.
<<
The system reset initializes to power up conditions. The spec. says
that it should be used "sparingly" and in particular not sent
automatically on power up.
AND NOW, CLIMBING TO THE PULPIT ....
>> - from here on out.
There are many deficiencies with MIDI, but it IS a standard. As such,
it will have to be grappled with.
The electrical specification leaves me with only one question - WHY?
What was wanted was a serial interface, and a perfectly good RS232
specification was to be had. WHY wasn't it used? The baud rate is
too fast to simply convert into something you can feed directly to
your serial port via fairly dumb hardware, also. The "standard"
baud rate step you would have to use would be 38.4 Kbaud which very
few hardware interfaces accept. The other alternative is to buffer
messages and send them out a slower baud rate - in fact buffering
of characters by some kind of I/O processor is very helpful. Hence
units like the MPU-401, which does a lot of other stuff, too of
course.
The fast baud rate with MIDI was set for two reasons I believe:
1) to allow daisy-chaining of a few devices with no noticeable
end to end lag.
2) to allow chords to be played by just sending all the notes down
the pipe, the baud rate being fast enough that they will
sound simultaneous.
It doesn't exactly work - I've heard gripes concerning end to end lag
on three instrument chains. And consider chords - at two bytes (running
status byte being used) per note, there will be a ten character lag
between the trailing edges of the first and last notes of a six note
chord. That's 3.2 ms., assuming no "dead air" between characters. It's
still pretty fast, but on large chords with voices possessing distinctive
attack characteristics, you may hear separate note beginnings.
I think MIDI could have used some means of packetizing chords, or having
transaction markers. If a "chord" message were specified, you could easily
break even on byte count with a few notes, given that we assume all notes
of a chord at the same velocity. Transaction markers might be useful in
any case, although I don't know if it would be worth taking over the
remaining system message space for them. I would say yes. I would
see having "start" and "end" transaction bytes. On receipt of a "start"
a receiver buffers up but does not act on messages until receipt of the
"end" byte. You could then do chords by sending the notes ahead of time,
and precisely timing the "end" marker. Of course, the job of the hardware
in the receiver has been complicated considerably.
The protocol is VERY keyboard oriented - take a look at the use of TWO
of the opcodes in the limited opcode space for "pressure" messages,
and the inability to specify semitones or glissando effects except
through the pitch wheel (which took up yet ANOTHER of the opcodes).
All keyboards I know of modify ALL playing notes when they receive
pitch wheel data. Also, you have to use a continuous stream of
pitch wheel messages to effect a slide, the pitch wheel step isn't
standardized, and on a slide of a large number of tones you will
overrun the range of the wheel.
? Some of these problems would be addressed by a device which allowed
its pitch wheel to have selective control - say modifying only
the notes playing on the channel the pitch wheel message is
received in, for instance. The thing for a guitar synthesizer
to do, then, would be to use mode 4, one channel per string, and
bends would only affect the one note. You could play a chord
on a voice with a lot of release, then bend a note and not have
the entire still sounding chord bend. Any such devices?
I think some of the deficiencies in MIDI might be addressed by
different communities of interest developing a standard set of
system exclusives which answer the problem. One perfect area
for this, I think, is a standard set for representation of "non-
keyboard / drum machine" instruments which have continuous pitch
capabilities. Like a pedal steel, for instance. Or non-western
intervals. Like a sitar.
There is a crying need to do SOMETHING about the "loopback" problem.
I would even vote for usurping a few more bytes in the mode messages
to allow you to TURN OFF input echo by the receiver. With the
local control message, you could then at least deal with something
that would act precisely like a half or full duplex terminal.
Several patchwork solutions exist to this problem, but there OUGHT
to be a standard way of doing it within the protocol. Another
thought is to allow data bytes of other than 0 or 127 to control
echo on the existing local control message.
The lack of acknowledgement is a problem. Another candidate for a
standard system exclusive set would be a series of messages for
mode setting with acknowledgement. This set could then also
take care of the loopback problem.
The complete lack of ability to specify standardized waveforms is
probably another source of intense disappointment to many readers.
Trouble is, the standard lingo used by the synthesizer industry and
most working musicians is something which hails back to the first
days of synthesizer design, deals with envelope generators and
filters and VCO / LFO hardware parameters, and is very damn difficult
to relate to Fourier series expressing the harmonic content or any other
abstractions some people interested in doing computer composition
would like. The parameter set used by the average synthesizer manufacturer
isn't anyplace close to orthogonal in any sense, and is bound to vary
wildly in comparison to anybody elses. There are essentially no
abstractions made by most of the industry from underlying hardware
parameters. What standardization exists reflects only the similarity
in hardware. This is one quagmire that we have a long way to go to
get out of, I think. It might be possible, eventually, to come up
with translation tables describing the best way to approximate a
desired sound on a given device in terms of its parameter set, but
the difficulties are enormous. MIDI has chosen to punt on this one,
folks.
Well, that's about it. Good luck with talking to your synthesizer.
Bob McQueer
22 Bcy, 3151
All rites reversed. Reprint what you like.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,205 @@
From : Ryan Nathan Thompson
Subj : SB autodetect
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Procedure SndWrite(Register, Data : Byte); assembler;
Asm
mov al, register
mov dx, SndPort { read register }
out dx, al
in al, dx; in al, dx; { add a few more for the needed delay time }
mov al, data
inc dx { write register }
out dx, al
dec dx
in al, dx; in al, dx; { add more for a proper delay }
End;
Function SndRead : Byte; assembler;
Asm
mov dx, SndPort
in al, dx
End;
Procedure WriteDSP(Command : Byte); assembler;
Asm
mov cx, $ff
mov dx, DSPWrite
@Wait1:
in al, dx
or al, al
jns @Wait2
loop @Wait1
@Wait2:
mov al, Command
out dx, al
End;
Procedure CheckIRQ; assembler;
Var
Old2, Old3, Old5, Old7, Old9, Old10, Old11, Old12 : Pointer;
Asm
@ScanIRQ:
cli
in al, $21 { save the IMR. PIC1 }
mov bl, al
in al, $a1 { save the IMR. PIC2 }
mov bh, al
mov al, $ff { disable all the IRQs. }
out $21, al { PIC1 }
out $a1, al { PIC2 }
xor ax, ax { trap the IRQs 2,3,5,7,10,11,12. }
mov es, ax
@SaveIrqs:
mov ax, [es:$28] { irq2 } mov dx, [es:$2A]
push ax push dx
mov ax, [es:$2C] { irq3 } mov dx, [es:$2E]
push ax push dx
mov ax, [es:$34] { irq5 } mov dx, [es:$36]
push ax push dx
mov ax, [es:$3C] { irq7 } mov dx, [es:$3E]
push ax push dx
mov ax, [es:$134] { irq9 } mov dx, [es:$136]
push ax push dx
mov ax, [es:$138] { irq10 } mov dx, [es:$13a]
push ax push dx
mov ax, [es:$13c] { irq11 } mov dx, [es:$13e]
push ax push dx
mov ax, [es:$140] { irq12 } mov dx, [es:$142]
push ax push dx
@SetIrqs:
mov ax, offset @TrapIrq2 { irq2 }
mov [es:$28], ax mov [es:$2A], cs
mov ax, offset @TrapIrq3 { irq3 }
mov [es:$2C], ax mov [es:$2E], cs
mov ax, offset @TrapIrq5 { irq5 }
mov [es:$34], ax mov [es:$36], cs
mov ax, offset @TrapIrq7 { irq7 }
mov [es:$3C], ax mov [es:$3E], cs
mov ax, offset @TrapIrq9 { irq9 }
mov [es:$1c4], ax mov [es:$1c6], cs
mov ax, offset @TrapIrq10 { irq10 }
mov [es:$1c8], ax mov [es:$1ca], cs
mov ax, offset @TrapIrq11 { irq11 }
mov [es:$1cc], ax mov [es:$1ce], cs
mov ax, offset @TrapIrq12 { irq12 }
mov [es:$140], ax mov [es:$142], cs
@EnableIrqs:
mov al, bl
and al, $53 { enable IRQs 2/Cascade,3,5,7. }
out $21, al { PIC1 }
mov al, bh
and al, $e1 { enable IRQs 9,10,11,12. }
out $a1, al { PIC2 }
sti
mov [SndIrq], 0 { clear the IRQ level. }
mov dx, [DSPWrite] { Tell the SB to generate a IRQ! }
@WaitSb:
in al, dx
or al, al
js @WaitSb
mov al, $F2
out dx, al
xor cx, cx { wait until IRQ level }
@WaitIRQ:
cmp [SndIrq], 0 { is changed or timeout. }
jne @IrqOk
loop @WaitIRQ
@IrqOk:
mov al, bl { restore IMR. }
out $21, al { PIC1 }
mov al, bh
out $a1, al { PIC2 }
cli { restore IRQ vectors. }
xor ax, ax
mov es, ax { point to vector table }
pop dx { irq12 } pop ax
mov [es:$140], ax mov [es:$142], dx
pop dx { irq11 } pop ax
mov [es:$1cc], ax mov [es:$1ce], dx
pop dx { irq10 } pop ax
mov [es:$1c8], ax mov [es:$1ca], dx
pop dx { irq9 } pop ax
mov [es:$1c6], ax mov [es:$1c4], dx
pop dx { irq7 } pop ax
mov [es:$3C], ax mov [es:$3E], dx
pop dx { irq5 } pop ax
mov [es:$34], ax mov [es:$36], dx
pop dx { irq3 } pop ax
mov [es:$2C], ax mov [es:$2E], dx
pop dx { irq2 } pop ax
mov [es:$28], ax mov [es:$2A], dx
cli
jmp @Done { Exit test }
@TrapIrq2:
push ax mov al, 2 jmp @TrapIrq
@TrapIrq3:
push ax mov al, 3 jmp @TrapIrq
@TrapIrq5:
push ax mov al, 5 jmp @TrapIrq
@TrapIrq7:
push ax mov al, 7 jmp @TrapIrq
@TrapIrq9:
push ax mov al, 9 jmp @TrapIrq
@TrapIrq10:
push ax mov al, 10 jmp @TrapIrq
@TrapIrq11:
push ax mov al, 11 jmp @TrapIrq
@TrapIrq12:
push ax mov al, 12
@TrapIrq:
push dx { General IRQ trapper }
push ds { used for IRQ autodetect. }
mov dx, seg SndIRQ
mov ds, dx
mov [SndIRQ], al { save IRQ level. }
mov dx, [DSPStatus]
in al, dx { SB acknowledge. }
mov al, $20
out $20, al { Hardware acknowledge PIC1 }
out $a0, al { Hardware acknowledge PIC2 }
pop ds pop dx pop ax
iret { bye! }
@Done:
End;
Function CheckSound : Boolean;
Var
Ver : Byte;
Function CheckPort(TestPort : Word) : Boolean;
Begin
SndPort:= TestPort;
if Port[SndPort] < $ff then begin
SndWrite(4, $60); SndWrite(4, $80); SndWrite(2, $ff);
If SndRead and $e0 = 0 then begin
SndWrite(4, $21);
if SndRead and $e0 = $c0 then CheckPort:= true
else CheckPort:= false;
SndWrite(4, $60); SndWrite(4, 0); DSPStatus:= SndPort + $e;
DSPRead:= SndPort + $a; DSPWrite:= SndPort + $c;
end
else CheckPort:= false;
end;
End;
Begin
SndCard:= 'None detected'; If CheckPort($388) then begin
SndCard:= 'AdLib'; If CheckPort($220) or CheckPort($240) or
CheckPort($260) or CheckPort($280) then begin
Port[DSPWrite]:= $e1; Delay(10); Ver:= Port[DSPRead];
Case Ver of
1, 2: SndCard:= 'SoundBlaster v';
3: SndCard:= 'SB Pro v';
4: SndCard:= 'SB16 v';
5: SndCard:= 'AWE32 v';
else SndCard:= 'SB-compatible v';
End; Delay(10);
SndCard:= SndCard + Stringof(Ver) + '.' + Stringof(Port[DSPRead]);
CheckIRQ;
end;
end
else SndPort:= 0;
End;
--- Renegade v10-05 Exp
* Origin: The BBS at Pooh Corner 707-445-0500/0599 14.4/28.8 (1:125/47)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,388 @@
/-------------------------------------\
| Programming the SoundBlaster 16 DSP |
| Written by Ethan Brodsky |
| Version 2.3 |
\-------------------------------------/
/----------------------------------------------------------------------------
| Introduction |
\--------------/
The Sound Blaster 16 is capable of both FM and digitized sounds. Digitized
sound capibilities range from 8-bit mono 5000 HZ sound all the way up to
16-bit stereo sound at 44khz. This FAQ documents programming the SB16 DSP
CT1341 chip for recording and playback of digitized audio. Prior knowledge
on programming earlier Sound Blaster sound cards is necessary.
/----------------------------------------------------------------------------
| The Sound Blaster 16 DSP I/O Ports |
\------------------------------------/
The SB16's DSP chip is programming using several I/O ports at a base I/O
address determined by jumper settings. On the SB16, there are 16 I/O ports
which are used for FM synthesized music, mixer settings, DSP programming and
CD-ROM access. Five of these ports are used in programming the DSP. They
are listed below.
2x6h - DSP Reset
2xAh - DSP Read
2xCh - DSP Write (Command/Data), DSP write-buffer status (Bit 7)
2xEh - DSP Read-buffer status (Bit 7), DSP interrupt acknowledge
2xFh - DSP 16-bit interrupt acknowledge
/----------------------------------------------------------------------------
| Resetting the DSP |
\-------------------/
You have to reset the DSP before you can program it. The DSP can be reset
using the following procedure:
1) Write a 1 to the reset port (2x6)
2) Wait for 3 microseconds
3) Write a 0 to the reset port (2x6)
4) Poll the read-buffer status port (2xE) until bit 7 is set
5) Poll the read data port (2xA) until you receive an AA
The DSP usually takes about 100 microseconds to initialized itself. After
this period of time, if the return value is not AA or there is no data at
all, then the SB card may not be installed or an incorrect I/O address is
being used.
/----------------------------------------------------------------------------
| Writing to the DSP |
\--------------------/
To write a byte to the SB16, the following procedure should be used:
1) Read the write-buffer status port (2xC) until bit 7 is cleared
2) Write the value to the write port (2xC)
/----------------------------------------------------------------------------
| Reading the DSP |
\-----------------/
To read a byte from the SB16, the following procedure should be used:
1) Read the read-buffer status port (2xE) until bit 7 is set
2) Read the value from the read port (2xA)
/----------------------------------------------------------------------------
| Programming the DMA Controller |
\--------------------------------/
The DMA (Direct Memory Access) controller controls data transfers between
I/O devices and memory without using the CPU. An Intel 8237 DMAC integrated
circut is used to control this. An IBM compatible computer has two DMA
controllers, one for 8-bit transfers and one for 16-bit transfers. The DMA
controller, coupled with an external page register, is capable of transfering
blocks of up 64k to the SB16. Here is information on I/O ports and register
settings necessary for sound card I/O:
I/O port addresses for the DMA Address and Count Registers
/----------------------------------------------\
| Controller | I/O address | Function |
|------------+-------------+-------------------|
| DMA 1 | 00 | Channel 0 address |
| 8-bit | 01 | Channel 0 count |
| Slave | 02 | Channel 1 address |
| | 03 | Channel 1 count |
| | 04 | Channel 2 address |
| | 05 | Channel 2 count |
| | 06 | Channel 3 address |
| | 07 | Channel 3 count |
|------------+-------------+-------------------|
| DMA 2 | C0 | Channel 4 address |
| 16-bit | C2 | Channel 4 count |
| Master | C4 | Channel 5 address |
| | C6 | Channel 5 count |
| | C8 | Channel 6 address |
| | CA | Channel 6 count |
| | CC | Channel 7 address |
| | CE | Channel 7 count |
\----------------------------------------------/
I/O port addresses for the control registers
/--------------------------------------------------------\
| Address | Operation | Function |
| DMAC1 DMAC2 | | |
|-------------+-----------+------------------------------|
| 0A D4 | Write | Write single mask register |
| 0B D6 | Write | Write mode register |
| 0C D8 | Write | Clear byte pointer flip-flop |
\--------------------------------------------------------/
I/O port addresses for lower page registers
/--------------------------------------\
| Address | Function |
|---------+----------------------------|
| 81 | 8-bit DMA channel 2 page |
| 82 | 8-bit DMA channel 3 page |
| 83 | 8-bit DMA channel 1 page |
| 87 | 8-bit DMA channel 0 page |
| 89 | 16-bit DMA channel 6 page |
| 8A | 16-bit DMA channel 7 page |
| 8B | 16-bit DMA channel 5 page |
\--------------------------------------/
Mode register bit assignments
-----------------------------------------------
| Bit/Value | Function |
|-----------+---------------------------------|
| Bits 7:6 | Mode selection bits |
| 00 | Demand mode selected |
| 01 | Single mode selected |
| 10 | Block mode selected |
| 11 | Cascade mode selected |
|-----------+---------------------------------|
| Bit 5 | Address increment/decrement bit |
| 1 | Address decrement selected |
| 0 | Address increment selected |
|-----------+---------------------------------|
| Bit 4 | Auto-initialization enable bit |
| 1 | Auto-initialized DMA selected |
| 0 | Single-cycle DMA selected |
|-----------+---------------------------------|
| Bits 3:2 | Transfer bits |
| 00 | Verify transfer |
| 01 | Write transfer (To memory) |
| 10 | Read transfer (From memory) |
| 11 | Illegal |
| ** | Ignored if bits 7:6 = 11 |
|-----------+---------------------------------|
| Bits 1:0 | Channel selection bits |
| 00 | Select channel 0 (4) |
| 01 | Select channel 1 (5) |
| 10 | Select channel 2 (6) |
| 11 | Select channel 3 (7) |
\---------------------------------------------/
Write single mask bit assignments
/----------------------------------------------\
| Bit/Value | Function |
|-----------+----------------------------------|
| Bits 7:3 | Unused (Set to 0) |
|-----------+----------------------------------|
| Bit 2 | Set/clear mask bit |
| 1 | Set mask bit (Disable channel) |
| 0 | Clear mask bit (Enable channel) |
|-----------+----------------------------------|
| Bits 1:0 | Channel selection bits |
| 00 | Select channel 0 (4) |
| 01 | Select channel 1 (5) |
| 10 | Select channel 2 (6) |
| 11 | Select channel 3 (7) |
\----------------------------------------------/
DMAC2 is used for 16-bit I/O and DMAC1 is used for 8-bit I/O. The procedure
for starting a transfer is complicated, so I'll list the steps for starting
the type of DMA transfers used for sound I/O:
1) Calculate the absolute linear address of your buffer
LinearAddr := Seg(Ptr^)*16 - Ofs(Ptr^));
2) Disable the sound card DMA channel by setting the appropriate mask bit
Port[MaskPort] := 1 - (Channel mod 4);
3) Clear the byte pointer flip-flop
Port[ClrBytePtr] := AnyValue;
4) Write the DMA mode for the transfer
The mode selection bits should be set to 00 for demand mode. The
address inc/dec bit should be set to 0 for address increment. The
auto-initialization bit should be set appropriately. I will discuss
auto-initialized DMA later. The transfer bits should be set to 10
for playback and 01 for recording. The channel select should be
set to the sound card DMA channel. Be aware that "read" means a read
from memory (Write to sound card) and that "write" means a write to
system memory (Read from sound card)
Port[ModePort] := Mode - (Channel mod 4);
Some often used modes are:
48h-Channel - Single-cycle playback
58h-Channel - Auto-initialized playback
44h-Channel - Single-cycle recording
54h-Channel - Auto-initialized recording
5) Write the offset of the buffer, low byte followed by high byte. For
sixteen bit data, the offset should be in words from the start of a
128kbyte page. The easiest method for computing 16-bit parameters is
to divide the linear address by two before calculating offset.
if SixteenBit
then
begin
BufOffset := (LinearAddr div 2) mod 65536;
Port[BaseAddrPort] := Lo(BufOffset);
Port[BaseAddrPort] := Hi(BufOffset);
end
else
begin
BufOffset := LinearAddr mod 65536;
Port[BaseAddrPort] := Lo(BufOffset);
Port[BaseAddrPort] := Hi(BufOffset);
end;
6) Write the transfer length, low byte followed by high byte. For an
8-bit transfer, write the number of bytes-1. For a 16-bit transfer,
write the number of words-1.
Port[CountPort] := Lo(TransferLength-1);
Port[CountPort] := Hi(TransferLength-1);
7) Write the buffer page to the DMA page register.
Port[PagePort] := LinearAddr div 65536;
8) Enable the sound card DMA channel by clearing the appropriate mask bit
Port[MaskPort] := DMAChannel mod 4;
/----------------------------------------------------------------------------
| Setting the sampling rate |
\---------------------------/
Unlike earlier Sound Blasters, the SB16 is programmed with actual sampling
rates instead of time constants. On the SB16, the sampling rate is set
using DSP commands 41h and 42h. Command 41h is used for output and 42h is
used for input. I have heard that on the SB16, both these command currently
do the same thing, but I would recommend using the individual commands to
guarantee compatibility with future sound cards. The procedure for setting
the sampling rate is:
1) Write the command (41h for output rate, 42h for input rate)
2) Write the high byte of the sampling rate (56h for 22050 hz)
3) Write the low byte of the sampling rate (22h for 22050 hz)
/----------------------------------------------------------------------------
| Digitized sound I/O |
\---------------------/
To record or play back sound, you should use the following sequence:
1) Allocate a buffer that does not cross a 64k physical page boundary
2) Install an interrupt service routine
3) Program the DMA controller for background transfer
4) Set the sampling rate
5) Write the I/O command to the DSP
6) Write the I/O transfer mode to the DSP
7) Write the block size to the DSP (Low byte/High byte)
Upon interrupt when using single-cycle DMA:
1) Program DMA controller for next block
2) Program DSP for next block
3) Copy next block if double-buffering
4) Acknowledge the interrupt with the SB by reading from port 2xE for
8-bit sound or port 2xF for 16-bit sound.
5) Acknowledge the end of interrupt with the PIC by writing 20h to port
20h. If the sound card is on IRQ8-15, you must also write 20h to A0h.
/----------------------------------------------------------------------------
| DSP commands |
\--------------/
D0 - Pause 8-bit DMA mode digitized sound I/O initiated by command Cxh.
Applicable to both single-cycle and auto-initialized DMA I/O.
D4 - Continue 8-bit DMA mode digitized sound I/O paused using command D0.
Applicable to both single-cycle and auto-initialzied DMA I/O.
D5 - Pause 16-bit DMA mode digitized sound I/O initiated by command Bxh.
Applicable to both single-cycle and auto-initialized DMA I/O.
D6 - Continue 16-bit DMA mode digitized sound I/O paused using command D5
Applicable to both single-cycle and auto-initialized DMA I/O.
D9 - Exit 16-bit auto-initialized DMA mode digitized sound I/O after the
end of the current block.
DA - Exit 8-bit auto-initialized DMA mode digitized sound I/O after the
end of the current block.
E1 - Get DSP version number. After sending this command, read back two
bytes form the DSP. The first byte is the major version number and
the second byte is the minor version number. A SB16 should have a
DSP version of 4.00 or greater. Check this before using an SB16
specific commands.
Bx - Program 16-bit DMA mode digitized sound I/O
Command sequence: Command, Mode, Lo(Length-1), Hi(Length-1)
Command:
/-----------------------------------------------\
| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|----+----+----+----+-------+------+-------+----|
| 1 | 0 | 1 | 1 | A/D | A/I | FIFO | 0 |
\-------------------+-------+------+-------+----/
| 0=D/A | 0=SC | 0=off |
| 1=A/D | 1=AI | 1=on |
\----------------------/
Mode:
/-----------------------------------------------------\
| D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|----+----+----------+------------+----+----+----+----|
| 0 | 0 | Stereo | Signed | 0 | 0 | 0 | 0 |
\--------------------+--------------------------------/
| 0=Mono | 0=unsigned |
| 1=Stereo | 1=signed |
\-----------------------/
Cx - Program 8-bit DMA mode digitized sound I/O
Same procedure as 16-bit sound I/O using command Bx
/----------------------------------------------------------------------------
| Auto-initialized DMA |
\----------------------/
When single-cycle DMA is used, sound output stops at the end of each block.
The interrupt handler can start another transfer, but there will be a break
in output. This causes a click between each block, reducing sound quality.
When auto-initialized DMA is used, sound output loops around at the end of
the buffer. The DMA controller keeps transfering the same block of memory
that the DMA transfer was initiated with. When the end of the buffer is
reached, it will start sending the buffer again by auto-initializing the
current offset and count registers with the values stored in the base offset
and count registers. The usual method for achieving click-less output is to
allocate a buffer and divide it into two blocks. Program the DMA controller
with the length of the whole buffer, but program the SB16 with the length of
a block. (Half of the buffer) An interrupt occurs for each sound card block,
so two interrupts will occur each time the buffer is played, once at the
midpoint (Start of the second block) and once at the end (In effect, the
start of the first block) The interrupt handler should copy data into the
block that was just finished so that the data is ready when it is needed for
output. The programming procedure for an auto-initialized DMA transfer is
identical to the procedure for a single-cycle DMA transfer, except that bit
4 of the DMA mode register and bit 3 of the DSP command are set.
Upon interrupt when using auto-initialized DMA:
1) Copy next chunk into output buffer block that just finished
4) Acknowledge the interrupt with the SB by reading from port 2xE for
8-bit sound or port 2xF for 16-bit sound.
5) Acknowledge the end of interrupt with the PIC by writing 20h to port
20h. If the sound card is on IRQ8-15, you must also write 20h to A0h.
To stop sound immediately:
8-bit - Write DSP command D0h (Pause 8-bit DMA mode digitized sound I/O)
16-bit - Write DSP command D5h (Pause 16-bit DMA mode digitized sound I/O)
(Stops sound immediately, without an interrupt)
To stop the sound at the end of the currently block:
8-bit - Write DSP command DAh (Stop 8-bit auto-init DMA sound I/O)
16-bit - Write DSP command D9h (Stop 16-bit auto-init DMA sound I/O)
(These two commands will stop the sound at the end of the current
block. If your program is not prepared for an interrupt after output
is finished, it may cause problems)
You can also end auto-initialized mode by reprogramming the DSP for
single-cycle mode. The card then switches from A/I mode to S/C mode after
the next interrupt. It will then contiue to play or record for the length
specified, generate an interrupt and stop. This will allow you to stop
output exactly at the end of the data, without requiring the remainder of
the DMA buffer to be filled with silence. This technique may or may not
be useful to you. I would recommend using the pause commands documented
in in the immediate stop section unless another method is more suited to
your purpose.
/----------------------------------------------------------------------------
| References |
\------------/
Title: Developer Kit for the Sound Blaster Series, Second Edition.
Publishers: Creative Technology Ltd.
Title: Intel 486 Microcomputer Model 401 Board Technical Ref. Manual
Publisher: Intel Corporation
Order-number: 504366-002
Title: 8237A High Performance Programmable DMA Controller specs
Publisher: Intel Corporation
Order-number: 231466-005
Title: 8259A Programmable Interrupt Controller specs
Publisher: Intel Corporation
Order-number: 231468-003

View File

@@ -0,0 +1,374 @@
WAIT_TIME EQU 000FFh
DSP_INTRQ_CMD EQU 000F2h
DATA SEGMENT WORD PUBLIC
EXTRN SBInt : WORD;
EXTRN SBIrq : WORD;
ORG_INT2_ADDX DD 0;
ORG_INT3_ADDX DD 0;
ORG_INT5_ADDX DD 0;
ORG_INT7_ADDX DD 0;
DATA ENDS
CODE SEGMENT WORD PUBLIC
ASSUME CS:CODE,DS:DATA
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;
; ResetDSP - reset the DSP
;
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ResetDSP PROC
MOV DX,SBInt
ADD DL,6 ; DX = DSP reset port 2x6h
MOV AL,1
OUT DX,AL ; write 1, then wait 3 micro-seconds
IN AL,DX ; read value from DSP
RDSP05:
INC AL
JNZ RDSP05 ; wait until AL = 0
OUT DX,AL ; write 0
MOV CL,20H ; set reset timeout value
RDSP10:
CALL ReadDSPTime ; read from DSP
CMP AL,0AAH ; if byte is 0AAh then
JE RDSP20 ; DSP is reset, exit
LOOP RDSP10 ; not reset, try again
MOV AX,2 ; set I/O failure error
JMP SHORT RDSP90 ; exit;
RDSP20:
XOR AX,AX ; clear AX, no error
RDSP90:
OR AX,AX ; set flags for return
RET
ResetDSP ENDP
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;
; ReadDSPTime - read from DSP with timeout
;
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ReadDSPTime PROC
PUSH CX
PUSH DX
MOV DX,SBInt
ADD DL,0EH ; DX = DSP data available port 2xEh
MOV CX,WAIT_TIME ; load timeout value into CX
RDT10:
IN AL,DX ; check to see if DSP is ready
OR AL,AL
JS RDT20 ; if sign set, then DSP read ready
LOOP RDT10 ; not ready, keep waiting
STC ; set error, DSP read timeout
JMP SHORT RDT90 ; exit
RDT20:
SUB DL,4 ; DX = DSP read data port 2xAh
IN AL,DX ; read byte from DSP
CLC ; clear error
RDT90:
POP DX
POP CX
RET
ReadDSPTime ENDP
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;
; CheckSBInt - detect DMA interrupt
;
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
PUBLIC CheckSBInt
CheckSBInt PROC FAR
push bp
mov bp,sp
MOV AL,2 ; setup end of DMA
MOV DX,OFFSET DUMMY_DMA_INT2 ; interrupts for all
MOV BX,OFFSET DATA:ORG_INT2_ADDX ; possible IRQs
CALL SetupInterrupt ; (2, 3, 5, and 7)
MOV AL,3
MOV DX,OFFSET DUMMY_DMA_INT3
MOV BX,OFFSET DATA:ORG_INT3_ADDX
CALL SetupInterrupt
MOV AL,5
MOV DX,OFFSET DUMMY_DMA_INT5
MOV BX,OFFSET DATA:ORG_INT5_ADDX
CALL SetupInterrupt
MOV AL,7
MOV DX,OFFSET DUMMY_DMA_INT7
MOV BX,OFFSET DATA:ORG_INT7_ADDX
CALL SetupInterrupt
MOV SBIrq,0 ; reset current IRQ
MOV DX,SBInt
ADD DX,0CH ; DX = DSP write port 2xCh
MOV AL,DSP_INTRQ_CMD ; AL = interrupt request command
CALL WriteDSP ; write command to DSP
XOR AX,AX ; assume success
MOV CX,WAIT_TIME ; load timeout value into CX
CLD
VI10:
CMP SBIrq,0 ; see if interrupt has been changed
JNE VI90 ; if so, continue
LOOP VI10 ; if not, keep waiting
MOV AX,0FFh ; set DMA failure error
VI90:
PUSH AX ; save result variable
MOV AL,2 ; restore end of DMA
MOV BX,OFFSET DATA:ORG_INT2_ADDX ; interrupts
CALL RestoreInterrupt
MOV AL,3
MOV BX,OFFSET DATA:ORG_INT3_ADDX
CALL RestoreInterrupt
MOV AL,5
MOV BX,OFFSET DATA:ORG_INT5_ADDX
CALL RestoreInterrupt
MOV AL,7
MOV BX,OFFSET DATA:ORG_INT7_ADDX
CALL RestoreInterrupt
POP AX ; restore result
OR AX,AX
mov sp,bp
pop bp
RET
CheckSBInt ENDP
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;
; WriteDSP
;
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
WriteDSP PROC
PUSH CX
MOV AH,AL ; save value in AL for later
MOV CX,WAIT_TIME
WD10:
IN AL,DX ; check to see if DSP is ready
OR AL,AL
JNS WD20 ; if sign set, DSP not write ready
LOOP WD10
WD20:
MOV AL,AH ; restore AL
OUT DX,AL ; send byte to DSP
POP CX
RET
WriteDSP ENDP
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;
; SetupInterrupt
;
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
SetupInterrupt PROC
PUSH BX
PUSH CX
PUSH DX
CLI
MOV CL,AL ; preserve interrupt number for use
ADD AL,8 ; calculate interrupt vector addx
CBW
SHL AL,1
SHL AL,1
MOV DI,AX
PUSH ES ; setup and preserve interrupt
XOR AX,AX
MOV ES,AX
MOV AX,ES:[DI]
MOV [BX],AX
MOV ES:[DI],DX
MOV AX,ES:[DI+2]
MOV [BX+2],AX
MOV ES:[DI+2],CS
POP ES
MOV AH,1 ; enable interrupt control mask-bit
SHL AH,CL
NOT AH
IN AL,21H
AND AL,AH
OUT 21H,AL
STI
POP DX
POP CX
POP BX
RET
SetupInterrupt ENDP
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;
; RestoreInterrupt
;
; ENTRY: AL = INTERRUPT NUM
; BX = offset to stored addx
;
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
RestoreInterrupt PROC
CLI
MOV CL,AL
ADD AL,8 ; calculate interrupt vector addx
CBW
SHL AL,1
SHL AL,1
MOV DI,AX
PUSH ES ; restore interrupt vector
XOR AX,AX
MOV ES,AX
MOV AX,[BX]
MOV ES:[DI],AX
MOV AX,[BX+2]
MOV ES:[DI+2],AX
POP ES
MOV AH,1
SHL AH,CL
IN AL,21H
OR AL,AH
OUT 21H,AL
STI
RET
RestoreInterrupt ENDP
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
;
; DUMMY INTERRUPTS - used for interrupt detection
;
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
DUMMY_DMA_INT2 PROC FAR
PUSH DX
MOV DX,2
JMP SHORT DUMMY_DMA_ISR
DUMMY_DMA_INT2 ENDP
DUMMY_DMA_INT3 PROC FAR
PUSH DX
MOV DX,3
JMP SHORT DUMMY_DMA_ISR
DUMMY_DMA_INT3 ENDP
DUMMY_DMA_INT5 PROC FAR
PUSH DX
MOV DX,5
JMP SHORT DUMMY_DMA_ISR
DUMMY_DMA_INT5 ENDP
DUMMY_DMA_INT7 PROC FAR
PUSH DX
MOV DX,7
DUMMY_DMA_ISR:
PUSH AX
PUSH DS
MOV AX,DATA
MOV DS,AX
MOV SBIrq,DX ; update interrupt variable with
; number of interrupt called
MOV DX,SBInt
ADD DX,0EH ; DX = DSP data available port 2xEh
IN AL,DX ; acknowledge DSP interrupt
MOV AL,20H ; send EOI (end of interrupt) to
OUT 20H,AL ; interrupt controller port 20h
POP DS
POP AX
POP DX
IRET ; interrupt return
DUMMY_DMA_INT7 ENDP
CODE ENDS
END

Binary file not shown.

View File

@@ -0,0 +1,184 @@
;---------------------------------------------------------------------------
; SB_DSP.ASM -- Programmer's library for the Sound Blaster DSP interface
;---------------------------------------------------------------------------
IDEAL
MODEL small
DATASEG
SB_IO_Port DW 0220h ;These values are kept here to avoid add
DSP_Reset DW 0226h ;instructions in code that may be time-
DSP_RDData DW 022Ah ;sensitive.
DSP_Command DW 022Ch
DSP_RDAvail DW 022Eh
DSP_WRData EQU DSP_Command ;Aliases for the same variable name
DSP_Status EQU DSP_Command
CODESEG
PUBLIC _dsp_reset,_dsp_voice,_set_SB_address,_dsp_dma_prepare,_dsp_time
MACRO await_DSP
LOCAL @@Wait_Ready
push ax dx
@@Wait_Ready:
mov dx,[DSP_Status]
in al,dx
and al,128
jnz @@Wait_Ready
pop dx ax
ENDM MACRO
MACRO ten_microsec_delay
LOCAL @@KT ;If you know of a better, more accurate,
push cx ;more reliable, just plain smarter, way
mov cx,20000 ;to do this, PLEASE TELL ME.
@@KT: ;
nop ;(The idea is to kill 10 microseconds.)
loop @@KT ;
pop cx ;email: heathh@cco.caltech.edu
ENDM ten_microsec_delay
;---------------------------------------------------------------------------
; void far dsp_time(int pacing)
;---------------------------------------------------------------------------
; pacing = 255 - (1,000,000 / frequency)
;---------------------------------------------------------------------------
PROC _dsp_time FAR
ARG delay:WORD
push bp
mov bp,sp
push ax dx
await_DSP
mov dx,[DSP_Command]
mov al,040h
out dx,al
await_DSP
mov dx,[DSP_Command]
mov ax,[delay]
out dx,al
pop dx ax
pop bp
ret
ENDP _dsp_time
;---------------------------------------------------------------------------
; void far dsp_reset(void)
;---------------------------------------------------------------------------
PROC _dsp_reset FAR
push ax dx
mov dx,[DSP_Reset]
mov al,1
out dx,al
ten_microsec_delay
mov al,0
out dx,al
@@Wait_Ready:
mov dx,[DSP_RDAvail]
in al,dx
and al,128
jz @@Wait_Ready
mov dx,[DSP_RDData]
in al,dx
cmp al,0AAh
jne @@Wait_Ready
mov ax,165
push ax
call _dsp_time
pop ax
pop dx ax
ret
ENDP _dsp_reset
;---------------------------------------------------------------------------
; void far dsp_dma_prepare(int Dir,int Length)
;---------------------------------------------------------------------------
; Dir = 0 for Microphone Input, 1 for Speaker Output
; Length = Length of data to be sampled/played
;---------------------------------------------------------------------------
PROC _dsp_dma_prepare FAR
ARG Dir:WORD,Len:WORD
push bp
mov bp,sp
push ax dx
await_DSP
mov al,24h
cmp [Dir],0
jz @@Is_Read
mov al,14h
@@Is_Read:
mov dx,[DSP_Command]
out dx,al
await_DSP
mov ax,[Len]
out dx,al
await_DSP
mov al,ah
out dx,al
pop dx ax
pop bp
ret
ENDP _dsp_dma_prepare
;---------------------------------------------------------------------------
; void far dsp_voice(Activity)
;---------------------------------------------------------------------------
; Activity = 0 for silent, 1 for audible
;---------------------------------------------------------------------------
PROC _dsp_voice FAR
ARG Which:WORD
push bp
mov bp,sp
push dx ax
await_DSP
mov ax,[Which]
and al,1 ;Want a 1/0 parameter
xor al,1
shl al,1
or al,0D1h
mov dx,[DSP_Command]
out dx,al
pop ax dx
pop bp
ret
ENDP _dsp_voice
;---------------------------------------------------------------------------
; void far set_SB_address(int base)
;---------------------------------------------------------------------------
; Sets base port of SoundBlaster that other functions refer to.
; Most likely value (and the default): 0x220
;---------------------------------------------------------------------------
PROC _set_SB_address FAR
ARG Port:WORD
push bp
mov bp,sp
push ax
mov ax,[Port]
mov [SB_IO_Port],ax
add ax,6
mov [DSP_Reset],ax
add ax,4
mov [DSP_RDData],ax
add ax,2
mov [DSP_Command],ax
add ax,2
mov [DSP_RDAvail],ax
pop ax
pop bp
ret
ENDP _set_SB_address
END

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,216 @@
How Dolby Stereo (aka Dolby Surround) works:
(version 2.01, 4/22/94)
Don Munsil (don@munsil.com)
2.01 changes:
- Better explanation of inverting a sample.
2.0 changes:
- Added responses from Otto Chrons and Adrian Kwong.
- Cleaned up text considerably.
- Added more tips on practical aspects.
** Introduction:
Dolby Stereo is a system designed by Dolby Labs in the '70s for creating
better movie sound, including surround-sound. The other benefits are
increased directionality of front sounds and improved localization of
on-screen sounds like dialog for the people sitting on the edges. The
system is totally separate from Dolby noise-reduction systems like Dolby B
and C. Remember that there is only one encoding process: Dolby Stereo,
which can be decoded by a Dolby Surround, Dolby Pro-Logic, or THX
decoder, for varying degrees of home-theatre "quality."
There are four output channels in Dolby Stereo: Left front, Right front,
Center front, and Surround. These are encoded on two channels in such a
way that the soundtrack can be played back on a standard stereo device, a
mono device, or a Dolby decoder. (Or a THX system, which is a Dolby
Pro-Logic decoder with specifications licensed by Lucasfilm).
A word is in order about THX. It is NOT different from Dolby Pro-Logic, at
least not precisely. THX is a licensing and quality-control wing of
LucasArts with the stated aim of improving movie sound and picture. It
licenses the name THX for movie equipment, movie theatres, home equipment,
and laserdiscs. The name means that the THX engineers certify it as good
quality. There are a few processing steps in home THX that are not
typically present in a plain Pro-Logic system, but they are merely
enhancements to Dolby Pro-Logic decoding, not a different system.
The center channel is the most used one in a film. It contains all of the
dialog, and most of the on-screen sound effects. It is important to have a
center channel so that people on the edges of the theatre (or your living
room) still hear the on-screen sound from the direction of the screen, not
panned to one side or another. Without the center channel, people hear
most of the sound coming from the nearest speaker. In addition, dialog
tends to be clearer when it is localized in the center channel.
The surround channel is used for "ambient" effects: sounds that should
envelop the listener. It is not a rear channel, and should not be used for
directional sounds. In a properly setup system, the listener should not be
able to tell where the surround speakers are located. In a movie theatre,
there are generally many surround speakers around the back of the hall. In
the home, this is impractical, so two speakers facing in such a way as to
maximize reflected sound are used.
Any device capable of playing back two distinct channels can produce Dolby
Stereo-compatible signals. This includes any stereo soundcard, stereo vcr,
or even CD player or record (there are Dolby Stereo encoded CDs).
** Here's how:
I'll refer to the four output channels as LO, RO, CO, and SO, for left,
right, center, and surround, respectively. The input channels (the ones
coming from the source and into the decoder) I'll call LI and RI. (If you
don't like acronyms, feel free to use search-and-replace to make this more
readable.) :-)
The LO channel and RO channel are recorded normally on the LI and RI tape
channels (we'll assume tape recording for example purposes). The CO
channel is recorded on BOTH the LI and RI channel at exactly the same
volume, in-phase (i.e., no special processing). The SO channel is recorded
on LI and RI at the same volume, with inverted phase (i.e. every peak on
one channel is a trough on the other).
There are a few interesting nuances here. Because the CO channel is
recorded normally on LI and RI, it will still image in the center on any
stereo playback system, as long as the listener is basically in the
center. As the listener moves further left or right, the image moves in
the same direction, which is a little distracting, but acceptable. This is
what one gets with a simple "surround" decoder (in addition to the
surround channel, of course). Without the Center channel, the imaging is
fine for one or two people, but not so great for groups. Dolby Pro-Logic
adds (among other things) the center channel.
Note that because of the inverted encoding scheme for the surround
channel, it will disappear when played back on a mono system. Each peak is
precisely canceled by a trough on the other channel, and all surround
information is lost. This is another reason to put only ambient,
non-essential sounds in the surround channel. Many systems are still mono
(most VCRs, for example) and will not reproduce them.
The Dolby decoder reproduces a fairly good semblance of the original four
channels from the two input channels, though there will always be leakage
and crosstalk. Dolby Pro-Logic and THX circuitry have special processing
that minimizes perceived crosstalk.
When the Dolby Stereo is mixed, the engineers listen to it running through
a Pro-Logic decoder exactly like the one in the theatre or your home.
Thus, they design the four channels specifically so they will decode
properly. It is not a good idea to mix four distinct channels, then do the
Pro-Logic encoding "blind" as a post-process, because the results will not
be exactly the same as the original four distinct channels.
** Doing it on a soundcard (kinky as it sounds):
On a soundcard, sending signals to the center channel is a simple as
playing the sound in dead-center (equal volume on both channels). Surround
is a bit tougher. The sound must be played back inverted on one channel.
One way would be to have two samples, with one pre-inverted. Another would
be to invert one side on the fly. I have been told that DMP, a MOD music
player by Otto Chrons, does just this. I haven't heard it myself.
Inverting a sample simply consists of negating it. If the sample values
are unsigned, the negation will still give the desired result because of
the nature of two's complement representation (though you should make
sure your compiler is actually doing the appropriate negation -- in C,
cast the value to signed, then negate it, then cast to unsigned to be
absolutely sure.)
>>New addition: Otto Chrons (c142092@cc.tut.fi), author of DMP, emailed
me the following:
You wrote an excellent article about Dolby Surround sound at csip.soundcard
but I wanted to comment on few things. DMP does work with surround channel
and the technique I use is extremely simple. Dolby standard state that
you should do +90 and -90 phase shifting on left & right channels, but I've
found out that doing a 0 and +180 shift works as well. So basically I
put the original sound data out of the left speaker and negate the data
on the right speaker. In my mixing routines this is accomplished by
using ADD and SUB instructions respectively. So doing surround sound is
as easy as doing mono!
>>End Chrons
** A few other issues to keep in mind:
>>Adrian Kwong (akwong@alfred.carleton.ca) had this to add:
You might want to add that the surround channel in a normal Dolby
Surround setup is placed through Dolby A type noise decoding. It has
something to do with making it 3dB larger following a specific
frequency envelope. To make the surround appear at the correct
volume, you'll need to "double" the signal to the surround channel.
(+3dB is about 2x the signal)
>>End Kwong
One thing to keep in mind is that the Surround channel is typically not
designed to handle a lot of bass. The speakers are generally small, and
the amplifiers are lower wattage. On a film soundtrack, the low bass is
generally filtered out of the soundtrack to avoid clipping.
In addition, the high frequencies are generally filtered out of the
surround channel because higher frequencies are easier to localize, and
the surround channel is not supposed to be directional. The end result is
that the surround channel is only "supposed" to carry about 200-8000Hz,
which is a fairly narrow spectrum.
It is difficult to get a sound to play on all four channels at once.
Generally, on a film soundtrack, a "big" sound, like an explosion, is sent
mainly to the surround channel. Since this will be lost in mono, a similar
sound is sent to the left and right channels as well.
A technique often used with thunder effects is to put the main sound in
the surround channel, followed by an echo in the front channels (or
sometimes vice-versa). The Dolby stereo listeners hear the two-part
thunder, and the mono listeners hear just the second bit (or a scaled-down
version of the first).
Another technique is to slightly pitch-shift or delay sounds going to the
different speakers, but results can be iffy. YMMV. The important thing is
to do testing on a real Pro-Logic setup, and experiment until a good
balance is reached.
One can also send frequency band-limited chunks of the sound to each channel,
which will decode rather well. It requires that the bulk of each channel
be using a different band of the frequency spectrum, which is not
practical in some cases.
Keep in mind that there are many tricks of the trade that are used in film
mixing that only Dolby really knows. They don't tell how they do it,
because they want film companies to buy their technology, not the
competition (e.g. UltraStereo, Chase Surround, StereoSurround). If anyone
reading this has useful techniques (that are not trade secrets of Dolby)
they would like to share, please email the author.
Fortunately, in computer sound, you don't have to make the soundtrack
mono-compatible. You can ask the user if the sound system is Dolby
Surround, and place sounds in the surround channel as needed. On a mono
system, the sounds can all be sent to the single channel.
** Disclaimers:
All of this information is from me, and any errors are my own darn fault.
None of this information has been endorsed by Dolby Labs. Dolby is a
trademark of Dolby labs, and should not be used on a product without
getting their permission. (Although I think if you called it "surround"
people would get the idea.)
Please email suggestions/criticisms/additions/subtractions/
multiplications/corrections to don@munsil.com.
This text is copyright 1993 by Don Munsil. It may be distributed freely,
as long as modifications are attributed and marked clearly.
--
------------------------------------------------------
Don Munsil | I respect faith, but doubt is
don@munsil.com | what gets you an education.
| -- Wilson Mizner

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,7 @@
<html>
<head>
<meta http-equiv="refresh" content="0;url=/Linux.old/sabre/os/articles">
</head>
<body lang="zh-CN">
</body>
</html>