Ensoniq .ECW File Format

Description

The mid-1990s saw the release of a low-cost sound card known as the Ensoniq AudioPCI. This card uses a sample-based software MIDI synthesizer for internal "MIDI playback". The samples used by the synth are stored in "wavesets", which are files with an extension of .ECW. The manufacturer, Ensoniq (and later Sound Blaster, who bought Ensoniq and continued the AudioPCI product line with descendents like the Sound Blaster PCI64 and PCI128), never released an editor for these files, nor did they release any info on the file format. As an exercise, I reverse engineered the majority of the format in 2003-2004, with occasional revisions in 2009.

Ensoniq .ECW files store articulation and sample data used by the software synthesizer of sound cards equipped with an ES1370, ES1371, or ES1373 chip. These sound cards include the Ensoniq AudioPCI, the Sound Blaster! AudioPCI, the Sound Blaster! PCI64, the Sound Blaster! PCI128, and the Sound Blaster Live!. The file also includes metadata that is largely textual, some of which is unused by any known application. Additionally, the file seems to make use of obfuscation by employing multiple banks of extraneous pointers.

The "Configurator" (file name "ENSCFG32.EXE") is an auxilliary application included with the Ensoniq/Sound Blaster installation package. The Configurator lets the user switch between multiple wavesets via a GUI, rather than manually editing a configuration file or the Windows Registry. It also displays metadata stored in the waveset file, such as the name, version number, and any copyright information for the selected waveset.

Specification

The .ECW file uses Intel byte order (LSB first).

The byte counts below are given in decimal, not hexadecimal. When the "TYPE" is "string", the count is the length of the string in characters.

File Header

The .ECW file header stores the text that is shown when the waveset is loaded in the configurator. It also specifies the size and quantity of the other sections of the file. The file header is 1930 bytes long.

OFFSET              Count TYPE   Description
0000h                   4 string File ID (always "ECLW")
0004h                   4 string Spacer*
0008h                   1 dword  File offset where allocation chunk starts
000ch                   1 dword  Unknown. Always has value of 16.
0010h                  80 string Copyright info for this waveset
0060h                  80 string Waveset name
00b0h                 256 string Filename of this waveset (ignored by the
                                 configurator)
01b0h                  80 string Description of this waveset
0200h                1280 string Information on this waveset. Usable length is
                                 only 963 characters or so, because the
                                 configurator will refuse to load the waveset
                                 if characters 964 to 1280 of this string are
                                 anything but nulls.
0700h                   4 string Spacer
0704h                   1 dword  File offset where bank map starts
0708h                   1 dword  Length in bytes of the bank map (always 256)
070ch                   1 dword  Number of bank maps (always 1)
0710h                   1 dword  File offset where drum kit map starts
0714h                   1 dword  Length in bytes of the drum kit map (always
                                 256)
0718h                   1 dword  Number of drum kit maps (always 1)
071ch                   1 dword  File offset where MIDI patch maps start
0720h                   1 dword  Total length in bytes of all MIDI patch maps 
                                 (always number of MIDI patch maps multiplied
                                 by 256)
0724h                   1 dword  Number of MIDI patch maps
0728h                   1 dword  File offset where drum note maps start
072ch                   1 dword  Total length in bytes of all drum note maps
                                 (always number of drum note maps multiplied by
                                 256)
0730h                   1 dword  Number of drum note maps
0734h                   1 dword  File offset where instrument headers start
0738h                   1 dword  Total length in bytes of all instrument
                                 headers (always number of instrument headers
                                 multiplied by 23)
073ch                   1 dword  Number of instrument headers
0740h                   1 dword  File offset where patch headers start
0744h                   1 dword  Total length in bytes of all patch headers
                                 (always number of patch headers multiplied by
                                 76)
0748h                   1 dword  Number of patch headers
074ch                   4 string Spacer
0750h                   1 dword  File offset where array #1 starts
0754h                   1 dword  Total length in bytes of all "slots" in
                                 array #1 (always number of "slots" in
                                 array #1, multiplied by 2)
