diff --git a/assets/disk0/home/mp3test.js b/assets/disk0/home/mp3test.js index 4428df6..ae2a8a9 100644 --- a/assets/disk0/home/mp3test.js +++ b/assets/disk0/home/mp3test.js @@ -2,22 +2,90 @@ const Mp3 = require('mp3dec') 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=>{ print(`${e}\t`) }) println() println("reading...") -let arr = files.open("A:/gateless.mp3").bread() -let ab = new ArrayBuffer(arr.length) -let abba = new Uint8Array(ab) -arr.forEach((v,i)=>{ abba[i] = v }) - - -let mp3ArrayBuffer = new Uint8Array(ab, 0, arr.length) +//let arr = files.open("A:/gateless.mp3").bread() +//let ab = new ArrayBuffer(arr.length) +//let abba = new Uint8Array(ab) +//arr.forEach((v,i)=>{ abba[i] = v }) +//let mp3ArrayBuffer = new Uint8Array(ab, 0, arr.length)* println("decoding...") -let decoder = Mp3.newDecoder(ab) +let decoder = Mp3.newDecoder(new SequentialFileBuffer("A:/gateless0.mp3")) if (decoder === null) throw Error("decoder is null") audio.resetParams(0) @@ -47,7 +115,11 @@ function printPlayBar() { const QUEUE_MAX = 4 +let t1 = sys.nanoTime() decoder.decode(obj=>{ + let t2 = sys.nanoTime() + + let buf = obj.buf let err = obj.err @@ -60,8 +132,16 @@ decoder.decode(obj=>{ audio.startSampleUpload(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 diff --git a/assets/disk0/tvdos/include/js-mp3/frame.js b/assets/disk0/tvdos/include/js-mp3/frame.js index 6dbc58e..c605f42 100644 --- a/assets/disk0/tvdos/include/js-mp3/frame.js +++ b/assets/disk0/tvdos/include/js-mp3/frame.js @@ -643,14 +643,8 @@ var Frame = { }, readCRC: function (source) { - var result = source.readFull(2); - if (result.err) { - return { - err: result.err - } - } - var buf = result.buf; - if (buf.byteLength < 2) { + var buf = source.readFull(2) + if (buf.length < 2) { return "mp3: error at readCRC"; } }, diff --git a/assets/disk0/tvdos/include/js-mp3/frameheader.js b/assets/disk0/tvdos/include/js-mp3/frameheader.js index 2716116..9d7d7d8 100644 --- a/assets/disk0/tvdos/include/js-mp3/frameheader.js +++ b/assets/disk0/tvdos/include/js-mp3/frameheader.js @@ -2,6 +2,7 @@ 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 @@ -214,14 +215,8 @@ var Frameheader = { read: function (source, position) { var pos = position; - var result = source.readFull(4); - if (result.err) { - return { - err: result.err - } - } - var buf = result.buf; - if (buf.byteLength < 4) { + var buf = source.readFull(4) + if (buf.length < 4) { return { h: 0, position: 0, @@ -238,15 +233,9 @@ var Frameheader = { while (!fh.isValid()) { // stopPosition++; - result = source.readFull(1); - if (result.err) { - return { - err: result.err - } - } - buf = result.buf; + buf = source.readFull(1); - if (buf.byteLength < 1) { + if (buf.length < 1) { return { h: 0, position: 0, diff --git a/assets/disk0/tvdos/include/js-mp3/maindata.js b/assets/disk0/tvdos/include/js-mp3/maindata.js index 6cd983d..86cce5f 100644 --- a/assets/disk0/tvdos/include/js-mp3/maindata.js +++ b/assets/disk0/tvdos/include/js-mp3/maindata.js @@ -186,23 +186,24 @@ var read = function (source, prev, size, offset) { if (prev !== null) { vec = prev.Tail(offset); } + + + +// serial.println(`maindata readFull(${size})`) + // Read the main_data from file - var result = source.readFull(size); - if (result.err) { - return { - err: result.err - } - } - var buf = result.buf; + var buf = source.readFull(size); // var buf = new Uint8Array(source, 0, size); - if (buf.byteLength < size) { + if (buf.length < size) { return { b: null, err: "maindata.Read (2)" } } + 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 } }; diff --git a/assets/disk0/tvdos/include/js-mp3/sideinfo.js b/assets/disk0/tvdos/include/js-mp3/sideinfo.js index e2d1404..4ca22c7 100644 --- a/assets/disk0/tvdos/include/js-mp3/sideinfo.js +++ b/assets/disk0/tvdos/include/js-mp3/sideinfo.js @@ -73,23 +73,21 @@ var Sideinfo = { if (fheader.protectionBit() === 0) { main_data_size -= 2; } + + +// serial.println(`sideinfo readFull(${sideinfo_size})`) + // Read sideinfo from bitstream into buffer used by Bits() - var result = source.readFull(sideinfo_size); - if (result.err) { - return { - err: result.err - } - } - var buf = result.buf; + var buf = source.readFull(sideinfo_size); // var buf = new Uint8Array(source.buf, pos, sideinfo_size); - if (buf.byteLength < 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.slice()).buffer); + var s = Bits.createNew(new Uint8Array(buf).buffer); // Parse audio data // Pointer to where we should start reading main data diff --git a/assets/disk0/tvdos/include/mp3dec.js b/assets/disk0/tvdos/include/mp3dec.js index 9056bf5..cbadafe 100644 --- a/assets/disk0/tvdos/include/mp3dec.js +++ b/assets/disk0/tvdos/include/mp3dec.js @@ -53,6 +53,7 @@ var Mp3 = { err: "position not correct" } } + source.buf.seek(position) source.pos = position; return { pos: source.pos @@ -60,35 +61,23 @@ var Mp3 = { }; source.readFull = function (length) { + if (length < 0) throw Error("Source.pos less than 0: "+source.pos) - try { - if (length < 0) throw Error("Source.pos less than 0: "+source.pos) + var l = Math.min(source.buf.byteLength - source.pos, length); - var l = Math.min(source.buf.byteLength - source.pos, length); - - if (l < 0) { - 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() - } + if (l < 0) { + serial.println("l < 0: "+l) + throw Error("l < 0: "+l) } + +// 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 () { @@ -99,69 +88,39 @@ var Mp3 = { }; source.skipTags = function () { - var result = source.readFull(3); - if (result.err) { - return { - err: result.err - } - } - var buf = result.buf; + var t = source.buf.readStr(3); + +// var buf = result.buf; // decode UTF-8 - var t = String.fromCharCode.apply(null, buf); switch (t) { case "TAG": - result = source.readFull(125); - if (result.err) { - return { - err: result.err - } - } - buf = result.buf; + source.readFull(125); break; case 'ID3': // Skip version (2 bytes) and flag (1 byte) - result = source.readFull(3); - if (result.err) { - return { - err: result.err - } - } + source.readFull(3); - result = source.readFull(4); - if (result.err) { - return { - err: result.err - } - } - buf = result.buf; - if (buf.byteLength !== 4) { + let buf = source.readFull(4) + if (buf.length !== 4) { return { err: "data not enough." }; } 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) { - return { - err: result.err - } - } - buf = result.buf; + + source.readFull(size) break; default: - source.unread(buf); + source.buf.unread(3); // source.pos -= 3; break; } return {}; }; - source.unread = function (buf) { - source.pos -= buf.byteLength - }; - source.rewind = function() { + source.buf.rewind() source.pos = 0; }; @@ -197,6 +156,9 @@ var Mp3 = { decoder.decode = function (callback) { var result; + + serial.println("Start decoding") + while(true) { result = decoder.readFrame(); @@ -227,6 +189,9 @@ var Mp3 = { var l = 0; while(true) { + +// serial.println(`Reading Frames; l = ${l}`) + var result = Frameheader.read(decoder.source, decoder.source.pos); if (result.err) { if (result.err.toString().indexOf("UnexpectedEOF") > -1) { @@ -236,10 +201,12 @@ var Mp3 = { err: result.err }; } + + decoder.frameStarts.push(result.position); 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) { break; } @@ -255,21 +222,31 @@ var Mp3 = { }; // ======= Methods of decoder :: end ========= +// serial.println("Reading tags") + var r = s.skipTags(); if (r && r.err) { throw Error(`Error creating new MP3 source: ${r.err}`) return null; } +// serial.println("Reading first frame") + var result = decoder.readFrame(); if (result.err) { throw Error(`Error reading frame: ${result.err}`) return null; } +// serial.println("First frame finished reading") + decoder.sampleRate = decoder.frame.samplingFrequency(); + serial.println("Sampling rate: "+decoder.sampleRate + " Hz") + result = decoder.ensureFrameStartsAndLength(); + + serial.println("Decode end") if (result.err) { throw Error(`Error ensuring Frame starts and length: ${result.err}`) return null;