mp3player
Version:
A mp3 player,get data by ajax and play by audiocontext or mediasource.it can download and reprocessing while playing
371 lines (284 loc) • 11.8 kB
JavaScript
import Mad from './global';
import Bit from './bit';
import layer_III from './layer3';
var bitrate_table /* [5][15] */ = [
/* MPEG-1 */
[ 0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, /* Layer I */
256000, 288000, 320000, 352000, 384000, 416000, 448000 ],
[ 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, /* Layer II */
128000, 160000, 192000, 224000, 256000, 320000, 384000 ],
[ 0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, /* Layer III */
112000, 128000, 160000, 192000, 224000, 256000, 320000 ],
/* MPEG-2 LSF */
[ 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, /* Layer I */
128000, 144000, 160000, 176000, 192000, 224000, 256000 ],
[ 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, /* Layers */
64000, 80000, 96000, 112000, 128000, 144000, 160000 ] /* II & III */
];
var samplerate_table /* [3] */ = [ 44100, 48000, 32000 ];
var decoder_table = [
function() { console.log("Layer I decoding is not implemented!"); },
function() { console.log("Layer II decoding is not implemented!"); },
layer_III
];
var Header = function () {
this.layer = 0; /* audio layer (1, 2, or 3) */
this.mode = 0; /* channel mode (see above) */
this.mode_extension = 0; /* additional mode info */
this.emphasis = 0; /* de-emphasis to use (see above) */
this.bitrate = 0; /* stream bitrate (bps) */
this.samplerate = 0; /* sampling frequency (Hz) */
this.crc_check = 0; /* frame CRC accumulator */
this.crc_target = 0; /* final target CRC checksum */
this.flags = 0; /* flags (see below) */
this.private_bits = 0; /* private bits (see below) */
//this.duration = mad_timer_zero; /* audio playing time of frame */
};
Header.prototype.nchannels = function () {
return this.mode == 0 ? 1 : 2;
}
Header.prototype.nbsamples = function() {
return (this.layer == Mad.Layer.I ? 12 :
((this.layer == Mad.Layer.III && (this.flags & Mad.Flag.LSF_EXT)) ? 18 : 36));
}
/* libmad's decode_header */
Header.actually_decode = function(stream) {
var header = new Header();
header.flags = 0;
header.private_bits = 0;
/* header() */
/* syncword */
stream.ptr.skip(11);
/* MPEG 2.5 indicator (really part of syncword) */
if (stream.ptr.read(1) == 0) {
header.flags |= Mad.Flag.MPEG_2_5_EXT;
}
/* ID */
if (stream.ptr.read(1) == 0) {
header.flags |= Mad.Flag.LSF_EXT;
} else if (header.flags & Mad.Flag.MPEG_2_5_EXT) {
stream.error = Mad.Error.LOSTSYNC;
return null;
}
/* layer */
header.layer = 4 - stream.ptr.read(2);
if (header.layer == 4) {
stream.error = Mad.Error.BADLAYER;
return header;
}
/* protection_bit */
if (stream.ptr.read(1) == 0) {
header.flags |= Mad.Flag.PROTECTION;
// TODO: crc
//header.crc_check = mad_bit_crc(stream.ptr, 16, 0xffff);
stream.ptr.skip(16);
}
/* bitrate_index */
var index = stream.ptr.read(4);
if (index == 15) {
stream.error = Mad.Error.BADBITRATE;
return header;
}
if (header.flags & Mad.Flag.LSF_EXT) {
header.bitrate = bitrate_table[3 + (header.layer >> 1)][index];
} else {
header.bitrate = bitrate_table[header.layer - 1][index];
}
/* sampling_frequency */
index = stream.ptr.read(2);
if (index == 3) {
stream.error = Mad.Error.BADSAMPLERATE;
return header;
}
header.samplerate = samplerate_table[index];
if (header.flags & Mad.Flag.LSF_EXT) {
header.samplerate /= 2;
if (header.flags & Mad.Flag.MPEG_2_5_EXT)
header.samplerate /= 2;
}
/* padding_bit */
if (stream.ptr.read(1))
header.flags |= Mad.Flag.PADDING;
/* private_bit */
if (stream.ptr.read(1))
header.private_bits |= Mad.Private.HEADER;
/* mode */
header.mode = 3 - stream.ptr.read(2);
/* mode_extension */
header.mode_extension = stream.ptr.read(2);
/* copyright */
if (stream.ptr.read(1))
header.flags |= Mad.Flag.COPYRIGHT;
/* original/copy */
if (stream.ptr.read(1))
header.flags |= Mad.Flag.ORIGINAL;
/* emphasis */
header.emphasis = stream.ptr.read(2);
/* error_check() */
/* crc_check */
if (header.flags & Mad.Flag.PROTECTION)
header.crc_target = stream.ptr.read(16);
return header;
}
/* libmad's mad_header_decode */
Header.decode = function(stream) {
var header = null;
// those are actually pointers. javascript powa.
var ptr = stream.next_frame;
var end = stream.bufend;
var pad_slot = 0;
var N = 0;
/* stream skip */
if (stream.skiplen) {
if (!stream.sync)
ptr = stream.this_frame;
if (end - ptr < stream.skiplen) {
stream.skiplen -= end - ptr;
stream.next_frame = end;
stream.error = Mad.Error.BUFLEN;
return null;
}
ptr += stream.skiplen;
stream.skiplen = 0;
stream.sync = 1;
}
// emulating goto in JS, yay! this was a 'sync:' label
var syncing = true;
while(syncing) {
syncing = false;
/* synchronize */
try {
if (stream.sync) {
if (end - ptr < Mad.BUFFER_GUARD) {
stream.next_frame = ptr;
stream.error = Mad.Error.BUFLEN;
return null;
} else if (!(stream.getU8(ptr) == 0xff && (stream.getU8(ptr + 1) & 0xe0) == 0xe0)) {
/* mark point where frame sync word was expected */
stream.this_frame = ptr;
stream.next_frame = ptr + 1;
stream.error = Mad.Error.LOSTSYNC;
return null;
}
} else {
stream.ptr = new Bit(stream.stream, ptr);
if (stream.doSync() == -1) {
if (end - stream.next_frame >= Mad.BUFFER_GUARD)
stream.next_frame = end - Mad.BUFFER_GUARD;
stream.error = Mad.Error.BUFLEN;
return null;
}
ptr = stream.ptr.nextbyte();
}
} catch (e) {
console.log("Synchronization error: " + e);
stream.error = Mad.Error.BUFLEN;
return null;
}
/* begin processing */
stream.this_frame = ptr;
stream.next_frame = ptr + 1; /* possibly bogus sync word */
stream.ptr = new Bit(stream.stream, stream.this_frame);
header = Header.actually_decode(stream);
if(header == null) return null; // well Duh^2
// console.log("============= Decoding layer " + header.layer + " audio mode " +
// header.mode + " with " + header.bitrate +
// " bps and a samplerate of " + header.samplerate);
/* calculate frame duration */
//mad_timer_set(&header.duration, 0, 32 * MAD_NSBSAMPLES(header), header.samplerate);
/* calculate free bit rate */
if (header.bitrate == 0) {
console.log("Uh oh, a free bitrate stream. We're fucked.");
stream.error = Mad.Error.BADDATAPTR; // best guess
return null;
// if ((stream.freerate == 0 || !stream.sync ||
// (header.layer == Mad.Layer.III && stream.freerate > 640000)) &&
// free_bitrate(stream, header) == -1)
// return null;
//
// header.bitrate = stream.freerate;
// header.flags |= Mad.Flag.FREEFORMAT;
}
/* calculate beginning of next frame */
pad_slot = (header.flags & Mad.Flag.PADDING) ? 1 : 0;
if (header.layer == Mad.Layer.I) {
N = (((12 * header.bitrate / header.samplerate) << 0) + pad_slot) * 4;
} else {
var slots_per_frame = (header.layer == Mad.Layer.III &&
(header.flags & Mad.Flag.LSF_EXT)) ? 72 : 144;
//console.log("slots_per_frame = " + slots_per_frame + ", bitrate = " + header.bitrate + ", samplerate = " + header.samplerate);
N = ((slots_per_frame * header.bitrate / header.samplerate) << 0) + pad_slot;
}
/* verify there is enough data left in buffer to decode this frame */
if (N + Mad.BUFFER_GUARD > end - stream.this_frame) {
stream.next_frame = stream.this_frame;
stream.error = Mad.Error.BUFLEN;
return null;
}
stream.next_frame = stream.this_frame + N;
// console.log("N = " + N + ", pad_slot = " + pad_slot + ", next_frame = " + stream.next_frame);
if (!stream.sync) {
/* check that a valid frame header follows this frame */
ptr = stream.next_frame;
if (!(stream.getU8(ptr) == 0xff && (stream.getU8(ptr + 1) & 0xe0) == 0xe0)) {
ptr = stream.next_frame = stream.this_frame + 1;
// emulating 'goto sync'
syncing = true;
continue;
}
stream.sync = 1;
}
} // end of goto emulation (label 'sync')
header.flags |= Mad.Flag.INCOMPLETE;
return header;
}
var Frame = function () {
this.header = new Header(); /* MPEG audio header */
this.options = 0; /* decoding options (from stream) */
// sbsample[2][36][32]
this.sbsample = []; /* synthesis subband filter samples */
for(var ch = 0; ch < 2; ch++) {
this.sbsample[ch] = [];
for(var grp = 0; grp < 36; grp++) {
// this.sbsample[ch][grp] = new Float64Array(new ArrayBuffer(8 * 32));
this.sbsample[ch][grp] = [];
for(var i = 0; i < 32; i++) {
this.sbsample[ch][grp][i] = 0;
}
}
}
// overlap[2][32][18]
this.overlap = []; /* Layer III block overlap data */
for(var ch = 0; ch < 2; ch++) {
this.overlap[ch] = [];
for(var sb = 0; sb < 32; sb++) {
// this.overlap[ch][sb] = new Float64Array(new ArrayBuffer(8 * 18));
this.overlap[ch][sb] = [];
for(var i = 0; i < 18; i++) {
this.overlap[ch][sb][i] = 0;
}
}
}
};
Frame.decode = function(frame, stream) {
frame.options = stream.options;
/* header() */
/* error_check() */
if (!(frame.header.flags & Mad.Flag.INCOMPLETE)) {
frame.header = Header.decode(stream);
if(frame.header == null) {
// something went wrong
return null;
}
}
/* audio_data() */
frame.header.flags &= ~Mad.Flag.INCOMPLETE;
// TODO: actually decode the data :)
if (decoder_table[frame.header.layer - 1](stream, frame) == -1) {
if (!Mad.recoverable(stream.error))
stream.next_frame = stream.this_frame;
return null;
}
return frame;
};
export default Frame;