0758h                   1 dword  Number of "slots" in array #1
075ch                   1 dword  File offset where array #2 starts
0760h                   1 dword  Total length in bytes of all "slots" in
                                 array #2 (always number of "slots" in
                                 array #2, multiplied by 2)
0764h                   1 dword  Number of "slots" in array #2
0768h                   1 dword  File offset where array #3 starts
076ch                   1 dword  Total length in bytes of all "slots" in
                                 array #3 (always number of "slots" in
                                 array #3, multiplied by 2)
0770h                   1 dword  Number of "slots" in array #3
0774h                   1 dword  File offset where sample headers start
0778h                   1 dword  Total length in bytes of all sample headers
                                 (always number of sample headers multiplied by
                                 16)
077ch                   1 dword  Number of sample headers
0780h                   4 string Spacer
0784h                   1 dword  File offset where sample waveform area begins
0788h                   1 dword  Total length of sample waveform area in bytes

Bank Map

The bank map assigns one MIDI patch map to each of the 128 MIDI banks. The bank map is 256 bytes long.

OFFSET              Count TYPE   Description
0000h                   1 word   MIDI patch map assigned to MIDI bank #0
0002h                   1 word   MIDI patch map assigned to MIDI bank #1
0004h                   1 word   MIDI patch map assigned to MIDI bank #2
0006h                   1 word   MIDI patch map assigned to MIDI bank #3
...
00feh                   1 word   MIDI patch map assigned to MIDI bank #127

Drum Kit Map

OFFSET              Count TYPE   Description
0000h                   1 word   Drum note map assigned to MIDI drum kit #0
0002h                   1 word   Drum note map assigned to MIDI drum kit #1
0004h                   1 word   Drum note map assigned to MIDI drum kit #2
0006h                   1 word   Drum note map assigned to MIDI drum kit #3
...
00feh                   1 word   Drum note map assigned to MIDI drum kit #127

MIDI Patch Maps

The MIDI patch maps assign one instrument to each of the 128 MIDI patches. Each MIDI patch map corresponds to one or more MIDI banks. One MIDI patch map can be used by more than one MIDI bank; in fact, all of the MIDI banks can use the same MIDI patch map if desired (which would allow a smaller filesize and save system RAM). The number of MIDI patch maps is set in the .ECW file header. Each MIDI patch map is 256 bytes long.

OFFSET              Count TYPE   Description
0000h                   1 word   Instrument assigned to MIDI patch #0 when
                                 using a MIDI bank whose entry in the bank map
                                 is equal to 0
0002h                   1 word   Instrument assigned to MIDI patch #1, bank #0
0004h                   1 word   Instrument assigned to MIDI patch #2, bank #0
0006h                   1 word   Instrument assigned to MIDI patch #3, bank #0
...
00feh                   1 word   Instrument assigned to MIDI patch #4, bank #0

If there are multiple MIDI patch maps (according to the file header), then the MIDI patch maps must follow one another immediately with no gaps between:

OFFSET              Count TYPE   Description
0100h                   1 word   Instrument assigned to MIDI patch #0 when
                                 using a MIDI bank whose entry in the bank map
                                 is equal to 1
...
01feh                   1 word   Instrument assigned to MIDI patch #127 when
                                 using a MIDI bank whose entry in the bank map
                                 is equal to 1
0200h                   1 word   Instrument assigned to MIDI patch #0 when
                                 using a MIDI bank whose entry in the bank map
                                 is equal to 2
etc.

Drum Note Maps

The drum note maps assign one instrument to each of the 128 MIDI drum notes. Each drum note map corresponds to one or more MIDI drum kits. One drum note map can be used by more than one drum kit; in fact, all of the drum kits can use the same drum note map if desired (which would allow a smaller filesize and save system RAM). The number of drum note maps is set in the .ECW file header. Each drum note map is 256 bytes long.

OFFSET              Count TYPE   Description
0000h                   1 word   Instrument assigned to MIDI drum note #0 when
                                 using a drum kit whose entry in the drum kit
                                 map is equal to 0
0002h                   1 word   Instrument assigned to MIDI patch #1, drum kit
                                 #0
