home *** CD-ROM | disk | FTP | other *** search
/ 17 Bit Software 1: Collection A / 17Bit_Collection_A.iso / files / 61.dms / 61.adf / iff.text / 8svx next >
Text File  |  1986-03-21  |  27KB  |  668 lines

  1. "8SVX" IFF 8-Bit Sampled Voice
  2.  
  3. Date:    February 7, 1985
  4. From:    Steve Hayes and Jerry Morrison, Electronic Arts
  5. Status:    Adopted
  6.  
  7. 1. Introduction
  8.  
  9. This memo is the IFF supplement for FORM "8SVX". An 8SVX is an IFF 
  10. "data section" or "FORM" (which can be an IFF file or a part of one) 
  11. containing a digitally sampled audio voice consisting of 8-bit samples. 
  12. A voice can be a one-shot sound orQwith repetition and pitch scalingQa 
  13. musical instrument. "EA IFF 85" is Electronic Arts' standard interchange 
  14. file format. [See "EA IFF 85" Standard for Interchange Format Files.]
  15.  
  16. The 8SVX format is designed for playback hardware that uses 8-bit 
  17. samples attenuated by a volume control for good overall signal-to-noise 
  18. ratio. So a FORM 8SVX stores 8-bit samples and a volume level.
  19.  
  20. A similar data format (or two) will be needed for higher resolution 
  21. samples (typically 12 or 16 bits). Properly converting a high resolution 
  22. sample down to 8 bits requires one pass over the data to find the 
  23. minimum and maximum values and a second pass to scale each sample 
  24. into the range -128 through 127. So it's reasonable to store higher 
  25. resolution data in a different FORM type and convert between them.
  26.  
  27. For instruments, FORM 8SVX can record a repeating waveform optionally 
  28. preceded by a startup transient waveform. These two recorded signals 
  29. can be pre-synthesized or sampled from an acoustic instrument. For 
  30. many instruments, this representation is compact. FORM 8SVX is less 
  31. practical for an instrument whose waveform changes from cycle to cycle 
  32. like a plucked string, where a long sample is needed for accurate 
  33. results.
  34.  
  35. FORM 8SVX can store an "envelope" or "amplitude contour" to enrichen 
  36. musical notes. A future voice FORM could also store amplitude, frequency, 
  37. and filter modulations.
  38.  
  39. FORM 8SVX is geared for relatively simple musical voices, where one 
  40. waveform per octave is sufficient, where the waveforms for the different 
  41. octaves follows a factor-of-two size rule, and where one envelope 
  42. is adequate for all octaves. You could store a more general voice 
  43. as a LIST containing one or more FORMs 8SVX per octave. A future voice 
  44. FORM could go beyond one "one-shot" waveform and one "repeat" waveform 
  45. per octave.
  46.  
  47. Section 2 defines the required property sound header "VHDR", optional 
  48. properties name "NAME", copyright "(c)J", and author "AUTH", the optional 
  49. annotation data chunk "ANNO", the required data chunk "BODY", and 
  50. optional envelope chunks "ATAK" and "RLSE". These are the "standard" 
  51. chunks. Specialized chunks for private or future needs can be added 
  52. later, e.g. to hold a frequency contour or Fourier series coefficients. 
  53. The 8SVX syntax is summarized in Appendix A as a regular expression 
  54. and in Appendix B as an example box diagram. Appendix C explains the 
  55. optional Fibonacci-delta compression algorithm.
  56.  
  57. Caution: The VHDR structure Voice8Header changed since draft proposal 
  58. #4! The new structure is incompatible with the draft version.
  59.  
  60.  
  61.  
  62. Reference:
  63.  
  64. "EA IFF 85" Standard for Interchange Format Files describes the underlying 
  65. conventions for all IFF files.
  66.  
  67. Amiga[tm] is a trademark of Commodore-Amiga, Inc.
  68.  
  69. Electronic Arts[tm] is a trademark of Electronic Arts.
  70.  
  71. MacWrite[tm] is a trademark of Apple Computer, Inc.
  72.  
  73.  
  74.  
  75. 2. Standard Data and Property Chunks
  76.  
  77. FORM 8SVX stores all the waveform data in one body chunk "BODY". It 
  78. stores playback parameters in the required header chunk "VHDR". "VHDR" 
  79. and any optional property chunks "NAME", "(c)J", and "AUTH" must all 
  80. appear before the BODY chunk. Any of these properties may be shared 
  81. over a LIST of FORMs 8SVX by putting them in a PROP 8SVX. [See "EA 
  82. IFF 85" Standard for Interchange Format Files.]
  83.  
  84. Background
  85.  
  86. There are two ways to use FORM 8SVX: as a one-shot sampled sound or 
  87. as a sampled musical instrument that plays "notes". Storing both kinds 
  88. of sounds in the same kind of FORM makes it easy to play a one-shot 
  89. sound as a (staccato) instrument or an instrument as a (one-note) 
  90. sound.
  91.  
  92. A one-shot sound is a series of audio data samples with a nominal 
  93. playback rate and amplitude. The recipient program can optionally 
  94. adjust or modulate the amplitude and playback data rate.
  95.  
  96. For musical instruments, the idea is to store a sampled (or pre-synthesized) 
  97. waveform that will be parameterized by pitch, duration, and amplitude 
  98. to play each "note". The creator of the FORM 8SVX can supply a waveform 
  99. per octave over a range of octaves for this purpose. The intent is 
  100. to perform a pitch by selecting the closest octave's waveform and 
  101. scaling the playback data rate. An optional "one-shot" waveform supplies 
  102. an arbitrary startup transient, then a "repeat" waveform is iterated 
  103. as long as necessary to sustain the note.
  104.  
  105. A FORM 8SVX can also store an envelope to modulate the waveform. Envelopes 
  106. are mostly useful for variable-duration notes but could be used for 
  107. one-shot sounds, too.
  108.  
  109. The FORM 8SVX standard has some restrictions. For example, each octave 
  110. of data must be twice as long as the next higher octave. Most sound 
  111. driver software and hardware imposes additional restrictions. E.g. 
  112. the Amiga sound hardware requires an even number of samples in each 
  113. one-shot and repeat waveform.
  114.  
  115. Required Property VHDR
  116.  
  117. The required property "VHDR" holds a Voice8Header structure as defined 
  118. in these C declarations and following documentation. This structure 
  119. holds the playback parameters for the sampled waveforms in the BODY 
  120. chunk. (See "Data Chunk BODY", below, for the storage layout of these 
  121. waveforms.)
  122.  
  123. #define ID_8SVX MakeID('8', 'S', 'V', 'X')
  124. #define ID_VHDR MakeID('V', 'H', 'D', 'R')
  125.  
  126. typedef LONG Fixed;    
  127.     /* A fixed-point value, 16 bits to the left of the point and 16 
  128.      * to the right. A Fixed is a number of 216ths, i.e. 65536ths.    */
  129.  
  130. #define Unity 0x10000L    /* Unity = Fixed 1.0 = maximum volume    */
  131.  
  132. /* sCompression: Choice of compression algorithm applied to the samples. */ 
  133.  
  134. #define sCmpNone       0    /* not compressed    */
  135. #define sCmpFibDelta   1    /* Fibonacci-delta encoding (Appendix C)  */ 
  136.  
  137. /* Can be more kinds in the future.    */
  138.  
  139. typedef struct {
  140.     ULONG oneShotHiSamples,    /* # samples in the high octave 1-shot part */
  141.         repeatHiSamples,    /* # samples in the high octave repeat part */
  142.         samplesPerHiCycle;    /* # samples/cycle in high octave, else 0   */
  143.     UWORD samplesPerSec;    /* data sampling rate    */
  144.     UBYTE ctOctave,        /* # octaves of waveforms    */
  145.           sCompression;        /* data compression technique used    */
  146.     Fixed volume;        /* playback volume from 0 to Unity (full 
  147.                  * volume). Map this value into the output 
  148.                  * hardware's dynamic range.    */
  149.     } Voice8Header;
  150.  
  151. [Implementation details. Fields are filed in the order shown. The 
  152. UBYTE fields are byte-packed (2 per 16-bit word). MakeID is a C macro 
  153. defined in the main IFF document and in the source file IFF.h.]
  154.  
  155. A FORM 8SVX holds waveform data for one or more octaves, each containing 
  156. a one-shot part and a repeat part. The fields oneShotHiSamples and 
  157. repeatHiSamples tell the number of audio samples in the two parts 
  158. of the highest frequency octave. Each successive (lower frequency) 
  159. octave contains twice as many data samples in both its one-shot and 
  160. repeat parts. One of these two parts can be empty across all octaves.
  161.  
  162. Note: Most audio output hardware and software has limitations. The 
  163. Amiga computer's sound hardware requires that all one-shot and repeat 
  164. parts have even numbers of samples. Amiga sound driver software would 
  165. have to adjust an odd-sized waveform, ignore an odd-sized lowest octave, 
  166. or ignore odd FORMs 8SVX altogether. Some other output devices require 
  167. all sample sizes to be powers of two.
  168.  
  169. The field samplesPerHiCycle tells the number of samples/cycle in the 
  170. highest frequency octave of data, or else 0 for "unknown". Each successive 
  171. (lower frequency) octave contains twice as many samples/cycle. The 
  172. samplesPerHiCycle value is needed to compute the data rate for a desired 
  173. playback pitch.
  174.  
  175. Actually, samplesPerHiCycle is an average number of samples/cycle. 
  176. If the one-shot part contains pitch bends, store the samples/cycle 
  177. of the repeat part in samplesPerHiCycle. The division repeatHiSamples/samplesPe
  178. rHiCycle should yield an integer number of cycles. (When the repeat 
  179. waveform is repeated, a partial cycle would come out as a higher-frequency 
  180. cycle with a "click".)
  181.  
  182. More limitations: Some Amiga music drivers require samplesPerHiCycle 
  183. to be a power of two in order to play the FORM 8SVX as a musical instrument 
  184. in tune. They may even assume samplesPerHiCycle is a particular power 
  185. of two without checking. (If samplesPerHiCycle is different by a factor 
  186. of two, the instrument will just be played an octave too low or high.)
  187.  
  188. The field samplesPerSec gives the sound sampling rate. A program may 
  189. adjust this to achieve frequency shifts or vary it dynamically to 
  190. achieve pitch bends and vibrato. A program that plays a FORM 8SVX 
  191. as a musical instrument would ignore samplesPerSec and select a playback 
  192. rate for each musical pitch.
  193.  
  194. The field ctOctave tells how many octaves of data are stored in the 
  195. BODY chunk. See "Data Chunk BODY", below, for the layout of the octaves.
  196.  
  197. The field sCompression indicates the compression scheme, if any, that 
  198. was applied to the entire set of data samples stored in the BODY chunk. 
  199. This field should contain one of the values defined above. Of course, 
  200. the matching decompression algorithm must be applied to the BODY data 
  201. before the sound can be played. (The Fibonacci-delta encoding scheme 
  202. sCmpFibDelta is described in Appendix C.) Note that the whole series 
  203. of data samples is compressed as a unit.
  204.  
  205. The field volume gives an overall playback volume for the waveforms 
  206. (all octaves). It lets the 8-bit data samples use the full range -128 
  207. through 127 for good signal-to-noise ratio and be attenuated on playback 
  208. to the desired level. The playback program should multiply this value 
  209. by a "volume control" and perhaps by a playback envelope (see ATAK 
  210. and RLSE, below).
  211.  
  212. Recording a one-shot sound. To store a one-shot sound in a FORM 8SVX, 
  213. set oneShotHiSamples = number of samples, repeatHiSamples = 0 , 
  214. samplesPerHiCycle = 0, samplesPerSec = sampling rate, and ctOctave = 1. 
  215. Scale the signal amplitude to the full sampling range -128 through 127. Set 
  216. volume so the sound will playback at the desired volume level. If 
  217. you set the samplesPerHiCycle field properly, the data can also be 
  218. used as a musical instrument.
  219.  
  220. Experiment with data compression. If the decompressed signal sounds 
  221. ok, store the compressed data in the BODY chunk and set sCompression 
  222. to the compression code number.
  223.  
  224. Recording a musical instrument. To store a musical instrument in a 
  225. FORM 8SVX, first record or synthesize as many octaves of data as you 
  226. want to make available for playback. Set ctOctaves to the count of 
  227. octaves. From the recorded data, excerpt an integral number of steady 
  228. state cycles for the repeat part and set repeatHiSamples and samplesPerHiCycle. 
  229. Either excerpt a startup transient waveform and set oneShotHiSamples, 
  230. or else set oneShotHiSamples to 0. Remember, the one-shot and repeat 
  231. parts of each octave must be twice as long as those of the next higher 
  232. octave. Scale the signal amplitude to the full sampling range and 
  233. set volume to adjust the instrument playback volume. If you set the 
  234. samplesPerSec field properly, the data can also be used as a one-shot 
  235. sound.
  236.  
  237. A distortion-introducing compressor like sCmpFibDelta is not recommended 
  238. for musical instruments, but you might try it anway.
  239.  
  240. Typically, creators of FORM 8SVX record an acoustic instrument at 
  241. just one frequency. Decimate (down- sample with filtering) to compute 
  242. higher octaves. Interpolate to compute lower octaves.
  243.  
  244. If you sample an acoustic instrument at different octaves, you may 
  245. find it hard to make the one-shot and repeat waveforms follow the 
  246. factor-of-two rule for octaves. To compensate, lengthen an octave's 
  247. one-shot part by appending replications of the repeating cycle or 
  248. prepending zeros. (This will have minimal impact on the sound's start 
  249. time.) You may be able to equalize the ratio one-shot-samples : repeat-samples 
  250. across all octaves.
  251.  
  252. Note that a "one-shot sound" may be played as a "musical instrument" 
  253. and vice versa. However, an instrument player depends on samplesPerHiCycle, 
  254. and a one-shot player depends on samplesPerSec.
  255.  
  256. Playing a one-shot sound. To play any FORM 8SVX data as a one-shot 
  257. sound, first select an octave if ctOctave > 1. (The lowest-frequency 
  258. octave has the greatest resolution.) Play the one-shot samples then 
  259. the repeat samples, scaled by volume, at a data rate of samplesPerSec. 
  260. Of course, you may adjust the playback rate and volume. You can play 
  261. out an envelope, too. (See ATAK and RLSE, below.)
  262.  
  263. Playing a musical note. To play a musical note using any FORM 8SVX, 
  264. first select the nearest octave of data from those available. Play 
  265. the one-shot waveform then cycle on the repeat waveform as long as 
  266. needed to sustain the note. Scale the signal by volume, perhaps also 
  267. by an envelope, and by a desired note volume. Select a playback data 
  268. rate s samples/second to achieve the desired frequency (in Hz):
  269. frequency = sJ/JsamplesPerHiCycle
  270. for the highest frequency octave.
  271.  
  272. The idea is to select an octave and one of 12 sampling rates (assuming 
  273. a 12-tone scale). If the FORM 8SVX doesn't have the right octave, 
  274. you can decimate or interpolate from the available data.
  275.  
  276. When it comes to musical instruments, FORM 8SVX is geared for a simple 
  277. sound driver. Such a driver uses a single table of 12 data rates to 
  278. reach all notes in all octaves. That's why 8SVX requires each octave 
  279. of data to have twice as many samples as the next higher octave. If 
  280. you restrict samplesPerHiCycle to a power of two, you can use a predetermined 
  281. table of data rates.
  282.  
  283. Optional Text Chunks NAME, (c), AUTH, ANNO
  284.  
  285. Several text chunks may be included in a FORM 8SVX to keep ancillary 
  286. information.
  287.  
  288. The optional property "NAME" names the voice, for instance "tubular 
  289. bells".
  290.  
  291. The optional property "(c)J" holds a copyright notice for the voice. 
  292. The chunk ID "(c)J" serves as the copyright characters ")J". E.g. 
  293. a "(c)J" chunk containing "1986 Electronic Arts" means ") 1986 Electronic 
  294. Arts".
  295.  
  296. The optional property "AUTH" holds the name of the instrument's "author" 
  297. or "creator".
  298.  
  299. The chunk types "NAME", "(c) ", and "AUTH" are property chunks. Putting 
  300. more than one NAME (or other) property in a FORM is redundant. Just 
  301. the last NAME counts. A property should be shorter than 256 characters. 
  302. Properties can appear in a PROP 8SVX to share them over a LIST of 
  303. FORMs 8SVX.
  304.  
  305. The optional data chunk "ANNO" holds any text annotations typed in 
  306. by the author.
  307.  
  308. An ANNO chunk is not a property chunk, so you can put more than one 
  309. in a FORM 8SVX. You can make ANNO chunks any length up to 231 - 1 
  310. characters, but 32767 is a practical limit. Since they're not properties, 
  311. ANNO chunks don't belong in a PROP 8SVX. That means they can't be 
  312. shared over a LIST of FORMs 8SVX.
  313.  
  314. Syntactically, each of these chunks contains an array of 8-bit ASCII 
  315. characters in the range " " (SP, hex 20) through "~" (tilde, hex 7F), 
  316. just like a standard "TEXT" chunk. [See "Strings, String Chunks, and 
  317. String Properties" in "EA IFF 85" Electronic Arts Interchange File 
  318. Format.] The chunk's ckSize field holds the count of characters.
  319.  
  320. #define ID_NAME MakeID('N', 'A', 'M', 'E')
  321. /* NAME chunk contains a CHAR[], the voice's name.    */
  322.  
  323. #define ID_Copyright MakeID('(', 'c', ')', ' ')
  324. /* "(c) " chunk contains a CHAR[], the FORM's copyright notice.    */
  325.  
  326. #define ID_AUTH MakeID('A', 'U', 'T', 'H')
  327. /* AUTH chunk contains a CHAR[], the author's name.    */
  328.  
  329. #define ID_ANNO MakeID('A', 'N', 'N', 'O')
  330. /* ANNO chunk contains a CHAR[], author's text annotations.    */
  331.  
  332. Remember to store a 0 pad byte after any odd-length chunk.
  333.  
  334. Optional Data Chunks ATAK and RLSE
  335.  
  336. The optional data chunks ATAK and RLSE together give a piecewise-linear 
  337. "envelope" or "amplitude contour". This contour may be used to modulate 
  338. the sound during playback. It's especially useful for playing musical 
  339. notes of variable durations. Playback programs may ignore the supplied 
  340. envelope or substitute another.
  341.  
  342. #define ID_ATAK MakeID('A', 'T', 'A', 'K')
  343. #define ID_RLSE MakeID('R', 'L', 'S', 'E')
  344.  
  345. typedef struct {
  346.     UWORD duration;    /* segment duration in milliseconds, > 0    */
  347.     Fixed dest;    /* destination volume factor    */
  348.     } EGPoint;
  349.  
  350. /* ATAK and RLSE chunks contain an EGPoint[], piecewise-linear envelope.*/ 
  351. /* The envelope defines a function of time returning Fixed values. It's
  352.  * used to scale the nominal volume specified in the Voice8Header. */
  353.  
  354. To explain the meaning of the ATAK and RLSE chunks, we'll overview 
  355. the envelope generation algorithm. Start at 0 volume, step through 
  356. the ATAK contour, then hold at the sustain level (the last ATAK EGPoint's 
  357. dest), and then step through the RLSE contour. Begin the release at 
  358. the desired note stop time minus the total duration of the release 
  359. contour (the sum of the RLSE EGPoints' durations). The attack contour 
  360. should be cut short if the note is shorter than the release contour.
  361.  
  362. The envelope is a piecewise-linear function. The envelope generator 
  363. interpolates between the EGPoints.
  364.  
  365. Remember to multiply the envelope function by the nominal voice header 
  366. volume and by any desired note volume.
  367.  
  368. Figure 1 shows an example envelope. The attack period is described 
  369. by 4 EGPoints in an ATAK chunk. The release period is described by 
  370. 4 EGPoints in a RLSE chunk. The sustain period in the middle just 
  371. holds the final ATAK level until it's time for the release.
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379.  
  380.  
  381.  
  382.             Figure 1. Amplitude contour.
  383.  
  384. Note: The number of EGPoints in an ATAK or RLSE chunk is its ckSize 
  385. / sizeof(EGPoint). In RAM, the playback program may terminate the 
  386. array with a 0 duration EGPoint.
  387.  
  388. Issue: Synthesizers also provide frequency contour (pitch bend), filtering 
  389. contour (wah-wah), amplitude oscillation (tremolo), frequency oscillation 
  390. (vibrato), and filtering oscillation (leslie). In the future, we may 
  391. define optional chunks to encode these modulations. The contours can 
  392. be encoded in linear segments. The oscillations can be stored as segments 
  393. with rate and depth parameters.
  394.  
  395. Data Chunk BODY
  396.  
  397. The BODY chunk contains the audio data samples.
  398.  
  399. #define ID_BODY MakeID('B', 'O', 'D', 'Y')
  400.  
  401. typedef character BYTE;    /* 8 bit signed number, -128 through 127.    */
  402.  
  403. /* BODY chunk contains a BYTE[], array of audio data samples.    */
  404.  
  405. The BODY contains data samples grouped by octave. Within each octave 
  406. are one-shot and repeat portions. Figure 2 depicts this arrangement 
  407. of samples for an 8SVX where oneShotHiSamples = 24, repeatHiSamples 
  408. = 16, samplesPerHiCycle = 8, and ctOctave = 3. The major divisions 
  409. are octaves, the intermediate divisions separate the one-shot and 
  410. repeat portions, and the minor divisions are cycles.
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.             Figure 2. BODY subdivisions.
  421.  
  422. In general, the BODY has ctOctave octaves of data. The highest frequency 
  423. octave comes first, comprising the fewest samples: oneShotHiSamples 
  424. + repeatHiSamples. Each successive octave contains twice as many samples 
  425. as the next higher octave but the same number of cycles. The lowest 
  426. frequency octave comes last with the most samples: 2ctOctave-1 * (oneShotHiSamp
  427. les + repeatHiSamples).
  428.  
  429. The number of samples in the BODY chunk is
  430.  
  431.   0          (ctOctave-1) 
  432. (2  + ... + 2              * (oneShotHiSamples + repeatHiSamples)
  433.  
  434. Figure 3, below, looks closer at an example waveform within one octave 
  435. of a different BODY chunk. In this example, oneShotHiSamples / samplesPerHiCycl
  436. e = 2 cycles and repeatHiSamples / samplesPerHiCycle = 1 cycle.
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.             Figure 3. Example waveform.
  447.  
  448. To avoid playback "clicks", the one-shot part should begin with a 
  449. small sample value, and the one-shot part should flow smoothly into 
  450. the repeat part, and the end of the repeat part should flow smoothly 
  451. into the beginning of the repeat part.
  452.  
  453. If the VHDR field sCompression - sCmpNone, the BODY chunk is just 
  454. an array of data bytes to feed through the specified decompresser 
  455. function. All this stuff about sample sizes, octaves, and repeat parts 
  456. applies to the decompressed data.
  457.  
  458. Be sure to follow an odd-length BODY chunk with a 0 pad byte.
  459.  
  460. Other Chunks
  461.  
  462. Issue: In the future, we may define an optional chunk containing Fourier 
  463. series coefficients for a repeating waveform. An editor for this kind 
  464. of synthesized voice could modify the coefficients and regenerate 
  465. the waveform.
  466.  
  467.  
  468.  
  469. Appendix A. Quick Reference
  470.  
  471. Type Definitions
  472.  
  473. #define ID_8SVX MakeID('8', 'S', 'V', 'X')
  474. #define ID_VHDR MakeID('V', 'H', 'D', 'R')
  475.  
  476. typedef LONG Fixed;    /* A fixed-point value, 16 bits to the left 
  477.              * of the point and 16 to the right. A Fixed 
  478.              * is a number of 216ths, i.e. 65536ths. */
  479.  
  480. #define Unity 0x10000L    /* Unity = Fixed 1.0 = maximum volume    */
  481.  
  482. /* sCompression: Choice of compression algorithm applied to the samples    */ 
  483.  
  484. #define sCmpNone       0    /* not compressed    */
  485. #define sCmpFibDelta   1    /* Fibonacci-delta encoding (Appendix C) */
  486.     /* Can be more kinds in the future.    */
  487.  
  488. typedef struct {
  489.     ULONG oneShotHiSamples,    /* # samples in the high octave 1-shot part */
  490.         repeatHiSamples,    /* # samples in the high octave repeat part */
  491.         samplesPerHiCycle;    /* # samples/cycle in high octave, else 0   */
  492.     UWORD samplesPerSec;    /* data sampling rate    */
  493.     UBYTE ctOctave,        /* # octaves of waveforms    */ 
  494.     sCompression;        /* data compression technique used    */
  495.     Fixed volume;        /* playback volume from 0 to Unity (full
  496.                   * volume). Map this value into the output
  497.                   * hardware's dynamic range.    */
  498.     } Voice8Header;
  499.  
  500. #define ID_NAME MakeID('N', 'A', 'M', 'E')
  501. /* NAME chunk contains a CHAR[], the voice's name.    */
  502.  
  503. #define ID_Copyright MakeID('(', 'c', ')', ' ')
  504. /* "(c) " chunk contains a CHAR[], the FORM's copyright notice.    */
  505.  
  506. #define ID_AUTH MakeID('A', 'U', 'T', 'H')
  507. /* AUTH chunk contains a CHAR[], the author's name.    */
  508.  
  509. #define ID_ANNO MakeID('A', 'N', 'N', 'O')
  510. /* ANNO chunk contains a CHAR[], author's text annotations.    */
  511.  
  512. #define ID_ATAK MakeID('A', 'T', 'A', 'K')
  513. #define ID_RLSE MakeID('R', 'L', 'S', 'E')
  514.  
  515. typedef struct {
  516.     UWORD duration;    /* segment duration in milliseconds, > 0    */
  517.     Fixed dest;    /* destination volume factor    */
  518.     } EGPoint;
  519.  
  520. /* ATAK and RLSE chunks contain an EGPoint[], piecewise-linear envelope. */
  521. /* The envelope defines a function of time returning Fixed values. It's
  522.  * used to scale the nominal volume specified in the Voice8Header.  */
  523.  
  524. #define ID_BODY MakeID('B', 'O', 'D', 'Y')
  525.  
  526. typedef character BYTE;    /* 8 bit signed number, -128 through 127.    */
  527.  
  528. /* BODY chunk contains a BYTE[], array of audio data samples.    */
  529.  
  530. 8SVX Regular Expression
  531.  
  532. Here's a regular expression summary of the FORM 8SVX syntax. This 
  533. could be an IFF file or part of one.
  534.  
  535. 8SVX    ::= "FORM" #{    "8SVX" VHDR [NAME] [Copyright] [AUTH] ANNO*
  536.         [ATAK] [RLSE] BODY }
  537.  
  538. VHDR    ::= "VHDR" #{ Voice8Header    }
  539. NAME    ::= "NAME" #{ CHAR*    } [0]
  540. Copyright    ::= "(c) " #{ CHAR*    } [0]
  541. AUTH    ::= "AUTH" #{ CHAR*    } [0]
  542. ANNO    ::= "ANNO" #{ CHAR*    } [0]
  543.  
  544. ATAK    ::= "ATAK" #{ EGPoint*    }
  545. RLSE    ::= "RLSE" #{ EGPoint*    }
  546. BODY    ::= "FORM" #{ BYTE*    } [0]
  547.  
  548. The token "#" represents a ckSize LONG count of the following {braced} 
  549. data bytes. E.g. a VHDR's "#" should equal sizeof(Voice8Header). Literal 
  550. items are shown in "quotes", [square bracket items] are optional, 
  551. and "*" means 0 or more replications. A sometimes-needed pad byte 
  552. is shown as "[0]".
  553.  
  554. Actually, the order of chunks in a FORM 8SVX is not as strict as this 
  555. regular expression indicates. The property chunks VHDR, NAME, Copyright, 
  556. and AUTH may actually appear in any order as long as they all precede 
  557. the BODY chunk. The optional data chunks ANNO, ATAK, and RLSE don't 
  558. have to precede the BODY chunk. And of course, new kinds of chunks 
  559. may appear inside a FORM 8SVX in the future.
  560.  
  561.  
  562. Appendix B. 8SVX Example
  563.  
  564. Here's a box diagram for a simple example containing the three octave 
  565. BODY shown earlier in Figure 2.
  566.  
  567.          +-----------------------------------+   
  568.          |'FORM'        362              | 
  569.           +-----------------------------------+   
  570.           |'8SVX'                    |     
  571.           +-----------------------------------+   
  572.           |  +-----------------------------+  |   
  573.           |  |'VHDR'        20       |  | 
  574.           |  |24,16,8,10000,3,0,1.0     |  |   
  575.           |  +-----------------------------+  |   
  576.           |  +-----------------------------+  |   
  577.           |  |'NAME'        11       |  |
  578.           |  |'bass guitar'         |  |   
  579.           |  +-----------------------------+  |   
  580.     |  0                    |
  581.           |  +-----------------------------+  |   
  582.           |  |'(c)'        20       |  |
  583.           |  |1985 Electronic Arts     |  |   
  584.           |  +-----------------------------+  |   
  585.           |  +-----------------------------+  |   
  586.           |  |'BODY'        280      |  |
  587.           |  |1, 2, 3, 4, ...         |  |   
  588.           |  +-----------------------------+  |   
  589.           +-----------------------------------+   
  590.  
  591. The "0" after the NAME chunk is a pad byte.
  592.  
  593.  
  594.  
  595. Appendix B. Standards Committee
  596.  
  597. The following people contributed to the design of this IFF standard:
  598.  
  599. Bob "Kodiak" Burns, Commodore-Amiga
  600. R. J. Mical, Commodore-Amiga
  601. Jerry Morrison, Electronic Arts
  602. Greg Riker, Electronic Arts
  603. Steve Shaw, Electronic Arts
  604. Barry Walsh, Commodore-Amiga
  605.  
  606.  
  607. The "0" after the NAME chunk is a pad byte.
  608.  
  609.  
  610.  
  611. Appendix C. Fibonacci Delta Compression
  612.  
  613. This is Steve Hayes' Fibonacci Delta sound compression technique. 
  614. It's like the traditional delta encoding but encodes each delta in 
  615. a mere 4 bits. The compressed data is half the size of the original 
  616. data plus a 2-byte overhead for the initial value. This much compression 
  617. introduces some distortion, so try it out and use it with discretion.
  618.  
  619. To achieve a reasonable slew rate, this algorithm looks up each stored 
  620. 4-bit value in a table of Fibonacci numbers. So very small deltas 
  621. are encoded precisely while larger deltas are approximated. When it 
  622. has to make approximations, the compressor should adjust all the values 
  623. (forwards and backwards in time) for minimum overall distortion.
  624.  
  625. Here is the decompressor written in the C programming language.
  626.  
  627. /* Fibonacci delta encoding for sound data. */
  628.  
  629. BYTE codeToDelta[16] = {-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21};
  630.  
  631. /* Unpack Fibonacci-delta encoded data from n byte source buffer into 2*n byte
  632.  * dest buffer, given initial data value x. It returns the last data value x
  633.  * so you can call it several times to incrementally decompress the data. */
  634.  
  635. short D1Unpack(source, n, dest, x)
  636.     BYTE source[], dest[];
  637.     LONG n;
  638.     BYTE x;
  639.     {
  640.     BYTE d;
  641.     LONG i, lim;
  642.  
  643.     lim = n <<<< 1;
  644.     for (i = 0; i << lim; ++i)
  645.         {    
  646.         /* Decode a data nybble; high nybble then low nybble. */
  647.         d = source[i >> 1];    /* get a pair of nybbles */
  648.         if (i & 1)        /* select low or high nybble? */
  649.             d &= 0xf;    /* mask to get the low nybble */
  650.         else
  651.             d >>= 4;    /* shift to get the high nybble */
  652.         x += codeToDelta[d];    /* add in the decoded delta */
  653.         dest[i] = x;        /* store a 1-byte sample */
  654.         }
  655.     return(x);
  656.     }
  657.  
  658. /* Unpack Fibonacci-delta encoded data from n byte source buffer into 2*(n-2)
  659.  * byte dest buffer. Source buffer has a pad byte, an 8-bit initial value,
  660.  * followed by n-2 bytes comprising 2*(n-2) 4-bit encoded samples. */
  661.  
  662. void DUnpack(source, n, dest)
  663.     BYTE source[], dest[];
  664.     LONG n;
  665.     {
  666.         D1Unpack(source + 2, n - 2, dest, source[1]);
  667.     }
  668.