I have files, which I recorded back in 90s with ESS ES688 AudioDrive card, 4-bit voice optimized codec. Nowadays I do not possess the card any more and proprietary codec is no longer supported or I can't find any hints how to decode it. Here ffmpeg output:

[wav @ 0x55cc15d2c900] Estimating duration from bitrate, this may be inaccurate
[wav @ 0x55cc15d2c900] Could not find codec parameters for stream 0 
(Audio: none ([136][230][0][0] / 0xE688), 8000 Hz, 1 channels, 33 kb/s): unknown codec
Consider increasing the value for the 'analyzeduration' and 'probesize' options
Guessed Channel Layout for Input Stream #0.0 : mono
Input #0, wav, from 'MY.WAV':
  Duration: 00:04:48.64, bitrate: 33 kb/s
    Stream #0:0: Audio: none ([136][230][0][0] / 0xE688), 8000 Hz, mono, 33 kb/s

Is there any way to do it without actual physical card and compatible PC hardware? Can sound card emulator solve this?

I have not found any hints of how 4-bit per sample ended in the WAV file, but eg this ES688 AudioDrive chip's datasheet mentions programmable sample rate from 4000 to 44100 Hz so my assumption is: When I requested low bit-rate I ended up with having a non-standard WAV-file with two samples per byte...

  • Can you recall what operating system you were running at the time: DOS, Windows 3.x, 95, etc?
    – Kaz
    Apr 19 '20 at 16:12
  • I've had a look online at ES688 drivers for DOS and OS/2, and they don't include any software for recording audio - it's likely this would have been done by a separate utility program. I think the most likely routes to success would be finding a copy of this software, or reverse-engineering the encoding from example sound files. For the latter option, do you have any short clips you can upload for any enterprising individuals to have a look at?
    – Kaz
    Apr 19 '20 at 16:32
  • It was most likely MSDOS and I believe sound card encoded this in hardware. As for file samples, the problem is I do not want those to be public in entirety, but I do not know which samples are ok (naturally, because I do not remember what was in that speech. I was asked by the speaker not to publish them, at least some parts of them).
    – Roman Susi
    Apr 19 '20 at 16:49
  • Could be nice to recognize whether it's ADPCM or something simpler.
    – Roman Susi
    Apr 19 '20 at 16:55
  • The first few kilobytes of a sound file may be enough for an initial analysis, and would keep privacy issues to a minimum.
    – Kaz
    Apr 19 '20 at 16:55

With hints taken from this answer, your 4-bit ESPCM format is not that difficult to be decoded correctly. Your python decoder does a lot of things right. Out of 20 nibbles, only 19 nibbles contain sound data, the 20th nibble is a control nibble. The 19 data nibbles are, in fact, a linear 4-bit PCM encoding of the sound data, just like your python script handles them. The control nibble contains a scale factor for the following 19 data nibbles.

The scale factor has to be interpreted like this. If we (for a moment) exclude the 4-bit value 0 (representing -8), so you get to a scale -7 to +7, this range represents on a scale between -127 to +127:

factor      range
  0        -7   ..   7
  1        -9   ..   9
  2       -11   ..  11
  3       -12.5 ..  12.5
  4       -14   ..  14
  5       -18   ..  18
  6       -23   ..  23
  7       -28   ..  28
  8       -33.3 ..  33.3
  9       -40.5 ..  40.5
 10       -49   ..  49
 11       -60   ..  60
 12       -70   ..  70
 13       -84   ..  84
 14      -105   .. 105
 15      -126   .. 126

You obtain the output value to use for the input 0 (aka -8) value by linear extrapolation, i.e. you can just put -8 as input into the linear relationship for -7 to +7 taken from the table above. Don't forget to clamp it it -128 in the case of scale factor number 15.

There also is a simple 1-bit format, which just consists of the sign bits of the 4-bit format, encoded as a 4-bit level, 1 padding bit and 19 data bits per frame.

The 2 bit/sample and 3 bit/sample formats are more complicated, because they use a proper ADPCM encoding of the 4-bit format described above. Interestingly, there are 8 ADPCM tables for the 2 bit/sample format and 4 ADPCM tables for the 4 bit/sample format. Those tables can be chosen on a packet-by-packet basis (where packet means a group of 19 samples).


I also created a lot of files using ESPCM compression in the 1990s. The ones I have were saved with an extension of AUD, but internally they are .wav files. ESPCM compression takes each sample and reduces it to 2 bits, 3 bits, or 4 bits, but I do not know the algorithm it uses. Sample rate can be anything. One channel only. They were created using software that came with an ESS AudioDrive sound card, but the software does not require the hardware to function.

