Files
tsvm/assets/disk0/tvdos/include/js-mp3/frameheader.js
2023-01-14 16:45:33 +09:00

278 lines
7.9 KiB
JavaScript

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 buf = source.readFull(4)
if (buf.err) {
return {
err: buf.err
}
}
if (buf.length < 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++;
buf = source.readFull(1);
if (buf.length < 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;