WSS File Format: Difference between revisions
m (→Decompression: C++ code) |
(improved description) |
||
Line 1: | Line 1: | ||
==Introduction== | ==Introduction== | ||
WSS files are used since OFP times to store sound data and its file format is pretty much like the [http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html RIFF WAVE file format] used for .wav files. | WSS files are used since OFP times to store sound data and its file format is pretty much like the [http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html RIFF WAVE file format] used for .wav files. | ||
For the purposes of description here, 'Sound' in both wav or wss is recorded as PCM data in 16 bit 'samples'. The quality of that sound is determined by the frequency of those 'samples' per second, referred to as the SampleRate. | |||
Given this: a few important paramaters are define here: | |||
*BitsPerSample: 16 | |||
*BytesPerSample: 2 (Inferred BitsPerSample/8) | |||
==File Format== | ==File Format== | ||
Line 17: | Line 25: | ||
|4 | |4 | ||
|ulong | |ulong | ||
| | |CompressionType | ||
| | |0 == none. 8== compressed PCM data | ||
|- | |- | ||
|8 | |8 | ||
|ushort | |ushort | ||
| | |format | ||
| | |Always 1 (WAVE_FORMAT_PCM) | ||
|- | |- | ||
|10 | |10 | ||
|ushort | |ushort | ||
| | |nChannels | ||
| | |1=mono, 2=stereo | ||
|- | |- | ||
|12 | |12 | ||
|ulong | |ulong | ||
| | |SampleRate | ||
| | |e.g. 44100Hz | ||
|- | |- | ||
|16 | |16 | ||
|ulong | |ulong | ||
| | |BytesPerSecond | ||
| | |SampleRate * BlockAlign | ||
|- | |- | ||
|20 | |20 | ||
|ushort | |ushort | ||
| | |BlockAlign | ||
| | |nChannels * BytesPerSample | ||
|- | |- | ||
|22 | |22 | ||
|ushort | |ushort | ||
| | |BitsPerSecond | ||
|usually | |usually 16 | ||
|- | |- | ||
|24 | |24 | ||
Line 65: | Line 73: | ||
Compression consists of | Compression consists of single encoded byte 'samples' versus uncompressed short 'samples'. | ||
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. | 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. | ||
Revision as of 06:02, 29 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.
For the purposes of description here, 'Sound' in both wav or wss is recorded as PCM data in 16 bit 'samples'. The quality of that sound is determined by the frequency of those 'samples' per second, referred to as the SampleRate.
Given this: a few important paramaters are define here:
- BitsPerSample: 16
- BytesPerSample: 2 (Inferred BitsPerSample/8)
File Format
Offset | Datatype | Content | Description |
---|---|---|---|
0 | char[4] | "WSS0" | file signature |
4 | ulong | CompressionType | 0 == none. 8== compressed PCM data |
8 | ushort | format | Always 1 (WAVE_FORMAT_PCM) |
10 | ushort | nChannels | 1=mono, 2=stereo |
12 | ulong | SampleRate | e.g. 44100Hz |
16 | ulong | BytesPerSecond | SampleRate * BlockAlign |
20 | ushort | BlockAlign | nChannels * BytesPerSample |
22 | ushort | BitsPerSecond | usually 16 |
24 | ushort | <unknown> | unknown value |
26 | byte[fileSize-26] | <soundData> | here the PCM data of the sound is stored |
Decompression
Compression consists of single encoded byte 'samples' versus uncompressed short 'samples'. 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]; }