Look for the file AUDIOREC.EXE "ESS Technology,Inc. Audio Recorder". The version I have is Version 1.81, file size is 114688 bytes. It is a 16-bit Windows 3.1 program, but functions fine in Windows XP in VirtualBox. It will let you open the original files, then resave them as standard uncompressed .wave files. It supports all 3 levels of ESPCM compression.

No, I will not supply a copy of the program.

  • Great find! So there actually is a software encoder/decoder for that format. I was afraid that the only consumer available implementation might be inside the ESS AudioDrive chips. Jul 12 '20 at 11:35

While preparing a sample, I did the following:

  1. Silenced error in Python wave module (sampwidth is arbitrary - should be 0.5, but it's hardly supported):

    if wFormatTag == WAVE_FORMAT_PCM:
            sampwidth = struct.unpack_from('<H', chunk.read(2))[0]
        except struct.error:
            raise EOFError from None
        self._sampwidth = (sampwidth + 7) // 8
        if not self._sampwidth:
            raise Error('bad sample width')
        self._sampwidth = 1  # this should be 0.5...
        #raise Error('unknown format: %r' % (wFormatTag,))
  2. Wrote wav-file samples into raw file, using lower and upper parts of each byte (number of frames obtained from method of obj):

    import wave
    obj = wave.open('/tmp/MY.WAV','rb')
    fh = open("audio.raw", 'bw')
    for i in obj.readframes(obj.getnframes() * 2):
        _noneed = fh.write(bytes([i & 0x0F, (i & 0xF0) >> 4]))
  3. Opened raw data in audacity using 4000 Hz unsigned PCM, 16 bit

Speech became intelligible. Probably, the original record was not of great quality anyway. Probably, that e688 just packed two half-bytes into one.

Note: The conversion script is approximate. Fractional framesize is not supported by Python wave module, so nframes calculation is not correct. Treat it as quick proof of concept.

This is how one small part of the WAV looked when loaded in audacity after I normalized it:

enter image description here

Update: I could not repeat my yesterday success with 8bit and noticed if I use Signed 16-bit PCM (which is default in my audacity - probably I made a mistake yesterday and forgot to select 8-bit), 4000 Hz the sound is good! I can't really explain that.

This is the settings I used:

enter image description here

  • 3
    Could it have been aLaw or uLaw encoded? Then each four bits would be an independent sample, but not on a linear scale.
    – Tommy
    Apr 19 '20 at 21:06
  • How can I know which of those? I am not even sure how u/aLaw applies to 4-bit samples.
    – Roman Susi
    Apr 20 '20 at 18:24
  • If you open the file you converted as 16 bits/sample, you are effectively throwing away every other sample (by putting it into the low bits). It should sound quite similar to opening the original file as unsigned 8 bits/sample. Apr 20 '20 at 19:23
  • True. But When I import as 8bit I am getting some bytes as 0 and it introduces very annoying noise. So I guess I need to see what are those nibbles and how to get rid of them. Every 20th is zero.
    – Roman Susi
    Apr 20 '20 at 19:33
  • @RomanSusi admittedly I've been extremely lazy with my terminology there. One scheme I'm aware in four bits uses a base-2-log approach such that a value of n represents an output level of n/(n+1), with output volume having been normalised in advance. So the available resolution is focussed on the top part of the available levels.
    – Tommy
    Apr 20 '20 at 23:40

Long shot: ESPCM WAV shares the same TwoCC as the Duck DK4 IMA ADPCM algorithm. So if you have access to ffmpeg, try:

ffmpeg -c:a adpcm_ima_dk4 -i infile.wav …

(I'm unsure how to coerce ffmpeg into producing a generic WAV file, and there may be sample rate/width commands in there, so this is only half an answer)

  • 1
    Tried conversion to mp3. Getting: [adpcm_ima_dk4 @ 0x55fffe372f40] ERROR: step_index[0] = -26233 Error while decoding stream #0:0: Invalid data found when processing input .... a lot. So the format is definitely not ESPCM. (but maybe some other people who come here will benefit from this answer)
    – Roman Susi
    Apr 19 '20 at 19:53
  • 1
    I am quite confident the format is ESPCM. While ESPCM and DK4 share the same TwoCC, it need not be the same format. The collision is likely accidental. Too bad the only thing you find in the internet about ESPCM is that it is supported by the AudioDrive family chips, and that it is patented. I failed to find any publicly available patent document. If there is any, it does not use the name ESPCM, and is probably not assigned to "ESS technology". Apr 21 '20 at 5:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.