WSS File Format: Difference between revisions
Jump to navigation
Jump to search
m (added to file formats) |
m (→Decompression: C++ code) |
||
Line 63: | Line 63: | ||
==Decompression== | ==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 | |||
<pre> | |||
#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; | |||
} | |||
</pre> | |||
===C# code=== | |||
If the <soundData> is compressed the following (C#) code can be used for decompression: | If the <soundData> is compressed the following (C#) code can be used for decompression: | ||
Revision as of 07:13, 28 January 2010
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]; }