From 5d8552de3dea1bf2328b4ab7aee07734e5c91d0b Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Wed, 6 Jul 2016 11:53:44 -0700 Subject: [PATCH 01/19] Initial implementation of Spectral Band Replication for HE-AAC v1 --- src/adts_demuxer.js | 24 +- src/decoder.js | 163 +++--- src/fil.js | 54 ++ src/sbr/AnalysisFilterbank.js | 63 +++ src/sbr/ChannelData.js | 406 +++++++++++++++ src/sbr/FrequencyTables.js | 340 +++++++++++++ src/sbr/HFAdjuster.js | 898 +++++++++++++++++++++++++++++++++ src/sbr/HFGenerator.js | 200 ++++++++ src/sbr/HuffmanTables.js | 651 ++++++++++++++++++++++++ src/sbr/SynthesisFilterbank.js | 69 +++ src/sbr/constants.js | 198 ++++++++ src/sbr/header.js | 57 +++ src/sbr/sbr.js | 310 ++++++++++++ src/sbr/utils.js | 16 + src/tables.js | 16 + 15 files changed, 3395 insertions(+), 70 deletions(-) create mode 100644 src/fil.js create mode 100644 src/sbr/AnalysisFilterbank.js create mode 100644 src/sbr/ChannelData.js create mode 100644 src/sbr/FrequencyTables.js create mode 100644 src/sbr/HFAdjuster.js create mode 100644 src/sbr/HFGenerator.js create mode 100644 src/sbr/HuffmanTables.js create mode 100644 src/sbr/SynthesisFilterbank.js create mode 100644 src/sbr/constants.js create mode 100644 src/sbr/header.js create mode 100644 src/sbr/sbr.js create mode 100644 src/sbr/utils.js diff --git a/src/adts_demuxer.js b/src/adts_demuxer.js index 4c01a95..2f5f4ae 100644 --- a/src/adts_demuxer.js +++ b/src/adts_demuxer.js @@ -1,10 +1,8 @@ var AV = require('av'); var tables = require('./tables'); -var ADTSDemuxer = AV.Demuxer.extend(function() { - AV.Demuxer.register(this); - - this.probe = function(stream) { +class ADTSDemuxer extends AV.Demuxer { + static probe(stream) { var offset = stream.offset; // attempt to find ADTS syncword @@ -17,15 +15,15 @@ var ADTSDemuxer = AV.Demuxer.extend(function() { stream.seek(offset); return false; - }; + } - this.prototype.init = function() { + init() { this.bitstream = new AV.Bitstream(this.stream); - }; + } // Reads an ADTS header // See http://wiki.multimedia.cx/index.php?title=ADTS - this.readHeader = function(stream) { + static readHeader(stream) { if (stream.read(12) !== 0xfff) throw new Error('Invalid ADTS header.'); @@ -49,9 +47,9 @@ var ADTSDemuxer = AV.Demuxer.extend(function() { stream.advance(16); return ret; - }; + } - this.prototype.readChunk = function() { + readChunk() { if (!this.sentHeader) { var offset = this.stream.offset; var header = ADTSDemuxer.readHeader(this.bitstream); @@ -77,7 +75,9 @@ var ADTSDemuxer = AV.Demuxer.extend(function() { var buffer = this.stream.readSingleBuffer(this.stream.remainingBytes()); this.emit('data', buffer); } - }; -}); + } +} + +AV.Demuxer.register(ADTSDemuxer); module.exports = ADTSDemuxer; diff --git a/src/decoder.js b/src/decoder.js index 6c3a7b5..5c337ad 100644 --- a/src/decoder.js +++ b/src/decoder.js @@ -25,37 +25,43 @@ var CPEElement = require('./cpe'); var CCEElement = require('./cce'); var FilterBank = require('./filter_bank'); var tables = require('./tables'); +var FIL = require('./fil'); +var SBR = require('./sbr/sbr'); -var AACDecoder = AV.Decoder.extend(function() { - AV.Decoder.register('mp4a', this); - AV.Decoder.register('aac ', this); - - // AAC profiles - const AOT_AAC_MAIN = 1, // no - AOT_AAC_LC = 2, // yes - AOT_AAC_LTP = 4, // no - AOT_ESCAPE = 31; - - // Channel configurations - const CHANNEL_CONFIG_NONE = 0, - CHANNEL_CONFIG_MONO = 1, - CHANNEL_CONFIG_STEREO = 2, - CHANNEL_CONFIG_STEREO_PLUS_CENTER = 3, - CHANNEL_CONFIG_STEREO_PLUS_CENTER_PLUS_REAR_MONO = 4, - CHANNEL_CONFIG_FIVE = 5, - CHANNEL_CONFIG_FIVE_PLUS_ONE = 6, - CHANNEL_CONFIG_SEVEN_PLUS_ONE = 8; - - this.prototype.init = function() { +// AAC profiles +const AOT_AAC_MAIN = 1, // no + AOT_AAC_LC = 2, // yes + AOT_AAC_LTP = 4, // no + AOT_ESCAPE = 31; + +// Channel configurations +const CHANNEL_CONFIG_NONE = 0, + CHANNEL_CONFIG_MONO = 1, + CHANNEL_CONFIG_STEREO = 2, + CHANNEL_CONFIG_STEREO_PLUS_CENTER = 3, + CHANNEL_CONFIG_STEREO_PLUS_CENTER_PLUS_REAR_MONO = 4, + CHANNEL_CONFIG_FIVE = 5, + CHANNEL_CONFIG_FIVE_PLUS_ONE = 6, + CHANNEL_CONFIG_SEVEN_PLUS_ONE = 8; + +const SCE_ELEMENT = 0, + CPE_ELEMENT = 1, + CCE_ELEMENT = 2, + LFE_ELEMENT = 3, + DSE_ELEMENT = 4, + PCE_ELEMENT = 5, + FIL_ELEMENT = 6, + END_ELEMENT = 7; + +class AACDecoder extends AV.Decoder { + init() { this.format.floatingPoint = true; } - this.prototype.setCookie = function(buffer) { - var data = AV.Stream.fromBuffer(buffer), - stream = new AV.Bitstream(data); + setCookie(buffer) { + var stream = AV.Bitstream.fromBuffer(buffer); this.config = {}; - this.config.profile = stream.read(5); if (this.config.profile === AOT_ESCAPE) this.config.profile = 32 + stream.read(6); @@ -75,6 +81,7 @@ var AACDecoder = AV.Decoder.extend(function() { this.config.chanConfig = stream.read(4); this.format.channelsPerFrame = this.config.chanConfig; // sometimes m4a files encode this wrong + this.format.sampleRate = this.config.sampleRate; switch (this.config.profile) { case AOT_AAC_MAIN: @@ -109,20 +116,31 @@ var AACDecoder = AV.Decoder.extend(function() { throw new Error('AAC profile ' + this.config.profile + ' not supported.'); } + console.log(stream.available(10)) + if (stream.available(11)) { + let type = stream.read(11); + switch (type) { + case 0x2B7: + let profile = stream.read(5); + if (profile === 5) { + this.config.sbrPresent = stream.read(1); + if (this.config.sbrPresent) { + this.config.profile = profile; + + let sampleIndex = stream.read(4); + this.format.sampleRate = tables.SAMPLE_RATES[sampleIndex]; + console.log(this.config) + } + } + break; + } + } + this.filter_bank = new FilterBank(false, this.config.chanConfig); - }; - - const SCE_ELEMENT = 0, - CPE_ELEMENT = 1, - CCE_ELEMENT = 2, - LFE_ELEMENT = 3, - DSE_ELEMENT = 4, - PCE_ELEMENT = 5, - FIL_ELEMENT = 6, - END_ELEMENT = 7; - + } + // The main decoding function. - this.prototype.readChunk = function() { + readChunk() { var stream = this.bitstream; // check if there is an ADTS header, and read it if so @@ -132,7 +150,8 @@ var AACDecoder = AV.Decoder.extend(function() { this.cces = []; var elements = [], config = this.config, - frameLength = config.frameLength, + mult = config.sbrPresent ? 2 : 1, + frameLength = mult * config.frameLength, elementType = null; while ((elementType = stream.read(3)) !== END_ELEMENT) { @@ -146,6 +165,7 @@ var AACDecoder = AV.Decoder.extend(function() { ics.id = id; elements.push(ics); ics.decode(stream, config, false); + this.prev = ics; break; // channel pair element @@ -154,6 +174,7 @@ var AACDecoder = AV.Decoder.extend(function() { cpe.id = id; elements.push(cpe); cpe.decode(stream, config); + this.prev = cpe; break; // channel coupling element @@ -161,6 +182,7 @@ var AACDecoder = AV.Decoder.extend(function() { var cce = new CCEElement(this.config); this.cces.push(cce); cce.decode(stream, config); + this.prev = null; break; // data-stream element @@ -176,20 +198,34 @@ var AACDecoder = AV.Decoder.extend(function() { // skip for now... stream.advance(count * 8); + this.prev = null; break; // program configuration element case PCE_ELEMENT: + this.prev = null; throw new Error("TODO: PCE_ELEMENT") break; // filler element case FIL_ELEMENT: - if (id === 15) + if (id === 15) { id += stream.read(8) - 1; - + } + + id *= 8; + var end = stream.offset() + id; + + FIL.decode(stream, id, this.prev, this.config.sampleRate); + + if (this.prev && this.prev.sbr) { + this.sbrPresent = true; + } + + this.prev = null; + // skip for now... - stream.advance(id * 8); + stream.seek(end); break; default: @@ -200,6 +236,12 @@ var AACDecoder = AV.Decoder.extend(function() { stream.align(); this.process(elements); + for (let element of elements) { + if (element.sbr) { + SBR.release(element.sbr); + } + } + // Interleave channels var data = this.data, channels = data.length, @@ -213,14 +255,14 @@ var AACDecoder = AV.Decoder.extend(function() { } return output; - }; + } - this.prototype.process = function(elements) { + process(elements) { var channels = this.config.chanConfig; // if (channels === 1 && psPresent) // TODO: sbrPresent (2) - var mult = 1; + var mult = this.config.sbrPresent ? 2 : 1; var len = mult * this.config.frameLength; var data = this.data = []; @@ -245,9 +287,9 @@ var AACDecoder = AV.Decoder.extend(function() { throw new Error("Unknown element found.") } } - }; + } - this.prototype.processSingle = function(element, channel) { + processSingle(element, channel) { var profile = this.config.profile, info = element.info, data = element.data; @@ -280,9 +322,9 @@ var AACDecoder = AV.Decoder.extend(function() { throw new Error("SBR not implemented"); return 1; - }; + } - this.prototype.processPair = function(element, channel) { + processPair(element, channel) { var profile = this.config.profile, left = element.left, right = element.right, @@ -329,12 +371,14 @@ var AACDecoder = AV.Decoder.extend(function() { if (right.gainPresent) throw new Error("Gain control not implemented"); - if (this.sbrPresent) - throw new Error("SBR not implemented"); - }; + if (this.sbrPresent) { + // throw new Error("SBR not implemented"); + element.sbr.process(this.data[channel], this.data[channel + 1], false); + } + } // Intensity stereo - this.prototype.processIS = function(element, left, right) { + processIS(element, left, right) { var ics = element.right, info = ics.info, offsets = info.swbOffsets, @@ -373,10 +417,10 @@ var AACDecoder = AV.Decoder.extend(function() { groupOff += info.groupLength[g] * 128; } - }; + } // Mid-side stereo - this.prototype.processMS = function(element, left, right) { + processMS(element, left, right) { var ics = element.left, info = ics.info, offsets = info.swbOffsets, @@ -401,9 +445,9 @@ var AACDecoder = AV.Decoder.extend(function() { } groupOff += info.groupLength[g] * 128; } - }; + } - this.prototype.applyChannelCoupling = function(element, couplingPoint, data1, data2) { + applyChannelCoupling(element, couplingPoint, data1, data2) { var cces = this.cces, isChannelPair = element instanceof CPEElement, applyCoupling = couplingPoint === CCEElement.AFTER_IMDCT ? 'applyIndependentCoupling' : 'applyDependentCoupling'; @@ -430,8 +474,11 @@ var AACDecoder = AV.Decoder.extend(function() { } } } - }; + } -}); +} + +AV.Decoder.register('mp4a', AACDecoder); +AV.Decoder.register('aac ', AACDecoder); module.exports = AACDecoder; diff --git a/src/fil.js b/src/fil.js new file mode 100644 index 0000000..d133de1 --- /dev/null +++ b/src/fil.js @@ -0,0 +1,54 @@ +var CPEElement = require('./cpe'); +var SBR = require('./sbr/sbr'); + +const TYPE_FILL = 0; +const TYPE_FILL_DATA = 1; +const TYPE_EXT_DATA_ELEMENT = 2; +const TYPE_DYNAMIC_RANGE = 11; +const TYPE_SBR_DATA = 13; +const TYPE_SBR_DATA_CRC = 14; + +function FIL() { + +} + +FIL.decode = function(stream, count, prev, sampleRate) { + var pos = stream.offset(); + var end = pos + count; + + while (count > 0) { + count = this.decodeExtension(stream, count, prev, sampleRate); + } + + stream.advance(end - stream.offset()); +}; + +FIL.decodeExtension = function(stream, count, prev, sampleRate) { + var type = stream.read(4); + count -= 4; + + switch (type) { + case TYPE_DYNAMIC_RANGE: + console.log('dynamic range'); + break; + + case TYPE_SBR_DATA: + case TYPE_SBR_DATA_CRC: + if (prev) { + // prev.sbr = new SBR(sampleRate, false); + prev.sbr = SBR.get(sampleRate, false); + prev.sbr.decode(stream, count, prev instanceof CPEElement, type === TYPE_SBR_DATA_CRC); + } + return 0; + + case TYPE_FILL: + case TYPE_FILL_DATA: + case TYPE_EXT_DATA_ELEMENT: + console.log('OTHER') + break; + } + + // stream.advance(count); +}; + +module.exports = FIL; diff --git a/src/sbr/AnalysisFilterbank.js b/src/sbr/AnalysisFilterbank.js new file mode 100644 index 0000000..61a13c0 --- /dev/null +++ b/src/sbr/AnalysisFilterbank.js @@ -0,0 +1,63 @@ +import {makeArray} from './utils'; +import {TIME_SLOTS_RATE, WINDOW} from './constants'; + +export default class AnalysisFilterbank { + constructor() { + this.X = makeArray([2, 320]); + this.z = new Float32Array(320); + this.u = new Float32Array(64); + + this.COEFS = makeArray([32, 64, 2]); + let tmp; + for (let k = 0; k < 32; k++) { + for (let n = 0; n < 64; n++) { + tmp = Math.PI / 64.0 * (k + 0.5) * (2 * n - 0.5); + this.COEFS[k][n][0] = 2 * Math.cos(tmp); + this.COEFS[k][n][1] = 2 * Math.sin(tmp); + } + } + } + + // in: 1024 time samples, out: 32 x 32 complex + process(inp, out, ch) { + let x = this.X[ch]; + let n, k, inOff = 0; + + // each loop creates 32 complex subband samples + for (let l = 0; l < TIME_SLOTS_RATE; l++) { + // 1. shift buffer + for (n = 319; n >= 32; n--) { + x[n] = x[n - 32]; + } + + // 2. add new samples + for (n = 31; n >= 0; n--) { + x[n] = inp[inOff]; + inOff++; + } + + // 3. windowing + for (n = 0; n < 320; n++) { + this.z[n] = x[n] * WINDOW[2 * n]; + } + + // 4. sum samples + for (n = 0; n < 64; n++) { + this.u[n] = this.z[n]; + for (k = 1; k < 5; k++) { + this.u[n] += this.z[n + k * 64]; + } + } + + // 5. calculate subband samples, TODO: replace with FFT? + for (k = 0; k < 32; k++) { + out[l][k][0] = this.u[0] * this.COEFS[k][0][0]; + out[l][k][1] = this.u[0] * this.COEFS[k][0][1]; + for (n = 1; n < 64; n++) { + out[l][k][0] += this.u[n] * this.COEFS[k][n][0]; + out[l][k][1] += this.u[n] * this.COEFS[k][n][1]; + } + } + } + } +} diff --git a/src/sbr/ChannelData.js b/src/sbr/ChannelData.js new file mode 100644 index 0000000..7362516 --- /dev/null +++ b/src/sbr/ChannelData.js @@ -0,0 +1,406 @@ +import * as HuffmanTables from './HuffmanTables'; +import {makeArray} from './utils'; +import {TIME_SLOTS_RATE} from './constants'; + +const MAX_ENV_COUNT = 5; +const MAX_NQ = 5; +const MAX_NOISE_COUNT = 2; +const MAX_BANDS = 64; +const MAX_CHIRP_FACTORS = 5; + +const TIME_SLOTS = 16; // TODO: 15 for 960-sample frames + +// frame classes +const FIXFIX = 0; +const FIXVAR = 1; +const VARFIX = 2; +const VARVAR = 3; + +const HIGH = 1; +const LOW = 0; + +//CEIL_LOG[i] = Math.ceil(Math.log(i+1)/Math.log(2)) +const CEIL_LOG2 = new Uint8Array([0, 1, 2, 2, 3, 3]); +const MAX_LTEMP = 6; + +const RATE = 2; + +export default class ChannelData { + constructor() { + this.freqRes = new Int32Array(MAX_ENV_COUNT); + this.invfMode = new Int32Array(MAX_NQ); + this.invfModePrevious = new Int32Array(MAX_NQ); + + this.dfEnv = new Uint8Array(MAX_ENV_COUNT); + this.dfNoise = new Uint8Array(MAX_NOISE_COUNT); + + this.envelopeSFQ = makeArray([MAX_ENV_COUNT, MAX_BANDS], Uint8Array); + this.envelopeSFQPrevious = new Uint8Array(MAX_BANDS); + this.envelopeSF = makeArray([MAX_ENV_COUNT, MAX_BANDS]); + this.te = new Uint8Array(MAX_ENV_COUNT + 1); + this.tePrevious = 0; + + this.noiseFloorDataQ = makeArray([MAX_NOISE_COUNT, MAX_BANDS], Uint8Array); + this.noiseFDPrevious = new Float32Array(MAX_BANDS); + this.noiseFloorData = makeArray([MAX_NOISE_COUNT, MAX_BANDS]); + this.tq = new Uint8Array(MAX_NOISE_COUNT + 1); + + this.sinusoidals = new Uint8Array(MAX_BANDS); + this.sIndexMappedPrevious = new Uint8Array(MAX_BANDS); + + this.bwArray = new Float32Array(MAX_CHIRP_FACTORS); + + this.lTemp = 0; + // TODO: check sizes! + this.gTmp = makeArray([42, 48]); + this.qTmp = makeArray([42, 48]); + + // grid + this.ampRes = 0; + this.frameClass = 0; + this.envCount = 0; + this.envCountPrev = 0; + this.noiseCount = 0; + this.pointer = 0; + this.la = 0; + this.laPrevious = 0; + + this.W = makeArray([2, TIME_SLOTS_RATE, TIME_SLOTS_RATE, 2]); + this.Y = makeArray([2, 38 + MAX_LTEMP, 64, 2]); + this.Ypos = 0; + + this.noiseIndex = 0; + this.sineIndex = 0; + } + + decodeGrid(stream, header, tables) { + // read bitstream and fill envelope borders + let absBordTrail = TIME_SLOTS; + let relLead, relTrail; + + this.ampRes = header.ampRes; + + switch (this.frameClass = stream.read(2)) { + case FIXFIX: + this.envCount = 1 << stream.read(2); + relLead = this.envCount - 1; + if (this.envCount === 1) this.ampRes = false; + + //check requirement (4.6.18.6.3): + else if (this.envCount > 4) { + throw new Error("SBR: too many envelopes: " + this.envCount); + } + + this.freqRes.fill(stream.read(1)); + + this.te[0] = 0; + this.te[this.envCount] = absBordTrail; + absBordTrail = (absBordTrail + (this.envCount >> 1)) / this.envCount; + for (let i = 0; i < relLead; i++) { + this.te[i + 1] = this.te[i] + absBordTrail; + } + + break; + case FIXVAR: + absBordTrail += stream.read(2); + relTrail = stream.read(2); + this.envCount = relTrail + 1; + + this.te[0] = 0; + this.te[this.envCount] = absBordTrail; + for (let i = 0; i < relTrail; i++) { + this.te[this.envCount - 1 - i] = this.te[this.envCount - i] - 2 * stream.read(2) - 2; + } + + this.pointer = stream.read(CEIL_LOG2[this.envCount]); + + for (let i = 0; i < this.envCount; i++) { + this.freqRes[this.envCount - 1 - i] = stream.read(1); + } + + break; + case VARFIX: + this.te[0] = stream.read(2); + relLead = stream.read(2); + this.envCount = relLead + 1; + + this.te[this.envCount] = absBordTrail; + for (let i = 0; i < relLead; i++) { + this.te[i + 1] = this.te[i] + 2 * stream.read(2) + 2; + } + + this.pointer = stream.read(CEIL_LOG2[this.envCount]); + + for (let i = 0; i < this.envCount; i++) { + this.freqRes[i] = stream.read(1); + } + break; + default: //VARVAR + this.te[0] = stream.read(2); + absBordTrail += stream.read(2); + relLead = stream.read(2); + relTrail = stream.read(2); + this.envCount = relLead + relTrail + 1; + if (this.envCount > 5) { + throw new Error("SBR: too many envelopes: " + this.envCount); + } + + this.te[this.envCount] = absBordTrail; + for (let i = 0; i < relLead; i++) { + this.te[i + 1] = this.te[i] + 2 * stream.read(2) + 2; + } + for (let i = 0; i < relTrail; i++) { + this.te[this.envCount - 1 - i] = this.te[this.envCount - i] - 2 * stream.read(2) - 2; + } + + this.pointer = stream.read(CEIL_LOG2[this.envCount]); + + for (let i = 0; i < this.envCount; i++) { + this.freqRes[i] = stream.read(1); + } + break; + } + + // fill noise floor time borders (4.6.18.3.3) + this.noiseCount = this.envCount > 1 ? 2 : 1; + this.tq[0] = this.te[0]; + this.tq[this.noiseCount] = this.te[this.envCount]; + if (this.envCount === 1) { + this.tq[1] = this.te[1]; + } else { + let middleBorder; + switch (this.frameClass) { + case FIXFIX: + middleBorder = this.envCount >> 1; + break; + case VARFIX: + if (this.pointer === 0) middleBorder = 1; + else if (this.pointer === 1) middleBorder = this.envCount - 1; + else middleBorder = this.pointer - 1; + break; + default: + // if (this.pointer > 1) middleBorder = this.envCount + 1 - this.pointer; + // else middleBorder = this.envCount - 1; + middleBorder = this.envCount - Math.max(this.pointer - 1, 1); + break; + } + + this.tq[1] = this.te[middleBorder]; + } + + // calculate La (table 4.157) + if ((this.frameClass === FIXVAR || this.frameClass === VARVAR) && this.pointer > 0) { + this.la = this.envCount + 1 - this.pointer; + } else if (this.frameClass === VARFIX && this.pointer > 1) { + this.la = this.pointer - 1; + } else { + this.la = -1; + } + } + + decodeDTDF(stream) { + for (let i = 0; i < this.envCount; i++) { + this.dfEnv[i] = stream.read(1); + } + + for (let i = 0; i < this.noiseCount; i++) { + this.dfNoise[i] = stream.read(1); + } + } + + decodeInvf(stream, header, tables) { + for (let i = 0; i < tables.nq; i++) { + this.invfMode[i] = stream.read(2); + } + } + + decodeEnvelope(stream, header, tables, secCh, coupling) { + // select huffman codebooks + let tHuff, fHuff; + let tLav, fLav; + let delta, bits; + if (coupling && secCh) { + delta = 1; + if (this.ampRes) { + bits = 5; + tHuff = HuffmanTables.T_HUFFMAN_ENV_BAL_3_0; + tLav = HuffmanTables.T_HUFFMAN_ENV_BAL_3_0_LAV; + fHuff = HuffmanTables.F_HUFFMAN_ENV_BAL_3_0; + fLav = HuffmanTables.F_HUFFMAN_ENV_BAL_3_0_LAV; + } else { + bits = 6; + tHuff = HuffmanTables.T_HUFFMAN_ENV_BAL_1_5; + tLav = HuffmanTables.T_HUFFMAN_ENV_BAL_1_5_LAV; + fHuff = HuffmanTables.F_HUFFMAN_ENV_BAL_1_5; + fLav = HuffmanTables.F_HUFFMAN_ENV_BAL_1_5_LAV; + } + } else { + delta = 0; + if (this.ampRes) { + bits = 6; + tHuff = HuffmanTables.T_HUFFMAN_ENV_3_0; + tLav = HuffmanTables.T_HUFFMAN_ENV_3_0_LAV; + fHuff = HuffmanTables.F_HUFFMAN_ENV_3_0; + fLav = HuffmanTables.F_HUFFMAN_ENV_3_0_LAV; + } else { + bits = 7; + tHuff = HuffmanTables.T_HUFFMAN_ENV_1_5; + tLav = HuffmanTables.T_HUFFMAN_ENV_1_5_LAV; + fHuff = HuffmanTables.F_HUFFMAN_ENV_1_5; + fLav = HuffmanTables.F_HUFFMAN_ENV_1_5_LAV; + } + } + + // read delta coded huffman data + let envBands = tables.n; + let odd = envBands[1] & 1; + + let j, k, frPrev; + let prev; + for (let i = 0; i < this.envCount; i++) { + prev = i === 0 ? this.envelopeSFQPrevious : this.envelopeSFQ[i - 1]; + frPrev = i === 0 ? this.freqResPrevious : this.freqRes[i - 1]; + + if (this.dfEnv[i]) { + if (this.freqRes[i] === frPrev) { + for (j = 0; j < envBands[this.freqRes[i]]; j++) { + this.envelopeSFQ[i][j] = prev[j] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); + if (this.envelopeSFQ[i][j] > 127) { + console.log("OUT OF BOUNDS", this.envelopeSFQ[i][j], i, prev[j], delta, tLav) + } + } + } else if (this.freqRes[i] !== 0) { + for (j = 0; j < envBands[this.freqRes[i]]; j++) { + k = (j + odd) >> 1; //fLow[k] <= fHigh[j] < fLow[k + 1] + this.envelopeSFQ[i][j] = prev[k] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); + if (this.envelopeSFQ[i][j] > 127) { + console.log("OUT OF BOUNDS 2", this.envelopeSFQ[i][j], i, k, prev[k], delta, tLav) + } + + } + } else { + for (j = 0; j < envBands[this.freqRes[i]]; j++) { + k = j !== 0 ? (2 * j - odd) : 0; //fHigh[k] == fLow[j] + this.envelopeSFQ[i][j] = prev[k] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); + if (this.envelopeSFQ[i][j] > 127) { + console.log("OUT OF BOUNDS 3", this.envelopeSFQ[i][j], i, k, prev[k], delta, tLav) + } + } + } + } else { + this.envelopeSFQ[i][0] = stream.read(bits) << delta; + if (this.envelopeSFQ[i][0] > 127) { + console.log("OUT OF BOUNDS 5", this.envelopeSFQ[i][0], delta) + } + + for (j = 1; j < envBands[this.freqRes[i]]; j++) { + this.envelopeSFQ[i][j] = this.envelopeSFQ[i][j - 1] + ((this.decodeHuffman(stream, fHuff) - fLav) << delta); + if (this.envelopeSFQ[i][j] > 127) { + console.log("OUT OF BOUNDS 4", this.envelopeSFQ[i][j], this.envelopeSFQ[i][j - 1], delta, tLav) + } + } + } + } + + // save for next frame + this.envelopeSFQPrevious.set(this.envelopeSFQ[this.envCount - 1]) + } + + decodeHuffman(stream, table) { + let off = 0; + let len = table[off][0]; + let cw = stream.read(len); + let j; + while (cw !== table[off][1]) { + off++; + j = table[off][0] - len; + len = table[off][0]; + cw <<= j; + cw |= stream.read(j); + } + return table[off][2]; + } + + decodeNoise(stream, header, tables, secCh, coupling) { + // select huffman codebooks + let tHuff, fHuff; + let tLav, fLav; + let delta; + if (coupling && secCh) { + delta = 1; + tHuff = HuffmanTables.T_HUFFMAN_NOISE_BAL_3_0; + tLav = HuffmanTables.T_HUFFMAN_NOISE_BAL_3_0_LAV; + fHuff = HuffmanTables.F_HUFFMAN_NOISE_BAL_3_0; + fLav = HuffmanTables.F_HUFFMAN_NOISE_BAL_3_0_LAV; + } else { + delta = 0; + tHuff = HuffmanTables.T_HUFFMAN_NOISE_3_0; + tLav = HuffmanTables.T_HUFFMAN_NOISE_3_0_LAV; + fHuff = HuffmanTables.F_HUFFMAN_NOISE_3_0; + fLav = HuffmanTables.F_HUFFMAN_NOISE_3_0_LAV; + } + + // read huffman data: i=noise, j=band + let noiseBands = tables.nq; + + let j; + let prev; + for (let i = 0; i < this.noiseCount; i++) { + if (this.dfNoise[i]) { + prev = i === 0 ? this.noiseFDPrevious : this.noiseFloorDataQ[i - 1]; + for (j = 0; j < noiseBands; j++) { + this.noiseFloorDataQ[i][j] = prev[j] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); + } + } else { + this.noiseFloorDataQ[i][0] = stream.read(5) << delta; + for (j = 1; j < noiseBands; j++) { + this.noiseFloorDataQ[i][j] = this.noiseFloorDataQ[i][j - 1] + ((this.decodeHuffman(stream, fHuff) - fLav) << delta); + } + } + } + + //save for next frame + this.noiseFDPrevious.set(this.noiseFloorDataQ[this.noiseCount - 1]); + } + + decodeSinusoidal(stream, header, tables) { + if (this.sinusoidalsPresent = stream.read(1)) { + for (let i = 0; i < tables.n[HIGH]; i++) { + this.sinusoidals[i] = stream.read(1); + } + } else { + this.sinusoidals.fill(0); + } + } + + copyGrid(cd) { + this.ampRes = cd.ampRes; + this.frameClass = cd.frameClass; + this.envCount = cd.envCount; + this.noiseCount = cd.noiseCount; + + this.freqRes.set(cd.freqRes); + this.te.set(cd.te); + this.tq.set(cd.tq); + + this.pointer = cd.pointer; + } + + copyInvf(cd) { + this.invfMode.set(cd.invfMode); + } + + savePreviousData() { + //lTemp for next frame + this.lTemp = RATE * this.te[this.envCount] - TIME_SLOTS_RATE; + + //grid + this.envCountPrev = this.envCount; + this.freqResPrevious = this.freqRes[this.freqRes.length - 1]; + this.laPrevious = this.la; + this.tePrevious = this.te[this.envCountPrev]; + + //invf + this.invfModePrevious.set(this.invfMode); + } +} diff --git a/src/sbr/FrequencyTables.js b/src/sbr/FrequencyTables.js new file mode 100644 index 0000000..61ea06b --- /dev/null +++ b/src/sbr/FrequencyTables.js @@ -0,0 +1,340 @@ +var tables = require('../tables'); + +const MAX_PATCHES = 6; +const MAX_BANDS = 64; +const LOG2 = Math.log(2); +const HIGH = 1; +const LOW = 0; + +const MFT_START_MIN = new Uint8Array([7, 7, 10, 11, 12, 16, 16, 17, 24]); +const MFT_STOP_MIN = new Uint8Array([13, 15, 20, 21, 23, 32, 32, 35, 48]); +const MFT_SF_OFFSETS = new Uint8Array([5, 5, 4, 4, 4, 3, 2, 1, 0]); +const MFT_START_OFFSETS = [ + new Int8Array([-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7]), //16000 + new Int8Array([-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13]), //22050 + new Int8Array([-5, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16]), //24000 + new Int8Array([-6, -4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16]), //32000 + new Int8Array([-4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20]), //44100-64000 + new Int8Array([-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24]) //>64000 +]; +const MFT_STOP_OFFSETS = [ + new Uint8Array([2, 4, 6, 8, 11, 14, 18, 22, 26, 31, 37, 44, 51]), + new Uint8Array([2, 4, 6, 8, 11, 14, 18, 22, 26, 31, 36, 42, 49]), + new Uint8Array([2, 4, 6, 9, 11, 14, 17, 21, 25, 29, 34, 39, 44]), + new Uint8Array([2, 4, 6, 9, 11, 14, 17, 21, 24, 28, 33, 38, 43]), + new Uint8Array([2, 4, 6, 9, 11, 14, 17, 20, 24, 28, 32, 36, 41]), + new Uint8Array([2, 4, 6, 8, 10, 12, 14, 17, 20, 23, 26, 29, 32]), + new Uint8Array([2, 4, 6, 8, 10, 12, 14, 17, 20, 23, 26, 29, 32]), + new Uint8Array([2, 3, 5, 7, 9, 11, 13, 16, 18, 21, 23, 26, 29]), + new Uint8Array([1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 15, 16]) +]; +const MFT_INPUT1 = new Uint8Array([12, 10, 8]); +const MFT_INPUT2 = new Float32Array([1.0, 1.3]); +const LIM_BANDS_PER_OCTAVE_POW = new Float32Array([ + 1.32715174233856803909, //2^(0.49/1.2) + 1.18509277094158210129, //2^(0.49/2) + 1.11987160404675912501 //2^(0.49/3) +]); +const GOAL_SB_FACTOR = 2.048E6; + +export default class FrequencyTables { + constructor() { + this.n = new Int32Array(2); + this.fTable = new Array(2); + this.patchSubbands = new Int32Array(MAX_PATCHES); + this.patchStartSubband = new Int32Array(MAX_PATCHES); + this.kx = 32; + this.kxPrev = 0; + this.m = 0; + this.mPrev = 0; + + this.k0 = 0; + this.k2 = 0; + this.nMaster = 0; + this.nq = 0; + this.nl = 0; + this.patchCount = 0; + } + + calculate(header, sampleRate) { + this.calculateMFT(header, sampleRate); + this.calculateFrequencyTables(header); + this.calculateNoiseTable(header); + this.calculatePatches(sampleRate); + this.calculateLimiterTable(header); + } + + calculateMFT(header, sampleRate) { + // lower border k0 + let sfIndex = tables.SAMPLE_INDEXES[sampleRate]; + let sfOff = MFT_SF_OFFSETS[sfIndex]; + this.k0 = MFT_START_MIN[sfIndex] + MFT_START_OFFSETS[sfOff][header.startFrequency]; + + // higher border k2 + let stop = header.stopFrequency; + let x; + if (stop === 15) { + x = 3 * this.k0; + } else if (stop === 14) { + x = 2 * this.k0 + } else { + x = MFT_STOP_MIN[sfIndex] + MFT_STOP_OFFSETS[sfOff][header.stopFrequency - 1]; + } + + this.k2 = Math.min(MAX_BANDS, x); + + if (this.k0 >= this.k2) { + throw new Error("SBR: MFT borders out of range: lower=" + this.k0 + ", higher=" + this.k2); + } + + // check requirement (4.6.18.3.6): + let max; + if (sampleRate === 44100) { + max = 35; + } else if (sampleRate >= 48000) { + max = 32; + } else { + max = 48; + } + + if ((this.k2 - this.k0) > max) { + throw new Error("SBR: too many subbands: "+ (this.k2 - this.k0) + ", maximum number for samplerate " + this.sampleRate + ": " + max); + } + + //MFT calculation + if (header.frequencyScale === 0) { + // TODO + this.calculateMFT1(header, this.k0, this.k2); + } else { + this.calculateMFT2(header, this.k0, this.k2); + } + + //check requirement (4.6.18.3.6): + if (header.xOverBand >= this.nMaster) { + throw new Error("SBR: illegal length of master frequency table: " + this.nMaster + ", xOverBand: " + header.xOverBand); + } + } + + // MFT calculation if frequencyScale>0 + calculateMFT2(header, k0, k2) { + let bands = MFT_INPUT1[header.frequencyScale - 1]; + let warp = MFT_INPUT2[header.alterScale ? 1 : 0]; + + let div1 = k2 / k0; + let twoRegions; + let k1; + if (div1 > 2.2449) { + twoRegions = true; + k1 = 2 * k0; + } else { + twoRegions = false; + k1 = k2; + } + + let div2 = k1 / k0; + let log = Math.log(div2) / (2 * LOG2); + let bandCount0 = 2 * Math.round(bands * log); + + // check requirement (4.6.18.6.3): + if (bandCount0 <= 0) { + throw new Error("SBR: illegal band count for master frequency table: " + bandCount0); + } + + let vDk0 = new Int32Array(bandCount0); + let pow1, pow2; + for (let i = 0; i < bandCount0; i++) { + pow1 = Math.pow(div2, (i + 1) / bandCount0); + pow2 = Math.pow(div2, i / bandCount0); + vDk0[i] = Math.round(k0 * pow1) - Math.round(k0 * pow2); + + // check requirement (4.6.18.6.3): + if (vDk0[i] <= 0) { + throw new AACException("SBR: illegal value in master frequency table: " + vDk0[i]); + } + } + + vDk0.sort(); + + let vk0 = new Int32Array(bandCount0 + 1); + vk0[0] = k0; + for (let i = 1; i <= bandCount0; i++) { + vk0[i] = vk0[i - 1] + vDk0[i - 1]; + } + + if (twoRegions) { + div1 = k2 / k1; + log = Math.log(div1); + let bandCount1 = 2 * Math.round(bands * log / (2 * LOG2 * warp)); + let vDk1 = new Int32Array(bandCount1); + let min = -1; + for (let i = 0; i < bandCount1; i++) { + pow1 = Math.pow(div1, (i + 1) / bandCount1); + pow2 = Math.pow(div1, i / bandCount1); + vDk1[i] = Math.round(k1 * pow1) - Math.round(k1 * pow2); + if (min < 0 || vDk1[i] < min) { + min = vDk1[i]; + } + } + + if (min < vDk0[vDk0.length - 1]) { + vDk1.sort(); + let change = vDk0[vDk0.length - 1] - vDk1[0]; + let x = vDk1[bandCount1 - 1] - vDk1[0] / 2.0; + if (change > x) change = x; + vDk1[0] += change; + vDk1[bandCount1 - 1] -= change; + } + + vDk1.sort(); + let vk1 = new Int32Array(bandCount1 + 1); + vk1[0] = k1; + for (let i = 1; i <= bandCount1; i++) { + vk1[i] = vk1[i - 1] + vDk1[i - 1]; + } + + this.nMaster = bandCount0 + bandCount1; + this.mft = new Int32Array(this.nMaster + 1); + this.mft.set(vk0, 0); + this.mft.set(vk1.subarray(1), bandCount0 + 1); + } else { + this.nMaster = bandCount0; + this.mft = vk0; + } + } + + calculateFrequencyTables(header) { + let xover = header.xOverBand; + this.n[HIGH] = this.nMaster - xover; + this.n[LOW] = (this.n[HIGH] + 1) >> 1; + this.fTable[HIGH] = new Int32Array(this.n[HIGH] + 1); + this.fTable[HIGH].set(this.mft, xover); + + this.kxPrev = this.kx; + this.kx = this.fTable[HIGH][0]; + this.mPrev = this.m; + this.m = this.fTable[HIGH][this.n[HIGH]] - this.kx; + + // check requirements (4.6.18.3.6): + if (this.kx > 32) throw new Error("SBR: start frequency border out of range: " + this.kx); + if ((this.kx + this.m) > 64) throw new Error("SBR: stop frequency border out of range: " + (this.kx + this.m)); + + this.fTable[LOW] = new Int32Array(this.n[LOW] + 1); + this.fTable[LOW][0] = this.fTable[HIGH][0]; + let div = this.n[HIGH] & 1; + for (let i = 1; i <= this.n[LOW]; i++) { + this.fTable[LOW][i] = this.fTable[HIGH][2 * i - div]; + } + } + + calculateNoiseTable(header) { + let log = Math.log(this.k2 / this.kx) / LOG2; + let x = Math.round(header.noiseBands * log); + this.nq = Math.max(1, x); + + // check requirement (4.6.18.6.3): + if (this.nq > 5) throw new Error("SBR: too many noise floor scalefactors: " + this.nq); + + this.fNoise = new Int32Array(this.nq + 1); + this.fNoise[0] = this.fTable[LOW][0]; + let i = 0; + for (let k = 1; k <= this.nq; k++) { + i += ((this.n[LOW] - i) / (this.nq + 1 - k)) | 0; + this.fNoise[k] = this.fTable[LOW][i]; + } + } + + calculatePatches(sampleRate) { + // patch construction (flowchart 4.46, p231) + let msb = this.k0; + let usb = this.kx; + this.patchCount = 0; + + let goalSb = Math.round(GOAL_SB_FACTOR / sampleRate); // TODO: replace with table + let k; + if (goalSb < this.kx + this.m) { + for (k = 0; this.mft[k] < goalSb; k++); + } else { + k = this.nMaster; + } + + let sb, j, odd; + do { + j = k + 1; + do { + j--; + sb = this.mft[j]; + odd = (sb - 2 + this.k0) & 1; + } while(sb > (this.k0 - 1 + msb - odd)); + + this.patchSubbands[this.patchCount] = Math.max(sb - usb, 0); + this.patchStartSubband[this.patchCount] = this.k0 - odd - this.patchSubbands[this.patchCount]; + + if (this.patchSubbands[this.patchCount] > 0) { + usb = sb; + msb = sb; + this.patchCount++; + } else { + msb = this.kx; + } + + if (this.mft[k] - sb < 3) { + k = this.nMaster; + } + } while (sb !== (this.kx + this.m)); + + if (this.patchSubbands[this.patchCount - 1] < 3 && this.patchCount > 1) { + this.patchCount--; + } + + // check requirement (4.6.18.6.3): + if (this.patchCount > 5) { + throw new AACException("SBR: too many patches: " + this.patchCount); + } + } + + calculateLimiterTable(header) { + // calculation of fTableLim (figure 4.40, p.213) + let bands = header.limiterBands; + if (bands == 0) { + this.fLim = new Int32Array([this.fTable[LOW][0], this.fTable[LOW][this.n[LOW]]]); + this.nl = 1; + this.patchBorders = new Int32Array(0); + } else { + let limBandsPerOctaveWarped = LIM_BANDS_PER_OCTAVE_POW[bands - 1]; + + this.patchBorders = new Int32Array(this.patchCount + 1); + this.patchBorders[0] = this.kx; + for (let i = 1; i <= this.patchCount; i++) { + this.patchBorders[i] = this.patchBorders[i - 1] + this.patchSubbands[i - 1]; + } + + let limTable = new Int32Array(this.n[LOW] + this.patchCount); + limTable.set(this.fTable[LOW].subarray(0, this.n[LOW] + 1)); + if (this.patchCount > 1) { + limTable.set(this.patchBorders.subarray(1, this.patchCount), this.n[LOW] + 1); + } + + limTable.sort(); + + let inp = 1; + let out = 0; + let lims = this.n[LOW] + this.patchCount - 1; + while (out < lims) { + if (limTable[inp] >= limTable[out] * limBandsPerOctaveWarped) { + limTable[++out] = limTable[inp++]; + } else if (limTable[inp] === limTable[out] || !this.patchBorders.includes(limTable[inp])) { + inp++; + lims--; + } else if (!this.patchBorders.includes(limTable[out])) { + limTable[out] = limTable[inp++]; + lims--; + } else { + limTable[++out] = limTable[inp++]; + } + } + + this.fLim = limTable.subarray(0, lims + 1); + this.nl = lims; + } + } +} diff --git a/src/sbr/HFAdjuster.js b/src/sbr/HFAdjuster.js new file mode 100644 index 0000000..d58ce2e --- /dev/null +++ b/src/sbr/HFAdjuster.js @@ -0,0 +1,898 @@ +import {HIGH, RATE, T_HF_ADJ} from './constants'; +import {makeArray} from './utils'; + +const LIMITER_GAINS = [0.70795, 1.0, 1.41254, 10000000000]; +const EPSILON = 1.0; +const EPSILON_0 = 1E-12; +const MAX_BOOST = 1.584893192; +const SMOOTHING_FACTORS = [ + 0.33333333333333, + 0.30150283239582, + 0.21816949906249, + 0.11516383427084, + 0.03183050093751 +]; +const PHI = [ + [1, 0, -1, 0], + [0, 1, 0, -1] +]; +const MAX_GAIN = 100000; + +// class Parameter { +// //helper class containing arrays calculated by and passed to different methods +// float[][] eMapped, qMapped; +// boolean[][] sIndexMapped, sMapped; +// float[][] Qm, Sm, Glim; +// } + +export default function process(header, tables, cd, Xhigh, Y) { + let p = map(tables, cd); + let eCurr = estimateEnvelopes(header, tables, cd, Xhigh); + calculateGain(header, tables, cd, p, eCurr); + assembleSignals(header, tables, cd, p, Xhigh, Y); +} + +// mapping of dequantized values (4.6.18.7.2) +function map(tables, cd) { + // parameter from FrequencyTables + let kx = tables.kx; + let noiseTable = tables.fNoise; + let fHigh = tables.fTable[HIGH]; + let nHigh = tables.n[HIGH]; + let M = tables.m; + let nq = tables.nq; + + // parameter from ChannelData + let le = cd.envCount; + let lq = cd.noiseCount; + let freqRes = cd.freqRes; + let la = cd.la; + + //input and output arrays + let eOrig = cd.envelopeSF; + let eMapped = makeArray([7, 48]); + let qOrig = cd.noiseFloorData; + let qMapped = makeArray([7, 48]); + let sinusoidals = cd.sinusoidals; + let sIndexMappedPrev = cd.sIndexMappedPrevious; + let sIndexMapped = makeArray([7, 48], Uint8Array); + let sMapped = makeArray([7, 48], Uint8Array); + + // tmp integer + let fr, maxI, k, i, m; + let table; + + for (let e = 0; e < le; e++) { + // envelopes: eOrig -> eMapped + fr = freqRes[e]; + maxI = tables.n[fr]; + table = tables.fTable[fr]; + + for (i = 0; i < maxI; i++) { + for (m = table[i]; m < table[i + 1]; m++) { + eMapped[e][m - kx] = eOrig[e][i]; + } + } + + // noise: qOrig -> qMapped + k = ((lq > 1) && (cd.te[e] >= cd.tq[1])) ? 1 : 0; + for (i = 0; i < nq; i++) { + for (m = noiseTable[i]; m < noiseTable[i + 1]; m++) { + qMapped[e][m - kx] = qOrig[k][i]; + } + } + + // sinusoidals: cd.sinusoidals -> sIndexMapped + for (i = 0; i < nHigh; i++) { + if (cd.sinusoidalsPresent) { + m = (fHigh[i] + fHigh[i + 1]) >> 1; + sIndexMapped[e][m - kx] = sinusoidals[i] && (e >= la || sIndexMappedPrev[m - kx]) ? 1 : 0; + } + } + + // sinusoidals: sIndexMapped -> sMapped + let found; + for (i = 0; i < maxI; i++) { + found = 0; + for (m = table[i]; m < table[i + 1]; m++) { + if (sIndexMapped[e][m - kx]) { + found = 1; + break; + } + } + + for (m = table[i]; m < table[i + 1]; m++) { + sMapped[e][m - kx] = found; + } + } + } + + // fill with 0, because next frame may be larger than this one + cd.sIndexMappedPrevious.fill(0); + cd.sIndexMappedPrevious.set(sIndexMapped[le - 1]); + + return {eMapped, qMapped, sIndexMapped, sMapped}; +} + +// envelope estimation (4.6.18.7.3) +function estimateEnvelopes(header, tables, cd, Xhigh) { + let te = cd.te; + let M = tables.m; + let kx = tables.kx; + let le = cd.envCount; + + let eCurr = makeArray([7, 48]); + + let sum; + let e, m, i, iLow, iHigh; + if (header.interpolFrequency) { + let div; + + for (e = 0; e < le; e++) { + div = 0.5 / (te[e + 1] - te[e]); + iLow = RATE * te[e] + T_HF_ADJ; + iHigh = RATE * te[e + 1] + T_HF_ADJ; + + for (m = 0; m < M; m++) { + sum = 0.0; + + //energy = sum over squares of absolute value + for (i = iLow; i < iHigh; i++) { + sum += Xhigh[m + kx][i][0] * Xhigh[m + kx][i][0] + Xhigh[m + kx][i][1] * Xhigh[m + kx][i][1]; + } + + eCurr[e][m] = sum * div; + } + } + } else { + let n = tables.n; + let freqRes = cd.freqRes; + + let k; + let table; + let div1, div2; + + for (e = 0; e < le; e++) { + div1 = RATE * (te[e + 1] - te[e]); + iLow = RATE * te[e] + T_HF_ADJ; + iHigh = RATE * te[e + 1] + T_HF_ADJ; + table = tables.fTable[freqRes[e + 1]]; + + for (m = 0; m < n[freqRes[e + 1]]; m++) { + sum = 0.0; + div2 = div1 * (table[m + 1] - table[m]); + + for (k = table[m]; k < table[m + 1]; k++) { + for (i = iLow; i < iHigh; i++) { + sum += Xhigh[k][i][0] * Xhigh[k][i][0] + Xhigh[k][i][1] * Xhigh[k][i][1]; + } + } + + sum /= div2; + + for (k = table[m]; k < table[m + 1]; k++) { + eCurr[e][k - kx] = sum; + } + } + } + } + + return eCurr; +} + +//calculation of levels of additional HF signal components (4.6.18.7.4) and gain calculation (4.6.18.7.5) +function calculateGain(header, tables, cd, p, eCurr) { + let limGain = header.limiterGains; + let M = tables.m; + let nl = tables.nl; + let fLim = tables.fLim; + let kx = tables.kx; + + let la = cd.la; + let laPrevious = cd.laPrevious === cd.envCountPrev ? 0 : -1; + let le = cd.envCount; + + // output arrays + let Qm = makeArray([7, 48]); + let Sm = makeArray([7, 48]); + let gain = makeArray([7, 48]); + + let delta, delta2; + let m, k, i; + let km = new Int32Array(M); + let eMappedSum = new Float32Array(nl); + let tmp; + let gTemp = makeArray([le, nl]); + let gMax; + + // TODO: optimize this loops + for (let e = 0; e < le; e++) { + delta = !((e == la) || (e == laPrevious)) ? 1 : 0; + + for (k = 0; k < nl; k++) { + let sum0, sum1; + + // level of additional HF components + gain + for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { + tmp = p.eMapped[e][m] / (1.0 + p.qMapped[e][m]); + Qm[e][m] = Math.sqrt(tmp * p.qMapped[e][m]); + Sm[e][m] = Math.sqrt(tmp * p.sIndexMapped[e][m]); + + if (p.sMapped[e][m] === 0) { + gain[e][m] = Math.sqrt(p.eMapped[e][m] / ((1.0 + eCurr[e][m]) * (1.0 + p.qMapped[e][m] * delta))); + } else { + gain[e][m] = Math.sqrt(p.eMapped[e][m] * p.qMapped[e][m] / ((1.0 + eCurr[e][m]) * (1.0 + p.qMapped[e][m]))); + } + } + + sum0 = sum1 = 0.0; + for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { + sum0 += p.eMapped[e][m]; + sum1 += eCurr[e][m]; + } + + gMax = LIMITER_GAINS[limGain] * Math.sqrt((EPSILON_0 + sum0) / (EPSILON_0 + sum1)); + gMax = Math.min(MAX_GAIN, gMax); + // console.log(gMax, limGain, LIMITER_GAINS[limGain], EPSILON_0, sum0, sum1) + + for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { + let qmMax = Qm[e][m] * gMax / gain[e][m]; + Qm[e][m] = Math.min(Qm[e][m], qmMax); + gain[e][m] = Math.min(gain[e][m], gMax); + } + + sum0 = sum1 = 0.0; + for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { + sum0 += p.eMapped[e][m]; + sum1 += eCurr[e][m] * gain[e][m] * gain[e][m] + + Sm[e][m] * Sm[e][m] + + ((delta && !Sm[e][m]) ? 1 : 0) * Qm[e][m] * Qm[e][m]; + } + + let gainBoost = Math.sqrt((EPSILON_0 + sum0) / (EPSILON_0 + sum1)); + gainBoost = Math.min(MAX_BOOST, gainBoost); + for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { + gain[e][m] *= gainBoost; + Qm[e][m] *= gainBoost; + Sm[e][m] *= gainBoost; + // if (isNaN(gain[e][m])) { + // console.log(gainBoost, sum0, sum1) + // } + } + } + } + + p.Qm = Qm; + p.Sm = Sm; + p.Glim = gain; +} + +function checkNaN(arr) { + for (let i = 0; i < arr.length; i++) { + if (isNaN(arr[i])) { + console.log('NaN', i); + break; + } + } +} + +// assembling HF signals (4.6.18.7.5) +function assembleSignals(header, tables, cd, p, Xhigh, Y) { + let reset = header.reset; + let hSL = header.smoothingMode ? 0 : 4; + let M = tables.m + let le = cd.envCount; + let lePrev = cd.envCountPrev; + let te = cd.te; + let la = cd.la; + let laPrev = cd.laPrevious === cd.envCountPrev ? 0 : -1; + let kx = tables.kx; + let noiseIndex = reset ? 0 : cd.noiseIndex; + let sineIndex = cd.sineIndex; + + let gTmp = cd.gTmp; + let qTmp = cd.qTmp; + + let e, i, m, j; + + // save previous values + if (reset) { + for (i = 0; i < hSL; i++) { + gTmp[i + 2 * te[0]].set(p.Glim[0].subarray(0, M)); + qTmp[i + 2 * te[0]].set(p.Qm[0].subarray(0, M)); + } + } else if (hSL !== 0) { + for (i = 0; i < 4; i++) { + gTmp[i + 2 * te[0]].set(gTmp[i + 2 * cd.tePrevious]); + qTmp[i + 2 * te[0]].set(qTmp[i + 2 * cd.tePrevious]); + } + } + + for (e = 0; e < le; e++) { + for (i = 2 * te[e]; i < 2 * te[e + 1]; i++) { + gTmp[hSL + i].set(p.Glim[e].subarray(0, M)); + qTmp[hSL + i].set(p.Qm[e].subarray(0, M)); + } + } + + // calculate new + let gFilt, qFilt; + + for (e = 0; e < le; e++) { + for (i = RATE * te[e]; i < RATE * te[e + 1]; i++) { + if (hSL !== 0 && e !== la && e != laPrev) { + for (m = 0; m < M; m++) { + let idx1 = i + hSL; + gFilt = 0.0; + for (j = 0; j <= hSL; j++) { + gFilt += gTmp[idx1 - j][m] * SMOOTHING_FACTORS[j]; + } + Y[i][m + kx][0] = Xhigh[m + kx][i + T_HF_ADJ][0] * gFilt; + Y[i][m + kx][1] = Xhigh[m + kx][i + T_HF_ADJ][1] * gFilt; + } + } else { + for (m = 0; m < M; m++) { + gFilt = gTmp[i + hSL][m]; + Y[i][m + kx][0] = Xhigh[m + kx][i + T_HF_ADJ][0] * gFilt; + Y[i][m + kx][1] = Xhigh[m + kx][i + T_HF_ADJ][1] * gFilt; + } + } + + if (e !== la && e !== laPrev) { + let phiSign = (1 - 2 * (kx & 1)); + + for (m = 0; m < M; m++) { + if (p.Sm[e][m] !== 0) { + Y[i][m + kx][0] += p.Sm[e][m] * PHI[0][sineIndex]; + Y[i][m + kx][1] += p.Sm[e][m] * (PHI[1][sineIndex] * phiSign); + } else { + if (hSL !== 0) { + let idx1 = i + hSL; + qFilt = 0.0; + for (j = 0; j <= hSL; j++) { + qFilt += qTmp[idx1 - j][m] * SMOOTHING_FACTORS[j]; + } + } else { + qFilt = qTmp[i][m]; + } + Y[i][m + kx][0] += qFilt * NOISE_TABLE[noiseIndex][0]; + Y[i][m + kx][1] += qFilt * NOISE_TABLE[noiseIndex][1]; + } + phiSign = -phiSign; + } + } else { + let phiSign = (1 - 2 * (kx & 1)); + for (m = 0; m < M; m++) { + Y[i][m + kx][0] += p.Sm[e][m] * PHI[0][sineIndex]; + Y[i][m + kx][1] += p.Sm[e][m] * (PHI[1][sineIndex] * phiSign); + phiSign = -phiSign; + + if (isNaN(Y[i][m + kx][0]) || isNaN(Y[i][m + kx][1])) { + console.log(p.Sm[e][m], PHI[0][sineIndex]); + } + } + } + + noiseIndex = (noiseIndex + 1) & 0x1ff; + sineIndex = (sineIndex + 1) & 3; + } + } + + cd.noiseIndex = noiseIndex; + cd.sineIndex = sineIndex; +} + +const NOISE_TABLE = [ + [-0.99948155879974, -0.59483414888382], + [0.97113454341888, -0.67528516054153], + [0.14130051434040, -0.95090985298157], + [-0.47005495429039, -0.37340548634529], + [0.80705064535141, 0.29653668403625], + [-0.38981479406357, 0.89572608470917], + [-0.01053049881011, -0.66959059238434], + [-0.91266369819641, -0.11522938311100], + [0.54840421676636, 0.75221365690231], + [0.40009254217148, -0.98929399251938], + [-0.99867975711823, -0.88147068023682], + [-0.95531076192856, 0.90908759832382], + [-0.45725932717323, -0.56716322898865], + [-0.72929674386978, -0.98008275032043], + [0.75622802972794, 0.20950329303741], + [0.07069442421198, -0.78247898817062], + [0.74496251344681, -0.91169005632401], + [-0.96440184116364, -0.94739919900894], + [0.30424630641937, -0.49438267946243], + [0.66565030813217, 0.64652937650681], + [0.91697007417679, 0.17514097690582], + [-0.70774918794632, 0.52548652887344], + [-0.70051413774490, -0.45340028405190], + [-0.99496513605118, -0.90071910619736], + [0.98164492845535, -0.77463155984879], + [-0.54671579599380, -0.02570928446949], + [-0.01689629070461, 0.00287506449968], + [-0.86110347509384, 0.42548584938049], + [-0.98892980813980, -0.87881129980087], + [0.51756626367569, 0.66926783323288], + [-0.99635028839111, -0.58107727766037], + [-0.99969369173050, 0.98369991779327], + [0.55266261100769, 0.59449058771133], + [0.34581178426743, 0.94879418611526], + [0.62664210796356, -0.74402970075607], + [-0.77149701118469, -0.33883658051491], + [-0.91592246294022, 0.03687901422381], + [-0.76285493373871, -0.91371870040894], + [0.79788339138031, -0.93180972337723], + [0.54473078250885, -0.11919206380844], + [-0.85639280080795, 0.42429855465889], + [-0.92882400751114, 0.27871808409691], + [-0.11708371341228, -0.99800843000412], + [0.21356749534607, -0.90716296434402], + [-0.76191693544388, 0.99768120050430], + [0.98111045360565, -0.95854461193085], + [-0.85913270711899, 0.95766568183899], + [-0.93307244777679, 0.49431759119034], + [0.30485755205154, -0.70540034770966], + [0.85289651155472, 0.46766132116318], + [0.91328084468842, -0.99839597940445], + [-0.05890199914575, 0.70741826295853], + [0.28398686647415, 0.34633556008339], + [0.95258164405823, -0.54893416166306], + [-0.78566324710846, -0.75568538904190], + [-0.95789498090744, -0.20423194766045], + [0.82411158084869, 0.96654617786407], + [-0.65185445547104, -0.88734990358353], + [-0.93643605709076, 0.99870789051056], + [0.91427159309387, -0.98290503025055], + [-0.70395684242249, 0.58796799182892], + [0.00563771976158, 0.61768198013306], + [0.89065051078796, 0.52783352136612], + [-0.68683707714081, 0.80806946754456], + [0.72165340185165, -0.69259858131409], + [-0.62928247451782, 0.13627037405968], + [0.29938435554504, -0.46051329374313], + [-0.91781955957413, -0.74012714624405], + [0.99298715591431, 0.40816611051559], + [0.82368296384811, -0.74036049842834], + [-0.98512834310532, -0.99972331523895], + [-0.95915371179581, -0.99237799644470], + [-0.21411126852036, -0.93424820899963], + [-0.68821477890015, -0.26892307400703], + [0.91851997375488, 0.09358228743076], + [-0.96062767505646, 0.36099094152451], + [0.51646184921265, -0.71373331546783], + [0.61130720376968, 0.46950140595436], + [0.47336128354073, -0.27333179116249], + [0.90998309850693, 0.96715664863586], + [0.44844800233841, 0.99211573600769], + [0.66614890098572, 0.96590173244476], + [0.74922239780426, -0.89879858493805], + [-0.99571585655212, 0.52785521745682], + [0.97401082515717, -0.16855870187283], + [0.72683745622635, -0.48060774803162], + [0.95432192087173, 0.68849605321884], + [-0.72962206602097, -0.76608443260193], + [-0.85359477996826, 0.88738125562668], + [-0.81412428617477, -0.97480767965317], + [-0.87930774688721, 0.74748307466507], + [-0.71573328971863, -0.98570609092712], + [0.83524298667908, 0.83702534437180], + [-0.48086065053940, -0.98848503828049], + [0.97139126062393, 0.80093622207642], + [0.51992827653885, 0.80247628688812], + [-0.00848591234535, -0.76670128107071], + [-0.70294374227524, 0.55359911918640], + [-0.95894426107407, -0.43265503644943], + [0.97079253196716, 0.09325857460499], + [-0.92404294013977, 0.85507702827454], + [-0.69506472349167, 0.98633414506912], + [0.26559203863144, 0.73314309120178], + [0.28038442134857, 0.14537914097309], + [-0.74138122797012, 0.99310338497162], + [-0.01752796024084, -0.82616633176804], + [-0.55126774311066, -0.98898541927338], + [0.97960901260376, -0.94021445512772], + [-0.99196308851242, 0.67019015550613], + [-0.67684930562973, 0.12631492316723], + [0.09140039235353, -0.20537731051445], + [-0.71658962965012, -0.97788202762604], + [0.81014639139175, 0.53722649812698], + [0.40616992115974, -0.26469007134438], + [-0.67680186033249, 0.94502049684525], + [0.86849772930145, -0.18333598971367], + [-0.99500381946564, -0.02634122036397], + [0.84329187870026, 0.10406957566738], + [-0.09215968847275, 0.69540011882782], + [0.99956172704697, -0.12358541786671], + [-0.79732781648636, -0.91582524776459], + [0.96349972486496, 0.96640455722809], + [-0.79942780733109, 0.64323902130127], + [-0.11566039919853, 0.28587844967842], + [-0.39922955632210, 0.94129604101181], + [0.99089199304581, -0.92062628269196], + [0.28631284832954, -0.91035044193268], + [-0.83302724361420, -0.67330408096313], + [0.95404446125031, 0.49162766337395], + [-0.06449863314629, 0.03250560909510], + [-0.99575054645538, 0.42389783263206], + [-0.65501141548157, 0.82546114921570], + [-0.81254440546036, -0.51627236604691], + [-0.99646371603012, 0.84490531682968], + [0.00287840608507, 0.64768260717392], + [0.70176988840103, -0.20453028380871], + [0.96361881494522, 0.40706968307495], + [-0.68883758783340, 0.91338956356049], + [-0.34875586628914, 0.71472293138504], + [0.91980081796646, 0.66507452726364], + [-0.99009048938751, 0.85868018865585], + [0.68865793943405, 0.55660319328308], + [-0.99484401941299, -0.20052559673786], + [0.94214510917664, -0.99696427583694], + [-0.67414629459381, 0.49548220634460], + [-0.47339352965355, -0.85904330015182], + [0.14323651790619, -0.94145596027374], + [-0.29268294572830, 0.05759225040674], + [0.43793860077858, -0.78904968500137], + [-0.36345127224922, 0.64874434471130], + [-0.08750604838133, 0.97686946392059], + [-0.96495270729065, -0.53960305452347], + [0.55526942014694, 0.78891521692276], + [0.73538213968277, 0.96452075242996], + [-0.30889773368835, -0.80664390325546], + [0.03574995696545, -0.97325617074966], + [0.98720687627792, 0.48409134149551], + [-0.81689298152924, -0.90827703475952], + [0.67866861820221, 0.81284505128860], + [-0.15808570384979, 0.85279554128647], + [0.80723392963409, -0.24717418849468], + [0.47788757085800, -0.46333149075508], + [0.96367555856705, 0.38486748933792], + [-0.99143874645233, -0.24945276975632], + [0.83081877231598, -0.94780850410461], + [-0.58753192424774, 0.01290772389621], + [0.95538109540939, -0.85557049512863], + [-0.96490919589996, -0.64020973443985], + [-0.97327101230621, 0.12378127872944], + [0.91400367021561, 0.57972472906113], + [-0.99925839900970, 0.71084845066071], + [-0.86875903606415, -0.20291699469090], + [-0.26240035891533, -0.68264555931091], + [-0.24664412438869, -0.87642270326614], + [0.02416275814176, 0.27192914485931], + [0.82068622112274, -0.85087788105011], + [0.88547372817993, -0.89636802673340], + [-0.18173077702522, -0.26152145862579], + [0.09355476498604, 0.54845124483109], + [-0.54668414592743, 0.95980775356293], + [0.37050989270210, -0.59910142421722], + [-0.70373594760895, 0.91227668523788], + [-0.34600785374641, -0.99441426992416], + [-0.68774479627609, -0.30238837003708], + [-0.26843291521072, 0.83115667104721], + [0.49072334170341, -0.45359709858894], + [0.38975992798805, 0.95515358448029], + [-0.97757124900818, 0.05305894464254], + [-0.17325553297997, -0.92770671844482], + [0.99948036670685, 0.58285546302795], + [-0.64946246147156, 0.68645507097244], + [-0.12016920745373, -0.57147324085236], + [-0.58947455883026, -0.34847131371498], + [-0.41815140843391, 0.16276422142982], + [0.99885648488998, 0.11136095225811], + [-0.56649613380432, -0.90494865179062], + [0.94138020277023, 0.35281917452812], + [-0.75725078582764, 0.53650552034378], + [0.20541973412037, -0.94435143470764], + [0.99980372190475, 0.79835915565491], + [0.29078277945518, 0.35393777489662], + [-0.62858772277832, 0.38765692710876], + [0.43440905213356, -0.98546332120895], + [-0.98298585414886, 0.21021524071693], + [0.19513028860092, -0.94239830970764], + [-0.95476663112640, 0.98364555835724], + [0.93379634618759, -0.70881992578506], + [-0.85235410928726, -0.08342348039150], + [-0.86425095796585, -0.45795026421547], + [0.38879778981209, 0.97274428606033], + [0.92045122385025, -0.62433654069901], + [0.89162534475327, 0.54950958490372], + [-0.36834338307381, 0.96458297967911], + [0.93891763687134, -0.89968353509903], + [0.99267655611038, -0.03757034242153], + [-0.94063472747803, 0.41332337260246], + [0.99740225076675, -0.16830494999886], + [-0.35899412631989, -0.46633225679398], + [0.05237237364054, -0.25640362501144], + [0.36703583598137, -0.38653266429901], + [0.91653180122375, -0.30587628483772], + [0.69000804424286, 0.90952169895172], + [-0.38658750057220, 0.99501574039459], + [-0.29250815510750, 0.37444993853569], + [-0.60182201862335, 0.86779648065567], + [-0.97418588399887, 0.96468526124954], + [0.88461571931839, 0.57508403062820], + [0.05198933184147, 0.21269661188126], + [-0.53499621152878, 0.97241556644440], + [-0.49429559707642, 0.98183864355087], + [-0.98935145139694, -0.40249159932137], + [-0.98081380128860, -0.72856897115707], + [-0.27338150143623, 0.99950921535492], + [0.06310802698135, -0.54539585113525], + [-0.20461677014828, -0.14209978282452], + [0.66223841905594, 0.72528582811356], + [-0.84764343500137, 0.02372316829860], + [-0.89039862155914, 0.88866579532623], + [0.95903307199478, 0.76744925975800], + [0.73504126071930, -0.03747203201056], + [-0.31744435429573, -0.36834111809731], + [-0.34110826253891, 0.40211221575737], + [0.47803884744644, -0.39423218369484], + [0.98299193382263, 0.01989791356027], + [-0.30963072180748, -0.18076720833778], + [0.99992591142654, -0.26281872391701], + [-0.93149733543396, -0.98313164710999], + [0.99923473596573, -0.80142992734909], + [-0.26024168729782, -0.75999760627747], + [-0.35712513327599, 0.19298963248730], + [-0.99899083375931, 0.74645155668259], + [0.86557173728943, 0.55593866109848], + [0.33408042788506, 0.86185956001282], + [0.99010735750198, 0.04602397605777], + [-0.66694271564484, -0.91643613576889], + [0.64016789197922, 0.15649530291557], + [0.99570536613464, 0.45844584703445], + [-0.63431465625763, 0.21079117059708], + [-0.07706847041845, -0.89581435918808], + [0.98590087890625, 0.88241720199585], + [0.80099332332611, -0.36851897835732], + [0.78368133306503, 0.45506998896599], + [0.08707806468010, 0.80938994884491], + [-0.86811882257462, 0.39347308874130], + [-0.39466530084610, -0.66809433698654], + [0.97875326871872, -0.72467839717865], + [-0.95038563013077, 0.89563220739365], + [0.17005239427090, 0.54683053493500], + [-0.76910793781281, -0.96226614713669], + [0.99743282794952, 0.42697158455849], + [0.95437383651733, 0.97002321481705], + [0.99578905105591, -0.54106825590134], + [0.28058260679245, -0.85361421108246], + [0.85256522893906, -0.64567607641220], + [-0.50608539581299, -0.65846014022827], + [-0.97210735082626, -0.23095212876797], + [0.95424050092697, -0.99240148067474], + [-0.96926569938660, 0.73775655031204], + [0.30872163176537, 0.41514959931374], + [-0.24523839354515, 0.63206630945206], + [-0.33813264966011, -0.38661777973175], + [-0.05826828256249, -0.06940773874521], + [-0.22898460924625, 0.97054851055145], + [-0.18509915471077, 0.47565764188766], + [-0.10488238185644, -0.87769949436188], + [-0.71886587142944, 0.78030979633331], + [0.99793875217438, 0.90041309595108], + [0.57563304901123, -0.91034334897995], + [0.28909647464752, 0.96307784318924], + [0.42188999056816, 0.48148649930954], + [0.93335050344467, -0.43537023663521], + [-0.97087377309799, 0.86636447906494], + [0.36722871661186, 0.65291655063629], + [-0.81093025207520, 0.08778370171785], + [-0.26240602135658, -0.92774093151093], + [0.83996498584747, 0.55839848518372], + [-0.99909615516663, -0.96024608612061], + [0.74649465084076, 0.12144893407822], + [-0.74774593114853, -0.26898062229156], + [0.95781666040421, -0.79047924280167], + [0.95472306013107, -0.08588775992393], + [0.48708331584930, 0.99999040365219], + [0.46332037448883, 0.10964126139879], + [-0.76497006416321, 0.89210927486420], + [0.57397389411926, 0.35289704799652], + [0.75374317169189, 0.96705216169357], + [-0.59174400568008, -0.89405369758606], + [0.75087904930115, -0.29612672328949], + [-0.98607856035233, 0.25034910440445], + [-0.40761056542397, -0.90045571327209], + [0.66929268836975, 0.98629492521286], + [-0.97463697195053, -0.00190223299433], + [0.90145510435104, 0.99781388044357], + [-0.87259286642075, 0.99233585596085], + [-0.91529458761215, -0.15698707103729], + [-0.03305738791823, -0.37205263972282], + [0.07223051041365, -0.88805001974106], + [0.99498009681702, 0.97094357013702], + [-0.74904936552048, 0.99985486268997], + [0.04585228487849, 0.99812334775925], + [-0.89054954051971, -0.31791913509369], + [-0.83782142400742, 0.97637635469437], + [0.33454805612564, -0.86231517791748], + [-0.99707579612732, 0.93237990140915], + [-0.22827528417110, 0.18874759972095], + [0.67248046398163, -0.03646211326122], + [-0.05146538093686, -0.92599701881409], + [0.99947297573090, 0.93625229597092], + [0.66951125860214, 0.98905825614929], + [-0.99602955579758, -0.44654715061188], + [0.82104903459549, 0.99540740251541], + [0.99186509847641, 0.72022998332977], + [-0.65284591913223, 0.52186721563339], + [0.93885445594788, -0.74895310401917], + [0.96735250949860, 0.90891814231873], + [-0.22225968539715, 0.57124030590057], + [-0.44132784008980, -0.92688840627670], + [-0.85694974660873, 0.88844531774521], + [0.91783040761948, -0.46356892585754], + [0.72556972503662, -0.99899554252625], + [-0.99711579084396, 0.58211559057236], + [0.77638977766037, 0.94321835041046], + [0.07717324048281, 0.58638399839401], + [-0.56049829721451, 0.82522302865982], + [0.98398894071579, 0.39467439055443], + [0.47546947002411, 0.68613046407700], + [0.65675091743469, 0.18331636488438], + [0.03273375332355, -0.74933111667633], + [-0.38684144616127, 0.51337349414825], + [-0.97346270084381, -0.96549361944199], + [-0.53282153606415, -0.91423267126083], + [0.99817311763763, 0.61133575439453], + [-0.50254499912262, -0.88829338550568], + [0.01995873264968, 0.85223513841629], + [0.99930381774902, 0.94578897953033], + [0.82907766103745, -0.06323442608118], + [-0.58660709857941, 0.96840775012970], + [-0.17573736608028, -0.48166921734810], + [0.83434289693832, -0.13023450970650], + [0.05946491286159, 0.20511047542095], + [0.81505483388901, -0.94685947895050], + [-0.44976380467415, 0.40894573926926], + [-0.89746475219727, 0.99846577644348], + [0.39677256345749, -0.74854665994644], + [-0.07588948309422, 0.74096214771271], + [0.76343196630478, 0.41746628284454], + [-0.74490106105804, 0.94725912809372], + [0.64880120754242, 0.41336661577225], + [0.62319535017014, -0.93098312616348], + [0.42215818166733, -0.07712787389755], + [0.02704554051161, -0.05417517945170], + [0.80001771450043, 0.91542196273804], + [-0.79351830482483, -0.36208897829056], + [0.63872361183167, 0.08128252625465], + [0.52890521287918, 0.60048872232437], + [0.74238550662994, 0.04491915181279], + [0.99096131324768, -0.19451183080673], + [-0.80412328243256, -0.88513815402985], + [-0.64612615108490, 0.72198677062988], + [0.11657770723104, -0.83662831783295], + [-0.95053184032440, -0.96939903497696], + [-0.62228870391846, 0.82767260074615], + [0.03004475869238, -0.99738895893097], + [-0.97987216711044, 0.36526128649712], + [-0.99986982345581, -0.36021611094475], + [0.89110648632050, -0.97894251346588], + [0.10407960414886, 0.77357792854309], + [0.95964735746384, -0.35435819625854], + [0.50843232870102, 0.96107691526413], + [0.17006334662437, -0.76854026317596], + [0.25872674584389, 0.99893301725388], + [-0.01115998718888, 0.98496019840240], + [-0.79598701000214, 0.97138410806656], + [-0.99264711141586, -0.99542820453644], + [-0.99829661846161, 0.01877138763666], + [-0.70801013708115, 0.33680686354637], + [-0.70467054843903, 0.93272775411606], + [0.99846023321152, -0.98725748062134], + [-0.63364970684052, -0.16473594307899], + [-0.16258217394352, -0.95939123630524], + [-0.43645593523979, -0.94805032014847], + [-0.99848473072052, 0.96245169639587], + [-0.16796459257603, -0.98987513780594], + [-0.87979227304459, -0.71725726127625], + [0.44183099269867, -0.93568974733353], + [0.93310177326202, -0.99913311004639], + [-0.93941932916641, -0.56409376859665], + [-0.88590002059937, 0.47624599933624], + [0.99971461296082, -0.83889955282211], + [-0.75376385450363, 0.00814643409103], + [0.93887686729431, -0.11284527927637], + [0.85126435756683, 0.52349251508713], + [0.39701420068741, 0.81779634952545], + [-0.37024465203285, -0.87071657180786], + [-0.36024826765060, 0.34655734896660], + [-0.93388813734055, -0.84476542472839], + [-0.65298801660538, -0.18439576029778], + [0.11960318684578, 0.99899345636368], + [0.94292563199997, 0.83163905143738], + [0.75081145763397, -0.35533222556114], + [0.56721979379654, -0.24076835811138], + [0.46857765316963, -0.30140233039856], + [0.97312313318253, -0.99548190832138], + [-0.38299977779388, 0.98516911268234], + [0.41025799512863, 0.02116736955941], + [0.09638062119484, 0.04411984235048], + [-0.85283249616623, 0.91475564241409], + [0.88866806030273, -0.99735265970230], + [-0.48202428221703, -0.96805608272552], + [0.27572581171989, 0.58634752035141], + [-0.65889132022858, 0.58835631608963], + [0.98838084936142, 0.99994349479675], + [-0.20651349425316, 0.54593044519424], + [-0.62126415967941, -0.59893679618835], + [0.20320105552673, -0.86879181861877], + [-0.97790551185608, 0.96290808916092], + [0.11112534999847, 0.21484763920307], + [-0.41368338465691, 0.28216838836670], + [0.24133038520813, 0.51294362545013], + [-0.66393411159515, -0.08249679952860], + [-0.53697830438614, -0.97649902105331], + [-0.97224736213684, 0.22081333398819], + [0.87392479181290, -0.12796173989773], + [0.19050361216068, 0.01602615416050], + [-0.46353441476822, -0.95249038934708], + [-0.07064096629620, -0.94479805231094], + [-0.92444086074829, -0.10457590222359], + [-0.83822596073151, -0.01695043221116], + [0.75214684009552, -0.99955683946609], + [-0.42102998495102, 0.99720942974091], + [-0.72094786167145, -0.35008960962296], + [0.78843313455582, 0.52851396799088], + [0.97394025325775, -0.26695942878723], + [0.99206465482712, -0.57010120153427], + [0.76789611577988, -0.76519358158112], + [-0.82002419233322, -0.73530179262161], + [0.81924992799759, 0.99698424339294], + [-0.26719850301743, 0.68903368711472], + [-0.43311259150505, 0.85321813821793], + [0.99194979667664, 0.91876250505447], + [-0.80691999197006, -0.32627540826797], + [0.43080005049706, -0.21919095516205], + [0.67709493637085, -0.95478075742722], + [0.56151771545410, -0.70693808794022], + [0.10831862688065, -0.08628837019205], + [0.91229414939880, -0.65987348556519], + [-0.48972892761230, 0.56289243698120], + [-0.89033657312393, -0.71656566858292], + [0.65269446372986, 0.65916007757187], + [0.67439478635788, -0.81684380769730], + [-0.47770830988884, -0.16789555549622], + [-0.99715977907181, -0.93565785884857], + [-0.90889590978622, 0.62034398317337], + [-0.06618622690439, -0.23812216520309], + [0.99430269002914, 0.18812555074692], + [0.97686403989792, -0.28664535284042], + [0.94813650846481, -0.97506642341614], + [-0.95434498786926, -0.79607981443405], + [-0.49104782938957, 0.32895213365555], + [0.99881172180176, 0.88993984460831], + [0.50449168682098, -0.85995072126389], + [0.47162890434265, -0.18680204451084], + [-0.62081581354141, 0.75000673532486], + [-0.43867015838623, 0.99998068809509], + [0.98630565404892, -0.53578901290894], + [-0.61510360240936, -0.89515018463135], + [-0.03841517493129, -0.69888818264008], + [-0.30102157592773, -0.07667808979750], + [0.41881284117699, 0.02188098989427], + [-0.86135452985764, 0.98947483301163], + [0.67226862907410, -0.13494388759136], + [-0.70737397670746, -0.76547348499298], + [0.94044947624207, 0.09026201069355], + [-0.82386350631714, 0.08924768865108], + [-0.32070666551590, 0.50143420696259], + [0.57593160867691, -0.98966425657272], + [-0.36326017975807, 0.07440242916346], + [0.99979043006897, -0.14130286872387], + [-0.92366021871567, -0.97979295253754], + [-0.44607177376747, -0.54233253002167], + [0.44226801395416, 0.71326756477356], + [0.03671907261014, 0.63606387376785], + [0.52175426483154, -0.85396826267242], + [-0.94701141119003, -0.01826348155737], + [-0.98759609460831, 0.82288712263107], + [0.87434792518616, 0.89399492740631], + [-0.93412041664124, 0.41374051570892], + [0.96063941717148, 0.93116706609726], + [0.97534251213074, 0.86150932312012], + [0.99642467498779, 0.70190042257309], + [-0.94705086946487, -0.29580041766167], + [0.91599804162979, -0.98147833347321] +]; diff --git a/src/sbr/HFGenerator.js b/src/sbr/HFGenerator.js new file mode 100644 index 0000000..5812482 --- /dev/null +++ b/src/sbr/HFGenerator.js @@ -0,0 +1,200 @@ +import {makeArray} from './utils'; +import {RATE, T_HF_ADJ} from './constants'; + +const RELAX_COEF = 1.000001; +const ALPHA_MAX = 16; +const CHIRP_COEFS = [[0.75, 0.25], [0.90625, 0.09375]]; +//values for bw [invfModePrev][invfMode] +const BW_COEFS = [ + [0.0, 0.6, 0.9, 0.98], + [0.6, 0.75, 0.9, 0.98], + [0.0, 0.75, 0.9, 0.98], + [0.0, 0.75, 0.9, 0.98] +]; +const CHIRP_MIN = 0.015625; + +// in: 32x40 complex Xlow, out: 32x40 complex Xhigh +export default function process(tables, cd, Xlow, Xhigh) { + // calculate chirp factors + let bwArray = calculateChirpFactors(tables, cd); + + // calculate inverse filter coefficients for bands 0-k0 + let k0 = tables.k0; + let alpha0 = makeArray([k0, 2]); + let alpha1 = makeArray([k0, 2]); + calculateIFCoefs(tables, alpha0, alpha1, Xlow); + + // HF generation + let patchCount = tables.patchCount; + let patchSubbands = tables.patchSubbands; + let patchStartSubband = tables.patchStartSubband; + let kx = tables.kx; + let m = tables.m; + let Nq = tables.nq; + let fNoise = tables.fNoise; + + let te = cd.te; + let start = RATE * te[0]; + let end = RATE * te[cd.envCount]; + + let alpha = new Float32Array(4); + let square; + let l, x; // loop indices + let k = kx; + let g = 0; + + for (let j = 0; j < patchCount; j++) { + for (x = 0; x < patchSubbands[j]; x++, k++) { + let p = patchStartSubband[j] + x; + while (g <= Nq && k >= fNoise[g]) { + g++; + } + g--; + + if (g < 0) { + throw new Error("SBR: HFGenerator: no subband found for frequency " + k); + } + + // fill Xhigh[k] (4.6.18.6.3) + square = bwArray[g] * bwArray[g]; + alpha[0] = alpha1[p][0] * square; + alpha[1] = alpha1[p][1] * square; + alpha[2] = alpha0[p][0] * bwArray[g]; + alpha[3] = alpha0[p][1] * bwArray[g]; + for (l = start; l < end; l++) { + let off = l + T_HF_ADJ; + Xhigh[k][off][0] = alpha[0] * Xlow[p][off - 2][0] + - alpha[1] * Xlow[p][off - 2][1] + + alpha[2] * Xlow[p][off - 1][0] + - alpha[3] * Xlow[p][off - 1][1] + + Xlow[p][off][0]; + + Xhigh[k][off][1] = alpha[0] * Xlow[p][off - 2][1] + + alpha[1] * Xlow[p][off - 2][0] + + alpha[2] * Xlow[p][off - 1][1] + + alpha[3] * Xlow[p][off - 1][0] + + Xlow[p][off][1]; + } + } + } + + // fill remaining with zero + while (k < m + kx) { + for (let j = 0; j < Xhigh[k].length; j++) { + Xhigh[k][j][0] = 0; + Xhigh[k][j][1] = 0; + } + k++; + } +} + +function calculateChirpFactors(tables, cd) { + //calculates chirp factors and replaces old ones in ChannelData + let nq = tables.nq; + let invfMode = cd.invfMode; + let invfModePrevious = cd.invfModePrevious; + let bwArray = cd.bwArray; + + let tmp; + let chirpCoefs; + for (let i = 0; i < nq; i++) { + tmp = BW_COEFS[invfModePrevious[i]][invfMode[i]]; + chirpCoefs = tmp < bwArray[i] ? CHIRP_COEFS[0] : CHIRP_COEFS[1]; + bwArray[i] = (chirpCoefs[0] * tmp) + (chirpCoefs[1] * bwArray[i]); + if (bwArray[i] < CHIRP_MIN) { + bwArray[i] = 0; + } + } + + return bwArray; +} + +// calculates inverse filter coefficients for bands 0-k0 (4.6.18.6.2) +function calculateIFCoefs(tables, alpha0, alpha1, Xlow) { + let k0 = tables.k0; + let tmp = new Float32Array(2); + + let phi = makeArray([3, 2, 2]); + let d; + for (let k = 0; k < k0; k++) { + //get covariance matrix + getCovarianceMatrix(Xlow[k], phi, 0); + // getCovarianceMatrix(Xlow[k], phi, 1); + // getCovarianceMatrix(Xlow[k], phi, 2); + + // d(k) + d = phi[2][1][0] * phi[1][0][0] - (phi[1][1][0] * phi[1][1][0] + phi[1][1][1] * phi[1][1][1]) / RELAX_COEF; + + // alpha1 + if (d === 0) { + alpha1[k][0] = 0; + alpha1[k][1] = 0; + } else { + tmp[0] = phi[0][0][0] * phi[1][1][0] - phi[0][0][1] * phi[1][1][1] - phi[0][1][0] * phi[1][0][0]; + tmp[1] = phi[0][0][0] * phi[1][1][1] + phi[0][0][1] * phi[1][1][0] - phi[0][1][1] * phi[1][0][0]; + alpha1[k][0] = tmp[0] / d; + alpha1[k][1] = tmp[1] / d; + } + + // alpha0 + if(phi[1][0][0] === 0) { + alpha0[k][0] = 0; + alpha0[k][1] = 0; + } else { + tmp[0] = phi[0][0][0] + alpha1[k][0] * phi[1][1][0] + alpha1[k][1] * phi[1][1][1]; + tmp[1] = phi[0][0][1] + alpha1[k][1] * phi[1][1][0] - alpha1[k][0] * phi[1][1][1]; + alpha0[k][0] = -tmp[0] / phi[1][0][0]; + alpha0[k][1] = -tmp[1] / phi[1][0][0]; + } + + if (alpha1[k][0] * alpha1[k][0] + alpha1[k][1] * alpha1[k][1] >= ALPHA_MAX + || alpha0[k][0] * alpha0[k][0] + alpha0[k][1] * alpha0[k][1] >= ALPHA_MAX) { + alpha1[k][0] = 0; + alpha1[k][1] = 0; + alpha0[k][0] = 0; + alpha0[k][1] = 0; + } + } +} + +// calculates covariance matrix (4.6.18.6.2) +function getCovarianceMatrix(x, phi, off) { + // let sum = new Float32Array(2); + // if (off === 0) { + // for (let i = 1; i < 38; i++) { + // sum[0] += x[i][0] * x[i][0] + x[i][1] * x[i][1]; + // } + // phi[2][1][0] = sum[0] + x[0][0] * x[0][0] + x[0][1] * x[0][1]; + // phi[1][0][0] = sum[0] + x[38][0] * x[38][0] + x[38][1] * x[38][1]; + // } else { + // for (let i = 1; i < 38; i++) { + // sum[0] += x[i][0] * x[i + off][0] + x[i][1] * x[i + off][1]; + // sum[1] += x[i][0] * x[i + off][1] - x[i][1] * x[i + off][0]; + // } + // phi[2 - off][1][0] = sum[0] + x[0][0] * x[off][0] + x[0][1] * x[off][1]; + // phi[2 - off][1][1] = sum[1] + x[0][0] * x[off][1] - x[0][1] * x[off][0]; + // if (off === 1) { + // phi[0][0][0] = sum[0] + x[38][0] * x[39][0] + x[38][1] * x[39][1]; + // phi[0][0][1] = sum[1] + x[38][0] * x[39][1] - x[38][1] * x[39][0]; + // } + // } + + let real_sum2 = x[0][0] * x[2][0] + x[0][1] * x[2][1]; + let imag_sum2 = x[0][0] * x[2][1] - x[0][1] * x[2][0]; + let real_sum1 = 0.0, imag_sum1 = 0.0, real_sum0 = 0.0; + for (let i = 1; i < 38; i++) { + real_sum0 += x[i][0] * x[i ][0] + x[i][1] * x[i ][1]; + real_sum1 += x[i][0] * x[i + 1][0] + x[i][1] * x[i + 1][1]; + imag_sum1 += x[i][0] * x[i + 1][1] - x[i][1] * x[i + 1][0]; + real_sum2 += x[i][0] * x[i + 2][0] + x[i][1] * x[i + 2][1]; + imag_sum2 += x[i][0] * x[i + 2][1] - x[i][1] * x[i + 2][0]; + } + phi[2 - 2][1][0] = real_sum2; + phi[2 - 2][1][1] = imag_sum2; + phi[2 ][1][0] = real_sum0 + x[ 0][0] * x[ 0][0] + x[ 0][1] * x[ 0][1]; + phi[1 ][0][0] = real_sum0 + x[38][0] * x[38][0] + x[38][1] * x[38][1]; + phi[2 - 1][1][0] = real_sum1 + x[ 0][0] * x[ 1][0] + x[ 0][1] * x[ 1][1]; + phi[2 - 1][1][1] = imag_sum1 + x[ 0][0] * x[ 1][1] - x[ 0][1] * x[ 1][0]; + phi[0 ][0][0] = real_sum1 + x[38][0] * x[39][0] + x[38][1] * x[39][1]; + phi[0 ][0][1] = imag_sum1 + x[38][0] * x[39][1] - x[38][1] * x[39][0]; +} diff --git a/src/sbr/HuffmanTables.js b/src/sbr/HuffmanTables.js new file mode 100644 index 0000000..249ffbe --- /dev/null +++ b/src/sbr/HuffmanTables.js @@ -0,0 +1,651 @@ +// largest absolute values +export const T_HUFFMAN_ENV_1_5_LAV = 60; +export const F_HUFFMAN_ENV_1_5_LAV = 60; +export const T_HUFFMAN_ENV_BAL_1_5_LAV = 24; +export const F_HUFFMAN_ENV_BAL_1_5_LAV = 24; +export const T_HUFFMAN_ENV_3_0_LAV = 31; +export const F_HUFFMAN_ENV_3_0_LAV = 31; +export const T_HUFFMAN_ENV_BAL_3_0_LAV = 12; +export const F_HUFFMAN_ENV_BAL_3_0_LAV = 12; +export const T_HUFFMAN_NOISE_3_0_LAV = 31; +export const F_HUFFMAN_NOISE_3_0_LAV = F_HUFFMAN_ENV_3_0_LAV; +export const T_HUFFMAN_NOISE_BAL_3_0_LAV = 12; +export const F_HUFFMAN_NOISE_BAL_3_0_LAV = F_HUFFMAN_ENV_BAL_3_0_LAV; + +//codebooks: [bit length, codeword, values...] +export const T_HUFFMAN_ENV_1_5 = [ + [2, 0, 60], + [2, 1, 59], + [3, 4, 61], + [3, 5, 58], + [4, 12, 62], + [4, 13, 57], + [5, 28, 63], + [5, 29, 56], + [6, 60, 64], + [6, 61, 55], + [7, 124, 65], + [7, 125, 54], + [8, 252, 66], + [8, 253, 53], + [9, 508, 67], + [9, 509, 52], + [10, 1020, 51], + [10, 1021, 68], + [11, 2044, 50], + [12, 4090, 69], + [12, 4091, 49], + [13, 8184, 70], + [13, 8185, 48], + [13, 8186, 47], + [14, 16374, 71], + [14, 16375, 46], + [14, 16376, 72], + [14, 16377, 45], + [15, 32756, 44], + [15, 32757, 73], + [16, 65516, 41], + [16, 65517, 42], + [16, 65518, 43], + [16, 65519, 74], + [16, 65520, 36], + [16, 65521, 40], + [16, 65522, 76], + [17, 131046, 34], + [17, 131047, 39], + [17, 131048, 75], + [17, 131049, 37], + [18, 262100, 35], + [18, 262101, 38], + [18, 262102, 0], + [18, 262103, 1], + [18, 262104, 2], + [18, 262105, 3], + [18, 262106, 4], + [18, 262107, 5], + [19, 524216, 6], + [19, 524217, 7], + [19, 524218, 8], + [19, 524219, 9], + [19, 524220, 10], + [19, 524221, 11], + [19, 524222, 12], + [19, 524223, 13], + [19, 524224, 14], + [19, 524225, 15], + [19, 524226, 16], + [19, 524227, 17], + [19, 524228, 18], + [19, 524229, 19], + [19, 524230, 20], + [19, 524231, 21], + [19, 524232, 22], + [19, 524233, 23], + [19, 524234, 24], + [19, 524235, 25], + [19, 524236, 26], + [19, 524237, 27], + [19, 524238, 28], + [19, 524239, 29], + [19, 524240, 30], + [19, 524241, 31], + [19, 524242, 32], + [19, 524243, 33], + [19, 524244, 77], + [19, 524245, 78], + [19, 524246, 79], + [19, 524247, 80], + [19, 524248, 81], + [19, 524249, 82], + [19, 524250, 83], + [19, 524251, 84], + [19, 524252, 85], + [19, 524253, 86], + [19, 524254, 87], + [19, 524255, 88], + [19, 524256, 89], + [19, 524257, 90], + [19, 524258, 91], + [19, 524259, 92], + [19, 524260, 93], + [19, 524261, 94], + [19, 524262, 95], + [19, 524263, 96], + [19, 524264, 97], + [19, 524265, 98], + [19, 524266, 99], + [19, 524267, 100], + [19, 524268, 101], + [19, 524269, 102], + [19, 524270, 103], + [19, 524271, 104], + [19, 524272, 105], + [19, 524273, 106], + [19, 524274, 107], + [19, 524275, 108], + [19, 524276, 109], + [19, 524277, 110], + [19, 524278, 111], + [19, 524279, 112], + [19, 524280, 113], + [19, 524281, 114], + [19, 524282, 115], + [19, 524283, 116], + [19, 524284, 117], + [19, 524285, 118], + [19, 524286, 119], + [19, 524287, 120] +]; + +export const F_HUFFMAN_ENV_1_5 = [ + [2, 0, 60], + [2, 1, 59], + [3, 4, 61], + [3, 5, 58], + [4, 12, 57], + [4, 13, 62], + [5, 28, 56], + [5, 29, 63], + [6, 60, 55], + [6, 61, 64], + [7, 124, 54], + [8, 250, 65], + [8, 251, 53], + [8, 252, 66], + [9, 506, 52], + [9, 507, 67], + [9, 508, 51], + [10, 1018, 68], + [10, 1019, 50], + [11, 2040, 69], + [11, 2041, 49], + [11, 2042, 70], + [11, 2043, 71], + [12, 4088, 48], + [12, 4089, 72], + [12, 4090, 47], + [12, 4091, 73], + [13, 8184, 74], + [13, 8185, 46], + [13, 8186, 45], + [13, 8187, 75], + [14, 16376, 76], + [14, 16377, 77], + [14, 16378, 44], + [15, 32758, 43], + [15, 32759, 42], + [16, 65520, 41], + [16, 65521, 78], + [16, 65522, 79], + [16, 65523, 40], + [16, 65524, 39], + [17, 131050, 80], + [17, 131051, 81], + [17, 131052, 36], + [17, 131053, 37], + [17, 131054, 38], + [17, 131055, 34], + [18, 262112, 32], + [18, 262113, 82], + [18, 262114, 83], + [18, 262115, 85], + [18, 262116, 19], + [18, 262117, 35], + [18, 262118, 86], + [18, 262119, 87], + [18, 262120, 30], + [18, 262121, 33], + [18, 262122, 84], + [18, 262123, 88], + [18, 262124, 104], + [19, 524250, 9], + [19, 524251, 14], + [19, 524252, 16], + [19, 524253, 17], + [19, 524254, 23], + [19, 524255, 27], + [19, 524256, 29], + [19, 524257, 31], + [19, 524258, 90], + [19, 524259, 97], + [19, 524260, 102], + [19, 524261, 107], + [19, 524262, 108], + [19, 524263, 0], + [19, 524264, 1], + [20, 1048530, 2], + [20, 1048531, 3], + [20, 1048532, 4], + [20, 1048533, 5], + [20, 1048534, 6], + [20, 1048535, 7], + [20, 1048536, 8], + [20, 1048537, 10], + [20, 1048538, 11], + [20, 1048539, 12], + [20, 1048540, 13], + [20, 1048541, 15], + [20, 1048542, 18], + [20, 1048543, 20], + [20, 1048544, 21], + [20, 1048545, 22], + [20, 1048546, 24], + [20, 1048547, 25], + [20, 1048548, 26], + [20, 1048549, 28], + [20, 1048550, 89], + [20, 1048551, 91], + [20, 1048552, 92], + [20, 1048553, 93], + [20, 1048554, 94], + [20, 1048555, 95], + [20, 1048556, 96], + [20, 1048557, 98], + [20, 1048558, 99], + [20, 1048559, 100], + [20, 1048560, 101], + [20, 1048561, 103], + [20, 1048562, 105], + [20, 1048563, 106], + [20, 1048564, 109], + [20, 1048565, 110], + [20, 1048566, 111], + [20, 1048567, 112], + [20, 1048568, 113], + [20, 1048569, 114], + [20, 1048570, 115], + [20, 1048571, 116], + [20, 1048572, 117], + [20, 1048573, 118], + [20, 1048574, 119], + [20, 1048575, 120] +]; + +export const T_HUFFMAN_ENV_BAL_1_5 = [ + [1, 0, 24], + [2, 2, 25], + [3, 6, 23], + [4, 14, 26], + [5, 30, 22], + [6, 62, 27], + [7, 126, 21], + [8, 254, 28], + [9, 510, 20], + [11, 2044, 19], + [11, 2045, 29], + [12, 4092, 18], + [12, 4093, 30], + [15, 32752, 31], + [16, 65506, 17], + [16, 65507, 32], + [16, 65508, 0], + [16, 65509, 1], + [16, 65510, 2], + [16, 65511, 3], + [16, 65512, 4], + [16, 65513, 5], + [16, 65514, 6], + [16, 65515, 7], + [16, 65516, 8], + [16, 65517, 9], + [16, 65518, 10], + [16, 65519, 11], + [16, 65520, 12], + [16, 65521, 13], + [16, 65522, 14], + [16, 65523, 15], + [16, 65524, 16], + [16, 65525, 33], + [16, 65526, 34], + [16, 65527, 35], + [16, 65528, 36], + [16, 65529, 37], + [16, 65530, 38], + [17, 131062, 39], + [17, 131063, 40], + [17, 131064, 41], + [17, 131065, 42], + [17, 131066, 43], + [17, 131067, 44], + [17, 131068, 45], + [17, 131069, 46], + [17, 131070, 47], + [17, 131071, 48] +]; + +export const F_HUFFMAN_ENV_BAL_1_5 = [ + [1, 0, 24], + [2, 2, 23], + [3, 6, 25], + [4, 14, 22], + [5, 30, 26], + [6, 62, 27], + [7, 126, 21], + [8, 254, 20], + [9, 510, 28], + [11, 2044, 19], + [11, 2045, 29], + [11, 2046, 18], + [12, 4094, 30], + [14, 16380, 17], + [15, 32762, 31], + [16, 65526, 32], + [16, 65527, 15], + [17, 131056, 16], + [18, 262114, 0], + [18, 262115, 1], + [18, 262116, 2], + [18, 262117, 3], + [18, 262118, 4], + [18, 262119, 5], + [18, 262120, 6], + [18, 262121, 7], + [18, 262122, 8], + [18, 262123, 9], + [18, 262124, 10], + [18, 262125, 11], + [18, 262126, 12], + [18, 262127, 13], + [18, 262128, 14], + [18, 262129, 33], + [18, 262130, 34], + [18, 262131, 35], + [18, 262132, 36], + [18, 262133, 37], + [18, 262134, 38], + [18, 262135, 39], + [18, 262136, 40], + [18, 262137, 41], + [18, 262138, 42], + [18, 262139, 43], + [18, 262140, 44], + [18, 262141, 45], + [18, 262142, 46], + [19, 524286, 47], + [19, 524287, 48] +]; + +export const T_HUFFMAN_ENV_3_0 = [ + [1, 0, 31], + [2, 2, 30], + [3, 6, 32], + [4, 14, 29], + [5, 30, 33], + [6, 62, 28], + [7, 126, 34], + [8, 254, 27], + [9, 510, 35], + [11, 2044, 26], + [11, 2045, 36], + [12, 4092, 25], + [13, 8186, 24], + [13, 8187, 37], + [14, 16376, 23], + [14, 16377, 38], + [14, 16378, 22], + [14, 16379, 21], + [14, 16380, 39], + [15, 32762, 40], + [16, 65526, 41], + [16, 65527, 18], + [16, 65528, 20], + [16, 65529, 19], + [17, 131060, 17], + [17, 131061, 42], + [18, 262124, 43], + [18, 262125, 0], + [18, 262126, 1], + [19, 524254, 2], + [19, 524255, 3], + [19, 524256, 4], + [19, 524257, 5], + [19, 524258, 6], + [19, 524259, 7], + [19, 524260, 8], + [19, 524261, 9], + [19, 524262, 10], + [19, 524263, 11], + [19, 524264, 12], + [19, 524265, 13], + [19, 524266, 14], + [19, 524267, 15], + [19, 524268, 16], + [19, 524269, 44], + [19, 524270, 45], + [19, 524271, 46], + [19, 524272, 47], + [19, 524273, 48], + [19, 524274, 49], + [19, 524275, 50], + [19, 524276, 51], + [19, 524277, 52], + [19, 524278, 53], + [19, 524279, 54], + [19, 524280, 55], + [19, 524281, 56], + [19, 524282, 57], + [19, 524283, 58], + [19, 524284, 59], + [19, 524285, 60], + [19, 524286, 61], + [19, 524287, 62] +]; + +export const F_HUFFMAN_ENV_3_0 = [ + [1, 0, 31], + [2, 2, 30], + [3, 6, 32], + [4, 14, 29], + [5, 30, 33], + [6, 62, 28], + [8, 252, 34], + [8, 253, 27], + [9, 508, 35], + [9, 509, 26], + [10, 1020, 36], + [10, 1021, 25], + [11, 2044, 37], + [11, 2045, 24], + [12, 4092, 38], + [12, 4093, 23], + [13, 8188, 39], + [14, 16378, 40], + [14, 16379, 22], + [15, 32760, 21], + [15, 32761, 41], + [15, 32762, 42], + [16, 65526, 20], + [16, 65527, 19], + [16, 65528, 43], + [16, 65529, 44], + [17, 131060, 18], + [17, 131061, 16], + [17, 131062, 45], + [17, 131063, 46], + [18, 262128, 17], + [18, 262129, 49], + [18, 262130, 13], + [18, 262131, 7], + [18, 262132, 12], + [18, 262133, 47], + [18, 262134, 48], + [19, 524270, 9], + [19, 524271, 10], + [19, 524272, 15], + [19, 524273, 51], + [19, 524274, 52], + [19, 524275, 53], + [19, 524276, 56], + [19, 524277, 8], + [19, 524278, 11], + [19, 524279, 55], + [20, 1048560, 0], + [20, 1048561, 1], + [20, 1048562, 2], + [20, 1048563, 3], + [20, 1048564, 4], + [20, 1048565, 5], + [20, 1048566, 6], + [20, 1048567, 14], + [20, 1048568, 50], + [20, 1048569, 54], + [20, 1048570, 57], + [20, 1048571, 58], + [20, 1048572, 59], + [20, 1048573, 60], + [20, 1048574, 61], + [20, 1048575, 62] +]; + +export const T_HUFFMAN_ENV_BAL_3_0 = [ + [1, 0, 12], + [2, 2, 13], + [3, 6, 11], + [4, 14, 10], + [5, 30, 14], + [6, 62, 15], + [7, 126, 9], + [8, 254, 8], + [9, 510, 16], + [12, 4088, 7], + [13, 8178, 0], + [13, 8179, 1], + [13, 8180, 2], + [13, 8181, 3], + [13, 8182, 4], + [13, 8183, 5], + [13, 8184, 6], + [13, 8185, 17], + [13, 8186, 18], + [13, 8187, 19], + [13, 8188, 20], + [13, 8189, 21], + [13, 8190, 22], + [14, 16382, 23], + [14, 16383, 24] +]; + +export const F_HUFFMAN_ENV_BAL_3_0 = [ + [1, 0, 12], + [2, 2, 11], + [3, 6, 13], + [4, 14, 10], + [5, 30, 14], + [6, 62, 15], + [7, 126, 9], + [8, 254, 8], + [9, 510, 16], + [11, 2044, 7], + [12, 4090, 17], + [13, 8182, 18], + [13, 8183, 0], + [13, 8184, 1], + [13, 8185, 2], + [13, 8186, 3], + [13, 8187, 4], + [14, 16376, 5], + [14, 16377, 6], + [14, 16378, 19], + [14, 16379, 20], + [14, 16380, 21], + [14, 16381, 22], + [14, 16382, 23], + [14, 16383, 24] +]; + +export const T_HUFFMAN_NOISE_3_0 = [ + [1, 0, 31], + [2, 2, 32], + [3, 6, 30], + [4, 14, 29], + [5, 30, 33], + [6, 62, 28], + [8, 252, 34], + [8, 253, 27], + [10, 1016, 35], + [11, 2034, 26], + [13, 8140, 36], + [13, 8141, 42], + [13, 8142, 0], + [13, 8143, 1], + [13, 8144, 2], + [13, 8145, 3], + [13, 8146, 4], + [13, 8147, 5], + [13, 8148, 6], + [13, 8149, 7], + [13, 8150, 8], + [13, 8151, 9], + [13, 8152, 10], + [13, 8153, 11], + [13, 8154, 12], + [13, 8155, 13], + [13, 8156, 14], + [13, 8157, 15], + [13, 8158, 16], + [13, 8159, 17], + [13, 8160, 18], + [13, 8161, 19], + [13, 8162, 20], + [13, 8163, 21], + [13, 8164, 22], + [13, 8165, 23], + [13, 8166, 24], + [13, 8167, 25], + [13, 8168, 37], + [13, 8169, 38], + [13, 8170, 39], + [13, 8171, 40], + [13, 8172, 41], + [13, 8173, 43], + [13, 8174, 44], + [13, 8175, 45], + [13, 8176, 46], + [13, 8177, 47], + [13, 8178, 48], + [13, 8179, 49], + [13, 8180, 50], + [13, 8181, 51], + [13, 8182, 52], + [13, 8183, 53], + [13, 8184, 54], + [13, 8185, 55], + [13, 8186, 56], + [13, 8187, 57], + [13, 8188, 58], + [13, 8189, 59], + [13, 8190, 60], + [14, 16382, 61], + [14, 16383, 62] +]; + +export const T_HUFFMAN_NOISE_BAL_3_0 = [ + [1, 0, 12], + [2, 2, 11], + [3, 6, 13], + [5, 28, 10], + [6, 58, 14], + [8, 236, 0], + [8, 237, 1], + [8, 238, 2], + [8, 239, 3], + [8, 240, 4], + [8, 241, 5], + [8, 242, 6], + [8, 243, 7], + [8, 244, 8], + [8, 245, 9], + [8, 246, 15], + [8, 247, 16], + [8, 248, 17], + [8, 249, 18], + [8, 250, 19], + [8, 251, 20], + [8, 252, 21], + [8, 253, 22], + [8, 254, 23], + [8, 255, 24] +]; + +export const F_HUFFMAN_NOISE_3_0 = F_HUFFMAN_ENV_3_0; +export const F_HUFFMAN_NOISE_BAL_3_0 = F_HUFFMAN_ENV_BAL_3_0; diff --git a/src/sbr/SynthesisFilterbank.js b/src/sbr/SynthesisFilterbank.js new file mode 100644 index 0000000..02a6a69 --- /dev/null +++ b/src/sbr/SynthesisFilterbank.js @@ -0,0 +1,69 @@ +import {makeArray} from './utils'; +import {TIME_SLOTS_RATE, WINDOW} from './constants'; + +export default class SynthesisFilterbank { + constructor() { + this.V = makeArray([2, 1280]); // for both channels + this.g = new Float32Array(640); // tmp buffer + this.w = new Float32Array(640); + + //complex coefficients: + this.COEFS = makeArray([128, 64, 2]); + let fac = 1.0 / 64.0; + let tmp; + for (let n = 0; n < 128; n++) { + for(let k = 0; k < 64; k++) { + tmp = Math.PI / 128 * (k + 0.5) * (2 * n - 255); + this.COEFS[n][k][0] = fac * Math.cos(tmp); + this.COEFS[n][k][1] = fac * Math.sin(tmp); + } + } + } + + // in: 64 x 32 complex, out: 2048 time samples + process(inp, out, ch) { + let v = this.V[ch]; + let n, k, outOff = 0; + + // each loop creates 64 output samples + for (let l = 0; l < TIME_SLOTS_RATE; l++) { + // 1. shift buffer + for (n = 1279; n >= 128; n--) { + v[n] = v[n - 128]; + } + + // 2. multiple input by matrix and save in buffer + for (n = 0; n < 128; n++) { + v[n] = (inp[0][l][0] * this.COEFS[n][0][0]) - (inp[0][l][1] * this.COEFS[n][0][1]); + for (k = 1; k < 64; k++) { + v[n] += (inp[k][l][0] * this.COEFS[n][k][0]) - (inp[k][l][1] * this.COEFS[n][k][1]); + // if (isNaN(inp[k][l][0])) { + // throw new Error('NAN') + // } + } + } + + // 3. extract samples + for (n = 0; n < 5; n++) { + for (k = 0; k < 64; k++) { + this.g[128 * n + k] = v[256 * n + k]; + this.g[128 * n + 64 + k] = v[256 * n + 192 + k]; + } + } + + // 4. window signal + for (n = 0; n < 640; n++) { + this.w[n] = this.g[n] * WINDOW[n]; + } + + // 5. calculate output samples + for (let i = 0; i < 64; i++) { + out[outOff] = this.w[i]; + for (let j = 1; j < 10; j++) { + out[outOff] = out[outOff] + this.w[64 * j + i]; + } + outOff++; + } + } + } +} diff --git a/src/sbr/constants.js b/src/sbr/constants.js new file mode 100644 index 0000000..dec0e6d --- /dev/null +++ b/src/sbr/constants.js @@ -0,0 +1,198 @@ +// frame classes +export const FIXFIX = 0; +export const FIXVAR = 1; +export const VARFIX = 2; +export const VARVAR = 3; + +// indizes for frequency tables +export const HIGH = 1; +export const LOW = 0; +export const RATE = 2; +export const TIME_SLOTS = 16; //TODO: 15 for 960-sample frames +export const TIME_SLOTS_RATE = TIME_SLOTS*RATE; +export const NOISE_FLOOR_OFFSET = 6; +export const T_HF_GEN = 8; +export const T_HF_ADJ = 2; + +// max values/lengths for arrays +export const MAX_BANDS = 64; +export const MAX_ENV_COUNT = 5; +export const MAX_NOISE_COUNT = 2; +export const MAX_RELATIVE_BORDERS = 3; +export const MAX_NQ = 5; +export const MAX_CHIRP_FACTORS = 5; +export const MAX_PATCHES = 6; +export const MAX_LTEMP = 6; + +// extension ids +export const EXTENSION_ID_PS = 2; + +// helper export constants +export const LOG2 = 0.6931471805599453; +export const PAN_OFFSETS = new Uint8Array([24, 12]); + +//CEIL_LOG[i] = Math.ceil(Math.log(i+1)/Math.log(2)) +export const CEIL_LOG2 = new Uint8Array([0, 1, 2, 2, 3, 3]); + +export const WINDOW = new Float64Array([ + 0.0, -5.525286E-4, -5.617692E-4, -4.947518E-4, + -4.875227E-4, -4.893791E-4, -5.040714E-4, -5.226564E-4, + -5.466565E-4, -5.677802E-4, -5.87093E-4, -6.132747E-4, + -6.312493E-4, -6.540333E-4, -6.77769E-4, -6.941614E-4, + -7.157736E-4, -7.255043E-4, -7.440941E-4, -7.490598E-4, + -7.681371E-4, -7.724848E-4, -7.834332E-4, -7.779869E-4, + -7.803664E-4, -7.801449E-4, -7.757977E-4, -7.630793E-4, + -7.530001E-4, -7.319357E-4, -7.215391E-4, -6.917937E-4, + -6.650415E-4, -6.341594E-4, -5.946118E-4, -5.564576E-4, + -5.145572E-4, -4.606325E-4, -4.095121E-4, -3.501175E-4, + -2.896981E-4, -2.098337E-4, -1.44638E-4, -6.17334E-5, + 1.34949E-5, 1.094383E-4, 2.043017E-4, 2.949531E-4, + 4.02654E-4, 5.107388E-4, 6.239376E-4, 7.458025E-4, + 8.608443E-4, 9.885988E-4, 0.0011250155, 0.0012577884, + 0.0013902494, 0.0015443219, 0.0016868083, 0.0018348265, + 0.001984114, 0.0021461583, 0.0023017254, 0.0024625616, + 0.0026201758, 0.0027870464, 0.0029469447, 0.003112542, + 0.0032739613, 0.0034418874, 0.0036008268, 0.0037603922, + 0.0039207432, 0.0040819753, 0.0042264269, 0.0043730719, + 0.0045209852, 0.004660646, 0.004793256, 0.0049137603, + 0.0050393022, 0.0051407353, 0.0052461166, 0.0053471681, + 0.0054196775, 0.005487604, 0.0055475714, 0.0055938023, + 0.0056220643, 0.0056455196, 0.0056389199, 0.0056266114, + 0.0055917128, 0.0055404363, 0.0054753783, 0.0053838975, + 0.0052715758, 0.0051382275, 0.0049839687, 0.0048109469, + 0.004603953, 0.0043801861, 0.0041251642, 0.0038456408, + 0.0035401246, 0.0032091885, 0.0028446757, 0.002450854, + 0.0020274176, 0.0015784682, 0.0010902329, 5.832264E-4, + 2.76045E-5, -5.46428E-4, -0.0011568135, -0.0018039472, + -0.0024826723, -0.0031933778, -0.0039401124, -0.0047222596, + -0.0055337211, -0.0063792293, -0.0072615816, -0.0081798233, + -0.0091325329, -0.0101150215, -0.0111315548, -0.0121849995, + 0.013271822, 0.0143904666, 0.0155405553, 0.0167324712, + 0.0179433381, 0.0191872431, 0.0204531793, 0.021746755, + 0.0230680169, 0.0244160992, 0.0257875847, 0.0271859429, + 0.0286072173, 0.0300502657, 0.0315017608, 0.0329754081, + 0.0344620948, 0.035969756, 0.037481285, 0.0390053679, + 0.040534917, 0.0420649094, 0.0436097542, 0.0451488405, + 0.0466843027, 0.048216572, 0.0497385755, 0.0512556155, + 0.0527630746, 0.0542452768, 0.0557173648, 0.057161645, + 0.0585915683, 0.059983748, 0.0613455171, 0.0626857808, + 0.0639715898, 0.0652247106, 0.0664367512, 0.0676075985, + 0.0687043828, 0.0697630244, 0.070762871, 0.0717002673, + 0.0725682583, 0.0733620255, 0.0741003642, 0.0747452558, + 0.0753137336, 0.0758008358, 0.0761992479, 0.076499217, + 0.076709349, 0.0768173975, 0.0768230011, 0.0767204924, + 0.0765050718, 0.0761748321, 0.0757305756, 0.0751576255, + 0.0744664394, 0.0736406005, 0.0726774642, 0.0715826364, + 0.0703533073, 0.0689664013, 0.0674525021, 0.0657690668, + 0.0639444805, 0.0619602779, 0.059816657, 0.0575152691, + 0.0550460034, 0.0524093821, 0.0495978676, 0.0466303305, + 0.0434768782, 0.0401458278, 0.0366418116, 0.032958393, + 0.0290824006, 0.0250307561, 0.0207997072, 0.0163701258, + 0.0117623832, 0.0069636862, 0.0019765601, -0.0032086896, + -0.0085711749, -0.0141288827, -0.0198834129, -0.0258227288, + -0.0319531274, -0.0382776572, -0.0447806821, -0.0514804176, + -0.0583705326, -0.0654409853, -0.07269433, -0.0801372934, + -0.0877547536, -0.0955533352, -0.1035329531, -0.1116826931, + -0.1200077984, -0.128500285, -0.1371551761, -0.1459766491, + -0.1549607071, -0.1640958855, -0.1733808172, -0.1828172548, + -0.1923966745, -0.2021250176, -0.2119735853, -0.2219652696, + -0.232069087, -0.2423016884, -0.2526480309, -0.2631053299, + -0.273663404, -0.2843214189, -0.2950716717, -0.3059098575, + -0.3168278913, -0.3278113727, -0.3388722693, -0.3499914122, + 0.3611589903, 0.3723795546, 0.3836350013, 0.3949211761, + 0.4062317676, 0.4175696896, 0.428911992, 0.4402553754, + 0.4515996535, 0.4629308085, 0.4742453214, 0.4855253091, + 0.4967708254, 0.50798175, 0.519123497, 0.5302240895, + 0.5412553448, 0.5522051258, 0.563078914, 0.5738524131, + 0.5845403235, 0.5951123086, 0.6055783538, 0.6159109932, + 0.6261242695, 0.6361980107, 0.6461269695, 0.6559016302, + 0.665513988, 0.674966319, 0.6842353293, 0.6933282376, + 0.7022388719, 0.7109410426, 0.7194462634, 0.72774489, + 0.7358211758, 0.7436827863, 0.7513137456, 0.758708076, + 0.7658674865, 0.7727780881, 0.7794287519, 0.785835312, + 0.7919735841, 0.7978466413, 0.8034485751, 0.8087695004, + 0.813819127, 0.8185776004, 0.823041989, 0.8272275347, + 0.8311038457, 0.8346937361, 0.8379717337, 0.8409541392, + 0.8436238281, 0.8459818469, 0.8480315777, 0.8497805198, + 0.8511971524, 0.8523047035, 0.8531020949, 0.8535720573, + 0.85373856, 0.8535720573, 0.8531020949, 0.8523047035, + 0.8511971524, 0.8497805198, 0.8480315777, 0.8459818469, + 0.8436238281, 0.8409541392, 0.8379717337, 0.8346937361, + 0.8311038457, 0.8272275347, 0.823041989, 0.8185776004, + 0.813819127, 0.8087695004, 0.8034485751, 0.7978466413, + 0.7919735841, 0.785835312, 0.7794287519, 0.7727780881, + 0.7658674865, 0.758708076, 0.7513137456, 0.7436827863, + 0.7358211758, 0.72774489, 0.7194462634, 0.7109410426, + 0.7022388719, 0.6933282376, 0.6842353293, 0.674966319, + 0.665513988, 0.6559016302, 0.6461269695, 0.6361980107, + 0.6261242695, 0.6159109932, 0.6055783538, 0.5951123086, + 0.5845403235, 0.5738524131, 0.563078914, 0.5522051258, + 0.5412553448, 0.5302240895, 0.519123497, 0.50798175, + 0.4967708254, 0.4855253091, 0.4742453214, 0.4629308085, + 0.4515996535, 0.4402553754, 0.428911992, 0.4175696896, + 0.4062317676, 0.3949211761, 0.3836350013, 0.3723795546, + -0.3611589903, -0.3499914122, -0.3388722693, -0.3278113727, + -0.3168278913, -0.3059098575, -0.2950716717, -0.2843214189, + -0.273663404, -0.2631053299, -0.2526480309, -0.2423016884, + -0.232069087, -0.2219652696, -0.2119735853, -0.2021250176, + -0.1923966745, -0.1828172548, -0.1733808172, -0.1640958855, + -0.1549607071, -0.1459766491, -0.1371551761, -0.128500285, + -0.1200077984, -0.1116826931, -0.1035329531, -0.0955533352, + -0.0877547536, -0.0801372934, -0.07269433, -0.0654409853, + -0.0583705326, -0.0514804176, -0.0447806821, -0.0382776572, + -0.0319531274, -0.0258227288, -0.0198834129, -0.0141288827, + -0.0085711749, -0.0032086896, 0.0019765601, 0.0069636862, + 0.0117623832, 0.0163701258, 0.0207997072, 0.0250307561, + 0.0290824006, 0.032958393, 0.0366418116, 0.0401458278, + 0.0434768782, 0.0466303305, 0.0495978676, 0.0524093821, + 0.0550460034, 0.0575152691, 0.059816657, 0.0619602779, + 0.0639444805, 0.0657690668, 0.0674525021, 0.0689664013, + 0.0703533073, 0.0715826364, 0.0726774642, 0.0736406005, + 0.0744664394, 0.0751576255, 0.0757305756, 0.0761748321, + 0.0765050718, 0.0767204924, 0.0768230011, 0.0768173975, + 0.076709349, 0.076499217, 0.0761992479, 0.0758008358, + 0.0753137336, 0.0747452558, 0.0741003642, 0.0733620255, + 0.0725682583, 0.0717002673, 0.070762871, 0.0697630244, + 0.0687043828, 0.0676075985, 0.0664367512, 0.0652247106, + 0.0639715898, 0.0626857808, 0.0613455171, 0.059983748, + 0.0585915683, 0.057161645, 0.0557173648, 0.0542452768, + 0.0527630746, 0.0512556155, 0.0497385755, 0.048216572, + 0.0466843027, 0.0451488405, 0.0436097542, 0.0420649094, + 0.040534917, 0.0390053679, 0.037481285, 0.035969756, + 0.0344620948, 0.0329754081, 0.0315017608, 0.0300502657, + 0.0286072173, 0.0271859429, 0.0257875847, 0.0244160992, + 0.0230680169, 0.021746755, 0.0204531793, 0.0191872431, + 0.0179433381, 0.0167324712, 0.0155405553, 0.0143904666, + -0.013271822, -0.0121849995, -0.0111315548, -0.0101150215, + -0.0091325329, -0.0081798233, -0.0072615816, -0.0063792293, + -0.0055337211, -0.0047222596, -0.0039401124, -0.0031933778, + -0.0024826723, -0.0018039472, -0.0011568135, -5.46428E-4, + 2.76045E-5, 5.832264E-4, 0.0010902329, 0.0015784682, + 0.0020274176, 0.002450854, 0.0028446757, 0.0032091885, + 0.0035401246, 0.0038456408, 0.0041251642, 0.0043801861, + 0.004603953, 0.0048109469, 0.0049839687, 0.0051382275, + 0.0052715758, 0.0053838975, 0.0054753783, 0.0055404363, + 0.0055917128, 0.0056266114, 0.0056389199, 0.0056455196, + 0.0056220643, 0.0055938023, 0.0055475714, 0.005487604, + 0.0054196775, 0.0053471681, 0.0052461166, 0.0051407353, + 0.0050393022, 0.0049137603, 0.004793256, 0.004660646, + 0.0045209852, 0.0043730719, 0.0042264269, 0.0040819753, + 0.0039207432, 0.0037603922, 0.0036008268, 0.0034418874, + 0.0032739613, 0.003112542, 0.0029469447, 0.0027870464, + 0.0026201758, 0.0024625616, 0.0023017254, 0.0021461583, + 0.001984114, 0.0018348265, 0.0016868083, 0.0015443219, + 0.0013902494, 0.0012577884, 0.0011250155, 9.885988E-4, + 8.608443E-4, 7.458025E-4, 6.239376E-4, 5.107388E-4, + 4.02654E-4, 2.949531E-4, 2.043017E-4, 1.094383E-4, + 1.34949E-5, -6.17334E-5, -1.44638E-4, -2.098337E-4, + -2.896981E-4, -3.501175E-4, -4.095121E-4, -4.606325E-4, + -5.145572E-4, -5.564576E-4, -5.946118E-4, -6.341594E-4, + -6.650415E-4, -6.917937E-4, -7.215391E-4, -7.319357E-4, + -7.530001E-4, -7.630793E-4, -7.757977E-4, -7.801449E-4, + -7.803664E-4, -7.779869E-4, -7.834332E-4, -7.724848E-4, + -7.681371E-4, -7.490598E-4, -7.440941E-4, -7.255043E-4, + -7.157736E-4, -6.941614E-4, -6.77769E-4, -6.540333E-4, + -6.312493E-4, -6.132747E-4, -5.87093E-4, -5.677802E-4, + -5.466565E-4, -5.226564E-4, -5.040714E-4, -4.893791E-4, + -4.875227E-4, -4.947518E-4, -5.617692E-4, -5.52528E-4 +]); diff --git a/src/sbr/header.js b/src/sbr/header.js new file mode 100644 index 0000000..f1c557f --- /dev/null +++ b/src/sbr/header.js @@ -0,0 +1,57 @@ +export default class SBRHeader { + constructor() { + this.decoded = false; + } + + decode(stream) { + this.decoded = true; + + // save previous values + this.startFrequencyPrev = this.startFrequency; + this.stopFrequencyPrev = this.stopFrequency; + this.frequencyScalePrev = this.frequencyScale; + this.alterScalePrev = this.alterScale; + this.xOverBandPrev = this.xOverBand; + this.noiseBandsPrev = this.noiseBands; + this.limiterBandsPrev = this.limiterBands; + + // read new values + this.ampRes = stream.read(1); + this.startFrequency = stream.read(4); + this.stopFrequency = stream.read(4); + this.xOverBand = stream.read(3); + stream.advance(2); //reserved + + let extraHeader1 = stream.read(1); + let extraHeader2 = stream.read(1); + + if (extraHeader1) { + this.frequencyScale = stream.read(2); + this.alterScale = stream.read(1); + this.noiseBands = stream.read(2); + } else { + this.frequencyScale = 2; + this.alterScale = 1; + this.noiseBands = 2; + } + + if (extraHeader2) { + this.limiterBands = stream.read(2); + this.limiterGains = stream.read(2); + this.interpolFrequency = stream.read(1); + this.smoothingMode = stream.read(1); + } else { + this.limiterBands = 2; + this.limiterGains = 2; + this.interpolFrequency = 1; + this.smoothingMode = 1; + } + + this.reset = this.startFrequency !== this.startFrequencyPrev + || this.stopFrequency !== this.stopFrequencyPrev + || this.frequencyScale !== this.frequencyScalePrev + || this.alterScale !== this.alterScalePrev + || this.xOverBand !== this.xOverBandPrev + || this.noiseBands !== this.noiseBandsPrev; + } +} diff --git a/src/sbr/sbr.js b/src/sbr/sbr.js new file mode 100644 index 0000000..fda0075 --- /dev/null +++ b/src/sbr/sbr.js @@ -0,0 +1,310 @@ +import SBRHeader from './header'; +import FrequencyTables from './FrequencyTables'; +import ChannelData from './ChannelData'; +import {makeArray} from './utils'; +import AnalysisFilterbank from './AnalysisFilterbank'; +import SynthesisFilterbank from './SynthesisFilterbank'; +import HFGenerator from './HFGenerator'; +import HFAdjuster from './HFAdjuster' + +const NOISE_FLOOR_OFFSET = 6; +const EXTENSION_ID_PS = 2; + +const T_HF_GEN = 8; +const T_HF_ADJ = 2; + +const RATE = 2; +const TIME_SLOTS = 16; //TODO: 15 for 960-sample frames +const TIME_SLOTS_RATE = TIME_SLOTS * RATE; +const MAX_LTEMP = 6; + +let pool = []; + +class SBR { + constructor(sampleRate, downSampled) { + this.sampleRate = 2 * sampleRate; + this.header = new SBRHeader; + this.tables = new FrequencyTables; + this.cd = [new ChannelData, new ChannelData]; + + this.qmfA = new AnalysisFilterbank; + this.qmfS = new SynthesisFilterbank; + + this.X = makeArray([2, 64, 38, 2]); + this.Xlow = makeArray([32, 40, 2]); + this.Xhigh = makeArray([64, 40, 2]); + } + + static get(sampleRate, downSampled) { + let sbr = pool.length ? pool.pop() : new SBR(sampleRate, downSampled); + sbr.sampleRate = 2 * sampleRate; + return sbr; + } + + static release(sbr) { + pool.push(sbr); + } + + decode(stream, count, stereo, crc) { + this.stereo = stereo; + var pos = stream.offset(); + var end = pos + count; + + if (crc) { + stream.advance(10); + } + + // if (this.header.decoded) { + // this.header.kxPrev = this.header.kx; + // this.header.mPrev = this.header.m; + // } + + if (stream.read(1)) { + // console.log("HEADER") + this.header.decode(stream); + if (this.header.reset) { + this.tables.calculate(this.header, this.sampleRate); + } else if (this.header.limiterBands !== this.header.limiterBandsPrev) { + console.log("LIMITER BANDS CHANGED") + this.tables.calculateLimiterTable(this.header); + } + } + + if (this.header.decoded) { + // console.log('decode', stereo) + if (stereo) { + this.decodeChannelPair(stream); + } else { + this.decodeSingleChannel(stream); + } + + // if (stream.read(1)) { + // let count = stream.read(4); + // if (count === 15) count += stream.read(8); + // let bitsLeft = 8 * count; + // + // let extensionID; + // while (bitsLeft>7) { + // bitsLeft -= 2; + // extensionID = stream.read(2); + // bitsLeft -= this.decodeExtension(stream, extensionID); + // } + // } + } + + stream.seek(end); + } + + decodeChannelPair(stream) { + if (stream.read(1)) { + stream.advance(8); // reserved + } + + let coupling = stream.read(1); + + if (coupling) { + throw new Error('COUPLING') + this.cd[0].decodeGrid(stream, this.header, this.tables); + this.cd[1].copyGrid(this.cd[0]); + this.cd[0].decodeDTDF(stream); + this.cd[1].decodeDTDF(stream); + this.cd[0].decodeInvf(stream, this.header, this.tables); + this.cd[1].copyInvf(this.cd[0]); + this.cd[0].decodeEnvelope(stream, this.header, this.tables, false, coupling); + this.cd[0].decodeNoise(stream, this.header, this.tables, false, coupling); + this.cd[1].decodeEnvelope(stream, this.header, this.tables, true, coupling); + this.cd[1].decodeNoise(stream, this.header, this.tables, true, coupling); + + this.dequantCoupled(); + } else { + this.cd[0].decodeGrid(stream, this.header, this.tables); + this.cd[1].decodeGrid(stream, this.header, this.tables); + this.cd[0].decodeDTDF(stream); + this.cd[1].decodeDTDF(stream); + this.cd[0].decodeInvf(stream, this.header, this.tables); + this.cd[1].decodeInvf(stream, this.header, this.tables); + this.cd[0].decodeEnvelope(stream, this.header, this.tables, false, coupling); + this.cd[1].decodeEnvelope(stream, this.header, this.tables, true, coupling); + this.cd[0].decodeNoise(stream, this.header, this.tables, false, coupling); + this.cd[1].decodeNoise(stream, this.header, this.tables, true, coupling); + + this.dequantSingle(0); + this.dequantSingle(1); + } + + this.cd[0].decodeSinusoidal(stream, this.header, this.tables); + this.cd[1].decodeSinusoidal(stream, this.header, this.tables); + } + + dequantSingle(ch) { + // envelopes + let a = this.cd[ch].ampRes; + let eq = this.cd[ch].envelopeSFQ; + let e = this.cd[ch].envelopeSF; + let freqRes = this.cd[ch].freqRes; + let n = this.tables.n; + const EXP2 = [1, Math.SQRT2]; + + for (let l = 0; l < this.cd[ch].envCount; l++) { + for (let k = 0; k < n[freqRes[l]]; k++) { + // e[l][k] = Math.pow(2.0, (e[l][k] >> a) + 6.0); + if (a) { + e[l][k] = Math.pow(2, eq[l][k] + 6); + } else { + e[l][k] = Math.pow(2, (eq[l][k] >> 1) + 6) * EXP2[eq[l][k] & 1]; + } + + if (e[l][k] > 1e20) { + console.log("DEQUANT OUT OF BOUNDS"); + e[l][k] = 1; + } + } + } + + // noise + let nq = this.tables.nq; + let lq = this.cd[ch].noiseCount; + let qq = this.cd[ch].noiseFloorDataQ; + let q = this.cd[ch].noiseFloorData; + + for (let l = 0; l < lq; l++) { + for (let k = 0; k < nq; k++) { + q[l][k] = Math.pow(2.0, NOISE_FLOOR_OFFSET - qq[l][k]); + } + } + } + + decodeExtension(stream, extensionID) { + switch (extensionID) { + case EXTENSION_ID_PS: + console.log("PS!") + this.psUsed = true; + // if(ps==null) ps = new PS(); + // ps.decode(in); + // if(!psUsed&&ps.hasHeader()) psUsed = true; + break; + } + } + + // left/right: 1024 time samples + process(left, right, downSampled) { + if (!this.header.decoded) return; + + this.processChannel(0, left); + if (this.stereo) { + this.processChannel(1, right); + } else if (this.psUsed) { + throw new Error('PS data unsupported') + } + + this.qmfS.process(this.X[0], left, 0); + if (this.stereo || this.psUsed) { + this.qmfS.process(this.X[1], right, 1); + } + + for (let i = 0; i < left.length; i++) { + if (isNaN(left[i])) { + console.log("NAN LEFT") + } + } + } + + processChannel(ch, data) { + // 2. analysis QMF (data -> W) + this.qmfA.process(data, this.cd[ch].W[this.cd[ch].Ypos], ch); + + let kx = this.tables.kx; + for (l = T_HF_GEN; l < TIME_SLOTS_RATE + T_HF_GEN; l++) { + for (k = 0; k < kx; k++) { + this.Xlow[k][l][0] = this.cd[ch].W[this.cd[ch].Ypos][l - T_HF_GEN][k][0]; + this.Xlow[k][l][1] = this.cd[ch].W[this.cd[ch].Ypos][l - T_HF_GEN][k][1]; + } + + for (k = kx; k < 32; k++) { + this.Xlow[k][l][0] = 0; + this.Xlow[k][l][1] = 0; + } + } + + // 1. old W -> Xlow (4.6.18.5) + let kxPrev = this.tables.kxPrev; + let l, k; + for (l = 0; l < T_HF_GEN; l++) { + for (k = 0; k < kxPrev; k++) { + this.Xlow[k][l][0] = this.cd[ch].W[1 - this.cd[ch].Ypos][l + TIME_SLOTS_RATE - T_HF_GEN][k][0]; + this.Xlow[k][l][1] = this.cd[ch].W[1 - this.cd[ch].Ypos][l + TIME_SLOTS_RATE - T_HF_GEN][k][1]; + } + + for (k = kxPrev; k < 32; k++) { + this.Xlow[k][l][0] = 0; + this.Xlow[k][l][1] = 0; + } + } + + this.cd[ch].Ypos ^= 1; + + // 3. new W -> Xlow (4.6.18.5) + // let kx = this.tables.kx; + // for (l = T_HF_GEN; l < TIME_SLOTS_RATE + T_HF_GEN; l++) { + // for (k = 0; k < kx; k++) { + // this.Xlow[k][l][0] = this.cd[ch].W[l - T_HF_GEN][k][0]; + // this.Xlow[k][l][1] = this.cd[ch].W[l - T_HF_GEN][k][1]; + // } + // + // for (k = kx; k < 32; k++) { + // this.Xlow[k][l][0] = 0; + // this.Xlow[k][l][1] = 0; + // } + // } + + // 4. HF generation (Xlow -> Xhigh) + HFGenerator(this.tables, this.cd[ch], this.Xlow, this.Xhigh); + + // 6. HF adjustment (Xhigh -> Y) + HFAdjuster(this.header, this.tables, this.cd[ch], this.Xhigh, this.cd[ch].Y[this.cd[ch].Ypos]); + + // 5. old Y -> X + let lTemp = this.cd[ch].lTemp; + let mPrev = this.tables.mPrev; + let m = this.tables.m; + for (l = 0; l < lTemp; l++) { + for (k = 0; k X + for (l = lTemp; l < TIME_SLOTS_RATE; l++) { + for (k = 0; k < kx; k++) { + this.X[ch][k][l][0] = this.Xlow[k][l + T_HF_ADJ][0]; + this.X[ch][k][l][1] = this.Xlow[k][l + T_HF_ADJ][1]; + } + + for (k = kx; k Date: Wed, 6 Jul 2016 17:37:15 -0700 Subject: [PATCH 02/19] Pre-allocate memory for HFGenerator and HFAdjuster --- src/sbr/HFAdjuster.js | 602 ++++++++++++++++++++--------------------- src/sbr/HFGenerator.js | 323 +++++++++++----------- src/sbr/sbr.js | 6 +- 3 files changed, 453 insertions(+), 478 deletions(-) diff --git a/src/sbr/HFAdjuster.js b/src/sbr/HFAdjuster.js index d58ce2e..350ae8a 100644 --- a/src/sbr/HFAdjuster.js +++ b/src/sbr/HFAdjuster.js @@ -18,368 +18,354 @@ const PHI = [ ]; const MAX_GAIN = 100000; -// class Parameter { -// //helper class containing arrays calculated by and passed to different methods -// float[][] eMapped, qMapped; -// boolean[][] sIndexMapped, sMapped; -// float[][] Qm, Sm, Glim; -// } - -export default function process(header, tables, cd, Xhigh, Y) { - let p = map(tables, cd); - let eCurr = estimateEnvelopes(header, tables, cd, Xhigh); - calculateGain(header, tables, cd, p, eCurr); - assembleSignals(header, tables, cd, p, Xhigh, Y); -} - -// mapping of dequantized values (4.6.18.7.2) -function map(tables, cd) { - // parameter from FrequencyTables - let kx = tables.kx; - let noiseTable = tables.fNoise; - let fHigh = tables.fTable[HIGH]; - let nHigh = tables.n[HIGH]; - let M = tables.m; - let nq = tables.nq; - - // parameter from ChannelData - let le = cd.envCount; - let lq = cd.noiseCount; - let freqRes = cd.freqRes; - let la = cd.la; - - //input and output arrays - let eOrig = cd.envelopeSF; - let eMapped = makeArray([7, 48]); - let qOrig = cd.noiseFloorData; - let qMapped = makeArray([7, 48]); - let sinusoidals = cd.sinusoidals; - let sIndexMappedPrev = cd.sIndexMappedPrevious; - let sIndexMapped = makeArray([7, 48], Uint8Array); - let sMapped = makeArray([7, 48], Uint8Array); - - // tmp integer - let fr, maxI, k, i, m; - let table; +export default class HFAdjuster { + constructor() { + this.eMapped = makeArray([7, 48]); + this.qMapped = makeArray([7, 48]); + this.sIndexMapped = makeArray([7, 48], Uint8Array); + this.sMapped = makeArray([7, 48], Uint8Array); + this.eCurr = makeArray([7, 48]); + this.Qm = makeArray([7, 48]); + this.Sm = makeArray([7, 48]); + this.gain = makeArray([7, 48]); + } + + process(header, tables, cd, Xhigh, Y) { + this.map(tables, cd); + this.estimateEnvelopes(header, tables, cd, Xhigh); + this.calculateGain(header, tables, cd); + this.assembleSignals(header, tables, cd, Xhigh, Y); + } + + // mapping of dequantized values (4.6.18.7.2) + map(tables, cd) { + // parameter from FrequencyTables + let kx = tables.kx; + let noiseTable = tables.fNoise; + let fHigh = tables.fTable[HIGH]; + let nHigh = tables.n[HIGH]; + let M = tables.m; + let nq = tables.nq; + + // parameter from ChannelData + let le = cd.envCount; + let lq = cd.noiseCount; + let freqRes = cd.freqRes; + let la = cd.la; + + //input and output arrays + let eOrig = cd.envelopeSF; + let eMapped = this.eMapped; + let qOrig = cd.noiseFloorData; + let qMapped = this.qMapped; + let sinusoidals = cd.sinusoidals; + let sIndexMappedPrev = cd.sIndexMappedPrevious; + let sIndexMapped = this.sIndexMapped; + let sMapped = this.sMapped; + + // tmp integer + let fr, maxI, k, i, m; + let table; - for (let e = 0; e < le; e++) { - // envelopes: eOrig -> eMapped - fr = freqRes[e]; - maxI = tables.n[fr]; - table = tables.fTable[fr]; + for (let e = 0; e < le; e++) { + // envelopes: eOrig -> eMapped + fr = freqRes[e]; + maxI = tables.n[fr]; + table = tables.fTable[fr]; - for (i = 0; i < maxI; i++) { - for (m = table[i]; m < table[i + 1]; m++) { - eMapped[e][m - kx] = eOrig[e][i]; + for (i = 0; i < maxI; i++) { + for (m = table[i]; m < table[i + 1]; m++) { + eMapped[e][m - kx] = eOrig[e][i]; + } } - } - // noise: qOrig -> qMapped - k = ((lq > 1) && (cd.te[e] >= cd.tq[1])) ? 1 : 0; - for (i = 0; i < nq; i++) { - for (m = noiseTable[i]; m < noiseTable[i + 1]; m++) { - qMapped[e][m - kx] = qOrig[k][i]; + // noise: qOrig -> qMapped + k = ((lq > 1) && (cd.te[e] >= cd.tq[1])) ? 1 : 0; + for (i = 0; i < nq; i++) { + for (m = noiseTable[i]; m < noiseTable[i + 1]; m++) { + qMapped[e][m - kx] = qOrig[k][i]; + } } - } - // sinusoidals: cd.sinusoidals -> sIndexMapped - for (i = 0; i < nHigh; i++) { - if (cd.sinusoidalsPresent) { - m = (fHigh[i] + fHigh[i + 1]) >> 1; - sIndexMapped[e][m - kx] = sinusoidals[i] && (e >= la || sIndexMappedPrev[m - kx]) ? 1 : 0; + // sinusoidals: cd.sinusoidals -> sIndexMapped + for (i = 0; i < nHigh; i++) { + if (cd.sinusoidalsPresent) { + m = (fHigh[i] + fHigh[i + 1]) >> 1; + sIndexMapped[e][m - kx] = sinusoidals[i] && (e >= la || sIndexMappedPrev[m - kx]) ? 1 : 0; + } } - } - // sinusoidals: sIndexMapped -> sMapped - let found; - for (i = 0; i < maxI; i++) { - found = 0; - for (m = table[i]; m < table[i + 1]; m++) { - if (sIndexMapped[e][m - kx]) { - found = 1; - break; + // sinusoidals: sIndexMapped -> sMapped + let found; + for (i = 0; i < maxI; i++) { + found = 0; + for (m = table[i]; m < table[i + 1]; m++) { + if (sIndexMapped[e][m - kx]) { + found = 1; + break; + } } - } - for (m = table[i]; m < table[i + 1]; m++) { - sMapped[e][m - kx] = found; - } - } - } - - // fill with 0, because next frame may be larger than this one - cd.sIndexMappedPrevious.fill(0); - cd.sIndexMappedPrevious.set(sIndexMapped[le - 1]); - - return {eMapped, qMapped, sIndexMapped, sMapped}; -} - -// envelope estimation (4.6.18.7.3) -function estimateEnvelopes(header, tables, cd, Xhigh) { - let te = cd.te; - let M = tables.m; - let kx = tables.kx; - let le = cd.envCount; - - let eCurr = makeArray([7, 48]); - - let sum; - let e, m, i, iLow, iHigh; - if (header.interpolFrequency) { - let div; - - for (e = 0; e < le; e++) { - div = 0.5 / (te[e + 1] - te[e]); - iLow = RATE * te[e] + T_HF_ADJ; - iHigh = RATE * te[e + 1] + T_HF_ADJ; - - for (m = 0; m < M; m++) { - sum = 0.0; - - //energy = sum over squares of absolute value - for (i = iLow; i < iHigh; i++) { - sum += Xhigh[m + kx][i][0] * Xhigh[m + kx][i][0] + Xhigh[m + kx][i][1] * Xhigh[m + kx][i][1]; + for (m = table[i]; m < table[i + 1]; m++) { + sMapped[e][m - kx] = found; } - - eCurr[e][m] = sum * div; } } - } else { - let n = tables.n; - let freqRes = cd.freqRes; - - let k; - let table; - let div1, div2; - for (e = 0; e < le; e++) { - div1 = RATE * (te[e + 1] - te[e]); - iLow = RATE * te[e] + T_HF_ADJ; - iHigh = RATE * te[e + 1] + T_HF_ADJ; - table = tables.fTable[freqRes[e + 1]]; + // fill with 0, because next frame may be larger than this one + cd.sIndexMappedPrevious.fill(0); + cd.sIndexMappedPrevious.set(sIndexMapped[le - 1]); + } + + // envelope estimation (4.6.18.7.3) + estimateEnvelopes(header, tables, cd, Xhigh) { + let te = cd.te; + let M = tables.m; + let kx = tables.kx; + let le = cd.envCount; + let eCurr = this.eCurr; + + let sum; + let e, m, i, iLow, iHigh; + if (header.interpolFrequency) { + let div; + + for (e = 0; e < le; e++) { + div = 0.5 / (te[e + 1] - te[e]); + iLow = RATE * te[e] + T_HF_ADJ; + iHigh = RATE * te[e + 1] + T_HF_ADJ; - for (m = 0; m < n[freqRes[e + 1]]; m++) { - sum = 0.0; - div2 = div1 * (table[m + 1] - table[m]); + for (m = 0; m < M; m++) { + sum = 0.0; - for (k = table[m]; k < table[m + 1]; k++) { + //energy = sum over squares of absolute value for (i = iLow; i < iHigh; i++) { - sum += Xhigh[k][i][0] * Xhigh[k][i][0] + Xhigh[k][i][1] * Xhigh[k][i][1]; + sum += Xhigh[m + kx][i][0] * Xhigh[m + kx][i][0] + Xhigh[m + kx][i][1] * Xhigh[m + kx][i][1]; } + + eCurr[e][m] = sum * div; } + } + } else { + let n = tables.n; + let freqRes = cd.freqRes; + + let k; + let table; + let div1, div2; + + for (e = 0; e < le; e++) { + div1 = RATE * (te[e + 1] - te[e]); + iLow = RATE * te[e] + T_HF_ADJ; + iHigh = RATE * te[e + 1] + T_HF_ADJ; + table = tables.fTable[freqRes[e + 1]]; + + for (m = 0; m < n[freqRes[e + 1]]; m++) { + sum = 0.0; + div2 = div1 * (table[m + 1] - table[m]); + + for (k = table[m]; k < table[m + 1]; k++) { + for (i = iLow; i < iHigh; i++) { + sum += Xhigh[k][i][0] * Xhigh[k][i][0] + Xhigh[k][i][1] * Xhigh[k][i][1]; + } + } - sum /= div2; + sum /= div2; - for (k = table[m]; k < table[m + 1]; k++) { - eCurr[e][k - kx] = sum; + for (k = table[m]; k < table[m + 1]; k++) { + eCurr[e][k - kx] = sum; + } } } } } - - return eCurr; -} - -//calculation of levels of additional HF signal components (4.6.18.7.4) and gain calculation (4.6.18.7.5) -function calculateGain(header, tables, cd, p, eCurr) { - let limGain = header.limiterGains; - let M = tables.m; - let nl = tables.nl; - let fLim = tables.fLim; - let kx = tables.kx; - - let la = cd.la; - let laPrevious = cd.laPrevious === cd.envCountPrev ? 0 : -1; - let le = cd.envCount; - - // output arrays - let Qm = makeArray([7, 48]); - let Sm = makeArray([7, 48]); - let gain = makeArray([7, 48]); - - let delta, delta2; - let m, k, i; - let km = new Int32Array(M); - let eMappedSum = new Float32Array(nl); - let tmp; - let gTemp = makeArray([le, nl]); - let gMax; - - // TODO: optimize this loops - for (let e = 0; e < le; e++) { - delta = !((e == la) || (e == laPrevious)) ? 1 : 0; + + //calculation of levels of additional HF signal components (4.6.18.7.4) and gain calculation (4.6.18.7.5) + calculateGain(header, tables, cd) { + let limGain = header.limiterGains; + let M = tables.m; + let nl = tables.nl; + let fLim = tables.fLim; + let kx = tables.kx; + + let la = cd.la; + let laPrevious = cd.laPrevious === cd.envCountPrev ? 0 : -1; + let le = cd.envCount; + + // output arrays + let Qm = this.Qm; + let Sm = this.Sm; + let gain = this.gain; + let eCurr = this.eCurr; + + let delta, delta2; + let m, k, i; + let tmp; + let gMax; + + // TODO: optimize this loops + for (let e = 0; e < le; e++) { + delta = !((e == la) || (e == laPrevious)) ? 1 : 0; - for (k = 0; k < nl; k++) { - let sum0, sum1; + for (k = 0; k < nl; k++) { + let sum0, sum1; - // level of additional HF components + gain - for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { - tmp = p.eMapped[e][m] / (1.0 + p.qMapped[e][m]); - Qm[e][m] = Math.sqrt(tmp * p.qMapped[e][m]); - Sm[e][m] = Math.sqrt(tmp * p.sIndexMapped[e][m]); - - if (p.sMapped[e][m] === 0) { - gain[e][m] = Math.sqrt(p.eMapped[e][m] / ((1.0 + eCurr[e][m]) * (1.0 + p.qMapped[e][m] * delta))); - } else { - gain[e][m] = Math.sqrt(p.eMapped[e][m] * p.qMapped[e][m] / ((1.0 + eCurr[e][m]) * (1.0 + p.qMapped[e][m]))); + // level of additional HF components + gain + for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { + tmp = this.eMapped[e][m] / (1.0 + this.qMapped[e][m]); + Qm[e][m] = Math.sqrt(tmp * this.qMapped[e][m]); + Sm[e][m] = Math.sqrt(tmp * this.sIndexMapped[e][m]); + + if (this.sMapped[e][m] === 0) { + gain[e][m] = Math.sqrt(this.eMapped[e][m] / ((1.0 + eCurr[e][m]) * (1.0 + this.qMapped[e][m] * delta))); + } else { + gain[e][m] = Math.sqrt(this.eMapped[e][m] * this.qMapped[e][m] / ((1.0 + eCurr[e][m]) * (1.0 + this.qMapped[e][m]))); + } } - } - sum0 = sum1 = 0.0; - for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { - sum0 += p.eMapped[e][m]; - sum1 += eCurr[e][m]; - } + sum0 = sum1 = 0.0; + for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { + sum0 += this.eMapped[e][m]; + sum1 += eCurr[e][m]; + } - gMax = LIMITER_GAINS[limGain] * Math.sqrt((EPSILON_0 + sum0) / (EPSILON_0 + sum1)); - gMax = Math.min(MAX_GAIN, gMax); - // console.log(gMax, limGain, LIMITER_GAINS[limGain], EPSILON_0, sum0, sum1) + gMax = LIMITER_GAINS[limGain] * Math.sqrt((EPSILON_0 + sum0) / (EPSILON_0 + sum1)); + gMax = Math.min(MAX_GAIN, gMax); + // console.log(gMax, limGain, LIMITER_GAINS[limGain], EPSILON_0, sum0, sum1) - for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { - let qmMax = Qm[e][m] * gMax / gain[e][m]; - Qm[e][m] = Math.min(Qm[e][m], qmMax); - gain[e][m] = Math.min(gain[e][m], gMax); - } + for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { + let qmMax = Qm[e][m] * gMax / gain[e][m]; + Qm[e][m] = Math.min(Qm[e][m], qmMax); + gain[e][m] = Math.min(gain[e][m], gMax); + } - sum0 = sum1 = 0.0; - for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { - sum0 += p.eMapped[e][m]; - sum1 += eCurr[e][m] * gain[e][m] * gain[e][m] - + Sm[e][m] * Sm[e][m] - + ((delta && !Sm[e][m]) ? 1 : 0) * Qm[e][m] * Qm[e][m]; - } + sum0 = sum1 = 0.0; + for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { + sum0 += this.eMapped[e][m]; + sum1 += eCurr[e][m] * gain[e][m] * gain[e][m] + + Sm[e][m] * Sm[e][m] + + ((delta && !Sm[e][m]) ? 1 : 0) * Qm[e][m] * Qm[e][m]; + } - let gainBoost = Math.sqrt((EPSILON_0 + sum0) / (EPSILON_0 + sum1)); - gainBoost = Math.min(MAX_BOOST, gainBoost); - for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { - gain[e][m] *= gainBoost; - Qm[e][m] *= gainBoost; - Sm[e][m] *= gainBoost; - // if (isNaN(gain[e][m])) { - // console.log(gainBoost, sum0, sum1) - // } + let gainBoost = Math.sqrt((EPSILON_0 + sum0) / (EPSILON_0 + sum1)); + gainBoost = Math.min(MAX_BOOST, gainBoost); + for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { + gain[e][m] *= gainBoost; + Qm[e][m] *= gainBoost; + Sm[e][m] *= gainBoost; + // if (isNaN(gain[e][m])) { + // console.log(gainBoost, sum0, sum1) + // } + } } } } - - p.Qm = Qm; - p.Sm = Sm; - p.Glim = gain; -} - -function checkNaN(arr) { - for (let i = 0; i < arr.length; i++) { - if (isNaN(arr[i])) { - console.log('NaN', i); - break; - } - } -} - -// assembling HF signals (4.6.18.7.5) -function assembleSignals(header, tables, cd, p, Xhigh, Y) { - let reset = header.reset; - let hSL = header.smoothingMode ? 0 : 4; - let M = tables.m - let le = cd.envCount; - let lePrev = cd.envCountPrev; - let te = cd.te; - let la = cd.la; - let laPrev = cd.laPrevious === cd.envCountPrev ? 0 : -1; - let kx = tables.kx; - let noiseIndex = reset ? 0 : cd.noiseIndex; - let sineIndex = cd.sineIndex; - - let gTmp = cd.gTmp; - let qTmp = cd.qTmp; - - let e, i, m, j; - - // save previous values - if (reset) { - for (i = 0; i < hSL; i++) { - gTmp[i + 2 * te[0]].set(p.Glim[0].subarray(0, M)); - qTmp[i + 2 * te[0]].set(p.Qm[0].subarray(0, M)); - } - } else if (hSL !== 0) { - for (i = 0; i < 4; i++) { - gTmp[i + 2 * te[0]].set(gTmp[i + 2 * cd.tePrevious]); - qTmp[i + 2 * te[0]].set(qTmp[i + 2 * cd.tePrevious]); + + // assembling HF signals (4.6.18.7.5) + assembleSignals(header, tables, cd, Xhigh, Y) { + let reset = header.reset; + let hSL = header.smoothingMode ? 0 : 4; + let M = tables.m + let le = cd.envCount; + let lePrev = cd.envCountPrev; + let te = cd.te; + let la = cd.la; + let laPrev = cd.laPrevious === cd.envCountPrev ? 0 : -1; + let kx = tables.kx; + let noiseIndex = reset ? 0 : cd.noiseIndex; + let sineIndex = cd.sineIndex; + + let gTmp = cd.gTmp; + let qTmp = cd.qTmp; + + let e, i, m, j; + + // save previous values + if (reset) { + for (i = 0; i < hSL; i++) { + gTmp[i + 2 * te[0]].set(this.gain[0].subarray(0, M)); + qTmp[i + 2 * te[0]].set(this.Qm[0].subarray(0, M)); + } + } else if (hSL !== 0) { + for (i = 0; i < 4; i++) { + gTmp[i + 2 * te[0]].set(gTmp[i + 2 * cd.tePrevious]); + qTmp[i + 2 * te[0]].set(qTmp[i + 2 * cd.tePrevious]); + } } - } - for (e = 0; e < le; e++) { - for (i = 2 * te[e]; i < 2 * te[e + 1]; i++) { - gTmp[hSL + i].set(p.Glim[e].subarray(0, M)); - qTmp[hSL + i].set(p.Qm[e].subarray(0, M)); + for (e = 0; e < le; e++) { + for (i = 2 * te[e]; i < 2 * te[e + 1]; i++) { + gTmp[hSL + i].set(this.gain[e].subarray(0, M)); + qTmp[hSL + i].set(this.Qm[e].subarray(0, M)); + } } - } - // calculate new - let gFilt, qFilt; + // calculate new + let gFilt, qFilt; - for (e = 0; e < le; e++) { - for (i = RATE * te[e]; i < RATE * te[e + 1]; i++) { - if (hSL !== 0 && e !== la && e != laPrev) { - for (m = 0; m < M; m++) { - let idx1 = i + hSL; - gFilt = 0.0; - for (j = 0; j <= hSL; j++) { - gFilt += gTmp[idx1 - j][m] * SMOOTHING_FACTORS[j]; + for (e = 0; e < le; e++) { + for (i = RATE * te[e]; i < RATE * te[e + 1]; i++) { + if (hSL !== 0 && e !== la && e != laPrev) { + for (m = 0; m < M; m++) { + let idx1 = i + hSL; + gFilt = 0.0; + for (j = 0; j <= hSL; j++) { + gFilt += gTmp[idx1 - j][m] * SMOOTHING_FACTORS[j]; + } + Y[i][m + kx][0] = Xhigh[m + kx][i + T_HF_ADJ][0] * gFilt; + Y[i][m + kx][1] = Xhigh[m + kx][i + T_HF_ADJ][1] * gFilt; + } + } else { + for (m = 0; m < M; m++) { + gFilt = gTmp[i + hSL][m]; + Y[i][m + kx][0] = Xhigh[m + kx][i + T_HF_ADJ][0] * gFilt; + Y[i][m + kx][1] = Xhigh[m + kx][i + T_HF_ADJ][1] * gFilt; } - Y[i][m + kx][0] = Xhigh[m + kx][i + T_HF_ADJ][0] * gFilt; - Y[i][m + kx][1] = Xhigh[m + kx][i + T_HF_ADJ][1] * gFilt; - } - } else { - for (m = 0; m < M; m++) { - gFilt = gTmp[i + hSL][m]; - Y[i][m + kx][0] = Xhigh[m + kx][i + T_HF_ADJ][0] * gFilt; - Y[i][m + kx][1] = Xhigh[m + kx][i + T_HF_ADJ][1] * gFilt; } - } - if (e !== la && e !== laPrev) { - let phiSign = (1 - 2 * (kx & 1)); + if (e !== la && e !== laPrev) { + let phiSign = (1 - 2 * (kx & 1)); - for (m = 0; m < M; m++) { - if (p.Sm[e][m] !== 0) { - Y[i][m + kx][0] += p.Sm[e][m] * PHI[0][sineIndex]; - Y[i][m + kx][1] += p.Sm[e][m] * (PHI[1][sineIndex] * phiSign); - } else { - if (hSL !== 0) { - let idx1 = i + hSL; - qFilt = 0.0; - for (j = 0; j <= hSL; j++) { - qFilt += qTmp[idx1 - j][m] * SMOOTHING_FACTORS[j]; - } + for (m = 0; m < M; m++) { + if (this.Sm[e][m] !== 0) { + Y[i][m + kx][0] += this.Sm[e][m] * PHI[0][sineIndex]; + Y[i][m + kx][1] += this.Sm[e][m] * (PHI[1][sineIndex] * phiSign); } else { - qFilt = qTmp[i][m]; + if (hSL !== 0) { + let idx1 = i + hSL; + qFilt = 0.0; + for (j = 0; j <= hSL; j++) { + qFilt += qTmp[idx1 - j][m] * SMOOTHING_FACTORS[j]; + } + } else { + qFilt = qTmp[i][m]; + } + Y[i][m + kx][0] += qFilt * NOISE_TABLE[noiseIndex][0]; + Y[i][m + kx][1] += qFilt * NOISE_TABLE[noiseIndex][1]; } - Y[i][m + kx][0] += qFilt * NOISE_TABLE[noiseIndex][0]; - Y[i][m + kx][1] += qFilt * NOISE_TABLE[noiseIndex][1]; + phiSign = -phiSign; } - phiSign = -phiSign; - } - } else { - let phiSign = (1 - 2 * (kx & 1)); - for (m = 0; m < M; m++) { - Y[i][m + kx][0] += p.Sm[e][m] * PHI[0][sineIndex]; - Y[i][m + kx][1] += p.Sm[e][m] * (PHI[1][sineIndex] * phiSign); - phiSign = -phiSign; + } else { + let phiSign = (1 - 2 * (kx & 1)); + for (m = 0; m < M; m++) { + Y[i][m + kx][0] += this.Sm[e][m] * PHI[0][sineIndex]; + Y[i][m + kx][1] += this.Sm[e][m] * (PHI[1][sineIndex] * phiSign); + phiSign = -phiSign; - if (isNaN(Y[i][m + kx][0]) || isNaN(Y[i][m + kx][1])) { - console.log(p.Sm[e][m], PHI[0][sineIndex]); + if (isNaN(Y[i][m + kx][0]) || isNaN(Y[i][m + kx][1])) { + console.log(this.Sm[e][m], PHI[0][sineIndex]); + } } } - } - noiseIndex = (noiseIndex + 1) & 0x1ff; - sineIndex = (sineIndex + 1) & 3; + noiseIndex = (noiseIndex + 1) & 0x1ff; + sineIndex = (sineIndex + 1) & 3; + } } - } - cd.noiseIndex = noiseIndex; - cd.sineIndex = sineIndex; + cd.noiseIndex = noiseIndex; + cd.sineIndex = sineIndex; + } } const NOISE_TABLE = [ diff --git a/src/sbr/HFGenerator.js b/src/sbr/HFGenerator.js index 5812482..525eae1 100644 --- a/src/sbr/HFGenerator.js +++ b/src/sbr/HFGenerator.js @@ -13,188 +13,175 @@ const BW_COEFS = [ ]; const CHIRP_MIN = 0.015625; -// in: 32x40 complex Xlow, out: 32x40 complex Xhigh -export default function process(tables, cd, Xlow, Xhigh) { - // calculate chirp factors - let bwArray = calculateChirpFactors(tables, cd); - - // calculate inverse filter coefficients for bands 0-k0 - let k0 = tables.k0; - let alpha0 = makeArray([k0, 2]); - let alpha1 = makeArray([k0, 2]); - calculateIFCoefs(tables, alpha0, alpha1, Xlow); - - // HF generation - let patchCount = tables.patchCount; - let patchSubbands = tables.patchSubbands; - let patchStartSubband = tables.patchStartSubband; - let kx = tables.kx; - let m = tables.m; - let Nq = tables.nq; - let fNoise = tables.fNoise; - - let te = cd.te; - let start = RATE * te[0]; - let end = RATE * te[cd.envCount]; - - let alpha = new Float32Array(4); - let square; - let l, x; // loop indices - let k = kx; - let g = 0; - - for (let j = 0; j < patchCount; j++) { - for (x = 0; x < patchSubbands[j]; x++, k++) { - let p = patchStartSubband[j] + x; - while (g <= Nq && k >= fNoise[g]) { - g++; - } - g--; - - if (g < 0) { - throw new Error("SBR: HFGenerator: no subband found for frequency " + k); - } - - // fill Xhigh[k] (4.6.18.6.3) - square = bwArray[g] * bwArray[g]; - alpha[0] = alpha1[p][0] * square; - alpha[1] = alpha1[p][1] * square; - alpha[2] = alpha0[p][0] * bwArray[g]; - alpha[3] = alpha0[p][1] * bwArray[g]; - for (l = start; l < end; l++) { - let off = l + T_HF_ADJ; - Xhigh[k][off][0] = alpha[0] * Xlow[p][off - 2][0] - - alpha[1] * Xlow[p][off - 2][1] - + alpha[2] * Xlow[p][off - 1][0] - - alpha[3] * Xlow[p][off - 1][1] - + Xlow[p][off][0]; +export default class HFGenerator { + constructor() { + this.alpha0 = makeArray([64, 2]); + this.alpha1 = makeArray([64, 2]); + this.alpha = new Float32Array(4); + this.phi = makeArray([3, 2, 2]); + } + + // in: 32x40 complex Xlow, out: 32x40 complex Xhigh + process(tables, cd, Xlow, Xhigh) { + // calculate chirp factors + let bwArray = this.calculateChirpFactors(tables, cd); + + // calculate inverse filter coefficients for bands 0-k0 + let k0 = tables.k0; + let alpha0 = this.alpha0; + let alpha1 = this.alpha1; + this.calculateIFCoefs(tables, alpha0, alpha1, Xlow); + + // HF generation + let patchCount = tables.patchCount; + let patchSubbands = tables.patchSubbands; + let patchStartSubband = tables.patchStartSubband; + let kx = tables.kx; + let m = tables.m; + let Nq = tables.nq; + let fNoise = tables.fNoise; + + let te = cd.te; + let start = RATE * te[0]; + let end = RATE * te[cd.envCount]; + + let alpha = this.alpha; + let square; + let l, x; // loop indices + let k = kx; + let g = 0; + + for (let j = 0; j < patchCount; j++) { + for (x = 0; x < patchSubbands[j]; x++, k++) { + let p = patchStartSubband[j] + x; + while (g <= Nq && k >= fNoise[g]) { + g++; + } + g--; + + if (g < 0) { + throw new Error("SBR: HFGenerator: no subband found for frequency " + k); + } + + // fill Xhigh[k] (4.6.18.6.3) + square = bwArray[g] * bwArray[g]; + alpha[0] = alpha1[p][0] * square; + alpha[1] = alpha1[p][1] * square; + alpha[2] = alpha0[p][0] * bwArray[g]; + alpha[3] = alpha0[p][1] * bwArray[g]; + for (l = start; l < end; l++) { + let off = l + T_HF_ADJ; + Xhigh[k][off][0] = alpha[0] * Xlow[p][off - 2][0] + - alpha[1] * Xlow[p][off - 2][1] + + alpha[2] * Xlow[p][off - 1][0] + - alpha[3] * Xlow[p][off - 1][1] + + Xlow[p][off][0]; - Xhigh[k][off][1] = alpha[0] * Xlow[p][off - 2][1] - + alpha[1] * Xlow[p][off - 2][0] - + alpha[2] * Xlow[p][off - 1][1] - + alpha[3] * Xlow[p][off - 1][0] - + Xlow[p][off][1]; + Xhigh[k][off][1] = alpha[0] * Xlow[p][off - 2][1] + + alpha[1] * Xlow[p][off - 2][0] + + alpha[2] * Xlow[p][off - 1][1] + + alpha[3] * Xlow[p][off - 1][0] + + Xlow[p][off][1]; + } } } - } - // fill remaining with zero - while (k < m + kx) { - for (let j = 0; j < Xhigh[k].length; j++) { - Xhigh[k][j][0] = 0; - Xhigh[k][j][1] = 0; + // fill remaining with zero + while (k < m + kx) { + for (let j = 0; j < Xhigh[k].length; j++) { + Xhigh[k][j][0] = 0; + Xhigh[k][j][1] = 0; + } + k++; } - k++; } -} -function calculateChirpFactors(tables, cd) { - //calculates chirp factors and replaces old ones in ChannelData - let nq = tables.nq; - let invfMode = cd.invfMode; - let invfModePrevious = cd.invfModePrevious; - let bwArray = cd.bwArray; - - let tmp; - let chirpCoefs; - for (let i = 0; i < nq; i++) { - tmp = BW_COEFS[invfModePrevious[i]][invfMode[i]]; - chirpCoefs = tmp < bwArray[i] ? CHIRP_COEFS[0] : CHIRP_COEFS[1]; - bwArray[i] = (chirpCoefs[0] * tmp) + (chirpCoefs[1] * bwArray[i]); - if (bwArray[i] < CHIRP_MIN) { - bwArray[i] = 0; + calculateChirpFactors(tables, cd) { + //calculates chirp factors and replaces old ones in ChannelData + let nq = tables.nq; + let invfMode = cd.invfMode; + let invfModePrevious = cd.invfModePrevious; + let bwArray = cd.bwArray; + + let tmp; + let chirpCoefs; + for (let i = 0; i < nq; i++) { + tmp = BW_COEFS[invfModePrevious[i]][invfMode[i]]; + chirpCoefs = tmp < bwArray[i] ? CHIRP_COEFS[0] : CHIRP_COEFS[1]; + bwArray[i] = (chirpCoefs[0] * tmp) + (chirpCoefs[1] * bwArray[i]); + if (bwArray[i] < CHIRP_MIN) { + bwArray[i] = 0; + } } - } - return bwArray; -} + return bwArray; + } -// calculates inverse filter coefficients for bands 0-k0 (4.6.18.6.2) -function calculateIFCoefs(tables, alpha0, alpha1, Xlow) { - let k0 = tables.k0; - let tmp = new Float32Array(2); - - let phi = makeArray([3, 2, 2]); - let d; - for (let k = 0; k < k0; k++) { - //get covariance matrix - getCovarianceMatrix(Xlow[k], phi, 0); - // getCovarianceMatrix(Xlow[k], phi, 1); - // getCovarianceMatrix(Xlow[k], phi, 2); - - // d(k) - d = phi[2][1][0] * phi[1][0][0] - (phi[1][1][0] * phi[1][1][0] + phi[1][1][1] * phi[1][1][1]) / RELAX_COEF; - - // alpha1 - if (d === 0) { - alpha1[k][0] = 0; - alpha1[k][1] = 0; - } else { - tmp[0] = phi[0][0][0] * phi[1][1][0] - phi[0][0][1] * phi[1][1][1] - phi[0][1][0] * phi[1][0][0]; - tmp[1] = phi[0][0][0] * phi[1][1][1] + phi[0][0][1] * phi[1][1][0] - phi[0][1][1] * phi[1][0][0]; - alpha1[k][0] = tmp[0] / d; - alpha1[k][1] = tmp[1] / d; - } + // calculates inverse filter coefficients for bands 0-k0 (4.6.18.6.2) + calculateIFCoefs(tables, alpha0, alpha1, Xlow) { + let k0 = tables.k0; + let tmp0, tmp1; + + let phi = this.phi; + let d; + for (let k = 0; k < k0; k++) { + //get covariance matrix + this.getCovarianceMatrix(Xlow[k], phi); + + // d(k) + d = phi[2][1][0] * phi[1][0][0] - (phi[1][1][0] * phi[1][1][0] + phi[1][1][1] * phi[1][1][1]) / RELAX_COEF; + + // alpha1 + if (d === 0) { + alpha1[k][0] = 0; + alpha1[k][1] = 0; + } else { + tmp0 = phi[0][0][0] * phi[1][1][0] - phi[0][0][1] * phi[1][1][1] - phi[0][1][0] * phi[1][0][0]; + tmp1 = phi[0][0][0] * phi[1][1][1] + phi[0][0][1] * phi[1][1][0] - phi[0][1][1] * phi[1][0][0]; + alpha1[k][0] = tmp0 / d; + alpha1[k][1] = tmp1 / d; + } - // alpha0 - if(phi[1][0][0] === 0) { - alpha0[k][0] = 0; - alpha0[k][1] = 0; - } else { - tmp[0] = phi[0][0][0] + alpha1[k][0] * phi[1][1][0] + alpha1[k][1] * phi[1][1][1]; - tmp[1] = phi[0][0][1] + alpha1[k][1] * phi[1][1][0] - alpha1[k][0] * phi[1][1][1]; - alpha0[k][0] = -tmp[0] / phi[1][0][0]; - alpha0[k][1] = -tmp[1] / phi[1][0][0]; - } + // alpha0 + if(phi[1][0][0] === 0) { + alpha0[k][0] = 0; + alpha0[k][1] = 0; + } else { + tmp0 = phi[0][0][0] + alpha1[k][0] * phi[1][1][0] + alpha1[k][1] * phi[1][1][1]; + tmp1 = phi[0][0][1] + alpha1[k][1] * phi[1][1][0] - alpha1[k][0] * phi[1][1][1]; + alpha0[k][0] = -tmp0 / phi[1][0][0]; + alpha0[k][1] = -tmp1 / phi[1][0][0]; + } - if (alpha1[k][0] * alpha1[k][0] + alpha1[k][1] * alpha1[k][1] >= ALPHA_MAX - || alpha0[k][0] * alpha0[k][0] + alpha0[k][1] * alpha0[k][1] >= ALPHA_MAX) { - alpha1[k][0] = 0; - alpha1[k][1] = 0; - alpha0[k][0] = 0; - alpha0[k][1] = 0; + if (alpha1[k][0] * alpha1[k][0] + alpha1[k][1] * alpha1[k][1] >= ALPHA_MAX + || alpha0[k][0] * alpha0[k][0] + alpha0[k][1] * alpha0[k][1] >= ALPHA_MAX) { + alpha1[k][0] = 0; + alpha1[k][1] = 0; + alpha0[k][0] = 0; + alpha0[k][1] = 0; + } } } -} -// calculates covariance matrix (4.6.18.6.2) -function getCovarianceMatrix(x, phi, off) { - // let sum = new Float32Array(2); - // if (off === 0) { - // for (let i = 1; i < 38; i++) { - // sum[0] += x[i][0] * x[i][0] + x[i][1] * x[i][1]; - // } - // phi[2][1][0] = sum[0] + x[0][0] * x[0][0] + x[0][1] * x[0][1]; - // phi[1][0][0] = sum[0] + x[38][0] * x[38][0] + x[38][1] * x[38][1]; - // } else { - // for (let i = 1; i < 38; i++) { - // sum[0] += x[i][0] * x[i + off][0] + x[i][1] * x[i + off][1]; - // sum[1] += x[i][0] * x[i + off][1] - x[i][1] * x[i + off][0]; - // } - // phi[2 - off][1][0] = sum[0] + x[0][0] * x[off][0] + x[0][1] * x[off][1]; - // phi[2 - off][1][1] = sum[1] + x[0][0] * x[off][1] - x[0][1] * x[off][0]; - // if (off === 1) { - // phi[0][0][0] = sum[0] + x[38][0] * x[39][0] + x[38][1] * x[39][1]; - // phi[0][0][1] = sum[1] + x[38][0] * x[39][1] - x[38][1] * x[39][0]; - // } - // } - - let real_sum2 = x[0][0] * x[2][0] + x[0][1] * x[2][1]; - let imag_sum2 = x[0][0] * x[2][1] - x[0][1] * x[2][0]; - let real_sum1 = 0.0, imag_sum1 = 0.0, real_sum0 = 0.0; - for (let i = 1; i < 38; i++) { - real_sum0 += x[i][0] * x[i ][0] + x[i][1] * x[i ][1]; - real_sum1 += x[i][0] * x[i + 1][0] + x[i][1] * x[i + 1][1]; - imag_sum1 += x[i][0] * x[i + 1][1] - x[i][1] * x[i + 1][0]; - real_sum2 += x[i][0] * x[i + 2][0] + x[i][1] * x[i + 2][1]; - imag_sum2 += x[i][0] * x[i + 2][1] - x[i][1] * x[i + 2][0]; + // calculates covariance matrix (4.6.18.6.2) + getCovarianceMatrix(x, phi) { + let real_sum2 = x[0][0] * x[2][0] + x[0][1] * x[2][1]; + let imag_sum2 = x[0][0] * x[2][1] - x[0][1] * x[2][0]; + let real_sum1 = 0.0, imag_sum1 = 0.0, real_sum0 = 0.0; + for (let i = 1; i < 38; i++) { + real_sum0 += x[i][0] * x[i ][0] + x[i][1] * x[i ][1]; + real_sum1 += x[i][0] * x[i + 1][0] + x[i][1] * x[i + 1][1]; + imag_sum1 += x[i][0] * x[i + 1][1] - x[i][1] * x[i + 1][0]; + real_sum2 += x[i][0] * x[i + 2][0] + x[i][1] * x[i + 2][1]; + imag_sum2 += x[i][0] * x[i + 2][1] - x[i][1] * x[i + 2][0]; + } + phi[2 - 2][1][0] = real_sum2; + phi[2 - 2][1][1] = imag_sum2; + phi[2 ][1][0] = real_sum0 + x[ 0][0] * x[ 0][0] + x[ 0][1] * x[ 0][1]; + phi[1 ][0][0] = real_sum0 + x[38][0] * x[38][0] + x[38][1] * x[38][1]; + phi[2 - 1][1][0] = real_sum1 + x[ 0][0] * x[ 1][0] + x[ 0][1] * x[ 1][1]; + phi[2 - 1][1][1] = imag_sum1 + x[ 0][0] * x[ 1][1] - x[ 0][1] * x[ 1][0]; + phi[0 ][0][0] = real_sum1 + x[38][0] * x[39][0] + x[38][1] * x[39][1]; + phi[0 ][0][1] = imag_sum1 + x[38][0] * x[39][1] - x[38][1] * x[39][0]; } - phi[2 - 2][1][0] = real_sum2; - phi[2 - 2][1][1] = imag_sum2; - phi[2 ][1][0] = real_sum0 + x[ 0][0] * x[ 0][0] + x[ 0][1] * x[ 0][1]; - phi[1 ][0][0] = real_sum0 + x[38][0] * x[38][0] + x[38][1] * x[38][1]; - phi[2 - 1][1][0] = real_sum1 + x[ 0][0] * x[ 1][0] + x[ 0][1] * x[ 1][1]; - phi[2 - 1][1][1] = imag_sum1 + x[ 0][0] * x[ 1][1] - x[ 0][1] * x[ 1][0]; - phi[0 ][0][0] = real_sum1 + x[38][0] * x[39][0] + x[38][1] * x[39][1]; - phi[0 ][0][1] = imag_sum1 + x[38][0] * x[39][1] - x[38][1] * x[39][0]; } diff --git a/src/sbr/sbr.js b/src/sbr/sbr.js index fda0075..26f8419 100644 --- a/src/sbr/sbr.js +++ b/src/sbr/sbr.js @@ -29,6 +29,8 @@ class SBR { this.qmfA = new AnalysisFilterbank; this.qmfS = new SynthesisFilterbank; + this.hfGen = new HFGenerator; + this.hfAdj = new HFAdjuster; this.X = makeArray([2, 64, 38, 2]); this.Xlow = makeArray([32, 40, 2]); @@ -258,10 +260,10 @@ class SBR { // } // 4. HF generation (Xlow -> Xhigh) - HFGenerator(this.tables, this.cd[ch], this.Xlow, this.Xhigh); + this.hfGen.process(this.tables, this.cd[ch], this.Xlow, this.Xhigh); // 6. HF adjustment (Xhigh -> Y) - HFAdjuster(this.header, this.tables, this.cd[ch], this.Xhigh, this.cd[ch].Y[this.cd[ch].Ypos]); + this.hfAdj.process(this.header, this.tables, this.cd[ch], this.Xhigh, this.cd[ch].Y[this.cd[ch].Ypos]); // 5. old Y -> X let lTemp = this.cd[ch].lTemp; From b794db12c58ea747532d731c470f9db6b2a3d819 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Fri, 8 Jul 2016 14:38:30 -0700 Subject: [PATCH 03/19] [SBR] Use flattened multidimensional typed arrays Much faster than arrays of arrays of arrays... Using [babel-plugin-multidimensional-array](https://github.com/devongovett/babel-plugin-multidimensional-array) for compilation. --- .babelrc | 4 + src/sbr/AnalysisFilterbank.js | 29 +++-- src/sbr/ChannelData.js | 83 ++++++--------- src/sbr/FrequencyTables.js | 44 ++++---- src/sbr/HFAdjuster.js | 110 ++++++++++--------- src/sbr/HFGenerator.js | 49 +++++---- src/sbr/SynthesisFilterbank.js | 26 ++--- src/sbr/constants.js | 33 +----- src/sbr/sbr.js | 188 +++++++++++++++------------------ src/sbr/utils.js | 16 --- 10 files changed, 253 insertions(+), 329 deletions(-) create mode 100644 .babelrc delete mode 100644 src/sbr/utils.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..d097c81 --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["es2015"], + "plugins": ["multidimensional-array"] +} diff --git a/src/sbr/AnalysisFilterbank.js b/src/sbr/AnalysisFilterbank.js index 61a13c0..7fb0378 100644 --- a/src/sbr/AnalysisFilterbank.js +++ b/src/sbr/AnalysisFilterbank.js @@ -1,44 +1,43 @@ -import {makeArray} from './utils'; import {TIME_SLOTS_RATE, WINDOW} from './constants'; export default class AnalysisFilterbank { constructor() { - this.X = makeArray([2, 320]); + this.X = new Float32Array(2 * 320); this.z = new Float32Array(320); this.u = new Float32Array(64); - this.COEFS = makeArray([32, 64, 2]); + let COEFS[32][64][2] = this.COEFS = new Float32Array(32 * 64 * 2); let tmp; for (let k = 0; k < 32; k++) { for (let n = 0; n < 64; n++) { tmp = Math.PI / 64.0 * (k + 0.5) * (2 * n - 0.5); - this.COEFS[k][n][0] = 2 * Math.cos(tmp); - this.COEFS[k][n][1] = 2 * Math.sin(tmp); + COEFS[k][n][0] = 2 * Math.cos(tmp); + COEFS[k][n][1] = 2 * Math.sin(tmp); } } } // in: 1024 time samples, out: 32 x 32 complex - process(inp, out, ch) { - let x = this.X[ch]; + process(inp, out[2][32][32][2], ch) { + let COEFS[32][64][2] = this.COEFS; + let x[2][320] = this.X; let n, k, inOff = 0; // each loop creates 32 complex subband samples for (let l = 0; l < TIME_SLOTS_RATE; l++) { // 1. shift buffer for (n = 319; n >= 32; n--) { - x[n] = x[n - 32]; + x[ch][n] = x[ch][n - 32]; } // 2. add new samples for (n = 31; n >= 0; n--) { - x[n] = inp[inOff]; - inOff++; + x[ch][n] = inp[inOff++]; } // 3. windowing for (n = 0; n < 320; n++) { - this.z[n] = x[n] * WINDOW[2 * n]; + this.z[n] = x[ch][n] * WINDOW[2 * n]; } // 4. sum samples @@ -51,11 +50,11 @@ export default class AnalysisFilterbank { // 5. calculate subband samples, TODO: replace with FFT? for (k = 0; k < 32; k++) { - out[l][k][0] = this.u[0] * this.COEFS[k][0][0]; - out[l][k][1] = this.u[0] * this.COEFS[k][0][1]; + out[ch][l][k][0] = this.u[0] * COEFS[k][0][0]; + out[ch][l][k][1] = this.u[0] * COEFS[k][0][1]; for (n = 1; n < 64; n++) { - out[l][k][0] += this.u[n] * this.COEFS[k][n][0]; - out[l][k][1] += this.u[n] * this.COEFS[k][n][1]; + out[ch][l][k][0] += this.u[n] * COEFS[k][n][0]; + out[ch][l][k][1] += this.u[n] * COEFS[k][n][1]; } } } diff --git a/src/sbr/ChannelData.js b/src/sbr/ChannelData.js index 7362516..4191c12 100644 --- a/src/sbr/ChannelData.js +++ b/src/sbr/ChannelData.js @@ -1,29 +1,19 @@ import * as HuffmanTables from './HuffmanTables'; -import {makeArray} from './utils'; -import {TIME_SLOTS_RATE} from './constants'; +import {TIME_SLOTS, RATE, TIME_SLOTS_RATE, MAX_BANDS} from './constants'; const MAX_ENV_COUNT = 5; const MAX_NQ = 5; const MAX_NOISE_COUNT = 2; -const MAX_BANDS = 64; const MAX_CHIRP_FACTORS = 5; -const TIME_SLOTS = 16; // TODO: 15 for 960-sample frames - // frame classes const FIXFIX = 0; const FIXVAR = 1; const VARFIX = 2; const VARVAR = 3; -const HIGH = 1; -const LOW = 0; - -//CEIL_LOG[i] = Math.ceil(Math.log(i+1)/Math.log(2)) +// CEIL_LOG[i] = Math.ceil(Math.log(i+1)/Math.log(2)) const CEIL_LOG2 = new Uint8Array([0, 1, 2, 2, 3, 3]); -const MAX_LTEMP = 6; - -const RATE = 2; export default class ChannelData { constructor() { @@ -34,15 +24,15 @@ export default class ChannelData { this.dfEnv = new Uint8Array(MAX_ENV_COUNT); this.dfNoise = new Uint8Array(MAX_NOISE_COUNT); - this.envelopeSFQ = makeArray([MAX_ENV_COUNT, MAX_BANDS], Uint8Array); - this.envelopeSFQPrevious = new Uint8Array(MAX_BANDS); - this.envelopeSF = makeArray([MAX_ENV_COUNT, MAX_BANDS]); + // previous is stored in envelopeSFQ[0] + this.envelopeSFQ = new Uint8Array((MAX_ENV_COUNT + 1) * MAX_BANDS); + this.envelopeSF = new Float32Array(MAX_ENV_COUNT * MAX_BANDS); this.te = new Uint8Array(MAX_ENV_COUNT + 1); this.tePrevious = 0; - this.noiseFloorDataQ = makeArray([MAX_NOISE_COUNT, MAX_BANDS], Uint8Array); - this.noiseFDPrevious = new Float32Array(MAX_BANDS); - this.noiseFloorData = makeArray([MAX_NOISE_COUNT, MAX_BANDS]); + // previous is stored in noiseFloorDataQ[0] + this.noiseFloorDataQ = new Uint8Array((MAX_NOISE_COUNT + 1) * MAX_BANDS); + this.noiseFloorData = new Float32Array(MAX_NOISE_COUNT * MAX_BANDS); this.tq = new Uint8Array(MAX_NOISE_COUNT + 1); this.sinusoidals = new Uint8Array(MAX_BANDS); @@ -51,9 +41,8 @@ export default class ChannelData { this.bwArray = new Float32Array(MAX_CHIRP_FACTORS); this.lTemp = 0; - // TODO: check sizes! - this.gTmp = makeArray([42, 48]); - this.qTmp = makeArray([42, 48]); + this.gTmp = new Float32Array(42 * 48); + this.qTmp = new Float32Array(42 * 48); // grid this.ampRes = 0; @@ -65,10 +54,6 @@ export default class ChannelData { this.la = 0; this.laPrevious = 0; - this.W = makeArray([2, TIME_SLOTS_RATE, TIME_SLOTS_RATE, 2]); - this.Y = makeArray([2, 38 + MAX_LTEMP, 64, 2]); - this.Ypos = 0; - this.noiseIndex = 0; this.sineIndex = 0; } @@ -254,56 +239,55 @@ export default class ChannelData { // read delta coded huffman data let envBands = tables.n; let odd = envBands[1] & 1; + let envelopeSFQ[6][48] = this.envelopeSFQ; let j, k, frPrev; - let prev; for (let i = 0; i < this.envCount; i++) { - prev = i === 0 ? this.envelopeSFQPrevious : this.envelopeSFQ[i - 1]; frPrev = i === 0 ? this.freqResPrevious : this.freqRes[i - 1]; if (this.dfEnv[i]) { if (this.freqRes[i] === frPrev) { for (j = 0; j < envBands[this.freqRes[i]]; j++) { - this.envelopeSFQ[i][j] = prev[j] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); - if (this.envelopeSFQ[i][j] > 127) { - console.log("OUT OF BOUNDS", this.envelopeSFQ[i][j], i, prev[j], delta, tLav) + envelopeSFQ[i + 1][j] = envelopeSFQ[i][j] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); + if (envelopeSFQ[i + 1][j] > 127) { + console.log("OUT OF BOUNDS", envelopeSFQ[i + 1][j], i, envelopeSFQ[i][j], delta, tLav) } } } else if (this.freqRes[i] !== 0) { for (j = 0; j < envBands[this.freqRes[i]]; j++) { k = (j + odd) >> 1; //fLow[k] <= fHigh[j] < fLow[k + 1] - this.envelopeSFQ[i][j] = prev[k] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); - if (this.envelopeSFQ[i][j] > 127) { - console.log("OUT OF BOUNDS 2", this.envelopeSFQ[i][j], i, k, prev[k], delta, tLav) + envelopeSFQ[i + 1][j] = envelopeSFQ[i][k] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); + if (envelopeSFQ[i + 1][j] > 127) { + console.log("OUT OF BOUNDS 2", envelopeSFQ[i + 1][j], i, k, envelopeSFQ[i][k], delta, tLav) } } } else { for (j = 0; j < envBands[this.freqRes[i]]; j++) { k = j !== 0 ? (2 * j - odd) : 0; //fHigh[k] == fLow[j] - this.envelopeSFQ[i][j] = prev[k] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); - if (this.envelopeSFQ[i][j] > 127) { - console.log("OUT OF BOUNDS 3", this.envelopeSFQ[i][j], i, k, prev[k], delta, tLav) + envelopeSFQ[i + 1][j] = envelopeSFQ[i][k] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); + if (envelopeSFQ[i + 1][j] > 127) { + console.log("OUT OF BOUNDS 3", envelopeSFQ[i + 1][j], i, k, envelopeSFQ[i][k], delta, tLav) } } } } else { - this.envelopeSFQ[i][0] = stream.read(bits) << delta; - if (this.envelopeSFQ[i][0] > 127) { - console.log("OUT OF BOUNDS 5", this.envelopeSFQ[i][0], delta) + envelopeSFQ[i + 1][0] = stream.read(bits) << delta; + if (envelopeSFQ[i + 1][0] > 127) { + console.log("OUT OF BOUNDS 5", envelopeSFQ[i + 1][0], delta) } for (j = 1; j < envBands[this.freqRes[i]]; j++) { - this.envelopeSFQ[i][j] = this.envelopeSFQ[i][j - 1] + ((this.decodeHuffman(stream, fHuff) - fLav) << delta); - if (this.envelopeSFQ[i][j] > 127) { - console.log("OUT OF BOUNDS 4", this.envelopeSFQ[i][j], this.envelopeSFQ[i][j - 1], delta, tLav) + envelopeSFQ[i + 1][j] = envelopeSFQ[i + 1][j - 1] + ((this.decodeHuffman(stream, fHuff) - fLav) << delta); + if (envelopeSFQ[i + 1][j] > 127) { + console.log("OUT OF BOUNDS 4", envelopeSFQ[i + 1][j], envelopeSFQ[i + 1][j - 1], delta, tLav) } } } } // save for next frame - this.envelopeSFQPrevious.set(this.envelopeSFQ[this.envCount - 1]) + envelopeSFQ[0].set(envelopeSFQ[this.envCount]); } decodeHuffman(stream, table) { @@ -342,30 +326,29 @@ export default class ChannelData { // read huffman data: i=noise, j=band let noiseBands = tables.nq; + let noiseFloorDataQ[3][64] = this.noiseFloorDataQ; let j; - let prev; for (let i = 0; i < this.noiseCount; i++) { if (this.dfNoise[i]) { - prev = i === 0 ? this.noiseFDPrevious : this.noiseFloorDataQ[i - 1]; for (j = 0; j < noiseBands; j++) { - this.noiseFloorDataQ[i][j] = prev[j] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); + noiseFloorDataQ[i + 1][j] = noiseFloorDataQ[i][j] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); } } else { - this.noiseFloorDataQ[i][0] = stream.read(5) << delta; + noiseFloorDataQ[i + 1][0] = stream.read(5) << delta; for (j = 1; j < noiseBands; j++) { - this.noiseFloorDataQ[i][j] = this.noiseFloorDataQ[i][j - 1] + ((this.decodeHuffman(stream, fHuff) - fLav) << delta); + noiseFloorDataQ[i + 1][j] = noiseFloorDataQ[i + 1][j - 1] + ((this.decodeHuffman(stream, fHuff) - fLav) << delta); } } } //save for next frame - this.noiseFDPrevious.set(this.noiseFloorDataQ[this.noiseCount - 1]); + noiseFloorDataQ[0].set(noiseFloorDataQ[this.noiseCount]); } decodeSinusoidal(stream, header, tables) { if (this.sinusoidalsPresent = stream.read(1)) { - for (let i = 0; i < tables.n[HIGH]; i++) { + for (let i = 0; i < tables.n[1]; i++) { this.sinusoidals[i] = stream.read(1); } } else { diff --git a/src/sbr/FrequencyTables.js b/src/sbr/FrequencyTables.js index 61ea06b..0a2ab3c 100644 --- a/src/sbr/FrequencyTables.js +++ b/src/sbr/FrequencyTables.js @@ -1,10 +1,8 @@ -var tables = require('../tables'); +import tables from '../tables'; +import {MAX_BANDS} from './constants'; const MAX_PATCHES = 6; -const MAX_BANDS = 64; const LOG2 = Math.log(2); -const HIGH = 1; -const LOW = 0; const MFT_START_MIN = new Uint8Array([7, 7, 10, 11, 12, 16, 16, 17, 24]); const MFT_STOP_MIN = new Uint8Array([13, 15, 20, 21, 23, 32, 32, 35, 48]); @@ -204,25 +202,25 @@ export default class FrequencyTables { calculateFrequencyTables(header) { let xover = header.xOverBand; - this.n[HIGH] = this.nMaster - xover; - this.n[LOW] = (this.n[HIGH] + 1) >> 1; - this.fTable[HIGH] = new Int32Array(this.n[HIGH] + 1); - this.fTable[HIGH].set(this.mft, xover); + this.n[1] = this.nMaster - xover; + this.n[0] = (this.n[1] + 1) >> 1; + this.fTable[1] = new Int32Array(this.n[1] + 1); + this.fTable[1].set(this.mft, xover); this.kxPrev = this.kx; - this.kx = this.fTable[HIGH][0]; + this.kx = this.fTable[1][0]; this.mPrev = this.m; - this.m = this.fTable[HIGH][this.n[HIGH]] - this.kx; + this.m = this.fTable[1][this.n[1]] - this.kx; // check requirements (4.6.18.3.6): if (this.kx > 32) throw new Error("SBR: start frequency border out of range: " + this.kx); if ((this.kx + this.m) > 64) throw new Error("SBR: stop frequency border out of range: " + (this.kx + this.m)); - this.fTable[LOW] = new Int32Array(this.n[LOW] + 1); - this.fTable[LOW][0] = this.fTable[HIGH][0]; - let div = this.n[HIGH] & 1; - for (let i = 1; i <= this.n[LOW]; i++) { - this.fTable[LOW][i] = this.fTable[HIGH][2 * i - div]; + this.fTable[0] = new Int32Array(this.n[0] + 1); + this.fTable[0][0] = this.fTable[1][0]; + let div = this.n[1] & 1; + for (let i = 1; i <= this.n[0]; i++) { + this.fTable[0][i] = this.fTable[1][2 * i - div]; } } @@ -235,11 +233,11 @@ export default class FrequencyTables { if (this.nq > 5) throw new Error("SBR: too many noise floor scalefactors: " + this.nq); this.fNoise = new Int32Array(this.nq + 1); - this.fNoise[0] = this.fTable[LOW][0]; + this.fNoise[0] = this.fTable[0][0]; let i = 0; for (let k = 1; k <= this.nq; k++) { - i += ((this.n[LOW] - i) / (this.nq + 1 - k)) | 0; - this.fNoise[k] = this.fTable[LOW][i]; + i += ((this.n[0] - i) / (this.nq + 1 - k)) | 0; + this.fNoise[k] = this.fTable[0][i]; } } @@ -296,7 +294,7 @@ export default class FrequencyTables { // calculation of fTableLim (figure 4.40, p.213) let bands = header.limiterBands; if (bands == 0) { - this.fLim = new Int32Array([this.fTable[LOW][0], this.fTable[LOW][this.n[LOW]]]); + this.fLim = new Int32Array([this.fTable[0][0], this.fTable[0][this.n[0]]]); this.nl = 1; this.patchBorders = new Int32Array(0); } else { @@ -308,17 +306,17 @@ export default class FrequencyTables { this.patchBorders[i] = this.patchBorders[i - 1] + this.patchSubbands[i - 1]; } - let limTable = new Int32Array(this.n[LOW] + this.patchCount); - limTable.set(this.fTable[LOW].subarray(0, this.n[LOW] + 1)); + let limTable = new Int32Array(this.n[0] + this.patchCount); + limTable.set(this.fTable[0].subarray(0, this.n[0] + 1)); if (this.patchCount > 1) { - limTable.set(this.patchBorders.subarray(1, this.patchCount), this.n[LOW] + 1); + limTable.set(this.patchBorders.subarray(1, this.patchCount), this.n[0] + 1); } limTable.sort(); let inp = 1; let out = 0; - let lims = this.n[LOW] + this.patchCount - 1; + let lims = this.n[0] + this.patchCount - 1; while (out < lims) { if (limTable[inp] >= limTable[out] * limBandsPerOctaveWarped) { limTable[++out] = limTable[inp++]; diff --git a/src/sbr/HFAdjuster.js b/src/sbr/HFAdjuster.js index 350ae8a..82a3d0e 100644 --- a/src/sbr/HFAdjuster.js +++ b/src/sbr/HFAdjuster.js @@ -1,5 +1,4 @@ -import {HIGH, RATE, T_HF_ADJ} from './constants'; -import {makeArray} from './utils'; +import {RATE, T_HF_ADJ} from './constants'; const LIMITER_GAINS = [0.70795, 1.0, 1.41254, 10000000000]; const EPSILON = 1.0; @@ -20,21 +19,21 @@ const MAX_GAIN = 100000; export default class HFAdjuster { constructor() { - this.eMapped = makeArray([7, 48]); - this.qMapped = makeArray([7, 48]); - this.sIndexMapped = makeArray([7, 48], Uint8Array); - this.sMapped = makeArray([7, 48], Uint8Array); - this.eCurr = makeArray([7, 48]); - this.Qm = makeArray([7, 48]); - this.Sm = makeArray([7, 48]); - this.gain = makeArray([7, 48]); + this.eMapped = new Float32Array(7 * 48); + this.qMapped = new Float32Array(7 * 48); + this.sIndexMapped = new Uint8Array(7 * 48); + this.sMapped = new Uint8Array(7 * 48); + this.eCurr = new Float32Array(7 * 48); + this.Qm = new Float32Array(7 * 48); + this.Sm = new Float32Array(7 * 48); + this.gain = new Float32Array(7 * 48); } - process(header, tables, cd, Xhigh, Y) { + process(header, tables, cd, Xhigh, Y, ch) { this.map(tables, cd); this.estimateEnvelopes(header, tables, cd, Xhigh); this.calculateGain(header, tables, cd); - this.assembleSignals(header, tables, cd, Xhigh, Y); + this.assembleSignals(header, tables, cd, Xhigh, Y, ch); } // mapping of dequantized values (4.6.18.7.2) @@ -42,8 +41,8 @@ export default class HFAdjuster { // parameter from FrequencyTables let kx = tables.kx; let noiseTable = tables.fNoise; - let fHigh = tables.fTable[HIGH]; - let nHigh = tables.n[HIGH]; + let fHigh = tables.fTable[1]; + let nHigh = tables.n[1]; let M = tables.m; let nq = tables.nq; @@ -54,14 +53,14 @@ export default class HFAdjuster { let la = cd.la; //input and output arrays - let eOrig = cd.envelopeSF; - let eMapped = this.eMapped; - let qOrig = cd.noiseFloorData; - let qMapped = this.qMapped; + let eOrig[5][48] = cd.envelopeSF; + let eMapped[7][48] = this.eMapped; + let qOrig[2][64] = cd.noiseFloorData; + let qMapped[7][48] = this.qMapped; let sinusoidals = cd.sinusoidals; let sIndexMappedPrev = cd.sIndexMappedPrevious; - let sIndexMapped = this.sIndexMapped; - let sMapped = this.sMapped; + let sIndexMapped[7][48] = this.sIndexMapped; + let sMapped[7][48] = this.sMapped; // tmp integer let fr, maxI, k, i, m; @@ -118,12 +117,12 @@ export default class HFAdjuster { } // envelope estimation (4.6.18.7.3) - estimateEnvelopes(header, tables, cd, Xhigh) { + estimateEnvelopes(header, tables, cd, Xhigh[64][40][2]) { let te = cd.te; let M = tables.m; let kx = tables.kx; let le = cd.envCount; - let eCurr = this.eCurr; + let eCurr[7][48] = this.eCurr; let sum; let e, m, i, iLow, iHigh; @@ -193,10 +192,14 @@ export default class HFAdjuster { let le = cd.envCount; // output arrays - let Qm = this.Qm; - let Sm = this.Sm; - let gain = this.gain; - let eCurr = this.eCurr; + let Qm[7][48] = this.Qm; + let Sm[7][48] = this.Sm; + let gain[7][48] = this.gain; + let eCurr[7][48] = this.eCurr; + let eMapped[7][48] = this.eMapped; + let sMapped[7][48] = this.sMapped; + let qMapped[7][48] = this.qMapped; + let sIndexMapped[7][48] = this.sIndexMapped; let delta, delta2; let m, k, i; @@ -212,20 +215,20 @@ export default class HFAdjuster { // level of additional HF components + gain for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { - tmp = this.eMapped[e][m] / (1.0 + this.qMapped[e][m]); - Qm[e][m] = Math.sqrt(tmp * this.qMapped[e][m]); - Sm[e][m] = Math.sqrt(tmp * this.sIndexMapped[e][m]); + tmp = eMapped[e][m] / (1.0 + qMapped[e][m]); + Qm[e][m] = Math.sqrt(tmp * qMapped[e][m]); + Sm[e][m] = Math.sqrt(tmp * sIndexMapped[e][m]); - if (this.sMapped[e][m] === 0) { - gain[e][m] = Math.sqrt(this.eMapped[e][m] / ((1.0 + eCurr[e][m]) * (1.0 + this.qMapped[e][m] * delta))); + if (sMapped[e][m] === 0) { + gain[e][m] = Math.sqrt(eMapped[e][m] / ((1.0 + eCurr[e][m]) * (1.0 + qMapped[e][m] * delta))); } else { - gain[e][m] = Math.sqrt(this.eMapped[e][m] * this.qMapped[e][m] / ((1.0 + eCurr[e][m]) * (1.0 + this.qMapped[e][m]))); + gain[e][m] = Math.sqrt(eMapped[e][m] * qMapped[e][m] / ((1.0 + eCurr[e][m]) * (1.0 + qMapped[e][m]))); } } sum0 = sum1 = 0.0; for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { - sum0 += this.eMapped[e][m]; + sum0 += eMapped[e][m]; sum1 += eCurr[e][m]; } @@ -241,7 +244,7 @@ export default class HFAdjuster { sum0 = sum1 = 0.0; for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { - sum0 += this.eMapped[e][m]; + sum0 += eMapped[e][m]; sum1 += eCurr[e][m] * gain[e][m] * gain[e][m] + Sm[e][m] * Sm[e][m] + ((delta && !Sm[e][m]) ? 1 : 0) * Qm[e][m] * Qm[e][m]; @@ -262,7 +265,7 @@ export default class HFAdjuster { } // assembling HF signals (4.6.18.7.5) - assembleSignals(header, tables, cd, Xhigh, Y) { + assembleSignals(header, tables, cd, Xhigh[64][40][2], Y[2][38][64][2], ch) { let reset = header.reset; let hSL = header.smoothingMode ? 0 : 4; let M = tables.m @@ -275,16 +278,19 @@ export default class HFAdjuster { let noiseIndex = reset ? 0 : cd.noiseIndex; let sineIndex = cd.sineIndex; - let gTmp = cd.gTmp; - let qTmp = cd.qTmp; + let gTmp[42][48] = cd.gTmp; + let qTmp[42][48] = cd.qTmp; + let Sm[7][48] = this.Sm; + let Qm[7][48] = this.Qm; + let gain[7][48] = this.gain; let e, i, m, j; // save previous values if (reset) { for (i = 0; i < hSL; i++) { - gTmp[i + 2 * te[0]].set(this.gain[0].subarray(0, M)); - qTmp[i + 2 * te[0]].set(this.Qm[0].subarray(0, M)); + gTmp[i + 2 * te[0]].set(gain.subarray(0, M)); + qTmp[i + 2 * te[0]].set(Qm.subarray(0, M)); } } else if (hSL !== 0) { for (i = 0; i < 4; i++) { @@ -295,8 +301,8 @@ export default class HFAdjuster { for (e = 0; e < le; e++) { for (i = 2 * te[e]; i < 2 * te[e + 1]; i++) { - gTmp[hSL + i].set(this.gain[e].subarray(0, M)); - qTmp[hSL + i].set(this.Qm[e].subarray(0, M)); + gTmp[hSL + i].set(gain[e].subarray(0, M)); + qTmp[hSL + i].set(Qm.subarray(0, M)); } } @@ -312,14 +318,14 @@ export default class HFAdjuster { for (j = 0; j <= hSL; j++) { gFilt += gTmp[idx1 - j][m] * SMOOTHING_FACTORS[j]; } - Y[i][m + kx][0] = Xhigh[m + kx][i + T_HF_ADJ][0] * gFilt; - Y[i][m + kx][1] = Xhigh[m + kx][i + T_HF_ADJ][1] * gFilt; + Y[ch][i][m + kx][0] = Xhigh[m + kx][i + T_HF_ADJ][0] * gFilt; + Y[ch][i][m + kx][1] = Xhigh[m + kx][i + T_HF_ADJ][1] * gFilt; } } else { for (m = 0; m < M; m++) { gFilt = gTmp[i + hSL][m]; - Y[i][m + kx][0] = Xhigh[m + kx][i + T_HF_ADJ][0] * gFilt; - Y[i][m + kx][1] = Xhigh[m + kx][i + T_HF_ADJ][1] * gFilt; + Y[ch][i][m + kx][0] = Xhigh[m + kx][i + T_HF_ADJ][0] * gFilt; + Y[ch][i][m + kx][1] = Xhigh[m + kx][i + T_HF_ADJ][1] * gFilt; } } @@ -327,9 +333,9 @@ export default class HFAdjuster { let phiSign = (1 - 2 * (kx & 1)); for (m = 0; m < M; m++) { - if (this.Sm[e][m] !== 0) { - Y[i][m + kx][0] += this.Sm[e][m] * PHI[0][sineIndex]; - Y[i][m + kx][1] += this.Sm[e][m] * (PHI[1][sineIndex] * phiSign); + if (Sm[e][m] !== 0) { + Y[ch][i][m + kx][0] += Sm[e][m] * PHI[0][sineIndex]; + Y[ch][i][m + kx][1] += Sm[e][m] * (PHI[1][sineIndex] * phiSign); } else { if (hSL !== 0) { let idx1 = i + hSL; @@ -340,16 +346,16 @@ export default class HFAdjuster { } else { qFilt = qTmp[i][m]; } - Y[i][m + kx][0] += qFilt * NOISE_TABLE[noiseIndex][0]; - Y[i][m + kx][1] += qFilt * NOISE_TABLE[noiseIndex][1]; + Y[ch][i][m + kx][0] += qFilt * NOISE_TABLE[noiseIndex][0]; + Y[ch][i][m + kx][1] += qFilt * NOISE_TABLE[noiseIndex][1]; } phiSign = -phiSign; } } else { let phiSign = (1 - 2 * (kx & 1)); for (m = 0; m < M; m++) { - Y[i][m + kx][0] += this.Sm[e][m] * PHI[0][sineIndex]; - Y[i][m + kx][1] += this.Sm[e][m] * (PHI[1][sineIndex] * phiSign); + Y[ch][i][m + kx][0] += Sm[e][m] * PHI[0][sineIndex]; + Y[ch][i][m + kx][1] += Sm[e][m] * (PHI[1][sineIndex] * phiSign); phiSign = -phiSign; if (isNaN(Y[i][m + kx][0]) || isNaN(Y[i][m + kx][1])) { diff --git a/src/sbr/HFGenerator.js b/src/sbr/HFGenerator.js index 525eae1..34cd3c7 100644 --- a/src/sbr/HFGenerator.js +++ b/src/sbr/HFGenerator.js @@ -1,4 +1,3 @@ -import {makeArray} from './utils'; import {RATE, T_HF_ADJ} from './constants'; const RELAX_COEF = 1.000001; @@ -15,21 +14,21 @@ const CHIRP_MIN = 0.015625; export default class HFGenerator { constructor() { - this.alpha0 = makeArray([64, 2]); - this.alpha1 = makeArray([64, 2]); + this.alpha0 = new Float32Array(64 * 2); + this.alpha1 = new Float32Array(64 * 2); this.alpha = new Float32Array(4); - this.phi = makeArray([3, 2, 2]); + this.phi = new Float32Array(3 * 2 * 2); } // in: 32x40 complex Xlow, out: 32x40 complex Xhigh - process(tables, cd, Xlow, Xhigh) { + process(tables, cd, Xlow[32][40][2], Xhigh[64][40][2]) { // calculate chirp factors let bwArray = this.calculateChirpFactors(tables, cd); // calculate inverse filter coefficients for bands 0-k0 let k0 = tables.k0; - let alpha0 = this.alpha0; - let alpha1 = this.alpha1; + let alpha0[64][2] = this.alpha0; + let alpha1[64][2] = this.alpha1; this.calculateIFCoefs(tables, alpha0, alpha1, Xlow); // HF generation @@ -88,7 +87,7 @@ export default class HFGenerator { // fill remaining with zero while (k < m + kx) { - for (let j = 0; j < Xhigh[k].length; j++) { + for (let j = 0; j < 40; j++) { Xhigh[k][j][0] = 0; Xhigh[k][j][1] = 0; } @@ -118,15 +117,15 @@ export default class HFGenerator { } // calculates inverse filter coefficients for bands 0-k0 (4.6.18.6.2) - calculateIFCoefs(tables, alpha0, alpha1, Xlow) { + calculateIFCoefs(tables, alpha0[64][2], alpha1[64][2], Xlow) { let k0 = tables.k0; let tmp0, tmp1; - let phi = this.phi; + let phi[3][2][2] = this.phi; let d; for (let k = 0; k < k0; k++) { //get covariance matrix - this.getCovarianceMatrix(Xlow[k], phi); + this.getCovarianceMatrix(Xlow, k, phi); // d(k) d = phi[2][1][0] * phi[1][0][0] - (phi[1][1][0] * phi[1][1][0] + phi[1][1][1] * phi[1][1][1]) / RELAX_COEF; @@ -164,24 +163,24 @@ export default class HFGenerator { } // calculates covariance matrix (4.6.18.6.2) - getCovarianceMatrix(x, phi) { - let real_sum2 = x[0][0] * x[2][0] + x[0][1] * x[2][1]; - let imag_sum2 = x[0][0] * x[2][1] - x[0][1] * x[2][0]; + getCovarianceMatrix(x[32][40][2], k, phi[3][2][2]) { + let real_sum2 = x[k][0][0] * x[k][2][0] + x[k][0][1] * x[k][2][1]; + let imag_sum2 = x[k][0][0] * x[k][2][1] - x[k][0][1] * x[k][2][0]; let real_sum1 = 0.0, imag_sum1 = 0.0, real_sum0 = 0.0; for (let i = 1; i < 38; i++) { - real_sum0 += x[i][0] * x[i ][0] + x[i][1] * x[i ][1]; - real_sum1 += x[i][0] * x[i + 1][0] + x[i][1] * x[i + 1][1]; - imag_sum1 += x[i][0] * x[i + 1][1] - x[i][1] * x[i + 1][0]; - real_sum2 += x[i][0] * x[i + 2][0] + x[i][1] * x[i + 2][1]; - imag_sum2 += x[i][0] * x[i + 2][1] - x[i][1] * x[i + 2][0]; + real_sum0 += x[k][i][0] * x[k][i ][0] + x[k][i][1] * x[k][i ][1]; + real_sum1 += x[k][i][0] * x[k][i + 1][0] + x[k][i][1] * x[k][i + 1][1]; + imag_sum1 += x[k][i][0] * x[k][i + 1][1] - x[k][i][1] * x[k][i + 1][0]; + real_sum2 += x[k][i][0] * x[k][i + 2][0] + x[k][i][1] * x[k][i + 2][1]; + imag_sum2 += x[k][i][0] * x[k][i + 2][1] - x[k][i][1] * x[k][i + 2][0]; } phi[2 - 2][1][0] = real_sum2; phi[2 - 2][1][1] = imag_sum2; - phi[2 ][1][0] = real_sum0 + x[ 0][0] * x[ 0][0] + x[ 0][1] * x[ 0][1]; - phi[1 ][0][0] = real_sum0 + x[38][0] * x[38][0] + x[38][1] * x[38][1]; - phi[2 - 1][1][0] = real_sum1 + x[ 0][0] * x[ 1][0] + x[ 0][1] * x[ 1][1]; - phi[2 - 1][1][1] = imag_sum1 + x[ 0][0] * x[ 1][1] - x[ 0][1] * x[ 1][0]; - phi[0 ][0][0] = real_sum1 + x[38][0] * x[39][0] + x[38][1] * x[39][1]; - phi[0 ][0][1] = imag_sum1 + x[38][0] * x[39][1] - x[38][1] * x[39][0]; + phi[2 ][1][0] = real_sum0 + x[k][ 0][0] * x[k][ 0][0] + x[k][ 0][1] * x[k][ 0][1]; + phi[1 ][0][0] = real_sum0 + x[k][38][0] * x[k][38][0] + x[k][38][1] * x[k][38][1]; + phi[2 - 1][1][0] = real_sum1 + x[k][ 0][0] * x[k][ 1][0] + x[k][ 0][1] * x[k][ 1][1]; + phi[2 - 1][1][1] = imag_sum1 + x[k][ 0][0] * x[k][ 1][1] - x[k][ 0][1] * x[k][ 1][0]; + phi[0 ][0][0] = real_sum1 + x[k][38][0] * x[k][39][0] + x[k][38][1] * x[k][39][1]; + phi[0 ][0][1] = imag_sum1 + x[k][38][0] * x[k][39][1] - x[k][38][1] * x[k][39][0]; } } diff --git a/src/sbr/SynthesisFilterbank.js b/src/sbr/SynthesisFilterbank.js index 02a6a69..fa9e0e5 100644 --- a/src/sbr/SynthesisFilterbank.js +++ b/src/sbr/SynthesisFilterbank.js @@ -1,42 +1,42 @@ -import {makeArray} from './utils'; import {TIME_SLOTS_RATE, WINDOW} from './constants'; export default class SynthesisFilterbank { constructor() { - this.V = makeArray([2, 1280]); // for both channels + this.V = new Float32Array(2 * 1280); this.g = new Float32Array(640); // tmp buffer this.w = new Float32Array(640); - //complex coefficients: - this.COEFS = makeArray([128, 64, 2]); + // complex coefficients: + let COEFS[128][64][2] = this.COEFS = new Float32Array(128 * 64 * 2); let fac = 1.0 / 64.0; let tmp; for (let n = 0; n < 128; n++) { for(let k = 0; k < 64; k++) { tmp = Math.PI / 128 * (k + 0.5) * (2 * n - 255); - this.COEFS[n][k][0] = fac * Math.cos(tmp); - this.COEFS[n][k][1] = fac * Math.sin(tmp); + COEFS[n][k][0] = fac * Math.cos(tmp); + COEFS[n][k][1] = fac * Math.sin(tmp); } } } // in: 64 x 32 complex, out: 2048 time samples - process(inp, out, ch) { - let v = this.V[ch]; + process(inp[2][64][38][2], out, ch) { + let COEFS[128][64][2] = this.COEFS; + let v[2][1280] = this.V; let n, k, outOff = 0; // each loop creates 64 output samples for (let l = 0; l < TIME_SLOTS_RATE; l++) { // 1. shift buffer for (n = 1279; n >= 128; n--) { - v[n] = v[n - 128]; + v[ch][n] = v[ch][n - 128]; } // 2. multiple input by matrix and save in buffer for (n = 0; n < 128; n++) { - v[n] = (inp[0][l][0] * this.COEFS[n][0][0]) - (inp[0][l][1] * this.COEFS[n][0][1]); + v[ch][n] = (inp[ch][0][l][0] * COEFS[n][0][0]) - (inp[ch][0][l][1] * COEFS[n][0][1]); for (k = 1; k < 64; k++) { - v[n] += (inp[k][l][0] * this.COEFS[n][k][0]) - (inp[k][l][1] * this.COEFS[n][k][1]); + v[ch][n] += (inp[ch][k][l][0] * COEFS[n][k][0]) - (inp[ch][k][l][1] * COEFS[n][k][1]); // if (isNaN(inp[k][l][0])) { // throw new Error('NAN') // } @@ -46,8 +46,8 @@ export default class SynthesisFilterbank { // 3. extract samples for (n = 0; n < 5; n++) { for (k = 0; k < 64; k++) { - this.g[128 * n + k] = v[256 * n + k]; - this.g[128 * n + 64 + k] = v[256 * n + 192 + k]; + this.g[128 * n + k] = v[ch][256 * n + k]; + this.g[128 * n + 64 + k] = v[ch][256 * n + 192 + k]; } } diff --git a/src/sbr/constants.js b/src/sbr/constants.js index dec0e6d..193ee8f 100644 --- a/src/sbr/constants.js +++ b/src/sbr/constants.js @@ -1,38 +1,9 @@ -// frame classes -export const FIXFIX = 0; -export const FIXVAR = 1; -export const VARFIX = 2; -export const VARVAR = 3; - -// indizes for frequency tables -export const HIGH = 1; -export const LOW = 0; export const RATE = 2; -export const TIME_SLOTS = 16; //TODO: 15 for 960-sample frames -export const TIME_SLOTS_RATE = TIME_SLOTS*RATE; -export const NOISE_FLOOR_OFFSET = 6; +export const TIME_SLOTS = 16; // TODO: 15 for 960-sample frames +export const TIME_SLOTS_RATE = TIME_SLOTS * RATE; export const T_HF_GEN = 8; export const T_HF_ADJ = 2; - -// max values/lengths for arrays export const MAX_BANDS = 64; -export const MAX_ENV_COUNT = 5; -export const MAX_NOISE_COUNT = 2; -export const MAX_RELATIVE_BORDERS = 3; -export const MAX_NQ = 5; -export const MAX_CHIRP_FACTORS = 5; -export const MAX_PATCHES = 6; -export const MAX_LTEMP = 6; - -// extension ids -export const EXTENSION_ID_PS = 2; - -// helper export constants -export const LOG2 = 0.6931471805599453; -export const PAN_OFFSETS = new Uint8Array([24, 12]); - -//CEIL_LOG[i] = Math.ceil(Math.log(i+1)/Math.log(2)) -export const CEIL_LOG2 = new Uint8Array([0, 1, 2, 2, 3, 3]); export const WINDOW = new Float64Array([ 0.0, -5.525286E-4, -5.617692E-4, -4.947518E-4, diff --git a/src/sbr/sbr.js b/src/sbr/sbr.js index 26f8419..6c4e5aa 100644 --- a/src/sbr/sbr.js +++ b/src/sbr/sbr.js @@ -1,22 +1,15 @@ import SBRHeader from './header'; import FrequencyTables from './FrequencyTables'; import ChannelData from './ChannelData'; -import {makeArray} from './utils'; import AnalysisFilterbank from './AnalysisFilterbank'; import SynthesisFilterbank from './SynthesisFilterbank'; import HFGenerator from './HFGenerator'; -import HFAdjuster from './HFAdjuster' +import HFAdjuster from './HFAdjuster'; +import {T_HF_GEN, T_HF_ADJ, TIME_SLOTS_RATE} from './constants'; const NOISE_FLOOR_OFFSET = 6; const EXTENSION_ID_PS = 2; - -const T_HF_GEN = 8; -const T_HF_ADJ = 2; - -const RATE = 2; -const TIME_SLOTS = 16; //TODO: 15 for 960-sample frames -const TIME_SLOTS_RATE = TIME_SLOTS * RATE; -const MAX_LTEMP = 6; +const EXP2 = [1, Math.SQRT2]; let pool = []; @@ -32,9 +25,11 @@ class SBR { this.hfGen = new HFGenerator; this.hfAdj = new HFAdjuster; - this.X = makeArray([2, 64, 38, 2]); - this.Xlow = makeArray([32, 40, 2]); - this.Xhigh = makeArray([64, 40, 2]); + this.X = new Float32Array(2 * 64 * 38 * 2); + this.Xlow = new Float32Array(32 * 40 * 2); + this.Xhigh = new Float32Array(64 * 40 * 2); + this.W = new Float32Array(2 * 32 * 32 * 2); + this.Y = new Float32Array(2 * 38 * 64 * 2); } static get(sampleRate, downSampled) { @@ -56,11 +51,6 @@ class SBR { stream.advance(10); } - // if (this.header.decoded) { - // this.header.kxPrev = this.header.kx; - // this.header.mPrev = this.header.m; - // } - if (stream.read(1)) { // console.log("HEADER") this.header.decode(stream); @@ -80,18 +70,18 @@ class SBR { this.decodeSingleChannel(stream); } - // if (stream.read(1)) { - // let count = stream.read(4); - // if (count === 15) count += stream.read(8); - // let bitsLeft = 8 * count; - // - // let extensionID; - // while (bitsLeft>7) { - // bitsLeft -= 2; - // extensionID = stream.read(2); - // bitsLeft -= this.decodeExtension(stream, extensionID); - // } - // } + if (stream.read(1)) { + let count = stream.read(4); + if (count === 15) count += stream.read(8); + let bitsLeft = 8 * count; + + let extensionID; + while (bitsLeft>7) { + bitsLeft -= 2; + extensionID = stream.read(2); + bitsLeft -= this.decodeExtension(stream, extensionID); + } + } } stream.seek(end); @@ -130,32 +120,30 @@ class SBR { this.cd[0].decodeNoise(stream, this.header, this.tables, false, coupling); this.cd[1].decodeNoise(stream, this.header, this.tables, true, coupling); - this.dequantSingle(0); - this.dequantSingle(1); + this.dequantSingle(this.cd[0]); + this.dequantSingle(this.cd[1]); } this.cd[0].decodeSinusoidal(stream, this.header, this.tables); this.cd[1].decodeSinusoidal(stream, this.header, this.tables); } - dequantSingle(ch) { + dequantSingle(cd) { // envelopes - let a = this.cd[ch].ampRes; - let eq = this.cd[ch].envelopeSFQ; - let e = this.cd[ch].envelopeSF; - let freqRes = this.cd[ch].freqRes; + let a = cd.ampRes; + let eq[6][48] = cd.envelopeSFQ; + let e[5][48] = cd.envelopeSF; + let freqRes = cd.freqRes; let n = this.tables.n; - const EXP2 = [1, Math.SQRT2]; - for (let l = 0; l < this.cd[ch].envCount; l++) { + for (let l = 0; l < cd.envCount; l++) { for (let k = 0; k < n[freqRes[l]]; k++) { - // e[l][k] = Math.pow(2.0, (e[l][k] >> a) + 6.0); if (a) { - e[l][k] = Math.pow(2, eq[l][k] + 6); + e[l][k] = Math.pow(2, eq[l + 1][k] + 6); } else { - e[l][k] = Math.pow(2, (eq[l][k] >> 1) + 6) * EXP2[eq[l][k] & 1]; + e[l][k] = Math.pow(2, (eq[l + 1][k] >> 1) + 6) * EXP2[eq[l + 1][k] & 1]; } - + if (e[l][k] > 1e20) { console.log("DEQUANT OUT OF BOUNDS"); e[l][k] = 1; @@ -165,13 +153,13 @@ class SBR { // noise let nq = this.tables.nq; - let lq = this.cd[ch].noiseCount; - let qq = this.cd[ch].noiseFloorDataQ; - let q = this.cd[ch].noiseFloorData; + let lq = cd.noiseCount; + let qq[3][64] = cd.noiseFloorDataQ; + let q[2][64] = cd.noiseFloorData; for (let l = 0; l < lq; l++) { for (let k = 0; k < nq; k++) { - q[l][k] = Math.pow(2.0, NOISE_FLOOR_OFFSET - qq[l][k]); + q[l][k] = Math.pow(2, NOISE_FLOOR_OFFSET - qq[l + 1][k]); } } } @@ -199,108 +187,100 @@ class SBR { throw new Error('PS data unsupported') } - this.qmfS.process(this.X[0], left, 0); + this.qmfS.process(this.X, left, 0); if (this.stereo || this.psUsed) { - this.qmfS.process(this.X[1], right, 1); - } - - for (let i = 0; i < left.length; i++) { - if (isNaN(left[i])) { - console.log("NAN LEFT") - } + this.qmfS.process(this.X, right, 1); } + // + // for (let i = 0; i < left.length; i++) { + // if (isNaN(left[i])) { + // console.log("NAN LEFT") + // } + // } } processChannel(ch, data) { - // 2. analysis QMF (data -> W) - this.qmfA.process(data, this.cd[ch].W[this.cd[ch].Ypos], ch); - - let kx = this.tables.kx; - for (l = T_HF_GEN; l < TIME_SLOTS_RATE + T_HF_GEN; l++) { - for (k = 0; k < kx; k++) { - this.Xlow[k][l][0] = this.cd[ch].W[this.cd[ch].Ypos][l - T_HF_GEN][k][0]; - this.Xlow[k][l][1] = this.cd[ch].W[this.cd[ch].Ypos][l - T_HF_GEN][k][1]; - } - - for (k = kx; k < 32; k++) { - this.Xlow[k][l][0] = 0; - this.Xlow[k][l][1] = 0; - } - } + let Xlow[32][40][2] = this.Xlow; + let Xhigh[64][40][2] = this.Xhigh; + let W[2][32][32][2] = this.W; + let Y[2][38][64][2] = this.Y; + let X[2][64][38][2] = this.X; // 1. old W -> Xlow (4.6.18.5) let kxPrev = this.tables.kxPrev; let l, k; for (l = 0; l < T_HF_GEN; l++) { for (k = 0; k < kxPrev; k++) { - this.Xlow[k][l][0] = this.cd[ch].W[1 - this.cd[ch].Ypos][l + TIME_SLOTS_RATE - T_HF_GEN][k][0]; - this.Xlow[k][l][1] = this.cd[ch].W[1 - this.cd[ch].Ypos][l + TIME_SLOTS_RATE - T_HF_GEN][k][1]; + Xlow[k][l][0] = W[ch][l + TIME_SLOTS_RATE - T_HF_GEN][k][0]; + Xlow[k][l][1] = W[ch][l + TIME_SLOTS_RATE - T_HF_GEN][k][1]; } for (k = kxPrev; k < 32; k++) { - this.Xlow[k][l][0] = 0; - this.Xlow[k][l][1] = 0; + Xlow[k][l][0] = 0; + Xlow[k][l][1] = 0; } } - this.cd[ch].Ypos ^= 1; - + // 2. analysis QMF (data -> W) + this.qmfA.process(data, W, ch); + // 3. new W -> Xlow (4.6.18.5) - // let kx = this.tables.kx; - // for (l = T_HF_GEN; l < TIME_SLOTS_RATE + T_HF_GEN; l++) { - // for (k = 0; k < kx; k++) { - // this.Xlow[k][l][0] = this.cd[ch].W[l - T_HF_GEN][k][0]; - // this.Xlow[k][l][1] = this.cd[ch].W[l - T_HF_GEN][k][1]; - // } - // - // for (k = kx; k < 32; k++) { - // this.Xlow[k][l][0] = 0; - // this.Xlow[k][l][1] = 0; - // } - // } + let kx = this.tables.kx; + for (l = T_HF_GEN; l < TIME_SLOTS_RATE + T_HF_GEN; l++) { + for (k = 0; k < kx; k++) { + Xlow[k][l][0] = W[ch][l - T_HF_GEN][k][0]; + Xlow[k][l][1] = W[ch][l - T_HF_GEN][k][1]; + } + + for (k = kx; k < 32; k++) { + Xlow[k][l][0] = 0; + Xlow[k][l][1] = 0; + } + } // 4. HF generation (Xlow -> Xhigh) - this.hfGen.process(this.tables, this.cd[ch], this.Xlow, this.Xhigh); + this.hfGen.process(this.tables, this.cd[ch], Xlow, Xhigh); - // 6. HF adjustment (Xhigh -> Y) - this.hfAdj.process(this.header, this.tables, this.cd[ch], this.Xhigh, this.cd[ch].Y[this.cd[ch].Ypos]); - // 5. old Y -> X let lTemp = this.cd[ch].lTemp; let mPrev = this.tables.mPrev; let m = this.tables.m; for (l = 0; l < lTemp; l++) { for (k = 0; k Y) + this.hfAdj.process(this.header, this.tables, this.cd[ch], Xhigh, Y, ch); // 7. new Y -> X for (l = lTemp; l < TIME_SLOTS_RATE; l++) { for (k = 0; k < kx; k++) { - this.X[ch][k][l][0] = this.Xlow[k][l + T_HF_ADJ][0]; - this.X[ch][k][l][1] = this.Xlow[k][l + T_HF_ADJ][1]; + X[ch][k][l][0] = Xlow[k][l + T_HF_ADJ][0]; + X[ch][k][l][1] = Xlow[k][l + T_HF_ADJ][1]; } for (k = kx; k Date: Fri, 8 Jul 2016 14:39:38 -0700 Subject: [PATCH 04/19] [SBR] Support dequantizing coupled pairs --- src/sbr/sbr.js | 54 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/sbr/sbr.js b/src/sbr/sbr.js index 6c4e5aa..1cf754f 100644 --- a/src/sbr/sbr.js +++ b/src/sbr/sbr.js @@ -95,7 +95,6 @@ class SBR { let coupling = stream.read(1); if (coupling) { - throw new Error('COUPLING') this.cd[0].decodeGrid(stream, this.header, this.tables); this.cd[1].copyGrid(this.cd[0]); this.cd[0].decodeDTDF(stream); @@ -128,6 +127,59 @@ class SBR { this.cd[1].decodeSinusoidal(stream, this.header, this.tables); } + dequantCoupled() { + // envelopes + let a = this.cd[0].ampRes; + let panOffset = this.cd[0].ampRes ? 12 : 24; + let e0q[6][48] = this.cd[0].envelopeSFQ; + let e0[5][48] = this.cd[0].envelopeSF; + let e1q[6][48] = this.cd[1].envelopeSFQ; + let e1[5][48] = this.cd[1].envelopeSF; + let r = this.cd[0].freqRes; + let le = this.cd[0].envCount; + let n = this.tables.n; + + let f1, f2, f3; + for (let l = 0; l < le; l++) { + for (let k = 0; k < n[r[l]]; k++) { + if (a) { + f1 = Math.pow(2, e0q[l + 1][k] + 7); + f2 = Math.pow(2, panOffset - e1q[l + 1][k]); + } else { + f1 = Math.pow(2, (e0q[l + 1][k] >> 1) + 7) * EXP2[e0q[l + 1][k] & 1]; + f2 = Math.pow(2, (panOffset - e1q[l + 1][k]) >> 1) * EXP2[panOffset - e1q[l + 1][k] & 1]; + } + + if (f1 > 1e20) { + console.log("DEQUANT OUT OF BOUNDS"); + f1 = 1; + } + + f3 = f1 / (1.0 + f2); + e0[l][k] = f3; + e1[l][k] = f3 * f2; + } + } + + // noise + let q0q[3][64] = this.cd[0].noiseFloorDataQ; + let q0[2][64] = this.cd[0].noiseFloorData; + let q1q[3][64] = this.cd[1].noiseFloorDataQ; + let q1[2][64] = this.cd[1].noiseFloorData; + let lq = this.cd[0].noiseCount; + let nq = this.tables.nq; + + for (let l = 0; l < lq; l++) { + for (let k = 0; k < nq; k++) { + f1 = Math.pow(2, NOISE_FLOOR_OFFSET - q0q[l + 1][k] + 1); + f2 = Math.pow(2, 12 - q1q[l + 1][k]); + f3 = f1 / (1 + f2); + q0[l][k] = f3; + q1[l][k] = f3 * f2; + } + } + } + dequantSingle(cd) { // envelopes let a = cd.ampRes; From c355a7654d00683ff865c52edaaa8da4384389a0 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sat, 9 Jul 2016 11:11:43 -0700 Subject: [PATCH 05/19] Simplify and speed up FFT * No more long vs short tables. * Precompute bit reversal table. --- src/fft.js | 160 +++++++++++++++++------------------------------------ 1 file changed, 52 insertions(+), 108 deletions(-) diff --git a/src/fft.js b/src/fft.js index 9735f82..3b3c697 100644 --- a/src/fft.js +++ b/src/fft.js @@ -20,74 +20,33 @@ function FFT(length) { this.length = length; - - switch (length) { - case 64: - this.roots = generateFFTTableShort(64); - break; - - case 512: - this.roots = generateFFTTableLong(512); - break; - - case 60: - this.roots = generateFFTTableShort(60); - break; - - case 480: - this.roots = generateFFTTableLong(480); - break; - - default: - throw new Error("unexpected FFT length: " + length); - } + + this.roots = generateFFTTable(length); // processing buffers - this.rev = new Array(length); - for (var i = 0; i < length; i++) { - this.rev[i] = new Float32Array(2); - } - - this.a = new Float32Array(2); - this.b = new Float32Array(2); - this.c = new Float32Array(2); - this.d = new Float32Array(2); - this.e1 = new Float32Array(2); - this.e2 = new Float32Array(2); -} - -function generateFFTTableShort(len) { - var t = 2 * Math.PI / len, - cosT = Math.cos(t), - sinT = Math.sin(t), - f = new Array(len); - - for (var i = 0; i < len; i++) { - f[i] = new Float32Array(2); - } - - f[0][0] = 1; - f[0][1] = 0; - var lastImag = 0; - - for (var i = 1; i < len; i++) { - f[i][0] = f[i - 1][0] * cosT + lastImag * sinT; - lastImag = lastImag * cosT - f[i - 1][0] * sinT; - f[i][1] = -lastImag; + this.buf = new Float32Array(length * 2); + + // Bit reversal lookup table + this.rev = new Uint16Array(length); + var ii = 0; + for (let i = 0; i < length; i++) { + this.rev[ii] = i; + + let k = length >>> 1; + while (ii >= k && k > 0) { + ii -= k; + k >>= 1; + } + + ii += k; } - - return f; } -function generateFFTTableLong(len) { +function generateFFTTable(len) { var t = 2 * Math.PI / len, cosT = Math.cos(t), sinT = Math.sin(t), - f = new Array(len); - - for (var i = 0; i < len; i++) { - f[i] = new Float32Array(3); - } + f[len][3] = new Float32Array(len * 3); f[0][0] = 1; f[0][1] = 0; @@ -102,70 +61,55 @@ function generateFFTTableLong(len) { return f; } -FFT.prototype.process = function(input, forward) { +FFT.prototype.process = function(input[length][2], forward) { var length = this.length, imOffset = (forward ? 2 : 1), scale = (forward ? length : 1), - rev = this.rev, - roots = this.roots; + buf[length][2] = this.buf, + roots[length][3] = this.roots, + rev = this.rev; // bit-reversal - var ii = 0; for (var i = 0; i < length; i++) { - rev[i][0] = input[ii][0]; - rev[i][1] = input[ii][1]; - - var k = length >>> 1; - while (ii >= k && k > 0) { - ii -= k; - k >>= 1; - } - - ii += k; + buf[i][0] = input[rev[i]][0]; + buf[i][1] = input[rev[i]][1]; } - var a = this.a, - b = this.b, - c = this.c, - d = this.d, - e1 = this.e1, - e2 = this.e2; - for (var i = 0; i < length; i++) { - input[i][0] = rev[i][0]; - input[i][1] = rev[i][1]; + input[i][0] = buf[i][0]; + input[i][1] = buf[i][1]; } // bottom base-4 round for (var i = 0; i < length; i += 4) { - a[0] = input[i][0] + input[i + 1][0]; - a[1] = input[i][1] + input[i + 1][1]; - b[0] = input[i + 2][0] + input[i + 3][0]; - b[1] = input[i + 2][1] + input[i + 3][1]; - c[0] = input[i][0] - input[i + 1][0]; - c[1] = input[i][1] - input[i + 1][1]; - d[0] = input[i + 2][0] - input[i + 3][0]; - d[1] = input[i + 2][1] - input[i + 3][1]; - input[i][0] = a[0] + b[0]; - input[i][1] = a[1] + b[1]; - input[i + 2][0] = a[0] - b[0]; - input[i + 2][1] = a[1] - b[1]; - - e1[0] = c[0] - d[1]; - e1[1] = c[1] + d[0]; - e2[0] = c[0] + d[1]; - e2[1] = c[1] - d[0]; + let a0 = input[i][0] + input[i + 1][0]; + let a1 = input[i][1] + input[i + 1][1]; + let b0 = input[i + 2][0] + input[i + 3][0]; + let b1 = input[i + 2][1] + input[i + 3][1]; + let c0 = input[i][0] - input[i + 1][0]; + let c1 = input[i][1] - input[i + 1][1]; + let d0 = input[i + 2][0] - input[i + 3][0]; + let d1 = input[i + 2][1] - input[i + 3][1]; + input[i][0] = a0 + b0; + input[i][1] = a1 + b1; + input[i + 2][0] = a0 - b0; + input[i + 2][1] = a1 - b1; + + let e10 = c0 - d1; + let e11 = c1 + d0; + let e20 = c0 + d1; + let e21 = c1 - d0; if (forward) { - input[i + 1][0] = e2[0]; - input[i + 1][1] = e2[1]; - input[i + 3][0] = e1[0]; - input[i + 3][1] = e1[1]; + input[i + 1][0] = e20; + input[i + 1][1] = e21; + input[i + 3][0] = e10; + input[i + 3][1] = e11; } else { - input[i + 1][0] = e1[0]; - input[i + 1][1] = e1[1]; - input[i + 3][0] = e2[0]; - input[i + 3][1] = e2[1]; + input[i + 1][0] = e10; + input[i + 1][1] = e11; + input[i + 3][0] = e20; + input[i + 3][1] = e21; } } From 90d97e751a65fed26ff7c3c019a39fcc055c3235 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sat, 9 Jul 2016 11:13:16 -0700 Subject: [PATCH 06/19] Generate MDCT tables at runtime Yay, smaller build! --- src/filter_bank.js | 4 +- src/mdct.js | 62 +-- src/mdct_tables.js | 1147 -------------------------------------------- 3 files changed, 27 insertions(+), 1186 deletions(-) delete mode 100644 src/mdct_tables.js diff --git a/src/filter_bank.js b/src/filter_bank.js index 4fb29de..57938ff 100644 --- a/src/filter_bank.js +++ b/src/filter_bank.js @@ -32,8 +32,8 @@ function FilterBank(smallFrames, channels) { this.mid = (this.length - this.shortLength) / 2; this.trans = this.shortLength / 2; - this.mdctShort = new MDCT(this.shortLength * 2); - this.mdctLong = new MDCT(this.length * 2); + this.mdctShort = new MDCT(this.shortLength * 2, 1 / 128); + this.mdctLong = new MDCT(this.length * 2, 1 / 1024); this.overlaps = new Array(channels); for (var i = 0; i < channels; i++) { diff --git a/src/mdct.js b/src/mdct.js index ea1562b..cda858e 100644 --- a/src/mdct.js +++ b/src/mdct.js @@ -18,45 +18,28 @@ * If not, see . */ -var tables = require('./mdct_tables'); var FFT = require('./fft'); // Modified Discrete Cosine Transform -function MDCT(length) { +function MDCT(length, scale) { this.N = length; this.N2 = length >>> 1; this.N4 = length >>> 2; this.N8 = length >>> 3; - switch (length) { - case 2048: - this.sincos = tables.MDCT_TABLE_2048; - break; - - case 256: - this.sincos = tables.MDCT_TABLE_256; - break; - - case 1920: - this.sincos = tables.MDCT_TABLE_1920; - break; - - case 240: - this.sincos = tables.MDCT_TABLE_240; - break; - - default: - throw new Error("unsupported MDCT length: " + length); - } - - this.fft = new FFT(this.N4); + this.sin = new Float32Array(this.N4); + this.cos = new Float32Array(this.N4); - this.buf = new Array(this.N4); - for (var i = 0; i < this.N4; i++) { - this.buf[i] = new Float32Array(2); + let theta = 1.0 / 8.0 + (scale < 0 ? this.N4 : 0); + scale = Math.sqrt(Math.abs(scale)); + for (let i = 0; i < this.N4; i++) { + let alpha = 2 * Math.PI * (i + theta) / length; + this.sin[i] = -Math.sin(alpha) * scale; + this.cos[i] = -Math.cos(alpha) * scale; } - this.tmp = new Float32Array(2); + this.fft = new FFT(this.N4); + this.buf = new Float32Array(this.N4 * 2); } MDCT.prototype.process = function(input, inOffset, output, outOffset) { @@ -64,26 +47,31 @@ MDCT.prototype.process = function(input, inOffset, output, outOffset) { var N2 = this.N2, N4 = this.N4, N8 = this.N8, - buf = this.buf, + buf[N4][2] = this.buf, tmp = this.tmp, - sincos = this.sincos, + sin = this.sin, + cos = this.cos, fft = this.fft; // pre-IFFT complex multiplication + let in1 = inOffset; + let in2 = inOffset + N2 - 1; for (var k = 0; k < N4; k++) { - buf[k][1] = (input[inOffset + 2 * k] * sincos[k][0]) + (input[inOffset + N2 - 1 - 2 * k] * sincos[k][1]); - buf[k][0] = (input[inOffset + N2 - 1 - 2 * k] * sincos[k][0]) - (input[inOffset + 2 * k] * sincos[k][1]); + buf[k][0] = (input[in2] * cos[k]) - (input[in1] * sin[k]); + buf[k][1] = (input[in2] * sin[k]) + (input[in1] * cos[k]); + in1 += 2; + in2 -= 2; } // complex IFFT, non-scaling fft.process(buf, false); // post-IFFT complex multiplication - for (var k = 0; k < N4; k++) { - tmp[0] = buf[k][0]; - tmp[1] = buf[k][1]; - buf[k][1] = (tmp[1] * sincos[k][0]) + (tmp[0] * sincos[k][1]); - buf[k][0] = (tmp[0] * sincos[k][0]) - (tmp[1] * sincos[k][1]); + for (let k = 0; k < N4; k++) { + let r = buf[k][0]; + let i = buf[k][1]; + buf[k][0] = (r * cos[k]) - (i * sin[k]); + buf[k][1] = (r * sin[k]) + (i * cos[k]); } // reordering diff --git a/src/mdct_tables.js b/src/mdct_tables.js deleted file mode 100644 index 677ce41..0000000 --- a/src/mdct_tables.js +++ /dev/null @@ -1,1147 +0,0 @@ -/* - * AAC.js - Advanced Audio Coding decoder in JavaScript - * Created by Devon Govett - * Copyright (c) 2012, Official.fm Labs - * - * AAC.js is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 3 of the - * License, or (at your option) any later version. - * - * AAC.js 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 Lesser General - * Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - * If not, see . - */ - -exports.MDCT_TABLE_2048 = [ - [0.031249997702054, 0.000011984224612], - [0.031249813866531, 0.000107857810004], - [0.031249335895858, 0.000203730380198], - [0.031248563794535, 0.000299601032804], - [0.031247497569829, 0.000395468865451], - [0.031246137231775, 0.000491332975794], - [0.031244482793177, 0.000587192461525], - [0.031242534269608, 0.000683046420376], - [0.031240291679407, 0.000778893950134], - [0.031237755043684, 0.000874734148645], - [0.031234924386313, 0.000970566113826], - [0.031231799733938, 0.001066388943669], - [0.031228381115970, 0.001162201736253], - [0.031224668564585, 0.001258003589751], - [0.031220662114728, 0.001353793602441], - [0.031216361804108, 0.001449570872710], - [0.031211767673203, 0.001545334499065], - [0.031206879765253, 0.001641083580144], - [0.031201698126266, 0.001736817214719], - [0.031196222805014, 0.001832534501709], - [0.031190453853031, 0.001928234540186], - [0.031184391324617, 0.002023916429386], - [0.031178035276836, 0.002119579268713], - [0.031171385769513, 0.002215222157753], - [0.031164442865236, 0.002310844196278], - [0.031157206629353, 0.002406444484258], - [0.031149677129975, 0.002502022121865], - [0.031141854437973, 0.002597576209488], - [0.031133738626977, 0.002693105847734], - [0.031125329773375, 0.002788610137442], - [0.031116627956316, 0.002884088179689], - [0.031107633257703, 0.002979539075801], - [0.031098345762200, 0.003074961927355], - [0.031088765557222, 0.003170355836197], - [0.031078892732942, 0.003265719904442], - [0.031068727382288, 0.003361053234488], - [0.031058269600939, 0.003456354929021], - [0.031047519487329, 0.003551624091024], - [0.031036477142640, 0.003646859823790], - [0.031025142670809, 0.003742061230921], - [0.031013516178519, 0.003837227416347], - [0.031001597775203, 0.003932357484328], - [0.030989387573042, 0.004027450539462], - [0.030976885686963, 0.004122505686697], - [0.030964092234638, 0.004217522031340], - [0.030951007336485, 0.004312498679058], - [0.030937631115663, 0.004407434735897], - [0.030923963698074, 0.004502329308281], - [0.030910005212362, 0.004597181503027], - [0.030895755789908, 0.004691990427350], - [0.030881215564835, 0.004786755188872], - [0.030866384674000, 0.004881474895632], - [0.030851263256996, 0.004976148656090], - [0.030835851456154, 0.005070775579142], - [0.030820149416533, 0.005165354774124], - [0.030804157285929, 0.005259885350819], - [0.030787875214864, 0.005354366419469], - [0.030771303356593, 0.005448797090784], - [0.030754441867095, 0.005543176475946], - [0.030737290905077, 0.005637503686619], - [0.030719850631972, 0.005731777834961], - [0.030702121211932, 0.005825998033626], - [0.030684102811835, 0.005920163395780], - [0.030665795601276, 0.006014273035101], - [0.030647199752570, 0.006108326065793], - [0.030628315440748, 0.006202321602594], - [0.030609142843557, 0.006296258760782], - [0.030589682141455, 0.006390136656185], - [0.030569933517616, 0.006483954405188], - [0.030549897157919, 0.006577711124743], - [0.030529573250956, 0.006671405932375], - [0.030508961988022, 0.006765037946194], - [0.030488063563118, 0.006858606284900], - [0.030466878172949, 0.006952110067791], - [0.030445406016919, 0.007045548414774], - [0.030423647297133, 0.007138920446372], - [0.030401602218392, 0.007232225283733], - [0.030379270988192, 0.007325462048634], - [0.030356653816724, 0.007418629863497], - [0.030333750916869, 0.007511727851390], - [0.030310562504198, 0.007604755136040], - [0.030287088796968, 0.007697710841838], - [0.030263330016124, 0.007790594093851], - [0.030239286385293, 0.007883404017824], - [0.030214958130781, 0.007976139740197], - [0.030190345481576, 0.008068800388104], - [0.030165448669342, 0.008161385089390], - [0.030140267928416, 0.008253892972610], - [0.030114803495809, 0.008346323167047], - [0.030089055611203, 0.008438674802711], - [0.030063024516947, 0.008530947010354], - [0.030036710458054, 0.008623138921475], - [0.030010113682202, 0.008715249668328], - [0.029983234439732, 0.008807278383932], - [0.029956072983640, 0.008899224202078], - [0.029928629569580, 0.008991086257336], - [0.029900904455860, 0.009082863685067], - [0.029872897903441, 0.009174555621425], - [0.029844610175929, 0.009266161203371], - [0.029816041539579, 0.009357679568679], - [0.029787192263292, 0.009449109855944], - [0.029758062618606, 0.009540451204587], - [0.029728652879702, 0.009631702754871], - [0.029698963323395, 0.009722863647900], - [0.029668994229134, 0.009813933025633], - [0.029638745879000, 0.009904910030891], - [0.029608218557702, 0.009995793807363], - [0.029577412552575, 0.010086583499618], - [0.029546328153577, 0.010177278253107], - [0.029514965653285, 0.010267877214177], - [0.029483325346896, 0.010358379530076], - [0.029451407532220, 0.010448784348962], - [0.029419212509679, 0.010539090819911], - [0.029386740582307, 0.010629298092923], - [0.029353992055740, 0.010719405318933], - [0.029320967238220, 0.010809411649818], - [0.029287666440590, 0.010899316238403], - [0.029254089976290, 0.010989118238474], - [0.029220238161353, 0.011078816804778], - [0.029186111314406, 0.011168411093039], - [0.029151709756664, 0.011257900259961], - [0.029117033811927, 0.011347283463239], - [0.029082083806579, 0.011436559861563], - [0.029046860069582, 0.011525728614630], - [0.029011362932476, 0.011614788883150], - [0.028975592729373, 0.011703739828853], - [0.028939549796957, 0.011792580614500], - [0.028903234474475, 0.011881310403886], - [0.028866647103744, 0.011969928361855], - [0.028829788029135, 0.012058433654299], - [0.028792657597583, 0.012146825448172], - [0.028755256158571, 0.012235102911499], - [0.028717584064137, 0.012323265213377], - [0.028679641668864, 0.012411311523990], - [0.028641429329882, 0.012499241014612], - [0.028602947406859, 0.012587052857618], - [0.028564196262001, 0.012674746226488], - [0.028525176260050, 0.012762320295819], - [0.028485887768276, 0.012849774241331], - [0.028446331156478, 0.012937107239875], - [0.028406506796976, 0.013024318469437], - [0.028366415064615, 0.013111407109155], - [0.028326056336751, 0.013198372339315], - [0.028285430993258, 0.013285213341368], - [0.028244539416515, 0.013371929297933], - [0.028203381991411, 0.013458519392807], - [0.028161959105334, 0.013544982810971], - [0.028120271148172, 0.013631318738598], - [0.028078318512309, 0.013717526363062], - [0.028036101592619, 0.013803604872943], - [0.027993620786463, 0.013889553458039], - [0.027950876493687, 0.013975371309367], - [0.027907869116616, 0.014061057619178], - [0.027864599060052, 0.014146611580959], - [0.027821066731270, 0.014232032389445], - [0.027777272540012, 0.014317319240622], - [0.027733216898487, 0.014402471331737], - [0.027688900221361, 0.014487487861307], - [0.027644322925762, 0.014572368029123], - [0.027599485431266, 0.014657111036262], - [0.027554388159903, 0.014741716085090], - [0.027509031536144, 0.014826182379271], - [0.027463415986904, 0.014910509123778], - [0.027417541941533, 0.014994695524894], - [0.027371409831816, 0.015078740790225], - [0.027325020091965, 0.015162644128704], - [0.027278373158618, 0.015246404750603], - [0.027231469470833, 0.015330021867534], - [0.027184309470088, 0.015413494692460], - [0.027136893600268, 0.015496822439704], - [0.027089222307671, 0.015580004324954], - [0.027041296040997, 0.015663039565269], - [0.026993115251345, 0.015745927379091], - [0.026944680392213, 0.015828666986247], - [0.026895991919487, 0.015911257607961], - [0.026847050291442, 0.015993698466859], - [0.026797855968734, 0.016075988786976], - [0.026748409414401, 0.016158127793763], - [0.026698711093851, 0.016240114714099], - [0.026648761474864, 0.016321948776289], - [0.026598561027585, 0.016403629210082], - [0.026548110224519, 0.016485155246669], - [0.026497409540530, 0.016566526118696], - [0.026446459452830, 0.016647741060271], - [0.026395260440982, 0.016728799306966], - [0.026343812986890, 0.016809700095831], - [0.026292117574797, 0.016890442665397], - [0.026240174691280, 0.016971026255683], - [0.026187984825246, 0.017051450108208], - [0.026135548467924, 0.017131713465990], - [0.026082866112867, 0.017211815573560], - [0.026029938255941, 0.017291755676967], - [0.025976765395322, 0.017371533023784], - [0.025923348031494, 0.017451146863116], - [0.025869686667242, 0.017530596445607], - [0.025815781807646, 0.017609881023449], - [0.025761633960080, 0.017688999850383], - [0.025707243634204, 0.017767952181715], - [0.025652611341960, 0.017846737274313], - [0.025597737597568, 0.017925354386623], - [0.025542622917522, 0.018003802778671], - [0.025487267820581, 0.018082081712071], - [0.025431672827768, 0.018160190450031], - [0.025375838462365, 0.018238128257362], - [0.025319765249906, 0.018315894400484], - [0.025263453718173, 0.018393488147432], - [0.025206904397193, 0.018470908767865], - [0.025150117819228, 0.018548155533070], - [0.025093094518776, 0.018625227715971], - [0.025035835032562, 0.018702124591135], - [0.024978339899534, 0.018778845434780], - [0.024920609660858, 0.018855389524780], - [0.024862644859912, 0.018931756140672], - [0.024804446042284, 0.019007944563666], - [0.024746013755764, 0.019083954076646], - [0.024687348550337, 0.019159783964183], - [0.024628450978184, 0.019235433512536], - [0.024569321593670, 0.019310902009663], - [0.024509960953345, 0.019386188745225], - [0.024450369615932, 0.019461293010596], - [0.024390548142329, 0.019536214098866], - [0.024330497095598, 0.019610951304848], - [0.024270217040961, 0.019685503925087], - [0.024209708545799, 0.019759871257867], - [0.024148972179639, 0.019834052603212], - [0.024088008514157, 0.019908047262901], - [0.024026818123164, 0.019981854540467], - [0.023965401582609, 0.020055473741208], - [0.023903759470567, 0.020128904172192], - [0.023841892367236, 0.020202145142264], - [0.023779800854935, 0.020275195962052], - [0.023717485518092, 0.020348055943974], - [0.023654946943242, 0.020420724402244], - [0.023592185719023, 0.020493200652878], - [0.023529202436167, 0.020565484013703], - [0.023465997687496, 0.020637573804361], - [0.023402572067918, 0.020709469346314], - [0.023338926174419, 0.020781169962854], - [0.023275060606058, 0.020852674979108], - [0.023210975963963, 0.020923983722044], - [0.023146672851322, 0.020995095520475], - [0.023082151873380, 0.021066009705072], - [0.023017413637435, 0.021136725608363], - [0.022952458752826, 0.021207242564742], - [0.022887287830934, 0.021277559910478], - [0.022821901485173, 0.021347676983716], - [0.022756300330983, 0.021417593124488], - [0.022690484985827, 0.021487307674717], - [0.022624456069185, 0.021556819978223], - [0.022558214202547, 0.021626129380729], - [0.022491760009405, 0.021695235229869], - [0.022425094115252, 0.021764136875192], - [0.022358217147572, 0.021832833668171], - [0.022291129735838, 0.021901324962204], - [0.022223832511501, 0.021969610112625], - [0.022156326107988, 0.022037688476709], - [0.022088611160696, 0.022105559413676], - [0.022020688306983, 0.022173222284699], - [0.021952558186166, 0.022240676452909], - [0.021884221439510, 0.022307921283403], - [0.021815678710228, 0.022374956143245], - [0.021746930643469, 0.022441780401478], - [0.021677977886316, 0.022508393429127], - [0.021608821087780, 0.022574794599206], - [0.021539460898790, 0.022640983286719], - [0.021469897972190, 0.022706958868676], - [0.021400132962735, 0.022772720724087], - [0.021330166527077, 0.022838268233979], - [0.021259999323769, 0.022903600781391], - [0.021189632013250, 0.022968717751391], - [0.021119065257845, 0.023033618531071], - [0.021048299721754, 0.023098302509561], - [0.020977336071050, 0.023162769078031], - [0.020906174973670, 0.023227017629698], - [0.020834817099409, 0.023291047559828], - [0.020763263119915, 0.023354858265748], - [0.020691513708680, 0.023418449146848], - [0.020619569541038, 0.023481819604585], - [0.020547431294155, 0.023544969042494], - [0.020475099647023, 0.023607896866186], - [0.020402575280455, 0.023670602483363], - [0.020329858877078, 0.023733085303813], - [0.020256951121327, 0.023795344739427], - [0.020183852699437, 0.023857380204193], - [0.020110564299439, 0.023919191114211], - [0.020037086611150, 0.023980776887692], - [0.019963420326171, 0.024042136944968], - [0.019889566137877, 0.024103270708495], - [0.019815524741412, 0.024164177602859], - [0.019741296833681, 0.024224857054779], - [0.019666883113346, 0.024285308493120], - [0.019592284280817, 0.024345531348888], - [0.019517501038246, 0.024405525055242], - [0.019442534089523, 0.024465289047500], - [0.019367384140264, 0.024524822763141], - [0.019292051897809, 0.024584125641809], - [0.019216538071215, 0.024643197125323], - [0.019140843371246, 0.024702036657681], - [0.019064968510369, 0.024760643685063], - [0.018988914202748, 0.024819017655836], - [0.018912681164234, 0.024877158020562], - [0.018836270112363, 0.024935064232003], - [0.018759681766343, 0.024992735745123], - [0.018682916847054, 0.025050172017095], - [0.018605976077037, 0.025107372507308], - [0.018528860180486, 0.025164336677369], - [0.018451569883247, 0.025221063991110], - [0.018374105912805, 0.025277553914591], - [0.018296468998280, 0.025333805916107], - [0.018218659870421, 0.025389819466194], - [0.018140679261596, 0.025445594037630], - [0.018062527905790, 0.025501129105445], - [0.017984206538592, 0.025556424146920], - [0.017905715897192, 0.025611478641598], - [0.017827056720375, 0.025666292071285], - [0.017748229748511, 0.025720863920056], - [0.017669235723550, 0.025775193674260], - [0.017590075389012, 0.025829280822525], - [0.017510749489986, 0.025883124855762], - [0.017431258773116, 0.025936725267170], - [0.017351603986600, 0.025990081552242], - [0.017271785880180, 0.026043193208768], - [0.017191805205132, 0.026096059736841], - [0.017111662714267, 0.026148680638861], - [0.017031359161915, 0.026201055419541], - [0.016950895303924, 0.026253183585908], - [0.016870271897651, 0.026305064647313], - [0.016789489701954, 0.026356698115431], - [0.016708549477186, 0.026408083504269], - [0.016627451985187, 0.026459220330167], - [0.016546197989277, 0.026510108111806], - [0.016464788254250, 0.026560746370212], - [0.016383223546365, 0.026611134628757], - [0.016301504633341, 0.026661272413168], - [0.016219632284346, 0.026711159251530], - [0.016137607269996, 0.026760794674288], - [0.016055430362340, 0.026810178214254], - [0.015973102334858, 0.026859309406613], - [0.015890623962454, 0.026908187788922], - [0.015807996021446, 0.026956812901119], - [0.015725219289558, 0.027005184285527], - [0.015642294545918, 0.027053301486856], - [0.015559222571044, 0.027101164052208], - [0.015476004146842, 0.027148771531083], - [0.015392640056594, 0.027196123475380], - [0.015309131084956, 0.027243219439406], - [0.015225478017946, 0.027290058979875], - [0.015141681642938, 0.027336641655915], - [0.015057742748656, 0.027382967029073], - [0.014973662125164, 0.027429034663317], - [0.014889440563862, 0.027474844125040], - [0.014805078857474, 0.027520394983066], - [0.014720577800046, 0.027565686808654], - [0.014635938186934, 0.027610719175499], - [0.014551160814797, 0.027655491659740], - [0.014466246481592, 0.027700003839960], - [0.014381195986567, 0.027744255297195], - [0.014296010130247, 0.027788245614933], - [0.014210689714436, 0.027831974379120], - [0.014125235542201, 0.027875441178165], - [0.014039648417870, 0.027918645602941], - [0.013953929147020, 0.027961587246792], - [0.013868078536476, 0.028004265705534], - [0.013782097394294, 0.028046680577462], - [0.013695986529763, 0.028088831463351], - [0.013609746753390, 0.028130717966461], - [0.013523378876898, 0.028172339692540], - [0.013436883713214, 0.028213696249828], - [0.013350262076462, 0.028254787249062], - [0.013263514781960, 0.028295612303478], - [0.013176642646205, 0.028336171028814], - [0.013089646486871, 0.028376463043317], - [0.013002527122799, 0.028416487967743], - [0.012915285373990, 0.028456245425361], - [0.012827922061597, 0.028495735041960], - [0.012740438007915, 0.028534956445849], - [0.012652834036379, 0.028573909267859], - [0.012565110971550, 0.028612593141354], - [0.012477269639111, 0.028651007702224], - [0.012389310865858, 0.028689152588899], - [0.012301235479693, 0.028727027442343], - [0.012213044309615, 0.028764631906065], - [0.012124738185712, 0.028801965626115], - [0.012036317939156, 0.028839028251097], - [0.011947784402191, 0.028875819432161], - [0.011859138408130, 0.028912338823015], - [0.011770380791341, 0.028948586079925], - [0.011681512387245, 0.028984560861718], - [0.011592534032306, 0.029020262829785], - [0.011503446564022, 0.029055691648087], - [0.011414250820918, 0.029090846983152], - [0.011324947642537, 0.029125728504087], - [0.011235537869437, 0.029160335882573], - [0.011146022343175, 0.029194668792871], - [0.011056401906305, 0.029228726911828], - [0.010966677402371, 0.029262509918876], - [0.010876849675891, 0.029296017496036], - [0.010786919572361, 0.029329249327922], - [0.010696887938235, 0.029362205101743], - [0.010606755620926, 0.029394884507308], - [0.010516523468793, 0.029427287237024], - [0.010426192331137, 0.029459412985906], - [0.010335763058187, 0.029491261451573], - [0.010245236501099, 0.029522832334255], - [0.010154613511943, 0.029554125336796], - [0.010063894943698, 0.029585140164654], - [0.009973081650240, 0.029615876525905], - [0.009882174486340, 0.029646334131247], - [0.009791174307650, 0.029676512694001], - [0.009700081970699, 0.029706411930116], - [0.009608898332881, 0.029736031558168], - [0.009517624252453, 0.029765371299366], - [0.009426260588521, 0.029794430877553], - [0.009334808201034, 0.029823210019210], - [0.009243267950778, 0.029851708453456], - [0.009151640699363, 0.029879925912053], - [0.009059927309220, 0.029907862129408], - [0.008968128643591, 0.029935516842573], - [0.008876245566520, 0.029962889791254], - [0.008784278942845, 0.029989980717805], - [0.008692229638191, 0.030016789367235], - [0.008600098518961, 0.030043315487212], - [0.008507886452329, 0.030069558828062], - [0.008415594306230, 0.030095519142772], - [0.008323222949351, 0.030121196186994], - [0.008230773251129, 0.030146589719046], - [0.008138246081733, 0.030171699499915], - [0.008045642312067, 0.030196525293257], - [0.007952962813750, 0.030221066865402], - [0.007860208459119, 0.030245323985357], - [0.007767380121212, 0.030269296424803], - [0.007674478673766, 0.030292983958103], - [0.007581504991203, 0.030316386362302], - [0.007488459948628, 0.030339503417126], - [0.007395344421816, 0.030362334904989], - [0.007302159287206, 0.030384880610993], - [0.007208905421891, 0.030407140322928], - [0.007115583703613, 0.030429113831278], - [0.007022195010752, 0.030450800929220], - [0.006928740222316, 0.030472201412626], - [0.006835220217939, 0.030493315080068], - [0.006741635877866, 0.030514141732814], - [0.006647988082948, 0.030534681174838], - [0.006554277714635, 0.030554933212813], - [0.006460505654964, 0.030574897656119], - [0.006366672786553, 0.030594574316845], - [0.006272779992593, 0.030613963009786], - [0.006178828156839, 0.030633063552447], - [0.006084818163601, 0.030651875765048], - [0.005990750897737, 0.030670399470520], - [0.005896627244644, 0.030688634494512], - [0.005802448090250, 0.030706580665388], - [0.005708214321004, 0.030724237814232], - [0.005613926823871, 0.030741605774849], - [0.005519586486321, 0.030758684383764], - [0.005425194196321, 0.030775473480228], - [0.005330750842327, 0.030791972906214], - [0.005236257313276, 0.030808182506425], - [0.005141714498576, 0.030824102128288], - [0.005047123288102, 0.030839731621963], - [0.004952484572181, 0.030855070840339], - [0.004857799241589, 0.030870119639036], - [0.004763068187541, 0.030884877876411], - [0.004668292301681, 0.030899345413553], - [0.004573472476075, 0.030913522114288], - [0.004478609603205, 0.030927407845180], - [0.004383704575956, 0.030941002475530], - [0.004288758287610, 0.030954305877381], - [0.004193771631837, 0.030967317925516], - [0.004098745502689, 0.030980038497461], - [0.004003680794587, 0.030992467473486], - [0.003908578402316, 0.031004604736602], - [0.003813439221017, 0.031016450172571], - [0.003718264146176, 0.031028003669899], - [0.003623054073616, 0.031039265119839], - [0.003527809899492, 0.031050234416394], - [0.003432532520278, 0.031060911456318], - [0.003337222832760, 0.031071296139114], - [0.003241881734029, 0.031081388367037], - [0.003146510121474, 0.031091188045095], - [0.003051108892766, 0.031100695081051], - [0.002955678945860, 0.031109909385419], - [0.002860221178978, 0.031118830871473], - [0.002764736490604, 0.031127459455239], - [0.002669225779478, 0.031135795055501], - [0.002573689944583, 0.031143837593803], - [0.002478129885137, 0.031151586994444], - [0.002382546500589, 0.031159043184484], - [0.002286940690606, 0.031166206093743], - [0.002191313355067, 0.031173075654800], - [0.002095665394051, 0.031179651802998], - [0.001999997707835, 0.031185934476438], - [0.001904311196878, 0.031191923615985], - [0.001808606761820, 0.031197619165268], - [0.001712885303465, 0.031203021070678], - [0.001617147722782, 0.031208129281370], - [0.001521394920889, 0.031212943749264], - [0.001425627799047, 0.031217464429043], - [0.001329847258653, 0.031221691278159], - [0.001234054201231, 0.031225624256825], - [0.001138249528420, 0.031229263328024], - [0.001042434141971, 0.031232608457502], - [0.000946608943736, 0.031235659613775], - [0.000850774835656, 0.031238416768124], - [0.000754932719759, 0.031240879894597], - [0.000659083498149, 0.031243048970010], - [0.000563228072993, 0.031244923973948], - [0.000467367346520, 0.031246504888762], - [0.000371502221008, 0.031247791699571], - [0.000275633598775, 0.031248784394264], - [0.000179762382174, 0.031249482963498], - [0.000083889473581, 0.031249887400697] -]; - -exports.MDCT_TABLE_256 = [ - [0.088387931675923, 0.000271171628935], - [0.088354655998507, 0.002440238387037], - [0.088268158780110, 0.004607835236780], - [0.088128492123423, 0.006772656498875], - [0.087935740158418, 0.008933398165942], - [0.087690018991670, 0.011088758687994], - [0.087391476636423, 0.013237439756448], - [0.087040292923427, 0.015378147086172], - [0.086636679392621, 0.017509591195118], - [0.086180879165703, 0.019630488181053], - [0.085673166799686, 0.021739560494940], - [0.085113848121515, 0.023835537710479], - [0.084503260043847, 0.025917157289369], - [0.083841770362110, 0.027983165341813], - [0.083129777532952, 0.030032317381813], - [0.082367710434230, 0.032063379076803], - [0.081556028106671, 0.034075126991164], - [0.080695219477356, 0.036066349323177], - [0.079785803065216, 0.038035846634965], - [0.078828326668693, 0.039982432574992], - [0.077823367035766, 0.041904934592675], - [0.076771529516540, 0.043802194644686], - [0.075673447698606, 0.045673069892513], - [0.074529783025390, 0.047516433390863], - [0.073341224397728, 0.049331174766491], - [0.072108487758894, 0.051116200887052], - [0.070832315663343, 0.052870436519557], - [0.069513476829429, 0.054592824978055], - [0.068152765676348, 0.056282328760143], - [0.066751001845620, 0.057937930171918], - [0.065309029707361, 0.059558631940996], - [0.063827717851668, 0.061143457817234], - [0.062307958565413, 0.062691453160784], - [0.060750667294763, 0.064201685517134], - [0.059156782093749, 0.065673245178784], - [0.057527263059216, 0.067105245733220], - [0.055863091752499, 0.068496824596852], - [0.054165270608165, 0.069847143534609], - [0.052434822330188, 0.071155389164853], - [0.050672789275903, 0.072420773449336], - [0.048880232828135, 0.073642534167879], - [0.047058232755862, 0.074819935377512], - [0.045207886563797, 0.075952267855771], - [0.043330308831298, 0.077038849527912], - [0.041426630540984, 0.078079025877766], - [0.039497998397473, 0.079072170341994], - [0.037545574136653, 0.080017684687506], - [0.035570533825892, 0.080914999371817], - [0.033574067155622, 0.081763573886112], - [0.031557376722714, 0.082562897080836], - [0.029521677306074, 0.083312487473584], - [0.027468195134911, 0.084011893539132], - [0.025398167150101, 0.084660693981419], - [0.023312840259098, 0.085258497987320], - [0.021213470584847, 0.085804945462053], - [0.019101322709138, 0.086299707246093], - [0.016977668910873, 0.086742485313442], - [0.014843788399692, 0.087133012951149], - [0.012700966545425, 0.087471054919968], - [0.010550494103830, 0.087756407596056], - [0.008393666439096, 0.087988899093631], - [0.006231782743558, 0.088168389368510], - [0.004066145255116, 0.088294770302461], - [0.001898058472816, 0.088367965768336] -]; - -exports.MDCT_TABLE_1920 = [ - [0.032274858518097, 0.000013202404176], - [0.032274642494505, 0.000118821372483], - [0.032274080835421, 0.000224439068308], - [0.032273173546860, 0.000330054360572], - [0.032271920638538, 0.000435666118218], - [0.032270322123873, 0.000541273210231], - [0.032268378019984, 0.000646874505642], - [0.032266088347691, 0.000752468873546], - [0.032263453131514, 0.000858055183114], - [0.032260472399674, 0.000963632303600], - [0.032257146184092, 0.001069199104358], - [0.032253474520390, 0.001174754454853], - [0.032249457447888, 0.001280297224671], - [0.032245095009606, 0.001385826283535], - [0.032240387252262, 0.001491340501313], - [0.032235334226272, 0.001596838748031], - [0.032229935985750, 0.001702319893890], - [0.032224192588507, 0.001807782809271], - [0.032218104096050, 0.001913226364749], - [0.032211670573582, 0.002018649431111], - [0.032204892090000, 0.002124050879359], - [0.032197768717898, 0.002229429580728], - [0.032190300533560, 0.002334784406698], - [0.032182487616965, 0.002440114229003], - [0.032174330051782, 0.002545417919644], - [0.032165827925374, 0.002650694350905], - [0.032156981328790, 0.002755942395358], - [0.032147790356771, 0.002861160925883], - [0.032138255107744, 0.002966348815672], - [0.032128375683825, 0.003071504938250], - [0.032118152190814, 0.003176628167476], - [0.032107584738196, 0.003281717377568], - [0.032096673439141, 0.003386771443102], - [0.032085418410500, 0.003491789239036], - [0.032073819772804, 0.003596769640711], - [0.032061877650267, 0.003701711523874], - [0.032049592170778, 0.003806613764680], - [0.032036963465906, 0.003911475239711], - [0.032023991670893, 0.004016294825985], - [0.032010676924657, 0.004121071400967], - [0.031997019369789, 0.004225803842586], - [0.031983019152549, 0.004330491029241], - [0.031968676422869, 0.004435131839816], - [0.031953991334348, 0.004539725153692], - [0.031938964044252, 0.004644269850758], - [0.031923594713510, 0.004748764811426], - [0.031907883506716, 0.004853208916638], - [0.031891830592124, 0.004957601047881], - [0.031875436141648, 0.005061940087200], - [0.031858700330859, 0.005166224917208], - [0.031841623338985, 0.005270454421097], - [0.031824205348907, 0.005374627482653], - [0.031806446547156, 0.005478742986267], - [0.031788347123916, 0.005582799816945], - [0.031769907273017, 0.005686796860323], - [0.031751127191935, 0.005790733002674], - [0.031732007081789, 0.005894607130928], - [0.031712547147340, 0.005998418132675], - [0.031692747596989, 0.006102164896182], - [0.031672608642773, 0.006205846310406], - [0.031652130500364, 0.006309461265002], - [0.031631313389067, 0.006413008650337], - [0.031610157531816, 0.006516487357501], - [0.031588663155172, 0.006619896278321], - [0.031566830489325, 0.006723234305370], - [0.031544659768083, 0.006826500331981], - [0.031522151228878, 0.006929693252258], - [0.031499305112758, 0.007032811961088], - [0.031476121664387, 0.007135855354151], - [0.031452601132040, 0.007238822327937], - [0.031428743767604, 0.007341711779751], - [0.031404549826572, 0.007444522607730], - [0.031380019568042, 0.007547253710853], - [0.031355153254712, 0.007649903988952], - [0.031329951152882, 0.007752472342725], - [0.031304413532445, 0.007854957673748], - [0.031278540666888, 0.007957358884484], - [0.031252332833290, 0.008059674878300], - [0.031225790312316, 0.008161904559473], - [0.031198913388214, 0.008264046833205], - [0.031171702348814, 0.008366100605636], - [0.031144157485525, 0.008468064783849], - [0.031116279093331, 0.008569938275893], - [0.031088067470786, 0.008671719990782], - [0.031059522920014, 0.008773408838517], - [0.031030645746705, 0.008875003730092], - [0.031001436260110, 0.008976503577507], - [0.030971894773039, 0.009077907293780], - [0.030942021601857, 0.009179213792959], - [0.030911817066483, 0.009280421990133], - [0.030881281490382, 0.009381530801444], - [0.030850415200566, 0.009482539144097], - [0.030819218527589, 0.009583445936373], - [0.030787691805541, 0.009684250097643], - [0.030755835372048, 0.009784950548375], - [0.030723649568268, 0.009885546210147], - [0.030691134738883, 0.009986036005661], - [0.030658291232103, 0.010086418858753], - [0.030625119399655, 0.010186693694402], - [0.030591619596781, 0.010286859438745], - [0.030557792182239, 0.010386915019088], - [0.030523637518292, 0.010486859363916], - [0.030489155970710, 0.010586691402906], - [0.030454347908763, 0.010686410066936], - [0.030419213705216, 0.010786014288099], - [0.030383753736329, 0.010885502999714], - [0.030347968381849, 0.010984875136338], - [0.030311858025010, 0.011084129633775], - [0.030275423052523, 0.011183265429088], - [0.030238663854579, 0.011282281460612], - [0.030201580824838, 0.011381176667967], - [0.030164174360430, 0.011479949992062], - [0.030126444861948, 0.011578600375117], - [0.030088392733446, 0.011677126760663], - [0.030050018382430, 0.011775528093563], - [0.030011322219859, 0.011873803320018], - [0.029972304660138, 0.011971951387578], - [0.029932966121114, 0.012069971245157], - [0.029893307024070, 0.012167861843041], - [0.029853327793724, 0.012265622132901], - [0.029813028858222, 0.012363251067801], - [0.029772410649132, 0.012460747602215], - [0.029731473601443, 0.012558110692033], - [0.029690218153558, 0.012655339294575], - [0.029648644747289, 0.012752432368600], - [0.029606753827855, 0.012849388874320], - [0.029564545843872, 0.012946207773407], - [0.029522021247356, 0.013042888029011], - [0.029479180493710, 0.013139428605762], - [0.029436024041725, 0.013235828469789], - [0.029392552353570, 0.013332086588727], - [0.029348765894794, 0.013428201931728], - [0.029304665134313, 0.013524173469475], - [0.029260250544412, 0.013620000174189], - [0.029215522600735, 0.013715681019643], - [0.029170481782283, 0.013811214981173], - [0.029125128571406, 0.013906601035686], - [0.029079463453801, 0.014001838161674], - [0.029033486918505, 0.014096925339225], - [0.028987199457889, 0.014191861550031], - [0.028940601567655, 0.014286645777401], - [0.028893693746829, 0.014381277006273], - [0.028846476497755, 0.014475754223221], - [0.028798950326094, 0.014570076416472], - [0.028751115740811, 0.014664242575910], - [0.028702973254178, 0.014758251693091], - [0.028654523381760, 0.014852102761253], - [0.028605766642418, 0.014945794775326], - [0.028556703558297, 0.015039326731945], - [0.028507334654823, 0.015132697629457], - [0.028457660460698, 0.015225906467935], - [0.028407681507891, 0.015318952249187], - [0.028357398331639, 0.015411833976768], - [0.028306811470432, 0.015504550655988], - [0.028255921466016, 0.015597101293927], - [0.028204728863381, 0.015689484899442], - [0.028153234210760, 0.015781700483179], - [0.028101438059619, 0.015873747057582], - [0.028049340964652, 0.015965623636907], - [0.027996943483779, 0.016057329237229], - [0.027944246178133, 0.016148862876456], - [0.027891249612061, 0.016240223574335], - [0.027837954353113, 0.016331410352467], - [0.027784360972039, 0.016422422234315], - [0.027730470042780, 0.016513258245214], - [0.027676282142466, 0.016603917412384], - [0.027621797851405, 0.016694398764938], - [0.027567017753080, 0.016784701333894], - [0.027511942434143, 0.016874824152183], - [0.027456572484404, 0.016964766254662], - [0.027400908496833, 0.017054526678124], - [0.027344951067546, 0.017144104461307], - [0.027288700795801, 0.017233498644904], - [0.027232158283994, 0.017322708271577], - [0.027175324137651, 0.017411732385960], - [0.027118198965418, 0.017500570034678], - [0.027060783379060, 0.017589220266351], - [0.027003077993454, 0.017677682131607], - [0.026945083426576, 0.017765954683088], - [0.026886800299502, 0.017854036975468], - [0.026828229236397, 0.017941928065456], - [0.026769370864511, 0.018029627011808], - [0.026710225814170, 0.018117132875340], - [0.026650794718768, 0.018204444718934], - [0.026591078214767, 0.018291561607551], - [0.026531076941680, 0.018378482608238], - [0.026470791542075, 0.018465206790142], - [0.026410222661558, 0.018551733224515], - [0.026349370948775, 0.018638060984730], - [0.026288237055398, 0.018724189146286], - [0.026226821636121, 0.018810116786819], - [0.026165125348656, 0.018895842986112], - [0.026103148853718, 0.018981366826109], - [0.026040892815028, 0.019066687390916], - [0.025978357899296, 0.019151803766819], - [0.025915544776223, 0.019236715042290], - [0.025852454118485, 0.019321420307998], - [0.025789086601733, 0.019405918656817], - [0.025725442904582, 0.019490209183837], - [0.025661523708606, 0.019574290986376], - [0.025597329698327, 0.019658163163984], - [0.025532861561211, 0.019741824818458], - [0.025468119987662, 0.019825275053848], - [0.025403105671008, 0.019908512976470], - [0.025337819307501, 0.019991537694913], - [0.025272261596305, 0.020074348320047], - [0.025206433239491, 0.020156943965039], - [0.025140334942028, 0.020239323745355], - [0.025073967411776, 0.020321486778774], - [0.025007331359476, 0.020403432185395], - [0.024940427498748, 0.020485159087650], - [0.024873256546079, 0.020566666610309], - [0.024805819220816, 0.020647953880491], - [0.024738116245157, 0.020729020027676], - [0.024670148344147, 0.020809864183709], - [0.024601916245669, 0.020890485482816], - [0.024533420680433, 0.020970883061607], - [0.024464662381971, 0.021051056059087], - [0.024395642086630, 0.021131003616670], - [0.024326360533561, 0.021210724878181], - [0.024256818464715, 0.021290218989868], - [0.024187016624830, 0.021369485100415], - [0.024116955761430, 0.021448522360944], - [0.024046636624808, 0.021527329925030], - [0.023976059968027, 0.021605906948708], - [0.023905226546906, 0.021684252590480], - [0.023834137120014, 0.021762366011328], - [0.023762792448662, 0.021840246374720], - [0.023691193296893, 0.021917892846620], - [0.023619340431478, 0.021995304595495], - [0.023547234621902, 0.022072480792330], - [0.023474876640361, 0.022149420610628], - [0.023402267261751, 0.022226123226426], - [0.023329407263659, 0.022302587818300], - [0.023256297426359, 0.022378813567377], - [0.023182938532797, 0.022454799657339], - [0.023109331368588, 0.022530545274437], - [0.023035476722006, 0.022606049607496], - [0.022961375383975, 0.022681311847926], - [0.022887028148061, 0.022756331189727], - [0.022812435810462, 0.022831106829504], - [0.022737599170003, 0.022905637966469], - [0.022662519028125, 0.022979923802453], - [0.022587196188874, 0.023053963541915], - [0.022511631458899, 0.023127756391950], - [0.022435825647437, 0.023201301562294], - [0.022359779566306, 0.023274598265338], - [0.022283494029900, 0.023347645716133], - [0.022206969855176, 0.023420443132400], - [0.022130207861645, 0.023492989734537], - [0.022053208871367, 0.023565284745628], - [0.021975973708940, 0.023637327391451], - [0.021898503201489, 0.023709116900488], - [0.021820798178663, 0.023780652503931], - [0.021742859472618, 0.023851933435691], - [0.021664687918017, 0.023922958932406], - [0.021586284352013, 0.023993728233451], - [0.021507649614247, 0.024064240580942], - [0.021428784546832, 0.024134495219750], - [0.021349689994350, 0.024204491397504], - [0.021270366803840, 0.024274228364600], - [0.021190815824791, 0.024343705374213], - [0.021111037909128, 0.024412921682298], - [0.021031033911210, 0.024481876547605], - [0.020950804687815, 0.024550569231683], - [0.020870351098134, 0.024618998998889], - [0.020789674003759, 0.024687165116394], - [0.020708774268678, 0.024755066854194], - [0.020627652759262, 0.024822703485116], - [0.020546310344257, 0.024890074284826], - [0.020464747894775, 0.024957178531837], - [0.020382966284284, 0.025024015507516], - [0.020300966388600, 0.025090584496093], - [0.020218749085876, 0.025156884784668], - [0.020136315256592, 0.025222915663218], - [0.020053665783549, 0.025288676424605], - [0.019970801551857, 0.025354166364584], - [0.019887723448925, 0.025419384781811], - [0.019804432364452, 0.025484330977848], - [0.019720929190419, 0.025549004257175], - [0.019637214821078, 0.025613403927192], - [0.019553290152943, 0.025677529298230], - [0.019469156084779, 0.025741379683559], - [0.019384813517595, 0.025804954399392], - [0.019300263354632, 0.025868252764895], - [0.019215506501354, 0.025931274102193], - [0.019130543865439, 0.025994017736379], - [0.019045376356769, 0.026056482995518], - [0.018960004887419, 0.026118669210657], - [0.018874430371648, 0.026180575715833], - [0.018788653725892, 0.026242201848076], - [0.018702675868750, 0.026303546947421], - [0.018616497720974, 0.026364610356909], - [0.018530120205464, 0.026425391422602], - [0.018443544247254, 0.026485889493583], - [0.018356770773502, 0.026546103921965], - [0.018269800713483, 0.026606034062902], - [0.018182634998576, 0.026665679274589], - [0.018095274562256, 0.026725038918274], - [0.018007720340083, 0.026784112358263], - [0.017919973269692, 0.026842898961926], - [0.017832034290785, 0.026901398099707], - [0.017743904345116, 0.026959609145127], - [0.017655584376488, 0.027017531474792], - [0.017567075330734, 0.027075164468401], - [0.017478378155718, 0.027132507508750], - [0.017389493801313, 0.027189559981742], - [0.017300423219401, 0.027246321276391], - [0.017211167363854, 0.027302790784828], - [0.017121727190533, 0.027358967902310], - [0.017032103657269, 0.027414852027226], - [0.016942297723858, 0.027470442561102], - [0.016852310352050, 0.027525738908608], - [0.016762142505537, 0.027580740477564], - [0.016671795149944, 0.027635446678948], - [0.016581269252819, 0.027689856926900], - [0.016490565783622, 0.027743970638730], - [0.016399685713714, 0.027797787234924], - [0.016308630016347, 0.027851306139149], - [0.016217399666655, 0.027904526778260], - [0.016125995641641, 0.027957448582309], - [0.016034418920170, 0.028010070984544], - [0.015942670482954, 0.028062393421421], - [0.015850751312545, 0.028114415332610], - [0.015758662393324, 0.028166136160998], - [0.015666404711489, 0.028217555352697], - [0.015573979255046, 0.028268672357047], - [0.015481387013797, 0.028319486626627], - [0.015388628979331, 0.028369997617257], - [0.015295706145012, 0.028420204788004], - [0.015202619505968, 0.028470107601191], - [0.015109370059084, 0.028519705522399], - [0.015015958802984, 0.028568998020472], - [0.014922386738030, 0.028617984567529], - [0.014828654866302, 0.028666664638963], - [0.014734764191593, 0.028715037713449], - [0.014640715719398, 0.028763103272951], - [0.014546510456900, 0.028810860802724], - [0.014452149412962, 0.028858309791325], - [0.014357633598114, 0.028905449730613], - [0.014262964024545, 0.028952280115756], - [0.014168141706090, 0.028998800445240], - [0.014073167658220, 0.029045010220868], - [0.013978042898030, 0.029090908947771], - [0.013882768444231, 0.029136496134411], - [0.013787345317136, 0.029181771292585], - [0.013691774538648, 0.029226733937433], - [0.013596057132255, 0.029271383587441], - [0.013500194123014, 0.029315719764447], - [0.013404186537539, 0.029359741993647], - [0.013308035403995, 0.029403449803598], - [0.013211741752084, 0.029446842726223], - [0.013115306613032, 0.029489920296820], - [0.013018731019584, 0.029532682054063], - [0.012922016005985, 0.029575127540008], - [0.012825162607977, 0.029617256300097], - [0.012728171862781, 0.029659067883165], - [0.012631044809089, 0.029700561841444], - [0.012533782487056, 0.029741737730567], - [0.012436385938281, 0.029782595109573], - [0.012338856205805, 0.029823133540913], - [0.012241194334091, 0.029863352590452], - [0.012143401369021, 0.029903251827477], - [0.012045478357878, 0.029942830824699], - [0.011947426349339, 0.029982089158259], - [0.011849246393462, 0.030021026407731], - [0.011750939541676, 0.030059642156129], - [0.011652506846768, 0.030097935989909], - [0.011553949362874, 0.030135907498976], - [0.011455268145464, 0.030173556276684], - [0.011356464251335, 0.030210881919845], - [0.011257538738598, 0.030247884028732], - [0.011158492666665, 0.030284562207083], - [0.011059327096240, 0.030320916062102], - [0.010960043089307, 0.030356945204470], - [0.010860641709118, 0.030392649248343], - [0.010761124020182, 0.030428027811361], - [0.010661491088253, 0.030463080514646], - [0.010561743980319, 0.030497806982812], - [0.010461883764593, 0.030532206843968], - [0.010361911510496, 0.030566279729717], - [0.010261828288652, 0.030600025275167], - [0.010161635170872, 0.030633443118931], - [0.010061333230142, 0.030666532903129], - [0.009960923540617, 0.030699294273397], - [0.009860407177603, 0.030731726878888], - [0.009759785217550, 0.030763830372273], - [0.009659058738038, 0.030795604409750], - [0.009558228817767, 0.030827048651045], - [0.009457296536545, 0.030858162759415], - [0.009356262975275, 0.030888946401653], - [0.009255129215945, 0.030919399248091], - [0.009153896341616, 0.030949520972603], - [0.009052565436412, 0.030979311252611], - [0.008951137585505, 0.031008769769084], - [0.008849613875105, 0.031037896206544], - [0.008747995392451, 0.031066690253072], - [0.008646283225794, 0.031095151600306], - [0.008544478464390, 0.031123279943448], - [0.008442582198486, 0.031151074981266], - [0.008340595519310, 0.031178536416098], - [0.008238519519057, 0.031205663953853], - [0.008136355290878, 0.031232457304017], - [0.008034103928871, 0.031258916179656], - [0.007931766528065, 0.031285040297416], - [0.007829344184412, 0.031310829377528], - [0.007726837994772, 0.031336283143813], - [0.007624249056906, 0.031361401323680], - [0.007521578469457, 0.031386183648135], - [0.007418827331946, 0.031410629851778], - [0.007315996744755, 0.031434739672811], - [0.007213087809115, 0.031458512853036], - [0.007110101627101, 0.031481949137863], - [0.007007039301610, 0.031505048276306], - [0.006903901936357, 0.031527810020993], - [0.006800690635862, 0.031550234128164], - [0.006697406505433, 0.031572320357675], - [0.006594050651161, 0.031594068473000], - [0.006490624179905, 0.031615478241233], - [0.006387128199278, 0.031636549433095], - [0.006283563817639, 0.031657281822929], - [0.006179932144080, 0.031677675188707], - [0.006076234288412, 0.031697729312034], - [0.005972471361157, 0.031717443978146], - [0.005868644473532, 0.031736818975914], - [0.005764754737440, 0.031755854097848], - [0.005660803265456, 0.031774549140098], - [0.005556791170816, 0.031792903902453], - [0.005452719567407, 0.031810918188350], - [0.005348589569753, 0.031828591804869], - [0.005244402293001, 0.031845924562742], - [0.005140158852914, 0.031862916276347], - [0.005035860365855, 0.031879566763717], - [0.004931507948778, 0.031895875846539], - [0.004827102719212, 0.031911843350155], - [0.004722645795254, 0.031927469103567], - [0.004618138295554, 0.031942752939435], - [0.004513581339303, 0.031957694694082], - [0.004408976046222, 0.031972294207493], - [0.004304323536549, 0.031986551323320], - [0.004199624931030, 0.032000465888879], - [0.004094881350902, 0.032014037755158], - [0.003990093917884, 0.032027266776813], - [0.003885263754166, 0.032040152812170], - [0.003780391982394, 0.032052695723232], - [0.003675479725661, 0.032064895375674], - [0.003570528107494, 0.032076751638847], - [0.003465538251839, 0.032088264385780], - [0.003360511283053, 0.032099433493181], - [0.003255448325892, 0.032110258841438], - [0.003150350505494, 0.032120740314619], - [0.003045218947373, 0.032130877800478], - [0.002940054777404, 0.032140671190449], - [0.002834859121810, 0.032150120379653], - [0.002729633107153, 0.032159225266897], - [0.002624377860318, 0.032167985754674], - [0.002519094508504, 0.032176401749168], - [0.002413784179212, 0.032184473160250], - [0.002308448000231, 0.032192199901481], - [0.002203087099626, 0.032199581890114], - [0.002097702605728, 0.032206619047093], - [0.001992295647121, 0.032213311297057], - [0.001886867352628, 0.032219658568338], - [0.001781418851302, 0.032225660792960], - [0.001675951272410, 0.032231317906644], - [0.001570465745428, 0.032236629848809], - [0.001464963400018, 0.032241596562566], - [0.001359445366028, 0.032246217994727], - [0.001253912773470, 0.032250494095799], - [0.001148366752513, 0.032254424819990], - [0.001042808433471, 0.032258010125204], - [0.000937238946789, 0.032261249973045], - [0.000831659423030, 0.032264144328817], - [0.000726070992868, 0.032266693161525], - [0.000620474787068, 0.032268896443871], - [0.000514871936481, 0.032270754152261], - [0.000409263572030, 0.032272266266801], - [0.000303650824695, 0.032273432771295], - [0.000198034825504, 0.032274253653254], - [0.000092416705518, 0.032274728903884] -]; - -exports.MDCT_TABLE_240 = [ - [0.091286604111815, 0.000298735779793], - [0.091247502481454, 0.002688238127538], - [0.091145864370807, 0.005075898091152], - [0.090981759437558, 0.007460079287760], - [0.090755300151030, 0.009839147718664], - [0.090466641715108, 0.012211472889198], - [0.090115981961863, 0.014575428926191], - [0.089703561215976, 0.016929395692256], - [0.089229662130024, 0.019271759896156], - [0.088694609490769, 0.021600916198470], - [0.088098769996564, 0.023915268311810], - [0.087442552006035, 0.026213230094844], - [0.086726405258214, 0.028493226639351], - [0.085950820564309, 0.030753695349588], - [0.085116329471329, 0.032993087013213], - [0.084223503897785, 0.035209866863042], - [0.083272955741727, 0.037402515628894], - [0.082265336461381, 0.039569530578832], - [0.081201336628670, 0.041709426549053], - [0.080081685455930, 0.043820736961749], - [0.078907150296148, 0.045902014830227], - [0.077678536117054, 0.047951833750597], - [0.076396684949434, 0.049968788879362], - [0.075062475310050, 0.051951497896226], - [0.073676821599542, 0.053898601951466], - [0.072240673475749, 0.055808766597225], - [0.070755015202858, 0.057680682702068], - [0.069220864976840, 0.059513067348201], - [0.067639274227625, 0.061304664710718], - [0.066011326898512, 0.063054246918278], - [0.064338138703282, 0.064760614894630], - [0.062620856361546, 0.066422599180399], - [0.060860656812842, 0.068039060734572], - [0.059058746410016, 0.069608891715145], - [0.057216360092450, 0.071131016238378], - [0.055334760539699, 0.072604391116154], - [0.053415237306106, 0.074028006570930], - [0.051459105937014, 0.075400886927784], - [0.049467707067153, 0.076722091283096], - [0.047442405501835, 0.077990714149396], - [0.045384589281588, 0.079205886075941], - [0.043295668730857, 0.080366774244592], - [0.041177075491445, 0.081472583040586], - [0.039030261541332, 0.082522554597810], - [0.036856698199564, 0.083515969318206], - [0.034657875117883, 0.084452146364948], - [0.032435299259796, 0.085330444129049], - [0.030190493867775, 0.086150260669096], - [0.027924997419306, 0.086911034123781], - [0.025640362572491, 0.087612243096981], - [0.023338155101933, 0.088253407015092], - [0.021019952825636, 0.088834086456390], - [0.018687344523641, 0.089353883452193], - [0.016341928849164, 0.089812441759604], - [0.013985313232951, 0.090209447105664], - [0.011619112781631, 0.090544627402740], - [0.009244949170797, 0.090817752935000], - [0.006864449533597, 0.091028636515846], - [0.004479245345574, 0.091177133616206], - [0.002090971306534, 0.091263142463585] -]; \ No newline at end of file From 713a5e513c1b91c79fa47ad44b3a7cb7002f3aa1 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sat, 9 Jul 2016 11:23:04 -0700 Subject: [PATCH 07/19] Refactor IMDCT implementation Separate method to compute just the middle half, excluding parts that can be derived by symmetry. Also should be faster. --- src/filter_bank.js | 8 +-- src/mdct.js | 145 ++++++++++++++++++++++----------------------- 2 files changed, 75 insertions(+), 78 deletions(-) diff --git a/src/filter_bank.js b/src/filter_bank.js index 57938ff..5613ae3 100644 --- a/src/filter_bank.js +++ b/src/filter_bank.js @@ -103,7 +103,7 @@ FilterBank.prototype.process = function(info, input, output, channel) { switch (info.windowSequence) { case ICStream.ONLY_LONG_SEQUENCE: - mdctLong.process(input, 0, buf, 0); + mdctLong.full(input, 0, buf, 0); // add second half output of previous frame to windowed output of current frame for (var i = 0; i < length; i++) { @@ -118,7 +118,7 @@ FilterBank.prototype.process = function(info, input, output, channel) { break; case ICStream.LONG_START_SEQUENCE: - mdctLong.process(input, 0, buf, 0); + mdctLong.full(input, 0, buf, 0); // add second half output of previous frame to windowed output of current frame for (var i = 0; i < length; i++) { @@ -142,7 +142,7 @@ FilterBank.prototype.process = function(info, input, output, channel) { case ICStream.EIGHT_SHORT_SEQUENCE: for (var i = 0; i < 8; i++) { - mdctShort.process(input, i * shortLen, buf, 2 * i * shortLen); + mdctShort.full(input, i * shortLen, buf, 2 * i * shortLen); } // add second half output of previous frame to windowed output of current frame @@ -178,7 +178,7 @@ FilterBank.prototype.process = function(info, input, output, channel) { break; case ICStream.LONG_STOP_SEQUENCE: - mdctLong.process(input, 0, buf, 0); + mdctLong.full(input, 0, buf, 0); // add second half output of previous frame to windowed output of current frame // construct first half window using padding with 1's and 0's diff --git a/src/mdct.js b/src/mdct.js index cda858e..868fae1 100644 --- a/src/mdct.js +++ b/src/mdct.js @@ -22,84 +22,81 @@ var FFT = require('./fft'); // Modified Discrete Cosine Transform function MDCT(length, scale) { - this.N = length; - this.N2 = length >>> 1; - this.N4 = length >>> 2; - this.N8 = length >>> 3; - - this.sin = new Float32Array(this.N4); - this.cos = new Float32Array(this.N4); - - let theta = 1.0 / 8.0 + (scale < 0 ? this.N4 : 0); - scale = Math.sqrt(Math.abs(scale)); - for (let i = 0; i < this.N4; i++) { - let alpha = 2 * Math.PI * (i + theta) / length; - this.sin[i] = -Math.sin(alpha) * scale; - this.cos[i] = -Math.cos(alpha) * scale; - } - - this.fft = new FFT(this.N4); - this.buf = new Float32Array(this.N4 * 2); + this.N = length; + this.N2 = length >>> 1; + this.N4 = length >>> 2; + this.N8 = length >>> 3; + + this.sin = new Float32Array(this.N4); + this.cos = new Float32Array(this.N4); + + let theta = 1.0 / 8.0 + (scale < 0 ? this.N4 : 0); + scale = Math.sqrt(Math.abs(scale)); + for (let i = 0; i < this.N4; i++) { + let alpha = 2 * Math.PI * (i + theta) / length; + this.sin[i] = -Math.sin(alpha) * scale; + this.cos[i] = -Math.cos(alpha) * scale; + } + + this.fft = new FFT(this.N4); + this.buf = new Float32Array(this.N4 * 2); } -MDCT.prototype.process = function(input, inOffset, output, outOffset) { - // local access - var N2 = this.N2, - N4 = this.N4, - N8 = this.N8, - buf[N4][2] = this.buf, - tmp = this.tmp, - sin = this.sin, - cos = this.cos, - fft = this.fft; - - // pre-IFFT complex multiplication - let in1 = inOffset; - let in2 = inOffset + N2 - 1; - for (var k = 0; k < N4; k++) { - buf[k][0] = (input[in2] * cos[k]) - (input[in1] * sin[k]); - buf[k][1] = (input[in2] * sin[k]) + (input[in1] * cos[k]); - in1 += 2; - in2 -= 2; - } - - // complex IFFT, non-scaling - fft.process(buf, false); - - // post-IFFT complex multiplication - for (let k = 0; k < N4; k++) { - let r = buf[k][0]; - let i = buf[k][1]; - buf[k][0] = (r * cos[k]) - (i * sin[k]); - buf[k][1] = (r * sin[k]) + (i * cos[k]); - } - - // reordering - for (var k = 0; k < N8; k += 2) { - output[outOffset + 2 * k] = buf[N8 + k][1]; - output[outOffset + 2 + 2 * k] = buf[N8 + 1 + k][1]; - - output[outOffset + 1 + 2 * k] = -buf[N8 - 1 - k][0]; - output[outOffset + 3 + 2 * k] = -buf[N8 - 2 - k][0]; - - output[outOffset + N4 + 2 * k] = buf[k][0]; - output[outOffset + N4 + 2 + 2 * k] = buf[1 + k][0]; - - output[outOffset + N4 + 1 + 2 * k] = -buf[N4 - 1 - k][1]; - output[outOffset + N4 + 3 + 2 * k] = -buf[N4 - 2 - k][1]; - - output[outOffset + N2 + 2 * k] = buf[N8 + k][0]; - output[outOffset + N2 + 2 + 2 * k] = buf[N8 + 1 + k][0]; - - output[outOffset + N2 + 1 + 2 * k] = -buf[N8 - 1 - k][1]; - output[outOffset + N2 + 3 + 2 * k] = -buf[N8 - 2 - k][1]; +/** + * Computes the middle half of the imdct of size N. Excludes the parts that + * can be derived by symmetry. Input N/2 samples, output N/2 samples. + */ +MDCT.prototype.half = function(input, inOffset, output, outOffset) { + // local access + let N2 = this.N2; + let N4 = this.N4; + let N8 = this.N8; + let buf[N4][2] = outOffset ? output.subarray(outOffset) : output; + let sin = this.sin; + let cos = this.cos; - output[outOffset + N2 + N4 + 2 * k] = -buf[k][1]; - output[outOffset + N2 + N4 + 2 + 2 * k] = -buf[1 + k][1]; + // pre-IFFT complex multiplication + let in1 = inOffset; + let in2 = inOffset + N2 - 1; + for (let k = 0; k < N4; k++) { + buf[k][0] = (input[in2] * cos[k]) - (input[in1] * sin[k]); + buf[k][1] = (input[in2] * sin[k]) + (input[in1] * cos[k]); + in1 += 2; + in2 -= 2; + } + + // complex IFFT, non-scaling + this.fft.process(buf, false); + + for (let k = 0; k < N8; k++) { + let r0 = (buf[N8 - k - 1][1] * sin[N8 - k - 1]) - (buf[N8 - k - 1][0] * cos[N8 - k - 1]); + let i1 = (buf[N8 - k - 1][1] * cos[N8 - k - 1]) + (buf[N8 - k - 1][0] * sin[N8 - k - 1]); + let r1 = (buf[N8 + k][1] * sin[N8 + k]) - (buf[N8 + k][0] * cos[N8 + k]); + let i0 = (buf[N8 + k][1] * cos[N8 + k]) + (buf[N8 + k][0] * sin[N8 + k]); + + buf[N8 - k - 1][0] = r0; + buf[N8 - k - 1][1] = i0; + buf[N8 + k][0] = r1; + buf[N8 + k][1] = i1; + } +}; - output[outOffset + N2 + N4 + 1 + 2 * k] = buf[N4 - 1 - k][0]; - output[outOffset + N2 + N4 + 3 + 2 * k] = buf[N4 - 2 - k][0]; - } +/** + * Computes the imdct of size N. Input N/2 samples, output N samples. + */ +MDCT.prototype.full = function(input, inOffset, output, outOffset) { + // local access + let N = this.N; + let N2 = this.N2; + let N4 = this.N4; + let buf = output; + + this.half(input, inOffset, output, outOffset + N4); + + for (let k = 0; k < N4; k++) { + output[outOffset + k] = -output[outOffset + N2 - k - 1]; + output[outOffset + N - k - 1] = output[outOffset + N2 + k]; + } }; module.exports = MDCT; From 6472831ac0a6bbc933862b4632260ee43f292425 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sat, 9 Jul 2016 18:21:54 -0700 Subject: [PATCH 08/19] [SBR] Reimplement QMF filter banks based on IMDCT Way faster than the previous method. This is based on a procedure to implement the filterbank on the DCT-IV described in Hsu, H.W. et al. "A Complex Quadrature Mirror Filterbanks for MPEG-4 HE-AAC", and implementation in ffmpeg. http://sites.google.com/site/wenchiehlee1020/Papers/ComplexFB_AES_121paper144.pdf --- src/sbr/AnalysisFilterbank.js | 57 ++++++++++----------- src/sbr/SynthesisFilterbank.js | 92 +++++++++++++++++----------------- src/sbr/sbr.js | 28 +++++------ 3 files changed, 85 insertions(+), 92 deletions(-) diff --git a/src/sbr/AnalysisFilterbank.js b/src/sbr/AnalysisFilterbank.js index 7fb0378..c174e86 100644 --- a/src/sbr/AnalysisFilterbank.js +++ b/src/sbr/AnalysisFilterbank.js @@ -1,61 +1,56 @@ import {TIME_SLOTS_RATE, WINDOW} from './constants'; +import MDCT from '../mdct'; export default class AnalysisFilterbank { constructor() { this.X = new Float32Array(2 * 320); this.z = new Float32Array(320); - this.u = new Float32Array(64); - - let COEFS[32][64][2] = this.COEFS = new Float32Array(32 * 64 * 2); - let tmp; - for (let k = 0; k < 32; k++) { - for (let n = 0; n < 64; n++) { - tmp = Math.PI / 64.0 * (k + 0.5) * (2 * n - 0.5); - COEFS[k][n][0] = 2 * Math.cos(tmp); - COEFS[k][n][1] = 2 * Math.sin(tmp); - } - } + this.mdct = new MDCT(128, 2); } // in: 1024 time samples, out: 32 x 32 complex process(inp, out[2][32][32][2], ch) { - let COEFS[32][64][2] = this.COEFS; let x[2][320] = this.X; - let n, k, inOff = 0; + let k, inOff = 0; + let z = this.z; // each loop creates 32 complex subband samples for (let l = 0; l < TIME_SLOTS_RATE; l++) { // 1. shift buffer - for (n = 319; n >= 32; n--) { - x[ch][n] = x[ch][n - 32]; + for (k = 319; k >= 32; k--) { + x[ch][k] = x[ch][k - 32]; } // 2. add new samples - for (n = 31; n >= 0; n--) { - x[ch][n] = inp[inOff++]; + for (k = 31; k >= 0; k--) { + x[ch][k] = inp[inOff++]; } // 3. windowing - for (n = 0; n < 320; n++) { - this.z[n] = x[ch][n] * WINDOW[2 * n]; + for (k = 0; k < 320; k++) { + z[k] = x[ch][k] * WINDOW[2 * k]; } // 4. sum samples - for (n = 0; n < 64; n++) { - this.u[n] = this.z[n]; - for (k = 1; k < 5; k++) { - this.u[n] += this.z[n + k * 64]; - } + for (k = 0; k < 64; k++) { + z[k] = z[k] + z[k + 64] + z[k + 128] + z[k + 192] + z[k + 256]; } + + // 5. pre IMDCT shuffle + z[64] = z[0]; + z[65] = z[1]; + for (k = 1; k < 32; k++) { + z[64 + 2 * k ] = -z[64 - k]; + z[64 + 2 * k + 1] = z[ k + 1]; + } + + // 6. calculate subband samples + this.mdct.half(z, 64, z, 0); - // 5. calculate subband samples, TODO: replace with FFT? + // 7. post IMDCT shuffle for (k = 0; k < 32; k++) { - out[ch][l][k][0] = this.u[0] * COEFS[k][0][0]; - out[ch][l][k][1] = this.u[0] * COEFS[k][0][1]; - for (n = 1; n < 64; n++) { - out[ch][l][k][0] += this.u[n] * COEFS[k][n][0]; - out[ch][l][k][1] += this.u[n] * COEFS[k][n][1]; - } + out[ch][l][k][0] = -z[63 - k]; + out[ch][l][k][1] = z[k]; } } } diff --git a/src/sbr/SynthesisFilterbank.js b/src/sbr/SynthesisFilterbank.js index fa9e0e5..d9d3634 100644 --- a/src/sbr/SynthesisFilterbank.js +++ b/src/sbr/SynthesisFilterbank.js @@ -1,69 +1,67 @@ import {TIME_SLOTS_RATE, WINDOW} from './constants'; +import MDCT from '../mdct'; export default class SynthesisFilterbank { constructor() { this.V = new Float32Array(2 * 1280); - this.g = new Float32Array(640); // tmp buffer - this.w = new Float32Array(640); - - // complex coefficients: - let COEFS[128][64][2] = this.COEFS = new Float32Array(128 * 64 * 2); - let fac = 1.0 / 64.0; - let tmp; - for (let n = 0; n < 128; n++) { - for(let k = 0; k < 64; k++) { - tmp = Math.PI / 128 * (k + 0.5) * (2 * n - 255); - COEFS[n][k][0] = fac * Math.cos(tmp); - COEFS[n][k][1] = fac * Math.sin(tmp); - } - } + this.mdctBuf = new Float32Array(2 * 64); + this.mdct = new MDCT(128, 1 / 64); } // in: 64 x 32 complex, out: 2048 time samples - process(inp[2][64][38][2], out, ch) { - let COEFS[128][64][2] = this.COEFS; + process(inp[2][2][38][64], out, ch) { let v[2][1280] = this.V; - let n, k, outOff = 0; + let k, outOff = 0; + let mdctBuf[2][64] = this.mdctBuf; // each loop creates 64 output samples for (let l = 0; l < TIME_SLOTS_RATE; l++) { // 1. shift buffer - for (n = 1279; n >= 128; n--) { - v[ch][n] = v[ch][n - 128]; + for (k = 1279; k >= 128; k--) { + v[ch][k] = v[ch][k - 128]; } - - // 2. multiple input by matrix and save in buffer - for (n = 0; n < 128; n++) { - v[ch][n] = (inp[ch][0][l][0] * COEFS[n][0][0]) - (inp[ch][0][l][1] * COEFS[n][0][1]); - for (k = 1; k < 64; k++) { - v[ch][n] += (inp[ch][k][l][0] * COEFS[n][k][0]) - (inp[ch][k][l][1] * COEFS[n][k][1]); - // if (isNaN(inp[k][l][0])) { - // throw new Error('NAN') - // } - } + + // 2. negate odd imaginary values + for (k = 1; k < 64; k += 2) { + inp[ch][1][l][k] = -inp[ch][1][l][k]; } - // 3. extract samples - for (n = 0; n < 5; n++) { - for (k = 0; k < 64; k++) { - this.g[128 * n + k] = v[ch][256 * n + k]; - this.g[128 * n + 64 + k] = v[ch][256 * n + 192 + k]; - } - } + // 3. compute IMDCT for real and imaginary parts + this.mdct.half(inp[ch][0][l], 0, mdctBuf[0], 0); + this.mdct.half(inp[ch][1][l], 0, mdctBuf[1], 0); - // 4. window signal - for (n = 0; n < 640; n++) { - this.w[n] = this.g[n] * WINDOW[n]; + // 4. combine IMDCT results + for (k = 0; k < 64; k++) { + v[ch][ k] = mdctBuf[1][k] - mdctBuf[0][63 - k]; + v[ch][127 - k] = mdctBuf[1][k] + mdctBuf[0][63 - k]; } - // 5. calculate output samples - for (let i = 0; i < 64; i++) { - out[outOff] = this.w[i]; - for (let j = 1; j < 10; j++) { - out[outOff] = out[outOff] + this.w[64 * j + i]; - } - outOff++; - } + // 5. window and sum + vector_fmul (out, outOff, v[ch], 0, WINDOW, 0, 64); + vector_fmul_add(out, outOff, v[ch], 192, WINDOW, 64, 64); + vector_fmul_add(out, outOff, v[ch], 256, WINDOW, 128, 64); + vector_fmul_add(out, outOff, v[ch], 448, WINDOW, 192, 64); + vector_fmul_add(out, outOff, v[ch], 512, WINDOW, 256, 64); + vector_fmul_add(out, outOff, v[ch], 704, WINDOW, 320, 64); + vector_fmul_add(out, outOff, v[ch], 768, WINDOW, 384, 64); + vector_fmul_add(out, outOff, v[ch], 960, WINDOW, 448, 64); + vector_fmul_add(out, outOff, v[ch], 1024, WINDOW, 512, 64); + vector_fmul_add(out, outOff, v[ch], 1216, WINDOW, 576, 64); + outOff += 64; } } } + +// Performs dst = src0 * src1 for a vector of length len +function vector_fmul(dst, dstOff, src0, src0off, src1, src1off, len) { + for (let i = 0; i < len; i++) { + dst[dstOff++] = src0[src0off++] * src1[src1off++]; + } +} + +// Performs dst += src0 * src1 for a vector of length len +function vector_fmul_add(dst, dstOff, src0, src0off, src1, src1off, len){ + for (let i = 0; i < len; i++) { + dst[dstOff++] += src0[src0off++] * src1[src1off++]; + } +} diff --git a/src/sbr/sbr.js b/src/sbr/sbr.js index 1cf754f..917a81b 100644 --- a/src/sbr/sbr.js +++ b/src/sbr/sbr.js @@ -25,7 +25,7 @@ class SBR { this.hfGen = new HFGenerator; this.hfAdj = new HFAdjuster; - this.X = new Float32Array(2 * 64 * 38 * 2); + this.X = new Float32Array(2 * 2 * 38 * 64); this.Xlow = new Float32Array(32 * 40 * 2); this.Xhigh = new Float32Array(64 * 40 * 2); this.W = new Float32Array(2 * 32 * 32 * 2); @@ -256,7 +256,7 @@ class SBR { let Xhigh[64][40][2] = this.Xhigh; let W[2][32][32][2] = this.W; let Y[2][38][64][2] = this.Y; - let X[2][64][38][2] = this.X; + let X[2][2][38][64] = this.X; // 1. old W -> Xlow (4.6.18.5) let kxPrev = this.tables.kxPrev; @@ -299,19 +299,19 @@ class SBR { let m = this.tables.m; for (l = 0; l < lTemp; l++) { for (k = 0; k X for (l = lTemp; l < TIME_SLOTS_RATE; l++) { for (k = 0; k < kx; k++) { - X[ch][k][l][0] = Xlow[k][l + T_HF_ADJ][0]; - X[ch][k][l][1] = Xlow[k][l + T_HF_ADJ][1]; + X[ch][0][l][k] = Xlow[k][l + T_HF_ADJ][0]; + X[ch][1][l][k] = Xlow[k][l + T_HF_ADJ][1]; } for (k = kx; k Date: Sat, 9 Jul 2016 18:24:04 -0700 Subject: [PATCH 09/19] [SBR] reduce size of window table --- src/sbr/constants.js | 236 +++++++++++++++---------------------------- 1 file changed, 83 insertions(+), 153 deletions(-) diff --git a/src/sbr/constants.js b/src/sbr/constants.js index 193ee8f..272f623 100644 --- a/src/sbr/constants.js +++ b/src/sbr/constants.js @@ -5,165 +5,95 @@ export const T_HF_GEN = 8; export const T_HF_ADJ = 2; export const MAX_BANDS = 64; -export const WINDOW = new Float64Array([ - 0.0, -5.525286E-4, -5.617692E-4, -4.947518E-4, - -4.875227E-4, -4.893791E-4, -5.040714E-4, -5.226564E-4, - -5.466565E-4, -5.677802E-4, -5.87093E-4, -6.132747E-4, - -6.312493E-4, -6.540333E-4, -6.77769E-4, -6.941614E-4, - -7.157736E-4, -7.255043E-4, -7.440941E-4, -7.490598E-4, - -7.681371E-4, -7.724848E-4, -7.834332E-4, -7.779869E-4, - -7.803664E-4, -7.801449E-4, -7.757977E-4, -7.630793E-4, - -7.530001E-4, -7.319357E-4, -7.215391E-4, -6.917937E-4, - -6.650415E-4, -6.341594E-4, -5.946118E-4, -5.564576E-4, - -5.145572E-4, -4.606325E-4, -4.095121E-4, -3.501175E-4, - -2.896981E-4, -2.098337E-4, -1.44638E-4, -6.17334E-5, - 1.34949E-5, 1.094383E-4, 2.043017E-4, 2.949531E-4, - 4.02654E-4, 5.107388E-4, 6.239376E-4, 7.458025E-4, - 8.608443E-4, 9.885988E-4, 0.0011250155, 0.0012577884, - 0.0013902494, 0.0015443219, 0.0016868083, 0.0018348265, - 0.001984114, 0.0021461583, 0.0023017254, 0.0024625616, - 0.0026201758, 0.0027870464, 0.0029469447, 0.003112542, - 0.0032739613, 0.0034418874, 0.0036008268, 0.0037603922, - 0.0039207432, 0.0040819753, 0.0042264269, 0.0043730719, - 0.0045209852, 0.004660646, 0.004793256, 0.0049137603, - 0.0050393022, 0.0051407353, 0.0052461166, 0.0053471681, - 0.0054196775, 0.005487604, 0.0055475714, 0.0055938023, - 0.0056220643, 0.0056455196, 0.0056389199, 0.0056266114, - 0.0055917128, 0.0055404363, 0.0054753783, 0.0053838975, - 0.0052715758, 0.0051382275, 0.0049839687, 0.0048109469, - 0.004603953, 0.0043801861, 0.0041251642, 0.0038456408, - 0.0035401246, 0.0032091885, 0.0028446757, 0.002450854, - 0.0020274176, 0.0015784682, 0.0010902329, 5.832264E-4, - 2.76045E-5, -5.46428E-4, -0.0011568135, -0.0018039472, +export const WINDOW = new Float32Array(640); + +WINDOW.set(new Float32Array([ + 0.0000000000, -0.0005525286, -0.0005617692, -0.0004947518, + -0.0004875227, -0.0004893791, -0.0005040714, -0.0005226564, + -0.0005466565, -0.0005677802, -0.0005870930, -0.0006132747, + -0.0006312493, -0.0006540333, -0.0006777690, -0.0006941614, + -0.0007157736, -0.0007255043, -0.0007440941, -0.0007490598, + -0.0007681371, -0.0007724848, -0.0007834332, -0.0007779869, + -0.0007803664, -0.0007801449, -0.0007757977, -0.0007630793, + -0.0007530001, -0.0007319357, -0.0007215391, -0.0006917937, + -0.0006650415, -0.0006341594, -0.0005946118, -0.0005564576, + -0.0005145572, -0.0004606325, -0.0004095121, -0.0003501175, + -0.0002896981, -0.0002098337, -0.0001446380, -0.0000617334, + 0.0000134949, 0.0001094383, 0.0002043017, 0.0002949531, + 0.0004026540, 0.0005107388, 0.0006239376, 0.0007458025, + 0.0008608443, 0.0009885988, 0.0011250155, 0.0012577884, + 0.0013902494, 0.0015443219, 0.0016868083, 0.0018348265, + 0.0019841140, 0.0021461583, 0.0023017254, 0.0024625616, + 0.0026201758, 0.0027870464, 0.0029469447, 0.0031125420, + 0.0032739613, 0.0034418874, 0.0036008268, 0.0037603922, + 0.0039207432, 0.0040819753, 0.0042264269, 0.0043730719, + 0.0045209852, 0.0046606460, 0.0047932560, 0.0049137603, + 0.0050393022, 0.0051407353, 0.0052461166, 0.0053471681, + 0.0054196775, 0.0054876040, 0.0055475714, 0.0055938023, + 0.0056220643, 0.0056455196, 0.0056389199, 0.0056266114, + 0.0055917128, 0.0055404363, 0.0054753783, 0.0053838975, + 0.0052715758, 0.0051382275, 0.0049839687, 0.0048109469, + 0.0046039530, 0.0043801861, 0.0041251642, 0.0038456408, + 0.0035401246, 0.0032091885, 0.0028446757, 0.0024508540, + 0.0020274176, 0.0015784682, 0.0010902329, 0.0005832264, + 0.0000276045, -0.0005464280, -0.0011568135, -0.0018039472, -0.0024826723, -0.0031933778, -0.0039401124, -0.0047222596, -0.0055337211, -0.0063792293, -0.0072615816, -0.0081798233, -0.0091325329, -0.0101150215, -0.0111315548, -0.0121849995, - 0.013271822, 0.0143904666, 0.0155405553, 0.0167324712, - 0.0179433381, 0.0191872431, 0.0204531793, 0.021746755, - 0.0230680169, 0.0244160992, 0.0257875847, 0.0271859429, - 0.0286072173, 0.0300502657, 0.0315017608, 0.0329754081, - 0.0344620948, 0.035969756, 0.037481285, 0.0390053679, - 0.040534917, 0.0420649094, 0.0436097542, 0.0451488405, - 0.0466843027, 0.048216572, 0.0497385755, 0.0512556155, - 0.0527630746, 0.0542452768, 0.0557173648, 0.057161645, - 0.0585915683, 0.059983748, 0.0613455171, 0.0626857808, - 0.0639715898, 0.0652247106, 0.0664367512, 0.0676075985, - 0.0687043828, 0.0697630244, 0.070762871, 0.0717002673, - 0.0725682583, 0.0733620255, 0.0741003642, 0.0747452558, - 0.0753137336, 0.0758008358, 0.0761992479, 0.076499217, - 0.076709349, 0.0768173975, 0.0768230011, 0.0767204924, - 0.0765050718, 0.0761748321, 0.0757305756, 0.0751576255, - 0.0744664394, 0.0736406005, 0.0726774642, 0.0715826364, - 0.0703533073, 0.0689664013, 0.0674525021, 0.0657690668, - 0.0639444805, 0.0619602779, 0.059816657, 0.0575152691, - 0.0550460034, 0.0524093821, 0.0495978676, 0.0466303305, - 0.0434768782, 0.0401458278, 0.0366418116, 0.032958393, - 0.0290824006, 0.0250307561, 0.0207997072, 0.0163701258, - 0.0117623832, 0.0069636862, 0.0019765601, -0.0032086896, + 0.0132718220, 0.0143904666, 0.0155405553, 0.0167324712, + 0.0179433381, 0.0191872431, 0.0204531793, 0.0217467550, + 0.0230680169, 0.0244160992, 0.0257875847, 0.0271859429, + 0.0286072173, 0.0300502657, 0.0315017608, 0.0329754081, + 0.0344620948, 0.0359697560, 0.0374812850, 0.0390053679, + 0.0405349170, 0.0420649094, 0.0436097542, 0.0451488405, + 0.0466843027, 0.0482165720, 0.0497385755, 0.0512556155, + 0.0527630746, 0.0542452768, 0.0557173648, 0.0571616450, + 0.0585915683, 0.0599837480, 0.0613455171, 0.0626857808, + 0.0639715898, 0.0652247106, 0.0664367512, 0.0676075985, + 0.0687043828, 0.0697630244, 0.0707628710, 0.0717002673, + 0.0725682583, 0.0733620255, 0.0741003642, 0.0747452558, + 0.0753137336, 0.0758008358, 0.0761992479, 0.0764992170, + 0.0767093490, 0.0768173975, 0.0768230011, 0.0767204924, + 0.0765050718, 0.0761748321, 0.0757305756, 0.0751576255, + 0.0744664394, 0.0736406005, 0.0726774642, 0.0715826364, + 0.0703533073, 0.0689664013, 0.0674525021, 0.0657690668, + 0.0639444805, 0.0619602779, 0.0598166570, 0.0575152691, + 0.0550460034, 0.0524093821, 0.0495978676, 0.0466303305, + 0.0434768782, 0.0401458278, 0.0366418116, 0.0329583930, + 0.0290824006, 0.0250307561, 0.0207997072, 0.0163701258, + 0.0117623832, 0.0069636862, 0.0019765601, -0.0032086896, -0.0085711749, -0.0141288827, -0.0198834129, -0.0258227288, -0.0319531274, -0.0382776572, -0.0447806821, -0.0514804176, - -0.0583705326, -0.0654409853, -0.07269433, -0.0801372934, + -0.0583705326, -0.0654409853, -0.0726943300, -0.0801372934, -0.0877547536, -0.0955533352, -0.1035329531, -0.1116826931, - -0.1200077984, -0.128500285, -0.1371551761, -0.1459766491, + -0.1200077984, -0.1285002850, -0.1371551761, -0.1459766491, -0.1549607071, -0.1640958855, -0.1733808172, -0.1828172548, -0.1923966745, -0.2021250176, -0.2119735853, -0.2219652696, - -0.232069087, -0.2423016884, -0.2526480309, -0.2631053299, - -0.273663404, -0.2843214189, -0.2950716717, -0.3059098575, + -0.2320690870, -0.2423016884, -0.2526480309, -0.2631053299, + -0.2736634040, -0.2843214189, -0.2950716717, -0.3059098575, -0.3168278913, -0.3278113727, -0.3388722693, -0.3499914122, - 0.3611589903, 0.3723795546, 0.3836350013, 0.3949211761, - 0.4062317676, 0.4175696896, 0.428911992, 0.4402553754, - 0.4515996535, 0.4629308085, 0.4742453214, 0.4855253091, - 0.4967708254, 0.50798175, 0.519123497, 0.5302240895, - 0.5412553448, 0.5522051258, 0.563078914, 0.5738524131, - 0.5845403235, 0.5951123086, 0.6055783538, 0.6159109932, - 0.6261242695, 0.6361980107, 0.6461269695, 0.6559016302, - 0.665513988, 0.674966319, 0.6842353293, 0.6933282376, - 0.7022388719, 0.7109410426, 0.7194462634, 0.72774489, - 0.7358211758, 0.7436827863, 0.7513137456, 0.758708076, - 0.7658674865, 0.7727780881, 0.7794287519, 0.785835312, - 0.7919735841, 0.7978466413, 0.8034485751, 0.8087695004, - 0.813819127, 0.8185776004, 0.823041989, 0.8272275347, - 0.8311038457, 0.8346937361, 0.8379717337, 0.8409541392, - 0.8436238281, 0.8459818469, 0.8480315777, 0.8497805198, - 0.8511971524, 0.8523047035, 0.8531020949, 0.8535720573, - 0.85373856, 0.8535720573, 0.8531020949, 0.8523047035, - 0.8511971524, 0.8497805198, 0.8480315777, 0.8459818469, - 0.8436238281, 0.8409541392, 0.8379717337, 0.8346937361, - 0.8311038457, 0.8272275347, 0.823041989, 0.8185776004, - 0.813819127, 0.8087695004, 0.8034485751, 0.7978466413, - 0.7919735841, 0.785835312, 0.7794287519, 0.7727780881, - 0.7658674865, 0.758708076, 0.7513137456, 0.7436827863, - 0.7358211758, 0.72774489, 0.7194462634, 0.7109410426, - 0.7022388719, 0.6933282376, 0.6842353293, 0.674966319, - 0.665513988, 0.6559016302, 0.6461269695, 0.6361980107, - 0.6261242695, 0.6159109932, 0.6055783538, 0.5951123086, - 0.5845403235, 0.5738524131, 0.563078914, 0.5522051258, - 0.5412553448, 0.5302240895, 0.519123497, 0.50798175, - 0.4967708254, 0.4855253091, 0.4742453214, 0.4629308085, - 0.4515996535, 0.4402553754, 0.428911992, 0.4175696896, - 0.4062317676, 0.3949211761, 0.3836350013, 0.3723795546, - -0.3611589903, -0.3499914122, -0.3388722693, -0.3278113727, - -0.3168278913, -0.3059098575, -0.2950716717, -0.2843214189, - -0.273663404, -0.2631053299, -0.2526480309, -0.2423016884, - -0.232069087, -0.2219652696, -0.2119735853, -0.2021250176, - -0.1923966745, -0.1828172548, -0.1733808172, -0.1640958855, - -0.1549607071, -0.1459766491, -0.1371551761, -0.128500285, - -0.1200077984, -0.1116826931, -0.1035329531, -0.0955533352, - -0.0877547536, -0.0801372934, -0.07269433, -0.0654409853, - -0.0583705326, -0.0514804176, -0.0447806821, -0.0382776572, - -0.0319531274, -0.0258227288, -0.0198834129, -0.0141288827, - -0.0085711749, -0.0032086896, 0.0019765601, 0.0069636862, - 0.0117623832, 0.0163701258, 0.0207997072, 0.0250307561, - 0.0290824006, 0.032958393, 0.0366418116, 0.0401458278, - 0.0434768782, 0.0466303305, 0.0495978676, 0.0524093821, - 0.0550460034, 0.0575152691, 0.059816657, 0.0619602779, - 0.0639444805, 0.0657690668, 0.0674525021, 0.0689664013, - 0.0703533073, 0.0715826364, 0.0726774642, 0.0736406005, - 0.0744664394, 0.0751576255, 0.0757305756, 0.0761748321, - 0.0765050718, 0.0767204924, 0.0768230011, 0.0768173975, - 0.076709349, 0.076499217, 0.0761992479, 0.0758008358, - 0.0753137336, 0.0747452558, 0.0741003642, 0.0733620255, - 0.0725682583, 0.0717002673, 0.070762871, 0.0697630244, - 0.0687043828, 0.0676075985, 0.0664367512, 0.0652247106, - 0.0639715898, 0.0626857808, 0.0613455171, 0.059983748, - 0.0585915683, 0.057161645, 0.0557173648, 0.0542452768, - 0.0527630746, 0.0512556155, 0.0497385755, 0.048216572, - 0.0466843027, 0.0451488405, 0.0436097542, 0.0420649094, - 0.040534917, 0.0390053679, 0.037481285, 0.035969756, - 0.0344620948, 0.0329754081, 0.0315017608, 0.0300502657, - 0.0286072173, 0.0271859429, 0.0257875847, 0.0244160992, - 0.0230680169, 0.021746755, 0.0204531793, 0.0191872431, - 0.0179433381, 0.0167324712, 0.0155405553, 0.0143904666, - -0.013271822, -0.0121849995, -0.0111315548, -0.0101150215, - -0.0091325329, -0.0081798233, -0.0072615816, -0.0063792293, - -0.0055337211, -0.0047222596, -0.0039401124, -0.0031933778, - -0.0024826723, -0.0018039472, -0.0011568135, -5.46428E-4, - 2.76045E-5, 5.832264E-4, 0.0010902329, 0.0015784682, - 0.0020274176, 0.002450854, 0.0028446757, 0.0032091885, - 0.0035401246, 0.0038456408, 0.0041251642, 0.0043801861, - 0.004603953, 0.0048109469, 0.0049839687, 0.0051382275, - 0.0052715758, 0.0053838975, 0.0054753783, 0.0055404363, - 0.0055917128, 0.0056266114, 0.0056389199, 0.0056455196, - 0.0056220643, 0.0055938023, 0.0055475714, 0.005487604, - 0.0054196775, 0.0053471681, 0.0052461166, 0.0051407353, - 0.0050393022, 0.0049137603, 0.004793256, 0.004660646, - 0.0045209852, 0.0043730719, 0.0042264269, 0.0040819753, - 0.0039207432, 0.0037603922, 0.0036008268, 0.0034418874, - 0.0032739613, 0.003112542, 0.0029469447, 0.0027870464, - 0.0026201758, 0.0024625616, 0.0023017254, 0.0021461583, - 0.001984114, 0.0018348265, 0.0016868083, 0.0015443219, - 0.0013902494, 0.0012577884, 0.0011250155, 9.885988E-4, - 8.608443E-4, 7.458025E-4, 6.239376E-4, 5.107388E-4, - 4.02654E-4, 2.949531E-4, 2.043017E-4, 1.094383E-4, - 1.34949E-5, -6.17334E-5, -1.44638E-4, -2.098337E-4, - -2.896981E-4, -3.501175E-4, -4.095121E-4, -4.606325E-4, - -5.145572E-4, -5.564576E-4, -5.946118E-4, -6.341594E-4, - -6.650415E-4, -6.917937E-4, -7.215391E-4, -7.319357E-4, - -7.530001E-4, -7.630793E-4, -7.757977E-4, -7.801449E-4, - -7.803664E-4, -7.779869E-4, -7.834332E-4, -7.724848E-4, - -7.681371E-4, -7.490598E-4, -7.440941E-4, -7.255043E-4, - -7.157736E-4, -6.941614E-4, -6.77769E-4, -6.540333E-4, - -6.312493E-4, -6.132747E-4, -5.87093E-4, -5.677802E-4, - -5.466565E-4, -5.226564E-4, -5.040714E-4, -4.893791E-4, - -4.875227E-4, -4.947518E-4, -5.617692E-4, -5.52528E-4 -]); + 0.3611589903, 0.3723795546, 0.3836350013, 0.3949211761, + 0.4062317676, 0.4175696896, 0.4289119920, 0.4402553754, + 0.4515996535, 0.4629308085, 0.4742453214, 0.4855253091, + 0.4967708254, 0.5079817500, 0.5191234970, 0.5302240895, + 0.5412553448, 0.5522051258, 0.5630789140, 0.5738524131, + 0.5845403235, 0.5951123086, 0.6055783538, 0.6159109932, + 0.6261242695, 0.6361980107, 0.6461269695, 0.6559016302, + 0.6655139880, 0.6749663190, 0.6842353293, 0.6933282376, + 0.7022388719, 0.7109410426, 0.7194462634, 0.7277448900, + 0.7358211758, 0.7436827863, 0.7513137456, 0.7587080760, + 0.7658674865, 0.7727780881, 0.7794287519, 0.7858353120, + 0.7919735841, 0.7978466413, 0.8034485751, 0.8087695004, + 0.8138191270, 0.8185776004, 0.8230419890, 0.8272275347, + 0.8311038457, 0.8346937361, 0.8379717337, 0.8409541392, + 0.8436238281, 0.8459818469, 0.8480315777, 0.8497805198, + 0.8511971524, 0.8523047035, 0.8531020949, 0.8535720573, + 0.8537385600, +])); + +for (let n = 1; n < 320; n++) { + WINDOW[320 + n] = WINDOW[320 - n]; +} + +WINDOW[384] = -WINDOW[384]; +WINDOW[512] = -WINDOW[512]; From 2e1eafa48956be3b68bc49b6d623c0462d21bc29 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sat, 9 Jul 2016 18:24:24 -0700 Subject: [PATCH 10/19] [SBR] cleanup --- src/sbr/FrequencyTables.js | 4 ++-- src/sbr/HFAdjuster.js | 4 ++-- src/sbr/sbr.js | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sbr/FrequencyTables.js b/src/sbr/FrequencyTables.js index 0a2ab3c..8a1f28f 100644 --- a/src/sbr/FrequencyTables.js +++ b/src/sbr/FrequencyTables.js @@ -147,7 +147,7 @@ export default class FrequencyTables { // check requirement (4.6.18.6.3): if (vDk0[i] <= 0) { - throw new AACException("SBR: illegal value in master frequency table: " + vDk0[i]); + throw new Error("SBR: illegal value in master frequency table: " + vDk0[i]); } } @@ -286,7 +286,7 @@ export default class FrequencyTables { // check requirement (4.6.18.6.3): if (this.patchCount > 5) { - throw new AACException("SBR: too many patches: " + this.patchCount); + throw new Error("SBR: too many patches: " + this.patchCount); } } diff --git a/src/sbr/HFAdjuster.js b/src/sbr/HFAdjuster.js index 82a3d0e..f225d9d 100644 --- a/src/sbr/HFAdjuster.js +++ b/src/sbr/HFAdjuster.js @@ -358,8 +358,8 @@ export default class HFAdjuster { Y[ch][i][m + kx][1] += Sm[e][m] * (PHI[1][sineIndex] * phiSign); phiSign = -phiSign; - if (isNaN(Y[i][m + kx][0]) || isNaN(Y[i][m + kx][1])) { - console.log(this.Sm[e][m], PHI[0][sineIndex]); + if (isNaN(Y[ch][i][m + kx][0]) || isNaN(Y[ch][i][m + kx][1])) { + console.log(Sm[e][m], PHI[0][sineIndex]); } } } diff --git a/src/sbr/sbr.js b/src/sbr/sbr.js index 917a81b..b9ea7ea 100644 --- a/src/sbr/sbr.js +++ b/src/sbr/sbr.js @@ -70,18 +70,18 @@ class SBR { this.decodeSingleChannel(stream); } - if (stream.read(1)) { + if (stream.read(1)) { let count = stream.read(4); if (count === 15) count += stream.read(8); let bitsLeft = 8 * count; let extensionID; - while (bitsLeft>7) { + while (bitsLeft > 7) { bitsLeft -= 2; extensionID = stream.read(2); bitsLeft -= this.decodeExtension(stream, extensionID); } - } + } } stream.seek(end); From 6d90963a8cae552cc0aecdbce2adc52837752473 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 10 Jul 2016 01:05:52 -0700 Subject: [PATCH 11/19] [SBR] implement single channel decoding --- src/decoder.js | 2 +- src/sbr/sbr.js | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/decoder.js b/src/decoder.js index 5c337ad..8109bb1 100644 --- a/src/decoder.js +++ b/src/decoder.js @@ -319,7 +319,7 @@ class AACDecoder extends AV.Decoder { throw new Error("Gain control not implemented"); if (this.sbrPresent) - throw new Error("SBR not implemented"); + element.sbr.process(this.data[channel], null, false); return 1; } diff --git a/src/sbr/sbr.js b/src/sbr/sbr.js index b9ea7ea..bf70a13 100644 --- a/src/sbr/sbr.js +++ b/src/sbr/sbr.js @@ -87,6 +87,21 @@ class SBR { stream.seek(end); } + decodeSingleChannel(stream) { + if (stream.read(1)) { + stream.advance(4); // reserved + } + + this.cd[0].decodeGrid(stream, this.header, this.tables); + this.cd[0].decodeDTDF(stream); + this.cd[0].decodeInvf(stream, this.header, this.tables); + this.cd[0].decodeEnvelope(stream, this.header, this.tables, false, false); + this.cd[0].decodeNoise(stream, this.header, this.tables, false, false); + this.cd[0].decodeSinusoidal(stream, this.header, this.tables); + + this.dequantSingle(this.cd[0]); + } + decodeChannelPair(stream) { if (stream.read(1)) { stream.advance(8); // reserved From afe8a386f47e8d51d7f76d8e36b22ef7b1233fe4 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 10 Jul 2016 01:06:44 -0700 Subject: [PATCH 12/19] [SBR] Disable parametric stereo for now --- src/sbr/sbr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sbr/sbr.js b/src/sbr/sbr.js index bf70a13..68fac02 100644 --- a/src/sbr/sbr.js +++ b/src/sbr/sbr.js @@ -235,7 +235,7 @@ class SBR { switch (extensionID) { case EXTENSION_ID_PS: console.log("PS!") - this.psUsed = true; + // this.psUsed = true; // if(ps==null) ps = new PS(); // ps.decode(in); // if(!psUsed&&ps.hasHeader()) psUsed = true; From e6c7bcb73d1ed5b3d0e5b677e1f59fbabafac1d0 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 10 Jul 2016 01:46:48 -0700 Subject: [PATCH 13/19] [SBR] Support explicit SBR and PS profiles --- src/decoder.js | 66 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/decoder.js b/src/decoder.js index 8109bb1..1a94f90 100644 --- a/src/decoder.js +++ b/src/decoder.js @@ -32,6 +32,8 @@ var SBR = require('./sbr/sbr'); const AOT_AAC_MAIN = 1, // no AOT_AAC_LC = 2, // yes AOT_AAC_LTP = 4, // no + AOT_AAC_SBR = 5, + AOT_AAC_PS = 29, AOT_ESCAPE = 31; // Channel configurations @@ -62,28 +64,24 @@ class AACDecoder extends AV.Decoder { var stream = AV.Bitstream.fromBuffer(buffer); this.config = {}; - this.config.profile = stream.read(5); - if (this.config.profile === AOT_ESCAPE) - this.config.profile = 32 + stream.read(6); - - this.config.sampleIndex = stream.read(4); - if (this.config.sampleIndex === 0x0f) { - this.config.sampleRate = stream.read(24); - for (var i = 0; i < tables.SAMPLE_RATES.length; i++) { - if (tables.SAMPLE_RATES[i] === this.config.sampleRate) { - this.config.sampleIndex = i; - break; - } - } - } else { - this.config.sampleRate = tables.SAMPLE_RATES[this.config.sampleIndex]; - } - + this.config.profile = this.decodeProfile(stream); + this.decodeSampleRate(stream, this.config); + this.config.chanConfig = stream.read(4); this.format.channelsPerFrame = this.config.chanConfig; // sometimes m4a files encode this wrong this.format.sampleRate = this.config.sampleRate; switch (this.config.profile) { + case AOT_AAC_PS: + this.config.psPresent = true; + // fall through + + case AOT_AAC_SBR: + this.config.sbrPresent = true; + this.format.sampleRate = this.decodeSampleRate(stream).sampleRate; + this.config.profile = this.decodeProfile(stream); + // fall through + case AOT_AAC_MAIN: case AOT_AAC_LC: case AOT_AAC_LTP: @@ -116,20 +114,15 @@ class AACDecoder extends AV.Decoder { throw new Error('AAC profile ' + this.config.profile + ' not supported.'); } - console.log(stream.available(10)) if (stream.available(11)) { let type = stream.read(11); switch (type) { - case 0x2B7: - let profile = stream.read(5); - if (profile === 5) { + case 0x2B7: // sync extension + let profile = this.decodeProfile(stream); + if (profile === AOT_AAC_SBR) { this.config.sbrPresent = stream.read(1); if (this.config.sbrPresent) { - this.config.profile = profile; - - let sampleIndex = stream.read(4); - this.format.sampleRate = tables.SAMPLE_RATES[sampleIndex]; - console.log(this.config) + this.format.sampleRate = this.decodeSampleRate(stream).sampleRate; } } break; @@ -138,6 +131,27 @@ class AACDecoder extends AV.Decoder { this.filter_bank = new FilterBank(false, this.config.chanConfig); } + + decodeProfile(stream) { + let profile = stream.read(5); + if (profile === AOT_ESCAPE) { + profile = 32 + stream.read(6); + } + + return profile; + } + + decodeSampleRate(stream, out = {}) { + out.sampleIndex = stream.read(4); + if (out.sampleIndex === 0x0f) { + out.sampleRate = stream.read(24); + out.sampleIndex = tables.SAMPLE_INDEXES[out.sampleRate]; + } else { + out.sampleRate = tables.SAMPLE_RATES[out.sampleIndex]; + } + + return out; + } // The main decoding function. readChunk() { From b2fa19da51f116802806f09b90acdb72325b7188 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 10 Jul 2016 11:20:36 -0700 Subject: [PATCH 14/19] [SBR] fixes for assembling signals in HFAdjuster --- src/sbr/ChannelData.js | 2 +- src/sbr/HFAdjuster.js | 38 +++++++++++++++++--------------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/sbr/ChannelData.js b/src/sbr/ChannelData.js index 4191c12..d2f71c6 100644 --- a/src/sbr/ChannelData.js +++ b/src/sbr/ChannelData.js @@ -380,7 +380,7 @@ export default class ChannelData { //grid this.envCountPrev = this.envCount; this.freqResPrevious = this.freqRes[this.freqRes.length - 1]; - this.laPrevious = this.la; + this.laPrevious = this.la === this.envCountPrev ? 0 : -1; this.tePrevious = this.te[this.envCountPrev]; //invf diff --git a/src/sbr/HFAdjuster.js b/src/sbr/HFAdjuster.js index f225d9d..c5ffb13 100644 --- a/src/sbr/HFAdjuster.js +++ b/src/sbr/HFAdjuster.js @@ -188,7 +188,7 @@ export default class HFAdjuster { let kx = tables.kx; let la = cd.la; - let laPrevious = cd.laPrevious === cd.envCountPrev ? 0 : -1; + let laPrevious = cd.laPrevious; let le = cd.envCount; // output arrays @@ -234,7 +234,6 @@ export default class HFAdjuster { gMax = LIMITER_GAINS[limGain] * Math.sqrt((EPSILON_0 + sum0) / (EPSILON_0 + sum1)); gMax = Math.min(MAX_GAIN, gMax); - // console.log(gMax, limGain, LIMITER_GAINS[limGain], EPSILON_0, sum0, sum1) for (m = fLim[k] - kx; m < fLim[k + 1] - kx; m++) { let qmMax = Qm[e][m] * gMax / gain[e][m]; @@ -256,9 +255,6 @@ export default class HFAdjuster { gain[e][m] *= gainBoost; Qm[e][m] *= gainBoost; Sm[e][m] *= gainBoost; - // if (isNaN(gain[e][m])) { - // console.log(gainBoost, sum0, sum1) - // } } } } @@ -273,9 +269,9 @@ export default class HFAdjuster { let lePrev = cd.envCountPrev; let te = cd.te; let la = cd.la; - let laPrev = cd.laPrevious === cd.envCountPrev ? 0 : -1; + let laPrev = cd.laPrevious; let kx = tables.kx; - let noiseIndex = reset ? 0 : cd.noiseIndex; + let noiseIndex = cd.noiseIndex; let sineIndex = cd.sineIndex; let gTmp[42][48] = cd.gTmp; @@ -311,6 +307,9 @@ export default class HFAdjuster { for (e = 0; e < le; e++) { for (i = RATE * te[e]; i < RATE * te[e + 1]; i++) { + let phiSign0 = PHI[0][sineIndex]; + let phiSign1 = PHI[1][sineIndex] * (1 - 2 * (kx & 1)); + if (hSL !== 0 && e !== la && e != laPrev) { for (m = 0; m < M; m++) { let idx1 = i + hSL; @@ -330,12 +329,12 @@ export default class HFAdjuster { } if (e !== la && e !== laPrev) { - let phiSign = (1 - 2 * (kx & 1)); - for (m = 0; m < M; m++) { + noiseIndex = (noiseIndex + 1) & 0x1ff; + if (Sm[e][m] !== 0) { - Y[ch][i][m + kx][0] += Sm[e][m] * PHI[0][sineIndex]; - Y[ch][i][m + kx][1] += Sm[e][m] * (PHI[1][sineIndex] * phiSign); + Y[ch][i][m + kx][0] += Sm[e][m] * phiSign0; + Y[ch][i][m + kx][1] += Sm[e][m] * phiSign1; } else { if (hSL !== 0) { let idx1 = i + hSL; @@ -349,22 +348,19 @@ export default class HFAdjuster { Y[ch][i][m + kx][0] += qFilt * NOISE_TABLE[noiseIndex][0]; Y[ch][i][m + kx][1] += qFilt * NOISE_TABLE[noiseIndex][1]; } - phiSign = -phiSign; + + phiSign1 = -phiSign1; } } else { - let phiSign = (1 - 2 * (kx & 1)); for (m = 0; m < M; m++) { - Y[ch][i][m + kx][0] += Sm[e][m] * PHI[0][sineIndex]; - Y[ch][i][m + kx][1] += Sm[e][m] * (PHI[1][sineIndex] * phiSign); - phiSign = -phiSign; - - if (isNaN(Y[ch][i][m + kx][0]) || isNaN(Y[ch][i][m + kx][1])) { - console.log(Sm[e][m], PHI[0][sineIndex]); - } + Y[ch][i][m + kx][0] += Sm[e][m] * phiSign0; + Y[ch][i][m + kx][1] += Sm[e][m] * phiSign1; + phiSign1 = -phiSign1; } + + noiseIndex = (noiseIndex + M) & 0x1ff; } - noiseIndex = (noiseIndex + 1) & 0x1ff; sineIndex = (sineIndex + 1) & 3; } } From 7d4be6342143b14541b784d1cb7b917e906a99a3 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 10 Jul 2016 15:05:46 -0700 Subject: [PATCH 15/19] [SBR] Renaming files --- src/sbr/{sbr.js => SBR.js} | 2 +- src/sbr/{header.js => SBRHeader.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/sbr/{sbr.js => SBR.js} (99%) rename src/sbr/{header.js => SBRHeader.js} (100%) diff --git a/src/sbr/sbr.js b/src/sbr/SBR.js similarity index 99% rename from src/sbr/sbr.js rename to src/sbr/SBR.js index 68fac02..4e88c2a 100644 --- a/src/sbr/sbr.js +++ b/src/sbr/SBR.js @@ -1,4 +1,4 @@ -import SBRHeader from './header'; +import SBRHeader from './SBRHeader'; import FrequencyTables from './FrequencyTables'; import ChannelData from './ChannelData'; import AnalysisFilterbank from './AnalysisFilterbank'; diff --git a/src/sbr/header.js b/src/sbr/SBRHeader.js similarity index 100% rename from src/sbr/header.js rename to src/sbr/SBRHeader.js From e81dfaaecef390aa8392c4e9a5f7243f3f7a3940 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 10 Jul 2016 16:06:40 -0700 Subject: [PATCH 16/19] [SBR] code cleanup --- src/decoder.js | 14 ++------------ src/mdct.js | 1 - src/sbr/ChannelData.js | 26 +++++++++++++------------- src/sbr/FrequencyTables.js | 37 ++++++++++++++++++++++--------------- src/sbr/HFAdjuster.js | 7 +++---- src/sbr/HFGenerator.js | 7 ++++--- src/sbr/HuffmanTables.js | 2 +- src/sbr/SBR.js | 22 ++++------------------ src/sbr/SBRHeader.js | 2 +- 9 files changed, 50 insertions(+), 68 deletions(-) diff --git a/src/decoder.js b/src/decoder.js index 1a94f90..747407c 100644 --- a/src/decoder.js +++ b/src/decoder.js @@ -231,11 +231,6 @@ class AACDecoder extends AV.Decoder { var end = stream.offset() + id; FIL.decode(stream, id, this.prev, this.config.sampleRate); - - if (this.prev && this.prev.sbr) { - this.sbrPresent = true; - } - this.prev = null; // skip for now... @@ -273,11 +268,7 @@ class AACDecoder extends AV.Decoder { process(elements) { var channels = this.config.chanConfig; - - // if (channels === 1 && psPresent) - // TODO: sbrPresent (2) var mult = this.config.sbrPresent ? 2 : 1; - var len = mult * this.config.frameLength; var data = this.data = []; @@ -332,7 +323,7 @@ class AACDecoder extends AV.Decoder { if (element.gainPresent) throw new Error("Gain control not implemented"); - if (this.sbrPresent) + if (element.sbr) element.sbr.process(this.data[channel], null, false); return 1; @@ -385,8 +376,7 @@ class AACDecoder extends AV.Decoder { if (right.gainPresent) throw new Error("Gain control not implemented"); - if (this.sbrPresent) { - // throw new Error("SBR not implemented"); + if (element.sbr) { element.sbr.process(this.data[channel], this.data[channel + 1], false); } } diff --git a/src/mdct.js b/src/mdct.js index 868fae1..2b92a59 100644 --- a/src/mdct.js +++ b/src/mdct.js @@ -39,7 +39,6 @@ function MDCT(length, scale) { } this.fft = new FFT(this.N4); - this.buf = new Float32Array(this.N4 * 2); } /** diff --git a/src/sbr/ChannelData.js b/src/sbr/ChannelData.js index d2f71c6..515d952 100644 --- a/src/sbr/ChannelData.js +++ b/src/sbr/ChannelData.js @@ -71,7 +71,7 @@ export default class ChannelData { relLead = this.envCount - 1; if (this.envCount === 1) this.ampRes = false; - //check requirement (4.6.18.6.3): + // check requirement (4.6.18.6.3): else if (this.envCount > 4) { throw new Error("SBR: too many envelopes: " + this.envCount); } @@ -120,7 +120,7 @@ export default class ChannelData { this.freqRes[i] = stream.read(1); } break; - default: //VARVAR + default: // VARVAR this.te[0] = stream.read(2); absBordTrail += stream.read(2); relLead = stream.read(2); @@ -250,37 +250,37 @@ export default class ChannelData { for (j = 0; j < envBands[this.freqRes[i]]; j++) { envelopeSFQ[i + 1][j] = envelopeSFQ[i][j] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); if (envelopeSFQ[i + 1][j] > 127) { - console.log("OUT OF BOUNDS", envelopeSFQ[i + 1][j], i, envelopeSFQ[i][j], delta, tLav) + throw new Error('Envelope scale factor out of bounds'); } } } else if (this.freqRes[i] !== 0) { for (j = 0; j < envBands[this.freqRes[i]]; j++) { - k = (j + odd) >> 1; //fLow[k] <= fHigh[j] < fLow[k + 1] + k = (j + odd) >> 1; // fLow[k] <= fHigh[j] < fLow[k + 1] envelopeSFQ[i + 1][j] = envelopeSFQ[i][k] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); if (envelopeSFQ[i + 1][j] > 127) { - console.log("OUT OF BOUNDS 2", envelopeSFQ[i + 1][j], i, k, envelopeSFQ[i][k], delta, tLav) + throw new Error('Envelope scale factor out of bounds'); } } } else { for (j = 0; j < envBands[this.freqRes[i]]; j++) { - k = j !== 0 ? (2 * j - odd) : 0; //fHigh[k] == fLow[j] + k = j !== 0 ? (2 * j - odd) : 0; // fHigh[k] == fLow[j] envelopeSFQ[i + 1][j] = envelopeSFQ[i][k] + ((this.decodeHuffman(stream, tHuff) - tLav) << delta); if (envelopeSFQ[i + 1][j] > 127) { - console.log("OUT OF BOUNDS 3", envelopeSFQ[i + 1][j], i, k, envelopeSFQ[i][k], delta, tLav) + throw new Error('Envelope scale factor out of bounds'); } } } } else { envelopeSFQ[i + 1][0] = stream.read(bits) << delta; if (envelopeSFQ[i + 1][0] > 127) { - console.log("OUT OF BOUNDS 5", envelopeSFQ[i + 1][0], delta) + throw new Error('Envelope scale factor out of bounds'); } for (j = 1; j < envBands[this.freqRes[i]]; j++) { envelopeSFQ[i + 1][j] = envelopeSFQ[i + 1][j - 1] + ((this.decodeHuffman(stream, fHuff) - fLav) << delta); if (envelopeSFQ[i + 1][j] > 127) { - console.log("OUT OF BOUNDS 4", envelopeSFQ[i + 1][j], envelopeSFQ[i + 1][j - 1], delta, tLav) + throw new Error('Envelope scale factor out of bounds'); } } } @@ -342,7 +342,7 @@ export default class ChannelData { } } - //save for next frame + // save for next frame noiseFloorDataQ[0].set(noiseFloorDataQ[this.noiseCount]); } @@ -374,16 +374,16 @@ export default class ChannelData { } savePreviousData() { - //lTemp for next frame + // lTemp for next frame this.lTemp = RATE * this.te[this.envCount] - TIME_SLOTS_RATE; - //grid + // grid this.envCountPrev = this.envCount; this.freqResPrevious = this.freqRes[this.freqRes.length - 1]; this.laPrevious = this.la === this.envCountPrev ? 0 : -1; this.tePrevious = this.te[this.envCountPrev]; - //invf + // invf this.invfModePrevious.set(this.invfMode); } } diff --git a/src/sbr/FrequencyTables.js b/src/sbr/FrequencyTables.js index 8a1f28f..ec90307 100644 --- a/src/sbr/FrequencyTables.js +++ b/src/sbr/FrequencyTables.js @@ -8,12 +8,12 @@ const MFT_START_MIN = new Uint8Array([7, 7, 10, 11, 12, 16, 16, 17, 24]); const MFT_STOP_MIN = new Uint8Array([13, 15, 20, 21, 23, 32, 32, 35, 48]); const MFT_SF_OFFSETS = new Uint8Array([5, 5, 4, 4, 4, 3, 2, 1, 0]); const MFT_START_OFFSETS = [ - new Int8Array([-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7]), //16000 - new Int8Array([-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13]), //22050 - new Int8Array([-5, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16]), //24000 - new Int8Array([-6, -4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16]), //32000 - new Int8Array([-4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20]), //44100-64000 - new Int8Array([-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24]) //>64000 + new Int8Array([-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7]), // 16000 + new Int8Array([-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13]), // 22050 + new Int8Array([-5, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16]), // 24000 + new Int8Array([-6, -4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16]), // 32000 + new Int8Array([-4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20]), // 44100-64000 + new Int8Array([-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24]) // >64000 ]; const MFT_STOP_OFFSETS = [ new Uint8Array([2, 4, 6, 8, 11, 14, 18, 22, 26, 31, 37, 44, 51]), @@ -29,9 +29,9 @@ const MFT_STOP_OFFSETS = [ const MFT_INPUT1 = new Uint8Array([12, 10, 8]); const MFT_INPUT2 = new Float32Array([1.0, 1.3]); const LIM_BANDS_PER_OCTAVE_POW = new Float32Array([ - 1.32715174233856803909, //2^(0.49/1.2) - 1.18509277094158210129, //2^(0.49/2) - 1.11987160404675912501 //2^(0.49/3) + 1.32715174233856803909, // 2^(0.49/1.2) + 1.18509277094158210129, // 2^(0.49/2) + 1.11987160404675912501 // 2^(0.49/3) ]); const GOAL_SB_FACTOR = 2.048E6; @@ -99,7 +99,7 @@ export default class FrequencyTables { throw new Error("SBR: too many subbands: "+ (this.k2 - this.k0) + ", maximum number for samplerate " + this.sampleRate + ": " + max); } - //MFT calculation + // MFT calculation if (header.frequencyScale === 0) { // TODO this.calculateMFT1(header, this.k0, this.k2); @@ -107,13 +107,13 @@ export default class FrequencyTables { this.calculateMFT2(header, this.k0, this.k2); } - //check requirement (4.6.18.3.6): + // check requirement (4.6.18.3.6): if (header.xOverBand >= this.nMaster) { throw new Error("SBR: illegal length of master frequency table: " + this.nMaster + ", xOverBand: " + header.xOverBand); } } - // MFT calculation if frequencyScale>0 + // MFT calculation if frequencyScale > 0 calculateMFT2(header, k0, k2) { let bands = MFT_INPUT1[header.frequencyScale - 1]; let warp = MFT_INPUT2[header.alterScale ? 1 : 0]; @@ -213,8 +213,13 @@ export default class FrequencyTables { this.m = this.fTable[1][this.n[1]] - this.kx; // check requirements (4.6.18.3.6): - if (this.kx > 32) throw new Error("SBR: start frequency border out of range: " + this.kx); - if ((this.kx + this.m) > 64) throw new Error("SBR: stop frequency border out of range: " + (this.kx + this.m)); + if (this.kx > 32) { + throw new Error("SBR: start frequency border out of range: " + this.kx); + } + + if ((this.kx + this.m) > 64) { + throw new Error("SBR: stop frequency border out of range: " + (this.kx + this.m)); + } this.fTable[0] = new Int32Array(this.n[0] + 1); this.fTable[0][0] = this.fTable[1][0]; @@ -230,7 +235,9 @@ export default class FrequencyTables { this.nq = Math.max(1, x); // check requirement (4.6.18.6.3): - if (this.nq > 5) throw new Error("SBR: too many noise floor scalefactors: " + this.nq); + if (this.nq > 5) { + throw new Error("SBR: too many noise floor scalefactors: " + this.nq); + } this.fNoise = new Int32Array(this.nq + 1); this.fNoise[0] = this.fTable[0][0]; diff --git a/src/sbr/HFAdjuster.js b/src/sbr/HFAdjuster.js index c5ffb13..b32f315 100644 --- a/src/sbr/HFAdjuster.js +++ b/src/sbr/HFAdjuster.js @@ -52,7 +52,7 @@ export default class HFAdjuster { let freqRes = cd.freqRes; let la = cd.la; - //input and output arrays + // input and output arrays let eOrig[5][48] = cd.envelopeSF; let eMapped[7][48] = this.eMapped; let qOrig[2][64] = cd.noiseFloorData; @@ -137,7 +137,7 @@ export default class HFAdjuster { for (m = 0; m < M; m++) { sum = 0.0; - //energy = sum over squares of absolute value + // energy = sum over squares of absolute value for (i = iLow; i < iHigh; i++) { sum += Xhigh[m + kx][i][0] * Xhigh[m + kx][i][0] + Xhigh[m + kx][i][1] * Xhigh[m + kx][i][1]; } @@ -148,7 +148,6 @@ export default class HFAdjuster { } else { let n = tables.n; let freqRes = cd.freqRes; - let k; let table; let div1, div2; @@ -179,7 +178,7 @@ export default class HFAdjuster { } } - //calculation of levels of additional HF signal components (4.6.18.7.4) and gain calculation (4.6.18.7.5) + // calculation of levels of additional HF signal components (4.6.18.7.4) and gain calculation (4.6.18.7.5) calculateGain(header, tables, cd) { let limGain = header.limiterGains; let M = tables.m; diff --git a/src/sbr/HFGenerator.js b/src/sbr/HFGenerator.js index 34cd3c7..9ff44a4 100644 --- a/src/sbr/HFGenerator.js +++ b/src/sbr/HFGenerator.js @@ -3,7 +3,7 @@ import {RATE, T_HF_ADJ} from './constants'; const RELAX_COEF = 1.000001; const ALPHA_MAX = 16; const CHIRP_COEFS = [[0.75, 0.25], [0.90625, 0.09375]]; -//values for bw [invfModePrev][invfMode] +// values for bw [invfModePrev][invfMode] const BW_COEFS = [ [0.0, 0.6, 0.9, 0.98], [0.6, 0.75, 0.9, 0.98], @@ -96,7 +96,7 @@ export default class HFGenerator { } calculateChirpFactors(tables, cd) { - //calculates chirp factors and replaces old ones in ChannelData + // calculates chirp factors and replaces old ones in ChannelData let nq = tables.nq; let invfMode = cd.invfMode; let invfModePrevious = cd.invfModePrevious; @@ -124,7 +124,6 @@ export default class HFGenerator { let phi[3][2][2] = this.phi; let d; for (let k = 0; k < k0; k++) { - //get covariance matrix this.getCovarianceMatrix(Xlow, k, phi); // d(k) @@ -167,6 +166,7 @@ export default class HFGenerator { let real_sum2 = x[k][0][0] * x[k][2][0] + x[k][0][1] * x[k][2][1]; let imag_sum2 = x[k][0][0] * x[k][2][1] - x[k][0][1] * x[k][2][0]; let real_sum1 = 0.0, imag_sum1 = 0.0, real_sum0 = 0.0; + for (let i = 1; i < 38; i++) { real_sum0 += x[k][i][0] * x[k][i ][0] + x[k][i][1] * x[k][i ][1]; real_sum1 += x[k][i][0] * x[k][i + 1][0] + x[k][i][1] * x[k][i + 1][1]; @@ -174,6 +174,7 @@ export default class HFGenerator { real_sum2 += x[k][i][0] * x[k][i + 2][0] + x[k][i][1] * x[k][i + 2][1]; imag_sum2 += x[k][i][0] * x[k][i + 2][1] - x[k][i][1] * x[k][i + 2][0]; } + phi[2 - 2][1][0] = real_sum2; phi[2 - 2][1][1] = imag_sum2; phi[2 ][1][0] = real_sum0 + x[k][ 0][0] * x[k][ 0][0] + x[k][ 0][1] * x[k][ 0][1]; diff --git a/src/sbr/HuffmanTables.js b/src/sbr/HuffmanTables.js index 249ffbe..1f739a6 100644 --- a/src/sbr/HuffmanTables.js +++ b/src/sbr/HuffmanTables.js @@ -12,7 +12,7 @@ export const F_HUFFMAN_NOISE_3_0_LAV = F_HUFFMAN_ENV_3_0_LAV; export const T_HUFFMAN_NOISE_BAL_3_0_LAV = 12; export const F_HUFFMAN_NOISE_BAL_3_0_LAV = F_HUFFMAN_ENV_BAL_3_0_LAV; -//codebooks: [bit length, codeword, values...] +// codebooks: [bit length, codeword, values...] export const T_HUFFMAN_ENV_1_5 = [ [2, 0, 60], [2, 1, 59], diff --git a/src/sbr/SBR.js b/src/sbr/SBR.js index 4e88c2a..59e9e23 100644 --- a/src/sbr/SBR.js +++ b/src/sbr/SBR.js @@ -52,18 +52,15 @@ class SBR { } if (stream.read(1)) { - // console.log("HEADER") this.header.decode(stream); if (this.header.reset) { this.tables.calculate(this.header, this.sampleRate); } else if (this.header.limiterBands !== this.header.limiterBandsPrev) { - console.log("LIMITER BANDS CHANGED") this.tables.calculateLimiterTable(this.header); } } if (this.header.decoded) { - // console.log('decode', stereo) if (stereo) { this.decodeChannelPair(stream); } else { @@ -166,7 +163,7 @@ class SBR { } if (f1 > 1e20) { - console.log("DEQUANT OUT OF BOUNDS"); + // out of bounds f1 = 1; } @@ -212,7 +209,7 @@ class SBR { } if (e[l][k] > 1e20) { - console.log("DEQUANT OUT OF BOUNDS"); + // out of bounds e[l][k] = 1; } } @@ -234,11 +231,7 @@ class SBR { decodeExtension(stream, extensionID) { switch (extensionID) { case EXTENSION_ID_PS: - console.log("PS!") - // this.psUsed = true; - // if(ps==null) ps = new PS(); - // ps.decode(in); - // if(!psUsed&&ps.hasHeader()) psUsed = true; + // TODO break; } } @@ -251,19 +244,13 @@ class SBR { if (this.stereo) { this.processChannel(1, right); } else if (this.psUsed) { - throw new Error('PS data unsupported') + throw new Error('PS data unsupported'); } this.qmfS.process(this.X, left, 0); if (this.stereo || this.psUsed) { this.qmfS.process(this.X, right, 1); } - // - // for (let i = 0; i < left.length; i++) { - // if (isNaN(left[i])) { - // console.log("NAN LEFT") - // } - // } } processChannel(ch, data) { @@ -321,7 +308,6 @@ class SBR { for (k = kxPrev; k < kxPrev + mPrev; k++) { X[ch][0][l][k] = Y[ch][l + TIME_SLOTS_RATE][k][0]; X[ch][1][l][k] = Y[ch][l + TIME_SLOTS_RATE][k][1]; - } for (k = kxPrev + mPrev; k < 64; k++) { diff --git a/src/sbr/SBRHeader.js b/src/sbr/SBRHeader.js index f1c557f..4acc0ad 100644 --- a/src/sbr/SBRHeader.js +++ b/src/sbr/SBRHeader.js @@ -20,7 +20,7 @@ export default class SBRHeader { this.startFrequency = stream.read(4); this.stopFrequency = stream.read(4); this.xOverBand = stream.read(3); - stream.advance(2); //reserved + stream.advance(2); // reserved let extraHeader1 = stream.read(1); let extraHeader2 = stream.read(1); From b072e4191c05f719065cfa28a9d60977632e3047 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 10 Jul 2016 16:14:10 -0700 Subject: [PATCH 17/19] [SBR] Abstract PooledObject from SBR --- src/PooledObject.js | 14 ++++++++++++++ src/decoder.js | 2 +- src/sbr/SBR.js | 19 +++++++------------ 3 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 src/PooledObject.js diff --git a/src/PooledObject.js b/src/PooledObject.js new file mode 100644 index 0000000..5029f03 --- /dev/null +++ b/src/PooledObject.js @@ -0,0 +1,14 @@ +export default class PooledObject { + static getFromPool() { + let pool = this._pool || (this._pool = []); + let obj = pool.length ? pool.pop() : new this(...arguments); + obj.init(...arguments) + return obj; + } + + init() {} + release() { + let pool = this.constructor._pool || (this.constructor._pool = []); + pool.push(this); + } +} diff --git a/src/decoder.js b/src/decoder.js index 747407c..146a27b 100644 --- a/src/decoder.js +++ b/src/decoder.js @@ -247,7 +247,7 @@ class AACDecoder extends AV.Decoder { for (let element of elements) { if (element.sbr) { - SBR.release(element.sbr); + element.sbr.release(); } } diff --git a/src/sbr/SBR.js b/src/sbr/SBR.js index 59e9e23..3c72af4 100644 --- a/src/sbr/SBR.js +++ b/src/sbr/SBR.js @@ -6,16 +6,16 @@ import SynthesisFilterbank from './SynthesisFilterbank'; import HFGenerator from './HFGenerator'; import HFAdjuster from './HFAdjuster'; import {T_HF_GEN, T_HF_ADJ, TIME_SLOTS_RATE} from './constants'; +import PooledObject from '../PooledObject'; const NOISE_FLOOR_OFFSET = 6; const EXTENSION_ID_PS = 2; const EXP2 = [1, Math.SQRT2]; -let pool = []; - -class SBR { - constructor(sampleRate, downSampled) { - this.sampleRate = 2 * sampleRate; +class SBR extends PooledObject { + constructor() { + super(); + this.sampleRate = 0; this.header = new SBRHeader; this.tables = new FrequencyTables; this.cd = [new ChannelData, new ChannelData]; @@ -32,15 +32,10 @@ class SBR { this.Y = new Float32Array(2 * 38 * 64 * 2); } - static get(sampleRate, downSampled) { - let sbr = pool.length ? pool.pop() : new SBR(sampleRate, downSampled); - sbr.sampleRate = 2 * sampleRate; - return sbr; + init(sampleRate) { + this.sampleRate = 2 * sampleRate; } - static release(sbr) { - pool.push(sbr); - } decode(stream, count, stereo, crc) { this.stereo = stereo; From 0c44377670434acc6b8478c3dfff678344277238 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 10 Jul 2016 16:18:27 -0700 Subject: [PATCH 18/19] [SBR] Clean up FIL element decoding --- src/fil.js | 103 +++++++++++++++++++++++++++++-------------------- src/sbr/SBR.js | 12 +++--- 2 files changed, 68 insertions(+), 47 deletions(-) diff --git a/src/fil.js b/src/fil.js index d133de1..3a704c3 100644 --- a/src/fil.js +++ b/src/fil.js @@ -1,5 +1,5 @@ -var CPEElement = require('./cpe'); -var SBR = require('./sbr/sbr'); +import CPEElement from './cpe'; +import SBR from './sbr/SBR'; const TYPE_FILL = 0; const TYPE_FILL_DATA = 1; @@ -8,47 +8,66 @@ const TYPE_DYNAMIC_RANGE = 11; const TYPE_SBR_DATA = 13; const TYPE_SBR_DATA_CRC = 14; -function FIL() { - -} - -FIL.decode = function(stream, count, prev, sampleRate) { - var pos = stream.offset(); - var end = pos + count; +export function decode(stream, count, prev, sampleRate) { + let end = stream.offset() + count; - while (count > 0) { - count = this.decodeExtension(stream, count, prev, sampleRate); - } + while (count > 0) { + count -= decodeExtension(stream, count, prev, sampleRate); + } - stream.advance(end - stream.offset()); -}; + stream.seek(end); +} -FIL.decodeExtension = function(stream, count, prev, sampleRate) { - var type = stream.read(4); - count -= 4; - - switch (type) { - case TYPE_DYNAMIC_RANGE: - console.log('dynamic range'); - break; - - case TYPE_SBR_DATA: - case TYPE_SBR_DATA_CRC: - if (prev) { - // prev.sbr = new SBR(sampleRate, false); - prev.sbr = SBR.get(sampleRate, false); - prev.sbr.decode(stream, count, prev instanceof CPEElement, type === TYPE_SBR_DATA_CRC); - } - return 0; - - case TYPE_FILL: - case TYPE_FILL_DATA: - case TYPE_EXT_DATA_ELEMENT: - console.log('OTHER') - break; - } - - // stream.advance(count); -}; +function decodeExtension(stream, count, prev, sampleRate) { + let end = stream.offset() + count; + let type = stream.read(4); + + switch (type) { + case TYPE_DYNAMIC_RANGE: + return skipDynamicRange(stream); + + case TYPE_SBR_DATA: + case TYPE_SBR_DATA_CRC: + if (prev) { + prev.sbr = SBR.decode(stream, sampleRate, prev instanceof CPEElement, type === TYPE_SBR_DATA_CRC); + } + // fall through + + default: + stream.seek(end); + return count; + } +} -module.exports = FIL; +function skipDynamicRange(stream) { + let offset = stream.offset(); + let drc_num_bands = 1; + + if (stream.read(1)) { // pce_tag_present + stream.advance(4); // pce_instance_tag + stream.advance(4); // tag_reserved_bits + } + + if (stream.read(1)) { // excluded_chns_present + let n = 0; + do { + stream.advance(7); + n += 7; + } while (n < 57 && stream.read(1)); + } + + if (stream.read(1)) { // drc_bands_present + drc_num_bands += stream.advance(4); + stream.advance(4); // interpolation_scheme + stream.advance(8 * drc_num_bands); // band top + } + + if (stream.read(1)) { // prog_ref_level_present + stream.advance(7); // prog_ref_level + stream.advance(1); // prog_ref_level_reserved_bits + } + + stream.advance(8 * drc_num_bands); // dyn_rng_sgn and dyn_rng_ctl + + return stream.offset() - offset; +} diff --git a/src/sbr/SBR.js b/src/sbr/SBR.js index 3c72af4..e96c077 100644 --- a/src/sbr/SBR.js +++ b/src/sbr/SBR.js @@ -16,6 +16,7 @@ class SBR extends PooledObject { constructor() { super(); this.sampleRate = 0; + this.stereo = true; this.header = new SBRHeader; this.tables = new FrequencyTables; this.cd = [new ChannelData, new ChannelData]; @@ -36,11 +37,14 @@ class SBR extends PooledObject { this.sampleRate = 2 * sampleRate; } + static decode(stream, sampleRate, stereo, crc) { + let sbr = this.getFromPool(sampleRate); + sbr.decode(stream, stereo, crc); + return sbr; + } - decode(stream, count, stereo, crc) { + decode(stream, stereo, crc) { this.stereo = stereo; - var pos = stream.offset(); - var end = pos + count; if (crc) { stream.advance(10); @@ -75,8 +79,6 @@ class SBR extends PooledObject { } } } - - stream.seek(end); } decodeSingleChannel(stream) { From 886d7c067383e64996a31abaae57e0a6644650ca Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 10 Jul 2016 16:24:16 -0700 Subject: [PATCH 19/19] Only reallocate output buffers when needed --- src/decoder.js | 11 +++++++---- src/sbr/SBR.js | 4 +--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/decoder.js b/src/decoder.js index 146a27b..9d1ac0e 100644 --- a/src/decoder.js +++ b/src/decoder.js @@ -270,11 +270,14 @@ class AACDecoder extends AV.Decoder { var channels = this.config.chanConfig; var mult = this.config.sbrPresent ? 2 : 1; var len = mult * this.config.frameLength; - var data = this.data = []; + var data = this.data; - // Initialize channels - for (var i = 0; i < channels; i++) { - data[i] = new Float32Array(len); + // Only reallocate if needed + if (!data || data.length !== channels || data[0].length !== len) { + data = this.data = []; + for (var i = 0; i < channels; i++) { + data[i] = new Float32Array(len); + } } var channel = 0; diff --git a/src/sbr/SBR.js b/src/sbr/SBR.js index e96c077..efec4f9 100644 --- a/src/sbr/SBR.js +++ b/src/sbr/SBR.js @@ -12,7 +12,7 @@ const NOISE_FLOOR_OFFSET = 6; const EXTENSION_ID_PS = 2; const EXP2 = [1, Math.SQRT2]; -class SBR extends PooledObject { +export default class SBR extends PooledObject { constructor() { super(); this.sampleRate = 0; @@ -338,5 +338,3 @@ class SBR extends PooledObject { this.cd[ch].savePreviousData(); } } - -module.exports = SBR;