WSS File Format

From Bohemia Interactive Community
Revision as of 07:13, 28 January 2010 by Mikero (talk | contribs) (→‎Decompression: C++ code)
Jump to navigation Jump to search

Introduction

WSS files are used since OFP times to store sound data and its file format is pretty much like the RIFF WAVE file format used for .wav files.

File Format

Offset Datatype Content Description
0 char[4] "WSS0" file signature
4 ulong <compression> if <compression> == 8 the PCM data is compressed, otherwise <compression> == 0
8 ushort <format tag> defines in which format the data is saved. Always 0x0001 in WSS files
10 ushort <channels> number of channels: 1=mono, 2=stereo
12 ulong <sample rate> sample rate in Hz (e.g. 44100Hz)
16 ulong <bytes/second> <sample rate> * <block align>
20 ushort <block align> <channels> * (<bits/sample> / 8)
22 ushort <bits/sample> usually 0x0010 in WSS files
24 ushort <unknown> unknown value
26 byte[fileSize-26] <soundData> here the PCM data of the sound is stored

Decompression

Compression consists of a single encoded bytes versus uncompressed shorts. Each byte is, effectively, extrapolated to a short, thus making the compressed BYTE array, and the resulting decompressed SHORT array the same number of elements(length). The length is the remaining file length (in bytes) after the header.

C++ code

Function returns a short array, same size as it's compressed byte equivalent

#define LOG10	2.3025850929940456840	//ln(10)
#define LOG2	1.4426950408889634070	//log2(e)
#define MAGIC_NUMBER	((LOG10*LOG2)/28.12574042515172)

short* DeCompress(const char *CompressedData,int len)
{
short *snap,*OutputData;

	if (!(snap=OutputData=new short[len]))  return 0;
	short LastVal=0;
	for (;len--;CompressedData++)
	{
		if (*CompressedData)
		{
			double asFloat = abs(*CompressedData) *MAGIC_NUMBER;
			double rnd = Round(asFloat);
			asFloat = pow(2.0, asFloat - rnd) * pow(2, rnd);// mantissa -
			if (*CompressedData < 0) asFloat *= -1;
			int asInt = Round(asFloat)+LastVal;
			if (asInt > SHRT_MAX ) asInt = SHRT_MAX ;
			if (asInt < SHRT_MIN) asInt = SHRT_MIN;
			LastVal=(short)asInt;
		 }
		*OutputData++ = LastVal;
	}
	return snap;
}

C# code

If the <soundData> is compressed the following (C#) code can be used for decompression:

PCMData = new Int16[soundData.Length];
for (int j = 0; j < PCMData.Length; j++)
{
  SByte srcSample = (SByte)soundData[j];
  if (srcSample != 0)
  {
    double asFloat = Math.Abs(srcSample) / 28.12574042515172;
    asFloat *= 2.3025850929940456840; //ln(10)
    asFloat *= 1.4426950408889634070; //log2(e)
    double rnd = Math.Round(asFloat);
    double mantisse = Math.Pow(2.0, asFloat - rnd);
    asFloat = mantisse * Math.Pow(2, rnd);
    if (srcSample < 0) asFloat *= -1;
    Int32 asInt = (int)Math.Round(asFloat);
    asInt = (j == 0) ? asInt : (asInt + PCMData[j - 1]);
    if (asInt > short.MaxValue) asInt = short.MaxValue;
    if (asInt < short.MinValue) asInt = short.MinValue;
    PCMData[j] = (Int16)asInt;
  }
  else PCMData[j] = (j == 0) ? (Int16)0 : PCMData[j - 1];
}