UNPKG

mp3

Version:
116 lines (93 loc) 3.58 kB
var AV = require('av'); var MP3FrameHeader = require('./header'); var MP3Stream = require('./stream'); var MP3Frame = require('./frame'); var MP3Synth = require('./synth'); var Layer1 = require('./layer1'); var Layer2 = require('./layer2'); var Layer3 = require('./layer3'); var MP3Decoder = AV.Decoder.extend(function() { AV.Decoder.register('mp3', this); this.prototype.init = function() { this.mp3_stream = new MP3Stream(this.bitstream); this.frame = new MP3Frame(); this.synth = new MP3Synth(); this.seeking = false; }; this.prototype.readChunk = function() { var stream = this.mp3_stream; var frame = this.frame; var synth = this.synth; // if we just seeked, we may start getting errors involving the frame reservoir, // so keep going until we successfully decode a frame if (this.seeking) { while (true) { try { frame.decode(stream); break; } catch (err) { if (err instanceof AV.UnderflowError) throw err; } } this.seeking = false; } else { frame.decode(stream); } synth.frame(frame); // interleave samples var data = synth.pcm.samples, channels = synth.pcm.channels, len = synth.pcm.length, output = new Float32Array(len * channels), j = 0; for (var k = 0; k < len; k++) { for (var i = 0; i < channels; i++) { output[j++] = data[i][k]; } } return output; }; this.prototype.seek = function(timestamp) { var offset; // if there was a Xing or VBRI tag with a seek table, use that // otherwise guesstimate based on CBR bitrate if (this.demuxer.seekPoints.length > 0) { timestamp = this._super(timestamp); offset = this.stream.offset; } else { offset = timestamp * this.format.bitrate / 8 / this.format.sampleRate; } this.mp3_stream.reset(offset); // try to find 3 consecutive valid frame headers in a row for (var i = 0; i < 4096; i++) { var pos = offset + i; for (var j = 0; j < 3; j++) { this.mp3_stream.reset(pos); try { var header = MP3FrameHeader.decode(this.mp3_stream); } catch (e) { break; } // skip the rest of the frame var size = header.framesize(); if (size == null) break; pos += size; } // check if we're done if (j === 3) break; } // if we didn't find 3 frames, just try the first one and hope for the best if (j !== 3) i = 0; this.mp3_stream.reset(offset + i); // if we guesstimated, update the timestamp to another estimate of where we actually seeked to if (this.demuxer.seekPoints.length === 0) timestamp = this.stream.offset / (this.format.bitrate / 8) * this.format.sampleRate; this.seeking = true; return timestamp; }; }); module.exports = MP3Decoder;