0004h                   1 word   Instrument assigned to MIDI patch #2, drum kit
                                 #0
0006h                   1 word   Instrument assigned to MIDI patch #3, drum kit
                                 #0
...
00feh                   1 word   Instrument assigned to MIDI patch #4, drum kit
                                 #0

If there are multiple drum kit maps (according to the file header), then the drum kit maps must follow one another immediately with no gaps between:

OFFSET              Count TYPE   Description
0100h                   1 word   Instrument assigned to drum note #0 when
                                 using a drum kit whose entry in the drum kit
                                 map is equal to 1
...
01feh                   1 word   Instrument assigned to drum note #127 when
                                 using a drum kit whose entry in the drum kit
                                 map is equal to 1
0200h                   1 word   Instrument assigned to drum note #0 when
                                 using a drum kit whose entry in the drum kit
                                 map is equal to 2
etc.

Instrument Headers

The instrument headers assign one or more patches (that is, the INTERNAL patches used in the waveset, as opposed to MIDI patches, which are EXTERNAL) to each of the instruments. The instrument headers also affect certain properties of the instruments, such as tuning and pan. The number of instrument headers is set in the .ECW file header. Each instrument header is 23 bytes long.

OFFSET              Count TYPE   Description
0000h                   1 char   Determines the function of the remaining 22
                                 bytes in the current instrument header

When the byte at offset 0000h of an instrument header has a value of 2, the rest of the header is arranged as follows:

OFFSET              Count TYPE   Description
0001h                   1 char   When set to a value of 0, only the first
                                 instrument sub-header (see below) is active.
                                 When set to 1, both sub-headers are used
                                 simultaneously for each note played. When set
                                 to 2, a split point is used to select which
                                 of the sub-headers is used for a given note. A
                                 value of 3 makes only the second sub-header
                                 active. (Other values make neither active.)
0002h                   1 char   The note number above which only the second
                                 instrument sub-header is used; otherwise, only
                                 the first instrument sub-header is used. This
                                 is only the case when the byte at offset 0001h
                                 is set to a value of 2.

FIRST INSTRUMENT SUB-HEADER
0003h                   1 int    Patch assigned to this instrument sub-header
0005h                   1 char   Amplitude and envelope steepness (signed)
0006h                   1 char   Pan (signed; 193 seems to be extreme left and
                                 64 seems to be extreme right)
0007h                   1 char   Coarse tune (signed; measured in semitones)
0008h                   1 char   Fine tune (signed; seems to be measured in
                                 increments of 1/256 of a semitone)
0009h                   1 int    Amount of delay before onset of notes (seems
                                 to be measured in miliseconds)
000bh                   1 char   Unknown. For tremolo strings and most if not
                                 all drum kit percussion, has value of either
                                 1 or 2.
000ch                   1 char   If, in two or more instrument sub-headers,
                                 the byte at offset 000ch has the same value,
                                 only one of the patches played by those
                                 instrument sub-headers can sound
                                 simultaneously. Examples of instruments where
                                 this is desirable include open/closed hi-hats
                                 and open/closed triangles.

SECOND INSTRUMENT SUB-HEADER (same as first)
000dh                   1 int    Patch assigned to this instrument sub-header
000fh                   1 char   Amplitude and envelope steepness (see above)
0010h                   1 char   Pan
0011h                   1 char   Coarse tune
0012h                   1 char   Fine tune
0013h                   1 int    Delay
0015h                   1 char   Unknown. For side stick and acoustic snare,
                                 has value of 1.
0016h                   1 char   Probably same function as byte at offset
                                 0000ch

When the byte at offset 0000h of an instrument header has a value of 255, the rest of the header is arranged as follows:

OFFSET              Count TYPE   Description
0001h                   1 char   Unknown.
0002h                   1 int    The number of another instrument header.
0004h                   1 char   When a MIDI note is played with a note number
                                 less than or equal to the value of this byte,
                                 the instrument header specified by the value
                                 at offset 0002h is used. (One can think of
                                 these bytes as IF-GOTO statements: IF the
                                 note number <= the value at offset 0004h, GOTO
                                 instrument header #X, where X is the value
                                 stored at offset 0002h.)
