From 1c9e99bb66b138b41e99827e3ad81daa06dcc039 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Fri, 13 Jan 2023 22:56:59 +0900 Subject: [PATCH] mp3 test --- assets/disk0/home/mp3test.js | 70 ++ assets/disk0/tvdos/include/js-mp3/LICENSE | 21 + assets/disk0/tvdos/include/js-mp3/bits.js | 84 ++ assets/disk0/tvdos/include/js-mp3/consts.js | 60 ++ assets/disk0/tvdos/include/js-mp3/frame.js | 741 ++++++++++++++++++ .../disk0/tvdos/include/js-mp3/frameheader.js | 283 +++++++ assets/disk0/tvdos/include/js-mp3/huffman.js | 412 ++++++++++ assets/disk0/tvdos/include/js-mp3/imdct.js | 95 +++ assets/disk0/tvdos/include/js-mp3/maindata.js | 314 ++++++++ assets/disk0/tvdos/include/js-mp3/sideinfo.js | 157 ++++ assets/disk0/tvdos/include/js-mp3/util.js | 108 +++ assets/disk0/tvdos/include/mp3dec.js | 282 +++++++ 12 files changed, 2627 insertions(+) create mode 100644 assets/disk0/tvdos/include/js-mp3/LICENSE create mode 100644 assets/disk0/tvdos/include/js-mp3/bits.js create mode 100644 assets/disk0/tvdos/include/js-mp3/consts.js create mode 100644 assets/disk0/tvdos/include/js-mp3/frame.js create mode 100644 assets/disk0/tvdos/include/js-mp3/frameheader.js create mode 100644 assets/disk0/tvdos/include/js-mp3/huffman.js create mode 100644 assets/disk0/tvdos/include/js-mp3/imdct.js create mode 100644 assets/disk0/tvdos/include/js-mp3/maindata.js create mode 100644 assets/disk0/tvdos/include/js-mp3/sideinfo.js create mode 100644 assets/disk0/tvdos/include/js-mp3/util.js create mode 100644 assets/disk0/tvdos/include/mp3dec.js diff --git a/assets/disk0/home/mp3test.js b/assets/disk0/home/mp3test.js index e69de29..4428df6 100644 --- a/assets/disk0/home/mp3test.js +++ b/assets/disk0/home/mp3test.js @@ -0,0 +1,70 @@ +const Mp3 = require('mp3dec') +const pcm = require("pcm") + + +Object.keys(Mp3).forEach(e=>{ + print(`${e}\t`) +}) +println() + +println("reading...") +let arr = files.open("A:/gateless.mp3").bread() +let ab = new ArrayBuffer(arr.length) +let abba = new Uint8Array(ab) +arr.forEach((v,i)=>{ abba[i] = v }) + + +let mp3ArrayBuffer = new Uint8Array(ab, 0, arr.length) + +println("decoding...") +let decoder = Mp3.newDecoder(ab) +if (decoder === null) throw Error("decoder is null") + +audio.resetParams(0) +audio.purgeQueue(0) +audio.setPcmMode(0) +audio.setMasterVolume(0, 255) +audio.play(0) + +let decodedLength = 0 +let readPtr = sys.malloc(8000) +let decodePtr = sys.malloc(12000) + + +function decodeAndResample(readArr, decodePtr, readLength) { + for (let i = 0; i < readLength; i+= 2) { + let sample = pcm.u16Tos16(readArr[i] | (readArr[i+1] << 8)) + let u8 = pcm.s16Tou8(sample) + + sys.poke(decodePtr + (i >> 1), u8) + } + return readLength / 2 +} + + +function printPlayBar() { +} + + +const QUEUE_MAX = 4 +decoder.decode(obj=>{ + let buf = obj.buf + let err = obj.err + + decodedLength += buf.byteLength + + let declen = decodeAndResample(buf, decodePtr, buf.byteLength) + + audio.putPcmDataByPtr(decodePtr, declen, 0) + audio.setSampleUploadLength(0, declen) + audio.startSampleUpload(0) + audio.play(0) + + serial.println(`Send sample (${audio.getPosition(0)})`) +// sys.sleep(0) // decoding time is slower than realtime :( + + +}) // now you got decoded PCM data + +sys.free(readPtr) +sys.free(decodePtr) \ No newline at end of file diff --git a/assets/disk0/tvdos/include/js-mp3/LICENSE b/assets/disk0/tvdos/include/js-mp3/LICENSE new file mode 100644 index 0000000..395c26f --- /dev/null +++ b/assets/disk0/tvdos/include/js-mp3/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 SoundBus Technologies CO., LTD. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/assets/disk0/tvdos/include/js-mp3/bits.js b/assets/disk0/tvdos/include/js-mp3/bits.js new file mode 100644 index 0000000..4d80110 --- /dev/null +++ b/assets/disk0/tvdos/include/js-mp3/bits.js @@ -0,0 +1,84 @@ +var Bits = { + createNew: function (vec) { + var bits = { + vec: vec, // ArrayBuffer + bitPos: 0, + bytePos: 0 + }; + + /** + * @return {number} + */ + bits.Bit = function () { + if (bits.vec.byteLength <= bits.bytePos) { + // TODO: Should this return error? + return 0; + } + var dv = new DataView(bits.vec, bits.bytePos); + var tmp = (dv.getUint8(0) >>> (7 - bits.bitPos)) >>> 0; + tmp &= 0x01; + bits.bytePos += ((bits.bitPos + 1) >>> 3) >>> 0; + bits.bitPos = (bits.bitPos + 1) & 0x07; + return tmp; + }; + + /** + * @return {number} + */ + bits.Bits = function (num) { + if (num === 0) { + return 0; + } + if (bits.vec.byteLength <= bits.bytePos) { + // TODO: Should this return error? + return 0; + } + var bb = new DataView(bits.vec, bits.bytePos); + // always end bit wise ops with >>> 0 so the result gets interpreted as unsigned. + // don't use >>. If the left-most bit is 1 it will try to preseve the sign and thus will introduce 1's to the left. Always use >>>. + // see https://stackoverflow.com/a/6798829 + var tmp = (((getValue(bb, 0) << 24) >>> 0) | ((getValue(bb, 1) << 16) >>> 0) | ((getValue(bb, 2) << 8) >>> 0) | (getValue(bb, 3) >>> 0)) >>> 0; + tmp = (tmp << bits.bitPos) >>> 0; + tmp = (tmp >>> (32 - num)) >>> 0; + bits.bytePos += ((bits.bitPos + num) >>> 3) >>> 0; + bits.bitPos = (bits.bitPos + num) & 0x07; + return tmp; + }; + + bits.Tail = function (offset) { + var a = new Uint8Array(bits.vec); + return a.slice(bits.vec.byteLength - offset).buffer; + // return new Uint8Array(bits.vec, bits.vec.byteLength - offset).buffer; + }; + + bits.LenInBytes = function () { + return bits.vec.byteLength; + }; + + /** + * @return {number} + */ + bits.BitPos = function () { + return ((bits.bytePos << 3) >>> 0) + bits.bitPos; + }; + + bits.SetPos = function (pos) { + bits.bytePos = (pos >>> 3) >>> 0; + bits.bitPos = (pos & 0x7) >>> 0; + }; + + return bits; + }, + append: function (bits, buf) { + return Bits.createNew(bits.vec.concat(buf)); + }, +}; + +var getValue = function (dv, index) { + if (index >= dv.byteLength) { + return 0; + } + return dv.getUint8(index); +}; + +exports = Bits; diff --git a/assets/disk0/tvdos/include/js-mp3/consts.js b/assets/disk0/tvdos/include/js-mp3/consts.js new file mode 100644 index 0000000..369a10f --- /dev/null +++ b/assets/disk0/tvdos/include/js-mp3/consts.js @@ -0,0 +1,60 @@ +var consts = { + Version2_5: 0, + VersionReserved: 1, + Version2: 2, + Version1: 3, + + LayerReserved: 0, + Layer3: 1, + Layer2: 2, + Layer1: 3, + + ModeStereo: 0, + ModeJointStereo: 1, + ModeDualChannel: 2, + ModeSingleChannel: 3, + + SamplesPerGr: 576, + + SamplingFrequency44100: 0, + SamplingFrequency48000: 1, + SamplingFrequency32000: 2, + SamplingFrequencyReserved: 3, + + newSamplingFrequencyInstance: function (value) { + var instance = { + value: value + }; + instance.Int = function () { + switch(instance.value) { + case consts.SamplingFrequency44100: + return 44100; + case consts.SamplingFrequency48000: + return 48000; + case consts.SamplingFrequency32000: + return 32000; + } + throw new Error('not reached'); + }; + return instance; + }, + + SfBandIndicesSet: { + 0: { // SamplingFrequency44100 + L: [0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, 576], + S: [0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84, 106, 136, 192] + }, + 1: { // SamplingFrequency48000 + L: [0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, 576], + S: [0, 4, 8, 12, 16, 22, 28, 38, 50, 64, 80, 100, 126, 192] + }, + 2: { // SamplingFrequency32000 + L: [0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, 576], + S: [0, 4, 8, 12, 16, 22, 30, 42, 58, 78, 104, 138, 180, 192] + } + } +}; + +consts.BytesPerFrame = consts.SamplesPerGr * 2 * 4; + +exports = consts; diff --git a/assets/disk0/tvdos/include/js-mp3/frame.js b/assets/disk0/tvdos/include/js-mp3/frame.js new file mode 100644 index 0000000..6dbc58e --- /dev/null +++ b/assets/disk0/tvdos/include/js-mp3/frame.js @@ -0,0 +1,741 @@ +var consts = require('A:/tvdos/include/js-mp3/consts.js'); +var util = require('A:/tvdos/include/js-mp3/util.js'); +var Frameheader = require('A:/tvdos/include/js-mp3/frameheader.js'); +var Imdct = require('A:/tvdos/include/js-mp3/imdct.js'); +var Maindata = require('A:/tvdos/include/js-mp3/maindata.js'); +var Sideinfo = require('A:/tvdos/include/js-mp3/sideinfo.js'); + +var powtab34 = new Float64Array(8207); +var pretab_data = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0]; +var pretab = new Float64Array(pretab_data.length); +pretab.set(pretab_data); + +for (var i = 0; i < powtab34.length; i++) { + powtab34[i] = Math.pow(i, 4.0 / 3.0); +} + +var synthNWin = []; +for (var i = 0; i < 64; i++) { + synthNWin.push(new Float32Array(32)); +} + +for (var i = 0; i < 64; i++) { + for (var j = 0; j < 32; j++) { + synthNWin[i][j] = Math.cos(((16 + i) * (2 * j + 1)) * (Math.PI / 64.0)); + } +} + +var synthDtbl = new Float32Array([ + 0.000000000, -0.000015259, -0.000015259, -0.000015259, + -0.000015259, -0.000015259, -0.000015259, -0.000030518, + -0.000030518, -0.000030518, -0.000030518, -0.000045776, + -0.000045776, -0.000061035, -0.000061035, -0.000076294, + -0.000076294, -0.000091553, -0.000106812, -0.000106812, + -0.000122070, -0.000137329, -0.000152588, -0.000167847, + -0.000198364, -0.000213623, -0.000244141, -0.000259399, + -0.000289917, -0.000320435, -0.000366211, -0.000396729, + -0.000442505, -0.000473022, -0.000534058, -0.000579834, + -0.000625610, -0.000686646, -0.000747681, -0.000808716, + -0.000885010, -0.000961304, -0.001037598, -0.001113892, + -0.001205444, -0.001296997, -0.001388550, -0.001480103, + -0.001586914, -0.001693726, -0.001785278, -0.001907349, + -0.002014160, -0.002120972, -0.002243042, -0.002349854, + -0.002456665, -0.002578735, -0.002685547, -0.002792358, + -0.002899170, -0.002990723, -0.003082275, -0.003173828, + 0.003250122, 0.003326416, 0.003387451, 0.003433228, + 0.003463745, 0.003479004, 0.003479004, 0.003463745, + 0.003417969, 0.003372192, 0.003280640, 0.003173828, + 0.003051758, 0.002883911, 0.002700806, 0.002487183, + 0.002227783, 0.001937866, 0.001617432, 0.001266479, + 0.000869751, 0.000442505, -0.000030518, -0.000549316, + -0.001098633, -0.001693726, -0.002334595, -0.003005981, + -0.003723145, -0.004486084, -0.005294800, -0.006118774, + -0.007003784, -0.007919312, -0.008865356, -0.009841919, + -0.010848999, -0.011886597, -0.012939453, -0.014022827, + -0.015121460, -0.016235352, -0.017349243, -0.018463135, + -0.019577026, -0.020690918, -0.021789551, -0.022857666, + -0.023910522, -0.024932861, -0.025909424, -0.026840210, + -0.027725220, -0.028533936, -0.029281616, -0.029937744, + -0.030532837, -0.031005859, -0.031387329, -0.031661987, + -0.031814575, -0.031845093, -0.031738281, -0.031478882, + 0.031082153, 0.030517578, 0.029785156, 0.028884888, + 0.027801514, 0.026535034, 0.025085449, 0.023422241, + 0.021575928, 0.019531250, 0.017257690, 0.014801025, + 0.012115479, 0.009231567, 0.006134033, 0.002822876, + -0.000686646, -0.004394531, -0.008316040, -0.012420654, + -0.016708374, -0.021179199, -0.025817871, -0.030609131, + -0.035552979, -0.040634155, -0.045837402, -0.051132202, + -0.056533813, -0.061996460, -0.067520142, -0.073059082, + -0.078628540, -0.084182739, -0.089706421, -0.095169067, + -0.100540161, -0.105819702, -0.110946655, -0.115921021, + -0.120697021, -0.125259399, -0.129562378, -0.133590698, + -0.137298584, -0.140670776, -0.143676758, -0.146255493, + -0.148422241, -0.150115967, -0.151306152, -0.151962280, + -0.152069092, -0.151596069, -0.150497437, -0.148773193, + -0.146362305, -0.143264771, -0.139450073, -0.134887695, + -0.129577637, -0.123474121, -0.116577148, -0.108856201, + 0.100311279, 0.090927124, 0.080688477, 0.069595337, + 0.057617188, 0.044784546, 0.031082153, 0.016510010, + 0.001068115, -0.015228271, -0.032379150, -0.050354004, + -0.069168091, -0.088775635, -0.109161377, -0.130310059, + -0.152206421, -0.174789429, -0.198059082, -0.221984863, + -0.246505737, -0.271591187, -0.297210693, -0.323318481, + -0.349868774, -0.376800537, -0.404083252, -0.431655884, + -0.459472656, -0.487472534, -0.515609741, -0.543823242, + -0.572036743, -0.600219727, -0.628295898, -0.656219482, + -0.683914185, -0.711318970, -0.738372803, -0.765029907, + -0.791213989, -0.816864014, -0.841949463, -0.866363525, + -0.890090942, -0.913055420, -0.935195923, -0.956481934, + -0.976852417, -0.996246338, -1.014617920, -1.031936646, + -1.048156738, -1.063217163, -1.077117920, -1.089782715, + -1.101211548, -1.111373901, -1.120223999, -1.127746582, + -1.133926392, -1.138763428, -1.142211914, -1.144287109, + 1.144989014, 1.144287109, 1.142211914, 1.138763428, + 1.133926392, 1.127746582, 1.120223999, 1.111373901, + 1.101211548, 1.089782715, 1.077117920, 1.063217163, + 1.048156738, 1.031936646, 1.014617920, 0.996246338, + 0.976852417, 0.956481934, 0.935195923, 0.913055420, + 0.890090942, 0.866363525, 0.841949463, 0.816864014, + 0.791213989, 0.765029907, 0.738372803, 0.711318970, + 0.683914185, 0.656219482, 0.628295898, 0.600219727, + 0.572036743, 0.543823242, 0.515609741, 0.487472534, + 0.459472656, 0.431655884, 0.404083252, 0.376800537, + 0.349868774, 0.323318481, 0.297210693, 0.271591187, + 0.246505737, 0.221984863, 0.198059082, 0.174789429, + 0.152206421, 0.130310059, 0.109161377, 0.088775635, + 0.069168091, 0.050354004, 0.032379150, 0.015228271, + -0.001068115, -0.016510010, -0.031082153, -0.044784546, + -0.057617188, -0.069595337, -0.080688477, -0.090927124, + 0.100311279, 0.108856201, 0.116577148, 0.123474121, + 0.129577637, 0.134887695, 0.139450073, 0.143264771, + 0.146362305, 0.148773193, 0.150497437, 0.151596069, + 0.152069092, 0.151962280, 0.151306152, 0.150115967, + 0.148422241, 0.146255493, 0.143676758, 0.140670776, + 0.137298584, 0.133590698, 0.129562378, 0.125259399, + 0.120697021, 0.115921021, 0.110946655, 0.105819702, + 0.100540161, 0.095169067, 0.089706421, 0.084182739, + 0.078628540, 0.073059082, 0.067520142, 0.061996460, + 0.056533813, 0.051132202, 0.045837402, 0.040634155, + 0.035552979, 0.030609131, 0.025817871, 0.021179199, + 0.016708374, 0.012420654, 0.008316040, 0.004394531, + 0.000686646, -0.002822876, -0.006134033, -0.009231567, + -0.012115479, -0.014801025, -0.017257690, -0.019531250, + -0.021575928, -0.023422241, -0.025085449, -0.026535034, + -0.027801514, -0.028884888, -0.029785156, -0.030517578, + 0.031082153, 0.031478882, 0.031738281, 0.031845093, + 0.031814575, 0.031661987, 0.031387329, 0.031005859, + 0.030532837, 0.029937744, 0.029281616, 0.028533936, + 0.027725220, 0.026840210, 0.025909424, 0.024932861, + 0.023910522, 0.022857666, 0.021789551, 0.020690918, + 0.019577026, 0.018463135, 0.017349243, 0.016235352, + 0.015121460, 0.014022827, 0.012939453, 0.011886597, + 0.010848999, 0.009841919, 0.008865356, 0.007919312, + 0.007003784, 0.006118774, 0.005294800, 0.004486084, + 0.003723145, 0.003005981, 0.002334595, 0.001693726, + 0.001098633, 0.000549316, 0.000030518, -0.000442505, + -0.000869751, -0.001266479, -0.001617432, -0.001937866, + -0.002227783, -0.002487183, -0.002700806, -0.002883911, + -0.003051758, -0.003173828, -0.003280640, -0.003372192, + -0.003417969, -0.003463745, -0.003479004, -0.003479004, + -0.003463745, -0.003433228, -0.003387451, -0.003326416, + 0.003250122, 0.003173828, 0.003082275, 0.002990723, + 0.002899170, 0.002792358, 0.002685547, 0.002578735, + 0.002456665, 0.002349854, 0.002243042, 0.002120972, + 0.002014160, 0.001907349, 0.001785278, 0.001693726, + 0.001586914, 0.001480103, 0.001388550, 0.001296997, + 0.001205444, 0.001113892, 0.001037598, 0.000961304, + 0.000885010, 0.000808716, 0.000747681, 0.000686646, + 0.000625610, 0.000579834, 0.000534058, 0.000473022, + 0.000442505, 0.000396729, 0.000366211, 0.000320435, + 0.000289917, 0.000259399, 0.000244141, 0.000213623, + 0.000198364, 0.000167847, 0.000152588, 0.000137329, + 0.000122070, 0.000106812, 0.000106812, 0.000091553, + 0.000076294, 0.000076294, 0.000061035, 0.000061035, + 0.000045776, 0.000045776, 0.000030518, 0.000030518, + 0.000030518, 0.000030518, 0.000015259, 0.000015259, + 0.000015259, 0.000015259, 0.000015259, 0.000015259, + ], 0, 512); + +var cs = new Float32Array([ + 0.857493, 0.881742, 0.949629, 0.983315, 0.995518, 0.999161, 0.999899, + 0.999993 + ]); + +var ca = new Float32Array([ + -0.514496, -0.471732, -0.313377, -0.181913, -0.094574, -0.040966, + -0.014199, -0.003700 + ]); + +var isRatios = [0.000000, 0.267949, 0.577350, 1.000000, 1.732051, 3.732051]; + +var Frame = { + createNew: function (header, sideInfo, mainData, mainDataBits) { + var frame = { + header: header, + sideInfo: sideInfo, + mainData: mainData, + mainDataBits: mainDataBits + }; + + frame.store = new Array(2); + for (var i = 0; i < frame.store.length; i++) { + var a = new Array(32); + for (var j = 0; j < a.length; j++) { + a[j] = new Float32Array(18); + } + frame.store[i] = a; + } + + frame.v_vec = new Array(2); + for (var i = 0; i < frame.v_vec.length; i++) { + frame.v_vec[i] = new Float32Array(1024); + } + + /** + * Return decoded pcm ArrayBuffer + * + * @constructor + */ + frame.decode = function () { + var nch = frame.header.numberOfChannels(); + var out; + if (nch === 1) { + out = new Uint8Array(consts.BytesPerFrame / 2); + } else { + out = new Uint8Array(consts.BytesPerFrame); + } + for (var gr = 0; gr < 2; gr++) { + for (var ch = 0; ch < nch; ch++) { + frame.requantize(gr, ch); + frame.reorder(gr, ch); + } + frame.stereo(gr); + for (var ch = 0; ch < nch; ch++) { + frame.antialias(gr, ch); + frame.hybridSynthesis(gr, ch); + frame.frequencyInversion(gr, ch); + if (nch === 1) { + frame.subbandSynthesis(gr, ch, out.subarray(consts.SamplesPerGr * 4 * gr / 2)); + } else { + frame.subbandSynthesis(gr, ch, out.subarray(consts.SamplesPerGr * 4 * gr)); + } + } + } + return out; + }; + + frame.antialias = function (gr, ch) { + // No antialiasing is done for short blocks + if ((frame.sideInfo.WinSwitchFlag[gr][ch] === 1) && + (frame.sideInfo.BlockType[gr][ch] === 2) && + (frame.sideInfo.MixedBlockFlag[gr][ch]) === 0) { + return; + } + // Setup the limit for how many subbands to transform + var sblim = 32; + if ((frame.sideInfo.WinSwitchFlag[gr][ch] === 1) && + (frame.sideInfo.BlockType[gr][ch] === 2) && + (frame.sideInfo.MixedBlockFlag[gr][ch] === 1)) { + sblim = 2 + } + // Do the actual antialiasing + for (var sb = 1; sb < sblim; sb++) { + for (var i = 0; i < 8; i++) { + var li = 18 * sb - 1 - i; + var ui = 18 * sb + i; + var lb = frame.mainData.Is[gr][ch][li] * cs[i] - frame.mainData.Is[gr][ch][ui] + * ca[i]; + var ub = frame.mainData.Is[gr][ch][ui] * cs[i] + frame.mainData.Is[gr][ch][li] + * ca[i]; + frame.mainData.Is[gr][ch][li] = lb; + frame.mainData.Is[gr][ch][ui] = ub; + } + } + }; + + frame.hybridSynthesis = function (gr, ch) { + // Loop through all 32 subbands + for (var sb = 0; sb < 32; sb++) { + // Determine blocktype for this subband + var bt = frame.sideInfo.BlockType[gr][ch]; + if ((frame.sideInfo.WinSwitchFlag[gr][ch] === 1) && + (frame.sideInfo.MixedBlockFlag[gr][ch] === 1) && (sb < 2)) { + bt = 0; + } + // Do the inverse modified DCT and windowing + var inData = new Float32Array(18); + for (var i = 0; i < 18; i++) { + inData[i] = frame.mainData.Is[gr][ch][sb * 18 + i]; + } + var rawout = Imdct.Win(inData, bt); + // Overlapp add with stored vector into main_data vector + for (var i = 0; i < 18; i++) { + frame.mainData.Is[gr][ch][sb * 18 + i] = rawout[i] + frame.store[ch][sb][i]; + frame.store[ch][sb][i] = rawout[i + 18]; + } + } + }; + + frame.frequencyInversion = function (gr, ch) { + for (var sb = 1; sb < 32; sb += 2) { + for (var i = 1; i < 18; i += 2) { + frame.mainData.Is[gr][ch][sb * 18 + i] = + -frame.mainData.Is[gr][ch][sb * 18 + i]; + } + } + }; + + frame.stereo = function (gr) { + if (frame.header.useMSStereo()) { + // Determine how many frequency lines to transform + var i = 1; + if (frame.sideInfo.Count1[gr][0] > frame.sideInfo.Count1[gr][1]) { + i = 0; + } + var max_pos = frame.sideInfo.Count1[gr][i]; + // Do the actual processing + const invSqrt2 = Math.SQRT2 / 2; + for (var i = 0; i < max_pos; i++) { + var left = (frame.mainData.Is[gr][0][i] + frame.mainData.Is[gr][1][i]) + * invSqrt2; + var right = (frame.mainData.Is[gr][0][i] - frame.mainData.Is[gr][1][i]) + * invSqrt2; + frame.mainData.Is[gr][0][i] = left; + frame.mainData.Is[gr][1][i] = right; + } + } + + if (frame.header.useIntensityStereo()) { + // Setup sampling frequency index + var sfreq = frame.header.samplingFrequency(); + + // First band that is intensity stereo encoded is first band scale factor + // band on or above count1 frequency line. N.B.: Intensity stereo coding is + // only done for higher subbands, but logic is here for lower subbands. + // Determine type of block to process + if ((frame.sideInfo.WinSwitchFlag[gr][0] === 1) && (frame.sideInfo.BlockType[gr][0] + === 2)) { // Short blocks + // Check if the first two subbands + // (=2*18 samples = 8 long or 3 short sfb's) uses long blocks + if (frame.sideInfo.MixedBlockFlag[gr][0] !== 0) { // 2 longbl. sb first + for (var sfb = 0; sfb < 8; sfb++) { // First process 8 sfb's at start + // Is this scale factor band above count1 for the right channel? + if (consts.SfBandIndicesSet[sfreq].L[sfb] + >= frame.sideInfo.Count1[gr][1]) { + frame.stereoProcessIntensityLong(gr, sfb); + } + } + // And next the remaining bands which uses short blocks + for (var sfb = 3; sfb < 12; sfb++) { + // Is this scale factor band above count1 for the right channel? + if (consts.SfBandIndicesSet[sfreq].S[sfb] * 3 + >= frame.sideInfo.Count1[gr][1]) { + frame.stereoProcessIntensityShort(gr, sfb); + } + } + } else { // Only short blocks + for (var sfb = 0; sfb < 12; sfb++) { + // Is this scale factor band above count1 for the right channel? + if (consts.SfBandIndicesSet[sfreq].S[sfb] * 3 + >= frame.sideInfo.Count1[gr][1]) { + frame.stereoProcessIntensityShort(gr, sfb); + } + } + } + } else { // Only long blocks + for (var sfb = 0; sfb < 21; sfb++) { + // Is this scale factor band above count1 for the right channel? + if (consts.SfBandIndicesSet[sfreq].L[sfb] >= frame.sideInfo.Count1[gr][1]) { + frame.stereoProcessIntensityLong(gr, sfb); + } + } + } + } + }; + + frame.stereoProcessIntensityLong = function (gr, sfb) { + var is_ratio_l = 0.0; + var is_ratio_r = 0.0; + // Check that((is_pos[sfb]=scalefac) < 7) => no intensity stereo + var is_pos = frame.mainData.ScalefacL[gr][0][sfb]; + if (is_pos < 7) { + var sfreq = frame.header.samplingFrequency().value; // Setup sampling freq index + var sfb_start = consts.SfBandIndicesSet[sfreq].L[sfb]; + var sfb_stop = consts.SfBandIndicesSet[sfreq].L[sfb + 1]; + if (is_pos === 6) { // tan((6*PI)/12 = PI/2) needs special treatment! + is_ratio_l = 1.0; + is_ratio_r = 0.0; + } else { + is_ratio_l = isRatios[is_pos] / (1.0 + isRatios[is_pos]); + is_ratio_r = 1.0 / (1.0 + isRatios[is_pos]); + } + // Now decode all samples in this scale factor band + for (var i = sfb_start; i < sfb_stop; i++) { + frame.mainData.Is[gr][0][i] *= is_ratio_l; + frame.mainData.Is[gr][1][i] *= is_ratio_r; + } + } + }; + + frame.stereoProcessIntensityShort = function (gr, sfb) { + var is_ratio_l = 0.0; + var is_ratio_r = 0.0; + var sfreq = frame.header.samplingFrequency().value; // Setup sampling freq index + // The window length + var win_len = consts.SfBandIndicesSet[sfreq].S[sfb + 1] + - consts.SfBandIndicesSet[sfreq].S[sfb]; + // The three windows within the band has different scalefactors + for (var win = 0; win < 3; win++) { + // Check that((is_pos[sfb]=scalefac) < 7) => no intensity stereo + var is_pos = frame.mainData.ScalefacS[gr][0][sfb][win]; + if (is_pos < 7) { + var sfb_start = consts.SfBandIndicesSet[sfreq].S[sfb] * 3 + win_len * win; + var sfb_stop = sfb_start + win_len; + if (is_pos === 6) { // tan((6*PI)/12 = PI/2) needs special treatment! + is_ratio_l = 1.0; + is_ratio_r = 0.0; + } else { + is_ratio_l = isRatios[is_pos] / (1.0 + isRatios[is_pos]); + is_ratio_r = 1.0 / (1.0 + isRatios[is_pos]); + } + // Now decode all samples in this scale factor band + for (var i = sfb_start; i < sfb_stop; i++) { + // https://github.com/technosaurus/PDMP3/issues/3 + frame.mainData.Is[gr][0][i] *= is_ratio_l; + frame.mainData.Is[gr][1][i] *= is_ratio_r; + } + } + } + }; + + frame.requantize = function (gr, ch) { + // Setup sampling frequency index + var sfreq = frame.header.samplingFrequency().value; + // Determine type of block to process + if (frame.sideInfo.WinSwitchFlag[gr][ch] === 1 && frame.sideInfo.BlockType[gr][ch] + === 2) { // Short blocks + // Check if the first two subbands + // (=2*18 samples = 8 long or 3 short sfb's) uses long blocks + if (frame.sideInfo.MixedBlockFlag[gr][ch] !== 0) { // 2 longbl. sb first + // First process the 2 long block subbands at the start + var sfb = 0; + var next_sfb = consts.SfBandIndicesSet[sfreq].L[sfb + 1]; + for (var i = 0; i < 36; i++) { + if (i === next_sfb) { + sfb++; + next_sfb = consts.SfBandIndicesSet[sfreq].L[sfb + 1]; + } + frame.requantizeProcessLong(gr, ch, i, sfb); + } + // And next the remaining,non-zero,bands which uses short blocks + sfb = 3; + next_sfb = consts.SfBandIndicesSet[sfreq].S[sfb + 1] * 3; + var win_len = consts.SfBandIndicesSet[sfreq].S[sfb + 1] - + consts.SfBandIndicesSet[sfreq].S[sfb]; + + for (var i = 36; i < int(f.sideInfo.Count1[gr][ch]);) /* i++ done below! */ { + // Check if we're into the next scalefac band + if (i === next_sfb) { + sfb++; + next_sfb = consts.SfBandIndicesSet[sfreq].S[sfb + 1] * 3; + win_len = consts.SfBandIndicesSet[sfreq].S[sfb + 1] - + consts.SfBandIndicesSet[sfreq].S[sfb]; + } + for (var win = 0; win < 3; win++) { + for (var j = 0; j < win_len; j++) { + frame.requantizeProcessShort(gr, ch, i, sfb, win); + i++; + } + } + } + } else { // Only short blocks + var sfb = 0; + var next_sfb = consts.SfBandIndicesSet[sfreq].S[sfb + 1] * 3; + var win_len = consts.SfBandIndicesSet[sfreq].S[sfb + 1] - + consts.SfBandIndicesSet[sfreq].S[sfb]; + for (var i = 0; i < frame.sideInfo.Count1[gr][ch];) /* i++ done below! */ { + // Check if we're into the next scalefac band + if (i === next_sfb) { + sfb++; + next_sfb = consts.SfBandIndicesSet[sfreq].S[sfb + 1] * 3; + win_len = consts.SfBandIndicesSet[sfreq].S[sfb + 1] - + consts.SfBandIndicesSet[sfreq].S[sfb]; + } + for (var win = 0; win < 3; win++) { + for (var j = 0; j < win_len; j++) { + frame.requantizeProcessShort(gr, ch, i, sfb, win); + i++; + } + } + } + } + } else { // Only long blocks + var sfb = 0; + var next_sfb = consts.SfBandIndicesSet[sfreq].L[sfb + 1]; + for (var i = 0; i < frame.sideInfo.Count1[gr][ch]; i++) { + if (i === next_sfb) { + sfb++; + next_sfb = consts.SfBandIndicesSet[sfreq].L[sfb + 1]; + } + frame.requantizeProcessLong(gr, ch, i, sfb); + } + } + }; + + frame.requantizeProcessLong = function (gr, ch, is_pos, sfb) { + var sf_mult = 0.5; + if (frame.sideInfo.ScalefacScale[gr][ch] !== 0) { + sf_mult = 1.0; + } + var pf_x_pt = frame.sideInfo.Preflag[gr][ch] * pretab[sfb]; + var idx = -(sf_mult * (frame.mainData.ScalefacL[gr][ch][sfb] + pf_x_pt)) + + 0.25 * (frame.sideInfo.GlobalGain[gr][ch] - 210); + var tmp1 = Math.pow(2.0, idx); + var tmp2 = 0.0; + if (frame.mainData.Is[gr][ch][is_pos] < 0.0) { + tmp2 = -powtab34[-frame.mainData.Is[gr][ch][is_pos]]; + } else { + tmp2 = powtab34[frame.mainData.Is[gr][ch][is_pos]]; + } + frame.mainData.Is[gr][ch][is_pos] = tmp1 * tmp2; + }; + + frame.requantizeProcessShort = function (gr, ch, is_pos, sfb, win) { + var sf_mult = 0.5; + if (frame.sideInfo.ScalefacScale[gr][ch] !== 0) { + sf_mult = 1.0; + } + var idx = -(sf_mult * frame.mainData.ScalefacS[gr][ch][sfb][win]) + + 0.25 * (frame.sideInfo.GlobalGain[gr][ch] - 210.0 - + 8.0 * frame.sideInfo.SubblockGain[gr][ch][win]); + var tmp1 = Math.pow(2.0, idx); + var tmp2 = 0.0; + if (frame.mainData.Is[gr][ch][is_pos] < 0) { + tmp2 = -powtab34[-frame.mainData.Is[gr][ch][is_pos]]; + } else { + tmp2 = powtab34[frame.mainData.Is[gr][ch][is_pos]]; + } + frame.mainData.Is[gr][ch][is_pos] = tmp1 * tmp2; + }; + + frame.reorder = function (gr, ch) { + var re = new Float32Array(consts.SamplesPerGr); + var sfreq = frame.header.samplingFrequency().value; // Setup sampling freq index + // Only reorder short blocks + if ((frame.sideInfo.WinSwitchFlag[gr][ch] === 1) && (frame.sideInfo.BlockType[gr][ch] + == 2)) { // Short blocks + // Check if the first two subbands + // (=2*18 samples = 8 long or 3 short sfb's) uses long blocks + var sfb = 0; + // 2 longbl. sb first + if (frame.sideInfo.MixedBlockFlag[gr][ch] !== 0) { + sfb = 3; + } + var next_sfb = consts.SfBandIndicesSet[sfreq].S[sfb + 1] * 3; + var win_len = consts.SfBandIndicesSet[sfreq].S[sfb + 1] + - consts.SfBandIndicesSet[sfreq].S[sfb]; + var i = 36; + if (sfb === 0) { + i = 0; + } + for (; i < consts.SamplesPerGr;) { + // Check if we're into the next scalefac band + if (i === next_sfb) { + // Copy reordered data back to the original vector + var j = 3 * consts.SfBandIndicesSet[sfreq].S[sfb]; + for (var s = 0; s < 3 * win_len; s++) { + frame.mainData.Is[gr][ch][j + s] = re[s]; // copy(frame.mainData.Is[gr][ch][j:j+3*win_len], + // re[0:3*win_len]) + } + // Check if this band is above the rzero region,if so we're done + if (i >= frame.sideInfo.Count1[gr][ch]) { + return; + } + sfb++; + next_sfb = consts.SfBandIndicesSet[sfreq].S[sfb + 1] * 3; + win_len = + consts.SfBandIndicesSet[sfreq].S[sfb + 1] + - consts.SfBandIndicesSet[sfreq].S[sfb]; + } + for (var win = 0; win < 3; win++) { // Do the actual reordering + for (j = 0; j < win_len; j++) { + re[j * 3 + win] = frame.mainData.Is[gr][ch][i]; + i++; + } + } + } + // Copy reordered data of last band back to original vector + var j = 3 * consts.SfBandIndicesSet[sfreq].S[12]; + for (var s = 0; s < 3 * win_len; s++) { + frame.mainData.Is[gr][ch][j + s] = re[s]; // copy(frame.mainData.Is[gr][ch][j:j+3*win_len], + // re[0:3*win_len]) + } + } + }; + + frame.subbandSynthesis = function (gr, ch, out) { + var u_vec = new Float32Array(512); + var s_vec = new Float32Array(32); + + var nch = frame.header.numberOfChannels(); + // Setup the n_win windowing vector and the v_vec intermediate vector + for (var ss = 0; ss < 18; ss++) { // Loop through 18 samples in 32 subbands + frame.v_vec[ch].set(frame.v_vec[ch].slice(0, 1024 - 64), 64); // copy(f.v_vec[ch][64:1024], + // f.v_vec[ch][0:1024-64]) + + var d = frame.mainData.Is[gr][ch]; + for (var i = 0; i < 32; i++) { // Copy next 32 time samples to a temp vector + s_vec[i] = d[i * 18 + ss]; + } + for (var i = 0; i < 64; i++) { // Matrix multiply input with n_win[][] matrix + var sum = 0; + for (var j = 0; j < 32; j++) { + sum += synthNWin[i][j] * s_vec[j]; + } + frame.v_vec[ch][i] = sum; + } + var v = frame.v_vec[ch]; + for (var i = 0; i < 512; i += 64) { // Build the U vector + u_vec.set(v.slice((i << 1) >>> 0, ((i << 1) >>> 0) + 32), i); // copy(u_vec[i:i+32], + // v[(i<<1):(i<<1)+32]) + u_vec.set(v.slice(((i << 1) >>> 0) + 96, ((i << 1) >>> 0) + 128), i + 32); // copy(u_vec[i+32:i+64], + // v[(i<<1)+96:(i<<1)+128]) + } + for (var i = 0; i < 512; i++) { // Window by u_vec[i] with synthDtbl[i] + u_vec[i] *= synthDtbl[i]; + } + for (var i = 0; i < 32; i++) { // Calc 32 samples,store in outdata vector + var sum = 0; + for (var j = 0; j < 512; j += 32) { + sum += u_vec[j + i]; + } + // sum now contains time sample 32*ss+i. Convert to 16-bit signed int + var samp = sum * 32767; + if (samp > 32767) { + samp = 32767; + } else if (samp < -32767) { + samp = -32767; + } + var s = samp; + var idx; + if (nch === 1) { + idx = 2 * (32*ss + i); + } else { + idx = 4 * (32*ss + i); + } + if (ch === 0) { + out[idx] = s; + out[idx + 1] = (s >>> 8) >>> 0; + } else { + out[idx + 2] = s; + out[idx + 3] = (s >>> 8) >>> 0; + } + } + } + return out; + }; + + frame.samplingFrequency = function () { + return frame.header.samplingFrequency().Int(); + }; + + return frame; + }, + + readCRC: function (source) { + var result = source.readFull(2); + if (result.err) { + return { + err: result.err + } + } + var buf = result.buf; + if (buf.byteLength < 2) { + return "mp3: error at readCRC"; + } + }, + + read: function (source, position, prev) { + var rr = Frameheader.read(source, position) + if (rr.err) { + return { + f: null, + position: 0, + err: rr.err + } + } + + var pos = rr.position; + var fh = rr.h; + // pos = rr.stopPosition; + if (fh.protectionBit() === 0) { + // pos += 2; + var err = Frame.readCRC(source); + if (typeof(err) !== 'undefined') { + return { + f: null, + position: 0, + err: err + } + } + } + + if (fh.id() !== consts.Version1) { + return { + f: null, + position: 0, + err: "mp3: only MPEG version 1 (want " + consts.Version1 + "; got " + fh.id() + + ") is supported" + } + } + if (fh.layer() !== consts.Layer3) { + return { + f: null, + position: 0, + err: "mp3: only layer3 (want " + consts.Version1 + "; got " + fh.layer() + + ") is supported" + } + } + + var result = Sideinfo.read(source, fh, pos); + if (result.err) { + return { + f: null, + position: 0, + err: result.err + } + } + var si = result.v; + + // If there's not enough main data in the bit reservoir, + // signal to calling function so that decoding isn't done! + // Get main data (scalefactors and Huffman coded frequency data) + var prevM = null; + if (prev) { + prevM = prev.mainDataBits; + } + + result = Maindata.read(source, prevM, fh, si); + if (result.err) { + return { + f: null, + position: 0, + err: result.err + } + } + + var f = Frame.createNew(fh, si, result.v, result.bits); + if (prev) { + f.store = prev.store; + f.v_vec = prev.v_vec; + } + + return { + f: f, + position: pos, + err: null + }; + } +}; + +exports = Frame; diff --git a/assets/disk0/tvdos/include/js-mp3/frameheader.js b/assets/disk0/tvdos/include/js-mp3/frameheader.js new file mode 100644 index 0000000..2716116 --- /dev/null +++ b/assets/disk0/tvdos/include/js-mp3/frameheader.js @@ -0,0 +1,283 @@ +var consts = require('A:/tvdos/include/js-mp3/consts.js'); + +var Frameheader = { + createNew: function (value) { + // A mepg1FrameHeader is MPEG1 Layer 1-3 frame header + var fh = { + value: value + }; + + /** + * ID returns this header's ID stored in position 20,19 + * + * @return {number} + */ + fh.id = function () { + return ((fh.value & 0x00180000) >>> 19) >>> 0; + }; + + /** + * Layer returns the mpeg layer of this frame stored in position 18,17 + * + * @return {number} + */ + fh.layer = function () { + return ((fh.value & 0x00060000) >>> 17) >>> 0; + }; + + /** + * ProtectionBit returns the protection bit stored in position 16 + * + * @return {number} + */ + fh.protectionBit = function () { + return ((fh.value & 0x00010000) >>> 16) >>> 0; + }; + + /** + * BirateIndex returns the bitrate index stored in position 15,12 + * + * @return {number} + */ + fh.bitrateIndex = function () { + return ((fh.value & 0x0000f000) >>> 12) >>> 0; + }; + + /** + * SamplingFrequency returns the SamplingFrequency in Hz stored in position 11,10 + * + * @returns {*} + * @constructor + */ + fh.samplingFrequency = function () { + return consts.newSamplingFrequencyInstance(((fh.value & 0x00000c00) >>> 10) >>> 0) + }; + + /** + * PaddingBit returns the padding bit stored in position 9 + * + * @return {number} + */ + fh.paddingBit = function () { + return ((fh.value & 0x00000200) >>> 9) >>> 0; + }; + + /** + * PrivateBit returns the private bit stored in position 8 - this bit may be used to store + * arbitrary data to be used by an application + * + * @return {number} + */ + fh.privateBit = function () { + return ((fh.value & 0x00000100) >>> 8) >>> 0; + }; + + /** + * Mode returns the channel mode, stored in position 7,6 + * + * @return {number} + */ + fh.mode = function () { + return ((fh.value & 0x000000c0) >>> 6) >>> 0; + }; + + /** + * modeExtension returns the mode_extension - for use with Joint Stereo - stored in + * position 4,5 + * + * @returns {number} + */ + fh.modeExtension = function () { + return ((fh.value & 0x00000030) >>> 4) >>> 0; + }; + + /** + * UseMSStereo returns a boolean value indicating whether the frame uses middle/side stereo. + * + * @returns {*} + */ + fh.useMSStereo = function () { + if (fh.mode() !== consts.ModeJointStereo) { + return false; + } + return (fh.modeExtension() & 0x2) !== 0; + }; + + /** + * UseIntensityStereo returns a boolean value indicating whether the frame uses intensity + * stereo. + * + * @returns {*} + */ + fh.useIntensityStereo = function () { + if (fh.mode() !== consts.ModeJointStereo) { + return false; + } + return (fh.modeExtension() & 0x1) !== 0; + }; + + /** + * Copyright returns whether or not this recording is copywritten - stored in position 3 + * + * @returns {number} + */ + fh.copyright = function () { + return ((fh.value & 0x00000008) >>> 3) >>> 0; + }; + + /** + * OriginalOrCopy returns whether or not this is an Original recording or a copy of one - + * stored in position 2 + * + * @returns {number} + */ + fh.originalOrCopy = function () { + return ((fh.value & 0x00000004) >>> 2) >>> 0; + }; + + /** + * Emphasis returns emphasis - the emphasis indication is here to tell the decoder that the + * file must be de-emphasized - stored in position 0,1 + * + * @returns {number} + */ + fh.emphasis = function () { + return (fh.value & 0x00000003) >>> 0; + }; + + /** + * IsValid returns a boolean value indicating whether the header is valid or not. + * + * @returns {boolean} + */ + fh.isValid = function () { + const sync = 0xffe00000; + if ((fh.value & sync) >>> 0 !== sync) { + return false; + } + if (fh.id() === consts.VersionReserved) { + return false; + } + if (fh.bitrateIndex() === 15) { + return false; + } + if (fh.samplingFrequency().value === consts.SamplingFrequencyReserved) { + return false; + } + if (fh.layer() === consts.LayerReserved) { + return false; + } + if (fh.emphasis() === 2) { + return false; + } + return true; + }; + + /** + * @returns {number} + */ + fh.frameSize = function () { + var value = (144 * Frameheader.bitrate(fh.layer(), fh.bitrateIndex())) + / fh.samplingFrequency().Int() + + fh.paddingBit(); + return Math.floor(value); + }; + + /** + * @returns {number} + */ + fh.numberOfChannels = function () { + if (fh.mode() === consts.ModeSingleChannel) { + return 1; + } + return 2; + }; + + return fh; + }, + + bitrate: function (layer, index) { + switch (layer) { + case consts.Layer1: + return [0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, + 256000, 288000, 320000, 352000, 384000, 416000, 448000][index]; + case consts.Layer2: + return [0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, + 128000, 160000, 192000, 224000, 256000, 320000, 384000][index]; + case consts.Layer3: + return [0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, + 112000, 128000, 160000, 192000, 224000, 256000, 320000][index]; + } + throw new Error('not reached'); + }, + + read: function (source, position) { + var pos = position; + + var result = source.readFull(4); + if (result.err) { + return { + err: result.err + } + } + var buf = result.buf; + if (buf.byteLength < 4) { + return { + h: 0, + position: 0, + err: "UnexpectedEOF readHeader (1)" + } + } + + var b1 = buf[0] >>> 0; + var b2 = buf[1] >>> 0; + var b3 = buf[2] >>> 0; + var b4 = buf[3] >>> 0; + + var fh = Frameheader.createNew((((b1 << 24) >>> 0) | ((b2 << 16) >>> 0) | ((b3 << 8) >>> 0) | ((b4 << 0) >>> 0)) >>> 0); + while (!fh.isValid()) { + // stopPosition++; + + result = source.readFull(1); + if (result.err) { + return { + err: result.err + } + } + buf = result.buf; + + if (buf.byteLength < 1) { + return { + h: 0, + position: 0, + err: "UnexpectedEOF readHeader (2)" + } + } + + b1 = b2; + b2 = b3; + b3 = b4; + b4 = buf[0] >>> 0; + + fh = Frameheader.createNew((((b1 << 24) >>> 0) | ((b2 << 16) >>> 0) | ((b3 << 8) >>> 0) | ((b4 << 0) >>> 0)) >>> 0); + pos++; + } + + // If we get here we've found the sync word, and can decode the header + // which is in the low 20 bits of the 32-bit sync+header word. + if (fh.bitrateIndex() === 0) { + return { + h: 0, + position: 0, + err: "mp3: free bitrate format is not supported. Header word is " + fh.value + " at position " + position + } + } + + return { + h: fh, + position: pos + } + } +}; + +exports = Frameheader; diff --git a/assets/disk0/tvdos/include/js-mp3/huffman.js b/assets/disk0/tvdos/include/js-mp3/huffman.js new file mode 100644 index 0000000..2856066 --- /dev/null +++ b/assets/disk0/tvdos/include/js-mp3/huffman.js @@ -0,0 +1,412 @@ +var huffmanTable = new Uint16Array([ + // 1 + 0x0201, 0x0000, 0x0201, 0x0010, 0x0201, 0x0001, 0x0011, + // 2 + 0x0201, 0x0000, 0x0401, 0x0201, 0x0010, 0x0001, 0x0201, 0x0011, 0x0401, 0x0201, 0x0020, + 0x0021, 0x0201, 0x0012, 0x0201, 0x0002, 0x0022, + // 3 + 0x0401, 0x0201, 0x0000, 0x0001, 0x0201, 0x0011, 0x0201, 0x0010, 0x0401, 0x0201, 0x0020, + 0x0021, 0x0201, 0x0012, 0x0201, 0x0002, 0x0022, + // 5 + 0x0201, 0x0000, 0x0401, 0x0201, 0x0010, 0x0001, 0x0201, 0x0011, 0x0801, 0x0401, 0x0201, + 0x0020, 0x0002, 0x0201, 0x0021, 0x0012, 0x0801, 0x0401, 0x0201, 0x0022, 0x0030, 0x0201, + 0x0003, 0x0013, 0x0201, 0x0031, 0x0201, 0x0032, 0x0201, 0x0023, 0x0033, + // 6 + 0x0601, 0x0401, 0x0201, 0x0000, 0x0010, 0x0011, 0x0601, 0x0201, 0x0001, 0x0201, 0x0020, + 0x0021, 0x0601, 0x0201, 0x0012, 0x0201, 0x0002, 0x0022, 0x0401, 0x0201, 0x0031, 0x0013, + 0x0401, 0x0201, 0x0030, 0x0032, 0x0201, 0x0023, 0x0201, 0x0003, 0x0033, + // 7 + 0x0201, 0x0000, 0x0401, 0x0201, 0x0010, 0x0001, 0x0801, 0x0201, 0x0011, 0x0401, 0x0201, + 0x0020, 0x0002, 0x0021, 0x1201, 0x0601, 0x0201, 0x0012, 0x0201, 0x0022, 0x0030, 0x0401, + 0x0201, 0x0031, 0x0013, 0x0401, 0x0201, 0x0003, 0x0032, 0x0201, 0x0023, 0x0004, 0x0a01, + 0x0401, 0x0201, 0x0040, 0x0041, 0x0201, 0x0014, 0x0201, 0x0042, 0x0024, 0x0c01, 0x0601, + 0x0401, 0x0201, 0x0033, 0x0043, 0x0050, 0x0401, 0x0201, 0x0034, 0x0005, 0x0051, 0x0601, + 0x0201, 0x0015, 0x0201, 0x0052, 0x0025, 0x0401, 0x0201, 0x0044, 0x0035, 0x0401, 0x0201, + 0x0053, 0x0054, 0x0201, 0x0045, 0x0055, + // 8 + 0x0601, 0x0201, 0x0000, 0x0201, 0x0010, 0x0001, 0x0201, 0x0011, 0x0401, 0x0201, 0x0021, + 0x0012, 0x0e01, 0x0401, 0x0201, 0x0020, 0x0002, 0x0201, 0x0022, 0x0401, 0x0201, 0x0030, + 0x0003, 0x0201, 0x0031, 0x0013, 0x0e01, 0x0801, 0x0401, 0x0201, 0x0032, 0x0023, 0x0201, + 0x0040, 0x0004, 0x0201, 0x0041, 0x0201, 0x0014, 0x0042, 0x0c01, 0x0601, 0x0201, 0x0024, + 0x0201, 0x0033, 0x0050, 0x0401, 0x0201, 0x0043, 0x0034, 0x0051, 0x0601, 0x0201, 0x0015, + 0x0201, 0x0005, 0x0052, 0x0601, 0x0201, 0x0025, 0x0201, 0x0044, 0x0035, 0x0201, 0x0053, + 0x0201, 0x0045, 0x0201, 0x0054, 0x0055, + // 9 + 0x0801, 0x0401, 0x0201, 0x0000, 0x0010, 0x0201, 0x0001, 0x0011, 0x0a01, 0x0401, 0x0201, + 0x0020, 0x0021, 0x0201, 0x0012, 0x0201, 0x0002, 0x0022, 0x0c01, 0x0601, 0x0401, 0x0201, + 0x0030, 0x0003, 0x0031, 0x0201, 0x0013, 0x0201, 0x0032, 0x0023, 0x0c01, 0x0401, 0x0201, + 0x0041, 0x0014, 0x0401, 0x0201, 0x0040, 0x0033, 0x0201, 0x0042, 0x0024, 0x0a01, 0x0601, + 0x0401, 0x0201, 0x0004, 0x0050, 0x0043, 0x0201, 0x0034, 0x0051, 0x0801, 0x0401, 0x0201, + 0x0015, 0x0052, 0x0201, 0x0025, 0x0044, 0x0601, 0x0401, 0x0201, 0x0005, 0x0054, 0x0053, + 0x0201, 0x0035, 0x0201, 0x0045, 0x0055, + // 10 + 0x0201, 0x0000, 0x0401, 0x0201, 0x0010, 0x0001, 0x0a01, 0x0201, 0x0011, 0x0401, 0x0201, + 0x0020, 0x0002, 0x0201, 0x0021, 0x0012, 0x1c01, 0x0801, 0x0401, 0x0201, 0x0022, 0x0030, + 0x0201, 0x0031, 0x0013, 0x0801, 0x0401, 0x0201, 0x0003, 0x0032, 0x0201, 0x0023, 0x0040, + 0x0401, 0x0201, 0x0041, 0x0014, 0x0401, 0x0201, 0x0004, 0x0033, 0x0201, 0x0042, 0x0024, + 0x1c01, 0x0a01, 0x0601, 0x0401, 0x0201, 0x0050, 0x0005, 0x0060, 0x0201, 0x0061, 0x0016, + 0x0c01, 0x0601, 0x0401, 0x0201, 0x0043, 0x0034, 0x0051, 0x0201, 0x0015, 0x0201, 0x0052, + 0x0025, 0x0401, 0x0201, 0x0026, 0x0036, 0x0071, 0x1401, 0x0801, 0x0201, 0x0017, 0x0401, + 0x0201, 0x0044, 0x0053, 0x0006, 0x0601, 0x0401, 0x0201, 0x0035, 0x0045, 0x0062, 0x0201, + 0x0070, 0x0201, 0x0007, 0x0064, 0x0e01, 0x0401, 0x0201, 0x0072, 0x0027, 0x0601, 0x0201, + 0x0063, 0x0201, 0x0054, 0x0055, 0x0201, 0x0046, 0x0073, 0x0801, 0x0401, 0x0201, 0x0037, + 0x0065, 0x0201, 0x0056, 0x0074, 0x0601, 0x0201, 0x0047, 0x0201, 0x0066, 0x0075, 0x0401, + 0x0201, 0x0057, 0x0076, 0x0201, 0x0067, 0x0077, + // 11 + 0x0601, 0x0201, 0x0000, 0x0201, 0x0010, 0x0001, 0x0801, 0x0201, 0x0011, 0x0401, 0x0201, + 0x0020, 0x0002, 0x0012, 0x1801, 0x0801, 0x0201, 0x0021, 0x0201, 0x0022, 0x0201, 0x0030, + 0x0003, 0x0401, 0x0201, 0x0031, 0x0013, 0x0401, 0x0201, 0x0032, 0x0023, 0x0401, 0x0201, + 0x0040, 0x0004, 0x0201, 0x0041, 0x0014, 0x1e01, 0x1001, 0x0a01, 0x0401, 0x0201, 0x0042, + 0x0024, 0x0401, 0x0201, 0x0033, 0x0043, 0x0050, 0x0401, 0x0201, 0x0034, 0x0051, 0x0061, + 0x0601, 0x0201, 0x0016, 0x0201, 0x0006, 0x0026, 0x0201, 0x0062, 0x0201, 0x0015, 0x0201, + 0x0005, 0x0052, 0x1001, 0x0a01, 0x0601, 0x0401, 0x0201, 0x0025, 0x0044, 0x0060, 0x0201, + 0x0063, 0x0036, 0x0401, 0x0201, 0x0070, 0x0017, 0x0071, 0x1001, 0x0601, 0x0401, 0x0201, + 0x0007, 0x0064, 0x0072, 0x0201, 0x0027, 0x0401, 0x0201, 0x0053, 0x0035, 0x0201, 0x0054, + 0x0045, 0x0a01, 0x0401, 0x0201, 0x0046, 0x0073, 0x0201, 0x0037, 0x0201, 0x0065, 0x0056, + 0x0a01, 0x0601, 0x0401, 0x0201, 0x0055, 0x0057, 0x0074, 0x0201, 0x0047, 0x0066, 0x0401, + 0x0201, 0x0075, 0x0076, 0x0201, 0x0067, 0x0077, + // 12 + 0x0c01, 0x0401, 0x0201, 0x0010, 0x0001, 0x0201, 0x0011, 0x0201, 0x0000, 0x0201, 0x0020, + 0x0002, 0x1001, 0x0401, 0x0201, 0x0021, 0x0012, 0x0401, 0x0201, 0x0022, 0x0031, 0x0201, + 0x0013, 0x0201, 0x0030, 0x0201, 0x0003, 0x0040, 0x1a01, 0x0801, 0x0401, 0x0201, 0x0032, + 0x0023, 0x0201, 0x0041, 0x0033, 0x0a01, 0x0401, 0x0201, 0x0014, 0x0042, 0x0201, 0x0024, + 0x0201, 0x0004, 0x0050, 0x0401, 0x0201, 0x0043, 0x0034, 0x0201, 0x0051, 0x0015, 0x1c01, + 0x0e01, 0x0801, 0x0401, 0x0201, 0x0052, 0x0025, 0x0201, 0x0053, 0x0035, 0x0401, 0x0201, + 0x0060, 0x0016, 0x0061, 0x0401, 0x0201, 0x0062, 0x0026, 0x0601, 0x0401, 0x0201, 0x0005, + 0x0006, 0x0044, 0x0201, 0x0054, 0x0045, 0x1201, 0x0a01, 0x0401, 0x0201, 0x0063, 0x0036, + 0x0401, 0x0201, 0x0070, 0x0007, 0x0071, 0x0401, 0x0201, 0x0017, 0x0064, 0x0201, 0x0046, + 0x0072, 0x0a01, 0x0601, 0x0201, 0x0027, 0x0201, 0x0055, 0x0073, 0x0201, 0x0037, 0x0056, + 0x0801, 0x0401, 0x0201, 0x0065, 0x0074, 0x0201, 0x0047, 0x0066, 0x0401, 0x0201, 0x0075, + 0x0057, 0x0201, 0x0076, 0x0201, 0x0067, 0x0077, + // 13 + 0x0201, 0x0000, 0x0601, 0x0201, 0x0010, 0x0201, 0x0001, 0x0011, 0x1c01, 0x0801, 0x0401, + 0x0201, 0x0020, 0x0002, 0x0201, 0x0021, 0x0012, 0x0801, 0x0401, 0x0201, 0x0022, 0x0030, + 0x0201, 0x0003, 0x0031, 0x0601, 0x0201, 0x0013, 0x0201, 0x0032, 0x0023, 0x0401, 0x0201, + 0x0040, 0x0004, 0x0041, 0x4601, 0x1c01, 0x0e01, 0x0601, 0x0201, 0x0014, 0x0201, 0x0033, + 0x0042, 0x0401, 0x0201, 0x0024, 0x0050, 0x0201, 0x0043, 0x0034, 0x0401, 0x0201, 0x0051, + 0x0015, 0x0401, 0x0201, 0x0005, 0x0052, 0x0201, 0x0025, 0x0201, 0x0044, 0x0053, 0x0e01, + 0x0801, 0x0401, 0x0201, 0x0060, 0x0006, 0x0201, 0x0061, 0x0016, 0x0401, 0x0201, 0x0080, + 0x0008, 0x0081, 0x1001, 0x0801, 0x0401, 0x0201, 0x0035, 0x0062, 0x0201, 0x0026, 0x0054, + 0x0401, 0x0201, 0x0045, 0x0063, 0x0201, 0x0036, 0x0070, 0x0601, 0x0401, 0x0201, 0x0007, + 0x0055, 0x0071, 0x0201, 0x0017, 0x0201, 0x0027, 0x0037, 0x4801, 0x1801, 0x0c01, 0x0401, + 0x0201, 0x0018, 0x0082, 0x0201, 0x0028, 0x0401, 0x0201, 0x0064, 0x0046, 0x0072, 0x0801, + 0x0401, 0x0201, 0x0084, 0x0048, 0x0201, 0x0090, 0x0009, 0x0201, 0x0091, 0x0019, 0x1801, + 0x0e01, 0x0801, 0x0401, 0x0201, 0x0073, 0x0065, 0x0201, 0x0056, 0x0074, 0x0401, 0x0201, + 0x0047, 0x0066, 0x0083, 0x0601, 0x0201, 0x0038, 0x0201, 0x0075, 0x0057, 0x0201, 0x0092, + 0x0029, 0x0e01, 0x0801, 0x0401, 0x0201, 0x0067, 0x0085, 0x0201, 0x0058, 0x0039, 0x0201, + 0x0093, 0x0201, 0x0049, 0x0086, 0x0601, 0x0201, 0x00a0, 0x0201, 0x0068, 0x000a, 0x0201, + 0x00a1, 0x001a, 0x4401, 0x1801, 0x0c01, 0x0401, 0x0201, 0x00a2, 0x002a, 0x0401, 0x0201, + 0x0095, 0x0059, 0x0201, 0x00a3, 0x003a, 0x0801, 0x0401, 0x0201, 0x004a, 0x0096, 0x0201, + 0x00b0, 0x000b, 0x0201, 0x00b1, 0x001b, 0x1401, 0x0801, 0x0201, 0x00b2, 0x0401, 0x0201, + 0x0076, 0x0077, 0x0094, 0x0601, 0x0401, 0x0201, 0x0087, 0x0078, 0x00a4, 0x0401, 0x0201, + 0x0069, 0x00a5, 0x002b, 0x0c01, 0x0601, 0x0401, 0x0201, 0x005a, 0x0088, 0x00b3, 0x0201, + 0x003b, 0x0201, 0x0079, 0x00a6, 0x0601, 0x0401, 0x0201, 0x006a, 0x00b4, 0x00c0, 0x0401, + 0x0201, 0x000c, 0x0098, 0x00c1, 0x3c01, 0x1601, 0x0a01, 0x0601, 0x0201, 0x001c, 0x0201, + 0x0089, 0x00b5, 0x0201, 0x005b, 0x00c2, 0x0401, 0x0201, 0x002c, 0x003c, 0x0401, 0x0201, + 0x00b6, 0x006b, 0x0201, 0x00c4, 0x004c, 0x1001, 0x0801, 0x0401, 0x0201, 0x00a8, 0x008a, + 0x0201, 0x00d0, 0x000d, 0x0201, 0x00d1, 0x0201, 0x004b, 0x0201, 0x0097, 0x00a7, 0x0c01, + 0x0601, 0x0201, 0x00c3, 0x0201, 0x007a, 0x0099, 0x0401, 0x0201, 0x00c5, 0x005c, 0x00b7, + 0x0401, 0x0201, 0x001d, 0x00d2, 0x0201, 0x002d, 0x0201, 0x007b, 0x00d3, 0x3401, 0x1c01, + 0x0c01, 0x0401, 0x0201, 0x003d, 0x00c6, 0x0401, 0x0201, 0x006c, 0x00a9, 0x0201, 0x009a, + 0x00d4, 0x0801, 0x0401, 0x0201, 0x00b8, 0x008b, 0x0201, 0x004d, 0x00c7, 0x0401, 0x0201, + 0x007c, 0x00d5, 0x0201, 0x005d, 0x00e0, 0x0a01, 0x0401, 0x0201, 0x00e1, 0x001e, 0x0401, + 0x0201, 0x000e, 0x002e, 0x00e2, 0x0801, 0x0401, 0x0201, 0x00e3, 0x006d, 0x0201, 0x008c, + 0x00e4, 0x0401, 0x0201, 0x00e5, 0x00ba, 0x00f0, 0x2601, 0x1001, 0x0401, 0x0201, 0x00f1, + 0x001f, 0x0601, 0x0401, 0x0201, 0x00aa, 0x009b, 0x00b9, 0x0201, 0x003e, 0x0201, 0x00d6, + 0x00c8, 0x0c01, 0x0601, 0x0201, 0x004e, 0x0201, 0x00d7, 0x007d, 0x0201, 0x00ab, 0x0201, + 0x005e, 0x00c9, 0x0601, 0x0201, 0x000f, 0x0201, 0x009c, 0x006e, 0x0201, 0x00f2, 0x002f, + 0x2001, 0x1001, 0x0601, 0x0401, 0x0201, 0x00d8, 0x008d, 0x003f, 0x0601, 0x0201, 0x00f3, + 0x0201, 0x00e6, 0x00ca, 0x0201, 0x00f4, 0x004f, 0x0801, 0x0401, 0x0201, 0x00bb, 0x00ac, + 0x0201, 0x00e7, 0x00f5, 0x0401, 0x0201, 0x00d9, 0x009d, 0x0201, 0x005f, 0x00e8, 0x1e01, + 0x0c01, 0x0601, 0x0201, 0x006f, 0x0201, 0x00f6, 0x00cb, 0x0401, 0x0201, 0x00bc, 0x00ad, + 0x00da, 0x0801, 0x0201, 0x00f7, 0x0401, 0x0201, 0x007e, 0x007f, 0x008e, 0x0601, 0x0401, + 0x0201, 0x009e, 0x00ae, 0x00cc, 0x0201, 0x00f8, 0x008f, 0x1201, 0x0801, 0x0401, 0x0201, + 0x00db, 0x00bd, 0x0201, 0x00ea, 0x00f9, 0x0401, 0x0201, 0x009f, 0x00eb, 0x0201, 0x00be, + 0x0201, 0x00cd, 0x00fa, 0x0e01, 0x0401, 0x0201, 0x00dd, 0x00ec, 0x0601, 0x0401, 0x0201, + 0x00e9, 0x00af, 0x00dc, 0x0201, 0x00ce, 0x00fb, 0x0801, 0x0401, 0x0201, 0x00bf, 0x00de, + 0x0201, 0x00cf, 0x00ee, 0x0401, 0x0201, 0x00df, 0x00ef, 0x0201, 0x00ff, 0x0201, 0x00ed, + 0x0201, 0x00fd, 0x0201, 0x00fc, 0x00fe, + // 15 + 0x1001, 0x0601, 0x0201, 0x0000, 0x0201, 0x0010, 0x0001, 0x0201, 0x0011, 0x0401, 0x0201, + 0x0020, 0x0002, 0x0201, 0x0021, 0x0012, 0x3201, 0x1001, 0x0601, 0x0201, 0x0022, 0x0201, + 0x0030, 0x0031, 0x0601, 0x0201, 0x0013, 0x0201, 0x0003, 0x0040, 0x0201, 0x0032, 0x0023, + 0x0e01, 0x0601, 0x0401, 0x0201, 0x0004, 0x0014, 0x0041, 0x0401, 0x0201, 0x0033, 0x0042, + 0x0201, 0x0024, 0x0043, 0x0a01, 0x0601, 0x0201, 0x0034, 0x0201, 0x0050, 0x0005, 0x0201, + 0x0051, 0x0015, 0x0401, 0x0201, 0x0052, 0x0025, 0x0401, 0x0201, 0x0044, 0x0053, 0x0061, + 0x5a01, 0x2401, 0x1201, 0x0a01, 0x0601, 0x0201, 0x0035, 0x0201, 0x0060, 0x0006, 0x0201, + 0x0016, 0x0062, 0x0401, 0x0201, 0x0026, 0x0054, 0x0201, 0x0045, 0x0063, 0x0a01, 0x0601, + 0x0201, 0x0036, 0x0201, 0x0070, 0x0007, 0x0201, 0x0071, 0x0055, 0x0401, 0x0201, 0x0017, + 0x0064, 0x0201, 0x0072, 0x0027, 0x1801, 0x1001, 0x0801, 0x0401, 0x0201, 0x0046, 0x0073, + 0x0201, 0x0037, 0x0065, 0x0401, 0x0201, 0x0056, 0x0080, 0x0201, 0x0008, 0x0074, 0x0401, + 0x0201, 0x0081, 0x0018, 0x0201, 0x0082, 0x0028, 0x1001, 0x0801, 0x0401, 0x0201, 0x0047, + 0x0066, 0x0201, 0x0083, 0x0038, 0x0401, 0x0201, 0x0075, 0x0057, 0x0201, 0x0084, 0x0048, + 0x0601, 0x0401, 0x0201, 0x0090, 0x0019, 0x0091, 0x0401, 0x0201, 0x0092, 0x0076, 0x0201, + 0x0067, 0x0029, 0x5c01, 0x2401, 0x1201, 0x0a01, 0x0401, 0x0201, 0x0085, 0x0058, 0x0401, + 0x0201, 0x0009, 0x0077, 0x0093, 0x0401, 0x0201, 0x0039, 0x0094, 0x0201, 0x0049, 0x0086, + 0x0a01, 0x0601, 0x0201, 0x0068, 0x0201, 0x00a0, 0x000a, 0x0201, 0x00a1, 0x001a, 0x0401, + 0x0201, 0x00a2, 0x002a, 0x0201, 0x0095, 0x0059, 0x1a01, 0x0e01, 0x0601, 0x0201, 0x00a3, + 0x0201, 0x003a, 0x0087, 0x0401, 0x0201, 0x0078, 0x00a4, 0x0201, 0x004a, 0x0096, 0x0601, + 0x0401, 0x0201, 0x0069, 0x00b0, 0x00b1, 0x0401, 0x0201, 0x001b, 0x00a5, 0x00b2, 0x0e01, + 0x0801, 0x0401, 0x0201, 0x005a, 0x002b, 0x0201, 0x0088, 0x0097, 0x0201, 0x00b3, 0x0201, + 0x0079, 0x003b, 0x0801, 0x0401, 0x0201, 0x006a, 0x00b4, 0x0201, 0x004b, 0x00c1, 0x0401, + 0x0201, 0x0098, 0x0089, 0x0201, 0x001c, 0x00b5, 0x5001, 0x2201, 0x1001, 0x0601, 0x0401, + 0x0201, 0x005b, 0x002c, 0x00c2, 0x0601, 0x0401, 0x0201, 0x000b, 0x00c0, 0x00a6, 0x0201, + 0x00a7, 0x007a, 0x0a01, 0x0401, 0x0201, 0x00c3, 0x003c, 0x0401, 0x0201, 0x000c, 0x0099, + 0x00b6, 0x0401, 0x0201, 0x006b, 0x00c4, 0x0201, 0x004c, 0x00a8, 0x1401, 0x0a01, 0x0401, + 0x0201, 0x008a, 0x00c5, 0x0401, 0x0201, 0x00d0, 0x005c, 0x00d1, 0x0401, 0x0201, 0x00b7, + 0x007b, 0x0201, 0x001d, 0x0201, 0x000d, 0x002d, 0x0c01, 0x0401, 0x0201, 0x00d2, 0x00d3, + 0x0401, 0x0201, 0x003d, 0x00c6, 0x0201, 0x006c, 0x00a9, 0x0601, 0x0401, 0x0201, 0x009a, + 0x00b8, 0x00d4, 0x0401, 0x0201, 0x008b, 0x004d, 0x0201, 0x00c7, 0x007c, 0x4401, 0x2201, + 0x1201, 0x0a01, 0x0401, 0x0201, 0x00d5, 0x005d, 0x0401, 0x0201, 0x00e0, 0x000e, 0x00e1, + 0x0401, 0x0201, 0x001e, 0x00e2, 0x0201, 0x00aa, 0x002e, 0x0801, 0x0401, 0x0201, 0x00b9, + 0x009b, 0x0201, 0x00e3, 0x00d6, 0x0401, 0x0201, 0x006d, 0x003e, 0x0201, 0x00c8, 0x008c, + 0x1001, 0x0801, 0x0401, 0x0201, 0x00e4, 0x004e, 0x0201, 0x00d7, 0x007d, 0x0401, 0x0201, + 0x00e5, 0x00ba, 0x0201, 0x00ab, 0x005e, 0x0801, 0x0401, 0x0201, 0x00c9, 0x009c, 0x0201, + 0x00f1, 0x001f, 0x0601, 0x0401, 0x0201, 0x00f0, 0x006e, 0x00f2, 0x0201, 0x002f, 0x00e6, + 0x2601, 0x1201, 0x0801, 0x0401, 0x0201, 0x00d8, 0x00f3, 0x0201, 0x003f, 0x00f4, 0x0601, + 0x0201, 0x004f, 0x0201, 0x008d, 0x00d9, 0x0201, 0x00bb, 0x00ca, 0x0801, 0x0401, 0x0201, + 0x00ac, 0x00e7, 0x0201, 0x007e, 0x00f5, 0x0801, 0x0401, 0x0201, 0x009d, 0x005f, 0x0201, + 0x00e8, 0x008e, 0x0201, 0x00f6, 0x00cb, 0x2201, 0x1201, 0x0a01, 0x0601, 0x0401, 0x0201, + 0x000f, 0x00ae, 0x006f, 0x0201, 0x00bc, 0x00da, 0x0401, 0x0201, 0x00ad, 0x00f7, 0x0201, + 0x007f, 0x00e9, 0x0801, 0x0401, 0x0201, 0x009e, 0x00cc, 0x0201, 0x00f8, 0x008f, 0x0401, + 0x0201, 0x00db, 0x00bd, 0x0201, 0x00ea, 0x00f9, 0x1001, 0x0801, 0x0401, 0x0201, 0x009f, + 0x00dc, 0x0201, 0x00cd, 0x00eb, 0x0401, 0x0201, 0x00be, 0x00fa, 0x0201, 0x00af, 0x00dd, + 0x0e01, 0x0601, 0x0401, 0x0201, 0x00ec, 0x00ce, 0x00fb, 0x0401, 0x0201, 0x00bf, 0x00ed, + 0x0201, 0x00de, 0x00fc, 0x0601, 0x0401, 0x0201, 0x00cf, 0x00fd, 0x00ee, 0x0401, 0x0201, + 0x00df, 0x00fe, 0x0201, 0x00ef, 0x00ff, + // 16 + 0x0201, 0x0000, 0x0601, 0x0201, 0x0010, 0x0201, 0x0001, 0x0011, 0x2a01, 0x0801, 0x0401, + 0x0201, 0x0020, 0x0002, 0x0201, 0x0021, 0x0012, 0x0a01, 0x0601, 0x0201, 0x0022, 0x0201, + 0x0030, 0x0003, 0x0201, 0x0031, 0x0013, 0x0a01, 0x0401, 0x0201, 0x0032, 0x0023, 0x0401, + 0x0201, 0x0040, 0x0004, 0x0041, 0x0601, 0x0201, 0x0014, 0x0201, 0x0033, 0x0042, 0x0401, + 0x0201, 0x0024, 0x0050, 0x0201, 0x0043, 0x0034, 0x8a01, 0x2801, 0x1001, 0x0601, 0x0401, + 0x0201, 0x0005, 0x0015, 0x0051, 0x0401, 0x0201, 0x0052, 0x0025, 0x0401, 0x0201, 0x0044, + 0x0035, 0x0053, 0x0a01, 0x0601, 0x0401, 0x0201, 0x0060, 0x0006, 0x0061, 0x0201, 0x0016, + 0x0062, 0x0801, 0x0401, 0x0201, 0x0026, 0x0054, 0x0201, 0x0045, 0x0063, 0x0401, 0x0201, + 0x0036, 0x0070, 0x0071, 0x2801, 0x1201, 0x0801, 0x0201, 0x0017, 0x0201, 0x0007, 0x0201, + 0x0055, 0x0064, 0x0401, 0x0201, 0x0072, 0x0027, 0x0401, 0x0201, 0x0046, 0x0065, 0x0073, + 0x0a01, 0x0601, 0x0201, 0x0037, 0x0201, 0x0056, 0x0008, 0x0201, 0x0080, 0x0081, 0x0601, + 0x0201, 0x0018, 0x0201, 0x0074, 0x0047, 0x0201, 0x0082, 0x0201, 0x0028, 0x0066, 0x1801, + 0x0e01, 0x0801, 0x0401, 0x0201, 0x0083, 0x0038, 0x0201, 0x0075, 0x0084, 0x0401, 0x0201, + 0x0048, 0x0090, 0x0091, 0x0601, 0x0201, 0x0019, 0x0201, 0x0009, 0x0076, 0x0201, 0x0092, + 0x0029, 0x0e01, 0x0801, 0x0401, 0x0201, 0x0085, 0x0058, 0x0201, 0x0093, 0x0039, 0x0401, + 0x0201, 0x00a0, 0x000a, 0x001a, 0x0801, 0x0201, 0x00a2, 0x0201, 0x0067, 0x0201, 0x0057, + 0x0049, 0x0601, 0x0201, 0x0094, 0x0201, 0x0077, 0x0086, 0x0201, 0x00a1, 0x0201, 0x0068, + 0x0095, 0xdc01, 0x7e01, 0x3201, 0x1a01, 0x0c01, 0x0601, 0x0201, 0x002a, 0x0201, 0x0059, + 0x003a, 0x0201, 0x00a3, 0x0201, 0x0087, 0x0078, 0x0801, 0x0401, 0x0201, 0x00a4, 0x004a, + 0x0201, 0x0096, 0x0069, 0x0401, 0x0201, 0x00b0, 0x000b, 0x00b1, 0x0a01, 0x0401, 0x0201, + 0x001b, 0x00b2, 0x0201, 0x002b, 0x0201, 0x00a5, 0x005a, 0x0601, 0x0201, 0x00b3, 0x0201, + 0x00a6, 0x006a, 0x0401, 0x0201, 0x00b4, 0x004b, 0x0201, 0x000c, 0x00c1, 0x1e01, 0x0e01, + 0x0601, 0x0401, 0x0201, 0x00b5, 0x00c2, 0x002c, 0x0401, 0x0201, 0x00a7, 0x00c3, 0x0201, + 0x006b, 0x00c4, 0x0801, 0x0201, 0x001d, 0x0401, 0x0201, 0x0088, 0x0097, 0x003b, 0x0401, + 0x0201, 0x00d1, 0x00d2, 0x0201, 0x002d, 0x00d3, 0x1201, 0x0601, 0x0401, 0x0201, 0x001e, + 0x002e, 0x00e2, 0x0601, 0x0401, 0x0201, 0x0079, 0x0098, 0x00c0, 0x0201, 0x001c, 0x0201, + 0x0089, 0x005b, 0x0e01, 0x0601, 0x0201, 0x003c, 0x0201, 0x007a, 0x00b6, 0x0401, 0x0201, + 0x004c, 0x0099, 0x0201, 0x00a8, 0x008a, 0x0601, 0x0201, 0x000d, 0x0201, 0x00c5, 0x005c, + 0x0401, 0x0201, 0x003d, 0x00c6, 0x0201, 0x006c, 0x009a, 0x5801, 0x5601, 0x2401, 0x1001, + 0x0801, 0x0401, 0x0201, 0x008b, 0x004d, 0x0201, 0x00c7, 0x007c, 0x0401, 0x0201, 0x00d5, + 0x005d, 0x0201, 0x00e0, 0x000e, 0x0801, 0x0201, 0x00e3, 0x0401, 0x0201, 0x00d0, 0x00b7, + 0x007b, 0x0601, 0x0401, 0x0201, 0x00a9, 0x00b8, 0x00d4, 0x0201, 0x00e1, 0x0201, 0x00aa, + 0x00b9, 0x1801, 0x0a01, 0x0601, 0x0401, 0x0201, 0x009b, 0x00d6, 0x006d, 0x0201, 0x003e, + 0x00c8, 0x0601, 0x0401, 0x0201, 0x008c, 0x00e4, 0x004e, 0x0401, 0x0201, 0x00d7, 0x00e5, + 0x0201, 0x00ba, 0x00ab, 0x0c01, 0x0401, 0x0201, 0x009c, 0x00e6, 0x0401, 0x0201, 0x006e, + 0x00d8, 0x0201, 0x008d, 0x00bb, 0x0801, 0x0401, 0x0201, 0x00e7, 0x009d, 0x0201, 0x00e8, + 0x008e, 0x0401, 0x0201, 0x00cb, 0x00bc, 0x009e, 0x00f1, 0x0201, 0x001f, 0x0201, 0x000f, + 0x002f, 0x4201, 0x3801, 0x0201, 0x00f2, 0x3401, 0x3201, 0x1401, 0x0801, 0x0201, 0x00bd, + 0x0201, 0x005e, 0x0201, 0x007d, 0x00c9, 0x0601, 0x0201, 0x00ca, 0x0201, 0x00ac, 0x007e, + 0x0401, 0x0201, 0x00da, 0x00ad, 0x00cc, 0x0a01, 0x0601, 0x0201, 0x00ae, 0x0201, 0x00db, + 0x00dc, 0x0201, 0x00cd, 0x00be, 0x0601, 0x0401, 0x0201, 0x00eb, 0x00ed, 0x00ee, 0x0601, + 0x0401, 0x0201, 0x00d9, 0x00ea, 0x00e9, 0x0201, 0x00de, 0x0401, 0x0201, 0x00dd, 0x00ec, + 0x00ce, 0x003f, 0x00f0, 0x0401, 0x0201, 0x00f3, 0x00f4, 0x0201, 0x004f, 0x0201, 0x00f5, + 0x005f, 0x0a01, 0x0201, 0x00ff, 0x0401, 0x0201, 0x00f6, 0x006f, 0x0201, 0x00f7, 0x007f, + 0x0c01, 0x0601, 0x0201, 0x008f, 0x0201, 0x00f8, 0x00f9, 0x0401, 0x0201, 0x009f, 0x00fa, + 0x00af, 0x0801, 0x0401, 0x0201, 0x00fb, 0x00bf, 0x0201, 0x00fc, 0x00cf, 0x0401, 0x0201, + 0x00fd, 0x00df, 0x0201, 0x00fe, 0x00ef, + // 24 + 0x3c01, 0x0801, 0x0401, 0x0201, 0x0000, 0x0010, 0x0201, 0x0001, 0x0011, 0x0e01, 0x0601, + 0x0401, 0x0201, 0x0020, 0x0002, 0x0021, 0x0201, 0x0012, 0x0201, 0x0022, 0x0201, 0x0030, + 0x0003, 0x0e01, 0x0401, 0x0201, 0x0031, 0x0013, 0x0401, 0x0201, 0x0032, 0x0023, 0x0401, + 0x0201, 0x0040, 0x0004, 0x0041, 0x0801, 0x0401, 0x0201, 0x0014, 0x0033, 0x0201, 0x0042, + 0x0024, 0x0601, 0x0401, 0x0201, 0x0043, 0x0034, 0x0051, 0x0601, 0x0401, 0x0201, 0x0050, + 0x0005, 0x0015, 0x0201, 0x0052, 0x0025, 0xfa01, 0x6201, 0x2201, 0x1201, 0x0a01, 0x0401, + 0x0201, 0x0044, 0x0053, 0x0201, 0x0035, 0x0201, 0x0060, 0x0006, 0x0401, 0x0201, 0x0061, + 0x0016, 0x0201, 0x0062, 0x0026, 0x0801, 0x0401, 0x0201, 0x0054, 0x0045, 0x0201, 0x0063, + 0x0036, 0x0401, 0x0201, 0x0071, 0x0055, 0x0201, 0x0064, 0x0046, 0x2001, 0x0e01, 0x0601, + 0x0201, 0x0072, 0x0201, 0x0027, 0x0037, 0x0201, 0x0073, 0x0401, 0x0201, 0x0070, 0x0007, + 0x0017, 0x0a01, 0x0401, 0x0201, 0x0065, 0x0056, 0x0401, 0x0201, 0x0080, 0x0008, 0x0081, + 0x0401, 0x0201, 0x0074, 0x0047, 0x0201, 0x0018, 0x0082, 0x1001, 0x0801, 0x0401, 0x0201, + 0x0028, 0x0066, 0x0201, 0x0083, 0x0038, 0x0401, 0x0201, 0x0075, 0x0057, 0x0201, 0x0084, + 0x0048, 0x0801, 0x0401, 0x0201, 0x0091, 0x0019, 0x0201, 0x0092, 0x0076, 0x0401, 0x0201, + 0x0067, 0x0029, 0x0201, 0x0085, 0x0058, 0x5c01, 0x2201, 0x1001, 0x0801, 0x0401, 0x0201, + 0x0093, 0x0039, 0x0201, 0x0094, 0x0049, 0x0401, 0x0201, 0x0077, 0x0086, 0x0201, 0x0068, + 0x00a1, 0x0801, 0x0401, 0x0201, 0x00a2, 0x002a, 0x0201, 0x0095, 0x0059, 0x0401, 0x0201, + 0x00a3, 0x003a, 0x0201, 0x0087, 0x0201, 0x0078, 0x004a, 0x1601, 0x0c01, 0x0401, 0x0201, + 0x00a4, 0x0096, 0x0401, 0x0201, 0x0069, 0x00b1, 0x0201, 0x001b, 0x00a5, 0x0601, 0x0201, + 0x00b2, 0x0201, 0x005a, 0x002b, 0x0201, 0x0088, 0x00b3, 0x1001, 0x0a01, 0x0601, 0x0201, + 0x0090, 0x0201, 0x0009, 0x00a0, 0x0201, 0x0097, 0x0079, 0x0401, 0x0201, 0x00a6, 0x006a, + 0x00b4, 0x0c01, 0x0601, 0x0201, 0x001a, 0x0201, 0x000a, 0x00b0, 0x0201, 0x003b, 0x0201, + 0x000b, 0x00c0, 0x0401, 0x0201, 0x004b, 0x00c1, 0x0201, 0x0098, 0x0089, 0x4301, 0x2201, + 0x1001, 0x0801, 0x0401, 0x0201, 0x001c, 0x00b5, 0x0201, 0x005b, 0x00c2, 0x0401, 0x0201, + 0x002c, 0x00a7, 0x0201, 0x007a, 0x00c3, 0x0a01, 0x0601, 0x0201, 0x003c, 0x0201, 0x000c, + 0x00d0, 0x0201, 0x00b6, 0x006b, 0x0401, 0x0201, 0x00c4, 0x004c, 0x0201, 0x0099, 0x00a8, + 0x1001, 0x0801, 0x0401, 0x0201, 0x008a, 0x00c5, 0x0201, 0x005c, 0x00d1, 0x0401, 0x0201, + 0x00b7, 0x007b, 0x0201, 0x001d, 0x00d2, 0x0901, 0x0401, 0x0201, 0x002d, 0x00d3, 0x0201, + 0x003d, 0x00c6, 0x55fa, 0x0401, 0x0201, 0x006c, 0x00a9, 0x0201, 0x009a, 0x00d4, 0x2001, + 0x1001, 0x0801, 0x0401, 0x0201, 0x00b8, 0x008b, 0x0201, 0x004d, 0x00c7, 0x0401, 0x0201, + 0x007c, 0x00d5, 0x0201, 0x005d, 0x00e1, 0x0801, 0x0401, 0x0201, 0x001e, 0x00e2, 0x0201, + 0x00aa, 0x00b9, 0x0401, 0x0201, 0x009b, 0x00e3, 0x0201, 0x00d6, 0x006d, 0x1401, 0x0a01, + 0x0601, 0x0201, 0x003e, 0x0201, 0x002e, 0x004e, 0x0201, 0x00c8, 0x008c, 0x0401, 0x0201, + 0x00e4, 0x00d7, 0x0401, 0x0201, 0x007d, 0x00ab, 0x00e5, 0x0a01, 0x0401, 0x0201, 0x00ba, + 0x005e, 0x0201, 0x00c9, 0x0201, 0x009c, 0x006e, 0x0801, 0x0201, 0x00e6, 0x0201, 0x000d, + 0x0201, 0x00e0, 0x000e, 0x0401, 0x0201, 0x00d8, 0x008d, 0x0201, 0x00bb, 0x00ca, 0x4a01, + 0x0201, 0x00ff, 0x4001, 0x3a01, 0x2001, 0x1001, 0x0801, 0x0401, 0x0201, 0x00ac, 0x00e7, + 0x0201, 0x007e, 0x00d9, 0x0401, 0x0201, 0x009d, 0x00e8, 0x0201, 0x008e, 0x00cb, 0x0801, + 0x0401, 0x0201, 0x00bc, 0x00da, 0x0201, 0x00ad, 0x00e9, 0x0401, 0x0201, 0x009e, 0x00cc, + 0x0201, 0x00db, 0x00bd, 0x1001, 0x0801, 0x0401, 0x0201, 0x00ea, 0x00ae, 0x0201, 0x00dc, + 0x00cd, 0x0401, 0x0201, 0x00eb, 0x00be, 0x0201, 0x00dd, 0x00ec, 0x0801, 0x0401, 0x0201, + 0x00ce, 0x00ed, 0x0201, 0x00de, 0x00ee, 0x000f, 0x0401, 0x0201, 0x00f0, 0x001f, 0x00f1, + 0x0401, 0x0201, 0x00f2, 0x002f, 0x0201, 0x00f3, 0x003f, 0x1201, 0x0801, 0x0401, 0x0201, + 0x00f4, 0x004f, 0x0201, 0x00f5, 0x005f, 0x0401, 0x0201, 0x00f6, 0x006f, 0x0201, 0x00f7, + 0x0201, 0x007f, 0x008f, 0x0a01, 0x0401, 0x0201, 0x00f8, 0x00f9, 0x0401, 0x0201, 0x009f, + 0x00af, 0x00fa, 0x0801, 0x0401, 0x0201, 0x00fb, 0x00bf, 0x0201, 0x00fc, 0x00cf, 0x0401, + 0x0201, 0x00fd, 0x00df, 0x0201, 0x00fe, 0x00ef, + // 32 + 0x0201, 0x0000, 0x0801, 0x0401, 0x0201, 0x0008, 0x0004, 0x0201, 0x0001, 0x0002, 0x0801, + 0x0401, 0x0201, 0x000c, 0x000a, 0x0201, 0x0003, 0x0006, 0x0601, 0x0201, 0x0009, 0x0201, + 0x0005, 0x0007, 0x0401, 0x0201, 0x000e, 0x000d, 0x0201, 0x000f, 0x000b, + // 33 + 0x1001, 0x0801, 0x0401, 0x0201, 0x0000, 0x0001, 0x0201, 0x0002, 0x0003, 0x0401, 0x0201, + 0x0004, 0x0005, 0x0201, 0x0006, 0x0007, 0x0801, 0x0401, 0x0201, 0x0008, 0x0009, 0x0201, + 0x000a, 0x000b, 0x0401, 0x0201, 0x000c, 0x000d, 0x0201, 0x000e, 0x000f, +]); + +var huffmanMain = [ + { hufftable: null, linbits: 0}, // Table 0 + { hufftable: huffmanTable.subarray(0, 7), linbits: 0}, // Table 1 + { hufftable: huffmanTable.subarray(7, (7 + 17)), linbits: 0}, // Table 2 + { hufftable: huffmanTable.subarray(24, (24 + 17)), linbits: 0}, // Table 3 + { hufftable: null, linbits: 0}, // Table 4 + { hufftable: huffmanTable.subarray(41, (41 + 31)), linbits: 0}, // Table 5 + { hufftable: huffmanTable.subarray(72, (72 + 31)), linbits: 0}, // Table 6 + { hufftable: huffmanTable.subarray(103, (103 + 71)), linbits: 0}, // Table 7 + { hufftable: huffmanTable.subarray(174, (174 + 71)), linbits: 0}, // Table 8 + { hufftable: huffmanTable.subarray(245, (245 + 71)), linbits: 0}, // Table 9 + { hufftable: huffmanTable.subarray(316, (316 + 127)), linbits: 0}, // Table 10 + { hufftable: huffmanTable.subarray(443, (443 + 127)), linbits: 0}, // Table 11 + { hufftable: huffmanTable.subarray(570, (570 + 127)), linbits: 0}, // Table 12 + { hufftable: huffmanTable.subarray(697, (697 + 511)), linbits: 0}, // Table 13 + { hufftable: null, linbits: 0}, // Table 14 + { hufftable: huffmanTable.subarray(1208, (1208 + 511)), linbits: 0}, // Table 15 + { hufftable: huffmanTable.subarray(1719, (1719 + 511)), linbits: 1}, // Table 16 + { hufftable: huffmanTable.subarray(1719, (1719 + 511)), linbits: 2}, // Table 17 + { hufftable: huffmanTable.subarray(1719, (1719 + 511)), linbits: 3}, // Table 18 + { hufftable: huffmanTable.subarray(1719, (1719 + 511)), linbits: 4}, // Table 19 + { hufftable: huffmanTable.subarray(1719, (1719 + 511)), linbits: 6}, // Table 20 + { hufftable: huffmanTable.subarray(1719, (1719 + 511)), linbits: 8}, // Table 21 + { hufftable: huffmanTable.subarray(1719, (1719 + 511)), linbits: 10},// Table 22 + { hufftable: huffmanTable.subarray(1719, (1719 + 511)), linbits: 13},// Table 23 + { hufftable: huffmanTable.subarray(2230, (2230 + 512)), linbits: 4}, // Table 24 + { hufftable: huffmanTable.subarray(2230, (2230 + 512)), linbits: 5}, // Table 25 + { hufftable: huffmanTable.subarray(2230, (2230 + 512)), linbits: 6}, // Table 26 + { hufftable: huffmanTable.subarray(2230, (2230 + 512)), linbits: 7}, // Table 27 + { hufftable: huffmanTable.subarray(2230, (2230 + 512)), linbits: 8}, // Table 28 + { hufftable: huffmanTable.subarray(2230, (2230 + 512)), linbits: 9}, // Table 29 + { hufftable: huffmanTable.subarray(2230, (2230 + 512)), linbits: 11},// Table 30 + { hufftable: huffmanTable.subarray(2230, (2230 + 512)), linbits: 13},// Table 31 + { hufftable: huffmanTable.subarray(2742, (2742 + 31)), linbits: 0}, // Table 32 + { hufftable: huffmanTable.subarray(2773, (2773 + 31)), linbits: 0}, // Table 33 +]; + +// m -> bits +function decode(m, tableNum) { + var x =0, y = 0 ,v = 0, w = 0; + var point = 0; + var error = 1; + var bitsleft = 32; + var hufftable = huffmanMain[tableNum].hufftable; + var linbits = huffmanMain[tableNum].linbits; + if (null === hufftable) { + return { + x: 0, + y: 0, + v: 0, + w: 0, + err: null + }; + } + while(true) { // Start reading the Huffman code word,bit by bit + // Check if we've matched a code word + if ((hufftable[point] & 0xff00) >>> 0 === 0) { + error = 0; + x = (((hufftable[point] >>> 4) >>> 0) & 0xf) >>> 0; + y = (hufftable[point] & 0xf) >>> 0; + break; + } + if (m.Bit() !== 0) { // Go right in tree + while((hufftable[point] & 0xff) >>> 0 >= 250) { + point += ((hufftable[point] & 0xff) >>> 0); + } + point += ((hufftable[point] & 0xff) >>> 0); + } else { // Go left in tree + while(((hufftable[point] >>> 8) >>> 0) >= 250) { + point += (hufftable[point] >>> 8) >>> 0; + } + point += (hufftable[point] >>> 8) >>> 0; + } + bitsleft--; + if ((bitsleft <= 0) || (point >= hufftable.length)) { + break + } + } + if (error !== 0) { // Check for error. + return { + x: 0, + y: 0, + v: 0, + w: 0, + err: "mp3: illegal Huff code in data. bleft = " + bitsleft + ", point = " + point +". tab = " + tableNum + "." + }; + } + if (tableNum > 31) { // Process sign encodings for quadruples tables. + v = (((y >>> 3) >>> 0) & 1) >>> 0; + w = (((y >>> 2) >>> 0) & 1) >>> 0; + x = (((y >>> 1) >>> 0) & 1) >>> 0; + y = (y & 1) >>> 0; + if ((v !== 0) && (m.Bit() === 1)) { + v = -v; + } + if ((w !== 0) && (m.Bit() === 1)) { + w = -w; + } + if ((x !== 0) && (m.Bit() === 1)) { + x = -x; + } + if ((y !== 0) && (m.Bit() === 1)) { + y = -y; + } + } else { + if ((linbits !== 0) && (x === 15)) { + x += m.Bits(linbits); // Get linbits + } + if ((x !== 0) && (m.Bit() === 1)) { + x = -x; // Get sign bit + } + if ((linbits !== 0) && (y === 15)) { + y += m.Bits(linbits); // Get linbits + } + if ((y !== 0) && (m.Bit() === 1)) { + y = -y; // Get sign bit + } + } + return { + x: x, + y: y, + v: v, + w: w, + err: null + } +} + +exports = { + decode: decode +}; diff --git a/assets/disk0/tvdos/include/js-mp3/imdct.js b/assets/disk0/tvdos/include/js-mp3/imdct.js new file mode 100644 index 0000000..7c70b02 --- /dev/null +++ b/assets/disk0/tvdos/include/js-mp3/imdct.js @@ -0,0 +1,95 @@ +var imdctWinData = [new Float32Array(36), new Float32Array(36), new Float32Array(36), new Float32Array(36)]; + +var cosN12 = []; +for (var i = 0; i < 6; i++) { + cosN12.push(new Float32Array(12)); +} + +var cosN36 = []; +for (var i = 0; i < 18; i++) { + cosN36.push(new Float32Array(36)); +} + +var init = function () { + for (var i = 0; i < 36; i++) { + imdctWinData[0][i] = Math.sin(Math.PI / 36 * (i + 0.5)); + } + for (var i = 0; i < 18; i++) { + imdctWinData[1][i] = Math.sin(Math.PI / 36 * (i + 0.5)); + } + for (var i = 18; i < 24; i++) { + imdctWinData[1][i] = 1.0; + } + for (var i = 24; i < 30; i++) { + imdctWinData[1][i] = Math.sin(Math.PI / 12 * (i + 0.5 - 18.0)); + } + for (var i = 30; i < 36; i++) { + imdctWinData[1][i] = 0.0; + } + for (var i = 0; i < 12; i++) { + imdctWinData[2][i] = Math.sin(Math.PI / 12 * (i + 0.5)); + } + for (var i = 12; i < 36; i++) { + imdctWinData[2][i] = 0.0; + } + for (var i = 0; i < 6; i++) { + imdctWinData[3][i] = 0.0; + } + for (var i = 6; i < 12; i++) { + imdctWinData[3][i] = Math.sin(Math.PI / 12 * (i + 0.5 - 6.0)); + } + for (var i = 12; i < 18; i++) { + imdctWinData[3][i] = 1.0; + } + for (var i = 18; i < 36; i++) { + imdctWinData[3][i] = Math.sin(Math.PI / 36 * (i + 0.5)); + } + + const cosN12_N = 12 + for (var i = 0; i < 6; i++) { + for (var j = 0; j < 12; j++) { + cosN12[i][j] = Math.cos(Math.PI / (2 * cosN12_N) * (2*j + 1 + cosN12_N/2) * (2*i + 1)); + } + } + + const cosN36_N = 36; + for (var i = 0; i < 18; i++) { + for (var j = 0; j < 36; j++) { + cosN36[i][j] = Math.cos(Math.PI / (2 * cosN36_N) * (2*j + 1 + cosN36_N/2) * (2*i + 1)); + } + } +}; + +init(); + +var Imdct = { + Win: function (inData, blockType) { + var out = new Float32Array(36); + if (blockType === 2) { + var iwd = imdctWinData[blockType]; + const N = 12; + for (var i = 0; i < 3; i++) { + for (var p = 0; p < N; p++) { + var sum = 0.0; + for (var m = 0; m < N/2; m++) { + sum += inData[i+3*m] * cosN12[m][p]; + } + out[6*i+p+6] += sum * iwd[p]; + } + } + return out; + } + const N = 36; + var iwd = imdctWinData[blockType]; + for (var p = 0; p < N; p++) { + var sum = 0.0; + for (var m = 0; m < N/2; m++) { + sum += inData[m] * cosN36[m][p]; + } + out[p] = sum * iwd[p]; + } + return out; + } +}; + +exports = Imdct; diff --git a/assets/disk0/tvdos/include/js-mp3/maindata.js b/assets/disk0/tvdos/include/js-mp3/maindata.js new file mode 100644 index 0000000..6cd983d --- /dev/null +++ b/assets/disk0/tvdos/include/js-mp3/maindata.js @@ -0,0 +1,314 @@ +var util = require('A:/tvdos/include/js-mp3/util.js'); +var consts = require('A:/tvdos/include/js-mp3/consts.js'); +var huffman = require('A:/tvdos/include/js-mp3/huffman.js'); +var bits = require('A:/tvdos/include/js-mp3/bits.js'); + +var scalefacSizes = [ + [0, 0], [0, 1], [0, 2], [0, 3], [3, 0], [1, 1], [1, 2], [1, 3], + [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3], [4, 2], [4, 3] +]; + +var MainData = { + createNew: function () { + // A MainData is MPEG1 Layer 3 Main Data. + var mainData = { + }; + + util.init3dArray(mainData, 'ScalefacL', 2, 2, 22); // 0-4 bits + util.init4dArray(mainData, 'ScalefacS', 2, 2, 13, 3); // 0-4 bits + util.init3dArray(mainData, 'Is', 2, 2, 576); // Huffman coded freq. lines + + return mainData; + }, + + read: function (source, prev, fh, si) { + var nch = fh.numberOfChannels(); + // Calculate header audio data size + var framesize = fh.frameSize(); + if (framesize > 2000) { + return { + v: null, + bits: null, + err: "mp3: framesize = " + framesize + } + } + // Sideinfo is 17 bytes for one channel and 32 bytes for two + var sideinfo_size = 32; + if (nch === 1) { + sideinfo_size = 17; + } + // Main data size is the rest of the frame,including ancillary data + var main_data_size = framesize - sideinfo_size - 4; // sync+header + // CRC is 2 bytes + if (fh.protectionBit() === 0) { + main_data_size -= 2; + } + // Assemble main data buffer with data from this frame and the previous + // two frames. main_data_begin indicates how many bytes from previous + // frames that should be used. This buffer is later accessed by the + // Bits function in the same way as the side info is. + var result = read(source, prev, main_data_size, si.MainDataBegin); // read bits for maindata + if (result.err) { + return { + v: null, + bits: null, + err: result.err + } + } + + var b = result.b; + var md = MainData.createNew(); + for (var gr = 0; gr < 2; gr++) { + for (var ch = 0; ch < nch; ch++) { + var part_2_start = b.BitPos(); + // Number of bits in the bitstream for the bands + var slen1 = scalefacSizes[si.ScalefacCompress[gr][ch]][0]; + var slen2 = scalefacSizes[si.ScalefacCompress[gr][ch]][1]; + if (si.WinSwitchFlag[gr][ch] === 1 && si.BlockType[gr][ch] === 2) { + if (si.MixedBlockFlag[gr][ch] !== 0) { + for (var sfb = 0; sfb < 8; sfb++) { + md.ScalefacL[gr][ch][sfb] = b.Bits(slen1) + } + for (var sfb = 3; sfb < 12; sfb++) { + //slen1 for band 3-5,slen2 for 6-11 + var nbits = slen2; + if (sfb < 6) { + nbits = slen1; + } + for (var win = 0; win < 3; win++) { + md.ScalefacS[gr][ch][sfb][win] = b.Bits(nbits); + } + } + } else { + for (var sfb = 0; sfb < 12; sfb++) { + //slen1 for band 3-5,slen2 for 6-11 + var nbits = slen2; + if (sfb < 6) { + nbits = slen1; + } + for (var win = 0; win < 3; win++) { + md.ScalefacS[gr][ch][sfb][win] = b.Bits(nbits); + } + } + } + } else { + // Scale factor bands 0-5 + if (si.Scfsi[ch][0] === 0 || gr === 0) { + for (var sfb = 0; sfb < 6; sfb++) { + md.ScalefacL[gr][ch][sfb] = b.Bits(slen1); + } + } else if (si.Scfsi[ch][0] === 1 && gr === 1) { + // Copy scalefactors from granule 0 to granule 1 + // TODO: This is not listed on the spec. + for (var sfb = 0; sfb < 6; sfb++) { + md.ScalefacL[1][ch][sfb] = md.ScalefacL[0][ch][sfb]; + } + } + // Scale factor bands 6-10 + if (si.Scfsi[ch][1] === 0 || gr === 0) { + for (var sfb = 6; sfb < 11; sfb++) { + md.ScalefacL[gr][ch][sfb] = b.Bits(slen1); + } + } else if (si.Scfsi[ch][1] === 1 && gr === 1) { + // Copy scalefactors from granule 0 to granule 1 + for (var sfb = 6; sfb < 11; sfb++) { + md.ScalefacL[1][ch][sfb] = md.ScalefacL[0][ch][sfb]; + } + } + // Scale factor bands 11-15 + if (si.Scfsi[ch][2] === 0 || gr === 0) { + for (var sfb = 11; sfb < 16; sfb++) { + md.ScalefacL[gr][ch][sfb] = b.Bits(slen2); + } + } else if (si.Scfsi[ch][2] === 1 && gr === 1) { + // Copy scalefactors from granule 0 to granule 1 + for (var sfb = 11; sfb < 16; sfb++) { + md.ScalefacL[1][ch][sfb] = md.ScalefacL[0][ch][sfb]; + } + } + // Scale factor bands 16-20 + if (si.Scfsi[ch][3] === 0 || gr === 0) { + for (var sfb = 16; sfb < 21; sfb++) { + md.ScalefacL[gr][ch][sfb] = b.Bits(slen2); + } + } else if (si.Scfsi[ch][3] === 1 && gr === 1) { + // Copy scalefactors from granule 0 to granule 1 + for (var sfb = 16; sfb < 21; sfb++) { + md.ScalefacL[1][ch][sfb] = md.ScalefacL[0][ch][sfb]; + } + } + } + var err = readHuffman(b, fh, si, md, part_2_start, gr, ch); + if (err) { + return { + v: null, + bits: null, + err: err + } + } + } + } + return { + v: md, + bits: b, + err: null + } + } +}; + +var read = function (source, prev, size, offset) { + if (size > 1500) { + return { + b: null, + err: "mp3: size = " + size + } + } + // Check that there's data available from previous frames if needed + if (prev !== null && offset > prev.LenInBytes()) { + // No, there is not, so we skip decoding this frame, but we have to + // read the main_data bits from the bitstream in case they are needed + // for decoding the next frame. + var buf = new Uint8Array(source, 0, size); + if (buf.byteLength < size) { + return { + b: null, + err: "maindata.Read (1)" + } + } + // TODO: Define a special error and enable to continue the next frame. + return { + m: bits.append(prev, buf), + err: null + }; + } + // Copy data from previous frames + var vec; + if (prev !== null) { + vec = prev.Tail(offset); + } + // Read the main_data from file + var result = source.readFull(size); + if (result.err) { + return { + err: result.err + } + } + var buf = result.buf; + // var buf = new Uint8Array(source, 0, size); + if (buf.byteLength < size) { + return { + b: null, + err: "maindata.Read (2)" + } + } + return { + b: bits.createNew(util.concatBuffers(vec, new Uint8Array(buf.slice()).buffer)), + err: null + } +}; + +var readHuffman = function (m, header, sideInfo, mainData, part_2_start, gr, ch) { + // Check that there is any data to decode. If not, zero the array. + if (sideInfo.Part2_3Length[gr][ch] === 0) { + for (var i = 0; i < consts.SamplesPerGr; i++) { + mainData.Is[gr][ch][i] = 0.0; + } + return null; + } + + // Calculate bit_pos_end which is the index of the last bit for this part. + var bit_pos_end = part_2_start + sideInfo.Part2_3Length[gr][ch] - 1; + // Determine region boundaries + var region_1_start = 0; + var region_2_start = 0; + if ((sideInfo.WinSwitchFlag[gr][ch] === 1) && (sideInfo.BlockType[gr][ch] === 2)) { + region_1_start = 36; // sfb[9/3]*3=36 + region_2_start = consts.SamplesPerGr; // No Region2 for short block case. + } else { + var sfreq = header.samplingFrequency().value; + var l = consts.SfBandIndicesSet[sfreq].L; + var i = sideInfo.Region0Count[gr][ch] + 1; + if (i < 0 || util.len(l) <= i) { + // TODO: Better error messages (#3) + return "mp3: readHuffman failed: invalid index i: " + i; + } + region_1_start = l[i]; + var j = sideInfo.Region0Count[gr][ch] + sideInfo.Region1Count[gr][ch] + 2; + if (j < 0 || util.len(l) <= j) { + // TODO: Better error messages (#3) + return "mp3: readHuffman failed: invalid index j: " + j; + } + region_2_start = l[j]; + } + // Read big_values using tables according to region_x_start + for (var is_pos = 0; is_pos < sideInfo.BigValues[gr][ch]*2; is_pos++) { + // #22 + if (is_pos >= util.len(mainData.Is[gr][ch])) { + return "mp3: is_pos was too big: " + is_pos; + } + var table_num = 0; + if (is_pos < region_1_start) { + table_num = sideInfo.TableSelect[gr][ch][0]; + } else if (is_pos < region_2_start) { + table_num = sideInfo.TableSelect[gr][ch][1]; + } else { + table_num = sideInfo.TableSelect[gr][ch][2]; + } + // Get next Huffman coded words + var result = huffman.decode(m, table_num); + if (result.err) { + return err; + } + // In the big_values area there are two freq lines per Huffman word + mainData.Is[gr][ch][is_pos] = result.x; + is_pos++; + mainData.Is[gr][ch][is_pos] = result.y; + } + // Read small values until is_pos = 576 or we run out of huffman data + // TODO: Is this comment wrong? + var table_num = sideInfo.Count1TableSelect[gr][ch] + 32; + var is_pos = sideInfo.BigValues[gr][ch] * 2; + for (;is_pos <= 572 && m.BitPos() <= bit_pos_end;) { + // Get next Huffman coded words + var result = huffman.decode(m, table_num); + if (result.err) { + return err; + } + mainData.Is[gr][ch][is_pos] = result.v; + is_pos++; + if (is_pos >= consts.SamplesPerGr) { + break; + } + mainData.Is[gr][ch][is_pos] = result.w; + is_pos++; + if (is_pos >= consts.SamplesPerGr) { + break; + } + mainData.Is[gr][ch][is_pos] = result.x; + is_pos++; + if (is_pos >= consts.SamplesPerGr) { + break; + } + mainData.Is[gr][ch][is_pos] = result.y; + is_pos++; + } + // Check that we didn't read past the end of this section + if (m.BitPos() > (bit_pos_end + 1)) { + // Remove last words read + is_pos -= 4; + } + + // Setup count1 which is the index of the first sample in the rzero reg. + sideInfo.Count1[gr][ch] = is_pos; + + // Zero out the last part if necessary + for (;is_pos < consts.SamplesPerGr;) { + mainData.Is[gr][ch][is_pos] = 0.0; + is_pos++; + } + // Set the bitpos to point to the next part to read + m.SetPos(bit_pos_end + 1); + return null; +}; + +exports = MainData; diff --git a/assets/disk0/tvdos/include/js-mp3/sideinfo.js b/assets/disk0/tvdos/include/js-mp3/sideinfo.js new file mode 100644 index 0000000..e2d1404 --- /dev/null +++ b/assets/disk0/tvdos/include/js-mp3/sideinfo.js @@ -0,0 +1,157 @@ +var Bits = require('A:/tvdos/include/js-mp3/bits.js'); +var consts = require('A:/tvdos/include/js-mp3/consts.js'); +var util = require('A:/tvdos/include/js-mp3/util.js'); + +var Sideinfo = { + createNew: function () { + // A SideInfo is MPEG1 Layer 3 Side Information. + // [2][2] means [gr][ch]. + // MainDataBegin int // 9 bits + // PrivateBits int // 3 bits in mono, 5 in stereo + // Scfsi [2][4]int // 1 bit + // Part2_3Length [2][2]int // 12 bits + // BigValues [2][2]int // 9 bits + // GlobalGain [2][2]int // 8 bits + // ScalefacCompress [2][2]int // 4 bits + // WinSwitchFlag [2][2]int // 1 bit + // + // BlockType [2][2]int // 2 bits + // MixedBlockFlag [2][2]int // 1 bit + // TableSelect [2][2][3]int // 5 bits + // SubblockGain [2][2][3]int // 3 bits + // + // Region0Count [2][2]int // 4 bits + // Region1Count [2][2]int // 3 bits + // + // Preflag [2][2]int // 1 bit + // ScalefacScale [2][2]int // 1 bit + // Count1TableSelect [2][2]int // 1 bit + // Count1 [2][2]int // Not in file, calc by huffman decoder + var sideinfo = { + }; + util.init2dArray(sideinfo, 'Scfsi', 2, 4); + util.init2dArray(sideinfo, 'Part2_3Length', 2, 2); + util.init2dArray(sideinfo, 'BigValues', 2, 2); + util.init2dArray(sideinfo, 'GlobalGain', 2, 2); + util.init2dArray(sideinfo, 'ScalefacCompress', 2, 2); + util.init2dArray(sideinfo, 'WinSwitchFlag', 2, 2); + + util.init2dArray(sideinfo, 'BlockType', 2, 2); + util.init2dArray(sideinfo, 'MixedBlockFlag', 2, 2); + util.init3dArray(sideinfo, 'TableSelect', 2, 2, 3); + util.init3dArray(sideinfo, 'SubblockGain', 2, 2, 3); + + util.init2dArray(sideinfo, 'Region0Count', 2, 2); + util.init2dArray(sideinfo, 'Region1Count', 2, 2); + + util.init2dArray(sideinfo, 'Preflag', 2, 2); + util.init2dArray(sideinfo, 'ScalefacScale', 2, 2); + util.init2dArray(sideinfo, 'Count1TableSelect', 2, 2); + util.init2dArray(sideinfo, 'Count1', 2, 2); + + return sideinfo; + }, + + read: function (source, fheader, pos) { + var nch = fheader.numberOfChannels(); + // Calculate header audio data size + var framesize = fheader.frameSize(); + if (framesize > 2000) { + return { + v: null, + err: "mp3: framesize = " + framesize + } + } + // Sideinfo is 17 bytes for one channel and 32 bytes for two + var sideinfo_size = 32; + if (nch === 1) { + sideinfo_size = 17; + } + // Main data size is the rest of the frame,including ancillary data + var main_data_size = framesize - sideinfo_size - 4; // sync+header + // CRC is 2 bytes + if (fheader.protectionBit() === 0) { + main_data_size -= 2; + } + // Read sideinfo from bitstream into buffer used by Bits() + var result = source.readFull(sideinfo_size); + if (result.err) { + return { + err: result.err + } + } + var buf = result.buf; + // var buf = new Uint8Array(source.buf, pos, sideinfo_size); + if (buf.byteLength < sideinfo_size) { + return { + v: null, + pos: pos, + err: "mp3: couldn't read sideinfo " + sideinfo_size + " bytes" + } + } + var s = Bits.createNew(new Uint8Array(buf.slice()).buffer); + + // Parse audio data + // Pointer to where we should start reading main data + var si = Sideinfo.createNew(); + si.MainDataBegin = s.Bits(9); + // Get private bits. Not used for anything. + if (fheader.mode() === consts.ModeSingleChannel) { + si.PrivateBits = s.Bits(5); + } else { + si.PrivateBits = s.Bits(3); + } + // Get scale factor selection information + for (var ch = 0; ch < nch; ch++) { + for (var scfsi_band = 0; scfsi_band < 4; scfsi_band++) { + si.Scfsi[ch][scfsi_band] = s.Bits(1); + } + } + // Get the rest of the side information + for (var gr = 0; gr < 2; gr++) { + for (var ch = 0; ch < nch; ch++) { + si.Part2_3Length[gr][ch] = s.Bits(12); + si.BigValues[gr][ch] = s.Bits(9); + si.GlobalGain[gr][ch] = s.Bits(8); + si.ScalefacCompress[gr][ch] = s.Bits(4); + si.WinSwitchFlag[gr][ch] = s.Bits(1); + if (si.WinSwitchFlag[gr][ch] === 1) { + si.BlockType[gr][ch] = s.Bits(2); + si.MixedBlockFlag[gr][ch] = s.Bits(1); + for (var region = 0; region < 2; region++) { + si.TableSelect[gr][ch][region] = s.Bits(5); + } + for (var window = 0; window < 3; window++) { + si.SubblockGain[gr][ch][window] = s.Bits(3); + } + + // TODO: This is not listed on the spec. Is this correct?? + if (si.BlockType[gr][ch] === 2 && si.MixedBlockFlag[gr][ch] === 0) { + si.Region0Count[gr][ch] = 8; // Implicit + } else { + si.Region0Count[gr][ch] = 7; // Implicit + } + // The standard is wrong on this!!! + // Implicit + si.Region1Count[gr][ch] = 20 - si.Region0Count[gr][ch]; + } else { + for (var region = 0; region < 3; region++) { + si.TableSelect[gr][ch][region] = s.Bits(5); + } + si.Region0Count[gr][ch] = s.Bits(4); + si.Region1Count[gr][ch] = s.Bits(3); + si.BlockType[gr][ch] = 0; // Implicit + } + si.Preflag[gr][ch] = s.Bits(1); + si.ScalefacScale[gr][ch] = s.Bits(1); + si.Count1TableSelect[gr][ch] = s.Bits(1); + } + } + return { + v: si, + err: null + } + } +}; + +exports = Sideinfo; diff --git a/assets/disk0/tvdos/include/js-mp3/util.js b/assets/disk0/tvdos/include/js-mp3/util.js new file mode 100644 index 0000000..ecfda7d --- /dev/null +++ b/assets/disk0/tvdos/include/js-mp3/util.js @@ -0,0 +1,108 @@ +function init2dArray(root, prop, first, second) { + root[prop] = []; + for (var i = 0; i < first; i++) { + root[prop].push([]); + } + + for(var i = 0; i < root[prop].length; i++) { + for (var j = 0; j < second; j++) { + root[prop][i].push(0); + } + } +} + +function init3dArray(root, prop, first, second, third) { + root[prop] = []; + for (var i = 0; i < first; i++) { + root[prop].push([]); + } + + for(var i = 0; i < root[prop].length; i++) { + for (var j = 0; j < second; j++) { + root[prop][i].push([]) + } + + for (var x = 0; x < root[prop][i].length; x++) { + for (var y = 0; y < third; y++) { + root[prop][i][x].push(0); + } + } + } +} + +function init4dArray(root, prop, first, second, third, fourth) { + root[prop] = []; + for (var i = 0; i < first; i++) { + root[prop].push([]); + } + + for(var i = 0; i < root[prop].length; i++) { + for (var j = 0; j < second; j++) { + root[prop][i].push([]) + } + + for (var x = 0; x < root[prop][i].length; x++) { + for (var y = 0; y < third; y++) { + var a = []; + for (var z = 0; z < fourth; z++) { + a.push(0); + } + root[prop][i][x].push(a); + } + } + } +} + +function concatTypedArrays(a, b) { // a, b TypedArray of same type + var c = new (a.constructor)(a.length + b.length); + c.set(a, 0); + c.set(b, a.length); + return c; +} + +function concatBuffers(a, b) { + return concatTypedArrays( + new Uint8Array((!!a ? a.buffer : new ArrayBuffer(0)) || a), + new Uint8Array((!!b ? b.buffer : new ArrayBuffer(0)) || b) + ).buffer; +} + +function concatBytes(ui8a, byte) { + var b = new Uint8Array(1); + b[0] = byte; + return concatTypedArrays(ui8a, b); +} + +function len(v) { + if (typeof(v) === 'object') { + return v.length; + } + return 0; +} + +exports = { + init2dArray: init2dArray, + init3dArray: init3dArray, + init4dArray: init4dArray, + concatTypedArrays: concatTypedArrays, + concatBuffers: concatBuffers, + concatBytes: concatBytes, + len: len, + + string: { + bin: function (v) { + return parseInt(v); + } + }, + + number: { + bin: function (v) { + var sign = (v < 0 ? "-" : ""); + var result = Math.abs(v).toString(2); + while(result.length < 32) { + result = "0" + result; + } + return sign + result; + } + } +}; diff --git a/assets/disk0/tvdos/include/mp3dec.js b/assets/disk0/tvdos/include/mp3dec.js new file mode 100644 index 0000000..9056bf5 --- /dev/null +++ b/assets/disk0/tvdos/include/mp3dec.js @@ -0,0 +1,282 @@ +/* +js-mp3 +https://github.com/soundbus-technologies/js-mp3 + +Copyright (c) 2018 SoundBus Technologies CO., LTD. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + + + +var Frame = require('A:/tvdos/include/js-mp3/frame.js'); +var util = require('A:/tvdos/include/js-mp3/util.js'); +var consts = require('A:/tvdos/include/js-mp3/consts.js'); +var Frameheader = require('A:/tvdos/include/js-mp3/frameheader.js'); + +const invalidLength = -1; + +var Mp3 = { + // Create new source object with specified ArrayBuffer + newSource: function(buf) { + + var source = { + buf: buf, + pos: 0 + }; + + /** + * Seek the buffer position + * + * @param position + * @param whence + */ + source.seek = function (position) { + if (position < 0 || position > source.buf.byteLength) { + return { + err: "position not correct" + } + } + source.pos = position; + return { + pos: source.pos + }; + }; + + source.readFull = function (length) { + + try { + if (length < 0) throw Error("Source.pos less than 0: "+source.pos) + + var l = Math.min(source.buf.byteLength - source.pos, length); + + if (l < 0) { + serial.println("l < 0: "+l) + throw Error("l < 0: "+l) + } + + var bbuf = new Uint8Array(source.buf, source.pos, l); + + source.pos += bbuf.byteLength; + + if (source.pos < 0) { + throw Error("pos < 0: "+source.pos) + } + + return { + buf: bbuf, + err: null + }; + } catch (e) { + return { + buf: null, + err: e.toString() + } + } + }; + + source.getPos = function () { + if (source.pos > 3) { + return source.pos - 3; // skip tags + } + return source.pos; + }; + + source.skipTags = function () { + var result = source.readFull(3); + if (result.err) { + return { + err: result.err + } + } + var buf = result.buf; + + // decode UTF-8 + var t = String.fromCharCode.apply(null, buf); + switch (t) { + case "TAG": + result = source.readFull(125); + if (result.err) { + return { + err: result.err + } + } + buf = result.buf; + break; + case 'ID3': + // Skip version (2 bytes) and flag (1 byte) + result = source.readFull(3); + if (result.err) { + return { + err: result.err + } + } + + result = source.readFull(4); + if (result.err) { + return { + err: result.err + } + } + buf = result.buf; + if (buf.byteLength !== 4) { + return { + err: "data not enough." + }; + } + var size = (((buf[0] >>> 0) << 21) >>> 0) | (((buf[1] >>> 0) << 14) >>> 0) | (((buf[2] >>> 0) << 7) >>> 0) | (buf[3] >>> 0); + result = source.readFull(size); + if (result.err) { + return { + err: result.err + } + } + buf = result.buf; + break; + default: + source.unread(buf); +// source.pos -= 3; + break; + } + return {}; + }; + + source.unread = function (buf) { + source.pos -= buf.byteLength + }; + + source.rewind = function() { + source.pos = 0; + }; + + return source; + }, + + newDecoder: function (buf) { + var s = Mp3.newSource(buf); + + var decoder = { + source: s, + sampleRate: 0, + frame: null, + frameStarts: [], +// buf: null, + pos: 0, + length: invalidLength + }; + + // ======= Methods of decoder :: start ========= + decoder.readFrame = function () { + var result = Frame.read(decoder.source, decoder.source.pos, decoder.frame); + if (result.err) { + return { + err: result.err + } + } + decoder.frame = result.f; + var pcm_buf = decoder.frame.decode(); +// decoder.buf = util.concatBuffers(decoder.buf, pcm_buf); + return { buf: pcm_buf }; + }; + + decoder.decode = function (callback) { + var result; + while(true) { + result = decoder.readFrame(); + + if (typeof callback == "function") callback(result) + + if (result.err) { + break; + } + } +// return decoder.buf; + }; + + decoder.ensureFrameStartsAndLength = function () { + if (decoder.length !== invalidLength) { + return {} + } + + var pos = decoder.source.pos; + + decoder.source.rewind(); + + var r = decoder.source.skipTags(); + if (r.err) { + return { + err: r.err + } + } + + var l = 0; + while(true) { + var result = Frameheader.read(decoder.source, decoder.source.pos); + if (result.err) { + if (result.err.toString().indexOf("UnexpectedEOF") > -1) { + break; + } + return { + err: result.err + }; + } + decoder.frameStarts.push(result.position); + l += consts.BytesPerFrame; + + result = decoder.source.readFull(result.h.frameSize() - 4); // move to next frame position + if (result.err) { + break; + } + } + decoder.length = l; + + var result = decoder.source.seek(pos); // reset to beginning position + if (result.err) { + return result; + } + + return {}; + }; + // ======= Methods of decoder :: end ========= + + var r = s.skipTags(); + if (r && r.err) { + throw Error(`Error creating new MP3 source: ${r.err}`) + return null; + } + + var result = decoder.readFrame(); + if (result.err) { + throw Error(`Error reading frame: ${result.err}`) + return null; + } + + decoder.sampleRate = decoder.frame.samplingFrequency(); + + result = decoder.ensureFrameStartsAndLength(); + if (result.err) { + throw Error(`Error ensuring Frame starts and length: ${result.err}`) + return null; + } + + return decoder; + } +}; + +exports = Mp3;