From: peter@sugar.hackercorp.com (Peter da Silva) Newsgroups: alt.binaries.multimedia Subject: Definition of Electronic Arts IFF format Date: 10 Dec 90 12:56:36 GMT Reply-To: peter@sugar.hackercorp.com (Peter da Silva) Organization: Sugar Land Unix - Houston In a radical move, infomation instead of flames. Definitions of the Electronic Arts IFF formats for text, sampled sounds, musical scores, and images. : 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 <." 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 /* < = MIDI < */ 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<<< = MIDI < */ 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<<<.