0005h                   1 int    The number of another instrument header.
0007h                   1 char   When a MIDI note is played with a note number
                                 less than or equal to the value of this byte,
                                 the instrument header specified by the value
                                 at offset 0005h is used.
0008h                   1 int    The number of another instrument header.
000ah                   1 char   When a MIDI note is played with a note number
                                 less than or equal to the value of this byte,
                                 the instrument header specified by the value
                                 at offset 0008h is used.
000bh                   1 int    The number of another instrument header.
000dh                   1 char   When a MIDI note is played with a note number
                                 less than or equal to the value of this byte,
                                 the instrument header specified by the value
                                 at offset 000bh is used.
...
0014h                   1 int    The number of another instrument header.
0016h                   1 char   When a MIDI note is played with a note number
                                 less than or equal to the value of this byte,
                                 the instrument header specified by the value
                                 at offset 0014h is used. (The value here MUST
                                 be 127.)

If there are multiple instrument headers (according to the file header), then the instrument headers must follow one another immediately with no gaps between.

Patch Headers

The patch headers (which refers to the INTERNAL patches used in the waveset, as opposed to MIDI patches, which are EXTERNAL) assign one "slot" in array #1 to each patch. The patch headers also affect certain properties of the patches, such as the pitch and amplitude envelopes. The number of patch headers is set in the .ECW file header. Each patch header is 76 bytes long.

OFFSET              Count TYPE   Description
0000h                   1 char   Magnitude of pitch envelope (signed). Negative
                                 values cause pitch to fall rather than rise.
                                 A value of 0 effectively disables pitch
                                 envelope.
0001h                   1 char   MIDI controller 1 (modulation) sensitivity
0002h                   1 char   Scale. A value of 0 denotes a 12-tones-per-
                                 octave (i.e. chromatic) scale. A value of 1
                                 causes this patch to ignore the MIDI note
                                 number, so that every key on the keyboard is
                                 the same pitch. A value of 2 denotes a 24-
                                 tones-per-octave (i.e. quarter tone) scale.
0003h                   8 string Unknown
000bh                   1 int    "Slot" in array #1 assigned to this patch
000dh                   1 char   Changes tuning slightly
000eh                   2 string Unknown
0010h                   1 char   Shifts the split points of the samples played
                                 by this patch
0011h                  10 string Unknown
001bh                   1 char   Causes pitch to change more rapidly upon
                                 note release when pitch envelope is enabled.
                                 May be the destination of the release phase
                                 of the pitch envelope.
001ch                   1 char   Delay before pitch envelope enters attack
                                 phase
001dh                   1 char   Initial pitch for pitch envelope**
001eh                   1 char   Attack time for pitch envelope
001fh                   1 char   Attack level for pitch envelope
0020h                   1 char   Decay time for pitch envelope
0021h                   1 char   Decay level for pitch envelope
0022h                   1 char   Sustain time for pitch envelope
0023h                   1 char   Sustain level for pitch envelope
0024h                   1 char   Release time for pitch envelope
0025h                   1 char   Influence of MIDI note velocity on magnitude
                                 of pitch envelope
0026h                   1 char   Unknown (may be proportional to attack time
                                 of pitch envelope)
0027h                   1 char   Influence of MIDI note number on pitch
                                 envelope time (0=none; 127=huge)
0028h                   1 char   When set to 0, the pitch envelope enters the
                                 release phase when a MIDI note-off command
                                 is received. When set to 1, pitch envelope
                                 never enters the release phase.
0029h                   2 string Unknown
002bh                   1 char   Delay before wavetable envelope enters attack
                                 phase. Seems to play the final wavetable while
                                 in this pre-attack phase.***
002ch                   1 char   Initial wavetable for wavetable envelope
002dh                   1 char   Attack time for wavetable envelope
002eh                   1 char   Attack level for wavetable envelope
002fh                   1 char   Decay time for wavetable envelope
0030h                   1 char   Decay level for wavetable envelope
0031h                   1 char   Sustain time for wavetable envelope
0032h                   1 char   Sustain level for wavetable envelope
0033h                   1 char   Release time for wavetable envelope
0034h                   1 char   Presumably influence of MIDI note velocity on
                                 magnitude of wavetable envelope (I haven't
                                 tested this)
