This commit is contained in:
minjaesong
2023-01-14 02:04:41 +09:00
parent 1c9e99bb66
commit f23dedc245
6 changed files with 159 additions and 120 deletions

View File

@@ -2,22 +2,90 @@ const Mp3 = require('mp3dec')
const pcm = require("pcm") const pcm = require("pcm")
class SequentialFileBuffer {
constructor(path, offset, length) {
if (Array.isArray(path)) throw Error("arg #1 is path(string), not array")
this.path = path
this.file = files.open(path)
this.offset = offset || 0
this.originalOffset = offset
this.length = length || this.file.size
this.seq = require("seqread")
this.seq.prepare(path)
}
/*readFull(n) {
throw Error()
let ptr = this.seq.readBytes(n)
return ptr
}*/
readStr(n) {
let ptr = this.seq.readBytes(n)
let s = ''
for (let i = 0; i < n; i++) {
if (i >= this.length) break
s += String.fromCharCode(sys.peek(ptr + i))
}
sys.free(ptr)
return s
}
readByteNumbers(n) {
let ptr = this.seq.readBytes(n)
let s = []
for (let i = 0; i < n; i++) {
if (i >= this.length) break
s.push(sys.peek(ptr + i))
}
sys.free(ptr)
return s
}
unread(diff) {
let newSkipLen = this.seq.getReadCount() - diff
this.seq.prepare(this.path)
this.seq.skip(newSkipLen)
}
rewind() {
this.seq.prepare(this.path)
}
seek(p) {
this.seq.prepare(this.path)
this.seq.skip(p)
}
get byteLength() {
return this.length
}
/*get remaining() {
return this.length - this.getReadCount()
}*/
}
Object.keys(Mp3).forEach(e=>{ Object.keys(Mp3).forEach(e=>{
print(`${e}\t`) print(`${e}\t`)
}) })
println() println()
println("reading...") println("reading...")
let arr = files.open("A:/gateless.mp3").bread() //let arr = files.open("A:/gateless.mp3").bread()
let ab = new ArrayBuffer(arr.length) //let ab = new ArrayBuffer(arr.length)
let abba = new Uint8Array(ab) //let abba = new Uint8Array(ab)
arr.forEach((v,i)=>{ abba[i] = v }) //arr.forEach((v,i)=>{ abba[i] = v })
//let mp3ArrayBuffer = new Uint8Array(ab, 0, arr.length)*
let mp3ArrayBuffer = new Uint8Array(ab, 0, arr.length)
println("decoding...") println("decoding...")
let decoder = Mp3.newDecoder(ab) let decoder = Mp3.newDecoder(new SequentialFileBuffer("A:/gateless0.mp3"))
if (decoder === null) throw Error("decoder is null") if (decoder === null) throw Error("decoder is null")
audio.resetParams(0) audio.resetParams(0)
@@ -47,7 +115,11 @@ function printPlayBar() {
const QUEUE_MAX = 4 const QUEUE_MAX = 4
let t1 = sys.nanoTime()
decoder.decode(obj=>{ decoder.decode(obj=>{
let t2 = sys.nanoTime()
let buf = obj.buf let buf = obj.buf
let err = obj.err let err = obj.err
@@ -60,8 +132,16 @@ decoder.decode(obj=>{
audio.startSampleUpload(0) audio.startSampleUpload(0)
audio.play(0) audio.play(0)
serial.println(`Send sample (${audio.getPosition(0)})`)
// sys.sleep(0) // decoding time is slower than realtime :( // sys.sleep(10) // decoding time is slower than realtime :(
let decodingTime = t2 - t1
let bufRealTimeLen = (declen) / 64000.0 * 1000000000
t1 = t2
println(`Decoded ${decodedLength} bytes; lag: ${(decodingTime - bufRealTimeLen) / 1000000} ms`)
}) // now you got decoded PCM data }) // now you got decoded PCM data

View File

@@ -643,14 +643,8 @@ var Frame = {
}, },
readCRC: function (source) { readCRC: function (source) {
var result = source.readFull(2); var buf = source.readFull(2)
if (result.err) { if (buf.length < 2) {
return {
err: result.err
}
}
var buf = result.buf;
if (buf.byteLength < 2) {
return "mp3: error at readCRC"; return "mp3: error at readCRC";
} }
}, },

View File

@@ -2,6 +2,7 @@ var consts = require('A:/tvdos/include/js-mp3/consts.js');
var Frameheader = { var Frameheader = {
createNew: function (value) { createNew: function (value) {
// A mepg1FrameHeader is MPEG1 Layer 1-3 frame header // A mepg1FrameHeader is MPEG1 Layer 1-3 frame header
var fh = { var fh = {
value: value value: value
@@ -214,14 +215,8 @@ var Frameheader = {
read: function (source, position) { read: function (source, position) {
var pos = position; var pos = position;
var result = source.readFull(4); var buf = source.readFull(4)
if (result.err) { if (buf.length < 4) {
return {
err: result.err
}
}
var buf = result.buf;
if (buf.byteLength < 4) {
return { return {
h: 0, h: 0,
position: 0, position: 0,
@@ -238,15 +233,9 @@ var Frameheader = {
while (!fh.isValid()) { while (!fh.isValid()) {
// stopPosition++; // stopPosition++;
result = source.readFull(1); buf = source.readFull(1);
if (result.err) {
return {
err: result.err
}
}
buf = result.buf;
if (buf.byteLength < 1) { if (buf.length < 1) {
return { return {
h: 0, h: 0,
position: 0, position: 0,

View File

@@ -186,23 +186,24 @@ var read = function (source, prev, size, offset) {
if (prev !== null) { if (prev !== null) {
vec = prev.Tail(offset); vec = prev.Tail(offset);
} }
// serial.println(`maindata readFull(${size})`)
// Read the main_data from file // Read the main_data from file
var result = source.readFull(size); var buf = source.readFull(size);
if (result.err) {
return {
err: result.err
}
}
var buf = result.buf;
// var buf = new Uint8Array(source, 0, size); // var buf = new Uint8Array(source, 0, size);
if (buf.byteLength < size) { if (buf.length < size) {
return { return {
b: null, b: null,
err: "maindata.Read (2)" err: "maindata.Read (2)"
} }
} }
return { return {
b: bits.createNew(util.concatBuffers(vec, new Uint8Array(buf.slice()).buffer)), // b: bits.createNew(util.concatBuffers(vec, new Uint8Array(buf.slice()).buffer)),
b: bits.createNew(util.concatBuffers(vec, new Uint8Array(buf).buffer)),
err: null err: null
} }
}; };

View File

@@ -73,23 +73,21 @@ var Sideinfo = {
if (fheader.protectionBit() === 0) { if (fheader.protectionBit() === 0) {
main_data_size -= 2; main_data_size -= 2;
} }
// serial.println(`sideinfo readFull(${sideinfo_size})`)
// Read sideinfo from bitstream into buffer used by Bits() // Read sideinfo from bitstream into buffer used by Bits()
var result = source.readFull(sideinfo_size); var buf = source.readFull(sideinfo_size);
if (result.err) {
return {
err: result.err
}
}
var buf = result.buf;
// var buf = new Uint8Array(source.buf, pos, sideinfo_size); // var buf = new Uint8Array(source.buf, pos, sideinfo_size);
if (buf.byteLength < sideinfo_size) { if (buf.length < sideinfo_size) {
return { return {
v: null, v: null,
pos: pos, pos: pos,
err: "mp3: couldn't read sideinfo " + sideinfo_size + " bytes" err: "mp3: couldn't read sideinfo " + sideinfo_size + " bytes"
} }
} }
var s = Bits.createNew(new Uint8Array(buf.slice()).buffer); var s = Bits.createNew(new Uint8Array(buf).buffer);
// Parse audio data // Parse audio data
// Pointer to where we should start reading main data // Pointer to where we should start reading main data

View File

@@ -53,6 +53,7 @@ var Mp3 = {
err: "position not correct" err: "position not correct"
} }
} }
source.buf.seek(position)
source.pos = position; source.pos = position;
return { return {
pos: source.pos pos: source.pos
@@ -60,35 +61,23 @@ var Mp3 = {
}; };
source.readFull = function (length) { source.readFull = function (length) {
if (length < 0) throw Error("Source.pos less than 0: "+source.pos)
try { var l = Math.min(source.buf.byteLength - source.pos, length);
if (length < 0) throw Error("Source.pos less than 0: "+source.pos)
var l = Math.min(source.buf.byteLength - source.pos, length); if (l < 0) {
serial.println("l < 0: "+l)
if (l < 0) { throw Error("l < 0: "+l)
serial.println("l < 0: "+l)
throw Error("l < 0: "+l)
}
var bbuf = new Uint8Array(source.buf, source.pos, l);
source.pos += bbuf.byteLength;
if (source.pos < 0) {
throw Error("pos < 0: "+source.pos)
}
return {
buf: bbuf,
err: null
};
} catch (e) {
return {
buf: null,
err: e.toString()
}
} }
// serial.println(`readFull(${length} -> ${l}); pos: ${source.pos}`)
if (source.pos + l < 0) {
throw Error("pos < 0: "+source.pos)
}
source.pos += l;
return source.buf.readByteNumbers(l)
}; };
source.getPos = function () { source.getPos = function () {
@@ -99,69 +88,39 @@ var Mp3 = {
}; };
source.skipTags = function () { source.skipTags = function () {
var result = source.readFull(3); var t = source.buf.readStr(3);
if (result.err) {
return { // var buf = result.buf;
err: result.err
}
}
var buf = result.buf;
// decode UTF-8 // decode UTF-8
var t = String.fromCharCode.apply(null, buf);
switch (t) { switch (t) {
case "TAG": case "TAG":
result = source.readFull(125); source.readFull(125);
if (result.err) {
return {
err: result.err
}
}
buf = result.buf;
break; break;
case 'ID3': case 'ID3':
// Skip version (2 bytes) and flag (1 byte) // Skip version (2 bytes) and flag (1 byte)
result = source.readFull(3); source.readFull(3);
if (result.err) {
return {
err: result.err
}
}
result = source.readFull(4); let buf = source.readFull(4)
if (result.err) { if (buf.length !== 4) {
return {
err: result.err
}
}
buf = result.buf;
if (buf.byteLength !== 4) {
return { return {
err: "data not enough." err: "data not enough."
}; };
} }
var size = (((buf[0] >>> 0) << 21) >>> 0) | (((buf[1] >>> 0) << 14) >>> 0) | (((buf[2] >>> 0) << 7) >>> 0) | (buf[3] >>> 0); var size = (((buf[0] >>> 0) << 21) >>> 0) | (((buf[1] >>> 0) << 14) >>> 0) | (((buf[2] >>> 0) << 7) >>> 0) | (buf[3] >>> 0);
result = source.readFull(size);
if (result.err) { source.readFull(size)
return {
err: result.err
}
}
buf = result.buf;
break; break;
default: default:
source.unread(buf); source.buf.unread(3);
// source.pos -= 3; // source.pos -= 3;
break; break;
} }
return {}; return {};
}; };
source.unread = function (buf) {
source.pos -= buf.byteLength
};
source.rewind = function() { source.rewind = function() {
source.buf.rewind()
source.pos = 0; source.pos = 0;
}; };
@@ -197,6 +156,9 @@ var Mp3 = {
decoder.decode = function (callback) { decoder.decode = function (callback) {
var result; var result;
serial.println("Start decoding")
while(true) { while(true) {
result = decoder.readFrame(); result = decoder.readFrame();
@@ -227,6 +189,9 @@ var Mp3 = {
var l = 0; var l = 0;
while(true) { while(true) {
// serial.println(`Reading Frames; l = ${l}`)
var result = Frameheader.read(decoder.source, decoder.source.pos); var result = Frameheader.read(decoder.source, decoder.source.pos);
if (result.err) { if (result.err) {
if (result.err.toString().indexOf("UnexpectedEOF") > -1) { if (result.err.toString().indexOf("UnexpectedEOF") > -1) {
@@ -236,10 +201,12 @@ var Mp3 = {
err: result.err err: result.err
}; };
} }
decoder.frameStarts.push(result.position); decoder.frameStarts.push(result.position);
l += consts.BytesPerFrame; l += consts.BytesPerFrame;
result = decoder.source.readFull(result.h.frameSize() - 4); // move to next frame position result = decoder.source.readFull(result.h.frameSize() - 4)[0]; // move to next frame position
if (result.err) { if (result.err) {
break; break;
} }
@@ -255,21 +222,31 @@ var Mp3 = {
}; };
// ======= Methods of decoder :: end ========= // ======= Methods of decoder :: end =========
// serial.println("Reading tags")
var r = s.skipTags(); var r = s.skipTags();
if (r && r.err) { if (r && r.err) {
throw Error(`Error creating new MP3 source: ${r.err}`) throw Error(`Error creating new MP3 source: ${r.err}`)
return null; return null;
} }
// serial.println("Reading first frame")
var result = decoder.readFrame(); var result = decoder.readFrame();
if (result.err) { if (result.err) {
throw Error(`Error reading frame: ${result.err}`) throw Error(`Error reading frame: ${result.err}`)
return null; return null;
} }
// serial.println("First frame finished reading")
decoder.sampleRate = decoder.frame.samplingFrequency(); decoder.sampleRate = decoder.frame.samplingFrequency();
serial.println("Sampling rate: "+decoder.sampleRate + " Hz")
result = decoder.ensureFrameStartsAndLength(); result = decoder.ensureFrameStartsAndLength();
serial.println("Decode end")
if (result.err) { if (result.err) {
throw Error(`Error ensuring Frame starts and length: ${result.err}`) throw Error(`Error ensuring Frame starts and length: ${result.err}`)
return null; return null;