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.
1512 lines
36 KiB
C++
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 ¶ms) {
|
|
|
|
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
|