mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-08 12:11:51 +09:00
156 lines
6.1 KiB
JavaScript
156 lines
6.1 KiB
JavaScript
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;
|
|
}
|
|
|
|
|
|
// serial.println(`sideinfo readFull(${sideinfo_size})`)
|
|
|
|
// Read sideinfo from bitstream into buffer used by Bits()
|
|
var buf = source.readFull(sideinfo_size);
|
|
// var buf = new Uint8Array(source.buf, pos, sideinfo_size);
|
|
if (buf.length < sideinfo_size) {
|
|
return {
|
|
v: null,
|
|
pos: pos,
|
|
err: "mp3: couldn't read sideinfo " + sideinfo_size + " bytes"
|
|
}
|
|
}
|
|
var s = Bits.createNew(new Uint8Array(buf).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;
|