mp3player
Version:
A mp3 player,get data by ajax and play by audiocontext or mediasource.it can download and reprocessing while playing
1,604 lines (1,286 loc) • 54.8 kB
JavaScript
import {huff_quad_table,huff_pair_table} from './huffman';
import imdct_s from './imdct_s';
import Mad from './global';
import Bit from './bit';
/*
* MPEG-1 scalefactor band widths
* derived from Table B.8 of ISO/IEC 11172-3
*/
var sfb_48000_long = [
4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10,
12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192
];
var sfb_44100_long = [
4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10,
12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158
];
var sfb_32000_long = [
4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12,
16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26
];
var sfb_48000_short = [
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6,
6, 6, 6, 6, 6, 10, 10, 10, 12, 12, 12, 14, 14,
14, 16, 16, 16, 20, 20, 20, 26, 26, 26, 66, 66, 66
];
var sfb_44100_short = [
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6,
6, 6, 8, 8, 8, 10, 10, 10, 12, 12, 12, 14, 14,
14, 18, 18, 18, 22, 22, 22, 30, 30, 30, 56, 56, 56
];
var sfb_32000_short = [
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6,
6, 6, 8, 8, 8, 12, 12, 12, 16, 16, 16, 20, 20,
20, 26, 26, 26, 34, 34, 34, 42, 42, 42, 12, 12, 12
];
var sfb_48000_mixed = [
/* long */ 4, 4, 4, 4, 4, 4, 6, 6,
/* short */ 4, 4, 4, 6, 6, 6, 6, 6, 6, 10,
10, 10, 12, 12, 12, 14, 14, 14, 16, 16,
16, 20, 20, 20, 26, 26, 26, 66, 66, 66
];
var sfb_44100_mixed = [
/* long */ 4, 4, 4, 4, 4, 4, 6, 6,
/* short */ 4, 4, 4, 6, 6, 6, 8, 8, 8, 10,
10, 10, 12, 12, 12, 14, 14, 14, 18, 18,
18, 22, 22, 22, 30, 30, 30, 56, 56, 56
];
var sfb_32000_mixed = [
/* long */ 4, 4, 4, 4, 4, 4, 6, 6,
/* short */ 4, 4, 4, 6, 6, 6, 8, 8, 8, 12,
12, 12, 16, 16, 16, 20, 20, 20, 26, 26,
26, 34, 34, 34, 42, 42, 42, 12, 12, 12
];
var sfbwidth_table = [
{ l: sfb_48000_long, s: sfb_48000_short, m: sfb_48000_mixed },
{ l: sfb_44100_long, s: sfb_44100_short, m: sfb_44100_mixed },
{ l: sfb_32000_long, s: sfb_32000_short, m: sfb_32000_mixed } /*, // fuck MPEG 2.5
{ l: sfb_24000_long, s: sfb_24000_short, m: sfb_24000_mixed },
{ l: sfb_22050_long, s: sfb_22050_short, m: sfb_22050_mixed },
{ l: sfb_16000_long, s: sfb_16000_short, m: sfb_16000_mixed },
{ l: sfb_12000_long, s: sfb_12000_short, m: sfb_12000_mixed },
{ l: sfb_11025_long, s: sfb_11025_short, m: sfb_11025_mixed },
{ l: sfb_8000_long, s: sfb_8000_short, m: sfb_8000_mixed }*/
];
var pretab /* [22] */ = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0
];
/*
* fractional powers of two
* used for requantization and joint stereo decoding
*
* root_table[3 + x] = 2^(x/4)
*/
var root_table /* 7 */ = [
/* 2^(-3/4) */ 0.59460355750136,
/* 2^(-2/4) */ 0.70710678118655,
/* 2^(-1/4) */ 0.84089641525371,
/* 2^( 0/4) */ 1.00000000000000,
/* 2^(+1/4) */ 1.18920711500272,
/* 2^(+2/4) */ 1.41421356237310,
/* 2^(+3/4) */ 1.68179283050743
];
var cs = [
+0.857492926 , +0.881741997,
+0.949628649 , +0.983314592,
+0.995517816 , +0.999160558,
+0.999899195 , +0.999993155
];
var ca = [
-0.514495755, -0.471731969,
-0.313377454, -0.181913200,
-0.094574193, -0.040965583,
-0.014198569, -0.003699975
];
/*
* windowing coefficients for long blocks
* derived from section 2.4.3.4.10.3 of ISO/IEC 11172-3
*
* window_l[i] = sin((PI / 36) * (i + 1/2))
*/
var window_l /* [36] */ = [
0.043619387, 0.130526192,
0.216439614, 0.300705800,
0.382683432, 0.461748613,
0.537299608, 0.608761429,
0.675590208, 0.737277337,
0.793353340, 0.843391446,
0.887010833, 0.923879533,
0.953716951, 0.976296007,
0.991444861, 0.999048222,
0.999048222, 0.991444861,
0.976296007, 0.953716951,
0.923879533, 0.887010833,
0.843391446, 0.793353340,
0.737277337, 0.675590208,
0.608761429, 0.537299608,
0.461748613, 0.382683432,
0.300705800, 0.216439614,
0.130526192, 0.043619387
];
/*
* windowing coefficients for short blocks
* derived from section 2.4.3.4.10.3 of ISO/IEC 11172-3
*
* window_s[i] = sin((PI / 12) * (i + 1/2))
*/
var window_s /* [12] */ = [
0.130526192, 0.382683432,
0.608761429, 0.793353340,
0.923879533, 0.991444861,
0.991444861, 0.923879533,
0.793353340, 0.608761429,
0.382683432, 0.130526192
];
/*
* coefficients for intensity stereo processing
* derived from section 2.4.3.4.9.3 of ISO/IEC 11172-3
*
* is_ratio[i] = tan(i * (PI / 12))
* is_table[i] = is_ratio[i] / (1 + is_ratio[i])
*/
var is_table /* [7] */ = [
0.000000000,
0.211324865,
0.366025404,
0.500000000,
0.633974596,
0.788675135,
1.000000000
];
/*
* coefficients for LSF intensity stereo processing
* derived from section 2.4.3.2 of ISO/IEC 13818-3
*
* is_lsf_table[0][i] = (1 / sqrt(sqrt(2)))^(i + 1)
* is_lsf_table[1][i] = (1 / sqrt(2)) ^(i + 1)
*/
var is_lsf_table /* [2][15] */ = [
[
0.840896415,
0.707106781,
0.594603558,
0.500000000,
0.420448208,
0.353553391,
0.297301779,
0.250000000,
0.210224104,
0.176776695,
0.148650889,
0.125000000,
0.105112052,
0.088388348,
0.074325445
], [
0.707106781,
0.500000000,
0.353553391,
0.250000000,
0.176776695,
0.125000000,
0.088388348,
0.062500000,
0.044194174,
0.031250000,
0.022097087,
0.015625000,
0.011048543,
0.007812500,
0.005524272
]
];
var CHAR_BIT = 8;
var SideInfo = function() {
this.gr = []; // array of Mad.Granule
this.scfsi = []; // array of ints
};
/*
* scalefactor bit lengths
* derived from section 2.4.2.7 of ISO/IEC 11172-3
*/
var sflen_table = [
{ slen1: 0, slen2: 0 }, { slen1: 0, slen2: 1 }, { slen1: 0, slen2: 2 }, { slen1: 0, slen2: 3 },
{ slen1: 3, slen2: 0 }, { slen1: 1, slen2: 1 }, { slen1: 1, slen2: 2 }, { slen1: 1, slen2: 3 },
{ slen1: 2, slen2: 1 }, { slen1: 2, slen2: 2 }, { slen1: 2, slen2: 3 }, { slen1: 3, slen2: 1 },
{ slen1: 3, slen2: 2 }, { slen1: 3, slen2: 3 }, { slen1: 4, slen2: 2 }, { slen1: 4, slen2: 3 }
];
var Granule = function() {
this.ch = []; // list of Channel
}
var Channel = function() {
this.table_select = []; // list of Numbers (I guess)
this.scalefac = []; // list of integers
this.subblock_gain = [];
}
/* we must take care that sz >= bits and sz < sizeof(long) lest bits == 0 */
var MASK = function (cache, sz, bits) {
// return Mad.bitwiseAnd(Mad.rshift(cache, sz - bits), Mad.lshift(1, bits) - 1);
return (((cache) >> ((sz) - (bits))) & ((1 << (bits)) - 1));
}
var MASK1BIT = function (cache, sz) {
// return Mad.bitwiseAnd(cache, Mad.lshift(1, sz - 1));
return ((cache) & (1 << ((sz) - 1)));
}
/*
* NAME: III_huffdecode()
* DESCRIPTION: decode Huffman code words of one channel of one granule
*/
var III_huffdecode = function(ptr, xr /* Float64Array(576) */, channel, sfbwidth, part2_length) {
var exponents = new Int32Array(new ArrayBuffer(4 * 39));
var expptr = 0;
var bits_left, cachesz;
var xrptr;
var sfbound;
var bitcache;
var sfbwidthptr = 0;
bits_left = channel.part2_3_length - part2_length;
if (bits_left < 0)
return Mad.Error.BADPART3LEN;
III_exponents(channel, sfbwidth, exponents);
var peek = ptr.clone();
ptr.skip(bits_left);
/* align bit reads to byte boundaries */
cachesz = peek.left;
cachesz += ((32 - 1 - 24) + (24 - cachesz)) & ~7;
bitcache = peek.read(cachesz);
//console.log("bitcache peek.read = " + bitcache);
bits_left -= cachesz;
xrptr = 0;
/* big_values */
{
var region = 0, rcount;
// var reqcache = new Float64Array(new ArrayBuffer(8 * 16));
var reqcache = [];
sfbound = xrptr + sfbwidth[sfbwidthptr++];
rcount = channel.region0_count + 1;
var entry = huff_pair_table[channel.table_select[region]];
var table = entry.table;
var linbits = entry.linbits;
var startbits = entry.startbits;
if (typeof(table) == 'undefined')
return Mad.Error.BADHUFFTABLE;
expptr = 0;
var exp = exponents[expptr++];
var reqhits = 0;
var big_values = channel.big_values;
while (big_values-- && cachesz + bits_left > 0) {
var pair;
var clumpsz, value;
var requantized;
//console.log("big_values = " + big_values + ", cachesz = " + cachesz + ", bits_left = " + bits_left);
if (xrptr == sfbound) {
sfbound += sfbwidth[sfbwidthptr++];
/* change table if region boundary */
if (--rcount == 0) {
if (region == 0)
rcount = channel.region1_count + 1;
else
rcount = 0; /* all remaining */
entry = huff_pair_table[channel.table_select[++region]];
table = entry.table;
linbits = entry.linbits;
startbits = entry.startbits;
if (typeof(table) == 'undefined')
return Mad.Error.BADHUFFTABLE;
}
if (exp != exponents[expptr]) {
exp = exponents[expptr];
reqhits = 0;
}
++expptr;
}
if (cachesz < 21) {
var bits = ((32 - 1 - 21) + (21 - cachesz)) & ~7;
bitcache = (bitcache << bits) | peek.read(bits);
cachesz += bits;
bits_left -= bits;
}
/* hcod (0..19) */
clumpsz = startbits;
pair = table[ (((bitcache) >> ((cachesz) - (clumpsz))) & ((1 << (clumpsz)) - 1))];
while (!pair['final']) {
cachesz -= clumpsz;
clumpsz = pair.ptr.bits;
pair = table[pair.ptr.offset + (((bitcache) >> ((cachesz) - (clumpsz))) & ((1 << (clumpsz)) - 1))];
}
cachesz -= pair.value.hlen;
if (linbits) {
/* x (0..14) */
value = pair.value.x;
var x_final = false;
switch (value) {
case 0:
xr[xrptr] = 0;
break;
case 15:
if (cachesz < linbits + 2) {
bitcache = (bitcache << 16) | peek.read(16);
cachesz += 16;
bits_left -= 16;
}
value += (((bitcache) >> ((cachesz) - (linbits))) & ((1 << (linbits)) - 1));
cachesz -= linbits;
requantized = III_requantize(value, exp);
x_final = true; // simulating goto, yay
break;
default:
if (reqhits & (1 << value))
requantized = reqcache[value];
else {
reqhits |= (1 << value);
requantized = reqcache[value] = III_requantize(value, exp);
}
x_final = true;
}
if(x_final) {
xr[xrptr] = ((bitcache) & (1 << ((cachesz--) - 1))) ?
-requantized : requantized;
}
/* y (0..14) */
value = pair.value.y;
var y_final = false;
switch (value) {
case 0:
xr[xrptr + 1] = 0;
break;
case 15:
if (cachesz < linbits + 1) {
bitcache = (bitcache << 16) | peek.read(16);
cachesz += 16;
bits_left -= 16;
}
value += (((bitcache) >> ((cachesz) - (linbits))) & ((1 << (linbits)) - 1));
cachesz -= linbits;
requantized = III_requantize(value, exp);
y_final = true;
break; // simulating goto, yayzor
default:
if (reqhits & (1 << value))
requantized = reqcache[value];
else {
reqhits |= (1 << value);
reqcache[value] = III_requantize(value, exp);
requantized = reqcache[value];
}
y_final = true;
}
if(y_final) {
xr[xrptr + 1] = ((bitcache) & (1 << ((cachesz--) - 1))) ?
-requantized : requantized;
}
} else {
/* x (0..1) */
value = pair.value.x;
if (value == 0) {
xr[xrptr] = 0;
} else {
if (reqhits & (1 << value))
requantized = reqcache[value];
else {
reqhits |= (1 << value);
requantized = reqcache[value] = III_requantize(value, exp);
}
xr[xrptr] = ((bitcache) & (1 << ((cachesz--) - 1))) ?
-requantized : requantized;
}
/* y (0..1) */
value = pair.value.y;
if (value == 0)
xr[xrptr + 1] = 0;
else {
if (reqhits & (1 << value))
requantized = reqcache[value];
else {
reqhits |= (1 << value);
requantized = reqcache[value] = III_requantize(value, exp);
}
xr[xrptr + 1] = ((bitcache) & (1 << ((cachesz--) - 1))) ?
-requantized : requantized;
}
}
xrptr += 2;
//console.log("big_values = " + big_values + ", cachesz = " + cachesz +
// ", bits_left = " + bits_left + ", xrptr = " + xrptr);
}
}
//console.log("bits_left (before big_values overrun) = " + bits_left);
if (cachesz + bits_left < 0)
return Mad.Error.BADHUFFDATA; /* big_values overrun */
/* count1 */
{
var table = huff_quad_table[channel.flags & Mad.count1table_select];
var requantized = III_requantize(1, exp);
while (cachesz + bits_left > 0 && xrptr <= 572) {
/* hcod (1..6) */
if (cachesz < 10) {
bitcache = (bitcache << 16) | peek.read(16);
cachesz += 16;
bits_left -= 16;
}
var quad = table[ (((bitcache) >> ((cachesz) - (4))) & ((1 << (4)) - 1))];
/* quad tables guaranteed to have at most one extra lookup */
if (!quad['final']) {
cachesz -= 4;
quad = table[quad.ptr.offset +
(((bitcache) >> ((cachesz) - (quad.ptr.bits))) & ((1 << (quad.ptr.bits)) - 1))];
}
cachesz -= quad.value.hlen;
if (xrptr == sfbound) {
sfbound += sfbwidth[sfbwidthptr++];
if (exp != exponents[expptr]) {
exp = exponents[expptr];
requantized = III_requantize(1, exp);
}
++expptr;
}
/* v (0..1) */
xr[xrptr] = quad.value.v ?
(((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0;
/* w (0..1) */
xr[xrptr + 1] = quad.value.w ?
(((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0;
xrptr += 2;
if (xrptr == sfbound) {
sfbound += sfbwidth[sfbwidthptr++];
if (exp != exponents[expptr]) {
exp = exponents[expptr];
requantized = III_requantize(1, exp);
}
++expptr;
}
/* x (0..1) */
xr[xrptr] = quad.value.x ?
(((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0;
/* y (0..1) */
xr[xrptr + 1] = quad.value.y ?
(((bitcache) & (1 << ((cachesz--) - 1))) ? -requantized : requantized) : 0;
xrptr += 2;
}
if (cachesz + bits_left < 0) {
//# if 0 && defined(DEBUG)
//console.log("huffman count1 overrun (" + (-(cachesz + bits_left)) + " bits)");
//# endif
/* technically the bitstream is misformatted, but apparently
some encoders are just a bit sloppy with stuffing bits */
xrptr -= 4;
}
}
if (!(-bits_left <= Mad.BUFFER_GUARD * CHAR_BIT)) {
throw new Error("assertion failed: (-bits_left <= Mad.BUFFER_GUARD * CHAR_BIT)");
}
/*
# if 0 && defined(DEBUG)
if (bits_left < 0)
console.log("read " + (-bits_left) + " bits too many");
else if (cachesz + bits_left > 0)
console.log((cachesz + bits_left) + " stuffing bits");
else
console.log("bits_left " + bits_left);
# endif
*/
/* rzero */
while (xrptr < 576) {
xr[xrptr] = 0;
xr[xrptr + 1] = 0;
xrptr += 2;
}
return Mad.Error.NONE;
}
/*
* NAME: III_sideinfo()
* DESCRIPTION: decode frame side information from a bitstream
*
* Since several values are passed by reference to this function, instead
* we're just returning a hash containing:
* {
* ptr (Bit)
* sideinfo (Mad.Sideinfo)
* data_bitlen (Number)
* priv_bitlen (Number)
* }
*/
var III_sideinfo = function (ptr, nch, lsf) {
var si = new SideInfo();
var result = Mad.Error.NONE;
var data_bitlen = 0;
var priv_bitlen = lsf ? ((nch == 1) ? 1 : 2) : ((nch == 1) ? 5 : 3);
si.main_data_begin = ptr.read(lsf ? 8 : 9);
si.private_bits = ptr.read(priv_bitlen);
var ngr = 1;
if (!lsf) {
ngr = 2;
for (var ch = 0; ch < nch; ++ch)
si.scfsi[ch] = ptr.read(4);
}
for (var gr = 0; gr < ngr; ++gr) {
var granule = new Granule();
si.gr[gr] = granule;
for (var ch = 0; ch < nch; ++ch) {
var channel = new Channel();
granule.ch[ch] = channel;
channel.part2_3_length = ptr.read(12);
channel.big_values = ptr.read(9);
channel.global_gain = ptr.read(8);
channel.scalefac_compress = ptr.read(lsf ? 9 : 4);
data_bitlen += channel.part2_3_length;
if (channel.big_values > 288 && result == 0)
result = Mad.Error.BADBIGVALUES;
channel.flags = 0;
/* window_switching_flag */
if (ptr.read(1)) {
channel.block_type = ptr.read(2);
if (channel.block_type == 0 && result == 0)
result = Mad.Error.BADBLOCKTYPE;
if (!lsf && channel.block_type == 2 && si.scfsi[ch] && result == 0)
result = Mad.Error.BADSCFSI;
channel.region0_count = 7;
channel.region1_count = 36;
if (ptr.read(1))
channel.flags |= Mad.mixed_block_flag;
else if (channel.block_type == 2)
channel.region0_count = 8;
for (var i = 0; i < 2; ++i)
channel.table_select[i] = ptr.read(5);
for (var i = 0; i < 3; ++i)
channel.subblock_gain[i] = ptr.read(3);
} else {
channel.block_type = 0;
for (var i = 0; i < 3; ++i)
channel.table_select[i] = ptr.read(5);
channel.region0_count = ptr.read(4);
channel.region1_count = ptr.read(3);
}
/* [preflag,] scalefac_scale, count1table_select */
channel.flags |= ptr.read(lsf ? 2 : 3);
}
}
return {
ptr: ptr,
si: si,
data_bitlen: data_bitlen,
priv_bitlen: priv_bitlen
};
}
/*
* NAME: III_scalefactors()
* DESCRIPTION: decode channel scalefactors of one granule from a bitstream
*/
var III_scalefactors = function (ptr, channel, gr0ch, scfsi) {
var start; /* Bit */
var slen1, slen2, sfbi;
var start = ptr.clone();
var slen1 = sflen_table[channel.scalefac_compress].slen1;
var slen2 = sflen_table[channel.scalefac_compress].slen2;
if (channel.block_type == 2) {
sfbi = 0;
var nsfb = (channel.flags & Mad.mixed_block_flag) ? 8 + 3 * 3 : 6 * 3;
while (nsfb--)
channel.scalefac[sfbi++] = ptr.read(slen1);
nsfb = 6 * 3;
while (nsfb--)
channel.scalefac[sfbi++] = ptr.read(slen2);
nsfb = 1 * 3;
while (nsfb--)
channel.scalefac[sfbi++] = 0;
}
else { /* channel.block_type != 2 */
if (scfsi & 0x8) {
for (var sfbi = 0; sfbi < 6; ++sfbi)
channel.scalefac[sfbi] = gr0ch.scalefac[sfbi];
}
else {
for (var sfbi = 0; sfbi < 6; ++sfbi)
channel.scalefac[sfbi] = ptr.read(slen1);
}
if (scfsi & 0x4) {
for (var sfbi = 6; sfbi < 11; ++sfbi)
channel.scalefac[sfbi] = gr0ch.scalefac[sfbi];
}
else {
for (var sfbi = 6; sfbi < 11; ++sfbi)
channel.scalefac[sfbi] = ptr.read(slen1);
}
if (scfsi & 0x2) {
for (var sfbi = 11; sfbi < 16; ++sfbi)
channel.scalefac[sfbi] = gr0ch.scalefac[sfbi];
}
else {
for (var sfbi = 11; sfbi < 16; ++sfbi)
channel.scalefac[sfbi] = ptr.read(slen2);
}
if (scfsi & 0x1) {
for (var sfbi = 16; sfbi < 21; ++sfbi)
channel.scalefac[sfbi] = gr0ch.scalefac[sfbi];
}
else {
for (var sfbi = 16; sfbi < 21; ++sfbi)
channel.scalefac[sfbi] = ptr.read(slen2);
}
channel.scalefac[21] = 0;
}
return start.length(ptr);
}
var c0 = 2 * Math.cos( 1 * Math.PI / 18);
var c1 = 2 * Math.cos( 3 * Math.PI / 18);
var c2 = 2 * Math.cos( 4 * Math.PI / 18);
var c3 = 2 * Math.cos( 5 * Math.PI / 18);
var c4 = 2 * Math.cos( 7 * Math.PI / 18);
var c5 = 2 * Math.cos( 8 * Math.PI / 18);
var c6 = 2 * Math.cos(16 * Math.PI / 18);
var fastsdct = function (x /* [9] */, y /* [18] */, offset) {
var a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12;
var a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25;
var m0, m1, m2, m3, m4, m5, m6, m7;
a0 = x[3] + x[5];
a1 = x[3] - x[5];
a2 = x[6] + x[2];
a3 = x[6] - x[2];
a4 = x[1] + x[7];
a5 = x[1] - x[7];
a6 = x[8] + x[0];
a7 = x[8] - x[0];
a8 = a0 + a2;
a9 = a0 - a2;
a10 = a0 - a6;
a11 = a2 - a6;
a12 = a8 + a6;
a13 = a1 - a3;
a14 = a13 + a7;
a15 = a3 + a7;
a16 = a1 - a7;
a17 = a1 + a3;
m0 = a17 * -c3;
m1 = a16 * -c0;
m2 = a15 * -c4;
m3 = a14 * -c1;
m4 = a5 * -c1;
m5 = a11 * -c6;
m6 = a10 * -c5;
m7 = a9 * -c2;
a18 = x[4] + a4;
a19 = 2 * x[4] - a4;
a20 = a19 + m5;
a21 = a19 - m5;
a22 = a19 + m6;
a23 = m4 + m2;
a24 = m4 - m2;
a25 = m4 + m1;
/* output to every other slot for convenience */
y[offset + 0] = a18 + a12;
y[offset + 2] = m0 - a25;
y[offset + 4] = m7 - a20;
y[offset + 6] = m3;
y[offset + 8] = a21 - m6;
y[offset + 10] = a24 - m1;
y[offset + 12] = a12 - 2 * a18;
y[offset + 14] = a23 + m0;
y[offset + 16] = a22 + m7;
}
/* sdctII_scale[i] = 2 * cos(PI * (2 * i + 1) / (2 * 18)) */
var sdctII_scale = [];
for(var i = 0; i < 9; ++i) {
sdctII_scale[i] = 2 * Math.cos(Math.PI * (2 * i + 1) / (2 * 18));
}
var sdctII = function (x /* [18] */, X /* [18] */) {
/* divide the 18-point SDCT-II into two 9-point SDCT-IIs */
// var tmp = new Float64Array(new ArrayBuffer(8 * 9));
var tmp = [];
/* even input butterfly */
for (var i = 0; i < 9; ++i) {
tmp[i] = x[i] + x[18 - i - 1];
}
fastsdct(tmp, X, 0);
/* odd input butterfly and scaling */
for (var i = 0; i < 9; ++i) {
tmp[i] = (x[i] - x[18 - i - 1]) * sdctII_scale[i];
}
fastsdct(tmp, X, 1);
/* output accumulation */
for (var i = 3; i < 18; i += 2) {
X[i] -= X[i - 2];
}
}
/* dctIV_scale[i] = 2 * cos(PI * (2 * i + 1) / (4 * 18)) */
var dctIV_scale = [];
for(i = 0; i < 18; i++) {
dctIV_scale[i] = 2 * Math.cos(Math.PI * (2 * i + 1) / (4 * 18));
}
var dctIV = function (y /* [18] */, X /* [18] */) {
// var tmp = new Float64Array(new ArrayBuffer(8 * 18));
var tmp = [];
/* scaling */
for (var i = 0; i < 18; ++i) {
tmp[i] = y[i] * dctIV_scale[i];
}
/* SDCT-II */
sdctII(tmp, X);
/* scale reduction and output accumulation */
X[0] /= 2;
for (var i = 1; i < 18; ++i) {
X[i] = X[i] / 2 - X[i - 1];
}
}
/*
* NAME: imdct36
* DESCRIPTION: perform X[18]->x[36] IMDCT using Szu-Wei Lee's fast algorithm
*/
var imdct36 = function (x /* [18] */, y /* [36] */) {
// var tmp = new Float64Array(new ArrayBuffer(8 * 18));
var tmp = [];
/* DCT-IV */
dctIV(x, tmp);
/* convert 18-point DCT-IV to 36-point IMDCT */
for (var i = 0; i < 9; ++i) {
y[i] = tmp[9 + i];
}
for (var i = 9; i < 27; ++i) {
y[i] = -tmp[36 - (9 + i) - 1];
}
for (var i = 27; i < 36; ++i) {
y[i] = -tmp[i - 27];
}
}
/*
* NAME: III_imdct_s()
* DESCRIPTION: perform IMDCT and windowing for short blocks
*/
var III_imdct_s = function (X /* [18] */, z /* [36] */)
{
var yptr = 0;
var wptr;
var Xptr = 0;
// var imdct_s_y = new Float64Array(new ArrayBuffer(8 * 36));
var y = [];
var hi, lo;
/* IMDCT */
for (var w = 0; w < 3; ++w) {
var s = imdct_s;
var sptr = 0;
for (var i = 0; i < 3; ++i) {
lo = X[Xptr + 0] * s[sptr][0] +
X[Xptr + 1] * s[sptr][1] +
X[Xptr + 2] * s[sptr][2] +
X[Xptr + 3] * s[sptr][3] +
X[Xptr + 4] * s[sptr][4] +
X[Xptr + 5] * s[sptr][5];
y[yptr + i + 0] = lo;
y[yptr + 5 - i] = -y[yptr + i + 0];
++sptr;
lo = X[Xptr + 0] * s[sptr][0] +
X[Xptr + 1] * s[sptr][1] +
X[Xptr + 2] * s[sptr][2] +
X[Xptr + 3] * s[sptr][3] +
X[Xptr + 4] * s[sptr][4] +
X[Xptr + 5] * s[sptr][5];
y[yptr + i + 6] = lo;
y[yptr + 11 - i] = y[yptr + i + 6];
++sptr;
}
yptr += 12;
Xptr += 6;
}
/* windowing, overlapping and concatenation */
yptr = 0;
var wptr = 0;
for (var i = 0; i < 6; ++i) {
z[i + 0] = 0;
z[i + 6] = y[yptr + 0 + 0] * window_s[wptr + 0];
lo = y[yptr + 0 + 6] * window_s[wptr + 6] +
y[yptr + 12 + 0] * window_s[wptr + 0];
z[i + 12] = lo;
lo = y[yptr + 12 + 6] * window_s[wptr + 6] +
y[yptr + 24 + 0] * window_s[wptr + 0];
z[i + 18] = lo;
z[i + 24] = y[yptr + 24 + 6] * window_s[wptr + 6];
z[i + 30] = 0;
++yptr;
++wptr;
}
}
/*
* NAME: III_imdct_l()
* DESCRIPTION: perform IMDCT and windowing for long blocks
*/
Mad.III_imdct_l = function (X /* 18 */, z /* 36 */, block_type) {
/* IMDCT */
imdct36(X, z);
/* windowing */
switch (block_type) {
case 0: /* normal window */
for (var i = 0; i < 36; ++i) z[i] = z[i] * window_l[i];
break;
case 1: /* start block */
for (var i = 0; i < 18; ++i) z[i] = z[i] * window_l[i];
/* (var i = 18; i < 24; ++i) z[i] unchanged */
for (var i = 24; i < 30; ++i) z[i] = z[i] * window_s[i - 18];
for (var i = 30; i < 36; ++i) z[i] = 0;
break;
case 3: /* stop block */
for (var i = 0; i < 6; ++i) z[i] = 0;
for (var i = 6; i < 12; ++i) z[i] = z[i] * window_s[i - 6];
/* (var i = 12; i < 18; ++i) z[i] unchanged */
for (var i = 18; i < 36; ++i) z[i] = z[i] * window_l[i];
break;
}
}
/*
* NAME:III_freqinver()
* DESCRIPTION: perform subband frequency inversion for odd sample lines
*/
var III_freqinver = function (sample /* [18][32] */, sb)
{
for (var i = 1; i < 18; i += 2)
sample[i][sb] = -sample[i][sb];
}
/*
* NAME: III_decode()
* DESCRIPTION: decode frame main_data
*
* result struct:
*/
var III_decode = function (ptr, frame, si, nch) {
var header = frame.header;
var sfreqi;
{
var sfreq = header.samplerate;
if (header.flags & Mad.Flag.MPEG_2_5_EXT)
sfreq *= 2;
/* 48000 => 0, 44100 => 1, 32000 => 2,
24000 => 3, 22050 => 4, 16000 => 5 */
sfreqi = ((sfreq >> 7) & 0x000f) +
((sfreq >> 15) & 0x0001) - 8;
if (header.flags & Mad.Flag.MPEG_2_5_EXT)
sfreqi += 3;
}
/* scalefactors, Huffman decoding, requantization */
var ngr = (header.flags & Mad.Flag.LSF_EXT) ? 1 : 2;
for (var gr = 0; gr < ngr; ++gr) {
var granule = si.gr[gr];
var sfbwidth = [];
/* unsigned char const *sfbwidth[2]; */
var l = 0;
// var xr = [ new Float64Array(new ArrayBuffer(8 * 576)), new Float64Array(new ArrayBuffer(8 * 576)) ];
var xr = [[], []];
var error;
for (var ch = 0; ch < nch; ++ch) {
var channel = granule.ch[ch];
var part2_length;
sfbwidth[ch] = sfbwidth_table[sfreqi].l;
if (channel.block_type == 2) {
sfbwidth[ch] = (channel.flags & Mad.mixed_block_flag) ?
sfbwidth_table[sfreqi].m : sfbwidth_table[sfreqi].s;
}
if (header.flags & Mad.Flag.LSF_EXT) {
part2_length = Mad.III_scalefactors_lsf(ptr, channel,
ch == 0 ? 0 : si.gr[1].ch[1], header.mode_extension);
} else {
part2_length = III_scalefactors(ptr, channel, si.gr[0].ch[ch],
gr == 0 ? 0 : si.scfsi[ch]);
}
error = III_huffdecode(ptr, xr[ch], channel, sfbwidth[ch], part2_length);
if (error)
return error;
}
if (Mad.debug) {
Mad.debug.huffdecode.write(Mad.debug.iteration + "\t");
for (var i = 0; i < 576; i++) {
Mad.debug.huffdecode.write(xr[0][i].toFixed(8) + "\t");
}
Mad.debug.huffdecode.write("\n");
}
/* joint stereo processing */
if ((header.mode == Mad.Mode.JOINT_STEREO) && (header.mode_extension != 0)) {
error = III_stereo(xr, granule, header, sfbwidth[0]);
if (error)
return error;
}
/* reordering, alias reduction, IMDCT, overlap-add, frequency inversion */
for (var ch = 0; ch < nch; ++ch) {
var channel = granule.ch[ch];
var sample = frame.sbsample[ch].slice(18 * gr);
var sb, l = 0, i, sblimit;
// var output = new Float64Array(new ArrayBuffer(8 * 36));
var output = [];
if (channel.block_type == 2) {
III_reorder(xr[ch], channel, sfbwidth[ch]);
/*
* According to ISO/IEC 11172-3, "Alias reduction is not applied for
* granules with block_type == 2 (short block)." However, other
* sources suggest alias reduction should indeed be performed on the
* lower two subbands of mixed blocks. Most other implementations do
* this, so by default we will too.
*/
if (channel.flags & Mad.mixed_block_flag)
III_aliasreduce(xr[ch], 36);
} else {
III_aliasreduce(xr[ch], 576);
}
/* subbands 0-1 */
if (channel.block_type != 2 || (channel.flags & Mad.mixed_block_flag)) {
var block_type = channel.block_type;
if (channel.flags & Mad.mixed_block_flag)
block_type = 0;
/* long blocks */
for (var sb = 0; sb < 2; ++sb, l += 18) {
Mad.III_imdct_l(xr[ch].slice(l, l + 18), output, block_type);
III_overlap(output, frame.overlap[ch][sb], sample, sb);
// var sys = require('sys');
// sys.print("\nblocktype: " + block_type + " sb: " + sb + "\n");
// for (var i = 0; i < 18; i++) {
// sys.print(output[i].toFixed(8) + "\t");
// if (i % 8 == 7) sys.print("\n");
// }
}
} else {
/* short blocks */
for (var sb = 0; sb < 2; ++sb, l += 18) {
III_imdct_s(xr[ch].slice(l, l + 18), output);
III_overlap(output, frame.overlap[ch][sb], sample, sb);
}
}
III_freqinver(sample, 1);
/* (nonzero) subbands 2-31 */
i = 576;
while (i > 36 && xr[ch][i - 1] == 0)
--i;
sblimit = 32 - (((576 - i) / 18) << 0);
if (channel.block_type != 2) {
/* long blocks */
for (var sb = 2; sb < sblimit; ++sb, l += 18) {
Mad.III_imdct_l(xr[ch].slice(l, l + 18), output, channel.block_type);
III_overlap(output, frame.overlap[ch][sb], sample, sb);
if (sb & 1)
III_freqinver(sample, sb);
}
} else {
/* short blocks */
for (var sb = 2; sb < sblimit; ++sb, l += 18) {
III_imdct_s(xr[ch].slice(l, l + 18), output);
III_overlap(output, frame.overlap[ch][sb], sample, sb);
if (sb & 1)
III_freqinver(sample, sb);
}
}
// remaining (zero) subbands
for (var sb = sblimit; sb < 32; ++sb) {
III_overlap_z(frame.overlap[ch][sb], sample, sb);
if (sb & 1)
III_freqinver(sample, sb);
}
if (Mad.debug) {
for (var i = 0; i < 18; i++) {
Mad.debug.sample.write(Mad.debug.iteration * 18 + i + "\t");
for (var j = 0; j < 32; j++) {
Mad.debug.sample.write(sample[i][j].toFixed(8) + "\t");
}
Mad.debug.sample.write("\n");
}
Mad.debug.iteration += 1;
}
}
}
return Mad.Error.NONE;
}
/*
* NAME: layer.III()
* DESCRIPTION: decode a single Layer III frame
*/
var layer_III = function (stream, frame) {
var header = frame.header;
var nch, next_md_begin = 0;
var si_len, data_bitlen, md_len = 0;
var frame_space, frame_used, frame_free;
var /* Mad.Error */ error;
var ptr;
var result = 0;
/* allocate Layer III dynamic structures */
nch = header.nchannels();
si_len = (header.flags & Mad.Flag.LSF_EXT) ?
(nch == 1 ? 9 : 17) : (nch == 1 ? 17 : 32);
/* check frame sanity */
if (stream.next_frame - stream.ptr.nextbyte() < si_len) {
stream.error = Mad.Error.BADFRAMELEN;
stream.md_len = 0;
return -1;
}
/* check CRC word */
if (header.flags & Mad.Flag.PROTECTION) {
header.crc_check = mad_bit_crc(stream.ptr, si_len * CHAR_BIT, header.crc_check);
if (header.crc_check != header.crc_target &&
!(frame.options & Mad.Option.IGNORECRC)) {
stream.error = Mad.Error.BADCRC;
result = -1;
}
}
/* decode frame side information */
var sideinfoResult = III_sideinfo(stream.ptr, nch, header.flags & Mad.Flag.LSF_EXT);
stream.ptr = sideinfoResult.ptr;
var si = sideinfoResult.si;
var data_bitlen = sideinfoResult.data_bitlen;
var priv_bitlen = sideinfoResult.priv_bitlen;
//console.log("We're at " + stream.ptr.offset + ", data_bitlen = " + data_bitlen + ", priv_bitlen = " + priv_bitlen);
if (error && result == 0) {
stream.error = error;
result = -1;
}
header.flags |= priv_bitlen;
header.private_bits |= si.private_bits;
/* find main_data of next frame */
{
var peek = new Bit(stream.stream, stream.next_frame);
header = peek.read(32);
if (Mad.bitwiseAnd(header, 0xffe60000) /* syncword | layer */ == 0xffe20000) {
if (!(Mad.bitwiseAnd(header, 0x00010000))) /* protection_bit */
peek.skip(16); /* crc_check */
next_md_begin = peek.read(Mad.bitwiseAnd(header, 0x00080000) /* ID */ ? 9 : 8);
}
}
/* find main_data of this frame */
frame_space = stream.next_frame - stream.ptr.nextbyte();
//console.log("next_frame = " + stream.next_frame + ", nextbyte = " + stream.ptr.nextbyte() + ", frame_space = " + frame_space);
//console.log("before, next_md_begin = " + next_md_begin);
if (next_md_begin > si.main_data_begin + frame_space)
next_md_begin = 0;
//console.log("so far, md_len = " + md_len + ", si.main_data_begin = " + si.main_data_begin + ", frame_space = " + frame_space + ", next_md_begin = " + next_md_begin);
md_len = si.main_data_begin + frame_space - next_md_begin;
frame_used = 0;
if (si.main_data_begin == 0) {
ptr = stream.ptr;
stream.md_len = 0;
frame_used = md_len;
} else {
//console.log("si.main_data_begin = " + si.main_data_begin + ", stream.md_len = " + stream.md_len);
if (si.main_data_begin > stream.md_len) {
if (result == 0) {
stream.error = Mad.Error.BADDATAPTR;
result = -1;
}
} else {
var old_md_len = stream.md_len;
if (md_len > si.main_data_begin) {
if(!(stream.md_len + md_len - si.main_data_begin <= Mad.BUFFER_MDLEN)) {
throw new Error("Assertion failed: (stream.md_len + md_len - si.main_data_begin <= MAD_BUFFER_MDLEN)");
}
frame_used = md_len - si.main_data_begin;
/* memcpy(dst, dstOffset, src, srcOffset, length) - returns a copy of dst with modified bytes */
stream.main_data = Mad.memcpy(stream.main_data, stream.md_len, stream.ptr.stream, stream.ptr.nextbyte(), frame_used);
/*
// Keeping this here as a handy little reference
memcpy(*stream.main_data + stream.md_len,
mad_bit_nextbyte(&stream.ptr),
frame_used = md_len - si.main_data_begin
);
*/
stream.md_len += frame_used;
}
ptr = new Bit(stream.main_data, old_md_len - si.main_data_begin);
}
}
frame_free = frame_space - frame_used;
/* decode main_data */
if (result == 0) {
error = III_decode(ptr, frame, si, nch);
if (error) {
stream.error = error;
result = -1;
}
/* designate ancillary bits */
stream.anc_ptr = ptr;
stream.anc_bitlen = md_len * CHAR_BIT - data_bitlen;
}
// DEBUG
/*
console.log(
"main_data_begin:" + si.main_data_begin +
", md_len:" + md_len +
", frame_free:" + frame_free +
", data_bitlen:" + data_bitlen +
", anc_bitlen: " + stream.anc_bitlen);
*/
/* preload main_data buffer with up to 511 bytes for next frame(s) */
if (frame_free >= next_md_begin) {
stream.main_data = Mad.memcpy(stream.main_data, 0, stream.stream, stream.next_frame - next_md_begin, next_md_begin);
/*
// Keeping here for reference
memcpy(*stream.main_data, stream.next_frame - next_md_begin, next_md_begin);
*/
stream.md_len = next_md_begin;
} else {
if (md_len < si.main_data_begin) {
var extra = si.main_data_begin - md_len;
if (extra + frame_free > next_md_begin)
extra = next_md_begin - frame_free;
if (extra < stream.md_len) {
stream.main_data = Mad.memcpy(stream.main_data, 0, stream.main_data, stream.md_len - extra, extra);
/*
// Keeping here for reference
memmove(*stream.main_data, *stream.main_data + stream.md_len - extra, extra);
*/
stream.md_len = extra;
}
} else {
stream.md_len = 0;
}
stream.main_data = Mad.memcpy(stream.main_data, stream.md_len, stream.stream, stream.next_frame - frame_free, frame_free);
/*
// Keeping here for reference
memcpy(*stream.main_data + stream.md_len, stream.next_frame - frame_free, frame_free);
*/
stream.md_len += frame_free;
}
return result;
}
var III_exponents = function(channel, sfbwidth, exponents) {
var gain = channel.global_gain - 210;
var scalefac_multiplier = (channel.flags & Mad.scalefac_scale) ? 2 : 1;
if (channel.block_type == 2) {
var sfbi = 0, l = 0;
if (channel.flags & Mad.mixed_block_flag) {
var premask = (channel.flags & Mad.preflag) ? ~0 : 0;
/* long block subbands 0-1 */
while (l < 36) {
exponents[sfbi] = gain - ((channel.scalefac[sfbi] + (pretab[sfbi] & premask)) << scalefac_multiplier);
l += sfbwidth[sfbi++]
}
}
/* this is probably wrong for 8000 Hz short/mixed blocks */
var gain0 = gain - 8 * channel.subblock_gain[0];
var gain1 = gain - 8 * channel.subblock_gain[1];
var gain2 = gain - 8 * channel.subblock_gain[2];
while (l < 576) {
exponents[sfbi + 0] = gain0 - (channel.scalefac[sfbi + 0] << scalefac_multiplier);
exponents[sfbi + 1] = gain1 - (channel.scalefac[sfbi + 1] << scalefac_multiplier);
exponents[sfbi + 2] = gain2 - (channel.scalefac[sfbi + 2] << scalefac_multiplier);
l += 3 * sfbwidth[sfbi];
sfbi += 3;
}
} else { /* channel.block_type != 2 */
if (channel.flags & Mad.preflag) {
for (var sfbi = 0; sfbi < 22; ++sfbi) {
exponents[sfbi] = gain - ((channel.scalefac[sfbi] + pretab[sfbi]) << scalefac_multiplier);
}
} else {
for (var sfbi = 0; sfbi < 22; ++sfbi) {
exponents[sfbi] = gain - (channel.scalefac[sfbi] << scalefac_multiplier);
}
}
}
}
var III_requantize = function(value, exp) {
// usual (x >> 0) tricks to make sure frac and exp stay integers
var frac = (exp % 4) >> 0; /* assumes sign(frac) == sign(exp) */
exp = (exp / 4) >> 0;
var requantized = Math.pow(value, 4.0 / 3.0);
requantized *= Math.pow(2.0, (exp / 4.0));
if(frac) {
requantized *= Math.pow(2.0, (frac / 4.0));
}
if(exp < 0) {
requantized /= Math.pow(2.0, -exp * (3.0 / 4.0));
}
return requantized;
}
var III_aliasreduce = function(xr, lines) {
var xrPointer = 0;
for (xrPointer += 18; xrPointer < lines; xrPointer += 18) {
for (var i = 0; i < 8; ++i) {
var a = xr[xrPointer - i - 1];
var b = xr[xrPointer + i];
var lo = a * cs[i] - b * ca[i];
xr[xrPointer - i - 1] = lo;
lo = b * cs[i] + a * ca[i];
xr[xrPointer + i] = lo
}
}
}
var III_overlap = function (output /* [36] */, overlap /* [18] */, sample /* [18][32] */, sb) {
for (var i = 0; i < 18; ++i) {
sample[i][sb] = output[i + 0] + overlap[i];
overlap[i] = output[i + 18];
}
}
var III_overlap_z = function (overlap /* [18] */, sample /* [18][32] */, sb) {
for (var i = 0; i < 18; ++i) {
sample[i][sb] = overlap[i];
overlap[i] = 0;
}
}
// allocating typed arrays once and for all, outside the function
// var reorder_tmp = new Float64Array(new ArrayBuffer(8 * 32 * 3 * 6));
// var reorder_sbw = new Float64Array(new ArrayBuffer(8 * 3));
// var reorder_sw = new Float64Array(new ArrayBuffer(8 * 3));
var III_reorder = function (xr /* [576] */, channel, sfbwidth /* [39] */) {
var sfbwidthPointer = 0;
var tmp = [];
for (var i = 0; i < 32; i++) {
tmp[i] = [];
for (var j = 0; j < 3; j++) {
tmp[i][j] = [];
for (var k = 0; k < 6; k++) {
tmp[i][j][k] = 0;
}
}
}
var sbw = [];
var sw = [];
/* this is probably wrong for 8000 Hz mixed blocks */
var sb = 0;
if (channel.flags & Mad.mixed_block_flag) {
var sb = 2;
var l = 0;
while (l < 36)
l += sfbwidth[sfbwidthPointer++];
}
for (var w = 0; w < 3; ++w) {
sbw[w] = sb;
sw[w] = 0;
}
var f = sfbwidth[sfbwidthPointer++];
var w = 0;
for (var l = 18 * sb; l < 576; ++l) {
if (f-- == 0) {
f = sfbwidth[sfbwidthPointer++] - 1;
w = (w + 1) % 3;
}
tmp[sbw[w]][w][sw[w]++] = xr[l];
if (sw[w] == 6) {
sw[w] = 0;
++sbw[w];
}
}
var tmp2 = [];
var ptr = 0;
for (var i = 0; i < 32; i++) {
for (var j = 0; j < 3; j++) {
for (var k = 0; k < 6; k++) {
tmp2[ptr++] = tmp[i][j][k];
}
}
}
var len = (576 - 18 * sb);
for (var i = 0; i < len; i++) {
xr[18 * sb + i] = tmp2[sb + i];
}
}
var III_stereo = function(xr /* [2][576] */, granule, header, sfbwidth) {
var modes = [];
var sfbi, l, n, i;
if (granule.ch[0].block_type !=
granule.ch[1].block_type ||
(granule.ch[0].flags & Mad.mixed_block_flag) !=
(granule.ch[1].flags & Mad.mixed_block_flag))
return Mad.Error.BADSTEREO;
for (i = 0; i < 39; ++i)
modes[i] = header.mode_extension;
/* intensity stereo */
if (header.mode_extension & Mad.I_STEREO) {
var right_ch = granule.ch[1];
var right_xr = xr[1];
var is_pos;
header.flags |= Mad.Flag.I_STEREO;
/* first determine which scalefactor bands are to be processed */
if (right_ch.block_type == 2) {
var lower, start, max, bound = [], w;
lower = start = max = bound[0] = bound[1] = bound[2] = 0;
sfbi = l =