
: This archive contains the following files...
: '8svx'
: 'ea.iff.85'
: 'ftxt'
: 'ilbm'
: 'smus'
: To extract them, run the following through /bin/sh
echo x - 8svx
sed 's/^X//' > 8svx << '//END'
X"8SVX" IFF 8-Bit Sampled Voice
X
XDate:	February 7, 1985
XFrom:	Steve Hayes and Jerry Morrison, Electronic Arts
XStatus:	Adopted
X
X1. Introduction
X
XThis memo is the IFF supplement for FORM "8SVX". An 8SVX is an IFF 
X"data section" or "FORM" (which can be an IFF file or a part of one) 
Xcontaining a digitally sampled audio voice consisting of 8-bit samples. 
XA voice can be a one-shot sound orQwith repetition and pitch scalingQa 
Xmusical instrument. "EA IFF 85" is Electronic Arts' standard interchange 
Xfile format. [See "EA IFF 85" Standard for Interchange Format Files.]
X
XThe 8SVX format is designed for playback hardware that uses 8-bit 
Xsamples attenuated by a volume control for good overall signal-to-noise 
Xratio. So a FORM 8SVX stores 8-bit samples and a volume level.
X
XA similar data format (or two) will be needed for higher resolution 
Xsamples (typically 12 or 16 bits). Properly converting a high resolution 
Xsample down to 8 bits requires one pass over the data to find the 
Xminimum and maximum values and a second pass to scale each sample 
Xinto the range -128 through 127. So it's reasonable to store higher 
Xresolution data in a different FORM type and convert between them.
X
XFor instruments, FORM 8SVX can record a repeating waveform optionally 
Xpreceded by a startup transient waveform. These two recorded signals 
Xcan be pre-synthesized or sampled from an acoustic instrument. For 
Xmany instruments, this representation is compact. FORM 8SVX is less 
Xpractical for an instrument whose waveform changes from cycle to cycle 
Xlike a plucked string, where a long sample is needed for accurate 
Xresults.
X
XFORM 8SVX can store an "envelope" or "amplitude contour" to enrichen 
Xmusical notes. A future voice FORM could also store amplitude, frequency, 
Xand filter modulations.
X
XFORM 8SVX is geared for relatively simple musical voices, where one 
Xwaveform per octave is sufficient, where the waveforms for the different 
Xoctaves follows a factor-of-two size rule, and where one envelope 
Xis adequate for all octaves. You could store a more general voice 
Xas a LIST containing one or more FORMs 8SVX per octave. A future voice 
XFORM could go beyond one "one-shot" waveform and one "repeat" waveform 
Xper octave.
X
XSection 2 defines the required property sound header "VHDR", optional 
Xproperties name "NAME", copyright "(c)J", and author "AUTH", the optional 
Xannotation data chunk "ANNO", the required data chunk "BODY", and 
Xoptional envelope chunks "ATAK" and "RLSE". These are the "standard" 
Xchunks. Specialized chunks for private or future needs can be added 
Xlater, e.g. to hold a frequency contour or Fourier series coefficients. 
XThe 8SVX syntax is summarized in Appendix A as a regular expression 
Xand in Appendix B as an example box diagram. Appendix C explains the 
Xoptional Fibonacci-delta compression algorithm.
X
XCaution: The VHDR structure Voice8Header changed since draft proposal 
X#4! The new structure is incompatible with the draft version.
X
X
X
XReference:
X
X"EA IFF 85" Standard for Interchange Format Files describes the underlying 
Xconventions for all IFF files.
X
XAmiga[tm] is a trademark of Commodore-Amiga, Inc.
X
XElectronic Arts[tm] is a trademark of Electronic Arts.
X
XMacWrite[tm] is a trademark of Apple Computer, Inc.
X
X
X
X2. Standard Data and Property Chunks
X
XFORM 8SVX stores all the waveform data in one body chunk "BODY". It 
Xstores playback parameters in the required header chunk "VHDR". "VHDR" 
Xand any optional property chunks "NAME", "(c)J", and "AUTH" must all 
Xappear before the BODY chunk. Any of these properties may be shared 
Xover a LIST of FORMs 8SVX by putting them in a PROP 8SVX. [See "EA 
XIFF 85" Standard for Interchange Format Files.]
X
XBackground
X
XThere are two ways to use FORM 8SVX: as a one-shot sampled sound or 
Xas a sampled musical instrument that plays "notes". Storing both kinds 
Xof sounds in the same kind of FORM makes it easy to play a one-shot 
Xsound as a (staccato) instrument or an instrument as a (one-note) 
Xsound.
X
XA one-shot sound is a series of audio data samples with a nominal 
Xplayback rate and amplitude. The recipient program can optionally 
Xadjust or modulate the amplitude and playback data rate.
X
XFor musical instruments, the idea is to store a sampled (or pre-synthesized) 
Xwaveform that will be parameterized by pitch, duration, and amplitude 
Xto play each "note". The creator of the FORM 8SVX can supply a waveform 
Xper octave over a range of octaves for this purpose. The intent is 
Xto perform a pitch by selecting the closest octave's waveform and 
Xscaling the playback data rate. An optional "one-shot" waveform supplies 
Xan arbitrary startup transient, then a "repeat" waveform is iterated 
Xas long as necessary to sustain the note.
X
XA FORM 8SVX can also store an envelope to modulate the waveform. Envelopes 
Xare mostly useful for variable-duration notes but could be used for 
Xone-shot sounds, too.
X
XThe FORM 8SVX standard has some restrictions. For example, each octave 
Xof data must be twice as long as the next higher octave. Most sound 
Xdriver software and hardware imposes additional restrictions. E.g. 
Xthe Amiga sound hardware requires an even number of samples in each 
Xone-shot and repeat waveform.
X
XRequired Property VHDR
X
XThe required property "VHDR" holds a Voice8Header structure as defined 
Xin these C declarations and following documentation. This structure 
Xholds the playback parameters for the sampled waveforms in the BODY 
Xchunk. (See "Data Chunk BODY", below, for the storage layout of these 
Xwaveforms.)
X
X#define ID_8SVX MakeID('8', 'S', 'V', 'X')
X#define ID_VHDR MakeID('V', 'H', 'D', 'R')
X
Xtypedef LONG Fixed;	
X	/* A fixed-point value, 16 bits to the left of the point and 16 
X	 * to the right. A Fixed is a number of 216ths, i.e. 65536ths.	*/
X
X#define Unity 0x10000L	/* Unity = Fixed 1.0 = maximum volume	*/
X
X/* sCompression: Choice of compression algorithm applied to the samples. */ 
X
X#define sCmpNone       0	/* not compressed	*/
X#define sCmpFibDelta   1	/* Fibonacci-delta encoding (Appendix C)  */ 
X
X/* Can be more kinds in the future.	*/
X
Xtypedef struct {
X	ULONG oneShotHiSamples,	/* # samples in the high octave 1-shot part */
X        repeatHiSamples,	/* # samples in the high octave repeat part */
X        samplesPerHiCycle;	/* # samples/cycle in high octave, else 0   */
X	UWORD samplesPerSec;	/* data sampling rate	*/
X	UBYTE ctOctave,		/* # octaves of waveforms	*/
X      	sCompression;		/* data compression technique used	*/
X	Fixed volume;		/* playback volume from 0 to Unity (full 
X				 * volume). Map this value into the output 
X				 * hardware's dynamic range.	*/
X	} Voice8Header;
X
X[Implementation details. Fields are filed in the order shown. The 
XUBYTE fields are byte-packed (2 per 16-bit word). MakeID is a C macro 
Xdefined in the main IFF document and in the source file IFF.h.]
X
XA FORM 8SVX holds waveform data for one or more octaves, each containing 
Xa one-shot part and a repeat part. The fields oneShotHiSamples and 
XrepeatHiSamples tell the number of audio samples in the two parts 
Xof the highest frequency octave. Each successive (lower frequency) 
Xoctave contains twice as many data samples in both its one-shot and 
Xrepeat parts. One of these two parts can be empty across all octaves.
X
XNote: Most audio output hardware and software has limitations. The 
XAmiga computer's sound hardware requires that all one-shot and repeat 
Xparts have even numbers of samples. Amiga sound driver software would 
Xhave to adjust an odd-sized waveform, ignore an odd-sized lowest octave, 
Xor ignore odd FORMs 8SVX altogether. Some other output devices require 
Xall sample sizes to be powers of two.
X
XThe field samplesPerHiCycle tells the number of samples/cycle in the 
Xhighest frequency octave of data, or else 0 for "unknown". Each successive 
X(lower frequency) octave contains twice as many samples/cycle. The 
XsamplesPerHiCycle value is needed to compute the data rate for a desired 
Xplayback pitch.
X
XActually, samplesPerHiCycle is an average number of samples/cycle. 
XIf the one-shot part contains pitch bends, store the samples/cycle 
Xof the repeat part in samplesPerHiCycle. The division repeatHiSamples/samplesPe
XrHiCycle should yield an integer number of cycles. (When the repeat 
Xwaveform is repeated, a partial cycle would come out as a higher-frequency 
Xcycle with a "click".)
X
XMore limitations: Some Amiga music drivers require samplesPerHiCycle 
Xto be a power of two in order to play the FORM 8SVX as a musical instrument 
Xin tune. They may even assume samplesPerHiCycle is a particular power 
Xof two without checking. (If samplesPerHiCycle is different by a factor 
Xof two, the instrument will just be played an octave too low or high.)
X
XThe field samplesPerSec gives the sound sampling rate. A program may 
Xadjust this to achieve frequency shifts or vary it dynamically to 
Xachieve pitch bends and vibrato. A program that plays a FORM 8SVX 
Xas a musical instrument would ignore samplesPerSec and select a playback 
Xrate for each musical pitch.
X
XThe field ctOctave tells how many octaves of data are stored in the 
XBODY chunk. See "Data Chunk BODY", below, for the layout of the octaves.
X
XThe field sCompression indicates the compression scheme, if any, that 
Xwas applied to the entire set of data samples stored in the BODY chunk. 
XThis field should contain one of the values defined above. Of course, 
Xthe matching decompression algorithm must be applied to the BODY data 
Xbefore the sound can be played. (The Fibonacci-delta encoding scheme 
XsCmpFibDelta is described in Appendix C.) Note that the whole series 
Xof data samples is compressed as a unit.
X
XThe field volume gives an overall playback volume for the waveforms 
X(all octaves). It lets the 8-bit data samples use the full range -128 
Xthrough 127 for good signal-to-noise ratio and be attenuated on playback 
Xto the desired level. The playback program should multiply this value 
Xby a "volume control" and perhaps by a playback envelope (see ATAK 
Xand RLSE, below).
X
XRecording a one-shot sound. To store a one-shot sound in a FORM 8SVX, 
Xset oneShotHiSamples = number of samples, repeatHiSamples = 0 , 
XsamplesPerHiCycle = 0, samplesPerSec = sampling rate, and ctOctave = 1. 
XScale the signal amplitude to the full sampling range -128 through 127. Set 
Xvolume so the sound will playback at the desired volume level. If 
Xyou set the samplesPerHiCycle field properly, the data can also be 
Xused as a musical instrument.
X
XExperiment with data compression. If the decompressed signal sounds 
Xok, store the compressed data in the BODY chunk and set sCompression 
Xto the compression code number.
X
XRecording a musical instrument. To store a musical instrument in a 
XFORM 8SVX, first record or synthesize as many octaves of data as you 
Xwant to make available for playback. Set ctOctaves to the count of 
Xoctaves. From the recorded data, excerpt an integral number of steady 
Xstate cycles for the repeat part and set repeatHiSamples and samplesPerHiCycle. 
XEither excerpt a startup transient waveform and set oneShotHiSamples, 
Xor else set oneShotHiSamples to 0. Remember, the one-shot and repeat 
Xparts of each octave must be twice as long as those of the next higher 
Xoctave. Scale the signal amplitude to the full sampling range and 
Xset volume to adjust the instrument playback volume. If you set the 
XsamplesPerSec field properly, the data can also be used as a one-shot 
Xsound.
X
XA distortion-introducing compressor like sCmpFibDelta is not recommended 
Xfor musical instruments, but you might try it anway.
X
XTypically, creators of FORM 8SVX record an acoustic instrument at 
Xjust one frequency. Decimate (down- sample with filtering) to compute 
Xhigher octaves. Interpolate to compute lower octaves.
X
XIf you sample an acoustic instrument at different octaves, you may 
Xfind it hard to make the one-shot and repeat waveforms follow the 
Xfactor-of-two rule for octaves. To compensate, lengthen an octave's 
Xone-shot part by appending replications of the repeating cycle or 
Xprepending zeros. (This will have minimal impact on the sound's start 
Xtime.) You may be able to equalize the ratio one-shot-samples : repeat-samples 
Xacross all octaves.
X
XNote that a "one-shot sound" may be played as a "musical instrument" 
Xand vice versa. However, an instrument player depends on samplesPerHiCycle, 
Xand a one-shot player depends on samplesPerSec.
X
XPlaying a one-shot sound. To play any FORM 8SVX data as a one-shot 
Xsound, first select an octave if ctOctave > 1. (The lowest-frequency 
Xoctave has the greatest resolution.) Play the one-shot samples then 
Xthe repeat samples, scaled by volume, at a data rate of samplesPerSec. 
XOf course, you may adjust the playback rate and volume. You can play 
Xout an envelope, too. (See ATAK and RLSE, below.)
X
XPlaying a musical note. To play a musical note using any FORM 8SVX, 
Xfirst select the nearest octave of data from those available. Play 
Xthe one-shot waveform then cycle on the repeat waveform as long as 
Xneeded to sustain the note. Scale the signal by volume, perhaps also 
Xby an envelope, and by a desired note volume. Select a playback data 
Xrate s samples/second to achieve the desired frequency (in Hz):
Xfrequency = sJ/JsamplesPerHiCycle
Xfor the highest frequency octave.
X
XThe idea is to select an octave and one of 12 sampling rates (assuming 
Xa 12-tone scale). If the FORM 8SVX doesn't have the right octave, 
Xyou can decimate or interpolate from the available data.
X
XWhen it comes to musical instruments, FORM 8SVX is geared for a simple 
Xsound driver. Such a driver uses a single table of 12 data rates to 
Xreach all notes in all octaves. That's why 8SVX requires each octave 
Xof data to have twice as many samples as the next higher octave. If 
Xyou restrict samplesPerHiCycle to a power of two, you can use a predetermined 
Xtable of data rates.
X
XOptional Text Chunks NAME, (c), AUTH, ANNO
X
XSeveral text chunks may be included in a FORM 8SVX to keep ancillary 
Xinformation.
X
XThe optional property "NAME" names the voice, for instance "tubular 
Xbells".
X
XThe optional property "(c)J" holds a copyright notice for the voice. 
XThe chunk ID "(c)J" serves as the copyright characters ")J". E.g. 
Xa "(c)J" chunk containing "1986 Electronic Arts" means ") 1986 Electronic 
XArts".
X
XThe optional property "AUTH" holds the name of the instrument's "author" 
Xor "creator".
X
XThe chunk types "NAME", "(c) ", and "AUTH" are property chunks. Putting 
Xmore than one NAME (or other) property in a FORM is redundant. Just 
Xthe last NAME counts. A property should be shorter than 256 characters. 
XProperties can appear in a PROP 8SVX to share them over a LIST of 
XFORMs 8SVX.
X
XThe optional data chunk "ANNO" holds any text annotations typed in 
Xby the author.
X
XAn ANNO chunk is not a property chunk, so you can put more than one 
Xin a FORM 8SVX. You can make ANNO chunks any length up to 231 - 1 
Xcharacters, but 32767 is a practical limit. Since they're not properties, 
XANNO chunks don't belong in a PROP 8SVX. That means they can't be 
Xshared over a LIST of FORMs 8SVX.
X
XSyntactically, each of these chunks contains an array of 8-bit ASCII 
Xcharacters in the range " " (SP, hex 20) through "~" (tilde, hex 7F), 
Xjust like a standard "TEXT" chunk. [See "Strings, String Chunks, and 
XString Properties" in "EA IFF 85" Electronic Arts Interchange File 
XFormat.] The chunk's ckSize field holds the count of characters.
X
X#define ID_NAME MakeID('N', 'A', 'M', 'E')
X/* NAME chunk contains a CHAR[], the voice's name.	*/
X
X#define ID_Copyright MakeID('(', 'c', ')', ' ')
X/* "(c) " chunk contains a CHAR[], the FORM's copyright notice.	*/
X
X#define ID_AUTH MakeID('A', 'U', 'T', 'H')
X/* AUTH chunk contains a CHAR[], the author's name.	*/
X
X#define ID_ANNO MakeID('A', 'N', 'N', 'O')
X/* ANNO chunk contains a CHAR[], author's text annotations.	*/
X
XRemember to store a 0 pad byte after any odd-length chunk.
X
XOptional Data Chunks ATAK and RLSE
X
XThe optional data chunks ATAK and RLSE together give a piecewise-linear 
X"envelope" or "amplitude contour". This contour may be used to modulate 
Xthe sound during playback. It's especially useful for playing musical 
Xnotes of variable durations. Playback programs may ignore the supplied 
Xenvelope or substitute another.
X
X#define ID_ATAK MakeID('A', 'T', 'A', 'K')
X#define ID_RLSE MakeID('R', 'L', 'S', 'E')
X
Xtypedef struct {
X	UWORD duration;	/* segment duration in milliseconds, > 0	*/
X	Fixed dest;	/* destination volume factor	*/
X	} EGPoint;
X
X/* ATAK and RLSE chunks contain an EGPoint[], piecewise-linear envelope.*/ 
X/* The envelope defines a function of time returning Fixed values. It's
X * used to scale the nominal volume specified in the Voice8Header. */
X
XTo explain the meaning of the ATAK and RLSE chunks, we'll overview 
Xthe envelope generation algorithm. Start at 0 volume, step through 
Xthe ATAK contour, then hold at the sustain level (the last ATAK EGPoint's 
Xdest), and then step through the RLSE contour. Begin the release at 
Xthe desired note stop time minus the total duration of the release 
Xcontour (the sum of the RLSE EGPoints' durations). The attack contour 
Xshould be cut short if the note is shorter than the release contour.
X
XThe envelope is a piecewise-linear function. The envelope generator 
Xinterpolates between the EGPoints.
X
XRemember to multiply the envelope function by the nominal voice header 
Xvolume and by any desired note volume.
X
XFigure 1 shows an example envelope. The attack period is described 
Xby 4 EGPoints in an ATAK chunk. The release period is described by 
X4 EGPoints in a RLSE chunk. The sustain period in the middle just 
Xholds the final ATAK level until it's time for the release.
X
X
X
X
X
X
X
X
X
X
X			Figure 1. Amplitude contour.
X
XNote: The number of EGPoints in an ATAK or RLSE chunk is its ckSize 
X/ sizeof(EGPoint). In RAM, the playback program may terminate the 
Xarray with a 0 duration EGPoint.
X
XIssue: Synthesizers also provide frequency contour (pitch bend), filtering 
Xcontour (wah-wah), amplitude oscillation (tremolo), frequency oscillation 
X(vibrato), and filtering oscillation (leslie). In the future, we may 
Xdefine optional chunks to encode these modulations. The contours can 
Xbe encoded in linear segments. The oscillations can be stored as segments 
Xwith rate and depth parameters.
X
XData Chunk BODY
X
XThe BODY chunk contains the audio data samples.
X
X#define ID_BODY MakeID('B', 'O', 'D', 'Y')
X
Xtypedef character BYTE;	/* 8 bit signed number, -128 through 127.	*/
X
X/* BODY chunk contains a BYTE[], array of audio data samples.	*/
X
XThe BODY contains data samples grouped by octave. Within each octave 
Xare one-shot and repeat portions. Figure 2 depicts this arrangement 
Xof samples for an 8SVX where oneShotHiSamples = 24, repeatHiSamples 
X= 16, samplesPerHiCycle = 8, and ctOctave = 3. The major divisions 
Xare octaves, the intermediate divisions separate the one-shot and 
Xrepeat portions, and the minor divisions are cycles.
X
X
X
X
X
X
X
X
X
X			Figure 2. BODY subdivisions.
X
XIn general, the BODY has ctOctave octaves of data. The highest frequency 
Xoctave comes first, comprising the fewest samples: oneShotHiSamples 
X+ repeatHiSamples. Each successive octave contains twice as many samples 
Xas the next higher octave but the same number of cycles. The lowest 
Xfrequency octave comes last with the most samples: 2ctOctave-1 * (oneShotHiSamp
Xles + repeatHiSamples).
X
XThe number of samples in the BODY chunk is
X
X  0          (ctOctave-1) 
X(2  + ... + 2	          * (oneShotHiSamples + repeatHiSamples)
X
XFigure 3, below, looks closer at an example waveform within one octave 
Xof a different BODY chunk. In this example, oneShotHiSamples / samplesPerHiCycl
Xe = 2 cycles and repeatHiSamples / samplesPerHiCycle = 1 cycle.
X
X
X
X
X
X
X
X
X
X			Figure 3. Example waveform.
X
XTo avoid playback "clicks", the one-shot part should begin with a 
Xsmall sample value, and the one-shot part should flow smoothly into 
Xthe repeat part, and the end of the repeat part should flow smoothly 
Xinto the beginning of the repeat part.
X
XIf the VHDR field sCompression - sCmpNone, the BODY chunk is just 
Xan array of data bytes to feed through the specified decompresser 
Xfunction. All this stuff about sample sizes, octaves, and repeat parts 
Xapplies to the decompressed data.
X
XBe sure to follow an odd-length BODY chunk with a 0 pad byte.
X
XOther Chunks
X
XIssue: In the future, we may define an optional chunk containing Fourier 
Xseries coefficients for a repeating waveform. An editor for this kind 
Xof synthesized voice could modify the coefficients and regenerate 
Xthe waveform.
X
X
X
XAppendix A. Quick Reference
X
XType Definitions
X
X#define ID_8SVX MakeID('8', 'S', 'V', 'X')
X#define ID_VHDR MakeID('V', 'H', 'D', 'R')
X
Xtypedef LONG Fixed;	/* A fixed-point value, 16 bits to the left 
X			 * of the point and 16 to the right. A Fixed 
X			 * is a number of 216ths, i.e. 65536ths. */
X
X#define Unity 0x10000L	/* Unity = Fixed 1.0 = maximum volume	*/
X
X/* sCompression: Choice of compression algorithm applied to the samples	*/ 
X
X#define sCmpNone       0	/* not compressed	*/
X#define sCmpFibDelta   1	/* Fibonacci-delta encoding (Appendix C) */
X	/* Can be more kinds in the future.	*/
X
Xtypedef struct {
X	ULONG oneShotHiSamples,	/* # samples in the high octave 1-shot part */
X        repeatHiSamples,	/* # samples in the high octave repeat part */
X        samplesPerHiCycle;	/* # samples/cycle in high octave, else 0   */
X	UWORD samplesPerSec;	/* data sampling rate	*/
X	UBYTE ctOctave,		/* # octaves of waveforms	*/ 
X	sCompression;		/* data compression technique used	*/
X	Fixed volume;		/* playback volume from 0 to Unity (full
X	 			 * volume). Map this value into the output
X	 			 * hardware's dynamic range.	*/
X	} Voice8Header;
X
X#define ID_NAME MakeID('N', 'A', 'M', 'E')
X/* NAME chunk contains a CHAR[], the voice's name.	*/
X
X#define ID_Copyright MakeID('(', 'c', ')', ' ')
X/* "(c) " chunk contains a CHAR[], the FORM's copyright notice.	*/
X
X#define ID_AUTH MakeID('A', 'U', 'T', 'H')
X/* AUTH chunk contains a CHAR[], the author's name.	*/
X
X#define ID_ANNO MakeID('A', 'N', 'N', 'O')
X/* ANNO chunk contains a CHAR[], author's text annotations.	*/
X
X#define ID_ATAK MakeID('A', 'T', 'A', 'K')
X#define ID_RLSE MakeID('R', 'L', 'S', 'E')
X
Xtypedef struct {
X	UWORD duration;	/* segment duration in milliseconds, > 0	*/
X	Fixed dest;	/* destination volume factor	*/
X	} EGPoint;
X
X/* ATAK and RLSE chunks contain an EGPoint[], piecewise-linear envelope. */
X/* The envelope defines a function of time returning Fixed values. It's
X * used to scale the nominal volume specified in the Voice8Header.  */
X
X#define ID_BODY MakeID('B', 'O', 'D', 'Y')
X
Xtypedef character BYTE;	/* 8 bit signed number, -128 through 127.	*/
X
X/* BODY chunk contains a BYTE[], array of audio data samples.	*/
X
X8SVX Regular Expression
X
XHere's a regular expression summary of the FORM 8SVX syntax. This 
Xcould be an IFF file or part of one.
X
X8SVX	::= "FORM" #{	"8SVX" VHDR [NAME] [Copyright] [AUTH] ANNO*
X		[ATAK] [RLSE] BODY }
X
XVHDR	::= "VHDR" #{ Voice8Header	}
XNAME	::= "NAME" #{ CHAR*	} [0]
XCopyright	::= "(c) " #{ CHAR*	} [0]
XAUTH	::= "AUTH" #{ CHAR*	} [0]
XANNO	::= "ANNO" #{ CHAR*	} [0]
X
XATAK	::= "ATAK" #{ EGPoint*	}
XRLSE	::= "RLSE" #{ EGPoint*	}
XBODY	::= "FORM" #{ BYTE*	} [0]
X
XThe token "#" represents a ckSize LONG count of the following {braced} 
Xdata bytes. E.g. a VHDR's "#" should equal sizeof(Voice8Header). Literal 
Xitems are shown in "quotes", [square bracket items] are optional, 
Xand "*" means 0 or more replications. A sometimes-needed pad byte 
Xis shown as "[0]".
X
XActually, the order of chunks in a FORM 8SVX is not as strict as this 
Xregular expression indicates. The property chunks VHDR, NAME, Copyright, 
Xand AUTH may actually appear in any order as long as they all precede 
Xthe BODY chunk. The optional data chunks ANNO, ATAK, and RLSE don't 
Xhave to precede the BODY chunk. And of course, new kinds of chunks 
Xmay appear inside a FORM 8SVX in the future.
X
X
XAppendix B. 8SVX Example
X
XHere's a box diagram for a simple example containing the three octave 
XBODY shown earlier in Figure 2.
X
X     	+-----------------------------------+   
X     	|'FORM'		362  		    | 
X      	+-----------------------------------+   
X      	|'8SVX'				    |     
X      	+-----------------------------------+   
X      	|  +-----------------------------+  |   
X      	|  |'VHDR'		20       |  | 
X      	|  |24,16,8,10000,3,0,1.0	 |  |   
X      	|  +-----------------------------+  |   
X      	|  +-----------------------------+  |   
X      	|  |'NAME'		11       |  |
X      	|  |'bass guitar'		 |  |   
X      	|  +-----------------------------+  |   
X	|  0				    |
X      	|  +-----------------------------+  |   
X      	|  |'(c)'		20       |  |
X      	|  |1985 Electronic Arts	 |  |   
X      	|  +-----------------------------+  |   
X      	|  +-----------------------------+  |   
X      	|  |'BODY'		280      |  |
X      	|  |1, 2, 3, 4, ...		 |  |   
X      	|  +-----------------------------+  |   
X      	+-----------------------------------+   
X
XThe "0" after the NAME chunk is a pad byte.
X
X
X
XAppendix B. Standards Committee
X
XThe following people contributed to the design of this IFF standard:
X
XBob "Kodiak" Burns, Commodore-Amiga
XR. J. Mical, Commodore-Amiga
XJerry Morrison, Electronic Arts
XGreg Riker, Electronic Arts
XSteve Shaw, Electronic Arts
XBarry Walsh, Commodore-Amiga
X
X
XThe "0" after the NAME chunk is a pad byte.
X
X
X
XAppendix C. Fibonacci Delta Compression
X
XThis is Steve Hayes' Fibonacci Delta sound compression technique. 
XIt's like the traditional delta encoding but encodes each delta in 
Xa mere 4 bits. The compressed data is half the size of the original 
Xdata plus a 2-byte overhead for the initial value. This much compression 
Xintroduces some distortion, so try it out and use it with discretion.
X
XTo achieve a reasonable slew rate, this algorithm looks up each stored 
X4-bit value in a table of Fibonacci numbers. So very small deltas 
Xare encoded precisely while larger deltas are approximated. When it 
Xhas to make approximations, the compressor should adjust all the values 
X(forwards and backwards in time) for minimum overall distortion.
X
XHere is the decompressor written in the C programming language.
X
X/* Fibonacci delta encoding for sound data. */
X
XBYTE codeToDelta[16] = {-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21};
X
X/* Unpack Fibonacci-delta encoded data from n byte source buffer into 2*n byte
X * dest buffer, given initial data value x. It returns the last data value x
X * so you can call it several times to incrementally decompress the data. */
X
Xshort D1Unpack(source, n, dest, x)
X	BYTE source[], dest[];
X	LONG n;
X	BYTE x;
X	{
X	BYTE d;
X	LONG i, lim;
X
X	lim = n <<<< 1;
X	for (i = 0; i << lim; ++i)
X		{	
X		/* Decode a data nybble; high nybble then low nybble. */
X		d = source[i >> 1];	/* get a pair of nybbles */
X		if (i & 1)		/* select low or high nybble? */
X			d &= 0xf;	/* mask to get the low nybble */
X		else
X			d >>= 4;	/* shift to get the high nybble */
X		x += codeToDelta[d];	/* add in the decoded delta */
X		dest[i] = x;		/* store a 1-byte sample */
X		}
X	return(x);
X	}
X
X/* Unpack Fibonacci-delta encoded data from n byte source buffer into 2*(n-2)
X * byte dest buffer. Source buffer has a pad byte, an 8-bit initial value,
X * followed by n-2 bytes comprising 2*(n-2) 4-bit encoded samples. */
X
Xvoid DUnpack(source, n, dest)
X	BYTE source[], dest[];
X	LONG n;
X	{
X		D1Unpack(source + 2, n - 2, dest, source[1]);
X	}
//END
echo x - ea.iff.85
sed 's/^X//' > ea.iff.85 << '//END'
X"EA IFF 85" Standard for Interchange Format Files
X
XDocument Date:		January 14, 1985
XFrom:			Jerry Morrison, Electronic Arts
XStatus of Standard:	Released and in use
X
X1. Introduction
X
XStandards are Good for Software Developers
X
XAs home computer hardware evolves to better and better media machines, 
Xthe demand increases for higher quality, more detailed data. Data 
Xdevelopment gets more expensive, requires more expertise and better 
Xtools, and has to be shared across projects. Think about several ports 
Xof a product on one CD-ROM with 500M Bytes of common data!
X
XDevelopment tools need standard interchange file formats. Imagine 
Xscanning in images of "player" shapes, moving them to a paint program 
Xfor editing, then incorporating them into a game. Or writing a theme 
Xsong with a Macintosh score editor and incorporating it into an Amiga 
Xgame. The data must at times be transformed, clipped, filled out, 
Xand moved across machine kinds. Media projects will depend on data 
Xtransfer from graphic, music, sound effect, animation, and script 
Xtools.
X
XStandards are Good for Software Users
X
XCustomers should be able to move their own data between independently 
Xdeveloped software products. And they should be able to buy data libraries 
Xusable across many such products. The types of data objects to exchange 
Xare open-ended and include plain and formatted text, raster and structured 
Xgraphics, fonts, music, sound effects, musical instrument descriptions, 
Xand animation.
X
XThe problem with expedient file formats typically memory dumps is 
Xthat they're too provincial. By designing data for one particular 
Xuse (e.g. a screen snapshot), they preclude future expansion (would 
Xyou like a full page picture? a multi-page document?). In neglecting 
Xthe possibility that other programs might read their data, they fail 
Xto save contextual information (how many bit planes? what resolution?). 
XIgnoring that other programs might create such files, they're intolerant 
Xof extra data (texture palette for a picture editor), missing data 
X(no color map), or minor variations (smaller image). In practice, 
Xa filed representation should rarely mirror an in-memory representation. 
XThe former should be designed for longevity; the latter to optimize 
Xthe manipulations of a particular program. The same filed data will 
Xbe read into different memory formats by different programs.
X
XThe IFF philosophy: "A little behind-the-scenes conversion when programs 
Xread and write files is far better than NxM explicit conversion utilities 
Xfor highly specialized formats."
X
XSo we need some standardization for data interchange among development 
Xtools and products. The more developers that adopt a standard, the 
Xbetter for all of us and our customers.
X
XHere is "EA IFF 1985"
X
XHere is our offering: Electronic Arts' IFF standard for Interchange 
XFile Format. The full name is "EA IFF 1985". Alternatives and justifications 
Xare included for certain choices. Public domain subroutine packages 
Xand utility programs are available to make it easy to write and use 
XIFF-compatible programs.
X
XPart 1 introduces the standard. Part 2 presents its requirements and 
Xbackground. Parts 3, 4, and 5 define the primitive data types, FORMs, 
Xand LISTs, respectively, and how to define new high level types. Part 
X6 specifies the top level file structure. Appendix A is included for 
Xquick reference and Appendix B names the committee responsible for 
Xthis standard.
X
XReferences
X
XAmerican National Standard Additional Control Codes for Use with ASCII, 
XANSI standard 3.64-1979 for an 8-bit character set. See also ISO standard 
X2022 and ISO/DIS standard 6429.2.
X
XAmiga[tm] is a trademark of Commodore-Amiga, Inc.
X
XC, A Reference Manual, Samuel P. Harbison and Guy L. Steele Jr., Tartan 
XLaboratories. Prentice-Hall, Englewood Cliffs, NJ, 1984.
X
XCompiler Construction, An Advanced Course, edited by F. L. Bauer and 
XJ. Eickel (Springer-Verlag, 1976). This book is one of many sources 
Xfor information on recursive descent parsing.
X
XDIF Technical Specification (c)1981 by Software Arts, Inc. DIF[tm] is 
Xthe format for spreadsheet data interchange developed by Software 
XArts, Inc.
XDIF[tm] is a trademark of Software Arts, Inc.
X
XElectronic Arts[tm] is a trademark of Electronic Arts.
X
X"FTXT" IFF Formatted Text, from Electronic Arts. IFF supplement document 
Xfor a text format.
X
XInside Macintosh (c) 1982, 1983, 1984, 1985 Apple Computer, Inc., a 
Xprogrammer's reference manual.
XApple(R) is a trademark of Apple Computer, Inc.
XMacintosh[tm] is a trademark licensed to Apple Computer, Inc.
X
X"ILBM" IFF Interleaved Bitmap, from Electronic Arts. IFF supplement 
Xdocument for a raster image format.
X
XM68000 16/32-Bit Microprocessor Programmer's Reference Manual(c) 1984, 
X1982, 1980, 1979 by Motorola, Inc.
X
XPostScript Language Manual (c) 1984 Adobe Systems Incorporated.
XPostScript[tm] is a trademark of Adobe Systems, Inc.
XTimes and Helvetica(R) are trademarks of Allied Corporation.
X
XInterScript: A Proposal for a Standard for the Interchange of Editable 
XDocuments (c)1984 Xerox Corporation.
XIntroduction to InterScript (c) 1985 Xerox Corporation.
X
X
X
X2. Background for Designers
X
XPart 2 is about the background, requirements, and goals for the standard. 
XIt's geared for people who want to design new types of IFF objects. 
XPeople just interested in using the standard may wish to skip this 
Xpart.
X
XWhat Do We Need?
X
XA standard should be long on prescription and short on overhead. It 
Xshould give lots of rules for designing programs and data files for 
Xsynergy. But neither the programs nor the files should cost too much 
Xmore than the expedient variety. While we're looking to a future with 
XCD-ROMs and perpendicular recording, the standard must work well on 
Xfloppy disks.
X
XFor program portability, simplicity, and efficiency, formats should 
Xbe designed with more than one implementation style in mind. (In practice, 
Xpure stream I/O is adequate although random access makes it easier 
Xto write files.) It ought to be possible to read one of many objects 
Xin a file without scanning all the preceding data. Some programs need 
Xto read and play out their data in real time, so we need good compromises 
Xbetween generality and efficiency.
X
XAs much as we need standards, they can't hold up product schedules. 
XSo we also need a kind of decentralized extensibility where any software 
Xdeveloper can define and refine new object types without some "standards 
Xauthority" in the loop. Developers must be able to extend existing 
Xformats in a forward- and backward-compatible way. A central repository 
Xfor design information and example programs can help us take full 
Xadvantage of the standard.
X
XFor convenience, data formats should heed the restrictions of various 
Xprocessors and environments. E.g. word-alignment greatly helps 68000 
Xaccess at insignificant cost to 8088 programs.
X
XOther goals include the ability to share common elements over a list 
Xof objects and the ability to construct composite objects containing 
Xother data objects with structural information like directories.
X
XAnd finally, "Simple things should be simple and complex things should 
Xbe possible."	Alan Kay.
X
XThink Ahead
X
XLet's think ahead and build programs that read and write files for 
Xeach other and for programs yet to be designed. Build data formats 
Xto last for future computers so long as the overhead is acceptable. 
XThis extends the usefulness and life of today's programs and data.
X
XTo maximize interconnectivity, the standard file structure and the 
Xspecific object formats must all be general and extensible. Think 
Xahead when designing an object. It should serve many purposes and 
Xallow many programs to store and read back all the information they 
Xneed; even squeeze in custom data. Then a programmer can store the 
Xavailable data and is encouraged to include fixed contextual details. 
XRecipient programs can read the needed parts, skip unrecognized stuff, 
Xdefault missing data, and use the stored context to help transform 
Xthe data as needed.
X
XScope
X
XIFF addresses these needs by defining a standard file structure, some 
Xinitial data object types, ways to define new types, and rules for 
Xaccessing these files. We can accomplish a great deal by writing programs 
Xaccording to this standard, but don't expect direct compatibility 
Xwith existing software. We'll need conversion programs to bridge the 
Xgap from the old world.
X
XIFF is geared for computers that readily process information in 8-bit 
Xbytes. It assumes a "physical layer" of data storage and transmission 
Xthat reliably maintains "files" as strings of 8-bit bytes. The standard 
Xtreats a "file" as a container of data bytes and is independent of 
Xhow to find a file and whether it has a byte count.
X
XThis standard does not by itself implement a clipboard for cutting 
Xand pasting data between programs. A clipboard needs software to mediate 
Xaccess, to maintain a "contents version number" so programs can detect 
Xupdates, and to manage the data in "virtual memory".
X
XData Abstraction
X
XThe basic problem is how to represent information  in a way that's 
Xprogram-independent, compiler- independent, machine-independent, and 
Xdevice-independent.
X
XThe computer science approach is "data abstraction", also known as 
X"objects", "actors", and "abstract data types". A data abstraction 
Xhas a "concrete representation" (its storage format), an "abstract 
Xrepresentation" (its capabilities and uses), and access procedures 
Xthat isolate all the calling software from the concrete representation. 
XOnly the access procedures touch the data storage. Hiding mutable 
Xdetails behind an interface is called "information hiding". What data 
Xabstraction does is abstract from details of implementing the object, 
Xnamely the selected storage representation and algorithms for manipulating 
Xit.
X
XThe power of this approach is modularity. By adjusting the access 
Xprocedures we can extend and restructure the data without impacting 
Xthe interface or its callers. Conversely, we can extend and restructure 
Xthe interface and callers without making existing data obsolete. It's 
Xgreat for interchange!
X
XBut we seem to need the opposite: fixed file formats for all programs 
Xto access. Actually, we could file data abstractions ("filed objects") 
Xby storing the data and access procedures together. We'd have to encode 
Xthe access procedures in a standard machine-independent programming 
Xlanguage   la PostScript. Even still, the interface can't evolve freely 
Xsince we can't update all copies of the access procedures. So we'll 
Xhave to design our abstract representations for limited evolution 
Xand occasional revolution (conversion).
X
XIn any case, today's microcomputers can't practically store data abstractions. 
XThey can do the next best thing: store arbitrary types of data in 
X"data chunks", each with a type identifier and a length count. The 
Xtype identifier is a reference by name to the access procedures (any 
Xlocal implementation). The length count enables storage-level object 
Xoperations like "copy" and "skip to next" independent of object type.
X
XChunk writing is straightforward. Chunk reading requires a trivial 
Xparser to scan each chunk and dispatch to the proper access/conversion 
Xprocedure. Reading chunks nested inside other chunks requires recursion, 
Xbut no lookahead or backup.
X
XThat's the main idea of IFF. There are, of course, a few other detailsI
X
XPrevious Work
X
XWhere our needs are similar, we borrow from existing standards.
X
XOur basic need to move data between independently developed programs 
Xis similar to that addressed by the Apple Macintosh desk scrap or 
X"clipboard" [Inside Macintosh chapter "Scrap Manager"]. The Scrap 
XManager works closely with the Resource Manager, a handy filer and 
Xswapper for data objects (text strings, dialog window templates, pictures, 
XfontsI) including types yet to be designed [Inside Macintosh chapter 
X"Resource Manager"]. The Resource Manager is a kin to Smalltalk's 
Xobject swapper.
X
XWe will probably write a Macintosh desk accessory that converts IFF 
Xfiles to and from the Macintosh clipboard for quick and easy interchange 
Xwith programs like MacPaint and Resource Mover.
X
XMacintosh uses a simple and elegant scheme of 4-character "identifiers" 
Xto identify resource types, clipboard format types, file types, and 
Xfile creator programs. Alternatives are unique ID numbers assigned 
Xby a central authority or by hierarchical authorities, unique ID numbers 
Xgenerated by algorithm, other fixed length character strings, and 
Xvariable length strings. Character string identifiers double as readable 
Xsignposts in data files and programs. The choice of 4 characters is 
Xa good tradeoff between storage space, fetch/compare/store time, and 
Xname space size. We'll honor Apple's designers by adopting this scheme.
X
X"PICT" is a good example of a standard structured graphics format 
X(including raster images) and its many uses [Inside Macintosh chapter 
X"QuickDraw"]. Macintosh provides QuickDraw routines in ROM to create, 
Xmanipulate, and display PICTs. Any application can create a PICT by 
Xsimply asking QuickDraw to record a sequence of drawing commands. 
XSince it's just as easy to ask QuickDraw to render a PICT to a screen 
Xor a printer, it's very effective to pass them between programs, say 
Xfrom an illustrator to a word processor. An important feature is the 
Xability to store "comments" in a PICT which QuickDraw will ignore. 
XActually, it passes them to your optional custom "comment handler".
X
XPostScript, Adobe's print file standard, is a more general way to 
Xrepresent any print image (which is a specification for putting marks 
Xon paper) [PostScript Language Manual]. In fact, PostScript is a full-fledged 
Xprogramming language. To interpret a PostScript program is to render 
Xa document on a raster output device. The language is defined in layers: 
Xa lexical layer of identifiers, constants, and operators; a layer 
Xof reverse polish semantics including scope rules and a way to define 
Xnew subroutines; and a printing-specific layer of built-in identifiers 
Xand operators for rendering graphic images. It is clearly a powerful 
X(Turing equivalent) image definition language. PICT and a subset of 
XPostScript are candidates for structured graphics standards.
X
XA PostScript document can be printed on any raster output device (including 
Xa display) but cannot generally be edited. That's because the original 
Xflexibility and constraints have been discarded. Besides, a PostScript 
Xprogram may use arbitrary computation to supply parameters like placement 
Xand size to each operator. A QuickDraw PICT, in comparison, is a more 
Xrestricted format of graphic primitives parameterized by constants. 
XSo a PICT can be edited at the level of the primitives, e.g. move 
Xor thicken a line. It cannot be edited at the higher level of, say, 
Xthe bar chart data which generated the picture.
X
XPostScript has another limitation: Not all kinds of data amount to 
Xmarks on paper. A musical instrument description is one example. PostScript 
Xis just not geared for such uses.
X
X"DIF" is another example of data being stored in a general format 
Xusable by future programs [DIF Technical Specification]. DIF is a 
Xformat for spreadsheet data interchange. DIF and PostScript are both 
Xexpressed in plain ASCII text files. This is very handy for printing, 
Xdebugging, experimenting, and transmitting across modems. It can have 
Xsubstantial cost in compaction and read/write work, depending on use. 
XWe won't store IFF files this way but we could define an ASCII alternate 
Xrepresentation with a converter program.
X
XInterScript is Xerox' standard for interchange of editable documents 
X[Introduction to InterScript]. It approaches a harder problem: How 
Xto represent editable word processor documents that may contain formatted 
Xtext, pictures, cross-references like figure numbers, and even highly 
Xspecialized objects like mathematical equations? InterScript aims 
Xto define one standard representation for each kind of information. 
XEach InterScript-compatible editor is supposed to preserve the objects 
Xit doesn't understand and even maintain nested cross-references. So 
Xa simple word processor would let you edit the text of a fancy document 
Xwithout discarding the equations or disrupting the equation numbers.
X
XOur task is similarly to store high level information and preserve 
Xas much content as practical while moving it between programs. But 
Xwe need to span a larger universe of data types and cannot expect 
Xto centrally define them all. Fortunately, we don't need to make programs 
Xpreserve information that they don't understand. And for better or 
Xworse, we don't have to tackle general-purpose cross-references yet.
X
X
X
X3. Primitive Data Types
X
XAtomic components such as integers and characters that are interpretable 
Xdirectly by the CPU are specified in one format for all processors. 
XWe chose a format that's most convenient for the Motorola MC68000 
Xprocessor [M68000 16/32-Bit Microprocessor Programmer's Reference 
XManual].
X
XN.B.: Part 3 dictates the format for "primitive" data types where and 
Xonly where used in the overall file structure and standard kinds of 
Xchunks (Cf. Chunks). The number of such occurrences will be small 
Xenough that the costs of conversion, storage, and management of processor-
Xspecific files would far exceed the costs of conversion during I/O by "foreign" 
Xprograms. A particular data chunk may be specified with a different 
Xformat for its internal primitive types or with processor- or environment-
Xspeci fic variants if necessary to optimize local usage. Since that hurts 
Xdata interchange, it's not recommended. (Cf. Designing New Data Sections, 
Xin Part 4.)
X
XAlignment
X
XAll data objects larger than a byte are aligned on even byte addresses 
Xrelative to the start of the file. This may require padding. Pad bytes 
Xare to be written as zeros, but don't count on that when reading.
X
XThis means that every odd-length "chunk" (see below) must be padded 
Xso that the next one will fall on an even boundary. Also, designers 
Xof structures to be stored in chunks should include pad fields where 
Xneeded to align every field larger than a byte. Zeros should be stored 
Xin all the pad bytes.
X
XJustification: Even-alignment causes a little extra work for files 
Xthat are used only on certain processors but allows 68000 programs 
Xto construct and scan the data in memory and do block I/O. You just 
Xadd an occasional pad field to data structures that you're going to 
Xblock read/write or else stream read/write an extra byte. And the 
Xsame source code works on all processors. Unspecified alignment, on 
Xthe other hand, would force 68000 programs to (dis)assemble word and 
Xlong-word data one byte at a time. Pretty cumbersome in a high level 
Xlanguage. And if you don't conditionally compile that out for other 
Xprocessors, you won't gain anything.
X
XNumbers
X
XNumeric types supported are two's complement binary integers in the 
Xformat used by the MC68000 processor high byte first, high word first the 
Xreverse of 8088 and 6502 format. They could potentially include signed 
Xand unsigned 8, 16, and 32 bit integers but the standard only uses 
Xthe following:
X
XUBYTE	 8 bits unsigned
XWORD	16 bits signed
XUWORD	16 bits unsigned
XLONG	32 bits signed
X
XThe actual type definitions depend on the CPU and the compiler. In 
Xthis document, we'll express data type definitions in the C programming 
Xlanguage. [See C, A Reference Manual.] In 68000 Lattice C:
X
Xtypedef unsigned char	UBYTE;	/*  8 bits unsigned	*/
Xtypedef short	WORD;	/* 16 bits signed	*/
Xtypedef unsigned short	UWORD;	/* 16 bits unsigned	*/
Xtypedef long	LONG;	/* 32 bits signed	*/
X
XCharacters
X
XThe following character set is assumed wherever characters are used, 
Xe.g. in text strings, IDs, and TEXT chunks (see below).
X
XCharacters are encoded in 8-bit ASCII. Characters in the range NUL 
X(hex 0) through DEL (hex 7F) are well defined by the 7-bit ASCII standard. 
XIFF uses the graphic group RJS (SP, hex 20) through R~S (hex 7E).
X
XMost of the control character group hex 01 through hex 1F have no 
Xstandard meaning in IFF. The control character LF (hex 0A) is defined 
Xas a "newline" character. It denotes an intentional line break, that 
Xis, a paragraph or line terminator. (There is no way to store an automatic 
Xline break. That is strictly a function of the margins in the environment 
Xthe text is placed.) The control character ESC (hex 1B) is a reserved 
Xescape character under the rules of ANSI standard 3.64-1979 American 
XNational Standard Additional Control Codes for Use with ASCII, ISO 
Xstandard 2022, and ISO/DIS standard 6429.2.
X
XCharacters in the range hex 7F through hex FF are not globally defined 
Xin IFF. They are best left reserved for future standardization. But 
Xnote that the FORM type FTXT (formatted text) defines the meaning 
Xof these characters within FTXT forms. In particular, character values 
Xhex 7F through hex 9F are control codes while characters hex A0 through 
Xhex FF are extended graphic characters like  , as per the ISO and 
XANSI standards cited above. [See the supplementary document "FTXT" 
XIFF Formatted Text.]
X
XDates
X
XA "creation date" is defined as the date and time a stream of data 
Xbytes was created. (Some systems call this a "last modified date".) 
XEditing some data changes its creation date. Moving the data between 
Xvolumes or machines does not.
X
XThe IFF standard date format will be one of those used in MS-DOS, 
XMacintosh, or Amiga DOS (probably a 32-bit unsigned number of seconds 
Xsince a reference point). Issue: Investigate these three.
X
XType IDs
X
XA "type ID", "property name", "FORM type", or any other IFF identifier 
Xis a 32-bit value: the concatenation of four ASCII characters in the 
Xrange R S (SP, hex 20) through R~S (hex 7E). Spaces (hex 20) should 
Xnot precede printing characters; trailing spaces are ok. Control characters 
Xare forbidden.
X
Xtypedef CHAR ID[4];
X
XIDs are compared using a simple 32-bit case-dependent equality test.
X
XData section type IDs (aka FORM types) are restriced IDs. (Cf. Data 
XSections.) Since they may be stored in filename extensions (Cf. Single 
XPurpose Files) lower case letters and punctuation marks are forbidden. 
XTrailing spaces are ok.
X
XCarefully choose those four characters when you pick a new ID. Make 
Xthem mnemonic so programmers can look at an interchange format file 
Xand figure out what kind of data it contains. The name space makes 
Xit possible for developers scattered around the globe to generate 
XID values with minimal collisions so long as they choose specific 
Xnames like "MUS4" instead of general ones like "TYPE" and "FILE". 
XEA will "register" new FORM type IDs and format descriptions as they're 
Xdevised, but collisions will be improbable so there will be no pressure 
Xon this "clearinghouse" process. Appendix A has a list of currently 
Xdefined IDs.
X
XSometimes it's necessary to make data format changes that aren't backward 
Xcompatible. Since IDs are used to denote data formats in IFF, new 
XIDs are chosen to denote revised formats. Since programs won't read 
Xchunks whose IDs they don't recognize (see Chunks, below), the new 
XIDs keep old programs from stumbling over new data. The conventional 
Xway to chose a "revision" ID is to increment the last character if 
Xit's a digit or else change the last character to a digit. E.g. first 
Xand second revisions of the ID "XY" would be "XY1" and "XY2". Revisions 
Xof "CMAP" would be "CMA1" and "CMA2".
X
XChunks
X
XChunks are the building blocks in the IFF structure. The form expressed 
Xas a C typedef is:
X
Xtypedef struct {
X	ID	ckID;
X	LONG	ckSize;	/* sizeof(ckData) */
X	UBYTE	ckData[/* ckSize */];
X	} Chunk;
X
XWe can diagram an example chunk a "CMAP" chunk containing 12 data 
Xbytes like this:
X			----------------
X		ckID:	|    'CMAP'    |
X		ckSize: |      12      |
X		ckData: | 0, 0, 0, 32  |   -------- 
X			| 0, 0, 64, 0  |    12 bytes
X			| 0, 0, 64, 0  |   ---------
X			----------------
X
XThe fixed header part means "Here's a type ckID chunk with ckSize 
Xbytes of data."
X
XThe ckID identifies the format and purpose of the chunk. As a rule, 
Xa program must recognize ckID to interpret ckData. It should skip 
Xover all unrecognized chunks. The ckID also serves as a format version 
Xnumber as long as we pick new IDs to identify new formats of ckData 
X(see above).
X
XThe following ckIDs are universally reserved to identify chunks with 
Xparticular IFF meanings: "LIST", "FORM", "PROP", "CAT ", and "    
X". The special ID "    " (4 spaces) is a ckID for "filler" chunks, 
Xthat is, chunks that fill space but have no meaningful contents. The 
XIDs "LIS1" through "LIS9", "FOR1" through "FOR9", and "CAT1" through 
X"CAT9" are reserved for future "version number" variations. All IFF-compatible 
Xsoftware must account for these 23 chunk IDs. Appendix A has a list 
Xof predefined IDs.
X
XThe ckSize is a logical block size how many data bytes are in ckData. 
XIf ckData is an odd number of bytes long, a 0 pad byte follows which 
Xis not included in ckSize. (Cf. Alignment.) A chunk's total physical 
Xsize is ckSize rounded up to an even number plus the size of the header. 
XSo the smallest chunk is 8 bytes long with ckSize = 0. For the sake 
Xof following chunks, programs must respect every chunk's ckSize as 
Xa virtual end-of-file for reading its ckData even if that data is 
Xmalformed, e.g. if nested contents are truncated.
X
XWe can describe the syntax of a chunk as a regular expression with 
X"#" representing the ckSize, i.e. the length of the following {braced} 
Xbytes. The "[0]" represents a sometimes needed pad byte. (The regular 
Xexpressions in this document are collected in Appendix A along with 
Xan explanation of notation.)
X
XChunk	::= ID #{ UBYTE* } [0]
X
XOne chunk output technique is to stream write a chunk header, stream 
Xwrite the chunk contents, then random access back to the header to 
Xfill in the size. Another technique is to make a preliminary pass 
Xover the data to compute the size, then write it out all at once.
X
XStrings, String Chunks, and String Properties
X
XIn a string of ASCII text, LF denotes a forced line break (paragraph 
Xor line terminator). Other control characters are not used. (Cf. Characters.)
X
XThe ckID for a chunk that contains a string of plain, unformatted 
Xtext is "TEXT". As a practical matter, a text string should probably 
Xnot be longer than 32767 bytes. The standard allows up to 231 - 1 
Xbytes.
X
XWhen used as a data property (see below), a text string chunk may 
Xbe 0 to 255 characters long. Such a string is readily converted to 
Xa C string or a Pascal STRING[255]. The ckID of a property must be 
Xthe property name, not "TEXT".
X
XWhen used as a part of a chunk or data property, restricted C string 
Xformat is normally used. That means 0 to 255 characters followed by 
Xa NUL byte (ASCII value 0).
X
XData Properties
X
XData properties specify attributes for following (non-property) chunks. 
XA data property essentially says "identifier = value", for example 
X"XY = (10, 200)", telling something about following chunks. Properties 
Xmay only appear inside data sections ("FORM" chunks, cf. Data Sections) 
Xand property sections ("PROP" chunks, cf. Group PROP).
X
XThe form of a data property is a special case of Chunk. The ckID is 
Xa property name as well as a property type. The ckSize should be small 
Xsince data properties are intended to be accumulated in RAM when reading 
Xa file. (256 bytes is a reasonable upper bound.) Syntactically:
X
XProperty	::= Chunk
X
XWhen designing a data object, use properties to describe context information 
Xlike the size of an image, even if they don't vary in your program. 
XOther programs will need this information.
X
XThink of property settings as assignments to variables in a programming 
Xlanguage. Multiple assignments are redundant and local assignments 
Xtemporarily override global assignments. The order of assignments 
Xdoesn't matter as long as they precede the affected chunks. (Cf. LISTs, 
XCATs, and Shared Properties.)
X
XEach object type (FORM type) is a local name space for property IDs. 
XThink of a "CMAP" property in a "FORM ILBM" as the qualified ID "ILBM.CMAP". 
XProperty IDs specified when an object type is designed (and therefore 
Xknown to all clients) are called "standard" while specialized ones 
Xadded later are "nonstandard".
X
XLinks
X
XIssue: A standard mechanism for "links" or "cross references" is very 
Xdesirable for things like combining images and sounds into animations. 
XPerhaps we'll define "link" chunks within FORMs that refer to other 
XFORMs or to specific chunks within the same and other FORMs. This 
Xneeds further work. EA IFF 1985 has no standard link mechanism.
X
XFor now, it may suffice to read a list of, say, musical instruments, 
Xand then just refer to them within a musical score by index number.
X
XFile References
X
XIssue: We may need a standard form for references to other files. 
XA "file ref" could name a directory and a file in the same type of 
Xoperating system as the ref's originator. Following the reference 
Xwould expect the file to be on some mounted volume. In a network environment, 
Xa file ref could name a server, too.
X
XIssue: How can we express operating-system independent file refs?
X
XIssue: What about a means to reference a portion of another file? 
XWould this be a "file ref" plus a reference to a "link" within the 
Xtarget file?
X
X
X
X4. Data Sections
X
XThe first thing we need of a file is to check: Does it contain IFF 
Xdata and, if so, does it contain the kind of data we're looking for? 
XSo we come to the notion of a "data section".
X
XA "data section" or IFF "FORM" is one self-contained "data object" 
Xthat might be stored in a file by itself. It is one high level data 
Xobject such as a picture or a sound effect. The IFF structure "FORM" 
Xmakes it self- identifying. It could be a composite object like a 
Xmusical score with nested musical instrument descriptions.
X
XGroup FORM
X
XA data section is a chunk with ckID "FORM" and this arrangement:
X
XFORM	::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)* 
X}
XFormType	::= ID
XLocalChunk	::= Property | Chunk
X
XThe ID "FORM" is a syntactic keyword like "struct" in C. Think of 
Xa "struct ILBM" containing a field "CMAP". If you see "FORM" you'll 
Xknow to expect a FORM type ID (the structure name, "ILBM" in this 
Xexample) and a particular contents arrangement or "syntax" (local 
Xchunks, FORMs, LISTs, and CATs). (LISTs and CATs are discussed in 
Xpart 5, below.) A "FORM ILBM", in particular, might contain a local 
Xchunk "CMAP", an "ILBM.CMAP" (to use a qualified name).
X
XSo the chunk ID "FORM" indicates a data section. It implies that the 
Xchunk contains an ID and some number of nested chunks. In reading 
Xa FORM, like any other chunk, programs must respect its ckSize as 
Xa virtual end-of-file for reading its contents, even if they're truncated.
X
XThe FormType (or FORM type) is a restricted ID that may not contain 
Xlower case letters or punctuation characters. (Cf. Type IDs. Cf. Single 
XPurpose Files.)
X
XThe type-specific information in a FORM is composed of its "local 
Xchunks": data properties and other chunks. Each FORM type is a local 
Xname space for local chunk IDs. So "CMAP" local chunks in other FORM 
Xtypes may be unrelated to "ILBM.CMAP". More than that, each FORM type 
Xdefines semantic scope. If you know what a FORM ILBM is, you'll know 
Xwhat an ILBM.CMAP is.
X
XLocal chunks defined when the FORM type is designed (and therefore 
Xknown to all clients of this type) are called "standard" while specialized 
Xones added later are "nonstandard".
X
XAmong the local chunks, property chunks give settings for various 
Xdetails like text font while the other chunks supply the essential 
Xinformation. This distinction is not clear cut. A property setting 
Xcancelled by a later setting of the same property has effect only 
Xon data chunks in between. E.g. in the sequence:
X
Xprop1 = x  (propN = value)*  prop1 = y
X
Xwhere the propNs are not prop1, the setting prop1 = x has no effect.
X
XThe following universal chunk IDs are reserved inside any FORM: "LIST", 
X"FORM", "PROP", "CAT ", "JJJJ", "LIS1" through "LIS9", "FOR1" through 
X"FOR9", and "CAT1" through "CAT9". (Cf. Chunks. Cf. Group LIST. Cf. 
XGroup PROP.) For clarity, these universal chunk names may not be FORM 
Xtype IDs, either.
X
XPart 5, below, talks about grouping FORMs into LISTs and CATs. They 
Xlet you group a bunch of FORMs but don't impose any particular meaning 
Xor constraints on the grouping. Read on.
X
XComposite FORMs
X
XA FORM chunk inside a FORM is a full-fledged data section. This means 
Xyou can build a composite object like a multi-frame animation sequence 
Xfrom available picture FORMs and sound effect FORMs. You can insert 
Xadditional chunks with information like frame rate and frame count.
X
XUsing composite FORMs, you leverage on existing programs that create 
Xand edit the component FORMs. Those editors may even look into your 
Xcomposite object to copy out its type of component, although it'll 
Xbe the rare program that's fancy enough to do that. Such editors are 
Xnot allowed to replace their component objects within your composite 
Xobject. That's because the IFF standard lets you specify consistency 
Xrequirements for the composite FORM such as maintaining a count or 
Xa directory of the components. Only programs that are written to uphold 
Xthe rules of your FORM type should create or modify such FORMs.
X
XTherefore, in designing a program that creates composite objects, 
Xyou are strongly requested to provide a facility for your users to 
Ximport and export the nested FORMs. Import and export could move the 
Xdata through a clipboard or a file.
X
XHere are several existing FORM types and rules for defining new ones.
X
XFTXT
X
XAn FTXT data section contains text with character formatting information 
Xlike fonts and faces. It has no paragraph or document formatting information 
Xlike margins and page headers. FORM FTXT is well matched to the text 
Xrepresentation in Amiga's Intuition environment. See the supplemental 
Xdocument "FTXT" IFF Formatted Text.
X
XILBM
X
X"ILBM" is an InterLeaved BitMap image with color map; a machine-independent 
Xformat for raster images. FORM ILBM is the standard image file format 
Xfor the Commodore-Amiga computer and is useful in other environments, 
Xtoo. See the supplemental document "ILBM" IFF Interleaved Bitmap.
X
XPICS
X
XThe data chunk inside a "PICS" data section has ID "PICT" and holds 
Xa QuickDraw picture. Issue: Allow more than one PICT in a PICS? See 
XInside Macintosh chapter "QuickDraw" for details on PICTs and how 
Xto create and display them on the Macintosh computer.
X
XThe only standard property for PICS is "XY", an optional property 
Xthat indicates the position of the PICT relative to "the big picture". 
XThe contents of an XY is a QuickDraw Point.
X
XNote: PICT may be limited to Macintosh use, in which case there'll 
Xbe another format for structured graphics in other environments.
X
XOther Macintosh Resource Types
X
XSome other Macintosh resource types could be adopted for use within 
XIFF files; perhaps MWRT, ICN, ICN#, and STR#.
X
XIssue: Consider the candidates and reserve some more IDs.
X
XDesigning New Data Sections
X
XSupplemental documents will define additional object types. A supplement 
Xneeds to specify the object's purpose, its FORM type ID, the IDs and 
Xformats of standard local chunks, and rules for generating and interpreting 
Xthe data. It's a good idea to supply typedefs and an example source 
Xprogram that accesses the new object. See "ILBM" IFF Interleaved Bitmap 
Xfor a good example.
X
XAnyone can pick a new FORM type ID but should reserve it with Electronic 
XArts at their earliest convenience. [Issue: EA contact person? Hand 
Xthis off to another organization?] While decentralized format definitions 
Xand extensions are possible in IFF, our preference is to get design 
Xconsensus by committee, implement a program to read and write it, 
Xperhaps tune the format, and then publish the format with example 
Xcode. Some organization should remain in charge of answering questions 
Xand coordinating extensions to the format.
X
XIf it becomes necessary to revise the design of some data section, 
Xits FORM type ID will serve as a version number (Cf. Type IDs). E.g. 
Xa revised "VDEO" data section could be called "VDE1". But try to get 
Xby with compatible revisions within the existing FORM type.
X
XIn a new FORM type, the rules for primitive data types and word-alignment 
X(Cf. Primitive Data Types) may be overriden for the contents of its 
Xlocal chunks but not for the chunk structure itself if your documentation 
Xspells out the deviations. If machine-specific type variants are needed, 
Xe.g. to store vast numbers of integers in reverse bit order, then 
Xoutline the conversion algorithm and indicate the variant inside each 
Xfile, perhaps via different FORM types. Needless to say, variations 
Xshould be minimized.
X
XIn designing a FORM type, encapsulate all the data that other programs 
Xwill need to interpret your files. E.g. a raster graphics image should 
Xspecify the image size even if your program always uses 320 x 200 
Xpixels x 3 bitplanes. Receiving programs are then empowered to append 
Xor clip the image rectangle, to add or drop bitplanes, etc. This enables 
Xa lot more compatibility.
X
XSeparate the central data (like musical notes) from more specialized 
Xinformation (like note beams) so simpler programs can extract the 
Xcentral parts during read-in. Leave room for expansion so other programs 
Xcan squeeze in new kinds of information (like lyrics). And remember 
Xto keep the property chunks manageably short let's say 2 256 bytes.
X
XWhen designing a data object, try to strike a good tradeoff between 
Xa super-general format and a highly-specialized one. Fit the details 
Xto at least one particular need, for example a raster image might 
Xas well store pixels in the current machine's scan order. But add 
Xthe kind of generality that makes it usable with foreseeable hardware 
Xand software. E.g. use a whole byte for each red, green, and blue 
Xcolor value even if this year's computer has only 4-bit video DACs. 
XThink ahead and help other programs so long as the overhead is acceptable. 
XE.g. run compress a raster by scan line rather than as a unit so future 
Xprograms can swap images by scan line to and from secondary storage.
X
XTry to design a general purpose "least common multiple" format that 
Xencompasses the needs of many programs without getting too complicated. 
XLet's coalesce our uses around a few such formats widely separated 
Xin the vast design space. Two factors make this flexibility and simplicity 
Xpractical. First, file storage space is getting very plentiful, so 
Xcompaction is not a priority. Second, nearly any locally-performed 
Xdata conversion work during file reading and writing will be cheap 
Xcompared to the I/O time.
X
XIt must be ok to copy a LIST or FORM or CAT intact, e.g. to incorporate 
Xit into a composite FORM. So any kind of internal references within 
Xa FORM must be relative references. They could be relative to the 
Xstart of the containing FORM, relative from the referencing chunk, 
Xor a sequence number into a collection.
X
XWith composite FORMs, you leverage on existing programs that create 
Xand edit the components. If you write a program that creates composite 
Xobjects, please provide a facility for your users to import and export 
Xthe nested FORMs. The import and export functions may move data through 
Xa separate file or a clipboard.
X
XFinally, don't forget to specify all implied rules in detail.
X
X
X
X5. LISTs, CATs, and Shared Properties
X
XData often needs to be grouped together like a list of icons. Sometimes 
Xa trick like arranging little images into a big raster works, but 
Xgenerally they'll need to be structured as a first class group. The 
Xobjects "LIST" and "CAT" are IFF-universal mechanisms for this purpose.
X
XProperty settings sometimes need to be shared over a list of similar 
Xobjects. E.g. a list of icons may share one color map. LIST provides 
Xa means called "PROP" to do this. One purpose of a LIST is to define 
Xthe scope of a PROP. A "CAT", on the other hand, is simply a concatenation 
Xof objects.
X
XSimpler programs may skip LISTs and PROPs altogether and just handle 
XFORMs and CATs. All "fully-conforming" IFF programs also know about 
X"CAT ", "LIST", and "PROP". Any program that reads a FORM inside a 
XLIST must process shared PROPs to correctly interpret that FORM.
X
XGroup CAT
X
XA CAT is just an untyped group of data objects.
X
XStructurally, a CAT is a chunk with chunk ID "CAT " containing a "contents 
Xtype" ID followed by the nested objects. The ckSize of each contained 
Xchunk is essentially a relative pointer to the next one.
X
XCAT	::= "CAT " #{ ContentsType (FORM | LIST | CAT)* }
XContentsType	::= ID	-- a hint or an "abstract data type" ID
X
XIn reading a CAT, like any other chunk, programs must respect it's 
XckSize as a virtual end-of-file for reading the nested objects even 
Xif they're malformed or truncated.
X
XThe "contents type" following the CAT's ckSize indicates what kind 
Xof FORMs are inside. So a CAT of ILBMs would store "ILBM" there. It's 
Xjust a hint. It may be used to store an "abstract data type". A CAT 
Xcould just have blank contents ID ("JJJJ") if it contains more than 
Xone kind of FORM.
X
XCAT defines only the format of the group. The group's meaning is open 
Xto interpretation. This is like a list in LISP: the structure of cells 
Xis predefined but the meaning of the contents as, say, an association 
Xlist depends on use. If you need a group with an enforced meaning 
X(an "abstract data type" or Smalltalk "subclass"), some consistency 
Xconstraints, or additional data chunks, use a composite FORM instead 
X(Cf. Composite FORMs).
X
XSince a CAT just means a concatenation of objects, CATs are rarely 
Xnested. Programs should really merge CATs rather than nest them.
X
XGroup LIST
X
XA LIST defines a group very much like CAT but it also gives a scope 
Xfor PROPs (see below). And unlike CATs, LISTs should not be merged 
Xwithout understanding their contents.
X
XStructurally, a LIST is a chunk with ckID "LIST" containing a "contents 
Xtype" ID, optional shared properties, and the nested contents (FORMs, 
XLISTs, and CATs), in that order. The ckSize of each contained chunk 
Xis a relative pointer to the next one. A LIST is not an arbitrary 
Xlinked list the cells are simply concatenated.
X
XLIST	::= "LIST" #{ ContentsType PROP* (FORM | LIST | CAT)* }
XContentsType	::= ID
X
XGroup PROP
X
XPROP chunks may appear in LISTs (not in FORMs or CATs). They supply 
Xshared properties for the FORMs in that LIST. This ability to elevate 
Xsome property settings to shared status for a list of forms is useful 
Xfor both indirection and compaction. E.g. a list of images with the 
Xsame size and colors can share one "size" property and one "color 
Xmap" property. Individual FORMs can override the shared settings.
X
XThe contents of a PROP is like a FORM with no data chunks:
X
XPROP	::= "PROP" #{ FormType Property* }
X
XIt means, "Here are the shared properties for FORM type <<FormType>."
X
XA LIST may have at most one PROP of a FORM type, and all the PROPs 
Xmust appear before any of the FORMs or nested LISTs and CATs. You 
Xcan have subsequences of FORMs sharing properties by making each subsequence 
Xa LIST.
X
XScoping: Think of property settings as variable bindings in nested 
Xblocks of a programming language. Where in C you could write:
X
XTEXT_FONT text_font = Courier;	/* program's global default	*/
X
XFile(); {
X	TEXT_FONT text_font = TimesRoman;	/* shared setting	*/
X
X		{
X		TEXT_FONT text_font = Helvetica;  /* local setting	*/
X		Print("Hello ");	/* uses font Helvetica	*/
X		}
X
X		{
X		Print("there.");	/* uses font TimesRoman	*/
X		}
X	}
X
XAn IFF file could contain:
X
XLIST {
X	PROP TEXT {
X		FONT {TimesRoman}	/* shared setting	*/
X		}
X
X	FORM TEXT {
X		FONT {Helvetica}	/* local setting	*/
X		CHRS {Hello }		/* uses font Helvetica	*/
X		}
X
X	FORM TEXT {
X		CHRS {there.}	/* uses font TimesRoman	*/
X		}
X	}
X
XThe shared property assignments selectively override the reader's 
Xglobal defaults, but only for FORMs within the group. A FORM's own 
Xproperty assignments selectively override the global and group-supplied 
Xvalues. So when reading an IFF file, keep property settings on a stack. 
XThey're designed to be small enough to hold in main memory.
X
XShared properties are semantically equivalent to copying those properties 
Xinto each of the nested FORMs right after their FORM type IDs.
X
XProperties for LIST
X
XOptional "properties for LIST" store the origin of the list's contents 
Xin a PROP chunk for the fake FORM type "LIST". They are the properties 
Xoriginating program "OPGM", processor family "OCPU", computer type 
X"OCMP", computer serial number or network address "OSN ", and user 
Xname "UNAM". In our imperfect world, these could be called upon to 
Xdistinguish between unintended variations of a data format or to work 
Xaround bugs in particular originating/receiving program pairs. Issue: 
XSpecify the format of these properties.
X
XA creation date could also be stored in a property but let's ask that 
Xfile creating, editing, and transporting programs maintain the correct 
Xdate in the local file system. Programs that move files between machine 
Xtypes are expected to copy across the creation dates.
X
X
X
X6. Standard File Structure
X
XFile Structure Overview
X
XAn IFF file is just a single chunk of type FORM, LIST, or CAT. Therefore 
Xan IFF file can be recognized by its first 4 bytes: "FORM", "LIST", 
Xor "CAT ". Any file contents after the chunk's end are to be ignored.
X
XSince an IFF file can be a group of objects, programs that read/write 
Xsingle objects can communicate to an extent with programs that read/write 
Xgroups. You're encouraged to write programs that handle all the objects 
Xin a LIST or CAT. A graphics editor, for example, could process a 
Xlist of pictures as a multiple page document, one page at a time.
X
XPrograms should enforce IFF's syntactic rules when reading and writing 
Xfiles. This ensures robust data transfer. The public domain IFF reader/writer 
Xsubroutine package does this for you. A utility program "IFFCheck" 
Xis available that scans an IFF file and checks it for conformance 
Xto IFF's syntactic rules. IFFCheck also prints an outline of the chunks 
Xin the file, showing the ckID and ckSize of each. This is quite handy 
Xwhen building IFF programs. Example programs are also available to 
Xshow details of reading and writing IFF files.
X
XA merge program "IFFJoin" will be available that logically appends 
XIFF files into a single CAT group. It "unwraps" each input file that 
Xis a CAT so that the combined file isn't nested CATs.
X
XIf we need to revise the IFF standard, the three anchoring IDs will 
Xbe used as "version numbers". That's why IDs "FOR1" through "FOR9", 
X"LIS1" through "LIS9", and "CAT1" through "CAT9" are reserved.
X
XIFF formats are designed for reasonable performance with floppy disks. 
XWe achieve considerable simplicity in the formats and programs by 
Xrelying on the host file system rather than defining universal grouping 
Xstructures like directories for LIST contents. On huge storage systems, 
XIFF files could be leaf nodes in a file structure like a B-tree. Let's 
Xhope the host file system implements that for us!
X
XThre are two kinds of IFF files: single purpose files and scrap files. 
XThey differ in the interpretation of multiple data objects and in 
Xthe file's external type.
X
XSingle Purpose Files
X
XA single purpose IFF file is for normal "document" and "archive" storage. 
XThis is in contrast with "scrap files" (see below) and temporary backing 
Xstorage (non-interchange files).
X
XThe external file type (or filename extension, depending on the host 
Xfile system) indicates the file's contents. It's generally the FORM 
Xtype of the data contained, hence the restrictions on FORM type IDs.
X
XProgrammers and users may pick an "intended use" type as the filename 
Xextension to make it easy to filter for the relevant files in a filename 
Xrequestor. This is actually a "subclass" or "subtype" that conveniently 
Xseparates files of the same FORM type that have different uses. Programs 
Xcannot demand conformity to its expected subtypes without overly restricting 
Xdata interchange since they cannot know about the subtypes to be used 
Xby future programs that users will want to exchange data with.
X
XIssue: How to generate 3-letter MS-DOS extensions from 4-letter FORM 
Xtype IDs?
X
XMost single purpose files will be a single FORM (perhaps a composite 
XFORM like a musical score containing nested FORMs like musical instrument 
Xdescriptions). If it's a LIST or a CAT, programs should skip over 
Xunrecognized objects to read the recognized ones or the first recognized 
Xone. Then a program that can read a single purpose file can read something 
Xout of a "scrap file", too.
X
XScrap Files
X
XA "scrap file" is for maximum interconnectivity in getting data between 
Xprograms; the core of a clipboard function. Scrap files may have type 
X"IFF " or filename extension ".IFF".
X
XA scrap file is typically a CAT containing alternate representations 
Xof the same basic information. Include as many alternatives as you 
Xcan readily generate. This redundancy improves interconnectivity in 
Xsituations where we can't make all programs read and write super-general 
Xformats. [Inside Macintosh chapter "Scrap Manager".] E.g. a graphically-
Xannotated musical score might be supplemented by a stripped down 4-voice 
Xmelody and by a text (the lyrics).
X
XThe originating program should write the alternate representations 
Xin order of "preference": most preferred (most comprehensive) type 
Xto least preferred (least comprehensive) type. A receiving program 
Xshould either use the first appearing type that it understands or 
Xsearch for its own "preferred" type.
X
XA scrap file should have at most one alternative of any type. (A LIST 
Xof same type objects is ok as one of the alternatives.) But don't 
Xcount on this when reading; ignore extra sections of a type. Then 
Xa program that reads scrap files can read something out of single 
Xpurpose files.
X
XRules for Reader Programs
X
XHere are some notes on building programs that read IFF files. If you 
Xuse the standard IFF reader module "IFFR.C", many of these rules and 
Xdetails will be automatically handled. (See "Support Software" in 
XAppendix A.) We recommend that you start from the example program 
X"ShowILBM.C". You should also read up on recursive descent parsers. 
X[See, for example, Compiler Construction, An Advanced Course.]
X
X%	The standard is very flexible so many programs can exchange 
Xdata. This implies a program has to scan the file and react to what's 
Xactually there in whatever order it appears. An IFF reader program 
Xis a parser.
X
X%	For interchange to really work, programs must be willing to 
Xdo some conversion during read-in. If the data isn't exactly what 
Xyou expect, say, the raster is smaller than those created by your 
Xprogram, then adjust it. Similarly, your program could crop a large 
Xpicture, add or drop bitplanes, and create/discard a mask plane. The 
Xprogram should give up gracefully on data that it can't convert.
X
X%	If it doesn't start with "FORM", "LIST", or "CAT ", it's not 
Xan IFF-85 file.
X
X%	For any chunk you encounter, you must recognize its type ID 
Xto understand its contents.
X
X%	For any FORM chunk you encounter, you must recognize its FORM 
Xtype ID to understand the contained "local chunks". Even if you don't 
Xrecognize the FORM type, you can still scan it for nested FORMs, LISTs, 
Xand CATs of interest.
X
X%	Don't forget to skip the pad byte after every odd-length chunk.
X
X%	Chunk types LIST, FORM, PROP, and CAT are generic groups. They 
Xalways contain a subtype ID followed by chunks.
X
X%	Readers ought to handle a CAT of FORMs in a file. You may treat 
Xthe FORMs like document pages to sequence through or just use the 
Xfirst FORM.
X
X%	Simpler IFF readers completely skip LISTs. "Fully IFF-conforming" 
Xreaders are those that handle LISTs, even if just to read the first 
XFORM from a file. If you do look into a LIST, you must process shared 
Xproperties (in PROP chunks) properly. The idea is to get the correct 
Xdata or none at all.
X
X%	The nicest readers are willing to look into unrecognized FORMs 
Xfor nested FORM types that they do recognize. For example, a musical 
Xscore may contain nested instrument descriptions and an animation 
Xfile may contain still pictures.
X
XNote to programmers: Processing PROP chunks is not simple! You'll 
Xneed some background in interpreters with stack frames. If this is 
Xforeign to you, build programs that read/write only one FORM per file. 
XFor the more intrepid programmers, the next paragraph summarizes how 
Xto process LISTs and PROPs. See the general IFF reader module "IFFR.C" 
Xand the example program "ShowILBM.C" for details.
X
XAllocate a stack frame for every LIST and FORM you encounter and initialize 
Xit by copying the stack frame of the parent LIST or FORM. At the top 
Xlevel, you'll need a stack frame initialized to your program's global 
Xdefaults. While reading each LIST or FORM, store all encountered properties 
Xinto the current stack frame. In the example ShowILBM, each stack 
Xframe has a place for a bitmap header property ILBM.BMHD and a color 
Xmap property ILBM.CMAP. When you finally get to the ILBM's BODY chunk, 
Xuse the property settings accumulated in the current stack frame.
X
XAn alternate implementation would just remember PROPs encountered, 
Xforgetting each on reaching the end of its scope (the end of the containing 
XLIST). When a FORM XXXX is encountered, scan the chunks in all remembered 
XPROPs XXXX, in order, as if they appeared before the chunks actually 
Xin the FORM XXXX. This gets trickier if you read FORMs inside of FORMs.
X
XRules for Writer Programs
X
XHere are some notes on building programs that write IFF files, which 
Xis much easier than reading them. If you use the standard IFF writer 
Xmodule "IFFW.C" (see "Support Software" in Appendix A), many of these 
Xrules and details will automatically be enforced. See the example 
Xprogram "Raw2ILBM.C".
X
X%	An IFF file is a single FORM, LIST, or CAT chunk.
X
X%	Any IFF-85 file must start with the 4 characters "FORM", "LIST", 
Xor "CAT ", followed by a LONG ckSize. There should be no data after 
Xthe chunk end.
X
X%	Chunk types LIST, FORM, PROP, and CAT are generic. They always 
Xcontain a subtype ID followed by chunks. These three IDs are universally 
Xreserved, as are "LIS1" through "LIS9", "FOR1" through "FOR9", "CAT1" 
Xthrough "CAT9", and "    ".
X
X%	Don't forget to write a 0 pad byte after each odd-length chunk.
X
X%	Four techniques for writing an IFF group: (1) build the data 
Xin a file mapped into virtual memory, (2) build the data in memory 
Xblocks and use block I/O, (3) stream write the data piecemeal and 
X(don't forget!) random access back to set the group length count, 
Xand (4) make a preliminary pass to compute the length count then stream 
Xwrite the data.
X
X%	Do not try to edit a file that you don't know how to create. 
XPrograms may look into a file and copy out nested FORMs of types that 
Xthey recognize, but don't edit and replace the nested FORMs and don't 
Xadd or remove them. That could make the containing structure inconsistent. 
XYou may write a new file containing items you copied (or copied and 
Xmodified) from another IFF file, but don't copy structural parts you 
Xdon't understand.
X
X%	You must adhere to the syntax descriptions in Appendex A. E.g. 
XPROPs may only appear inside LISTs.
X
X
X
X
XAppendix A. Reference
X
XType Definitions
X
XThe following C typedefs describe standard IFF structures. Declarations 
Xto use in practice will vary with the CPU and compiler. For example, 
X68000 Lattice C produces efficient comparison code if we define ID 
Xas a "LONG". A macro "MakeID" builds these IDs at compile time.
X
X/* Standard IFF types, expressed in 68000 Lattice C.	*/
X
Xtypedef unsigned char UBYTE;	/*  8 bits unsigned	*/
Xtypedef short WORD;	/* 16 bits signed	*/
Xtypedef unsigned short UWORD;	/* 16 bits unsigned	*/
Xtypedef long LONG;	/* 32 bits signed	*/
X
Xtypedef char ID[4];	/* 4 chars in ' ' through '~'	*/
X
Xtypedef struct {
X	ID	ckID;
X	LONG	ckSize;	/* sizeof(ckData)	*/
X	UBYTE	ckData[/* ckSize */];
X	} Chunk;
X
X/* ID typedef and builder for 68000 Lattice C. */
Xtypedef LONG ID; 	/* 4 chars in ' ' through '~'	*/
X#define MakeID(a,b,c,d) ( (a)<<<<24 | (b)<<<<16 | (c)<<<<8 | (d) )
X
X/* Globally reserved IDs. */
X#define ID_FORM   MakeID('F','O','R','M')
X#define ID_LIST   MakeID('L','I','S','T')
X#define ID_PROP   MakeID('P','R','O','P')
X#define ID_CAT    MakeID('C','A','T',' ')
X#define ID_FILLER MakeID(' ',' ',' ',' ')
X
XSyntax Definitions
X
XHere's a collection of the syntax definitions in this document.
X
XChunk	::= ID #{ UBYTE* } [0]
X
XProperty	::= Chunk
X
XFORM	::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)* 
X}
XFormType	::= ID
XLocalChunk	::= Property | Chunk
X
XCAT	::= "CAT " #{ ContentsType (FORM | LIST | CAT)* }
XContentsType	::= ID	-- a hint or an "abstract data type" ID
X
XLIST	::= "LIST" #{ ContentsType PROP* (FORM | LIST | CAT)* }
XPROP	::= "PROP" #{ FormType Property* }
X
XIn this extended regular expression notation, the token "#" represents 
Xa ckSize LONG count of the following {braced} data bytes. Literal 
Xitems are shown in "quotes", [square bracketed items] are optional, 
Xand "*" means 0 or more instances. A sometimes-needed pad byte is 
Xshown as "[0]".
X
XDefined Chunk IDs
X
XThis is a table of currently defined chunk IDs. We may also borrow 
Xsome Macintosh IDs and data formats.
X
XGroup chunk IDs
X	FORM, LIST, PROP, CAT.
XFuture revision group chunk IDs
X	FOR1 I FOR9, LIS1 I LIS9, CAT1 I CAT9.
XFORM type IDs
X	(The above group chunk IDs may not be used for FORM type IDs.)
X	(Lower case letters and punctuation marks are forbidden in FORM 
Xtype IDs.)
X	8SVX 8-bit sampled sound voice, ANBM animated bitmap, FNTR raster 
Xfont, FNTV vector font, FTXT formatted text, GSCR general-use musical 
Xscore, ILBM interleaved raster bitmap image, PDEF Deluxe Print page 
Xdefinition, PICS Macintosh picture, PLBM (obsolete), USCR Uhuru Sound 
XSoftware musical score, UVOX Uhuru Sound Software Macintosh voice, 
XSMUS simple musical score, VDEO Deluxe Video Construction Set video.
XData chunk IDs
X	"JJJJ", TEXT, PICT.
XPROP LIST property IDs
X	OPGM, OCPU, OCMP, OSN, UNAM.
X
X
X
XSupport Software
X
XThese public domain C source programs are available for use in building 
XIFF-compatible programs:
X
XIFF.H, IFFR.C, IFFW.C	
X
X		IFF reader and writer package. 
X		These modules handle many of the details of reliably 
X		reading and writing IFF files.
X
XIFFCheck.C	This handy utility program scans an IFF file, checks 
X		that the contents are well formed, and prints an outline 
X		of the chunks.
X
XPACKER.H, Packer.C, UnPacker.C	
X
X		Run encoder and decoder used for ILBM files.
X
XILBM.H, ILBMR.C, ILBMW.C	
X
X		Reader and writer support routines for raster image 
X		FORM ILBM. ILBMR calls IFFR and UnPacker. ILBMW calls 
X		IFFW and Packer.
X
XShowILBM.C	
X		Example caller of IFFR and ILBMR modules. This 
X		Commodore-Amiga program reads and displays a FORM ILBM.
XRaw2ILBM.C	
X		Example ILBM writer program. As a demonstration, it 
X		reads a raw raster image file and writes the image 
X		as a FORM ILBM file.
XILBM2Raw.C	
X		Example ILBM reader program.  Reads a FORM ILBM file
X		and writes it into a raw raster image.
X
XREMALLOC.H, Remalloc.c
X
X		Memory allocation routines used in these examples.
X
XINTUALL.H	generic "include almost everything" include-file
X		with the sequence of includes correctly specified.
X
XREADPICT.H, ReadPict.c	
X
X		given an ILBM file, read it into a bitmap and 
X		a color map
X
XPUTPICT.H, PutPict.c 	
X
X		given a bitmap and a color map, save it as
X		an ILBM file.
X
XGIO.H, Gio.c	generic I/O speedup package.  Attempts to speed
X		disk I/O by buffering writes and reads.
X
Xgiocall.c	sample call to gio.
X
Xilbmdump.c	reads in ILBM file, prints out ascii representation
X		for including in C files.
X
Xbmprintc.c	prints out a C-language representation of data for
X		a bitmap.
X
X
X
XExample Diagrams
X
XHere's a box diagram for an example IFF file, a raster image FORM 
XILBM. This FORM contains a bitmap header property chunk BMHD, a color 
Xmap property chunk CMAP, and a raster data chunk BODY. This particular 
Xraster is 320 x 200 pixels x 3 bit planes uncompressed. The "0" after 
Xthe CMAP chunk represents a zero pad byte; included since the CMAP 
Xchunk has an odd length. The text to the right of the diagram shows 
Xthe outline that would be printed by the IFFCheck utility program 
Xfor this particular file.
X
X	+-----------------------------------+
X	|'FORM'		24070		    |	FORM 24070 IBLM
X	+-----------------------------------+
X	|'ILBM'				    |
X	+-----------------------------------+
X	| +-------------------------------+ |
X	| | 'BMHD'	20		  | |	.BMHD  20
X	| | 320, 200, 0, 0, 3, 0, 0, ...  | |
X	| + ------------------------------+ |
X	| | 'CMAP'	21	          | |	.CMAP  21
X	| | 0, 0, 0; 32, 0, 0; 64,0,0; .. | |
X	| +-------------------------------+ |
X	| 0				    |
X	+-----------------------------------+
X	|'BODY'		24000		    |	.BODY 24000
X	|0, 0, 0, ...			    |
X	+-----------------------------------+
X
XThis second diagram shows a LIST of two FORMs ILBM sharing a common 
XBMHD property and a common CMAP property. Again, the text on the right 
Xis an outline  a la IFFCheck.
X
X
X     +-----------------------------------------+
X     |'LIST'		48114	       	       |  LIST  48114  AAAA
X     +-----------------------------------------+
X     |'AAAA'				       |  .PROP  62  ILBM
X     |	+-----------------------------------+  |
X     |  |'PROP'		62		    |  |  
X     |  +-----------------------------------+  |
X     |	|'ILBM'				    |  |
X     |	+-----------------------------------+  |
X     |	| +-------------------------------+ |  |
X     |	| | 'BMHD'	20		  | |  |  ..BMHD  20
X     |	| | 320, 200, 0, 0, 3, 0, 0, ...  | |  |
X     |	| | ------------------------------+ |  |
X     |	| | 'CMAP'	21	          | |  |  ..CMAP  21
X     |	| | 0, 0, 0; 32, 0, 0; 64,0,0; .. | |  |
X     |	| +-------------------------------+ |  |
X     |	| 0				    |  |
X     |	+-----------------------------------+  |
X     |	+-----------------------------------+  |
X     |	|'FORM'		24012		    |  |  .FORM  24012  ILBM
X     |	+-----------------------------------+  |
X     |	|'ILBM'				    |  |  
X     |	+-----------------------------------+  |
X     |	|  +-----------------------------+  |  |
X     |	|  |'BODY'		24000    |  |  |  ..BODY  24000
X     |	|  |0, 0, 0, ...		 |  |  |
X     |	|  +-----------------------------+  |  |
X     |	+-----------------------------------+  |
X     |	+-----------------------------------+  |
X     |	|'FORM'		24012		    |  |  .FORM  24012  ILBM
X     |	+-----------------------------------+  |
X     |	|'ILBM'				    |  |
X     |	+-----------------------------------+  |
X     |	|  +-----------------------------+  |  |
X     |	|  |'BODY'		24000    |  |  |  ..BODY  24000
X     |	|  |0, 0, 0, ...		 |  |  |
X     |	|  +-----------------------------+  |  |
X     |	+-----------------------------------+  |
X     +-----------------------------------------+
X
X
X
XAppendix B. Standards Committee
X
XThe following people contributed to the design of this IFF standard:
X
XBob "Kodiak" Burns, Commodore-Amiga
XR. J. Mical, Commodore-Amiga
XJerry Morrison, Electronic Arts
XGreg Riker, Electronic Arts
XSteve Shaw, Electronic Arts
XBarry Walsh, Commodore-Amiga
//END
echo x - ftxt
sed 's/^X//' > ftxt << '//END'
X"FTXT" IFF Formatted Text
X
XDate:	November 15, 1985
XFrom:	Steve Shaw and Jerry Morrison, Electronic Arts and 
X	Bob "Kodiak" Burns, Commodore-Amiga
XStatus:	Draft 2.6
X
XDRAFT                 DRAFT             DRAFT               
XDRAFT                 DRAFT		DRAFT	
X
X1. Introduction
X
XThis memo is the IFF supplement for FORM FTXT. An FTXT is an IFF "data 
Xsection" or "FORM type" which can be an IFF file or a part of one containing 
Xa stream of text plus optional formatting information."EA IFF 85" 
Xis Electronic Arts' standard for interchange format files. (See the 
XIFF reference.)
X
XAn FTXT is an archival and interchange representation designed for 
Xthree uses. The simplest use is for a "console device" or "glass teletype" 
X(the minimal 2-D text layout means): a stream of "graphic" ("printable") 
Xcharacters plus positioning characters "space" ("SP") and line terminator 
X("LF"). This is not intended for cursor movements on a screen although 
Xit does not conflict with standard cursor-moving characters. The second 
Xuse is text that has explicit formatting information (or "looks") 
Xsuch as font family and size, typeface, etc. The third use is as the 
Xlowest layer of a structured document that also has "inherited" styles 
Xto implicitly control character looks. For that use, FORMs FTXT would 
Xbe embedded within a future document FORM type. The beauty of FTXT 
Xis that these three uses are interchangeable, that is, a program written 
Xfor one purpose can read and write the others' files. So a word processor 
Xdoes not have to write a separate plain text file to communicate with 
Xother programs.
X
XText is stored in one or more "CHRS" chunks inside an FTXT. Each CHRS 
Xcontains a stream of 8-bit text compatible with ISO and ANSI data 
Xinterchange standards. FTXT uses just the central character set from 
Xthe ISO/ANSI standards. (These two standards are henceforth called 
X"ISO/ANSI" as in "see the ISO/ANSI reference".)
X
XSince it's possible to extract just the text portions from future 
Xdocument FORM types, programs can exchange data without having to 
Xsave both plain text and formatted text representations.
X
XCharacter looks are stored as embedded control sequences within CHRS 
Xchunks. This document specifies which class of control sequences to 
Xuse: the CSI group. This document does not yet specify their meanings, 
Xe.g. which one means "turn on italic face". Consult ISO/ANSI.
X
XSection 2 defines the chunk types character stream "CHRS" and font 
Xspecifier "FONS". These are the "standard" chunks. Specialized chunks 
Xfor private or future needs can be added later. Section 3 outlines 
Xan FTXT reader program that strips a document down to plain unformatted 
Xtext. Appendix A is a code table for the 8-bit ISO/ANSI character 
Xset used here. Appendix B is an example FTXT shown as a box diagram. 
XAppendix C is a racetrack diagram of the syntax of ISO/ANSI control 
Xsequences.
X
X
XReference:
X
XAmiga[tm] is a trademark of Commodore-Amiga, Inc.
X
XElectronic Arts[tm] is a trademark of Electronic Arts.
X
XIFF: "EA IFF 85" Standard for Interchange Format Files describes the 
Xunderlying conventions for all IFF files.
X
XISO/ANSI: ISO/DIS 6429.2 and ANSI X3.64-1979. International Organization 
Xfor Standardization (ISO) and American National Standards Institute 
X(ANSI) data-interchange standards. The relevant parts of these two 
Xstandards documents are identical. ISO standard 2022 is also relevant.
X
X
X2. Standard Data and Property Chunks
X
XThe main contents of a FORM FTXT is in its character stream "CHRS" 
Xchunks. Formatting property chunks may also appear. The only formatting 
Xproperty yet defined is "FONS", a font specifier. A FORM FTXT with 
Xno CHRS represents an empty text stream. A FORM FTXT may contain nested 
XIFF FORMs, LISTs, or CATs, although a "stripping" reader (see section 
X3) will ignore them.
X
XCharacter Set
X
XFORM FTXT uses the core of the 8-bit character set defined by the 
XISO/ANSI standards cited at the start of this document. (See Appendix 
XA for a character code table.) This character set is divided into 
Xtwo "graphic" groups plus two "control" groups. Eight of the control 
Xcharacters begin ISO/ANSI standard control sequences. (See "Control 
XSequences", below.) Most control sequences and control characters 
Xare reserved for future use and for compatibility with ISO/ANSI. Current 
Xreader programs should skip them.
X
X%	C0 is the group of control characters in the range NUL (hex 
X0) through hex 1F. Of these, only LF (hex 0A) and ESC (hex 1B) are 
Xsignificant. ESC begins a control sequence. LF is the line terminator, 
Xmeaning "go to the first horizontal position of the next line". All 
Xother C0 characters are not used. In particular, CR (hex 0D) is not 
Xrecognized as a line terminator.
X
X%	G0 is the group of graphic characters in the range hex 20 through 
Xhex 7F. SP (hex 20) is the space character. DEL (hex 7F) is the delete 
Xcharacter which is not used. The rest are the standard ASCII printable 
Xcharacters "!" (hex 21) through "~" (hex 7E).
X
X%	C1 is the group of extended control characters in the range 
Xhex 80 through hex 9F. Some of these begin control sequences. The 
Xcontrol sequence starting with CSI (hex 9B) is used for FTXT formatting. 
XAll other control sequences and C1 control characters are unused.
X
X%	G1 is the group of extended graphic characters in the range 
XNBSP (hex A0) through "X" (hex FF). It is one of the alternate graphic 
Xgroups proposed for ISO/ANSI standardization.
X
XControl Sequences
X
XEight of the control characters begin ISO/ANSI standard "control sequences" 
X(or "escape sequences"). These sequences are described below and diagrammed 
Xin Appendix C.
X
XG0	::= (SP through DEL)
XG1	::= (NBSP through "X")
X
XESC-Seq	::= ESC (SP through "/")* ("0" through "~")
XShiftToG2	::= SS2 G0
XShiftToG3	::= SS3 G0
XCSI-Seq	::= CSI (SP through "?")* ("@" through "~")
XDCS-Seq	::= (DCS | OSC | PM | APC) (SP through "~" | G1)* ST
X
X"ESC-Seq" is the control sequence ESC (hex 1B), followed by zero or 
Xmore characters in the range SP through "/S (hex 20 through hex 2F), 
Xfollowed by a character in the range "0" through "~" (hex 30 through 
Xhex 7E). These sequences are reserved for future use and should be 
Xskipped by current FTXT reader programs.
X
XSS2 (hex 8E) and SS3 (hex 8F) shift the single following G0 character 
Xinto yet-to-be-defined graphic sets G2 and G3, respectively. These 
Xsequences should not be used until the character sets G2 and G3 are 
Xstandardized. A reader may simply skip the SS2 or SS3 (taking the 
Xfollowing character as a corresponding G0 character) or replace the 
Xtwo-character sequence with a character like "?" to mean "absent".
X
XFTXT uses "CSI-Seq" control sequences to store character formatting 
X(font selection by number, type face, and text size) and perhaps layout 
Xinformation (position and rotation). "CSI-Seq" control sequences start 
Xwith CSI (the "control sequence introducer", hex 9B). Syntactically, 
Xthe sequence includes zero or more characters in the range SP through 
X"?" (hex 20 through hex 3F) and a concluding character in the range 
X"@" through "~" (hex 40 through hex 7E). These sequences may be skipped 
Xby a minimal FTXT reader, i.e. one that ignores formatting information.
X
XNote: A future FTXT standardization document will explain the uses 
Xof CSI-Seq sequences for setting character face (light weight vs. 
Xmedium vs. bold, italic vs. upright, height, pitch, position, and 
Xrotation). For now, consult the ISO/ANSI references.
X
X"DCS-Seq" is the control sequences starting with DCS (hex 90), OSC 
X(hex 9D), PM (hex 9E), or APC (hex 9F), followed by zero or more characters 
Xeach of which is in the range SP through "~" (hex 20 through hex 7E) 
Xor else a G1 character, and terminated by an ST (hex 9C). These sequences 
Xare reserved for future use and should be skipped by current FTXT 
Xreader programs.
X
XData Chunk CHRS
X
XA CHRS chunk contains a sequence of 8-bit characters abiding by the 
XISO/ANSI standards cited at the start of this document. This includes 
Xthe character set and control sequences as described above and summarized 
Xin Appendicies A and C.
X
XA FORM FTXT may contain any number of CHRS chunks. Taken together, 
Xthey represent a single stream of textual information. That is, the 
Xcontents of CHRS chunks are effectively concatenated except that (1) 
Xeach control sequence must be completely within a single CHRS chunk, 
Xand (2) any formatting property chunks appearing between two CHRS 
Xchunks affects the formatting of the latter chunk's text. Any formatting 
Xsettings set by control sequences inside a CHRS carry over to the 
Xnext CHRS in the same FORM FTXT. All formatting properties stop at 
Xthe end of the FORM since IFF specifies that adjacent FORMs are independent 
Xof each other (although not independent of any properties inherited 
Xfrom an enclosing LIST or FORM).
X
XProperty Chunk FONS
X
XThe optional property "FONS" holds a FontSpecifier as defined in the 
XC declaration below. It assignes a font to a numbered "font register" 
Xso it can be referenced by number within subsequent CHRS chunks. (This 
Xfunction is not provided within the ISO and ANSI standards.) The font 
Xspecifier gives both a name and a description for the font so the 
Xrecipient program can do font substitution.
X
XBy default, CHRS text uses font 1 until it selects another font. A 
Xminimal text reader always uses font 1. If font 1 hasn't been specified, 
Xthe reader may use the local system font as font 1.
X
X	typedef struct {
X		UBYTE id;	
X			/* 0 through 9 is a font id number referenced by an 
X			 * SGR control sequence selective parameter of 10 
X			 * through 19. Other values are reserved for future 
X			 * standardization.	
X			 */
X		UBYTE pad1;   /* reserved for future use; store 0 here */
X		UBYTE proportional;	
X			/* proportional font? 0 = unknown, 1 = no, 2 = yes */ 
X		UBYTE serif;		
X			/* serif font? 0 = unknown, 1 = no, 2 = yes */
X		char name[];	
X			/* A NULL-terminated string naming preferred font. */
X		} FontSpecifier;
X	
XFields are filed in the order shown. The UBYTE fields are byte-packed 
X(2 per 16-bit word). The field pad1 is reserved for future standardization. 
XPrograms should store 0 there for now.
X
XThe field proportional indicates if the desired font is proportional 
Xwidth as opposed to fixed width. The field serif indicates if the 
Xdesired font is serif as opposed to sans serif. [Issue: Discuss font 
Xsubstitution!]
X
XFuture Properties
X
XNew optional property chunks may be defined in the future to store 
Xadditional formatting information. They will be used to represent 
Xformatting not encoded in standard ISO/ANSI control sequences and 
Xfor "inherited" formatting in structured documents. Text orientation 
Xmight be one example.
X
XPositioning Units
X
XUnless otherwise specified, position and size units used in FTXT formatting 
Xproperties and control sequences are in decipoints (720 decipoints/inch). 
XThis is ANSI/ISO Positioning Unit Mode (PUM) 2. While a metric standard 
Xmight be nice, decipoints allow the existing U.S.A. typographic units 
Xto be encoded easily, e.g. "12 points" is "120 decipoints".
X
X
X3. FTXT Stripper
X
XAn FTXT reader program can read the text and ignore all formatting 
Xand structural information in a document FORM that uses FORMs FTXT 
Xfor the leaf nodes. This amounts to stripping a document down to a 
Xstream of plain text. It would do this by skipping over all chunks 
Xexcept FTXT.CHRS (CHRS chunks found inside a FORM FTXT) and within 
Xthe FTXT.CHRS chunks skipping all control characters and control sequences. 
X(Appendix C diagrams this text scanner.) It may also read FTXT.FONS 
Xchunks to find a description for font 1.
X
XHere's a Pascal-ish program for an FTXT stripper. Given a FORM (a 
Xdocument of some kind), it scans for all FTXT.CHRS chunks. This would 
Xlikely be applied to the first FORM in an IFF file.
X
XPROCEDURE ReadFORM4CHRS();	{Read an IFF FORM for FTXT.CHRS chunks.}
XBEGIN
XIF the FORM's subtype = "FTXT"
X	THEN ReadFTXT4CHRS()
X	ELSE WHILE something left to read in the FORM DO BEGIN
X			read the next chunk header;
X			CASE the chunk's ID OF
X				"LIST", "CAT ": ReadCAT4CHRS();
X				"FORM": ReadFORM4CHRS();
X				OTHERWISE skip the chunk's body;
X				END
X			END
XEND;
X
X{Read a LIST or CAT for all FTXT.CHRS chunks.}
XPROCEDURE ReadCAT4CHRS();
X	BEGIN
XWHILE something left to read in the LIST or CAT DO BEGIN
X	read the next chunk header;
X	CASE the chunk's ID OF
X		"LIST", "CAT ": ReadCAT4CHRS();
X		"FORM": ReadFORM4CHRS();
X		"PROP": IF we're reading a LIST AND the PROP's subtype = 
X"FTXT"
X					THEN read the PROP for "FONS" chunks;
X		OTHERWISE error--malformed IFF file;
X		END
X	END
XEND;
X
XPROCEDURE ReadFTXT4CHRS();	{Read a FORM FTXT for CHRS chunks.}
XBEGIN
XWHILE something left to read in the FORM FTXT DO BEGIN
X	read the next chunk header;
X	CASE the chunk's ID OF
X		"CHRS": ReadCHRS();
X		"FONS": BEGIN
X			read the chunk's contents into a FontSpecifier variable;
X			IF the font specifier's id = 1 THEN use this font;
X			END;
X		OTHERWISE skip the chunk's body;
X		END
X	END
XEND;
X
X{Read an FTXT.CHRS. Skip all control sequences and unused control 
Xchars.}
XPROCEDURE ReadCHRS();
XBEGIN
XWHILE something left to read in the CHRS chunk DO
X	CASE read the next character OF
X		LF:  start a new output line;
X		ESC: SkipControl([' '..'/'], ['0'..'~']);
X		IN [' '..'~'], IN [NBSP..'X']: output the character;
X		SS2, SS3: ;	{Just handle the following G0 character 
X				directly, ignoring the shift to G2 or G3.}
X		CSI: SkipControl([' '..'?'], ['@'..'~']);
X		DCS, OSC, PM, APC: SkipControl([' '..'~'] + [NBSP..'X'], [ST]);
X		END
XEND;
X
X{Skip a control sequence of the format (rSet)* (tSet), i.e. any number 
Xof characters in the set rSet followed by a character in the set tSet.}
XPROCEDURE SkipControl(rSet, tSet);
XVAR c: CHAR;
XBEGIN
XREPEAT c := read the next character
X	UNTIL c NOT IN rSet;
XIF c NOT IN tSet
X	THEN put character c back into the input stream;
XEND
X
XThe following program is an optimized version of the above routines 
XReadFORM4CHRS and ReadCAT4CHRS for the case where you're ignoring 
Xfonts as well as formatting. It takes advantage of certain facts of 
Xthe IFF format to read a document FORM and its nested FORMs, LISTs, 
Xand CATs without a stack. In other words, it's a hack that ignores 
Xall fonts and faces to cheaply get to the plain text of the document.
X
X{Cheap scan of an IFF FORM for FTXT.CHRS chunks.}
XPROCEDURE ScanFORM4CHRS();
XBEGIN
XIF the document FORM's subtype = "FTXT"
X	THEN ReadFTXT4CHRS()
X	ELSE WHILE something left to read in the FORM DO BEGIN
X		read the next chunk header;
X		IF it's a group chunk (LIST, FORM, PROP, or CAT)
X			THEN read its subtype ID;
X		CASE the chunk's ID OF
X			"LIST", "CAT ":;	{NOTE: See explanation below.*}
X			"FORM": IF this FORM's subtype = "FTXT" THEN 
X						ReadFTXT4CHRS()
X				ELSE;	{NOTE: See explanation below.*}
X			OTHERWISE skip the chunk's body;
X			END
X		END
XEND;
X
X*Note: This implementation is subtle. After reading a group header 
Xother than FORM FTXT it just continues reading. This amounts to reading 
Xall the chunks inside that group as if they weren't nested in a group.
X
X
XAppendix A: Character Code Table
X
XThis table corresponds to the ISO/DIS 6429.2 and ANSI X3.64-1979 8-bit 
Xcharacter set standards. Only the core character set of those standards 
Xis used in FTXT.
X
XTwo G1 characters aren't defined in the standards and are shown as 
Xdark gray entries in this table. Light gray shading denotes control 
Xcharacters. (DEL is a control character although it belongs to the 
Xgraphic group G0.) The following five rare G1 characters are left 
Xblank in the table below due to limitations of available fonts: hex 
XA8, D0, DE, F0, and FE.
X
X
X
X   ISO/DIS 6429.2 and ANSI X3.64-1979 Character Code Table
X
X
X  (figure named "TextTable", viewable by ShowILBM or SeeILBM)
X
X
X[_____] [_______________________] [_____] [____________________________]
XControl   Grapic Group            Control   Graphic Group
X Group        G0                   Group         G1
X  C0                                C1
X
X"NBSP" is a "non-breaking space"
X"SHY" is a "soft-hyphen"
X
X
X
XAppendix B. FTXT Example
X
XHere's a box diagram for a simple example: "The quick brown fox jumped.Four 
Xscore and seven", written in a proportional serif font named "Roman".
X
X
X      	+-----------------------------------+   
X      	|'FORM'		24070		    |     FORM  24070  ILBM
X      	+-----------------------------------+   
X      	|'ILBM'				    |     
X      	+-----------------------------------+   
X      	| +-------------------------------+ |   
X      	| | 'BMHD'	20		  | |     .BMHD  20
X      	| | 320, 200, 0, 0, 3, 0, 0, ...  | |   
X      	| | ------------------------------+ |   
X      	| | 'CMAP'	21	          | |     .CMAP  21
X      	| | 0, 0, 0; 32, 0, 0; 64,0,0; .. | |   
X      	| +-------------------------------+ |   
X      	| +-------------------------------+ |   
X      	| |'BODY'		24000     | |     .BODY  24000
X      	| |0, 0, 0, ...			  | |   
X      	| +-------------------------------+ |   
X      	+-----------------------------------+   
X
XThe "0" after the CMAP chunk is a pad byte.
X
X
X
X
XAppendix B. Standards Committee
X
XThe following people contributed to the design of this IFF standard:
X
XBob "Kodiak" Burns, Commodore-Amiga
XR. J. Mical, Commodore-Amiga
XJerry Morrison, Electronic Arts
XGreg Riker, Electronic Arts
XSteve Shaw, Electronic Arts
XBarry Walsh, Commodore-Amiga
X
X
X
XAppendix C. ISO/ANSI Control Sequences
X
XThis is a racetrack diagram of the ISO/ANSI characters and control 
Xsequences as used in FTXT CHRS chunks.
X
X	line terminator   
X-----+-------------------> LF --------------------------------------->
X     |	ESC-Seq 
X     +-------------------> ESC ---+>----------------+--> 0 thru ~ --->
X     |				  |		    |
X     |				  +-- SP thru / <---+
X     |  printable
X     +---------------+---> SP thru ~ --+->--------------------------->
X     |		     |		       |
X     |		     +---> G1 -------->+
X     |  shift to G2				
X     +-------------------> SS2 ----> G0 ---> (produces a G2 character)
X     |  shift to G3				
X     +-------------------> SS3 ----> G0 ---> (produces a G3 character)
X     |	CSI-Seq 
X     +-------------------> CSI ---+>----------------+--> @ thru ~ --->
X     |				  |		    |
X     |				  +-- SP thru ? <---+
X     |	DCS-Seq 
X     +----------> DCS,OSC,PM,or APC --+>-------------+--+-> ST -+----> 
X     |				      |	             |  |       |
X     |				      +- SP thru ~ <-+  +-> G1 -+
X     |  discard
X     +----------> any other character ------------------------------->
X
X
X
XOf the various control sequences, only CSI-Seq is used for FTXT character 
Xformatting information. The others are reserved for future use and 
Xfor compatibility with ISO/ANSI standards. Certain character sequences 
Xare syntactically malformed, e.g. CSI followed by a C0, C1, or G1 
Xcharacter. Writer programs should not generate reserved or malformed 
Xsequences and reader programs should skip them.
X
XConsult the ISO/ANSI standards for the meaning of the CSI-Seq control 
Xsequences.
X
XThe two character set shifts SS2 and SS3 may be used when the graphic 
Xcharacter groups G2 and G3 become standardized.
X
//END
echo x - ilbm
sed 's/^X//' > ilbm << '//END'
X"ILBM" IFF Interleaved Bitmap
X
XDate:	January 17, 1986
XFrom:	Jerry Morrison, Electronic Arts
XStatus:	Released and in use
X
X1. Introduction
X
X"EA IFF 85" is Electronic Arts' standard for interchange format files. 
X"ILBM" is a format for a 2 dimensional raster graphics image, specifically 
Xan InterLeaved bitplane BitMap image with color map. An ILBM is an 
XIFF "data section" or "FORM type", which can be an IFF file or a part 
Xof one. (See the IFF reference.)
X
XAn ILBM is an archival representation designed for three uses. First, 
Xa standalone image that specifies exactly how to display itself (resolution, 
Xsize, color map, etc.). Second, an image intended to be merged into 
Xa bigger picture which has its own depth, color map, and so on. And 
Xthird, an empty image with a color map selection or "palette" for 
Xa paint program. ILBM is also intended as a building block for composite 
XIFF FORMs like "animation sequence" and "structured graphics". Some 
Xuses of ILBM will be to preserve as much information as possible across 
Xdisparate environments. Other uses will be to store data for a single 
Xprogram or highly cooperative programs while maintaining subtle details. 
XSo we're trying to accomplish a lot with this one format.
X
XThis memo is the IFF supplement for FORM ILBM. Section 2 defines the 
Xpurpose and format of property chunks bitmap header "BMHD", color 
Xmap "CMAP", hotspot "GRAB", destination merge data "DEST", sprite 
Xinformation "SPRT", and Commodore Amiga viewport mode "CAMG". Section 
X3 defines the standard data chunk "BODY". These are the "standard" 
Xchunks. Section 4 defines the nonstandard color range data chunk "CRNG". 
XAdditional specialized chunks like texture pattern can be added later. 
XThe ILBM syntax is summarized in Appendix A as a regular expression 
Xand in Appendix B as a box diagram. Appendix C explains the optional 
Xrun encoding scheme. Appendix D names the committee responsible for 
Xthis FORM ILBM standard.
X
XDetails of the raster layout are given in part 3, "Standard Data Chunk". 
XSome elements are based on the Commodore Amiga hardware but generalized 
Xfor use on other computers. An alternative to ILBM would be appropriate 
Xfor computers with true color data in each pixel.
X
XReference:
X
X"EA IFF 85" Standard for Interchange Format Files describes the underlying 
Xconventions for all IFF files.
X
XAmiga[tm] is a trademark of Commodore-Amiga, Inc.
XElectronic Arts[tm] is a trademark of Electronic Arts.
XMacintosh[tm] is a trademark licensed to Apple Computer, Inc.
XMacPaint[tm] is a trademark of Apple Computer, Inc.
X
X
X2. Standard Properties
X
XThe required property "BMHD" and any optional properties must appear 
Xbefore any "BODY" chunk. (Since an ILBM has only one BODY chunk, any 
Xfollowing properties are superfluous.) Any of these properties may 
Xbe shared over a LIST of FORMs IBLM by putting them in a PROP ILBM. 
X(See the "EA IFF 85" memo.)
X
XBMHD
X
XThe required property "BMHD" holds a BitMapHeader as defined in these 
XC declarations and following documentation. It describes the dimensions 
Xand encoding of the image, including data necessary to understand 
Xthe BODY chunk to follow.
X
Xtypedef UBYTE Masking; 	/* Choice of masking technique. */
X
X#define mskNone	0
X#define mskHasMask	1
X#define mskHasTransparentColor	2
X#define mskLasso	3
X
Xtypedef UBYTE Compression;	
X	/* Choice of compression algorithm applied to the rows of all 
X	 * source and mask planes. "cmpByteRun1" is the byte run encoding 
X	 * described in Appendix C. Do not compress across rows! */
X#define cmpNone	0
X#define cmpByteRun1	1
X
Xtypedef struct {
X	UWORD w, h;	/* raster width & height in pixels	*/
X	WORD  x, y;	/* pixel position for this image	*/
X	UBYTE nPlanes;	/* # source bitplanes	*/
X	Masking masking;
X	Compression compression;
X	UBYTE pad1;	/* unused; for consistency, put 0 here	*/
X	UWORD transparentColor;	/* transparent "color number" (sort of)	*/
X	UBYTE xAspect, yAspect;	/* pixel aspect, a ratio width : height	*/
X	WORD  pageWidth, pageHeight;	/* source "page" size in pixels	*/
X	} BitMapHeader;
X
XFields are filed in the order shown. The UBYTE fields are byte-packed.
X
XThe fields w and h indicate the size of the image rectangle in pixels. 
XEach row of the image is stored in an integral number of 16 bit words. 
XThe number of words per row is Ceiling(w/16). The fields x and y indicate 
Xthe desired position of this image within the destination picture. 
XSome reader programs may ignore x and y. A safe default for writing 
Xan ILBM is (x, y) = (0, 0).
X
XThe number of source bitplanes in the BODY chunk (see below) is stored 
Xin nPlanes. An ILBM with a CMAP but no BODY and nPlanes = 0 is the 
Xrecommended way to store a color map.
X
XNote: Color numbers are color map index values formed by pixels in 
Xthe destination bitmap, which may be deeper than nPlanes if a DEST 
Xchunk calls for merging the image into a deeper image.
X
XThe field masking indicates what kind of masking is to be used for 
Xthis image. The value mskNone designates an opaque rectangular image. 
XThe value mskHasMask means that a mask plane is interleaved with the 
Xbitplanes in the BODY chunk (see below). The value mskHasTransparentColor 
Xindicates that pixels in the source planes matching transparentColor 
Xare to be considered "transparent". (Actually, transparentColor isn't 
Xa "color number" since it's matched with numbers formed by the source 
Xbitmap rather than the possibly deeper destination bitmap. Note that 
Xhaving a transparent color implies ignoring one of the color registers. 
XSee CMAP, below.) The value mskLasso indicates the reader may construct 
Xa mask by lassoing the image as in MacPaint*. To do this, put a 1 
Xpixel border of transparentColor around the image rectangle. Then 
Xdo a seed fill from this border. Filled pixels are to be transparent.
X
XIssue: Include in an appendix an algorithm for converting a transparent 
Xcolor to a mask plane, and maybe a lasso algorithm.
X
XA code indicating the kind of data compression used is stored in compression. 
XBeware that using data compression makes your data unreadable by programs 
Xthat don't implement the matching decompression algorithm. So we'll 
Xemploy as few compression encodings as possible. The run encoding 
XbyteRun1 is documented in Appendix C, below.
X
XThe field pad1 is a pad byte and must be set to 0 for consistency. 
XThis field could get used in the future.
X
XThe transparentColor specifies which bit pattern means "transparent".  
XThis only applies if masking is mskHasTransparentColor or mskLasso 
X(see above). Otherwise, transparentColor should be 0.
X
XThe pixel aspect ratio is stored as a ratio in the two fields xAspect 
Xand yAspect. This may be used by programs to compensate for different 
Xaspects or to help interpret the fields w, h, x, y, pageWidth, and 
XpageHeight, which are in units of pixels. The fraction xAspect/yAspect 
Xrepresents a pixel's width/height. It's recommended that your programs 
Xstore proper fractions in BitMapHeaders, but aspect ratios can always 
Xbe correctly compared with the the test
X
XxAspect%yDesiredAspect = yAspect%xDesiredAspect
X
XTypical values for aspect ratio are width : height = 10 : 11 (Amiga 
X320 x 200 display) and 1 : 1 (Macintosh*).
X
XThe size in pixels of the source "page" (any raster device) is stored 
Xin pageWidth and pageHeight, e.g. (320, 200) for a low resolution 
XAmiga display. This information might be used to scale an image or 
Xto automatically set the display format to suit the image. (The image 
Xcan be larger than the page.)
X
XCMAP
X
XThe optional (but encouraged) property "CMAP" stores color map data 
Xas triplets of red, green, and blue intensity values. The n color 
Xmap entries ("color registers") are stored in the order 0 through 
Xn-1, totaling 3n bytes. Thus n is the ckSize/3. Normally, n would 
Xequal 2nPlanes.
X
XA CMAP chunk contains a ColorMap array as defined below. (These typedefs 
Xassume a C compiler that implements packed arrays of 3-byte elements.)
X
Xtypedef struct {
X	UBYTE red, green, blue;	/* color intensities 0..255 */
X	} ColorRegister;	/* size = 3 bytes */
X
Xtypedef ColorRegister ColorMap[n];	/* size = 3n bytes */
X
XThe color components red, green, and blue represent fractional intensity 
Xvalues in the range 0 through 255 256ths. White is (255, 255, 255) 
Xand black is (0, 0, 0). If your machine has less color resolution, 
Xuse the high order bits. Shift each field right on reading (or left 
Xon writing) and assign it to (from) a field in a local packed format 
Xlike Color4, below. This achieves automatic conversion of images across 
Xenvironments with different color resolutions. On reading an ILBM, 
Xuse defaults if the color map is absent or has fewer color registers 
Xthan you need. Ignore any extra color registers.
X
XThe example type Color4 represents the format of a color register 
Xin working memory of an Amiga computer, which has 4 bit video DACs. 
X(The ":4" tells the C compiler to pack the field into 4 bits.)
X
Xtypedef struct {
X	unsigned pad1 :4, red :4, green :4, blue :4;
X	} Color4;	/* Amiga RAM format. Not filed. */
X
XRemember that every chunk must be padded to an even length, so a color 
Xmap with an odd number of entries would be followed by a 0 byte, not 
Xincluded in the ckSize.
X
XGRAB
X
XThe optional property "GRAB" locates a "handle" or "hotspot" of the 
Ximage relative to its upper left corner, e.g. when used as a mouse 
Xcursor or a "paint brush". A GRAB chunk contains a Point2D.
X
Xtypedef struct {
X	WORD x, y;	/* relative coordinates (pixels) */
X	} Point2D;
X
XDEST
X
XThe optional property "DEST" is a way to say how to scatter zero or 
Xmore source bitplanes into a deeper destination image. Some readers 
Xmay ignore DEST.
X
XThe contents of a DEST chunk is DestMerge structure:
X
Xtypedef struct {
X	UBYTE depth;	/* # bitplanes in the original source	*/
X	UBYTE pad1;	/* unused; for consistency put 0 here	*/
X	UWORD planePick; /* how to scatter source bitplanes into destination */
X	UWORD planeOnOff;	/* default bitplane data for planePick	*/
X	UWORD planeMask;	/* selects which bitplanes to store into */
X	} DestMerge;
X
XThe low order depth number of bits in planePick, planeOnOff, and planeMask 
Xcorrespond one-to-one with destination bitplanes. Bit 0 with bitplane 
X0, etc. (Any higher order bits should be ignored.) "1" bits in planePick 
Xmean "put the next source bitplane into this bitplane", so the number 
Xof "1" bits should equal nPlanes. "0" bits mean "put the corresponding 
Xbit from planeOnOff into this bitplane". Bits in planeMask gate writing 
Xto the destination bitplane: "1" bits mean "write to this bitplane" 
Xwhile "0" bits mean "leave this bitplane alone". The normal case (with 
Xno DEST property) is equivalent to planePick = planeMask = 2nPlanesJ- 
X1.
X
XRemember that color numbers are formed by pixels in the destination 
Xbitmap (depth planes deep) not in the source bitmap (nPlanes planes 
Xdeep).
X
XSPRT
X
XThe presence of an "SPRT" chunk indicates that this image is intended 
Xas a sprite. It's up to the reader program to actually make it a sprite, 
Xif even possible, and to use or overrule the sprite precedence data 
Xinside the SPRT chunk:
X
Xtypedef UWORD SpritePrecedence; /* relative precedence, 0 is the highest */
X
XPrecedence 0 is the highest, denoting a sprite that is foremost.
X
XCreating a sprite may imply other setup. E.g. a 2 plane Amiga sprite 
Xwould have transparentColor = 0. Color registers 1, 2, and 3 in the 
XCMAP would be stored into the correct hardware color registers for 
Xthe hardware sprite number used, while CMAP color register 0 would 
Xbe ignored.
X
XCAMG
X
XA "CAMG" chunk is specifically for the Commodore Amiga computer. It 
Xstores a LONG "viewport mode". This lets you specify Amiga display 
Xmodes like "dual playfield" and "hold and modify".
X3. Standard Data Chunk
X
XRaster Layout
X
XRaster scan proceeds left-to-right (increasing X) across scan lines, 
Xthen top-to-bottom (increasing Y) down columns of scan lines. The 
Xcoordinate system is in units of pixels, where (0,0) is the upper 
Xleft corner.
X
XThe raster is typically organized as bitplanes in memory. The corresponding 
Xbits from each plane, taken together, make up an index into the color 
Xmap which gives a color value for that pixel. The first bitplane, 
Xplane 0, is the low order bit of these color indexes.
X
XA scan line is made of one "row" from each bitplane. A row is one 
XplanesU bits for one scan line, but padded out to a word (2 byte) 
Xboundary (not necessarily the first word boundary). Within each row, 
Xsuccessive bytes are displayed in order and the most significant bit 
Xof each byte is displayed first.
X
XA "mask" is an optional "plane" of data the same size (w, h) as a 
Xbitplane.  It tells how to "cut out" part of the image when painting 
Xit onto another image."One" bits in the mask mean "copy the corresponding 
Xpixel to the destination" while "zero" mask bits mean "leave this 
Xdestination pixel alone". In other words, "zero" bits designate transparent 
Xpixels.
X
XThe rows of the different bitplanes and mask are interleaved in the 
Xfile (see below). This localizes all the information pertinent to 
Xeach scan line. It makes it much easier to transform the data while 
Xreading it to adjust the image size or depth. It also makes it possible 
Xto scroll a big image by swapping rows directly from the file without 
Xrandom-accessing to all the bitplanes.
X
XBODY
X
XThe source raster  is stored in a "BODY" chunk. This one chunk holds 
Xall bitplanes and the optional mask, interleaved by row.
X
XThe BitMapHeader, in a BMHD property chunk, specifies the raster's 
Xdimensions w, h, and nPlanes. It also holds the masking field which 
Xindicates if there is a mask plane and the compression field which 
Xindicates the compression algorithm used. This information is needed 
Xto interpret the BODY chunk, so the BMHD chunk must appear first. 
XWhile reading an ILBM's BODY, a program may convert the image to another 
Xsize by filling (with transparentColor) or clipping.
X
XThe BODY's content is a concatenation of scan lines. Each scan line 
Xis a concatenation of one row of data from each plane in order 0 through 
XnPlanes-1 followed by one row from the mask (if masking = hasMask 
X). If the BitMapHeader field compression is cmpNone, all h rows are 
Xexactly Ceiling(w/16) words wide. Otherwise, every row is compressed 
Xaccording to the specified algorithm and their stored widths depend 
Xon the data compression.
X
XReader programs that require fewer bitplanes than appear in a particular 
XILBM file can combine planes or drop the high-order (later) planes. 
XSimilarly, they may add bitplanes and/or discard the mask plane.
X
XDo not compress across rows and don't forget to compress the mask 
Xjust like the bitplanes. Remember to pad any BODY chunk that contains 
Xan odd number of bytes.
X4. Nonstandard Data Chunk
X
XThe following data chunk was defined after various programs began 
Xusing FORM ILBM so it's a "nonstandard" chunk. That means there's 
Xsome slight chance of name collisions.
X
XCRNG
X
XA "CRNG" chunk contains "color register range" information. It's used 
Xby Electronic Arts' Deluxe Paint program to identify a contiguous 
Xrange of color registers for a "shade range" and color cycling. There 
Xcan be zero or more CRNG chunks in an ILBM, but all should appear 
Xbefore the BODY chunk. Deluxe Paint normally writes 4 CRNG chunks 
Xin an ILBM when the user asks it to "Save Picture".
X
Xtypedef struct {
X	WORD  pad1;	/* reserved for future use; store 0 here	*/
X	WORD  rate;	/* color cycle rate	*/
X	WORD  active;	/* nonzero means cycle the colors	*/
X	UBYTE low, high; /* lower and upper color registers selected	*/
X	} CRange;
X
XThe fields low and high indicate the range of color registers (color 
Xnumbers) selected by this CRange.
X
XThe field active indicates whether color cycling is on or off. Zero 
Xmeans off.
X
XThe field rate determines the speed at which the colors will step 
Xwhen color cycling is on. The units are such that a rate of 60 steps 
Xper second is represented as 214 = 16384. Slower rates can be obtained 
Xby linear scaling: for 30 steps/second, rate = 8192; for 1 step/second, 
Xrate = 16384/60 E 273.
X
XCCRT
X
XCommodore's Graphicraft program uses a similar chunk "CCRT" (for Color 
XCyling Range and Timing). This chunk contains a CycleInfo structure.
X
Xtypedef struct {
X	WORD  direction; /* 0 = don't cycle. 1 = cycle forwards (1, 2, 3).
X		 	  * -1 = cycle backwards (3, 2, 1)	*/
X	UBYTE start, end;  /* lower and upper color registers selected	*/
X	LONG  seconds;	   /* # seconds between changing colors	*/
X	LONG  microseconds;	/* # microseconds between changing colors */ 
X	WORD  pad;		/* reserved for future use; store 0 here  */ 
X	} CycleInfo;
X
XThis is pretty similar to a CRNG chunk. A program would probably only 
Xuse one of these two methods of expressing color cycle data. You could 
Xwrite out both if you want to communicate this information to both 
XDeluxe Paint and Graphicraft.
X
XA CCRT chunk expresses the color cycling rate as a number of seconds 
Xplus a number of microseconds.
X
X
X
XAppendix A. ILBM Regular Expression
X
XHere's a regular expression summary of the FORM ILBM syntax. This 
Xcould be an IFF file or a part of one.
X
XILBM ::= "FORM" #{	"ILBM" BMHD [CMAP] [GRAB] [DEST] [SPRT] [CAMG]
X	CRNG* CCRT* [BODY]	}
X
XBMHD ::= "BMHD" #{	BitMapHeader	}
XCMAP ::= "CMAP" #{	(red green blue)*	} [0]
XGRAB ::= "GRAB" #{	Point2D	}
XDEST ::= "DEST" #{	DestMerge	}
XSPRT ::= "SPRT" #{	SpritePrecendence	}
XCAMG ::= "CAMG" #{	LONG	}
X
XCRNG ::= "CRNG" #{	CRange	}
XCCRT ::= "CCRT" #{	CycleInfo	}
XBODY ::= "BODY" #{	UBYTE*	} [0]
X
XThe token "#" represents a ckSize LONG count of the following {braced} 
Xdata bytes. E.g. a BMHD's "#" should equal sizeof(BitMapHeader). Literal 
Xstrings are shown in "quotes", [square bracket items] are optional, 
Xand "*" means 0 or more repetitions. A sometimes-needed pad byte is 
Xshown as "[0]".
X
XThe property chunks (BMHD, CMAP, GRAB, DEST, SPRT, and CAMG) and any 
XCRNG and CCRT data chunks may actually be in any order but all must 
Xappear before the BODY chunk since ILBM readers usually stop as soon 
Xas they read the BODY. If any of the 6 property chunks are missing, 
Xdefault values are "inherited" from any shared properties (if the 
XILBM appears inside an IFF LIST with PROPs) or from the reader program's 
Xdefaults. If any property appears more than once, the last occurrence 
Xbefore the BODY is the one that counts since that's the one that modifies 
Xthe BODY.
X
X
X
XAppendix B. ILBM Box Diagram
X
XHere's a box diagram for a simple example: an uncompressed image 320 
Xx 200 pixels x 3 bitplanes. The text to the right of the diagram shows 
Xthe outline that would be printed by the IFFCheck utility program 
Xfor this particular file.
X
X 
X        +-----------------------------------+
X        |'FORM'         24070               |   FORM 24070 IBLM
X        +-----------------------------------+
X        |'ILBM'                             |
X        +-----------------------------------+
X        | +-------------------------------+ |
X        | | 'BMHD'      20                | |   .BMHD  20
X        | | 320, 200, 0, 0, 3, 0, 0, ...  | |
X        | + ------------------------------+ |
X        | | 'CMAP'      21                | |   .CMAP  21
X        | | 0, 0, 0; 32, 0, 0; 64,0,0; .. | |
X        | +-------------------------------+ |
X        | 0                                 |
X        +-----------------------------------+
X        |'BODY'         24000               |   .BODY 24000
X        |0, 0, 0, ...                       |
X        +-----------------------------------+
X
X
X
XThe "0" after the CMAP chunk is a pad byte.
X
X
X
XAppendix C. ByteRun1 Run Encoding
X
XThe run encoding scheme byteRun1 is best described by psuedo code 
Xfor the decoder Unpacker (called UnPackBits in the Macintosh* toolbox):
X
XUnPacker:
X	LOOP until produced the desired number of bytes
X		Read the next source byte into n
X		SELECT n FROM
X			[0..127]	=> copy the next n+1 bytes literally
X			[-1..-127]	=> replicate the next byte -n+1 times
X			-128	=> noop
X			ENDCASE;
X		ENDLOOP;
X
XIn the inverse routine Packer, it's best to encode a 2 byte repeat 
Xrun as a replicate run except when preceded and followed by a literal 
Xrun, in which case it's best to merge the three into one literal run. 
XAlways encode 3 byte repeats as replicate runs.
X
XRemember that each row of each scan line of a raster is separately 
Xpacked.
X
X
X
XAppendix D. Standards Committee
X
XThe following people contributed to the design of this FORM ILBM standard:
X
XBob "Kodiak" Burns, Commodore-Amiga
XR. J. Mical, Commodore-Amiga
XJerry Morrison, Electronic Arts
XGreg Riker, Electronic Arts
XSteve Shaw, Electronic Arts
XDan Silva, Electronic Arts
XBarry Walsh, Commodore-Amiga
//END
echo x - smus
sed 's/^X//' > smus << '//END'
X"SMUS" IFF Simple Musical Score
X
XDate:	February 5, 1986
XFrom:	Jerry Morrison, Electronic Arts
XStatus:	Adopted
X
X1. Introduction
X
XThis is a reference manual for the data interchange format "SMUS", 
Xwhich stands for Simple MUsical Score. "EA IFF 85" is Electronic Arts' 
Xstandard for interchange format files. A FORM (or "data section") 
Xsuch as FORM SMUS can be an IFF file or a part of one. [See "EA IFF 
X85" Electronic Arts Interchange File Format.]
X
XSMUS is a practical data format for uses like moving limited scores 
Xbetween programs and storing theme songs for game programs. The format 
Xshould be geared for easy read-in and playback. So FORM SMUS uses 
Xthe compact time encoding of Common Music Notation (half notes, dotted 
Xquarter rests, etc.). The SMUS format should also be structurally 
Xsimple. So it has no provisions for fancy notational information needed 
Xby graphical score editors or the more general timing (overlapping 
Xnotes, etc.) and continuous data (pitch bends, etc.) needed by 
Xperformance-oriented MIDI recorders and sequencers.
X
XA SMUS score can say which "instruments" are supposed play which notes. 
XBut the score is independent of whatever output device and driver 
Xsoftware is used to perform the notes. The score can contain device- 
Xand driver-dependent instrument data, but this is just a cache. As 
Xlong as a SMUS file stays in one environment, the embedded instrument 
Xdata is very convenient. When you move a SMUS file between programs 
Xor hardware configurations, the contents of this cache usually become 
Xuseless.
X
XLike all IFF formats, SMUS is a filed or "archive" format. It is completely 
Xindependent of score representations in working memory, editing operations, 
Xuser interface, display graphics, computation hardware, and sound 
Xhardware. Like all IFF formats, SMUS is extensible.
X
XSMUS is not an end-all musical score format. Other formats may be 
Xmore appropriate for certain uses. (We'd like to design an general-use 
XIFF score format "GSCR". FORM GSCR would encode fancy notational data 
Xand performance data. There would be a SMUS to/from GSCR converter.)
X
XSection 2 gives important background information. Section 3 details 
Xthe SMUS components by defining the required property score header 
X"SHDR", the optional text properties name "NAME", copyright "(c) ", 
Xand author "AUTH", optional text annotation "ANNO", the optional instrument 
Xspecifier "INS1", and the track data chunk "TRAK". Section 4 defines 
Xsome chunks for particular programs to store private information. 
XThese are "standard" chunks; specialized chunks for future needs can 
Xbe added later. Appendix A is a quick-reference summary. Appendix 
XB is an example box diagram. Appendix C names the committee responsible 
Xfor this standard.
X
XUpdate: This standard has been revised since the draft versions. The 
X"INST" chunk type was revised to form the "INS1" chunk type. Also, 
Xseveral SEvent types and a few text chunk types have been added.
X
XNote: This is a MacWrite[tm] 4.5 document. If you strip it down to a 
Xtext file, you'll lose pictures, significant formatting information 
Xlike superscripts, and characters like ")". Don't do it.  
X
X
X  ----------------------------------------------------------------
X  |(Sorry, EA. We had to strip it down for ease of distribution, |
X  |  but we did convert pictures to text-form and where we could |
X  |  not do that, we provided ILBM illustrations that people     |
X  |  could actually show using the standard "showilbm" program)  |
X  ----------------------------------------------------------------
X
X
XReferences:
X
X"EA IFF 85" Standard for Interchange Format Files describes the underlying 
Xconventions for all IFF files.
X
X"8SVX" IFF 8-Bit Sampled Voice documents a data format for sampled 
Xinstruments.
X
XElectronic Arts[tm] is a trademark of Electronic Arts.
X
XMIDI: Musical Instrument Digital Interface Specification 1.0, International 
XMIDI Association, 1983.
X
XMacWrite[tm] is a trademark of Apple Computer, Inc.
X
XSSSP: See various articles on Structured Sound Synthesis Project in 
XFoundations of Computer Music.
X
X
X
X
X2. Background
X
XHere's some background information on score representation in general 
Xand design choices for SMUS.
X
XFirst, we'll borrow some terminology from the Structured Sound Synthesis 
XProject. [See the SSSP reference.] A "musical note" is one kind of 
Xscheduled event. It's properties include an event duration, an event 
Xdelay, and a timbre object. Theevent duration tells the scheduler 
Xhow long the note should last. The event delay tells how long after 
Xstarting this note to wait before starting the next event. The timbre 
Xobject selects sound driver data for the note; an "instrument" or 
X"timbre". A "rest" is a sort of a null event. Its only property is 
Xan event delay.
X
XClassical Event Durations
X
XSMUS is geared for "classical" scores, not free-form performances. 
XSo its event durations are classical (whole note, dotted quarter rest, 
Xetc.). It can tie notes together to build a "note event" with an unusual 
Xevent duration.
X
XThe set of useful classical durations is very small. So SMUS needs 
Xonly a handful of bits to encode an event duration. This is very compact. 
XIt's also very easy to display in Common Music Notation (CMN).
X
XTracks
X
XThe events in a SMUS score are grouped into parallel "tracks". Each 
Xtrack is a linear stream of events.
X
XWhy use tracks? Tracks serve 4 functions:
X
X1.	Tracks make it possible to encode event delays very compactly. 
XA "classical" score has chorded notes and sequential notes; no overlapping 
Xnotes. That is, each event begins either simultaneous with or immediately 
Xfollowing the previous event in that track. So each event delay is 
Xeither 0 or the same as the event's duration. This binary distinction 
Xrequires only one bit of storage.
X
X2.	Tracks represent the "voice tracks" in Common Music Notation. 
XCMN organizes a score in parallel staves, with one or two "voice tracks" 
Xper staff. So one or two SMUS tracks represents a CMN staff.
X
X3.	Tracks are a good match to available sound hardware. We can 
Xuse "instrument settings" in a track to store the timbre assignments 
Xfor that track's notes. The instrument setting may change over the 
Xtrack.
X
X	Furthermore, tracks can help to allocate notes among available 
Xoutput channels or performance devices or tape recorder "tracks". 
XTracks can also help to adapt polyphonic data to monophonic output 
Xchannels.
X
X4.	Tracks are a good match to simple sound software. Each track 
Xis a place to hold state settings like "dynamic mark pp ", "time signature 
X3/4", "mute this track", etc., just as it's a context for instrument 
Xsettings. This is a lot like a text stream with running "font" and 
X"face" properties (attributes). Running state is usually more compact 
Xthan, say, storing an instrument setting in every note event. It's 
Xalso a useful way to organize "attributes" of notes. With "running 
Xtrack state" we can define new note attributes in an upward- and 
Xbackward-compatible way.
X
X	Running track state can be expanded (run decoded) while loading 
Xa track into memory or while playing the track. The runtime track 
Xstate must be reinitialized every time the score is played.
X
XSeparated vs. interleaved tracks. Multi-track data could be stored 
Xeither as separate event streams or interleaved into one stream. To 
Xinterleave the streams, each event has to carry a "track number" attribute.
X
XIf we were designing an editable score format, we might interleave 
Xthe streams so that nearby events are stored nearby. This helps when 
Xsearching the data, especially if you can't fit the entire score into 
Xmemory at once. But it takes extra storage for the track numbers and 
Xmay take extra work to manipulate the interleaved tracks.
X
XThe musical score format FORM SMUS is intended for simple loading 
Xand playback of small scores that fit entirely in main memory. So 
Xwe chose to store its tracks separately.
X
XThere can be up to 255 tracks in a FORM SMUS. Each track is stored 
Xas a TRAK chunk. The count of tracks (the number of TRAK chunks) is 
Xrecorded in the SHDR chunk at the beginning of the FORM SMUS. The 
XTRAK chunks appear in numerical order 1, 2, 3, .... This is also priority 
Xorder, most important track first. A player program that can handle 
Xup to N parallel tracks should read the first N tracks and ignore 
Xany others.
X
XThe different tracks in a score may have different lengths. This is 
Xtrue both of storage length and of playback duration.
X
XInstrument Registers
X
XInstrument reference. In SSSP, each note event points to a "timbre 
Xobject" which supplies the "instrument" (the sound driver data) for 
Xthat note. FORM SMUS stores these pointers as a "current instrument 
Xsetting" for each track. It's just a run encoded version of the same 
Xinformation. SSSP uses a symbol table to hold all the pointers to 
X"timbre object". SMUS uses INS1 chunks for the same purpose. They 
Xname the score's instruments.
X
XThe actual instrument data to use depends on the playback environment, 
Xbut we want the score to be independent of environment. Different 
Xplayback environments have different audio output hardware and different 
Xsound driver software. And there are channel allocation issues like 
Xhow many output channels there are, which ones are polyphonic, and 
Xwhich I/O ports they're connected to. If you use MIDI to control the 
Xinstruments, you get into issues of what kind of device is listening 
Xto each MIDI channel and what each of its preset sounds like. If you 
Xuse computer-based instruments, you need driver-specific data like 
Xwaveform tables and oscillator parameters.
X
XWe just want to put some orchestration in the score. If the score 
Xwants a "piano", we let the playback program to find a "piano".
X
XInstrument reference by name. A reference from a SMUS score to actual 
Xinstrument data is normally by name. The score simply names the instrument, 
Xfor instance "tubular bells". It's up to the player program to find 
Xsuitable instrument data for its output devices. (More on locating 
Xinstruments below.)
X
XInstrument reference by MIDI channel and preset. A SMUS score can 
Xalso ask for a specific MIDI channel number and preset number. MIDI 
Xprograms may honor these specific requests. But these channel allocations 
Xcan become obsolete or the score may be played without MIDI hardware. 
XIn such cases, the player program should fall back to instrument reference 
Xby name.
X
XInstrument reference via instrument register. Each reference from 
Xa SMUS track to an instrument is via an "instrument register". Each 
Xtrack selects an instrument register which in turn points to the specific 
Xinstrument data.
X
XEach score has an array of instrument registers. Each track has a 
X"current instrument setting", which is simply an index number into 
Xthis array. This is like setting a raster image's pixel to a specific 
Xcolor number (a reference to a color value through a "color register") 
Xor setting a text character to a specific font number (a reference 
Xto a font through a "font register"). This is diagrammed below.
X
X
X Track 1  |Set Inst 2| Note | Note | Set Inst 1 | Note | Note | Note |... 
X		|			  |
X  +-------------+			  |
X  |  +------------------------------------+
X  |  |	       +--------------------------------------------------------+
X  |  +-------->|"piano"  ---------------> (internal piano data)	 	|
X  +----------->|"guitar" ---------------> (internal guitar data)	|
X	       |"Spanish guitar" -------> (internal Spanish guitar data)|
X     +-------->|"bass drum" ------------> (internal bass drum data)	|
X     |	       +--------------------------------------------------------+
X     |
X     +---------+
X	       |
X Track 2  |Set Inst 4| Note | Note | Note | Note | Note | Note | Note |... 
X
X
X
XLocating instrument data by name. "INS1" chunks in a SMUS score name 
Xthe instruments to use for that score. The player program uses these 
Xnames to locate instrument data.
X
XTo locate instrument data, the player performs these steps:
X
XFor each instrument register, check for a suitable instrument with 
Xthe right name.  "Suitable" means usable with an available output 
Xdevice and driver.  {Use case independent name comparisons.}
X
X1.	Initialize the instrument register to point to a built-in default 
X	instrument.  {Every player program must have default instruments. 
X	Simple programs stop here. For fancier programs, the default 
X	instruments are a backstop in case the search fails.}
X
X2.	Check any instrument FORMs embedded in the FORM SMUS. (This 
X	is an "instrument cache".)
X
X3.	Else check the default instruments.
X
X4.	Else search the local "instrument library". (The library might 
X	simply be a disk directory.)
X
X5.	If all else fails, display the desired instrument name and 
X	ask the user to pick an available one.
X
XThis algorithm can be implemented to varying degrees of fanciness. 
XIt's ok to stop searching after step 1, 2, 3, or 4. If exact instrument 
Xname matches fail, it's ok to try approximate matches. E.g. search 
Xfor any kind of "guitar" if you can't find a "Spanish guitar". In 
Xany case, a player only has to search for instruments while loading 
Xa score.
X
XWhen the embedded instruments are suitable, they save the program 
Xfrom asking the user to insert the "right" disk in a drive and searching 
Xthat disk for the "right" instrument. But it's just a cache. In practice, 
Xwe rarely move scores between environments so the cache often works. 
XWhen the score is moved, embedded instruments must be discarded (a 
Xcache miss) and other instrument data used.
X
XBe careful to distinguish an instrument's name from its filenameQthe 
Xcontents name vs. container name. A musical instrument FORM should 
Xcontain a NAME chunk that says what instrument it really is. Its filename, 
Xon the other hand, is a handle used to locate the FORM. Filenames 
Xare affected by external factors like drives, directories, and filename 
Xcharacter and length limits. Instrument names are not.
X
XIssue: Consider instrument naming conventions for consistency. Consider 
Xa naming convention that aids approximate matches. E.g. we could accept 
X"guitar, bass1" if we didn't find "guitar, bass". Failing that, we 
Xcould accept "guitar" or any name starting with "guitar".
X
XSet instrument events. If the player implements the set-instrument 
Xscore event, each track can change instrument numbers while playing. 
XThat is, it can switch between the loaded instruments.
X
XInitial instrument settings. Each time a score is played, every tracks' 
Xrunning state information must be initialized. Specifically, each 
Xtrack's instrument number should be initialized to its track number. 
XTrack 1 to instrument 1, etc. It's as if each track began with a 
Xset-instrument event.
X
XIn this way, programs that don't implement the set-instrument event 
Xstill assign an instrument to each track. The INS1 chunks imply these 
Xinitial instrument settings.
X
XMIDI Instruments
X
XAs mentioned above, A SMUS score can also ask for MIDI instruments. 
XThis is done by putting the MIDI channel and preset numbers in an 
XINS1 chunk with the instrument name. Some programs will honor these 
Xrequests while others will just find instruments by name.
X
XMIDI Recorder and sequencer programs may simply transcribe the MIDI 
Xchannel and preset commands in a recording session. For this purpose, 
Xset-MIDI-channel and set-MIDI-preset events can be embedded in a SMUS 
Xscore's tracks. Most programs should ignore these events. An editor 
Xprogram that wants to exchange scores with such programs should recognize 
Xthese events. It should let the user change them to the more general 
Xset-instrument events.
X
X
X
X3. Standard Data and Property Chunks
X
XA FORM SMUS contains a required property "SHDR" followed by any number 
Xof parallel "track" data chunks "TRAK". Optional property chunks such 
Xas "NAME", copyright "(c) ", and instrument reference "INS1" may also 
Xappear. Any of the properties may be shared over a LIST of FORMs SMUS 
Xby putting them in a PROP SMUS. [See the IFF reference.]
X
XRequired Property SHDR
X
XThe required property "SHDR" holds an SScoreHeader as defined in these 
XC declarations and following documentation. An SHDR specifies global 
Xinformation for the score. It must appear before the TRAKs in a FORM 
XSMUS.
X
X#define ID_SMUS MakeID('S', 'M', 'U', 'S')
X#define ID_SHDR MakeID('S', 'H', 'D', 'R')
X
Xtypedef struct {
X	UWORD tempo;	/* tempo, 128ths quarter note/minute	*/
X	UBYTE volume;	/* overall playback volume 0 through 127	*/
X	UBYTE ctTrack;	/* count of tracks in the score	*/
X	} SScoreHeader;
X
X[Implementation details. In the C struct definitions in this memo, 
Xfields are filed in the order shown. A UBYTE field is packed into 
Xan 8-bit byte. Programs should set all "pad" fields to 0. MakeID is 
Xa C macro defined in the main IFF document and in the source file 
XIFF.h.]
X
XThe field tempo gives the nominal tempo for all tracks in the score. 
XIt is expressed in 128ths of a quarter note per minute, i.e. 1 represents 
X1 quarter note per 128 minutes while 12800 represents 100 quarter 
Xnotes per minute. You may think of this as a fixed point fraction 
Xwith a 9-bit integer part and a 7-bit fractional part (to the right 
Xof the point). A course-tempoed program may simply shift tempo right 
Xby 7 bits to get a whole number of quarter notes per minute. The tempo 
Xfield can store tempi in the range 0 up to 512. The playback program 
Xmay adjust this tempo, perhaps under user control.
X
XActually, this global tempo could actually be just an initial tempo 
Xif there are any "set tempo" SEvents inside the score (see TRAK, below). 
XOr the global tempo could be scaled by "scale tempo" SEvents inside 
Xthe score. These are potential extensions that can safely be ignored 
Xby current programs. [See More SEvents To Be Defined, below.]
X
XThe field volume gives an overall nominal playback volume for all 
Xtracks in the score. The range of volume values 0 through 127 is like 
Xa MIDI key velocity value. The playback program may adjust this volume, 
Xperhaps under direction of a user "volume control".
X
XActually, this global volume level could be scaled by dynamic-mark 
XSEvents inside the score (see TRAK, below).
X
XThe field ctTrack holds the count of tracks, i.e. the number of TRAK 
Xchunks in the FORM SMUS (see below). This information helps the reader 
Xprepare for the following data.
X
XA playback program will typically load the score and call a driver 
Xroutine PlayScore(tracks, tempo, volume), supplying the tempo and 
Xvolume from the SHDR chunk.
X
XOptional Text Chunks NAME, (c), AUTH, ANNO
X
XSeveral text chunks may be included in a FORM SMUS to keep ancillary 
Xinformation.
X
XThe optional property "NAME" names the musical score, for instance 
X"Fugue in C".
X
XThe optional property "(c)J" holds a copyright notice for the score. 
XThe chunk ID "(c)J" serves the function of the copyright characters 
X")J". E.g. a "(c)J" chunk containing "1986 Electronic Arts" means 
X") 1986 Electronic Arts".
X
XThe optional property "AUTH" holds the name of the score's author.
X
XThe chunk types "NAME", "(c) ", and "AUTH" are property chunks. Putting 
Xmore than one NAME (or other) property in a FORM is redundant. Just 
Xthe last NAME counts. A property should be shorter than 256 characters. 
XProperties can appear in a PROP SMUS to share them over a LIST of 
XFORMs SMUS.
X
XThe optional data chunk "ANNO" holds any text annotations typed in 
Xby the author.
X
XAn ANNO chunk is not a property chunk, so you can put more than one 
Xin a FORM SMUS. You can make ANNO chunks any length up to 231 - 1 
Xcharacters, but 32767 is a practical limit. Since they're not properties, 
XANNO chunks don't belong in a PROP SMUS. That means they can't be 
Xshared over a LIST of FORMs SMUS.
X
XSyntactically, each of these chunks contains an array of 8-bit ASCII 
Xcharacters in the range R S (SP, hex 20) through R~S (tilde, hex 7F), 
Xjust like a standard "TEXT" chunk. [See "Strings, String Chunks, and 
XString Properties" in "EA IFF 85" Electronic Arts Interchange File 
XFormat.] The chunk's ckSize field holds the count of characters.
X
X#define ID_NAME MakeID('N', 'A', 'M', 'E')
X/* NAME chunk contains a CHAR[], the musical score's name.	*/
X
X#define ID_Copyright MakeID('(', 'c', ')', ' ')
X/* "(c) " chunk contains a CHAR[], the FORM's copyright notice.	*/
X
X#define ID_AUTH MakeID('A', 'U', 'T', 'H')
X/* AUTH chunk contains a CHAR[], the name of the score's author.	*/
X
X#define ID_ANNO MakeID('A', 'N', 'N', 'O')
X/* ANNO chunk contains a CHAR[], author's text annotations.	*/
X
XRemember to store a 0 pad byte after any odd-length chunk.
X
XOptional Property INS1
X
XThe "INS1" chunks in a FORM SMUS identify the instruments to use for 
Xthis score. A program can ignore INS1 chunks and stick with its built-in 
Xdefault instrument assignments. Or it can use them to locate instrument 
Xdata. [See "Instrument Registers" in section 2, above.]
X
X#define ID_INS1 MakeID('I', 'N', 'S', '1')
X
X/* Values for the RefInstrument field "type".	*/
X#define INS1_Name  0	/* just use the name; ignore data1, data2	*/
X#define INS1_MIDI  1	/* <<data1, data2> = MIDI <<channel, preset>	*/
X
Xtypedef struct {
X	UBYTE register;	/* set this instrument register number	*/
X	UBYTE type;	/* instrument reference type	*/
X	UBYTE data1, data2;	/* depends on the "type" field	*/
X	CHAR  name[];	/* instrument name	*/
X	} RefInstrument;
X
XAn INS1 chunk names the instrument for instrument register number 
Xregister. The register field can range from 0 through 255. In practice, 
Xmost scores will need only a few instrument registers.
X
XThe name field gives a text name for the instrument. The string length 
Xcan be determined from the ckSize of the INS1 chunk. The string is 
Xsimply an array of 8-bit ASCII characters in the range R S (SP, hex 
X20) through R~S (tilde, hex 7F).
X
XBesides the instrument name, an INS1 chunk has two data numbers to 
Xhelp locate an instrument. The use of these data numbers is controlled 
Xby the type field. A value type = INS1_Name means just find an instrument 
Xby name. In this case, data1 and data2 should just be set to 0. A 
Xvalue type = INS1_MIDI means look for an instrument on MIDI channel 
X# data1, preset # data2. Programs and computers without MIDI outputs 
Xwill just ignore the MIDI data. They'll always look for the named 
Xinstrument. Other values of the type field are reserved for future 
Xstandardization.
X
XSee section 2, above, for the algorithm for locating instrument data 
Xby name.
X
XObsolete Property INST
X
XThe chunk type "INST" is obsolete in SMUS. It was revised to form 
Xthe "INS1" chunk.
X
XData Chunk TRAK
X
XThe main contents of a score is stored in one or more TRAK chunks 
Xrepresenting parallel "tracks". One TRAK chunk per track.
X
XThe contents of a TRAK chunk is an array of 16-bit "events" such as 
X"note", "rest", and "set instrument". Events are really commands to 
Xa simple scheduler, stored in time order. The tracks can be polyphonic, 
Xthat is, they can contain chorded "note" events.
X
XEach event is stored as an "SEvent" record. ("SEvent" means "simple 
Xmusical event".) Each SEvent has an 8-bit type field called an "sID" 
Xand 8 bits of type-dependent data. This is like a machine language 
Xinstruction with an 8-bit opcode and an 8-bit operand.
X
XThis format is extensible since new event types can be defined in 
Xthe future. The "note" and "rest" events are the only ones that every 
Xprogram must understand. We will carefully design any new event types 
Xso that programs can safely skip over unrecognized events in a score.
X
XCaution: SID codes must be allocated by a central clearinghouse to 
Xavoid conflicts.
X
XHere are the C type definitions for TRAK and SEvent and the currently 
Xdefined sID values. Afterward are details on each SEvent.
X
X#define ID_TRAK MakeID('T', 'R', 'A', 'K')
X
X/* TRAK chunk contains an SEvent[].	*/
X
X/* SEvent: Simple musical event.	*/
Xtypedef struct {
X	UBYTE sID;	/* SEvent type code	*/
X	UBYTE data;	/* sID-dependent data	*/
X	} SEvent;
X
X/* SEvent type codes "sID".		*/
X#define SID_FirstNote     0
X#define SID_LastNote    127	/* sIDs in the range SID_FirstNote through
X			 	 * SID_LastNote (sign bit = 0) are notes. The
X			 	 * sID is the MIDI tone number (pitch).	*/
X#define SID_Rest        128	/* a rest (same data format as a note).	*/
X
X#define SID_Instrument  129	/* set instrument number for this 
Xtrack.	*/
X#define SID_TimeSig     130	/* set time signature for this track.	*/
X#define SID_KeySig      131	/* set key signature for this track.	*/
X#define SID_Dynamic     132	/* set volume for this track.	*/
X#define SID_MIDI_Chnl   133	/* set MIDI channel number (sequencers)	*/
X#define SID_MIDI_Preset 134	/* set MIDI preset number (sequencers)	*/
X
X/* SID values 144 through 159: reserved for Instant Music SEvents.	*/
X
X/* Remaining sID values up through 254: reserved for future
X * standardization.		*/
X
X#define SID_Mark        255	/* sID reserved for an end-mark in RAM.	*/
X
XNote and Rest SEvents
X
XThe note and rest SEvents SID_FirstNote through SID_Rest have the 
Xfollowing structure overlaid onto the SEvent structure:
X
Xtypedef struct {
X	UBYTE    tone;	/* MIDI tone number 0 to 127; 128 = rest	*/
X	unsigned chord    :1,	/* 1 = a chorded note	*/
X        tieOut   :1,	/* 1 = tied to the next note or chord	*/
X        nTuplet  :2,	/* 0 = none, 1 = triplet, 2 = quintuplet,
X	* 3 = septuplet	*/
X        dot      :1,	/* dotted note; multiply duration by 3/2	*/
X        division :3;	/* basic note duration is 2-division: 0 = whole
X	 		 * note, 1 = half note, 2 = quarter note, I 
X			 * 7 = 128th note	*/
X	} SNote;
X
X[Implementation details. Unsigned ":n" fields are packed into n bits 
Xin the order shown, most significant bit to least significant bit. 
XAn SNote fits into 16 bits like any other SEvent. Warning: Some compilers 
Xdon't implement bit-packed fields properly. E.g. Lattice 68000 C pads 
Xa group of bit fields out to a LONG, which would make SNote take 5-bytes! 
XIn that situation, use the bit-field constants defined below.]
X
XThe SNote structure describes one "note" or "rest" in a track. The 
Xfield SNote.tone, which is overlaid with the SEvent.sID field, indicates 
Xthe MIDI tone number (pitch) in the range 0 through 127. A value of 
X128 indicates a rest.
X
XThe fields nTuplet, dot, and division together give the duration of 
Xthe note or rest. The division gives the basic duration: whole note, 
Xhalf note, etc. The dot indicates if the note or rest is dotted. A 
Xdotted note is 3/2 as long as an undotted note. The value nTuplet 
X(0 through 3) tells if this note or rest is part of an N-tuplet of 
Xorder 1 (normal), 3, 5, or 7; an N-tuplet of order (2J*JnTupletJ+J1). 
XA triplet note is 2/3 as long as a normal note, while a quintuplet 
Xis 4/5 as long and a septuplet is 6/7 as long.
X
XPutting these three fields together, the duration of the note or rest 
Xis 2-division * {1, 3/2} * {1, 2/3, 4/5, 6/7}
X
XThese three fields are contiguous so you can easily convert to your 
Xlocal duration encoding by using the combined 6 bits as an index into 
Xa mapping table.
X
XThe field chord indicates if the note is chorded with the following 
Xnote (which is supposed to have the same duration). A group of notes 
Xmay be chorded together by setting the chord bit of all but the last 
Xone. (In the terminology of SSSP and GSCR, setting the chord bit to 
X1 makes the "entry delay" 0.) A monophonic-track player can simply 
Xignore any SNote event whose chord bit is set, either by discarding 
Xit when reading the track or by skipping it when playing the track.
X
XPrograms that create polyphonic tracks are expected to store the most 
Ximportant note of each chord last, which is the note with the 0 chord 
Xbit. This way, monophonic programs will play the most important note 
Xof the chord. The most important note might be the chord's root note 
Xor its melody note.
X
XIf the field tieOut is set, the note is tied to the following note 
Xin the track if the following note has the same pitch. A group of 
Xtied notes is played as a single note whose duration is the sum of 
Xthe component durations. Actually, the tie mechanism ties a group 
Xof one or more chorded notes to another group of one or more chorded 
Xnotes. Every note in a tied chord should have its tieOut bit set.
X
XOf course, the chord and tieOut fields don't apply to SID_Rest SEvents.
X
XPrograms should be robust enough to ignore an unresolved tie, i.e. 
Xa note whose tieOut bit is set but isn't followed by a note of the 
Xsame pitch. If that's true, monophonic-track programs can simply ignore 
Xchorded notes even in the presense of ties. That is, tied chords pose 
Xno extra problems.
X
XThe following diagram shows some combinations of notes and chords 
Xtied to notes and chords. The text below the staff has a column for 
Xeach SNote SEvent to show the pitch, chord bit, and tieOut bit.
X
X
X
X		(figure)
X
X
X
X
XIf you read the above track into a monophonic-track program, it'll 
Xstrip out the chorded notes and ignore unresolved ties. You'll end 
Xup with:
X
X
X
X		(figure)
X
X
X
X
XA rest event (sID = SID_Rest) has the same SEvent.data field as a 
Xnote. It tells the duration of the rest. The chord and tieOut fields 
Xof rest events are ignored.
X
XWithin a TRAK chunk, note and rest events appear in time order.
X
XInstead of the bit-packed structure SNote, it might be easier to assemble 
Xdata values by or-ing constants and to disassemble them by masking 
Xand shifting. In that case, use the following definitions.
X
X#define noteChord  (1<<<<7)	/* note is chorded to next note	*/
X
X#define noteTieOut (1<<<<6)	/* tied to next note/chord	*/
X
X#define noteNShift 4	/* shift count for nTuplet field	*/
X#define noteN3     (1<<<<noteNShift)	/* note is a triplet	*/
X#define noteN5     (2<<<<noteNShift)	/* note is a quintuplet	*/
X#define noteN7     (3<<<<noteNShift)	/* note is a septuplet	*/
X#define noteNMask  noteN7	/* bit mask for the nTuplet field	*/
X
X#define noteDot    (1<<<<3)	/* note is dotted	*/
X
X#define noteD1     0	/* whole note division	*/
X#define noteD2     1	/* half note division	*/
X#define noteD4     2	/* quarter note division	*/
X#define noteD8     3 	/* eighth note division	*/
X#define noteD16    4 	/* sixteenth note division	*/
X#define noteD32    5 	/* thirty-secondth note division	*/
X#define noteD64    6 	/* sixty-fourth note division	*/
X#define noteD128   7 	/* 1/128 note division	*/
X#define noteDMask  noteD128	/* bit mask for the division field	*/
X
X#define noteDurMask 0x3F	/* mask for combined duration fields	*/
X
XNote: The remaining SEvent types are optional. A writer program doesn't 
Xhave to generate them. A reader program can safely ignore them.
X
XSet Instrument SEvent
X
XOne of the running state variables of every track is an instrument 
Xnumber. An instrument number is the array index of an "instrument 
Xregister", which in turn points to an instrument. (See "Instrument 
XRegisters", in section 2.) This is like a color number in a bitmap; 
Xa reference to a color through a "color register".
X
XThe initial setting for each track's instrument number is the track 
Xnumber. Track 1 is set to instrument 1, etc. Each time the score is 
Xplayed, every track's instrument number should be reset to the track 
Xnumber.
X
XThe SEvent SID_Instrument changes the instrument number for a track, 
Xthat is, which instrument plays the following notes. Its SEvent.data 
Xfield is an instrument register number in the range 0 through 255. 
XIf a program doesn't implement the SID_Instrument event, each track 
Xis fixed to one instrument.
X
XSet Time Signature SEvent
X
XThe SEvent SID_TimeSig sets the time signature for the track. A "time 
Xsignature" SEvent has the following structure overlaid on the SEvent 
Xstructure:
X
Xtypedef struct {
X	UBYTE    type;	/* = SID_TimeSig	*/
X	unsigned timeNSig :5,	/* time sig. "numerator" is timeNSig + 1 */ 
X	timeDSig :3;	/* time sig. "denominator" is 2timeDSig: 
X			 * 0 = whole note, 1 = half note, 2 = quarter 	 
X			 * note, I 7 = 128th note	*/
X	} STimeSig;
X
X[Implementation details. Unsigned ":n" fields are packed into n bits 
Xin the order shown, most significant bit to least significant bit. 
XAn STimeSig fits into 16 bits like any other SEvent. Warning: Some 
Xcompilers don't implement bit-packed fields properly. E.g. Lattice 
XC pads a group of bit fields out to a LONG, which would make an STimeSig 
Xtake 5-bytes! In that situation, use the bit-field constants defined 
Xbelow.]
X
XThe field type contains the value SID_TimeSig, indicating that this 
XSEvent is a "time signature" event. The field timeNSig indicates the 
Xtime signature "numerator" is timeNSig + 1, that is, 1 through 32 
Xbeats per measure. The field timeDSig indicates the time signature 
X"denominator" is 2timeDSig, that is each "beat" is a 2-timeDSig note 
X(see SNote division, above). So 4/4 time is expressed as timeNSig 
X= 3, timeDSig = 2.
X
XThe default time signature is 4/4 time.
X
XBeware that the time signature has no effect on the score's playback. 
XTempo is uniformly expressed in quarter notes per minute, independent 
Xof time signature. (Quarter notes per minute equals beats per minute 
Xonly if timeDSig = 2, n/4 time). Nonetheless, any program that has 
Xtime signatures should put them at the beginning of each TRAK when 
Xcreating a FORM SMUS because music editors need them.
X
XInstead of the bit-packed structure STimeSig, it might be easier to 
Xassemble data values by or-ing constants and to disassemble them by 
Xmasking and shifting. In that case, use the following definitions.
X
X#define timeNMask  0xF8	/* bit mask for the timeNSig field	*/
X#define timeNShift 3	/* shift count for  timeNSig field	*/
X
X#define timeDMask  0x07	/* bit mask for the timeDSig field	*/
X
XKey Signature SEvent
X
XAn SEvent SID_KeySig sets the key signature for the track. Its data 
Xfield is a UBYTE number encoding a major key:
X
Xdata	key	music notation	data	key	music notation
XJ0	C maj
XJ1	G	#	J8	F	b
XJ2	D	##	J9	Bb	bb
XJ3	A	###	10	Eb	bbb
XJ4	E	####	11	Ab	bbbb
XJ5	B	#####	12	Db	bbbbb
XJ6	F#	######	13	Gb	bbbbbb
XJ7	C#	#######	14	Cb	bbbbbbb
X
XA SID_KeySig SEvent changes the key for the following notes in that 
Xtrack. C major is the default key in every track before the first 
XSID_KeySig SEvent.
X
XDynamic Mark SEvent
X
XAn SEvent SID_Dynamic represents a dynamic mark like ppp and fff in 
XCommon Music Notation. Its data field is a MIDI key velocity number 
X0 through 127. This sets a "volume control" for following notes in 
Xthe track. This "track volume control" is scaled by the overall score 
Xvolume in the SHDR chunk.
X
XThe default dynamic level is 127 (full volume).
X
XSet MIDI Channel SEvent
X
XThe SEvent SID_MIDI_Chnl is for recorder programs to record the set-MIDI-channe
Xl low level event. The data byte contains a MIDI channel number. Other 
Xprograms should use instrument registers instead.
X
XSet MIDI Preset SEvent
X
XThe SEvent SID_MIDI_Preset is for recorder programs to record the 
Xset-MIDI-preset low level event. The data byte contains a MIDI preset 
Xnumber. Other programs should use instrument registers instead.
X
XInstant Music Private SEvents
X
XSixteen SEvents are used for private data for the Instant Music program. 
XSID values 144 through 159 are reserved for this purpose. Other programs 
Xshould skip over these SEvents.
X
XEnd-Mark SEvent
X
XThe SEvent type SID_Mark is reserved for an end marker in working 
Xmemory. This event is never stored in a file. It may be useful if 
Xyou decide to use the filed TRAK format intact in working memory.
X
XMore SEvents To Be Defined
X
XMore SEvents can be defined in the future. The sID codes 133 through 
X143 and 160 through 254 are reserved for future needs. Caution: sID 
Xcodes must be allocated by a central "clearinghouse" to avoid conflicts. 
XWhen this SMUS standard passes the "draft" state, Commodore-Amiga 
Xwill be in charge of this activity.
X
XThe following SEvent types are under consideration and should not 
Xyet be used.
X
XIssue: A "change tempo" SEvent changes tempo during a score. Changing 
Xthe tempo affects all tracks, not just the track containing the change 
Xtempo event.
X
XOne possibility is a "scale tempo" SEvent SID_ScaleTempo that rescales 
Xthe global tempo:
XcurrentTempo := globalTempo * (data + 1) / 128
X
XThis can scale the global tempo (in the SHDR) anywhere from x1/128 
Xto x2 in roughly 1% increments.
X
XAn alternative is two events SID_SetHTempo and SID_SetLTempo. SID_SetHTempo 
Xgives the high byte and SID_SetLTempo gives the low byte of a new 
Xtempo setting, in 128ths quarter note/minute. SetHTempo automatically 
Xsets the low byte to 0, so the SetLTempo event isn't needed for course 
Xsettings. In this scheme, the SHDR's tempo is simply a starting tempo.
X
XAn advantage of SID_ScaleTempo is that the playback program can just 
Xalter the global tempo to adjust the overall performance time and 
Xstill easily implement tempo variations during the score. But the 
X"set tempo" SEvent may be simpler to generate.
X
XIssue: The events SID_BeginRepeat and SID_EndRepeat define a repeat 
Xspan for one track. The span of events between a BeginRepeat and an 
XEndRepeat is played twice. The SEvent.data field in the BeginRepeat 
Xevent could give an iteration count,1 through 255 times or 0 for "repeat 
Xforever".
X
XRepeat spans can be nested. All repeat spans automatically end at 
Xthe end of the track.
X
XAn event SID_Ending begins a section like "first ending" or "second 
Xending". The SEvent.data field gives the ending number. This SID_Ending 
Xevent only applies to the innermost repeat group. (Consider generalizing 
Xit.)
X
XA more general alternative is a "subtrack" or "subscore" event. A 
X"subtrack" event is essentially a "subroutine call" to another series 
Xof SEvents. This is a nice way to encode all the possible variations 
Xof repeats, first endings, codas, and such.
X
XTo define a subtrack, we must demark its start and end. One possibility 
Xis to define a relative brach-to-subtrack event SID_BSR and a return-from-subtr
Xack event SID_RTS. The 8-bit data field in the SID_BSR event can reach 
Xas far as 512 SEvents. A second possibility is to call a subtrack 
Xby index number, with an IFF chunk outside the TRAK defining the start 
Xand end of all subtracks. This is very general since a portion of 
Xone subtrack can be used as another subtrack. It also models the tape 
Xrecording practice of first "laying down a track" and then selecting 
Xportions of it to play and repeat. To embody the music theory idea 
Xof playing a sequence like "ABBA", just compose the "main" track entirely 
Xof subtrack events. A third possibility is to use a numbered subtrack 
Xchunk "STRK" for each subroutine.
X
X
X
X
X4. Private Chunks
X
XAs in any IFF FORM, there can be private chunks in a FORM SMUS that 
Xare designed for one particular program to store its private information. 
XAll IFF reader programs skip over unrecognized chunks, so the presense 
Xof private chunks can't hurt.
X
XInstant Music stores some global score information in a chunk of ID 
X"IRev".
X
X
X
XAppendix A. Quick Reference
X
XType Definitions
X
XHere's a collection of the C type definitions in this memo. In the 
X"struct" type definitions, fields are filed in the order shown. A 
XUBYTE field is packed into an 8-bit byte. Programs should set all 
X"pad" fields to 0.
X
X#define ID_SMUS MakeID('S', 'M', 'U', 'S')
X#define ID_SHDR MakeID('S', 'H', 'D', 'R')
X
Xtypedef struct {
X	UWORD tempo;	/* tempo, 128ths quarter note/minute	*/
X	UBYTE volume;	/* overall playback volume 0 through 127	*/
X	UBYTE ctTrack;	/* count of tracks in the score	*/
X	} SScoreHeader;
X
X#define ID_NAME MakeID('N', 'A', 'M', 'E')
X/* NAME chunk contains a CHAR[], the musical score's name.	*/
X
X#define ID_Copyright MakeID('(', 'c', ')', ' ')
X/* "(c) " chunk contains a CHAR[], the FORM's copyright notice.	*/
X
X#define ID_AUTH MakeID('A', 'U', 'T', 'H')
X/* AUTH chunk contains a CHAR[], the name of the score's author.	*/
X
X#define ID_ANNO MakeID('A', 'N', 'N', 'O')
X/* ANNO chunk contains a CHAR[], author's text annotations.	*/
X
X#define ID_INS1 MakeID('I', 'N', 'S', '1')
X
X/* Values for the RefInstrument field "type".	*/
X#define INS1_Name 0	/* just use the name; ignore data1, data2	*/
X#define INS1_MIDI 1	/* <<data1, data2> = MIDI <<channel, preset>	*/
X
Xtypedef struct {
X	UBYTE register;	/* set this instrument register number	*/
X	UBYTE type;	/* instrument reference type	*/
X	UBYTE data1, data2;	/* depends on the "type" field	*/
X	CHAR  name[];	/* instrument name	*/
X	} RefInstrument;
X
X#define ID_TRAK MakeID('T', 'R', 'A', 'K')
X/* TRAK chunk contains an SEvent[].	*/
X
X/* SEvent: Simple musical event.	*/
Xtypedef struct {
X	UBYTE sID;	/* SEvent type code	*/
X	UBYTE data;	/* sID-dependent data	*/
X	} SEvent;
X
X/* SEvent type codes "sID".		*/
X#define SID_FirstNote     0
X#define SID_LastNote    127	/* sIDs in the range SID_FirstNote through
X			 	 * SID_LastNote (sign bit = 0) are notes. The 
X				 * sID is the MIDI tone number (pitch).	*/
X#define SID_Rest        128	/* a rest (same data format as a note).	*/
X
X#define SID_Instrument  129	/* set instrument number for this 
Xtrack.	*/
X#define SID_TimeSig     130	/* set time signature for this track.	*/
X#define SID_KeySig      131	/* set key signature for this track.	*/
X#define SID_Dynamic     132	/* set volume for this track.	*/
X#define SID_MIDI_Chnl   133	/* set MIDI channel number (sequencers)	*/
X#define SID_MIDI_Preset 134	/* set MIDI preset number (sequencers)	*/
X
X/* SID values 144 through 159: reserved for Instant Music SEvents.	*/
X
X/* Remaining sID values up through 254: reserved for future
X * standardization.		*/
X
X#define SID_Mark        255	/* sID reserved for an end-mark in RAM.	*/
X
X/* SID_FirstNote..SID_LastNote, SID_Rest SEvents	*/
Xtypedef struct {
X	UBYTE    tone;	/* MIDI tone number 0 to 127; 128 = rest	*/
X	unsigned chord    :1,	/* 1 = a chorded note	*/
X        tieOut   :1,	/* 1 = tied to the next note or chord	*/
X        nTuplet  :2,	/* 0 = none, 1 = triplet, 2 = quintuplet,
X			 * 3 = septuplet	*/
X        dot      :1,	/* dotted note; multiply duration by 3/2	*/
X        division :3;	/* basic note duration is 2-division: 0 = whole
X	  	 	 * note, 1 = half note, 2 = quarter note, I 
X			 * 7 = 128th note	*/
X	} SNote;
X
X#define noteChord  (1<<<<7)	/* note is chorded to next note	*/
X
X#define noteTieOut (1<<<<6)	/* tied to next note/chord	*/
X
X#define noteNShift 4	/* shift count for nTuplet field	*/
X#define noteN3     (1<<<<noteNShift)	/* note is a triplet	*/
X#define noteN5     (2<<<<noteNShift)	/* note is a quintuplet	*/
X#define noteN7     (3<<<<noteNShift)	/* note is a septuplet	*/
X#define noteNMask  noteN7	/* bit mask for the nTuplet field	*/
X
X#define noteDot    (1<<<<3)	/* note is dotted	*/
X
X#define noteD1     0	/* whole note division	*/
X#define noteD2     1	/* half note division	*/
X#define noteD4     2	/* quarter note division	*/
X#define noteD8     3 	/* eighth note division	*/
X#define noteD16    4 	/* sixteenth note division	*/
X#define noteD32    5 	/* thirty-secondth note division	*/
X#define noteD64    6 	/* sixty-fourth note division	*/
X#define noteD128   7 	/* 1/128 note division	*/
X#define noteDMask  noteD128	/* bit mask for the division field	*/
X
X#define noteDurMask 0x3F	/* mask for combined duration fields	*/
X
X/* SID_Instrument SEvent		*/
X/* "data" value is an instrument register number 0 through 255.	*/
X
X/* SID_TimeSig SEvent		*/
Xtypedef struct {
X	UBYTE    type;	/* = SID_TimeSig	*/
X	unsigned timeNSig :5,	/* time sig. "numerator" is timeNSig + 1 */
X        timeDSig :3;	/* time sig. "denominator" is 2timeDSig:
X	 	 	 * 0 = whole note, 1 = half note, 2 = quarter 	 
X			 * note, I 7 = 128th note	*/
X	} STimeSig;
X
X#define timeNMask  0xF8	/* bit mask for the timeNSig field	*/
X#define timeNShift 3	/* shift count for  timeNSig field	*/
X
X#define timeDMask  0x07	/* bit mask for the timeDSig field	*/
X
X/* SID_KeySig SEvent		*/
X/* "data" value 0 = Cmaj; 1 through 7 = G,D,A,E,B,F#,C#;
X * 8 through 14 = F,Bb,Eb,Ab,Db,Gb,Cb.	*/
X
X/* SID_Dynamic SEvent		*/
X/* "data" value is a MIDI key velocity 0..127.	*/
X
XSMUS Regular Expression
X
XHere's a regular expression summary of the FORM SMUS syntax. This 
Xcould be an IFF file or part of one.
X
XSMUS	::= "FORM" #{	"SMUS" SHDR [NAME] [Copyright] [AUTH] [IRev]
X		ANNO* INS1*  TRAK*  InstrForm* }
X
XSHDR	::= "SHDR" #{	SScoreHeader	}
XNAME	::= "NAME" #{	CHAR*	} [0]
XCopyright	::= "(c) " #{	CHAR*	} [0]
XAUTH	::= "AUTH" #{	CHAR*	} [0]
XIRev	::= "IRev" #{	...	}
X
XANNO	::= "ANNO" #{	CHAR*	} [0]
XINS1	::= "INS1" #{	RefInstrument	} [0]
X
XTRAK	::= "TRAK" #{	SEvent*	}
X
XInstrForm	::= "FORM" #{	...	}
X
XThe token "#" represents a ckSize LONG count of the following {braced} 
Xdata bytes. Literal items are shown in "quotes", [square bracket items] 
Xare optional, and "*" means 0 or more replications. A sometimes-needed 
Xpad byte is shown as "[0]".
X
XActually, the order of chunks in a FORM SMUS is not as strict as this 
Xregular expression indicates. The SHDR, NAME, Copyright, AUTH, IRev, 
XANNO, and INS1 chunks may appear in any order, as long as they precede 
Xthe TRAK chunks.
X
XThe chunk RInstrFormS represents any kind of instrument data FORM 
Xembedded in the FORM SMUS. For example, see the document "8SVX" IFF 
X8-Bit Sampled Voice. Of course, a recipient program will ignore an 
Xinstrument FORM if it doesn't recognize that FORM type.
X
X
X
XAppendix B. SMUS Example
X
XHere's a box diagram for a simple example, a SMUS with two instruments 
Xand two tracks. Each track contains 1 note event and 1 rest event.
X
X
X
X     +-----------------------------------------+	------
X     |'FORM'		94		       |  	  ^
X     |	+-----------------------------------+  |	  |
X     |  |'SMUS'				    |  |  	  |
X     |  +-----------------------------------+  |	  |
X     |	| +-------------------------------+ |  |	  |
X     |	| | 'SHDR'	4		  | |  |  	  |
X     |	| | 12800, 127, 2		  | |  |	  |
X     |	| +-------------------------------+ |  |	  |
X     |	| +-------------------------------+ |  |	  |
X     |	| | 'NAME'	10	          | |  |  	  |
X     |	| | 'Fugue in C'		  | |  |	  |
X     |	| +-------------------------------+ |  |	  |
X     |	| +-------------------------------+ |  |	  
X     |	| | 'INS1'	9	          | |  |      (94 bytes)
X     |	| | 1,0,0,0,'piano'		  | |  |	   
X     |	| +-------------------------------+ |  |	  |
X     |	| 0				    |  |	  |
X     |	| +-------------------------------+ |  |	  |
X     |	| | 'INS1'	10	          | |  |  	  |
X     |	| | 2,0,0,0,'guitar'		  | |  |	  |
X     |	| +-------------------------------+ |  |	  |
X     |	| +-------------------------------+ |  |	  |
X     |	| | 'TRAK'	4	          | |  |  	  |
X     |	| | 60, 16, 128, 16		  | |  |	  |
X     |	| +-------------------------------+ |  |	  |
X     |	| +-------------------------------+ |  |	  |
X     |	| | 'TRAK'	4	          | |  | 	  |
X     |	| | 128, 16, 60, 16		  | |  |	  |
X     |	| +-------------------------------+ |  |	  |
X     |	+-----------------------------------+  |	  V
X     +-----------------------------------------+	-----
X	  
X
X
XAppendix B. Standards Committee
X
XThe following people contributed to the design of this IFF standard:
X
XBob "Kodiak" Burns, Commodore-Amiga
XR. J. Mical, Commodore-Amiga
XJerry Morrison, Electronic Arts
XGreg Riker, Electronic Arts
XSteve Shaw, Electronic Arts
XBarry Walsh, Commodore-Amiga
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XThe "0" after the first INS1 chunk is a pad byte.
X
X
X
XAppendix C. Standards Committee
X
XThe following people contributed to the design of this SMUS standard:
X
XRalph Bellafatto, Cherry Lane Technologies
XGeoff Brown, Uhuru Sound Software
XSteve Hayes, Electronic Arts
XJerry Morrison, Electronic Arts
//END
: end of archive.
exit 0
-- 
Peter da Silva.   `-_-'
<peter@sugar.hackercorp.com>.


