scummvm/audio/decoders/wma.cpp
2021-04-15 21:20:36 +02:00

1513 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 = (float)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