home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-03-01 | 54.0 KB | 1,175 lines |
- Sampled sound format
-
- IFF FORM "SAMP" Sampled Sound
-
- Date: Dec 3,1989
- From: Jim Fiore and Jeff Glatt, dissidents
-
- The form "SAMP" is a file format used to store sampled sound data in some
- ways like the current standard, "8SVX". Unlike "8SVX", this new format is not
- restricted to 8 bit sample data. There can be more than one waveform per
- octave, and the lengths of different waveforms do not have to be factors of
- 2. In fact, the lengths (waveform size) and playback mapping (which musical
- notes each waveform will "play") are independently determined for each wave-
- form. Furthermore, this format takes into account the MIDI sample dump stan-
- dard (the defacto standard for musical sample storage), while also incorpo-
- rating the ability to store Amiga specific info (for example, the sample data
- that might be sent to an audio channel which is modulating another channel).
- Although this form can be used to store "sound effects" (typically oneShot
- sounds played at a set pitch), it is primarily intended to correct the many
- deficiencies of the "8SVX" form in regards to musical sampling. Because the
- emphasis is on musical sampling, this format relies on the MIDI (Musical
- Instrument Digital Interface) method of describing "sound events" as does
- virtually all currently manufactured, musical samplers. In addition, it at-
- tempts to incorporate features found on many professional music samplers, in
- anticipation that future Amiga models will implement 16 bit sampling, and
- thus be able to achieve this level of performance. Because this format is
- more complex than "8SVX", programming examples to demonstrate the use of this
- format have been included in both C and assembly. Also, a library of func-
- tions to read and write SAMP files is available, with example applications.
-
- SEMANTICS: When MIDI literature talks about a sample, usually it means a
- collection of many sample points that make up what we call a "wave".
-
-
- =====SIMILARITIES AND DIFFERENCES FROM THE "8SVX" FORM=======
-
- Like "8SVX", this new format uses headers to separate the various sections
- of the sound file into chunks. Some of the chunks are exactly the same since
- there wasn't a need to improve them. The chunks that remain unchanged are as
- follows:
-
- "(c) "
- "AUTH"
- "ANNO"
-
- Since these properties are all described in the original "8SVX" document,
- please refer to that for a description of these chunks and their uses. Like
- the "8SVX" form, none of these chunks are required to be in a sound file.
- If they do appear, they must be padded out to an even number of bytes.
-
- Furthermore, two "8SVX" chunks no longer exist as they have been incorpo-
- rated into the "BODY" chunk. They are:
-
- "ATAK"
- "RLSE"
-
- Since each wave can be completely different than the other waves in the
- sound file (one wave might be middle C on a piano, and another might be a
- snare drum hit), it is necessary for each wave to have its own envelope de-
- scription, and name.
-
- The major changes from the "8SVX" format are in the "MHDR", "NAME", and
- "BODY" chunks.
-
-
- =================THE "SAMP" HEADER================
-
- At the very beginning of a sound file is the "SAMP" header. This is used to
- determine if the disk file is indeed a SAMP sound file. It's attributes are
- as follows:
-
- #define ID_SAMP MakeID('S','A','M','P')
-
- In assembly, this looks like:
-
- CNOP 0,2 ;word-align
-
- SAMP dc.b 'SAMP'
- sizeOfChunks dc.l [sizes of all subsequent chunks summed]
-
-
- =================THE "MHDR" CHUNK=================
-
- The required "MHDR" chunk immediately follows the "SAMP" header and consists
- of the following components:
-
- #define ID_MHDR MakeID('M','H','D','R')
-
- /* MHDR size is dependant on the size of the imbedded PlayMap. */
-
- typedef struct{
- UBYTE NumOfWaves, /* The number of waves in this file */
- Format, /* # of ORIGINAL significant bits from 8-28 */
- Flags, /* Various bits indicate various functions */
- PlayMode, /* determines play MODE of the PlayMap */
- NumOfChans,
- Pad,
- PlayMap[128*4], /* a map of which wave numbers to use for
- each of 128 possible Midi Notes. Default to 4 */
- } MHDRChunk;
-
- The PlayMap is an array of bytes representing wave numbers. There can be a
- total of 255 waves in a "SAMP" file. They are numbered from 1 to 255. A wave
- number of 0 is reserved to indicate "NO WAVE". The Midi Spec 1.0 designates
- that there are 128 possible note numbers (pitches), 0 to 127. The size of an
- MHDR's PlayMap is determined by (NumOfChans * 128). For example, if NumOfChans
- = 4, then an MHDR's PlayMap is 512 bytes. There are 4 bytes in the PlayMap
- for EACH of the 128 Midi Note numbers. For example, the first 4 bytes
- in PlayMap pertain to Midi Note #0. Of those 4 bytes, the first byte is the
- wave number to play back on Amiga audio channel 0. The second byte is the
- wave number to play back on Amiga audio channel 1, etc. In this way, a single
- Midi Note Number could simultaneously trigger a sound event on each of the 4
- Amiga audio channels. If NumOfChans is 1, then the PlayMap is 128 bytes and
- each midi note has only 1 byte in the PlayMap. The first byte pertains to midi
- note #0, the second pertains to midi note #1, etc. In this case, a player
- program might elect to simply play back the PlayMap wave number on any
- available amiga audio channel. If NumOfChans = 0, then there is no imbedded
- PlayMap in the MHDR, no midi note assignments for the waves, and an application
- should play back waves on any channel at their default sampleRates.
- In effect, the purpose of the PlayMap array is to determine which (if any)
- waves are to be played back for each of the 128 possible Midi Note Numbers.
- Usually, the MHDR's NumOfChans will be set to 4 since the Amiga has 4 audio
- channels. For the rest of this document, the NumOfChans is assumed to be 4.
- As mentioned, there can be a total of 255 waves in a "SAMP" file, numbered
- from 1 to 255. A PlayMap wave number of 0 is reserved to indicate that NO WAVE
- number should be played back. Consider the following example:
-
- The first 4 bytes of PlayMap are 1,3,0,200.
-
- If a sample playing program receives (from the serial port or another task
- perhaps) Midi Note Number 0, the following should occur:
-
- 1) The sampler plays back wave 1 on Amiga audio channel
- number 0 (because the first PlayMap byte is 1).
- 2) The sampler plays back wave 3 on Amiga audio channel
- number 1 (because the second PlayMap byte is 3).
- 3) The sampler does not effect Amiga audio channel 2 in
- any way (because the third PlayMap byte is a 0).
- 4) The sampler plays back wave 200 on Amiga audio channel
- number 4 (because the fourth PlayMap byte is 200).
-
- (This assumes INDEPENDANT CHANNEL play MODE to be discussed later in this
- document.)
-
- All four of the PlayMap bytes could even be the same wave number. This would
- cause that wave to be output of all 4 Amiga channels simultaneously.
-
- NumOfWaves is simply the number of waves in the sound file.
-
- Format is the number of significant bits in every sample of a wave.
- For example, if Format = 8, then this means that the sample data is an
- 8 bit format, and that every sample of the wave can be expressed by a single
- BYTE. (A 16 bit sample would need a WORD for every sample point).
-
- Each bit of the Flags byte, when set, means the following:
-
- Bit #0 - File continued on another disc. This might occur if the SAMP file
- was too large to fit on 1 floppy. The accepted practice (as incor-
- porated by Yamaha's TX sampler and Casio's FZ-1 for example) is to
- dump as much as possible onto one disc and set a flag to indicate
- that more is on another disc's file. The name of the files must
- be the related. The continuation file should have its own SAMP header
- MHDR, and BODY chunks. This file could even have its continuation
- bit set, etc. Never chop a sample wave in half. Always close the
- file on 1 disc after the last wave which can be completely saved.
- Resume with the next wave within the BODY of the continuation file.
- Also, the NumOfWaves in each file's BODY should be the number saved
- on that disc (not the total number in all combined disk files).
- See the end of this document for filename conventions.
-
- In C, here is how the PlayMap is used when receiving a midi note-on event:
-
- MapOffset = (UBYTE) MidiNoteNumber * numOfChans;
- /* MidiNoteNumber is the received note number (i.e. the second byte of a
- midi note-on event. numOfChans is from the SAMP MHDR. */
- chan0waveNum = (UBYTE) playMap[MapOffset];
- chan1waveNum = (UBYTE) playMap[MapOffset+1];
- chan2waveNum = (UBYTE) playMap[MapOffset+2];
- chan3waveNum = (UBYTE) playMap[MapOffset+3];
-
- if (chan0waveNum != 0)
- { /* get the pointer to wave #1's data, determine the values
- that need to be passed to the audio device, and play this
- wave on Amiga audio channel #0 (if INDEPENDANT PlayMode) */
- }
-
- /* do the same with the other 3 channel's wave numbers */
-
- In assembly, the "MHDR" structure looks like this:
-
- CNOP 0,2
- MHDR dc.b 'MHDR'
- sizeOfMHDR dc.l [this is 6 + (NumOfChans * 128) ]
- NumOfWaves dc.b [a byte count of the # of waves in the file]
- Format dc.b [a byte count of the # of significant bits in a sample point]
- Flags dc.b [bit mask]
- PlayMode dc.b [play MODE discussed later]
- NumOfChans dc.b [# of bytes per midi note for PlayMap]
- PlayMap ds.b [128 x NumOfChans bytes of initialized values]
-
- and a received MidiNoteNumber is interpreted as follows:
-
- moveq #0,d0
- move.b MidiNoteNumber,d0 ;this is the received midi note #
- bmi.s Illegal_Number ;exit, as this is an illegal midi note #
- moveq #0,d1
- move.b NumOfChans,d1
- mulu.w d1,d0 ;MidiNoteNumber x NumOfChans
- lea PlayMap,a0
- adda.l d0,a0
- move.b (a0)+,chan0waveNum
- move.b (a0)+,chan1waveNum
- move.b (a0)+,chan2waveNum
- move.b (a0),chan3waveNum
-
- tst.b chan0waveNum
- beq.s Chan1
- ;Now get the address of this wave number's sample data, determine the
- ;values that need to be passed to the audio device, and output the wave's
- ;data on Amiga chan 0 (assuming INDEPENDANT PlayMode).
-
- Chan1 tst.b chan1waveNum
- beq.s Chan2
- ;do the same for the other wave numbers, etc.
-
-
- =====================THE "NAME" CHUNK=========================
-
- #define ID_NAME MakeID('N','A','M','E')
-
- If a NAME chunk is included in the file, then EVERY wave must have a name.
- Each name is NULL-terminated. The first name is for the first wave, and it
- is immediately followed by the second wave's name, etc. It is legal for a
- wave's name to be simply a NULL byte. For example, if a file contained 4
- waves and a name chunk, the chunk might look like this:
-
- CNOP 0,2
-
- Name dc.b 'NAME'
- sizeOfName dc.l 30
- dc.b 'Snare Drum',0 ;wave 1
- dc.b 'Piano 1',0 ;wave 2
- dc.b 'Piano A4',0 ;wave 3
- dc.b 0 ;wave 4
- dc.b 0
-
- NAME chunks should ALWAYS be padded out to an even number of bytes. (Hence
- the extra NULL byte in this example). The chunk's size should ALWAYS be even
- consequently. DO NOT USE the typical IFF method of padding a chunk out to an
- even number of bytes, but allowing an odd number size in the header.
-
-
- ==============THE "BODY" CHUNK===============
-
- The "BODY" chunk is CONSIDERABLY different than the "8SVX" form. Like all
- chunks it has an ID.
-
- #define ID_BODY MakeID('B','O','D','Y')
-
- Every wave has an 80 byte waveHeader, followed by its data. The waveHeader
- structure is as follows:
-
- typedef struct {
- ULONG WaveSize; /* total # of BYTES in the wave (MUST be even) */
- UWORD MidiSampNum; /* ONLY USED for Midi Dumps */
- UBYTE LoopType, /* ONLY USED for Midi Dumps */
- InsType; /* Used for searching for a certain instrument */
- ULONG Period, /* in nanoseconds at original pitch */
- Rate, /* # of samples per second at original pitch */
- LoopStart, /* an offset in BYTES (from the beginning of the
- of the wave) where the looping portion of the
- wave begins. Set to WaveSize if no loop. */
- LoopEnd; /* an offset in BYTES (from the beginning of the
- of the wave) where the looping portion of the
- wave ends. Set to WaveSize if no loop. */
- UBYTE RootNote, /* the Midi Note # that plays back original pitch */
- VelStart; /* 0 = NO velocity effect, 128 =
- negative direction, 64 = positive
- direction (it must be one of these 3) */
- UWORD VelTable[16]; /* contains 16 successive offset values
- in BYTES from the beginning of the wave */
-
- /* The ATAK and RLSE segments contain an EGPoint[] piece-wise
- linear envelope just like 8SVX. The structure of an EGPoint[]
- is the same as 8SVX. See that document for details. */
-
- ULONG ATAKsize, /* # of BYTES in subsequent ATAK envelope.
- If 0, then no ATAK data for this wave. */
- RLSEsize, /* # of BYTES in subsequent RLSE envelope
- If 0, then no RLSE envelope follows */
-
- /* The FATK and FRLS segments contain an EGPoint[] piece-wise
- linear envelope for filtering purposes. This is included in
- the hope that future Amiga audio will incorporate a VCF
- (Voltage Controlled Filter). Until then, if you are doing any
- non-realtime digital filtering, you could store info here. */
-
- sizeOfFATK, /* # of BYTES in FATK segment */
- sizeOfFRLS, /* # of BYTES in FRLS segment */
-
- USERsize; /* # of BYTES in the following data
- segment (not including USERtype).
- If zero, then no user data */
- UWORD USERtype; /* See explanation below. If USERsize
- = 0, then ignore this. */
-
- /* End of the waveHeader. */
-
- /* The data for any ATAK, RLSE, FATK, FRLS, USER, and the actual wave
- data for wave #1 follows in this order:
- Now list each EGPoint[] (if any) for the VCA's (Voltage Controlled Amp)
- attack portion.
- Now list each EGPoint[] for the VCA's (Voltage Controlled Amp)
- release portion.
- List EGPoints[] (if any) for FATK.
- List EGPoints[] if any for FRLS */
- Now include the user data here if there is any. Just pad it out
- to an even number of bytes and have USERsize reflect that.
- Finally, here is the actual sample data for the wave. The size (in BYTES)
- of this data is WaveSize. It MUST be padded out to an even number of bytes. */
-
- } WaveFormInfo;
-
- /* END OF WAVE #1 */
-
- /* The waveHeader and data for the next wave would now follow. It is
- the same form as the first wave */
-
-
- In assembly, the BODY chunk looks like this:
-
- CNOP 0,2
- BodyHEADER dc.b 'BODY'
- sizeOfBody dc.l [total bytes in the BODY chunk not counting 8 byte header]
-
- ; Now for the first wave
- WaveSize dc.l ;[total # of BYTES in this wave (MUST be even)]
- MidiSampNum dc.w ;[from Midi Sample Dump] ; ONLY USED for Midi Dumps
- LoopType dc.b ;[0 or 1] ; ONLY USED for Midi Dumps
- InsType dc.b 0
- Period dc.l ;[period in nanoseconds at original pitch]
- Rate dc.l ;[# of samples per second at original pitch]
- LoopStart dc.l ;[an offset in BYTES (from the beginning of the
- ; of the wave) to where the looping
- ; portion of the wave begins.]
- LoopEnd dc.l ;[an offset in BYTES (from the beginning of the
- ; of the wave) to where the looping
- ; portion of the wave ends]
- RootNote dc.b ;[the Midi Note # that plays back original pitch]
- VelStart dc.b ;[0, 64, or 128]
- VelTable dc.w ;[first velocity offset]
- dc.w ;[second velocity offset]...etc
- ds.w 14 ;...for a TOTAL of 16 velocity offsets
-
- ATAKsize dc.l ;# of BYTES in subsequent ATAK envelope.
- ;If 0, then no ATAK data for this wave.
- RLSEsize dc.l ;# of BYTES in subsequent RLSE envelope
- ;If 0, then no RLSE data
- FATKsize dc.l ;# of BYTES in FATK segment
- FRLSsize dc.l ;# of BYTES in FRLS segment
- USERsize dc.l ;# of BYTES in the following User data
- ;segment (not including USERtype).
- ;If zero, then no user data
- USERtype dc.w ; See explanation below. If USERsize
- ; = 0, then ignore this.
-
- ;Now include the EGpoints[] (data) for the ATAK if any
- ;Now the EGpoints for the RLSE
- ;Now the EGpoints for the FATK
- ;Now the EGpoints for the FLSR
- ;Now include the user data here if there is any. Just pad
- ;it out to an even number of bytes.
- ;After the userdata (if any) is the actual sample data for
- ;the wave. The size (in BYTES) of this segment is WaveSize.
- ;It MUST be padded out to an even number of bytes.
-
- ; END OF WAVE #1
-
-
- =============STRUCTURE OF AN INDIVIDUAL SAMPLE POINT=============
-
- Even though the next generation of computers will probably have 16 bit
- audio, and 8 bit sampling will quickly disappear, this spec has sizes expressed
- in BYTES. (ie LoopStart, WaveSize, etc.) This is because each successive
- address in RAM is a byte to the 68000, and so calculating address offsets
- will be much easier with all sizes in BYTES. The Midi sample dump, on the
- other hand, has sizes expressed in WORDS. What this means is that if you
- have a 16 bit wave, for example, the WaveSize is the total number of BYTES,
- not WORDS, in the wave.
- Also, there is no facility for storing a compression type. This is because
- sample data should be stored in linear format (as per the MIDI spec). Currently,
- all music samplers, regardless of their internal method of playing sample data
- must transmit and expect to receive sample dumps in a linear format. It is
- up to each device to translate the linear format into its own compression
- scheme. For example, if you are using an 8 bit compression scheme that yields
- a 14 bit linear range, you should convert each sample data BYTE to a decom-
- pressed linear WORD when you save a sound file. Set the MHDR's Format
- to 14. It is up to the application to do its own compression upon loading
- a file. The midi spec was set up this way because musical samplers need to
- pass sample data between each other, and computers (via a midi interface).
- Since there are almost as many data compression schemes on the market as
- there are musical products, it was decided that all samplers should expect
- data received over midi to be in LINEAR format. It seems logical to store it
- this way on disc as well. Therefore, any software program "need not know" how
- to decompress another software program's SAMP file. When 16 bit sampling is
- eventually implemented there won't be much need for compression on playback
- anyway. The continuation Flag solves the problem of disc storage as well.
- Since the 68000 can only perform math on BYTES, WORDS, or LONGS, it has
- been decided that a sample point should be converted to one of these sizes
- when saved in SAMP as follows:
-
- ORIGINAL significant bits SAMP sample point size
-
- 8 BYTE
- 9 to 16 WORD
- 17 to 28 LONG
-
- Furthermore, the significant bits should be left-justified since it is
- easier to perform math on the samples.
-
- So, for example, an 8 bit sample point (like 8SVX) would be saved as a
- BYTE with all 8 bits being significant. The MHDR's Format = 8. No
- conversion is necessary.
-
- A 12 bit sample point should be stored as a WORD with the significant bits
- being numbers 4 to 15. (i.e shift the 12-bit WORD 4 places to the left). Bits
- 0, 1, 2 and 3 may be zero (unless some 16-bit math was performed and you wish to
- save these results). The MHDR's Format = 12. In this way, the sample
- may be loaded and manipulated as a 16-bit wave, but when transmitted via
- midi, it can be converted back to 12 bits (rounded and shifted right by 4).
-
- A 16 bit sample point would be saved as a WORD with all 16 bits being
- significant. The MHDR's Format = 16. No conversion is necessary.
-
-
- ============== The waveHeader explained ==============
-
- The WaveSize is, as stated, the number of BYTES in the wave's sample table.
- If your sample data consisted of the following 8 bit samples:
-
- BYTE 100,-90,80,-60,30,35,40,-30,-35,-40,00,12,12,10
-
- then WaveSize = 14. (PAD THE DATA OUT TO AN EVEN NUMBER OF BYTES!)
-
- The MidiSampNum is ONLY used to hold the sample number received from a MIDI
- Sample Dump. It has no bearing on where the wave should be placed in a SAMP
- file. Also, the wave numbers in the PlayMap are between 1 to 255, with 1 being
- the number of the first wave in the file. Remember that a wave number of 0 is
- reserved to mean "no wave to play back". Likewise, the LoopType is only used
- to hold info from a MIDI sample dump.
-
- The InsType is explained at the end of this document. Often it will be set
- to 0.
-
- The RootNote is the Midi Note number that will play the wave back at it's
- original, recorded pitch. For example, consider the following excerpt of a
- PlayMap:
-
- PlayMap {2,0,0,4 /* Midi Note #0 channel assignment */
- 4,100,1,0 /* Midi Note #1 " " */
- 1,4,0,0 /* Midi Note #2 " " */
- 60,2,1,1...} /* Midi Note #3 " " */
-
- Notice that Midi Notes 0, 1, and 2 are all set to play wave number 4 (on
- Amiga channels 3, 0, and 1 respectively). If we set wave 4's RootNote = 1,
- then receiving Midi Note number 1 would play back wave 4 (on Amiga channel 0)
- at it's original pitch. If we receive a Midi Note number 0, then wave 4 would
- be played back on channel 3) a half step lower than it's original pitch. If we
- receive Midi Note number 2, then wave 4 would be played (on channel 1) a half
- step higher than it's original pitch. If we receive Midi Note number 3, then
- wave 4 would not be played at all because it isn't specified in the PlayMap
- bytes for Midi Note number 3.
-
- The Rate is the number of samples per second of the original pitch.
- For example, if Rate = 20000, then to play the wave at it's original
- pitch, the sampling period would be:
-
- (1/20000)/.279365 = .000178977
-
- #define AUDIO_HARDWARE_FUDGE .279365
-
- where .279365 is the Amiga Fudge Factor (a hardware limitation). Since the
- amiga needs to see the period in terms of microseconds, move the decimal place
- to the right 6 places and our sampling period = 179 (rounded to an integer).
- In order to play the wave at higher or lower pitches, one would need to
- "transpose" this period value. By specifying a higher period value, the Amiga
- will play back the samples slower, and a lower pitch will be achieved. By
- specifying a lower period value, the amiga will play back the sample faster,
- and a higher pitch will be achieved. By specifying this exact period, the wave
- will be played back exactly "as it was recorded (sampled)". ("This period is
- JUST RIGHT!", exclaimed GoldiLocks.) Later, a method of transposing pitch will
- be shown using a "look up" table of periods. This should prove to be the
- fastest way to transpose pitch, though there is nothing in the SAMP format
- that compels you to do it this way.
-
- The LoopStart is a BYTE offset from the beginning of the wave to where
- the looping portion of the wave begins. For example, if SampleData points to
- the start of the wave, then SampleData + LoopStart is the start address
- of the looping portion. In 8SVX, the looping portion was referred to as
- repeatHiSamples. The data from the start of the wave up to the start of the
- looping portion is the oneShot portion of the wave. LoopEnd is a BYTE
- offset from the beginning of the wave to where the looping portion ends. This
- might be the very end of the wave in memory, or perhaps there might be still
- more data after this point. You can choose to ignore this "trailing" data and
- play back the two other portions of the wave just like an 8SVX file (except
- that there are no other interpolated octaves of this wave).
-
- VelTable contains 16 BYTE offsets from the beginning of the wave. Each
- successive value should be greater (or equal to) the preceding value. If
- VelStart = POSITIVE (64), then for each 8 increments in Midi Velocity
- above 0, you move UP in the table, add this offset to the wave's beginning
- address (start of oneShot), and start playback at that address. Here is a
- table relating received midi note-on velocity vs. start playback address for
- POSITIVE VelStart. SamplePtr points to the beginning of the sample.
-
- If midi velocity = 0, then don't play a sample, this is a note off
- If midi velocity = 1 to 7, then start play at SamplePtr + VelTable[0]
- If midi velocity = 8 to 15, then start at SamplePtr + VelTable[1]
- If midi velocity = 16 to 23, then start at SamplePtr + VelTable[2]
- If midi velocity = 24 to 31, then start at SamplePtr + VelTable[3]
- If midi velocity = 32 to 39, then start at SamplePtr + VelTable[4]
- If midi velocity = 40 to 47, then start at SamplePtr + VelTable[5]
- If midi velocity = 48 to 55, then start at SamplePtr + VelTable[6]
- If midi velocity = 56 to 63, then start at SamplePtr + VelTable[7]
- If midi velocity = 64 to 71, then start at SamplePtr + VelTable[8]
- If midi velocity = 72 to 79, then start at SamplePtr + VelTable[9]
- If midi velocity = 80 to 87, then start at SamplePtr + VelTable[10]
- If midi velocity = 88 to 95, then start at SamplePtr + VelTable[11]
- If midi velocity = 96 to 103, then start at SamplePtr + VelTable[12]
- If midi velocity = 104 to 111, then start at SamplePtr + VelTable[13]
- If midi velocity = 112 to 119, then start at SamplePtr + VelTable[14]
- If midi velocity = 120 to 127, then start at SamplePtr + VelTable[15]
-
- We don't want to specify a scale factor and use integer division to find the
- sample start. This would not only be slow, but also, it could never be certain
- that the resulting sample would be a zero crossing if the start point is calcu-
- lated "on the fly". The reason for having a table is so that the offsets can be
- be initially set on zero crossings via an editor. This way, no audio "clicks"
- guaranteed. This table should provide enough resolution.
-
- If VelStart = NEGATIVE (128), then for each 8 increments in midi
- velocity, you start from the END of VelTable, and work backwards. Here
- is a table for NEGATIVE velocity start.
-
- If midi velocity = 0, then don't play a sample, this is a note off
- If midi velocity = 1 to 7, then start play at SamplePtr + VelTable[15]
- If midi velocity = 8 to 15, then start at SamplePtr + VelTable[14]
- If midi velocity = 16 to 23, then start at SamplePtr + VelTable[13]
- If midi velocity = 24 to 31, then start at SamplePtr + VelTable[12]
- If midi velocity = 32 to 39, then start at SamplePtr + VelTable[11]
- If midi velocity = 40 to 47, then start at SamplePtr + VelTable[10]
- If midi velocity = 48 to 55, then start at SamplePtr + VelTable[9]
- If midi velocity = 56 to 63, then start at SamplePtr + VelTable[8]
- If midi velocity = 64 to 71, then start at SamplePtr + VelTable[7]
- If midi velocity = 72 to 81, then start at SamplePtr + VelTable[6]
- If midi velocity = 80 to 87, then start at SamplePtr + VelTable[5]
- If midi velocity = 88 to 95, then start at SamplePtr + VelTable[4]
- If midi velocity = 96 to 103, then start at SamplePtr + VelTable[3]
- If midi velocity = 104 to 111, then start at SamplePtr + VelTable[2]
- If midi velocity = 112 to 119, then start at SamplePtr + VelTable[1]
- If midi velocity = 120 to 127, then start at SamplePtr + VelTable[0]
-
- In essence, increasing midi velocity starts playback "farther into" the wave
- for POSITIVE VelStart. Increasing midi velocity "brings the start point
- back" toward the beginning of the wave for NEGATIVE VelStart.
-
- If VelStart is set to NONE (0), then the wave's playback start should
- not be affected by the table of offsets.
-
- What is the use of this feature? As an example, when a snare drum is hit with
- a soft volume, its initial attack is less pronounced than when it is struck
- hard. You might record a snare being hit hard. By setting VelStart to a
- NEGATIVE value and setting up the offsets in the Table, a lower midi velocity
- will "skip" the beginning samples and thereby tend to soften the initial
- attack. In this way, one wave yields a true representation of its instrument
- throughout its volume range. Furthermore, stringed and plucked instruments
- (violins, guitars, pianos, etc) exhibit different attacks at different
- volumes. VelStart makes these kinds of waves more realistic via a software
- implementation. Also, an application program can allow the user to enable/
- disable this feature. See the section "Making the Velocity Table" for info on
- how to best choose the 16 table values.
-
-
- =========MIDI VELOCITY vs. AMIGA CHANNEL VOLUME============
-
- The legal range for Midi Velocity bytes is 0 to 127. (A midi velocity of 0
- should ALWAYS be interpreted as a note off).
-
- The legal range for Amiga channel volume is 0 to 64. Since this is half of
- the midi range, a received midi velocity should be divided by 2 and add 1
- (but only AFTER checking for a received midi velocity of 0).
-
- An example of how to implement a received midi velocity in C:
-
- If ( ReceivedVelocity != 0 && ReceivedVelocity < 128 )
- { /* the velocity byte of a midi message */
- If (velStart != 0)
- {
- tableEntry = ReceivedVelocity / 8;
- If (velStart == 64)
- { /* Is it POSITIVE */
- startOfWave = SamplePtr + velTable[tableEntry];
- /* ^where to find the sample start point */
- }
- If (velStart == 128)
- { /* Is it NEGATIVE */
- startOfWave = SamplePtr + velTable[15 - tableEntry];
- }
- volume = (receivedVelocity/2 + 1; /* playback volume */
- /* Now playback the wave */
- }
- }
-
- In assembly,
-
- lea SampleData,a0 ;the start addr of the sample data
- moveq #0,d0
- move.b ReceivedVelocity,d0 ;the velocity byte of a midi message
- beq A_NoteOff ;If zero, branch to a routine to
- ;process a note-off message.
-
- bmi Illegal_Vol ;exit if received velocity > 127
- ;---Check for velocity start feature ON, and direction
- move.b VelStart,d1
- beq.s Volume ;skip the velocity offset routine if 0
- bmi.s NegativeVel ;is it NEGATIVE? (128)
-
- ;---Positive velocity offset
- move.l d0,d1 ;duplicate velocity
- lsr.b #3,d1 ;divide by 8
- add.b d1,d1 ;x 2 because we need to fetch a word
- lea VelTable,a1 ;start at table's HEAD
- adda.l d1,a1 ;go forward
- move.w (a1),d1 ;get the velocity offet
- adda.l d1,a0 ;where to start actual playback
- bra.s Volume
-
- NegativeVel:
- ;---Negative velocity offset
- move.l d0,d1 ;duplicate velocity
- lsr.b #3,d1 ;divide by 8
- add.b d1,d1 ;x 2 because we need to fetch a word
- lea VelTable+30,a1 ;start at table's END
- suba.l d1,a1 ;go backwards
- move.w (a1),d1 ;get the velocity offset
- adda.l d1,a0 ;where to start actual playback
-
- ;---Convert Midi velocity to an Amiga volume
- Volume lsr.b #1,d0 ;divide by 2
- addq.b #1,d0 ;an equivalent Amiga volume
-
- ;---Now a0 and d0 are the address of sample start, and volume
-
-
- ================= AN EGpoint (envelope generator) ================
-
- A single EGpoint is a 6 byte structure as follows:
-
- EGpoint1: dc.w ;[the duration in milliseconds]
- dc.l ;[the volume factor - fixed point, 16 bits to the left of the
- ;decimal point and 16 to the right.]
-
- The volume factor is a fixed point where 1.0 ($00010000) represents the
- MAXIMUM volume possible. (i.e. No volume factor should exceed this value.)
- The last EGpoint in the ATAK is always the sustain point. Each EG's volume
- is determined from 0.0, not as a difference from the previous EG's volume.
- I hope that this clears up the ambiguity in the original 8SVX document.
- So, to recreate an amplifier envelope like this:
-
- /\
- / \____
- / \
- / \
-
- | | | | |
- 1 2 3 4
-
- Stages 1, 2, and 3 would be in the ATAK data, like so:
-
- ;Stage 1
- dc.w 100 ;take 100ms
- dc.l $00004000 ;go to this volume
- dc.w 100
- dc.l $00008000
- dc.w 100
- dc.l $0000C000
- dc.w 100
- dc.l $00010000 ;the "peak" of our attack is full volume
- ;Stage 2
- dc.w 100
- dc.l $0000C000 ;back off to this level
- dc.l 100
- dc.l $00008000 ;this is where we hold (SUSTAIN) until the note is turned
- ;off. (We are now holding at stage 3)
-
- Now the RLSE data would specify stage 4 as follows:
- dc.w 100
- dc.l $00004000
- dc.w 100
- dc.l $00000000 ;the volume is 0
-
-
- ===============ADDITIONAL USER DATA SECTION=================
-
- There is a provision for storing user data for each wave. This is where an
- application can store Amiga hardware info, or other, application specific info.
- The waveHeader's USERtype tells what kind of data is stored. The current
- types are:
-
- #define SPECIFIC 0
- #define VOLMOD 1
- #define PERMOD 2
- #define LOOPING 3
-
- SPECIFIC (0) - application specific data. It should be stored
- in a format that some application can immediately
- recognize. (i.e. a "format within" the SAMP format)
- If the USERtype is SPECIFIC, and an application
- doesn't find some sort of header that it can re-
- cognize, it should conclude that this data was
- put there by "someone else", and ignore the data.
-
- VOLMOD (1) - This data is for volume modulation of an Amiga
- channel as described by the ADKCON register. This
- data will be sent to the modulator channel of the
- channel set to play the wave.
-
- PERMOD (2) - This data is for period modulation of an Amiga
- channel as described by the ADKCON register. This
- data will be sent to the modulator channel of the
- channel set to play the wave.
-
- LOOPING (3) - This contains more looping points for the sample.
- There are some samplers that allow more than just
- one loop (Casio products primarily). Additional
- looping info can be stored in this format:
-
- UWORD numOfLoops; /* number of loop points to follow */
-
- ULONG StartLoop1, /* BYTE offset from the beginning of
- the sample to the start of loop1 */
- EndLoop1, /* BYTE offset from the beginning of
- the sample to the end of loop1 */
-
- StartLoop2, /* ...etc */
-
-
- =========Converting Midi Sample Dump to SAMP=========
-
- SEMANTICS: When MIDI literature talks about a sample, usually it means a
- collection of many sample points that make up what we call "a wave".
- Therefore, a Midi Sample Dump sends all the sample data that makes up ONE
- wave. A SAMP file is designed to hold up to 255 of these waves (midi dumps).
-
- The Midi Sample Dump specifies playback rate only in terms of a sample
- PERIOD in nanoseconds. SAMP also expresses playback in terms of samples per
- second (frequency). The Amiga needs to see its period rounded to the nearest
- microsecond. If you take the sample period field of a Midi sample Dump (the
- 8th, 9th, and 10th bytes of the Dump Header LSB first) which we will call
- MidiSamplePer, and the Rate of a SAMP file, here is the relationship:
-
- Rate = (1/MidiSamplePer) x 10E9
-
- Also the number of samples (wave's length) in a Midi Sample Dump (the 11th,
- 12th, and 13th bytes of the Dump header) is expressed in WORDS. SAMP's
- WaveSize is expressed in the number of BYTES. (For the incredibly stupid),
- the relationship is:
-
- WaveSize = MidiSampleLength x 2
-
- A Midi sample dump's LoopStart point and LoopEnd point are also in WORDS as
- versus the SAMP equivalents expressed in BYTES.
-
- A Midi sample dump's sample number can be 0 to 65535. A SAMP file can hold
- up to 255 waves, and their numbers in the playmap must be 1 to 255. (A single,
- Midi Sample Dump only sends info on one wave.) When recieving a Midi Sample
- Dump, just store the sample number (5th and 6th bytes of the Dump Header LSB
- first) in SAMP's MidiSampNum field. Then forget about this number until you
- need to send the wave back to the Midi instrument from whence it came.
-
- A Midi Dump's loop type can be forward, or forward/backward. Amiga hardware
- supports forward only. You should store the Midi Dump's LoopType byte here,
- but ignore it otherwise until/unless Amiga hardware supports "reading audio
- data" in various ways. If so, then the looptype is as follows:
-
- forward = 0, backward/forward = 1
-
- A Midi Dump's sample format byte is the same as SAMP's.
-
-
- ===================== INTERPRETING THE PLAYMODE ==========================
-
- PlayMode specifies how the bytes in the PlayMap are to be interpreted.
- Remember that a PlayMap byte of 0 means "No Wave to Play".
-
- #define INDEPENDANT 0
- #define MULTI 1
- #define STEREO 2
- #define PAN 3
-
- PlayMode types:
-
- INDEPENDANT (0) - The wave #s for a midi note are to be output on
- Amiga audio channels 0, 1, 2, and 3 respectively.
- If the NumOfChans is < 4, then only use that many channels.
-
- MULTI (1) - The first wave # (first of the PlayMap bytes) for a
- midi note is to be output on any free channel. The other
- wave numbers are ignored. If all four channels are in
- play, the application can decide whether to "steal" a
- channel.
-
- STEREO (2) - The first wave # (first of the PlayMap bytes) is to be
- output of the Left stereo jack (channel 1 or 3) and if
- there is a second wave number (the second of the PlayMap
- bytes), it is to be output the Right jack (channel 2 or 4).
- The other wave numbers are ignored.
-
- PAN (3) - This is just like STEREO except that the volume of wave 1
- should start at its initial volume (midi velocity) and
- fade to 0. At the same rate, wave 2 should start at 0
- volume and rise to wave #1's initial level. The net
- effect is that the waves "cross" from Left to Right in
- the stereo field. This is most effective when the wave
- numbers are the same. (ie the same wave) The application
- program should set the rate. Also, the application can
- reverse the stereo direction (ie Right to Left fade).
-
- The most important wave # to be played back by a midi note should be the
- first of the PlayMap bytes. If the NumOfChans > 1, the second PlayMap byte
- should be a defined wave number as well (even if it is deliberately set to the
- same value as the first byte). This insures that all 4 PlayModes will have some
- effect on a given SAMP file. Also, an application should allow the user to
- change the PlayMode at will. The PlayMode stored in the SAMP file is only a
- default or initial set-up condition.
-
-
- =================== MAKING A TRANSPOSE TABLE =====================
-
- In order to allow a wave to playback over a range of musical notes, (+/-
- semitones), its playback rate must be raised or lowered by a set amount.
- From one semitone to the next, this set amount is by a factor of the 12th
- root of 2 (assuming a western, equal-tempered scale). Here is a table that
- shows what factor would need to be multiplied by the sampling rate in order
- to transpose the wave's pitch.
-
- Pitch in relation to the Root Multiply Rate by this amount
- ------------------------------- ------------------------------
- DOWN 6 semitones 0.5
- DOWN 5 1/2 semitones 0.529731547
- DOWN 5 semitones 0.561231024
- DOWN 4 1/2 semitones 0.594603557
- DOWN 4 semitones 0.629960525
- DOWN 3 1/2 semitones 0.667419927
- DOWN 3 semitones 0.707106781
- DOWN 2 1/2 semitones 0.749153538
- DOWN 2 semitones 0.793700526
- DOWN 1 1/2 semitones 0.840896415
- DOWN 1 semitones 0.890898718
- DOWN 1/2 semitone 0.943874312
- ORIGINAL_PITCH 1.0 /* rootnote's pitch */
- UP 1/2 semitone 1.059463094
- UP 1 semitones 1.122562048
- UP 1 1/2 semitones 1.189207115
- UP 2 semitones 1.259921050
- UP 2 1/2 semitones 1.334839854
- UP 3 semitones 1.414213562
- UP 3 1/2 semitones 1.498307077
- UP 4 semitones 1.587401052
- UP 4 1/2 semitones 1.681792830
- UP 5 semitones 1.781797436
- UP 5 1/2 semitones 1.887748625
- UP 6 semitones 2
-
- For example, if the wave's Rate is 18000 hz, and you wish to play
- the wave UP 1 semitone, then the playback rate is:
-
- 18000 x 1.122562048 = 20206.11686 hz
-
- The sampling period for the Amiga is therefore:
-
- (1/20206.11686)/.279365 = .000177151
-
- and to send it to the Audio Device, it is rounded and expressed in micro-
- seconds: 177
-
- Obviously, this involves floating point math which can be time consuming
- and impractical for outputing sound in real-time. A better method is to con-
- struct a transpose table that contains the actual periods already calculated
- for every semitone. The drawback of this method is that you need a table for
- EVERY DIFFERENT Rate in the SAMP file. If all the Rates in the
- file happened to be the same, then only one table would be needed. Let's
- assume that this is the case, and that the Rate = 18000 hz. Here is a
- table containing enough entries to transpose the waves +/- 6 semitones.
-
- Pitch in relation to the Root The Amiga Period (assuming rate = 18000 hz)
- ------------------------------- ------------------------------
- Transposition_table[TRANS_TABLE_SIZE]={
- /* DOWN 6 semitones */ 398,
- /* DOWN 5 1/2 semitones */ 375,
- /* DOWN 5 semitones */ 354,
- /* DOWN 4 1/2 semitones */ 334,
- /* DOWN 4 semitones */ 316,
- /* DOWN 3 1/2 semitones */ 298,
- /* DOWN 3 semitones */ 281,
- /* DOWN 2 1/2 semitones */ 265,
- /* DOWN 2 semitones */ 251,
- /* DOWN 1 1/2 semitones */ 236,
- /* DOWN 1 semitones */ 223,
- /* DOWN 1/2 semitone */ 211,
- /* ORIGINAL_PITCH */ 199, /* rootnote's pitch */
- /* UP 1/2 semitone */ 187,
- /* UP 1 semitones */ 177,
- /* UP 1 1/2 semitones */ 167,
- /* UP 2 semitones */ 157,
- /* UP 2 1/2 semitones */ 148,
- /* UP 3 semitones */ 141,
- /* UP 3 1/2 semitones */ 133,
- /* Since the minimum Amiga period = 127 the following
- are actually out of range. */
- /* UP 4 semitones */ 125,
- /* UP 4 1/2 semitones */ 118,
- /* UP 5 semitones */ 112,
- /* UP 5 1/2 semitones */ 105,
- /* UP 6 semitones */ 99 };
-
-
- Let's assume that (according to the PlayMap) midi note #40 is set to play
- wave number 3. Upon examining wave 3's structure, we discover that the
- Rate = 18000, and the RootNote = 38. Here is how the Amiga sampling
- period is calulated using the above 18000hz "transpose chart" in C:
- /* MidiNoteNumber is the received midi note's number (here 40) */
-
- #define ORIGINAL_PITCH TRANS_TABLE_SIZE/2 + 1
- /* TRANS_TABLE_SIZE is the number of entries in the transposition table
- (dynamic, ie this can change with the application) */
-
- transposeAmount = (LONG) (MidiNoteNumber - rootNote); /* make it a SIGNED LONG */
- amigaPeriod = Transposition_table[ORIGINAL_PITCH + transposeAmount];
-
-
- In assembly, the 18000hz transpose chart and above example would be:
-
- Table dc.w 398
- dc.w 375
- dc.w 354
- dc.w 334
- dc.w 316
- dc.w 298
- dc.w 281
- dc.w 265
- dc.w 251
- dc.w 236
- dc.w 223
- dc.w 211
- ORIGINAL_PITCH dc.w 199 ; rootnote's pitch
- dc.w 187
- dc.w 177
- dc.w 167
- dc.w 157
- dc.w 148
- dc.w 141
- dc.w 133
- ; Since the minimum Amiga period = 127, the following
- ; are actually out of range.
- dc.w 125
- dc.w 118
- dc.w 112
- dc.w 105
- dc.w 99
-
- lea ORIGINAL_PITCH,a0
- move.b MidiNoteNumber,d0 ;the received note number
- sub.b RootNote,d0 ;subtract the wave's root note
- ext.w d0
- ext.l d0 ;make it a signed LONG
- add.l d0,d0 ;x 2 in order to fetch a WORD
- adda.l d0,a0
- move.w (a0),d0 ;the Amiga Period (WORD)
-
- Note that these examples don't check to see if the transpose amount is
- beyond the number of entries in the transpose table. Nor do they check if
- the periods in the table are out of range of the Amiga hardware.
-
-
- ===================== MAKING THE VELOCITY TABLE ======================
-
- The 16 entries in the velocity table should be within the oneShot portion of
- the sample (ie not in the looping portion). THe first offset, VelTable[0]
- should be set to zero (in order to play back from the beginning of the data).
- The subsequent values should be increasing numbers. If you are using a graphic
- editor, try choosing offsets that will keep you within the initial attack
- portion of the wave. In practice, these values will be relatively close
- together within the wave. Always set the offsets so that when they are added
- to the sample start point, the resulting address points to a sample value of
- zero (a zero crossing point). This will eliminate pops and clicks at the
- beginning of the playback.
-
- In addition, the start of the wave should be on a sample with a value of
- zero. The last sample of the oneShot portion and the first sample of the
- looping portion should be approximately equal, (or zero points). The same is
- true of the first and last samples of the looping portion. Finally, try to
- keep the slopes of the end of the oneShot, the beginning of the looping, and
- the end of the looping section, approximately equal. All this will eliminate
- noise on the audio output and provide "seamless" looping.
-
-
- ======================== THE INSTRUMENT TYPE ==========================
-
- Many SMUS players search for certain instruments by name. Not only is this
- slow (comparing strings), but if the exact name can't be found, then it is
- very difficult and time-consuming to search for a suitable replacement. For
- this reason, many SMUS players resort to "default" instruments even if these
- are nothing like the desired instruments. The InsType byte in each
- waveHeader is meant to be a numeric code which will tell an SMUS player
- exactly what the instrument is. In this way, the SMUS player can search for
- the correct "type" of instrument if it can't find the desired name. The type
- byte is divided into 2 nibbles (4 bits for you C programmers) with the low
- 4 bits representing the instrument "family" as follows:
-
- 1 = STRING, 2 = WOODWIND, 3 = KEYBOARD, 4 = GUITAR, 5 = VOICE, 6 = DRUM1,
- 7 = DRUM2, 8 = PERCUSSION1, 9 = BRASS1, A = BRASS2, B = CYMBAL, C = EFFECT1,
- D = EFFECT2, E = SYNTH, F is undefined at this time
-
- Now, the high nibble describes the particular type within that family.
-
- For the STRING family, the high nibble is as follows:
-
- 1 = VIOLIN BOW, 2 = VIOLIN PLUCK, 3 = VIOLIN GLISSANDO, 4 = VIOLIN TREMULO,
- 5 = VIOLA BOW, 6 = VIOLA PLUCK, 7 = VIOLA GLIS, 8 = VIOLA TREM, 9 = CELLO
- BOW, A = CELLO PLUCK, B = CELLO GLIS, C = CELLO TREM, D = BASS BOW, E =
- BASS PLUCK (jazz bass), F = BASS TREM
-
- For the BRASS1 family, the high nibble is as follows:
-
- 1 = BARITONE SAX, 2 = BARI GROWL, 3 = TENOR SAX, 4 = TENOR GROWL, 5 = ALTO
- SAX, 6 = ALTO GROWL, 7 = SOPRANO SAX, 8 = SOPRANO GROWL, 9 = TRUMPET, A =
- MUTED TRUMPET, B = TRUMPET DROP, C = TROMBONE, D = TROMBONE SLIDE, E =
- TROMBONE MUTE
-
- For the BRASS2 family, the high nibble is as follows:
-
- 1 = FRENCH HORN, 2 = TUBA, 3 = FLUGAL HORN, 4 = ENGLISH HORN
-
- For the WOODWIND family, the high nibble is as follows:
-
- 1 = CLARINET, 2 = FLUTE, 3 = PAN FLUTE, 4 = OBOE, 5 = PICCOLO, 6 = RECORDER,
- 7 = BASSOON, 8 = BASS CLARINET, 9 = HARMONICA
-
- For the KEYBOARD family, the high nibble is as follows:
-
- 1 = GRAND PIANO, 2 = ELEC. PIANO, 3 = HONKYTONK PIANO, 4 = TOY PIANO, 5 =
- HARPSICHORD, 6 = CLAVINET, 7 = PIPE ORGAN, 8 = HAMMOND B-3, 9 = FARFISA
- ORGAN, A = HARP
-
- For the DRUM1 family, the high nibble is as follows:
-
- 1 = KICK, 2 = SNARE, 3 = TOM, 4 = TIMBALES, 5 = CONGA HIT, 6 = CONGA SLAP,
- 7 = BRUSH SNARE, 8 = ELEC SNARE, 9 = ELEC KICK, A = ELEC TOM, B = RIMSHOT,
- C = CROSS STICK, D = BONGO, E = STEEL DRUM, F = DOUBLE TOM
-
- For the DRUM2 family, the high nibble is as follows:
-
- 1 = TIMPANI, 2 = TIMPANI ROLL, 3 = LOG DRUM
-
- For the PERCUSSION1 family, the high nibble is as follows:
-
- 1 = BLOCK, 2 = COWBELL, 3 = TRIANGLE, 4 = TAMBOURINE, 5 = WHISTLE, 6 =
- MARACAS, 7 = BELL, 8 = VIBES, 9 = MARIMBA, A = XYLOPHONE, B = TUBULAR BELLS,
- C = GLOCKENSPEIL
-
- For the CYMBAL family, the high nibble is as follows:
-
- 1 = CLOSED HIHAT, 2 = OPEN HIHAT, 3 = STEP HIHAT, 4 = RIDE, 5 = BELL CYMBAL,
- 6 = CRASH, 7 = CHOKE CRASH, 8 = GONG, 9 = BELL TREE, A = CYMBAL ROLL
-
- For the GUITAR family, the high nibble is as follows:
-
- 1 = ELECTRIC, 2 = MUTED ELECTRIC, 3 = DISTORTED, 4 = ACOUSTIC, 5 = 12-STRING,
- 6 = NYLON STRING, 7 = POWER CHORD, 8 = HARMONICS, 9 = CHORD STRUM, A = BANJO,
- B = ELEC. BASS, C = SLAPPED BASS, D = POPPED BASS, E = SITAR, F = MANDOLIN
- (Note that an acoustic picked bass is found in the STRINGS - Bass Pluck)
-
- For the VOICE family, the high nibble is as follows:
-
- 1 = MALE AHH, 2 = FEMALE AHH, 3 = MALE OOO, 4 = FEMALE OOO, 5 = FEMALE
- BREATHY, 6 = LAUGH, 7 = WHISTLE
-
- For the EFFECTS1 family, the high nibble is as follows:
-
- 1 = EXPLOSION, 2 = GUNSHOT, 3 = CREAKING DOOR OPEN, 4 = DOOR SLAM, 5 = DOOR
- CLOSE, 6 = SPACEGUN, 7 = JET ENGINE, 8 = PROPELLER, 9 = HELOCOPTER, A =
- BROKEN GLASS, B = THUNDER, C = RAIN, D = BIRDS, E = JUNGLE NOISES, F =
- FOOTSTEP
-
- For the EFFECTS2 family, the high nibble is as follows:
-
- 1 = MACHINE GUN, 2 = TELEPHONE, 3 = DOG BARK, 4 = DOG GROWL, 5 = BOAT
- WHISTLE, 6 = OCEAN, 7 = WIND, 8 = CROWD BOOS, 9 = APPLAUSE, A = ROARING
- CROWDS, B = SCREAM, C = SWORD CLASH, D = AVALANCE, E = BOUNCING BALL,
- F = BALL AGAINST BAT OR CLUB
-
- For the SYNTH family, the high nibble is as follows:
-
- 1 = STRINGS, 2 = SQUARE, 3 = SAWTOOTH, 4 = TRIANGLE, 5 = SINE, 6 = NOISE
-
- So, for example if a wave's type byte was 0x26, this would be a SNARE DRUM.
- If a wave's type byte is 0, then this means "UNKNOWN" instrument.
-
-
- ===================== THE ORDER OF THE CHUNKS =========================
-
- The SAMP header obviously must be first in the file, followed by the MHDR
- chunk. After this, the ANNO, (c), AUTH and NAME chunks may follow in any
- order, though none of these need appear in the file at all. The BODY chunk
- must be last.
-
-
- ================= FILENAME CONVENTIONS =================
-
- For when it becomes necessary to split a SAMP file between floppies using
- the Continuation feature, the filenames should be related. The method is the
- following:
-
- The "root" file has the name that the user chose to save under. Subsequent
- files have an ascii number appended to the name to indicate what sublevel the
- file is in. In this way, a program can reload the files in the proper order.
-
- For example, if a user saved a file called "Gurgle", the first continuation
- file should be named "Gurgle1", etc.
-
-
- ============ WHY DOES ANYONE NEED SUCH A COMPLICATED FILE? ==============
- (or "What's wrong with 8SVX anyway?")
-
- In a nutshell, 8SVX is not adequate for professional music sampling. First
- of all, it is nearly impossible to use multi-sampling (utilizing several,
- different samples of any instrument throughout its musical range). This very
- reason alone makes it impossible to realistically reproduce a musical in-
- strument, as none in existance (aside from an electronic organ) uses inter-
- polations of a single wave to create its musical note range.
- Also, stretching a sample out over an entire octave range does grotesque
- (and VERY unmusical) things to such elements as the overtone structure,
- wind/percussive noises, the instrument's amplitude envelope, etc. The 8SVX
- format is designed to stretch the playback in exactly this manner.
- 8SVX ignores MIDI which is the de facto standard of musical data transmission.
- 8SVX does not allow storing data for features that are commonplace to pro-
- fessional music samplers. Such features are: velocity sample start, separate
- filter and envelopes for each sample, separate sampling rates, and various
- playback modes like stereo sampling and panning.
- SAMP attempts to remedy all of these problems with a format that can be
- used by a program that simulates these professional features in software. The
- format was inspired by the capabilities of the following musical products:
-
- EMU's EMAX, EMULATOR
- SEQUENTIAL CIRCUIT's PROPHET 2000, STUDIO 440
- ENSONIQ's MIRAGE
- CASIO's FZ-1
- OBERHEIM's DPX
- YAMAHA TX series
-
- So why does the Amiga need the SAMP format? Because professional musician's
- are buying computers. With the firm establishment of MIDI, musician's are
- buying and using a variety of sequencers, patch editors, and scoring programs.
- It is now common knowledge amoung professional musicians that the Amiga
- lags far behind IBM clones, Macintosh, and Atari ST computers in both music
- software and hardware support. Both Commodore and the current crop of short-
- sighted 3rd party Amiga developers are pigeon-holing the Amiga as "a video
- computer". It is important for music software to exploit whatever capabili-
- ties the Amiga offers before the paint and animation programs, genlocks,
- frame-grabbers, and video breadboxes are the only applications selling
- for the Amiga. Hopefully, this format, with the SAMP disk I/O library will
- make it possible for Amiga software to attain the level of professionalism
- that the other machines now boast, and the Amiga lacks.
-