0035h                   1 string Unknown
0036h                   1 char   Presumably influence of MIDI note number on
                                 wavetable envelope time (I haven't tested
                                 this)
0037h                   1 char   Presumably, when set to 0, the wavetable
                                 envelope enters the release phase when a MIDI
                                 note-off command is received; when set to 1,
                                 wavetable envelope never enters the release
                                 phase (I haven't tested this)
0038h                   1 string Unknown
0039h                   1 char   Possibly the destination of the release phase
                                 of the amplitude envelope.
003ah                   1 string Unknown
003bh                   1 char   Initial amplitude for amplitude envelope**
003ch                   1 char   Attack time for amplitude envelope
003dh                   1 char   Attack level for amplitude envelope
003eh                   1 char   Decay time for amplitude envelope
003fh                   1 char   Decay level for amplitude envelope
0040h                   1 char   Sustain time for amplitude envelope
0041h                   1 char   Sustain level for amplitude envelope
0042h                   1 char   Release time for amplitude envelope
0043h                   1 char   Influence of MIDI note velocity on magnitude
                                 of amplitude envelope.
0044h                   1 char   Unknown. Seems to affect amplitude attack.
0045h                   1 char   Influence of MIDI note number on amplitude
                                 envelope time.
0046h                   1 char   When set to 0, the amplitude envelope enters
                                 the release phase when a MIDI note-off command
                                 is received. When set to 1, amplitude envelope
                                 never enters the release phase.
0047h                   1 string Unknown
0048h                   1 char   Pitch LFO (i.e. vibrato) depth. A value above
                                 0 will add pitch modulation to a patch even
                                 when MIDI controller 1 (modulation) is set to
                                 0.
0049h                   1 char   Pitch LFO (i.e. vibrato) speed.
004ah                   1 char   Delay before pitch LFO (i.e. vibrato) reaches
                                 full depth.
004bh                   1 string Unknown

Array #1 "Slots"

The "slots" in array #1 assign one "slot" in array #3 to each "slot" in array #1. The number of "slots" in array #1 is set in the .ECW file header.

"SLOT" #0:
OFFSET              Count TYPE   Description
0000h                   1 int    "Slot" in array #3 assigned to this
                                 "slot".

If there are multiple "slots" (according to the file header), then the "slots" must follow one another immediately with no gaps between.

"SLOT" #1:
OFFSET              Count TYPE   Description
0002h                   1 int    "Slot" in array #3 assigned to this
                                 "slot".
"SLOT" #2:
OFFSET              Count TYPE   Description
0004h                   1 int    "Slot" in array #3 assigned to this
                                 "slot".
etc.

Array #2 "Slots"

The "slots" in array #2 are linked to the sample set info area. The number of "slots" in array #2 is set in the .ECW file header.

"SLOT" #0:
OFFSET              Count TYPE   Description
0000h                   1 int    Corresponds to value in sample set header.
                                 The values tend to be extremely random, as
                                 if to thwart reverse engineering of the .ecw
                                 file format.
                                 (Also seems to affect snare drums
                                 in the 2 megabyte official waveset.)

If there are multiple "slots" (according to the file header), then the "slots" must follow one another immediately with no gaps between.

"SLOT" #1:
OFFSET              Count TYPE   Description
0002h                   1 int    Corresponds to value in sample set header.
                                 The values tend to be extremely random, as
                                 if to thwart reverse engineering of the .ecw
                                 file format.
                                 (Also seems to affect snare drums
                                 in the 2 megabyte official waveset.)

"SLOT" #2:
OFFSET              Count TYPE   Description
0004h                   1 int    Corresponds to value in sample set header.
                                 The values tend to be extremely random, as
                                 if to thwart reverse engineering of the .ecw
                                 file format.
                                 (Also seems to affect snare drums
                                 in the 2 megabyte official waveset.)
etc.

Array #3 "Slots"

The "slots" in array #3 assign one sample header to each "slot" in array #3. The number of "slots" in array #3 is set in the .ECW file header.

"SLOT" #0:
OFFSET              Count TYPE   Description
0000h                   1 int    Sample header assigned to this "slot".

If there are multiple "slots" (according to the file header), then the
"slots" must follow one another immediately with no gaps between.

"SLOT" #1:
OFFSET              Count TYPE   Description
0002h                   1 int    Sample header assigned to this "slot".
"SLOT" #2:
OFFSET              Count TYPE   Description
0004h                   1 int    Sample header assigned to this "slot".
etc.

Sample Headers

The sample headers indicate where the individual samples are to be found in the sample waveform area. They also specify how those samples are looped (if at all), and any split points between one sample and another. The number of sample headers is set in the .ECW file header. Each sample header is 16 bytes long.

OFFSET              Count TYPE   Description
0000h                   1 char   If a MIDI note is received with a MIDI note
                                 number above this value, the next sample
                                 header is used instead. If the MIDI note
                                 number is still greater than the byte value at
                                 offset 0000h of the next sample header, the
                                 sample header after the next sample header is
                                 used and so on until the MIDI note number is
                                 less than or equal to the byte value at offset
                                 0000h.
0001h                   1 char   Determines whether the sample is looped,
                                 whether to apply tuning adjustments from patch
                                 and instrument headers when the sample is used
                                 as part of a drum kit, and whether to shift
                                 loop points further into the sample waveform
                                 area. When set to 0, no tuning adjustments are
                                 made when the sample is used in a drum kit. A
                                 value of 0 or 1 also disables looping. Values
                                 of 2 or higher enable looping using the loop
                                 points specified in the sample header (see
                                 below). Values of 129 or higher shift the loop
                                 points forward by an amount proportional to the
                                 value minus 128 (i.e. 129 will shift the loop
                                 points slightly, while 255 will shift them
                                 quite far into the sample waveform area). Be
                                 careful when experimenting with values over 129
                                 as it is very possible to play past the end of
                                 the sample waveform area, which may cause
                                 Windows to crash.
0002h                   1 char   Fine tune (signed; seems to be in increments
                                 of 1/256 of a semitone)
0003h                   1 char   Coarse tune (signed; measured in semitones)
0004h                   1 dword  Offset in sample waveform area where this
                                 sample begins, multiplied by 8. Sample
                                 waveform data can be shared by multiple sample
                                 headers.
0008h                   1 dword  Offset in sample waveform area of this
                                 sample's loop point, multiplied by 8.
000bh                   1 dword  Offset in sample waveform area of this
                                 sample's end loop point, multiplied by 8 
                                 (fractional loop lengths permitted). This is
                                 also where the sample ends when looping is
                                 disabled. If a sample plays beyond the end of
                                 the file, the operating system may lock up.

If there are multiple sample headers, then the sample headers must follow one another immediately with no gaps between.

Sample Waveform Area/Sample Set Info Area

The sample waveform area stores the actual sample waveform data used by the sound card's MIDI synthesizer. The sample waveform data is stored using 16-bit, mono, signed samples, with LSB first (Intel byte order). Theoretically, the sample waveform area can be up to 512 megabytes in size (sample start/loop/end loop points in the sample headers are specified using dwords, which have a maximum value of 2^32 or 4294967296. Diving this value by 8 - the sample start/ loop/end loop points are measured in 1/8 bytes - we get 536870912 bytes, or 512 megabytes. The practical limit, however, is about 16 megabytes--the configurator refuses to load wavesets larger than that. (Perhaps the sound card driver or ENSCFG32.EXE could be hacked to increase the effective file size limit?) The size of the sample waveform area is set in the .ECW file header.

In the wavesets provided by Ensoniq/Creative, the beginning of the sample waveform area is not used to store samples. Rather, it contains the names of each sample set in the remainder of the sample waveform area and other data pertaining to these sample sets (here, "sample sets" means a single sample or multiple samples if the split point for a sample--i.e. the byte in offset 0 of a sample header--is less than 127, in which case the sample set would "continue" to the following sample until a value of 127 was reached.) The AudioPCI's softsynth does not seem to need this section for playback, as changing the values in this section has little if any effect. I speculate that this area of the .ecw file was used by the proprietary software that Ensoniq/Creative used for designing the official wavesets, for displaying names for each sample set and such. I also speculate that the entire sample waveform area was at one point an Ensoniq file type itself, as the structure of the sample waveform area (as it exists in the wavesets provided by Ensoniq/Creative) resembles an independent file.

The beginning of the sample waveform area in the official .ecw files, which I will call the "Sample Set Info Area", has the following layout:

OFFSET              Count TYPE   Description
0000h                   4 string Unknown (value of 16 in all wavesets provided
                                 by Ensoniq/Creative)
0004h                   1 dword  Size of sample waveform area in bytes
0008h                   4 string Unknown (always "RDNS")
000ch                   1 char   Unknown (always 14--length of sample set
                                         names?)
000dh                   1 char   Always 22--probably length in bytes of each
                                 sample set header
000eh                   1 int    Always 16--probably length in bytes of each
                                 sample header in duplicate copy of Sample
                                 Headers
0010h                   1 int    Always 40--probably offset where first sample
                                 set header begins
0012h                   1 int    Offset in sample waveform area where sample set
                                 headers begin
0014h                   1 int    Size of duplicate copy of Sample Headers in
                                 bytes
0016h                   1 int    Number of sample sets
0018h                   1 int    Number of sample headers
001ah                  14 string Unknown; "ENSONIQ ROM[null][null][null]" in 
                                 DOSTEST.ECW;
                                 "[null]NSONIQ ROM[null][null][null]" in
                                 all other wavesets provided by Ensoniq/Creative

"SAMPLE SET HEADER" #1:
0028h                   1 dword  Offset in the Sample Waveform Area where sample
                                 header for the first sample in this sample set
                                 is stored
002ch                   1 int    Corresponds to a "slot" number in array #1
002eh                   1 int    Corresponds to a value in array #2
0030h                  14 string Name of this sample set. Null-terminated
                                 string.

If there are multiple sample set headers (according to the value at offset 0x16 of the sample waveform area), then the sample set headers must follow one another immediately with no gaps between.

"SAMPLE SET HEADER" #2:
003eh                   1 dword  Offset in the Sample Waveform Area where sample
                                 header for the first sample in this sample set
                                 is stored
0042h                   1 int    Corresponds to a "slot" number in array #1
0044h                   1 int    Corresponds to a value in array #2
0046h                  14 string Name of this sample set. Null-terminated
                                 string.

"SAMPLE SET HEADER" #3:
0054h                   1 dword  Offset in the Sample Waveform Area where sample
                                 header for the first sample in this sample set
                                 is stored
0058h                   1 int    Corresponds to a "slot" number in array #1
005ah                   1 int    Corresponds to a value in array #2
005ch                  14 string Name of this sample set. Null-terminated
                                 string.
etc.

A duplicate copy of the Sample Headers follows the "Sample Set Headers". The actual sample waveform data seems to begin immediately afterward.

Footnotes

*A "spacer" is a series of 4 bytes of unknown purpose. The contents of a spacer are usually 01h, 00h, 01h, 00h; however, changing the contents does not seem to have any effect whatsoever. Only the size and placement of spacers matters; their contents do not.

**Most if not all of the values dealing with the envelopes are unsigned and confined to values between 0 and 127. Using values between 128 and 255 typically generates unpredictable results.

***The "wavetable envelope" transitions from one sample in a sample set to another. This is useful in creating evolving timbres without using long samples. This only seems to work with the "ELEC PIANO 2" (simulates decay of the upper partials) and "SAWTOOTH" (simulates a sweeping resonant filter) sample sets, however; I'm not sure why it doesn't do the same with any sample set.

Commentary

Comparison with .SF2 and other technologies

.ECW format advantages over SoundFonts (.SF2)

These features cannot be preserved when converting from .ECW to .SF2:

.ECW format disadvantages

AudioPCI/PCI64 MIDI synthesizer limitations

Up