/* 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::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 = (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