U8 Audio File Format

The .U8 audio file is a simple and efficient format for storing 8-bit digital audio effects (1 byte per sample). Two DOS games from the 1990s that use this are Mortal Kombat II and Lemmings 3D. All files have a 32-byte header, most of which is zeros. In all the files I examined, only the following byte offsets have meaningful values:

  • 0 – always has the value 0x20 = 32. Possibly refers to the header length.
  • 4-5 – unsigned 16-bit little-endian value indicating the Last valid data offset. There is some discrepancy in this field. In U8 files from 1994 (most FX files from MK2) this excludes the header length, and so the value is actually (file size – 32 – 1). In files from 1995 (3 FX files from MK2 and all files from L3D) this value includes the header and is equal to (file size – 1).
  • 16-17 – Sampling rate in Hz, typically 11025 (0x2B11) or 22050 (0x5622). A few files in L3D have 11000 (0x2AF8) – this may be an error.
  • 18-19 – always contains the constant 0x0106. Possibly format identifier / version.

Starting from byte offset 32 and until end-of-file the data is a stream of 8-bit signed raw audio data samples.

Years ago, for reasons I now cannot remember, I wanted to check all the audio effects of MK2. Having some experience in MATLAB, it seemed it would be easiest to achieve using its built-in sound-playing engine (sound.m and soundsc.m). I wrote a small script to load a bunch of .U8 files into a MATLAB struct array and a small function to play any given sound, by name or by array index. The code is offered below for reference.

% LOADSNDS.M - Load all .U8 sound files in current directory
d = dir ('*.u8');
x = cell(size(d));
n = cell(size(d));
f = cell(size(d));
for i = 1:length(d)
    n{i} = d(i).name;
    fid = fopen(n{i});
    fread(fid,16,'int8');       	% bytes 00-15 - discard
    f{i} = fread(fid,1,'uint16');   % sampling rate
    fread(fid,14,'int8');           % bytes 18-31 - discard
    x{i} = fread(fid,inf,'int8');   % read data till EOF
    fclose(fid);
end
sounds = struct('name',n,'wave',x,'freq',f); % store fields in struct array
% PLAYSND.M - Play 8-bit waveform from a struct array of waveforms
function playsnd(sounds,snd)
xx = [];
ff = [];
if (ischar(snd))    % play sound by name
    for i = 1:length(sounds)
        if (strncmpi(snd,sounds(i).name,length(snd)))
            xx = sounds(i).wave;
            ff = sounds(i).freq;
            break;
        end
    end
    if (isempty(xx))
        error ('Invalid filename');
    end
else                % play sound by index
    if (snd>length(sounds))
        error('Invalid index');
    end
    xx = sounds(snd).wave;
    ff = sounds(snd).freq;
end
soundsc(xx,ff);

MATLAB is not free, but something just as simple can be implemented in Python or any other environment that has an audio engine capable of playing raw data. With an appropriate codec library, you could also save the data as .WAV or any other audio format.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s