scummvm/audio/decoders/wma.cpp
Bastien Bouclet 148655f5c2 COMMON: Use a prefix table to speed up the Huffman decoder
Symbols for codes shorter than the prefix table index width are stored
in the table. All the entries in the table with an index starting with
the code are set to the symbol value. That way, when decoding it is
possible to get the number of bits corresponding to the table width from
the bitstream and directly find the symbol value. Longer code still need
to be searched for in the codes list.
2019-04-14 20:24:26 +02:00

1512 lines
36 KiB
C++

/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
// Based on xoreos' WMA code which is in turn
// Largely based on the WMA implementation found in FFmpeg.
#include "common/util.h"
#include "common/math.h"
#include "common/sinewindows.h"
#include "common/error.h"
#include "common/memstream.h"
#include "common/mdct.h"
#include "common/huffman.h"
#include "audio/audiostream.h"
#include "audio/decoders/util.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/wma.h"
#include "audio/decoders/wmadata.h"
namespace Audio {
static inline void butterflyFloats(float *v1, float *v2, int len) {
while (len-- > 0) {
float t = *v1 - *v2;
*v1++ += *v2;
*v2++ = t;
}
}
static inline void vectorFMulAdd(float *dst, const float *src0,
const float *src1, const float *src2, int len) {
while (len-- > 0)
*dst++ = *src0++ * *src1++ + *src2++;
}
static inline void vectorFMulReverse(float *dst, const float *src0,
const float *src1, int len) {
src1 += len - 1;
while (len-- > 0)
*dst++ = *src0++ * *src1--;
}
WMACodec::WMACodec(int version, uint32 sampleRate, uint8 channels,
uint32 bitRate, uint32 blockAlign, Common::SeekableReadStream *extraData) :
_version(version), _sampleRate(sampleRate), _channels(channels),
_bitRate(bitRate), _blockAlign(blockAlign), _audioFlags(0),
_resetBlockLengths(true), _curFrame(0), _frameLen(0), _frameLenBits(0),
_blockSizeCount(0), _framePos(0), _curBlock(0), _blockLen(0), _blockLenBits(0),
_nextBlockLenBits(0), _prevBlockLenBits(0), _byteOffsetBits(0),
_hgainHuffman(0), _expHuffman(0), _lastSuperframeLen(0), _lastBitoffset(0) {
for (int i = 0; i < 2; i++) {
_coefHuffman[i] = 0;
_coefHuffmanRunTable [i] = 0;
_coefHuffmanLevelTable[i] = 0;
_coefHuffmanIntTable [i] = 0;
}
if ((_version != 1) && (_version != 2))
error("WMACodec::init(): Unsupported WMA version %d", _version);
if ((_sampleRate == 0) || (_sampleRate > 50000))
error("WMACodec::init(): Invalid sample rate %d", _sampleRate);
if ((_channels == 0) || (_channels > kChannelsMax))
error("WMACodec::init(): Unsupported number of channels %d",
_channels);
_audioFlags = FLAG_16BITS;
#ifdef SCUMM_LITTLE_ENDIAN
_audioFlags |= FLAG_LITTLE_ENDIAN;
#endif
if (_channels == 2) {
_audioFlags |= FLAG_STEREO;
}
init(extraData);
}
WMACodec::~WMACodec() {
delete _expHuffman;
delete _hgainHuffman;
for (int i = 0; i < 2; i++) {
delete[] _coefHuffmanRunTable [i];
delete[] _coefHuffmanLevelTable[i];
delete[] _coefHuffmanIntTable [i];
delete _coefHuffman[i];
}
for (Common::Array<Common::MDCT *>::iterator m = _mdct.begin(); m != _mdct.end(); ++m)
delete *m;
}
void WMACodec::init(Common::SeekableReadStream *extraData) {
// Flags
uint16 flags = getFlags(extraData);
evalFlags(flags, extraData);
// Frame length
_frameLenBits = getFrameBitLength();
_frameLen = 1 << _frameLenBits;
// Number of MDCT block sizes
_blockSizeCount = getBlockSizeCount(flags);
float bps = ((float) _bitRate) / ((float) (_channels * _sampleRate));
_byteOffsetBits = Common::intLog2((int) (bps * _frameLen / 8.0 + 0.05)) + 2;
// Compute high frequency value and choose if noise coding should be activated
float highFreq;
_useNoiseCoding = useNoiseCoding(highFreq, bps);
// Compute the scale factor band sizes for each MDCT block size
evalMDCTScales(highFreq);
// Init the noise generator
initNoise();
// Init the coefficient huffman codes
initCoefHuffman(bps);
// Init MDCTs
initMDCT();
// Init exponent codes
initExponents();
// Clear the sample output buffers
memset(_output , 0, sizeof(_output));
memset(_frameOut, 0, sizeof(_frameOut));
}
uint16 WMACodec::getFlags(Common::SeekableReadStream *extraData) {
if ((_version == 1) && extraData && (extraData->size() >= 4)) {
extraData->seek(2);
return extraData->readUint16LE();
}
if ((_version == 2) && extraData && (extraData->size() >= 6)) {
extraData->seek(4);
return extraData->readUint16LE();
}
return 0;
}
void WMACodec::evalFlags(uint16 flags, Common::SeekableReadStream *extraData) {
_useExpHuffman = (flags & 0x0001) != 0;
_useBitReservoir = (flags & 0x0002) != 0;
_useVariableBlockLen = (flags & 0x0004) != 0;
if ((_version == 2) && extraData && (extraData->size() >= 8)) {
extraData->seek(4);
if ((extraData->readUint16LE() == 0x000D) && _useVariableBlockLen) {
// Apparently, this fixes ffmpeg "issue1503"
_useVariableBlockLen = false;
}
}
}
int WMACodec::getFrameBitLength() {
if (_sampleRate <= 16000)
return 9;
if ((_sampleRate <= 22050) || (_sampleRate <= 32000 && _version == 1))
return 10;
if (_sampleRate <= 48000)
return 11;
if (_sampleRate <= 96000)
return 12;
return 13;
}
int WMACodec::getBlockSizeCount(uint16 flags) {
if (!_useVariableBlockLen)
return 1;
int count = ((flags >> 3) & 3) + 1;
if ((_bitRate / _channels) >= 32000)
count += 2;
const int maxCount = _frameLenBits - kBlockBitsMin;
return MIN(count, maxCount) + 1;
}
uint32 WMACodec::getNormalizedSampleRate() {
// Sample rates are only normalized in WMAv2
if (_version != 2)
return _sampleRate;
if (_sampleRate>= 44100)
return 44100;
if (_sampleRate >= 22050)
return 22050;
if (_sampleRate >= 16000)
return 16000;
if (_sampleRate >= 11025)
return 11025;
if (_sampleRate >= 8000)
return 8000;
return _sampleRate;
}
bool WMACodec::useNoiseCoding(float &highFreq, float &bps) {
highFreq = _sampleRate * 0.5;
uint32 rateNormalized = getNormalizedSampleRate();
float bpsOrig = bps;
if (_channels == 2)
bps = bpsOrig * 1.6;
if (rateNormalized == 44100) {
if (bps >= 0.61)
return false;
highFreq = highFreq * 0.4;
return true;
}
if (rateNormalized == 22050) {
if (bps >= 1.16)
return false;
if (bps >= 0.72)
highFreq = highFreq * 0.7;
else
highFreq = highFreq * 0.6;
return true;
}
if (rateNormalized == 16000) {
if (bpsOrig > 0.5)
highFreq = highFreq * 0.5;
else
highFreq = highFreq * 0.3;
return true;
}
if (rateNormalized == 11025) {
highFreq = highFreq * 0.7;
return true;
}
if (rateNormalized == 8000) {
if (bpsOrig > 0.75)
return false;
if (bpsOrig <= 0.625)
highFreq = highFreq * 0.5;
else
highFreq = highFreq * 0.65;
return true;
}
if (bpsOrig >= 0.8)
highFreq = highFreq * 0.75;
else if (bpsOrig >= 0.6)
highFreq = highFreq * 0.6;
else
highFreq = highFreq * 0.5;
return true;
}
void WMACodec::evalMDCTScales(float highFreq) {
if (_version == 1)
_coefsStart = 3;
else
_coefsStart = 0;
for (int k = 0; k < _blockSizeCount; k++) {
int blockLen = _frameLen >> k;
if (_version == 1) {
int i, lpos = 0;
for (i = 0; i < 25; i++) {
int a = wmaCriticalFreqs[i];
int b = _sampleRate;
int pos = ((blockLen * 2 * a) + (b >> 1)) / b;
if (pos > blockLen)
pos = blockLen;
_exponentBands[0][i] = pos - lpos;
if (pos >= blockLen) {
i++;
break;
}
lpos = pos;
}
_exponentSizes[0] = i;
} else {
// Hardcoded tables
const uint8 *table = 0;
int t = _frameLenBits - kBlockBitsMin - k;
if (t < 3) {
if (_sampleRate >= 44100)
table = exponentBand44100[t];
else if (_sampleRate >= 32000)
table = exponentBand32000[t];
else if (_sampleRate >= 22050)
table = exponentBand22050[t];
}
if (table) {
int n = *table++;
for (int i = 0; i < n; i++)
_exponentBands[k][i] = table[i];
_exponentSizes[k] = n;
} else {
int j = 0, lpos = 0;
for (int i = 0; i < 25; i++) {
int a = wmaCriticalFreqs[i];
int b = _sampleRate;
int pos = ((blockLen * 2 * a) + (b << 1)) / (4 * b);
pos <<= 2;
if (pos > blockLen)
pos = blockLen;
if (pos > lpos)
_exponentBands[k][j++] = pos - lpos;
if (pos >= blockLen)
break;
lpos = pos;
}
_exponentSizes[k] = j;
}
}
// Max number of coefs
_coefsEnd[k] = (_frameLen - ((_frameLen * 9) / 100)) >> k;
// High freq computation
_highBandStart[k] = (int)((blockLen * 2 * highFreq) / _sampleRate + 0.5);
int n = _exponentSizes[k];
int j = 0;
int pos = 0;
for (int i = 0; i < n; i++) {
int start, end;
start = pos;
pos += _exponentBands[k][i];
end = pos;
if (start < _highBandStart[k])
start = _highBandStart[k];
if (end > _coefsEnd[k])
end = _coefsEnd[k];
if (end > start)
_exponentHighBands[k][j++] = end - start;
}
_exponentHighSizes[k] = j;
}
}
void WMACodec::initNoise() {
if (!_useNoiseCoding)
return;
_noiseMult = _useExpHuffman ? 0.02 : 0.04;
_noiseIndex = 0;
uint seed = 1;
float norm = (1.0 / (float)(1LL << 31)) * sqrt(3.0f) * _noiseMult;
for (int i = 0; i < kNoiseTabSize; i++) {
seed = seed * 314159 + 1;
_noiseTable[i] = (float)((int)seed) * norm;
}
_hgainHuffman = new HuffmanDecoder(0, ARRAYSIZE(hgainHuffCodes),
hgainHuffCodes, hgainHuffBits);
}
void WMACodec::initCoefHuffman(float bps) {
// Choose the parameter table
int coefHuffTable = 2;
if (_sampleRate >= 32000) {
if (bps < 0.72) {
coefHuffTable = 0;
} else if (bps < 1.16) {
coefHuffTable = 1;
}
}
_coefHuffmanParam[0] = &coefHuffmanParam[coefHuffTable * 2 ];
_coefHuffmanParam[1] = &coefHuffmanParam[coefHuffTable * 2 + 1];
_coefHuffman[0] = initCoefHuffman(_coefHuffmanRunTable[0], _coefHuffmanLevelTable[0],
_coefHuffmanIntTable[0], *_coefHuffmanParam[0]);
_coefHuffman[1] = initCoefHuffman(_coefHuffmanRunTable[1], _coefHuffmanLevelTable[1],
_coefHuffmanIntTable[1], *_coefHuffmanParam[1]);
}
void WMACodec::initMDCT() {
_mdct.reserve(_blockSizeCount);
for (int i = 0; i < _blockSizeCount; i++)
_mdct.push_back(new Common::MDCT(_frameLenBits - i + 1, true, 1.0));
// Init MDCT windows (simple sine window)
_mdctWindow.reserve(_blockSizeCount);
for (int i = 0; i < _blockSizeCount; i++)
_mdctWindow.push_back(Common::getSineWindow(_frameLenBits - i));
}
void WMACodec::initExponents() {
if (_useExpHuffman)
_expHuffman = new HuffmanDecoder(0, ARRAYSIZE(scaleHuffCodes),
scaleHuffCodes, scaleHuffBits);
else
initLSPToCurve();
}
WMACodec::HuffmanDecoder *WMACodec::initCoefHuffman(uint16 *&runTable, float *&levelTable,
uint16 *&intTable, const WMACoefHuffmanParam &params) {
HuffmanDecoder *huffman =
new HuffmanDecoder(0, params.n, params.huffCodes, params.huffBits);
runTable = new uint16[params.n];
levelTable = new float[params.n];
intTable = new uint16[params.n];
uint16 *iLevelTable = new uint16[params.n];
int i = 2;
int level = 1;
int k = 0;
while (i < params.n) {
intTable[k] = i;
int l = params.levels[k++];
for (int j = 0; j < l; j++) {
runTable [i] = j;
iLevelTable[i] = level;
levelTable [i] = level;
i++;
}
level++;
}
delete[] iLevelTable;
return huffman;
}
void WMACodec::initLSPToCurve() {
float wdel = M_PI / _frameLen;
for (int i = 0; i < _frameLen; i++)
_lspCosTable[i] = 2.0f * cosf(wdel * i);
// Tables for x^-0.25 computation
for (int i = 0; i < 256; i++) {
int e = i - 126;
_lspPowETable[i] = powf(2.0, e * -0.25);
}
// NOTE: These two tables are needed to avoid two operations in pow_m1_4
float b = 1.0;
for (int i = (1 << kLSPPowBits) - 1; i >= 0; i--) {
int m = (1 << kLSPPowBits) + i;
float a = (float) m * (0.5 / (1 << kLSPPowBits));
a = pow(a, -0.25f);
_lspPowMTable1[i] = 2 * a - b;
_lspPowMTable2[i] = b - a;
b = a;
}
}
AudioStream *WMACodec::decodeFrame(Common::SeekableReadStream &data) {
Common::SeekableReadStream *stream = decodeSuperFrame(data);
if (!stream)
return 0;
return makeRawStream(stream, _sampleRate, _audioFlags, DisposeAfterUse::YES);
}
Common::SeekableReadStream *WMACodec::decodeSuperFrame(Common::SeekableReadStream &data) {
uint32 size = data.size();
if (size < _blockAlign) {
warning("WMACodec::decodeSuperFrame(): size < _blockAlign");
return 0;
}
if (_blockAlign)
size = _blockAlign;
Common::BitStream8MSB bits(data);
int outputDataSize = 0;
int16 *outputData = 0;
_curFrame = 0;
if (_useBitReservoir) {
// This superframe consists of more than just one frame
bits.skip(4); // Super frame index
// Number of frames in this superframe
int newFrameCount = bits.getBits(4) - 1;
if (newFrameCount < 0) {
warning("WMACodec::decodeSuperFrame(): newFrameCount == %d", newFrameCount);
_resetBlockLengths = true;
_lastSuperframeLen = 0;
_lastBitoffset = 0;
return 0;
}
// Number of frames in this superframe + overhang from the last superframe
int frameCount = newFrameCount;
if (_lastSuperframeLen > 0)
frameCount++;
// PCM output data
outputDataSize = frameCount * _channels * _frameLen;
outputData = new int16[outputDataSize];
memset(outputData, 0, outputDataSize * 2);
// Number of bits data that completes the last superframe's overhang.
int bitOffset = bits.getBits(_byteOffsetBits + 3);
if (_lastSuperframeLen > 0) {
// We have overhang data from the last superframe. Paste the
// complementary data from this superframe at the end and
// decode it as another frame.
byte *lastSuperframeEnd = _lastSuperframe + _lastSuperframeLen;
while (bitOffset > 7) { // Full bytes
*lastSuperframeEnd++ = bits.getBits(8);
bitOffset -= 8;
_lastSuperframeLen += 1;
}
if (bitOffset > 0) { // Remaining bits
*lastSuperframeEnd++ = bits.getBits(bitOffset) << (8 - bitOffset);
bitOffset = 0;
_lastSuperframeLen += 1;
}
Common::MemoryReadStream lastSuperframe(_lastSuperframe, _lastSuperframeLen);
Common::BitStream8MSB lastBits(lastSuperframe);
lastBits.skip(_lastBitoffset);
decodeFrame(lastBits, outputData);
_curFrame++;
}
// Skip any complementary data we haven't used
bits.skip(bitOffset);
// New superframe = New block lengths
_resetBlockLengths = true;
// Decode the frames
for (int i = 0; i < newFrameCount; i++, _curFrame++)
if (!decodeFrame(bits, outputData))
return 0;
// Check if we've got new overhang data
int remainingBits = bits.size() - bits.pos();
if (remainingBits > 0) {
// We do: Save it
_lastSuperframeLen = remainingBits >> 3;
_lastBitoffset = 8 - (remainingBits - (_lastSuperframeLen << 3));
if (_lastBitoffset > 0)
_lastSuperframeLen++;
data.seek(data.size() - _lastSuperframeLen);
data.read(_lastSuperframe, _lastSuperframeLen);
} else {
// We don't
_lastSuperframeLen = 0;
_lastBitoffset = 0;
}
} else {
// This superframe has only one frame
// PCM output data
outputDataSize = _channels * _frameLen;
outputData = new int16[outputDataSize];
memset(outputData, 0, outputDataSize * 2);
// Decode the frame
if (!decodeFrame(bits, outputData)) {
delete[] outputData;
return 0;
}
}
// And return our PCM output data as a stream, if available
if (!outputData)
return 0;
return new Common::MemoryReadStream((byte *) outputData, outputDataSize * 2, DisposeAfterUse::YES);
}
bool WMACodec::decodeFrame(Common::BitStream8MSB &bits, int16 *outputData) {
_framePos = 0;
_curBlock = 0;
// Decode all blocks
int finished = 0;
while (finished == 0)
finished = decodeBlock(bits);
// Check for error
if (finished < 0)
return false;
// Convert output into interleaved PCM data
const float *floatOut[kChannelsMax];
for (int i = 0; i < kChannelsMax; i++)
floatOut[i] = _frameOut[i];
int16 *pcmOut = outputData + _curFrame * _channels * _frameLen;
floatToInt16Interleave(pcmOut, floatOut, _frameLen, _channels);
// Prepare for the next frame
for (int i = 0; i < _channels; i++)
memmove(&_frameOut[i][0], &_frameOut[i][_frameLen], _frameLen * sizeof(float));
return true;
}
int WMACodec::decodeBlock(Common::BitStream8MSB &bits) {
// Computer new block length
if (!evalBlockLength(bits))
return -1;
// Block size
int bSize = _frameLenBits - _blockLenBits;
assert((bSize >= 0) && (bSize < _blockSizeCount));
// MS Stereo?
bool msStereo = false;
if (_channels == 2)
msStereo = bits.getBit();
// Which channels are encoded?
bool hasChannels = false;
bool hasChannel[kChannelsMax];
for (int i = 0; i < kChannelsMax; i++)
hasChannel[i] = false;
for (int i = 0; i < _channels; i++) {
hasChannel[i] = bits.getBit();
if (hasChannel[i])
hasChannels = true;
}
// Decode channels
if (hasChannels)
if (!decodeChannels(bits, bSize, msStereo, hasChannel))
return -1;
// Calculate IMDCTs
if (!calculateIMDCT(bSize, msStereo, hasChannel))
return -1;
// Update block number
_curBlock += 1;
_framePos += _blockLen;
// Finished
if (_framePos >= _frameLen)
return 1;
// Need more blocks
return 0;
}
bool WMACodec::decodeChannels(Common::BitStream8MSB &bits, int bSize,
bool msStereo, bool *hasChannel) {
int totalGain = readTotalGain(bits);
int coefBitCount = totalGainToBits(totalGain);
int coefCount[kChannelsMax];
calculateCoefCount(coefCount, bSize);
if (!decodeNoise(bits, bSize, hasChannel, coefCount))
return false;
if (!decodeExponents(bits, bSize, hasChannel))
return false;
if (!decodeSpectralCoef(bits, msStereo, hasChannel, coefCount, coefBitCount))
return false;
float mdctNorm = getNormalizedMDCTLength();
calculateMDCTCoefficients(bSize, hasChannel, coefCount, totalGain, mdctNorm);
if (msStereo && hasChannel[1]) {
// Nominal case for ms stereo: we do it before MDCT
// No need to optimize this case because it should almost never happen
if (!hasChannel[0]) {
memset(_coefs[0], 0, sizeof(float) * _blockLen);
hasChannel[0] = true;
}
butterflyFloats(_coefs[0], _coefs[1], _blockLen);
}
return true;
}
bool WMACodec::calculateIMDCT(int bSize, bool msStereo, bool *hasChannel) {
Common::MDCT &mdct = *_mdct[bSize];
for (int i = 0; i < _channels; i++) {
int n4 = _blockLen / 2;
if (hasChannel[i])
mdct.calcIMDCT(_output, _coefs[i]);
else if (!(msStereo && (i == 1)))
memset(_output, 0, sizeof(_output));
// Multiply by the window and add in the frame
int index = (_frameLen / 2) + _framePos - n4;
window(&_frameOut[i][index]);
}
return true;
}
bool WMACodec::evalBlockLength(Common::BitStream8MSB &bits) {
if (_useVariableBlockLen) {
// Variable block lengths
int n = Common::intLog2(_blockSizeCount - 1) + 1;
if (_resetBlockLengths) {
// Completely new block lengths
_resetBlockLengths = false;
const int prev = bits.getBits(n);
const int prevBits = _frameLenBits - prev;
if (prev >= _blockSizeCount) {
warning("WMACodec::evalBlockLength(): _prevBlockLenBits %d out of range", prevBits);
return false;
}
_prevBlockLenBits = prevBits;
const int cur = bits.getBits(n);
const int curBits = _frameLenBits - cur;
if (cur >= _blockSizeCount) {
warning("WMACodec::evalBlockLength(): _blockLenBits %d out of range", curBits);
return false;
}
_blockLenBits = curBits;
} else {
// Update block lengths
_prevBlockLenBits = _blockLenBits;
_blockLenBits = _nextBlockLenBits;
}
const int next = bits.getBits(n);
const int nextBits = _frameLenBits - next;
if (next >= _blockSizeCount) {
warning("WMACodec::evalBlockLength(): _nextBlockLenBits %d out of range", nextBits);
return false;
}
_nextBlockLenBits = nextBits;
} else {
// Fixed block length
_nextBlockLenBits = _frameLenBits;
_prevBlockLenBits = _frameLenBits;
_blockLenBits = _frameLenBits;
}
// Sanity checks
if (_frameLenBits - _blockLenBits >= _blockSizeCount) {
warning("WMACodec::evalBlockLength(): _blockLenBits not initialized to a valid value");
return false;
}
_blockLen = 1 << _blockLenBits;
if ((_framePos + _blockLen) > _frameLen) {
warning("WMACodec::evalBlockLength(): frame length overflow");
return false;
}
return true;
}
void WMACodec::calculateCoefCount(int *coefCount, int bSize) const {
const int coefN = _coefsEnd[bSize] - _coefsStart;
for (int i = 0; i < _channels; i++)
coefCount[i] = coefN;
}
bool WMACodec::decodeNoise(Common::BitStream8MSB &bits, int bSize,
bool *hasChannel, int *coefCount) {
if (!_useNoiseCoding)
return true;
for (int i = 0; i < _channels; i++) {
if (!hasChannel[i])
continue;
const int n = _exponentHighSizes[bSize];
for (int j = 0; j < n; j++) {
bool a = bits.getBit() != 0;
_highBandCoded[i][j] = a;
// With noise coding, the coefficients are not transmitted
if (a)
coefCount[i] -= _exponentHighBands[bSize][j];
}
}
for (int i = 0; i < _channels; i++) {
if (!hasChannel[i])
continue;
const int n = _exponentHighSizes[bSize];
int val = (int) 0x80000000;
for (int j = 0; j < n; j++) {
if (!_highBandCoded[i][j])
continue;
if (val != (int) 0x80000000) {
int code = _hgainHuffman->getSymbol(bits);
if (code < 0) {
warning("WMACodec::decodeNoise(): HGain Huffman invalid");
return false;
}
val += code - 18;
} else
val = bits.getBits(7) - 19;
_highBandValues[i][j] = val;
}
}
return true;
}
bool WMACodec::decodeExponents(Common::BitStream8MSB &bits, int bSize, bool *hasChannel) {
// Exponents can be reused in short blocks
if (!((_blockLenBits == _frameLenBits) || bits.getBit()))
return true;
for (int i = 0; i < _channels; i++) {
if (!hasChannel[i])
continue;
if (_useExpHuffman) {
if (!decodeExpHuffman(bits, i))
return false;
} else {
if (!decodeExpLSP(bits, i))
return false;
}
_exponentsBSize[i] = bSize;
}
return true;
}
bool WMACodec::decodeSpectralCoef(Common::BitStream8MSB &bits, bool msStereo, bool *hasChannel,
int *coefCount, int coefBitCount) {
// Simple RLE encoding
for (int i = 0; i < _channels; i++) {
if (hasChannel[i]) {
// Special Huffman tables are used for MS stereo
// because there is potentially less energy there.
const int tindex = ((i == 1) && msStereo);
float *ptr = &_coefs1[i][0];
memset(ptr, 0, _blockLen * sizeof(float));
if (!decodeRunLevel(bits, *_coefHuffman[tindex],
_coefHuffmanLevelTable[tindex], _coefHuffmanRunTable[tindex],
0, ptr, 0, coefCount[i], _blockLen, _frameLenBits, coefBitCount))
return false;
}
if ((_version == 1) && (_channels >= 2))
bits.skip(-bits.pos() & 7);
}
return true;
}
float WMACodec::getNormalizedMDCTLength() const {
const int n4 = _blockLen / 2;
float mdctNorm = 1.0 / (float) n4;
if (_version == 1)
mdctNorm *= sqrt((float) n4);
return mdctNorm;
}
void WMACodec::calculateMDCTCoefficients(int bSize, bool *hasChannel,
int *coefCount, int totalGain, float mdctNorm) {
for (int i = 0; i < _channels; i++) {
if (!hasChannel[i])
continue;
float *coefs = _coefs[i];
const float *coefs1 = _coefs1[i];
const float *exponents = _exponents[i];
const int eSize = _exponentsBSize[i];
const float mult = (pow(10, totalGain * 0.05) / _maxExponent[i]) * mdctNorm;
if (_useNoiseCoding) {
// Very low freqs: noise
for (int j = 0; j < _coefsStart; j++) {
*coefs++ = _noiseTable[_noiseIndex] * exponents[(j << bSize) >> eSize] * mult;
_noiseIndex = (_noiseIndex + 1) & (kNoiseTabSize - 1);
}
// Compute power of high bands
float expPower[kHighBandSizeMax];
const int n1 = _exponentHighSizes[bSize];
exponents = _exponents[i] + ((_highBandStart[bSize] << bSize) >> eSize);
int lastHighBand = 0;
for (int k = 0; k < n1; k++) {
const int n = _exponentHighBands[_frameLenBits - _blockLenBits][k];
if (_highBandCoded[i][k]) {
float e2 = 0;
for (int j = 0; j < n; j++) {
const float v = exponents[(j << bSize) >> eSize];
e2 += v * v;
}
expPower[k] = e2 / n;
lastHighBand = k;
}
exponents += (n << bSize) >> eSize;
}
// Main freqs and high freqs
exponents = _exponents[i] + ((_coefsStart << bSize) >> eSize);
for (int k = -1; k < n1; k++) {
int n;
if (k < 0)
n = _highBandStart[bSize] - _coefsStart;
else
n = _exponentHighBands[_frameLenBits - _blockLenBits][k];
if (k >= 0 && _highBandCoded[i][k]) {
// Use noise with specified power
float mult1 = sqrt(expPower[k] / expPower[lastHighBand]);
mult1 *= pow(10, _highBandValues[i][k] * 0.05);
mult1 /= _maxExponent[i] * _noiseMult;
mult1 *= mdctNorm;
for (int j = 0; j < n; j++) {
float noise = _noiseTable[_noiseIndex];
_noiseIndex = (_noiseIndex + 1) & (kNoiseTabSize - 1);
*coefs++ = noise * exponents[(j << bSize) >> eSize] * mult1;
}
exponents += (n << bSize) >> eSize;
} else {
// Coded values + small noise
for (int j = 0; j < n; j++) {
float noise = _noiseTable[_noiseIndex];
_noiseIndex = (_noiseIndex + 1) & (kNoiseTabSize - 1);
*coefs++ = ((*coefs1++) + noise) * exponents[(j << bSize) >> eSize] * mult;
}
exponents += (n << bSize) >> eSize;
}
}
// Very high freqs: Noise
const int n = _blockLen - _coefsEnd[bSize];
const float mult1 = mult * exponents[(-(1 << bSize)) >> eSize];
for (int j = 0; j < n; j++) {
*coefs++ = _noiseTable[_noiseIndex] * mult1;
_noiseIndex = (_noiseIndex + 1) & (kNoiseTabSize - 1);
}
} else {
for (int j = 0; j < _coefsStart; j++)
*coefs++ = 0.0;
for (int j = 0;j < coefCount[i]; j++) {
*coefs = coefs1[j] * exponents[(j << bSize) >> eSize] * mult;
coefs++;
}
int n = _blockLen - _coefsEnd[bSize];
for (int j = 0; j < n; j++)
*coefs++ = 0.0;
}
}
}
static const float powTab[] = {
1.7782794100389e-04, 2.0535250264571e-04,
2.3713737056617e-04, 2.7384196342644e-04,
3.1622776601684e-04, 3.6517412725484e-04,
4.2169650342858e-04, 4.8696752516586e-04,
5.6234132519035e-04, 6.4938163157621e-04,
7.4989420933246e-04, 8.6596432336006e-04,
1.0000000000000e-03, 1.1547819846895e-03,
1.3335214321633e-03, 1.5399265260595e-03,
1.7782794100389e-03, 2.0535250264571e-03,
2.3713737056617e-03, 2.7384196342644e-03,
3.1622776601684e-03, 3.6517412725484e-03,
4.2169650342858e-03, 4.8696752516586e-03,
5.6234132519035e-03, 6.4938163157621e-03,
7.4989420933246e-03, 8.6596432336006e-03,
1.0000000000000e-02, 1.1547819846895e-02,
1.3335214321633e-02, 1.5399265260595e-02,
1.7782794100389e-02, 2.0535250264571e-02,
2.3713737056617e-02, 2.7384196342644e-02,
3.1622776601684e-02, 3.6517412725484e-02,
4.2169650342858e-02, 4.8696752516586e-02,
5.6234132519035e-02, 6.4938163157621e-02,
7.4989420933246e-02, 8.6596432336007e-02,
1.0000000000000e-01, 1.1547819846895e-01,
1.3335214321633e-01, 1.5399265260595e-01,
1.7782794100389e-01, 2.0535250264571e-01,
2.3713737056617e-01, 2.7384196342644e-01,
3.1622776601684e-01, 3.6517412725484e-01,
4.2169650342858e-01, 4.8696752516586e-01,
5.6234132519035e-01, 6.4938163157621e-01,
7.4989420933246e-01, 8.6596432336007e-01,
1.0000000000000e+00, 1.1547819846895e+00,
1.3335214321633e+00, 1.5399265260595e+00,
1.7782794100389e+00, 2.0535250264571e+00,
2.3713737056617e+00, 2.7384196342644e+00,
3.1622776601684e+00, 3.6517412725484e+00,
4.2169650342858e+00, 4.8696752516586e+00,
5.6234132519035e+00, 6.4938163157621e+00,
7.4989420933246e+00, 8.6596432336007e+00,
1.0000000000000e+01, 1.1547819846895e+01,
1.3335214321633e+01, 1.5399265260595e+01,
1.7782794100389e+01, 2.0535250264571e+01,
2.3713737056617e+01, 2.7384196342644e+01,
3.1622776601684e+01, 3.6517412725484e+01,
4.2169650342858e+01, 4.8696752516586e+01,
5.6234132519035e+01, 6.4938163157621e+01,
7.4989420933246e+01, 8.6596432336007e+01,
1.0000000000000e+02, 1.1547819846895e+02,
1.3335214321633e+02, 1.5399265260595e+02,
1.7782794100389e+02, 2.0535250264571e+02,
2.3713737056617e+02, 2.7384196342644e+02,
3.1622776601684e+02, 3.6517412725484e+02,
4.2169650342858e+02, 4.8696752516586e+02,
5.6234132519035e+02, 6.4938163157621e+02,
7.4989420933246e+02, 8.6596432336007e+02,
1.0000000000000e+03, 1.1547819846895e+03,
1.3335214321633e+03, 1.5399265260595e+03,
1.7782794100389e+03, 2.0535250264571e+03,
2.3713737056617e+03, 2.7384196342644e+03,
3.1622776601684e+03, 3.6517412725484e+03,
4.2169650342858e+03, 4.8696752516586e+03,
5.6234132519035e+03, 6.4938163157621e+03,
7.4989420933246e+03, 8.6596432336007e+03,
1.0000000000000e+04, 1.1547819846895e+04,
1.3335214321633e+04, 1.5399265260595e+04,
1.7782794100389e+04, 2.0535250264571e+04,
2.3713737056617e+04, 2.7384196342644e+04,
3.1622776601684e+04, 3.6517412725484e+04,
4.2169650342858e+04, 4.8696752516586e+04,
5.6234132519035e+04, 6.4938163157621e+04,
7.4989420933246e+04, 8.6596432336007e+04,
1.0000000000000e+05, 1.1547819846895e+05,
1.3335214321633e+05, 1.5399265260595e+05,
1.7782794100389e+05, 2.0535250264571e+05,
2.3713737056617e+05, 2.7384196342644e+05,
3.1622776601684e+05, 3.6517412725484e+05,
4.2169650342858e+05, 4.8696752516586e+05,
5.6234132519035e+05, 6.4938163157621e+05,
7.4989420933246e+05, 8.6596432336007e+05,
};
bool WMACodec::decodeExpHuffman(Common::BitStream8MSB &bits, int ch) {
const float *ptab = powTab + 60;
const uint32 *iptab = (const uint32 *) ptab;
const uint16 *ptr = _exponentBands[_frameLenBits - _blockLenBits];
uint32 *q = (uint32 *) _exponents[ch];
uint32 *qEnd = q + _blockLen;
float maxScale = 0;
int lastExp;
if (_version == 1) {
lastExp = bits.getBits(5) + 10;
float v = ptab[lastExp];
uint32 iv = iptab[lastExp];
maxScale = v;
int n = *ptr++;
switch (n & 3) do {
case 0: *q++ = iv; // fall through
case 3: *q++ = iv; // fall through
case 2: *q++ = iv; // fall through
case 1: *q++ = iv;
} while ((n -= 4) > 0);
} else
lastExp = 36;
while (q < qEnd) {
int code = _expHuffman->getSymbol(bits);
if (code < 0) {
warning("WMACodec::decodeExpHuffman(): Exponent invalid");
return false;
}
// NOTE: This offset is the same as MPEG4 AAC!
lastExp += code - 60;
if ((unsigned) lastExp + 60 >= ARRAYSIZE(powTab)) {
warning("WMACodec::decodeExpHuffman(): Exponent out of range: %d", lastExp);
return false;
}
float v = ptab[lastExp];
uint32 iv = iptab[lastExp];
if (v > maxScale)
maxScale = v;
int n = *ptr++;
switch (n & 3) do {
case 0: *q++ = iv; // fall through
case 3: *q++ = iv; // fall through
case 2: *q++ = iv; // fall through
case 1: *q++ = iv;
} while ((n -= 4) > 0);
}
_maxExponent[ch] = maxScale;
return true;
}
void WMACodec::lspToCurve(float *out, float *val_max_ptr, int n, float *lsp) {
float val_max = 0;
for (int i = 0; i < n; i++) {
float p = 0.5f;
float q = 0.5f;
float w = _lspCosTable[i];
for (int j = 1; j < kLSPCoefCount; j += 2) {
q *= w - lsp[j - 1];
p *= w - lsp[j];
}
p *= p * (2.0f - w);
q *= q * (2.0f + w);
float v = p + q;
v = pow_m1_4(v);
if (v > val_max)
val_max = v;
out[i] = v;
}
*val_max_ptr = val_max;
}
// Decode exponents coded with LSP coefficients (same idea as Vorbis)
bool WMACodec::decodeExpLSP(Common::BitStream8MSB &bits, int ch) {
float lspCoefs[kLSPCoefCount];
for (int i = 0; i < kLSPCoefCount; i++) {
int val;
if (i == 0 || i >= 8)
val = bits.getBits(3);
else
val = bits.getBits(4);
lspCoefs[i] = lspCodebook[i][val];
}
lspToCurve(_exponents[ch], &_maxExponent[ch], _blockLen, lspCoefs);
return true;
}
bool WMACodec::decodeRunLevel(Common::BitStream8MSB &bits, const HuffmanDecoder &huffman,
const float *levelTable, const uint16 *runTable, int version, float *ptr,
int offset, int numCoefs, int blockLen, int frameLenBits, int coefNbBits) {
const uint32 *ilvl = (const uint32*) levelTable;
uint32 *iptr = (uint32 *) ptr;
const unsigned int coefMask = blockLen - 1;
for (; offset < numCoefs; offset++) {
const int code = huffman.getSymbol(bits);
if (code > 1) {
// Normal code
const int sign = bits.getBit() - 1;
offset += runTable[code];
iptr[offset & coefMask] = ilvl[code] ^ (sign << 31);
} else if (code == 1) {
// EOB
break;
} else {
// Escape
int level;
if (!version) {
level = bits.getBits(coefNbBits);
// NOTE: This is rather suboptimal. reading blockLenBits would be better
offset += bits.getBits(frameLenBits);
} else {
level = getLargeVal(bits);
// Escape decode
if (bits.getBit()) {
if (bits.getBit()) {
if (bits.getBit()) {
warning("WMACodec::decodeRunLevel(): Broken escape sequence");
return false;
} else
offset += bits.getBits(frameLenBits) + 4;
} else
offset += bits.getBits(2) + 1;
}
}
const int sign = bits.getBit() - 1;
ptr[offset & coefMask] = (level ^ sign) - sign;
}
}
// NOTE: EOB can be omitted
if (offset > numCoefs) {
warning("WMACodec::decodeRunLevel(): Overflow in spectral RLE, ignoring");
return true;
}
return true;
}
/** Apply MDCT window and add into output.
*
* We ensure that when the windows overlap their squared sum
* is always 1 (MDCT reconstruction rule).
*/
void WMACodec::window(float *out) const {
const float *in = _output;
// Left part
if (_blockLenBits <= _prevBlockLenBits) {
const int bSize = _frameLenBits - _blockLenBits;
vectorFMulAdd(out, in, _mdctWindow[bSize], out, _blockLen);
} else {
const int blockLen = 1 << _prevBlockLenBits;
const int n = (_blockLen - blockLen) / 2;
const int bSize = _frameLenBits - _prevBlockLenBits;
vectorFMulAdd(out + n, in + n, _mdctWindow[bSize], out + n, blockLen);
memcpy(out + n + blockLen, in + n + blockLen, n * sizeof(float));
}
out += _blockLen;
in += _blockLen;
// Right part
if (_blockLenBits <= _nextBlockLenBits) {
const int bSize = _frameLenBits - _blockLenBits;
vectorFMulReverse(out, in, _mdctWindow[bSize], _blockLen);
} else {
const int blockLen = 1 << _nextBlockLenBits;
const int n = (_blockLen - blockLen) / 2;
const int bSize = _frameLenBits - _nextBlockLenBits;
memcpy(out, in, n*sizeof(float));
vectorFMulReverse(out + n, in + n, _mdctWindow[bSize], blockLen);
memset(out + n + blockLen, 0, n * sizeof(float));
}
}
float WMACodec::pow_m1_4(float x) const {
union {
float f;
unsigned int v;
} u, t;
u.f = x;
const unsigned int e = u.v >> 23;
const unsigned int m = (u.v >> (23 - kLSPPowBits)) & ((1 << kLSPPowBits) - 1);
// Build interpolation scale: 1 <= t < 2
t.v = ((u.v << kLSPPowBits) & ((1 << 23) - 1)) | (127 << 23);
const float a = _lspPowMTable1[m];
const float b = _lspPowMTable2[m];
return _lspPowETable[e] * (a + b * t.f);
}
int WMACodec::readTotalGain(Common::BitStream8MSB &bits) {
int totalGain = 1;
int v = 127;
while (v == 127) {
v = bits.getBits(7);
totalGain += v;
}
return totalGain;
}
int WMACodec::totalGainToBits(int totalGain) {
if (totalGain < 15) return 13;
else if (totalGain < 32) return 12;
else if (totalGain < 40) return 11;
else if (totalGain < 45) return 10;
else return 9;
}
uint32 WMACodec::getLargeVal(Common::BitStream8MSB &bits) {
// Consumes up to 34 bits
int count = 8;
if (bits.getBit()) {
count += 8;
if (bits.getBit()) {
count += 8;
if (bits.getBit())
count += 7;
}
}
return bits.getBits(count);
}
} // End of namespace Audio