From af03ab23aa5f4a1bb16a9661210fd7010ad062c0 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 15 Jan 2023 16:42:09 +0900 Subject: [PATCH] deploying mp2 player --- .../{home/mp2test.js => tvdos/bin/playmp2.js} | 166 ++-- assets/disk0/tvdos/bin/playmp3.js | 10 +- assets/disk0/tvdos/bin/playpcm.js | 16 +- assets/disk0/tvdos/bin/playwav.js | 16 +- assets/disk0/tvdos/include/mp2dec.js | 871 ------------------ assets/disk0/tvdos/include/seqread.js | 17 +- assets/disk0/tvdos/tuidev/zfm.js | 5 +- .../net/torvald/tsvm/AudioJSR223Delegate.kt | 94 +- 8 files changed, 226 insertions(+), 969 deletions(-) rename assets/disk0/{home/mp2test.js => tvdos/bin/playmp2.js} (54%) delete mode 100644 assets/disk0/tvdos/include/mp2dec.js diff --git a/assets/disk0/home/mp2test.js b/assets/disk0/tvdos/bin/playmp2.js similarity index 54% rename from assets/disk0/home/mp2test.js rename to assets/disk0/tvdos/bin/playmp2.js index 8e8d365..a5279c9 100644 --- a/assets/disk0/home/mp2test.js +++ b/assets/disk0/tvdos/bin/playmp2.js @@ -1,10 +1,7 @@ -exec_args[1] = "A:/loopey.mp2" - -const mp2 = require('mp2dec') const pcm = require("pcm") const interactive = exec_args[2] && exec_args[2].toLowerCase() == "/i" +function printdbg(s) { if (0) serial.println(s) } -function printdbg(s) { if (1) serial.println(s) } class SequentialFileBuffer { @@ -26,12 +23,6 @@ class SequentialFileBuffer { return this.seq.readBytes(size, ptr) } - /*readFull(n) { - throw Error() - let ptr = this.seq.readBytes(n) - return ptr - }*/ - readStr(n) { let ptr = this.seq.readBytes(n) let s = '' @@ -43,23 +34,6 @@ class SequentialFileBuffer { return s } - /*readByteNumbers(n) { - let ptr = this.seq.readBytes(n) - try { - 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 - } - catch (e) { - println(`n: ${n}; ptr: ${ptr}`) - println(e) - } - }*/ - unread(diff) { let newSkipLen = this.seq.getReadCount() - diff this.seq.prepare(this.path) @@ -79,43 +53,29 @@ class SequentialFileBuffer { return this.length } + get fileHeader() { + return this.seq.fileHeader + } + /*get remaining() { return this.length - this.getReadCount() }*/ } -// this reads file, initialises all the craps, gets initial frame size, then discards everything; truly wasteful :) -// TODO use virtual audio hardware! -function getInitialFrameSize() { - - let frame = filebuf.readBytes(4096) - let mp2 = require('mp2dec') - let mp2context = mp2.kjmp2_make_mp2_state() - mp2.kjmp2_init(mp2context) - - let sampleRate = mp2.kjmp2_get_sample_rate(frame) - let [frameSize, _] = mp2.kjmp2_decode_frame(mp2context, frame, null, []) - - filebuf.rewind() - sys.free(frame) - - return [frameSize, sampleRate] -} - let filebuf = new SequentialFileBuffer(_G.shell.resolvePathInput(exec_args[1]).full) const FILE_SIZE = filebuf.length - 100 +let FRAME_SIZE = audio.mp2GetInitialFrameSize(filebuf.fileHeader) -const [FRAME_SIZE, SAMPLE_RATE] = getInitialFrameSize() let bytes_left = FILE_SIZE let decodedLength = 0 -println(`Sampling rate: ${SAMPLE_RATE}, Frame size: ${FRAME_SIZE}`) +//serial.println(`Frame size: ${FRAME_SIZE}`) @@ -131,21 +91,10 @@ function decodeAndResample(inPtrL, inPtrR, outPtr, inputLen) { } } function decodeEvent(frameSize, len) { - if (interactive) { - sys.poke(-40, 1) - if (sys.peek(-41) == 67) { - stopPlay = true - throw "STOP" - } - } - -// printPlayBar(pos) let t2 = sys.nanoTime() - decodedLength += frameSize - - printdbg(`Audio queue size: ${audio.getPosition(0)}/${QUEUE_MAX}`) +// printdbg(`Audio queue size: ${audio.getPosition(0)}/${QUEUE_MAX}`) if (audio.getPosition(0) >= QUEUE_MAX) { while (audio.getPosition(0) >= (QUEUE_MAX >>> 1)) { @@ -166,7 +115,48 @@ function decodeEvent(frameSize, len) { bufRealTimeLen = (len) / 64000.0 * 1000 t1 = t2 - println(`Decoded ${decodedLength} bytes; target: ${bufRealTimeLen} ms, lag: ${decodingTime - bufRealTimeLen} ms`) +// println(`Decoded ${decodedLength} bytes; target: ${bufRealTimeLen} ms, lag: ${decodingTime - bufRealTimeLen} ms`) +} + + +con.curs_set(0) +con.curs_set(0) +if (interactive) { + println("Push and hold Backspace to exit") +} +let [cy, cx] = con.getyx() +let [__, CONSOLE_WIDTH] = con.getmaxyx() +let paintWidth = CONSOLE_WIDTH - 16 +function bytesToSec(i) { + // using fixed value: FRAME_SIZE(216) bytes for 36 ms on sampling rate 32000 Hz + return i / (FRAME_SIZE * 1000 / bufRealTimeLen) +} +function secToReadable(n) { + let mins = ''+((n/60)|0) + let secs = ''+(n % 60) + return `${mins.padStart(2,'0')}:${secs.padStart(2,'0')}` +} +function printPlayBar(currently) { + if (interactive) { + let currently = decodedLength + let total = FILE_SIZE + + let currentlySec = Math.round(bytesToSec(currently)) + let totalSec = Math.round(bytesToSec(total)) + + con.move(cy, 1) + print(' '.repeat(15)) + con.move(cy, 1) + + print(`${secToReadable(currentlySec)} / ${secToReadable(totalSec)}`) + + con.move(cy, 15) + print(' ') + let progressbar = '\x84205u'.repeat(paintWidth + 1) + print(progressbar) + + con.mvaddch(cy, 16 + Math.round(paintWidth * (currently / total)), 0xDB) + } } @@ -180,35 +170,51 @@ audio.setMasterVolume(0, 255) audio.play(0) -let mp2context = audio.createNewMP2context() -audio.kjmp2_init(mp2context) +let mp2context = audio.mp2Init() // decode frame let frame = sys.malloc(FRAME_SIZE) -let samplePtrL = sys.malloc(6000) // 16b samples -let samplePtrR = sys.malloc(6000) // 16b samples -let decodePtr = sys.malloc(6000) // 8b samples +let samplePtrL = sys.malloc(2304) // 16b samples +let samplePtrR = sys.malloc(2304) // 16b samples +let decodePtr = sys.malloc(2304) // 8b samples let t1 = sys.nanoTime() let bufRealTimeLen = 36 -while (bytes_left >= 0) { +let stopPlay = false +let errorlevel = 0 +try { + while (bytes_left >= 0 && !stopPlay) { -// println(`Bytes left: ${bytes_left}`) + if (interactive) { + sys.poke(-40, 1) + if (sys.peek(-41) == 67) { + stopPlay = true + } + } + printPlayBar() - filebuf.readBytes(FRAME_SIZE, frame) - bytes_left -= FRAME_SIZE + filebuf.readBytes(FRAME_SIZE, frame) + bytes_left -= FRAME_SIZE + decodedLength += FRAME_SIZE - let decodedL = [] - let decodedR = [] - let [frameSize, samples] = audio.kjmp2_decode_frame(mp2context, frame, true, samplePtrL, samplePtrR) - if (frameSize) { - // play using decodedLR - decodeEvent(frameSize, samples) + let [frameSize, samples] = audio.mp2DecodeFrame(mp2context, frame, true, samplePtrL, samplePtrR) + if (frameSize) { +// println(samples) + // play using decodedLR + decodeEvent(frameSize, samples) + FRAME_SIZE = frameSize // JUST IN CASE when a vbr mp2 is not filtered and played thru + } } - +} +catch (e) { + printerrln(e) + errorlevel = 1 +} +finally { + sys.free(frame) + sys.free(decodePtr) + sys.free(samplePtrL) + sys.free(samplePtrR) } -sys.free(frame) -sys.free(decodePtr) -sys.free(samplePtrL) -sys.free(samplePtrR) +return errorlevel \ No newline at end of file diff --git a/assets/disk0/tvdos/bin/playmp3.js b/assets/disk0/tvdos/bin/playmp3.js index 4ba8ff0..fb7b8c6 100644 --- a/assets/disk0/tvdos/bin/playmp3.js +++ b/assets/disk0/tvdos/bin/playmp3.js @@ -170,6 +170,7 @@ function printPlayBar(currently) { } } let t1 = sys.nanoTime() +let errorlevel = 0 let bufRealTimeLen = 36 try { decoder.decode((ptr, len, pos)=>{ @@ -217,10 +218,15 @@ try { }) // now you got decoded PCM data } catch (e) { - if (e != "STOP") throw e + if (e != "STOP") { + printerrln(e) + errorlevel = 1 + } } finally { //audio.stop(0) sys.free(readPtr) sys.free(decodePtr) -} \ No newline at end of file +} + +return errorlevel \ No newline at end of file diff --git a/assets/disk0/tvdos/bin/playpcm.js b/assets/disk0/tvdos/bin/playpcm.js index 3f42e5e..3bdabfc 100644 --- a/assets/disk0/tvdos/bin/playpcm.js +++ b/assets/disk0/tvdos/bin/playpcm.js @@ -108,6 +108,8 @@ function printPlayBar() { con.mvaddch(cy, 16 + Math.round(paintWidth * (currently / total)), 0xDB) } } +let errorlevel = 0 +try { while (!stopPlay && seqread.getReadCount() < FILE_SIZE && readLength > 0) { if (interactive) { sys.poke(-40, 1) @@ -155,8 +157,16 @@ while (!stopPlay && seqread.getReadCount() < FILE_SIZE && readLength > 0) { sys.sleep(10) } +} +catch (e) { + printerrln(e) + errorlevel = 1 +} +finally { + //audio.stop(0) + if (readPtr !== undefined) sys.free(readPtr) + if (decodePtr !== undefined) sys.free(decodePtr) +} +return errorlevel -//audio.stop(0) -if (readPtr !== undefined) sys.free(readPtr) -if (decodePtr !== undefined) sys.free(decodePtr) diff --git a/assets/disk0/tvdos/bin/playwav.js b/assets/disk0/tvdos/bin/playwav.js index 9ce0bd0..6cc59bc 100644 --- a/assets/disk0/tvdos/bin/playwav.js +++ b/assets/disk0/tvdos/bin/playwav.js @@ -127,7 +127,9 @@ function printPlayBar(startOffset) { con.mvaddch(cy, 16 + Math.round(paintWidth * (currently / total)), 0xDB) } } +let errorlevel = 0 // read chunks loop +try { while (!stopPlay && seqread.getReadCount() < FILE_SIZE - 8) { let chunkName = seqread.readFourCC() let chunkSize = seqread.readInt() @@ -267,7 +269,15 @@ while (!stopPlay && seqread.getReadCount() < FILE_SIZE - 8) { printdbg(`remainingBytes2 = ${remainingBytes}`) sys.spin() } +} +catch (e) { + printerrln(e) + errorlevel = 1 +} +finally { + //audio.stop(0) + if (readPtr !== undefined) sys.free(readPtr) + if (decodePtr !== undefined) sys.free(decodePtr) +} -//audio.stop(0) -if (readPtr !== undefined) sys.free(readPtr) -if (decodePtr !== undefined) sys.free(decodePtr) +return errorlevel diff --git a/assets/disk0/tvdos/include/mp2dec.js b/assets/disk0/tvdos/include/mp2dec.js deleted file mode 100644 index fc904e3..0000000 --- a/assets/disk0/tvdos/include/mp2dec.js +++ /dev/null @@ -1,871 +0,0 @@ -/* - mp2dec.js JavaScript MPEG-1 Audio Layer II decoder - Copyright (C) 2011 Liam Wilson - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. -*/ -/* Note this is a port of kjmp2 by Martin J. Fiedler: */ - -/****************************************************************************** -** kjmp2 -- a minimal MPEG-1 Audio Layer II decoder library ** -******************************************************************************* -** Copyright (C) 2006 Martin J. Fiedler martin.fiedler@gmx.net ** -** ** -** This software is provided 'as-is', without any express or implied ** -** warranty. In no event will the authors be held liable for any damages ** -** arising from the use of this software. ** -** ** -** Permission is granted to anyone to use this software for any purpose, ** -** including commercial applications, and to alter it and redistribute it ** -** freely, subject to the following restrictions: ** -** 1. The origin of this software must not be misrepresented; you must not ** -** claim that you wrote the original software. If you use this software ** -** in a product, an acknowledgment in the product documentation would ** -** be appreciated but is not required. ** -** 2. Altered source versions must be plainly marked as such, and must not ** -** be misrepresented as being the original software. ** -** 3. This notice may not be removed or altered from any source ** -** distribution. ** -******************************************************************************/ - -var frame = null; // ptr - -var STEREO=0; - -// #define JOINT_STEREO 1 -var JOINT_STEREO=1; - -// #define DUAL_CHANNEL 2 -var DUAL_CHANNEL=2; - -// #define MONO 3 -var MONO=3; - -// sample rate table -// static const int sample_rates[4] = { 44100, 48000, 32000, 0 }; -var sample_rates= [ 44100, 48000, 32000, 0 ]; - -// bitrate table -// static const int bitrates[14] = -// { 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 }; - -var bitrates =[ 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 ]; -/* -// scale factors (24-bit fixed-point) -static const int scf_value[64] = { - 0x02000000, 0x01965FEA, 0x01428A30, 0x01000000, - 0x00CB2FF5, 0x00A14518, 0x00800000, 0x006597FB, - 0x0050A28C, 0x00400000, 0x0032CBFD, 0x00285146, - 0x00200000, 0x001965FF, 0x001428A3, 0x00100000, - 0x000CB2FF, 0x000A1451, 0x00080000, 0x00065980, - 0x00050A29, 0x00040000, 0x00032CC0, 0x00028514, - 0x00020000, 0x00019660, 0x0001428A, 0x00010000, - 0x0000CB30, 0x0000A145, 0x00008000, 0x00006598, - 0x000050A3, 0x00004000, 0x000032CC, 0x00002851, - 0x00002000, 0x00001966, 0x00001429, 0x00001000, - 0x00000CB3, 0x00000A14, 0x00000800, 0x00000659, - 0x0000050A, 0x00000400, 0x0000032D, 0x00000285, - 0x00000200, 0x00000196, 0x00000143, 0x00000100, - 0x000000CB, 0x000000A1, 0x00000080, 0x00000066, - 0x00000051, 0x00000040, 0x00000033, 0x00000028, - 0x00000020, 0x00000019, 0x00000014, 0 -}; -*/ -// scale factors (24-bit fixed-point) -var scf_value = [ - 0x02000000, 0x01965FEA, 0x01428A30, 0x01000000, - 0x00CB2FF5, 0x00A14518, 0x00800000, 0x006597FB, - 0x0050A28C, 0x00400000, 0x0032CBFD, 0x00285146, - 0x00200000, 0x001965FF, 0x001428A3, 0x00100000, - 0x000CB2FF, 0x000A1451, 0x00080000, 0x00065980, - 0x00050A29, 0x00040000, 0x00032CC0, 0x00028514, - 0x00020000, 0x00019660, 0x0001428A, 0x00010000, - 0x0000CB30, 0x0000A145, 0x00008000, 0x00006598, - 0x000050A3, 0x00004000, 0x000032CC, 0x00002851, - 0x00002000, 0x00001966, 0x00001429, 0x00001000, - 0x00000CB3, 0x00000A14, 0x00000800, 0x00000659, - 0x0000050A, 0x00000400, 0x0000032D, 0x00000285, - 0x00000200, 0x00000196, 0x00000143, 0x00000100, - 0x000000CB, 0x000000A1, 0x00000080, 0x00000066, - 0x00000051, 0x00000040, 0x00000033, 0x00000028, - 0x00000020, 0x00000019, 0x00000014, 0]; - -/* -// synthesis window -static const int D[512] = { - 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,-0x00001, - -0x00001,-0x00001,-0x00001,-0x00002,-0x00002,-0x00003,-0x00003,-0x00004, - -0x00004,-0x00005,-0x00006,-0x00006,-0x00007,-0x00008,-0x00009,-0x0000A, - -0x0000C,-0x0000D,-0x0000F,-0x00010,-0x00012,-0x00014,-0x00017,-0x00019, - -0x0001C,-0x0001E,-0x00022,-0x00025,-0x00028,-0x0002C,-0x00030,-0x00034, - -0x00039,-0x0003E,-0x00043,-0x00048,-0x0004E,-0x00054,-0x0005A,-0x00060, - -0x00067,-0x0006E,-0x00074,-0x0007C,-0x00083,-0x0008A,-0x00092,-0x00099, - -0x000A0,-0x000A8,-0x000AF,-0x000B6,-0x000BD,-0x000C3,-0x000C9,-0x000CF, - 0x000D5, 0x000DA, 0x000DE, 0x000E1, 0x000E3, 0x000E4, 0x000E4, 0x000E3, - 0x000E0, 0x000DD, 0x000D7, 0x000D0, 0x000C8, 0x000BD, 0x000B1, 0x000A3, - 0x00092, 0x0007F, 0x0006A, 0x00053, 0x00039, 0x0001D,-0x00001,-0x00023, - -0x00047,-0x0006E,-0x00098,-0x000C4,-0x000F3,-0x00125,-0x0015A,-0x00190, - -0x001CA,-0x00206,-0x00244,-0x00284,-0x002C6,-0x0030A,-0x0034F,-0x00396, - -0x003DE,-0x00427,-0x00470,-0x004B9,-0x00502,-0x0054B,-0x00593,-0x005D9, - -0x0061E,-0x00661,-0x006A1,-0x006DE,-0x00718,-0x0074D,-0x0077E,-0x007A9, - -0x007D0,-0x007EF,-0x00808,-0x0081A,-0x00824,-0x00826,-0x0081F,-0x0080E, - 0x007F5, 0x007D0, 0x007A0, 0x00765, 0x0071E, 0x006CB, 0x0066C, 0x005FF, - 0x00586, 0x00500, 0x0046B, 0x003CA, 0x0031A, 0x0025D, 0x00192, 0x000B9, - -0x0002C,-0x0011F,-0x00220,-0x0032D,-0x00446,-0x0056B,-0x0069B,-0x007D5, - -0x00919,-0x00A66,-0x00BBB,-0x00D16,-0x00E78,-0x00FDE,-0x01148,-0x012B3, - -0x01420,-0x0158C,-0x016F6,-0x0185C,-0x019BC,-0x01B16,-0x01C66,-0x01DAC, - -0x01EE5,-0x02010,-0x0212A,-0x02232,-0x02325,-0x02402,-0x024C7,-0x02570, - -0x025FE,-0x0266D,-0x026BB,-0x026E6,-0x026ED,-0x026CE,-0x02686,-0x02615, - -0x02577,-0x024AC,-0x023B2,-0x02287,-0x0212B,-0x01F9B,-0x01DD7,-0x01BDD, - 0x019AE, 0x01747, 0x014A8, 0x011D1, 0x00EC0, 0x00B77, 0x007F5, 0x0043A, - 0x00046,-0x003E5,-0x00849,-0x00CE3,-0x011B4,-0x016B9,-0x01BF1,-0x0215B, - -0x026F6,-0x02CBE,-0x032B3,-0x038D3,-0x03F1A,-0x04586,-0x04C15,-0x052C4, - -0x05990,-0x06075,-0x06771,-0x06E80,-0x0759F,-0x07CCA,-0x083FE,-0x08B37, - -0x09270,-0x099A7,-0x0A0D7,-0x0A7FD,-0x0AF14,-0x0B618,-0x0BD05,-0x0C3D8, - -0x0CA8C,-0x0D11D,-0x0D789,-0x0DDC9,-0x0E3DC,-0x0E9BD,-0x0EF68,-0x0F4DB, - -0x0FA12,-0x0FF09,-0x103BD,-0x1082C,-0x10C53,-0x1102E,-0x113BD,-0x116FB, - -0x119E8,-0x11C82,-0x11EC6,-0x120B3,-0x12248,-0x12385,-0x12467,-0x124EF, - 0x1251E, 0x124F0, 0x12468, 0x12386, 0x12249, 0x120B4, 0x11EC7, 0x11C83, - 0x119E9, 0x116FC, 0x113BE, 0x1102F, 0x10C54, 0x1082D, 0x103BE, 0x0FF0A, - 0x0FA13, 0x0F4DC, 0x0EF69, 0x0E9BE, 0x0E3DD, 0x0DDCA, 0x0D78A, 0x0D11E, - 0x0CA8D, 0x0C3D9, 0x0BD06, 0x0B619, 0x0AF15, 0x0A7FE, 0x0A0D8, 0x099A8, - 0x09271, 0x08B38, 0x083FF, 0x07CCB, 0x075A0, 0x06E81, 0x06772, 0x06076, - 0x05991, 0x052C5, 0x04C16, 0x04587, 0x03F1B, 0x038D4, 0x032B4, 0x02CBF, - 0x026F7, 0x0215C, 0x01BF2, 0x016BA, 0x011B5, 0x00CE4, 0x0084A, 0x003E6, - -0x00045,-0x00439,-0x007F4,-0x00B76,-0x00EBF,-0x011D0,-0x014A7,-0x01746, - 0x019AE, 0x01BDE, 0x01DD8, 0x01F9C, 0x0212C, 0x02288, 0x023B3, 0x024AD, - 0x02578, 0x02616, 0x02687, 0x026CF, 0x026EE, 0x026E7, 0x026BC, 0x0266E, - 0x025FF, 0x02571, 0x024C8, 0x02403, 0x02326, 0x02233, 0x0212B, 0x02011, - 0x01EE6, 0x01DAD, 0x01C67, 0x01B17, 0x019BD, 0x0185D, 0x016F7, 0x0158D, - 0x01421, 0x012B4, 0x01149, 0x00FDF, 0x00E79, 0x00D17, 0x00BBC, 0x00A67, - 0x0091A, 0x007D6, 0x0069C, 0x0056C, 0x00447, 0x0032E, 0x00221, 0x00120, - 0x0002D,-0x000B8,-0x00191,-0x0025C,-0x00319,-0x003C9,-0x0046A,-0x004FF, - -0x00585,-0x005FE,-0x0066B,-0x006CA,-0x0071D,-0x00764,-0x0079F,-0x007CF, - 0x007F5, 0x0080F, 0x00820, 0x00827, 0x00825, 0x0081B, 0x00809, 0x007F0, - 0x007D1, 0x007AA, 0x0077F, 0x0074E, 0x00719, 0x006DF, 0x006A2, 0x00662, - 0x0061F, 0x005DA, 0x00594, 0x0054C, 0x00503, 0x004BA, 0x00471, 0x00428, - 0x003DF, 0x00397, 0x00350, 0x0030B, 0x002C7, 0x00285, 0x00245, 0x00207, - 0x001CB, 0x00191, 0x0015B, 0x00126, 0x000F4, 0x000C5, 0x00099, 0x0006F, - 0x00048, 0x00024, 0x00002,-0x0001C,-0x00038,-0x00052,-0x00069,-0x0007E, - -0x00091,-0x000A2,-0x000B0,-0x000BC,-0x000C7,-0x000CF,-0x000D6,-0x000DC, - -0x000DF,-0x000E2,-0x000E3,-0x000E3,-0x000E2,-0x000E0,-0x000DD,-0x000D9, - 0x000D5, 0x000D0, 0x000CA, 0x000C4, 0x000BE, 0x000B7, 0x000B0, 0x000A9, - 0x000A1, 0x0009A, 0x00093, 0x0008B, 0x00084, 0x0007D, 0x00075, 0x0006F, - 0x00068, 0x00061, 0x0005B, 0x00055, 0x0004F, 0x00049, 0x00044, 0x0003F, - 0x0003A, 0x00035, 0x00031, 0x0002D, 0x00029, 0x00026, 0x00023, 0x0001F, - 0x0001D, 0x0001A, 0x00018, 0x00015, 0x00013, 0x00011, 0x00010, 0x0000E, - 0x0000D, 0x0000B, 0x0000A, 0x00009, 0x00008, 0x00007, 0x00007, 0x00006, - 0x00005, 0x00005, 0x00004, 0x00004, 0x00003, 0x00003, 0x00002, 0x00002, - 0x00002, 0x00002, 0x00001, 0x00001, 0x00001, 0x00001, 0x00001, 0x00001 -}; -*/ - -// synthesis window -var D= [ - 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,-0x00001, - -0x00001,-0x00001,-0x00001,-0x00002,-0x00002,-0x00003,-0x00003,-0x00004, - -0x00004,-0x00005,-0x00006,-0x00006,-0x00007,-0x00008,-0x00009,-0x0000A, - -0x0000C,-0x0000D,-0x0000F,-0x00010,-0x00012,-0x00014,-0x00017,-0x00019, - -0x0001C,-0x0001E,-0x00022,-0x00025,-0x00028,-0x0002C,-0x00030,-0x00034, - -0x00039,-0x0003E,-0x00043,-0x00048,-0x0004E,-0x00054,-0x0005A,-0x00060, - -0x00067,-0x0006E,-0x00074,-0x0007C,-0x00083,-0x0008A,-0x00092,-0x00099, - -0x000A0,-0x000A8,-0x000AF,-0x000B6,-0x000BD,-0x000C3,-0x000C9,-0x000CF, - 0x000D5, 0x000DA, 0x000DE, 0x000E1, 0x000E3, 0x000E4, 0x000E4, 0x000E3, - 0x000E0, 0x000DD, 0x000D7, 0x000D0, 0x000C8, 0x000BD, 0x000B1, 0x000A3, - 0x00092, 0x0007F, 0x0006A, 0x00053, 0x00039, 0x0001D,-0x00001,-0x00023, - -0x00047,-0x0006E,-0x00098,-0x000C4,-0x000F3,-0x00125,-0x0015A,-0x00190, - -0x001CA,-0x00206,-0x00244,-0x00284,-0x002C6,-0x0030A,-0x0034F,-0x00396, - -0x003DE,-0x00427,-0x00470,-0x004B9,-0x00502,-0x0054B,-0x00593,-0x005D9, - -0x0061E,-0x00661,-0x006A1,-0x006DE,-0x00718,-0x0074D,-0x0077E,-0x007A9, - -0x007D0,-0x007EF,-0x00808,-0x0081A,-0x00824,-0x00826,-0x0081F,-0x0080E, - 0x007F5, 0x007D0, 0x007A0, 0x00765, 0x0071E, 0x006CB, 0x0066C, 0x005FF, - 0x00586, 0x00500, 0x0046B, 0x003CA, 0x0031A, 0x0025D, 0x00192, 0x000B9, - -0x0002C,-0x0011F,-0x00220,-0x0032D,-0x00446,-0x0056B,-0x0069B,-0x007D5, - -0x00919,-0x00A66,-0x00BBB,-0x00D16,-0x00E78,-0x00FDE,-0x01148,-0x012B3, - -0x01420,-0x0158C,-0x016F6,-0x0185C,-0x019BC,-0x01B16,-0x01C66,-0x01DAC, - -0x01EE5,-0x02010,-0x0212A,-0x02232,-0x02325,-0x02402,-0x024C7,-0x02570, - -0x025FE,-0x0266D,-0x026BB,-0x026E6,-0x026ED,-0x026CE,-0x02686,-0x02615, - -0x02577,-0x024AC,-0x023B2,-0x02287,-0x0212B,-0x01F9B,-0x01DD7,-0x01BDD, - 0x019AE, 0x01747, 0x014A8, 0x011D1, 0x00EC0, 0x00B77, 0x007F5, 0x0043A, - 0x00046,-0x003E5,-0x00849,-0x00CE3,-0x011B4,-0x016B9,-0x01BF1,-0x0215B, - -0x026F6,-0x02CBE,-0x032B3,-0x038D3,-0x03F1A,-0x04586,-0x04C15,-0x052C4, - -0x05990,-0x06075,-0x06771,-0x06E80,-0x0759F,-0x07CCA,-0x083FE,-0x08B37, - -0x09270,-0x099A7,-0x0A0D7,-0x0A7FD,-0x0AF14,-0x0B618,-0x0BD05,-0x0C3D8, - -0x0CA8C,-0x0D11D,-0x0D789,-0x0DDC9,-0x0E3DC,-0x0E9BD,-0x0EF68,-0x0F4DB, - -0x0FA12,-0x0FF09,-0x103BD,-0x1082C,-0x10C53,-0x1102E,-0x113BD,-0x116FB, - -0x119E8,-0x11C82,-0x11EC6,-0x120B3,-0x12248,-0x12385,-0x12467,-0x124EF, - 0x1251E, 0x124F0, 0x12468, 0x12386, 0x12249, 0x120B4, 0x11EC7, 0x11C83, - 0x119E9, 0x116FC, 0x113BE, 0x1102F, 0x10C54, 0x1082D, 0x103BE, 0x0FF0A, - 0x0FA13, 0x0F4DC, 0x0EF69, 0x0E9BE, 0x0E3DD, 0x0DDCA, 0x0D78A, 0x0D11E, - 0x0CA8D, 0x0C3D9, 0x0BD06, 0x0B619, 0x0AF15, 0x0A7FE, 0x0A0D8, 0x099A8, - 0x09271, 0x08B38, 0x083FF, 0x07CCB, 0x075A0, 0x06E81, 0x06772, 0x06076, - 0x05991, 0x052C5, 0x04C16, 0x04587, 0x03F1B, 0x038D4, 0x032B4, 0x02CBF, - 0x026F7, 0x0215C, 0x01BF2, 0x016BA, 0x011B5, 0x00CE4, 0x0084A, 0x003E6, - -0x00045,-0x00439,-0x007F4,-0x00B76,-0x00EBF,-0x011D0,-0x014A7,-0x01746, - 0x019AE, 0x01BDE, 0x01DD8, 0x01F9C, 0x0212C, 0x02288, 0x023B3, 0x024AD, - 0x02578, 0x02616, 0x02687, 0x026CF, 0x026EE, 0x026E7, 0x026BC, 0x0266E, - 0x025FF, 0x02571, 0x024C8, 0x02403, 0x02326, 0x02233, 0x0212B, 0x02011, - 0x01EE6, 0x01DAD, 0x01C67, 0x01B17, 0x019BD, 0x0185D, 0x016F7, 0x0158D, - 0x01421, 0x012B4, 0x01149, 0x00FDF, 0x00E79, 0x00D17, 0x00BBC, 0x00A67, - 0x0091A, 0x007D6, 0x0069C, 0x0056C, 0x00447, 0x0032E, 0x00221, 0x00120, - 0x0002D,-0x000B8,-0x00191,-0x0025C,-0x00319,-0x003C9,-0x0046A,-0x004FF, - -0x00585,-0x005FE,-0x0066B,-0x006CA,-0x0071D,-0x00764,-0x0079F,-0x007CF, - 0x007F5, 0x0080F, 0x00820, 0x00827, 0x00825, 0x0081B, 0x00809, 0x007F0, - 0x007D1, 0x007AA, 0x0077F, 0x0074E, 0x00719, 0x006DF, 0x006A2, 0x00662, - 0x0061F, 0x005DA, 0x00594, 0x0054C, 0x00503, 0x004BA, 0x00471, 0x00428, - 0x003DF, 0x00397, 0x00350, 0x0030B, 0x002C7, 0x00285, 0x00245, 0x00207, - 0x001CB, 0x00191, 0x0015B, 0x00126, 0x000F4, 0x000C5, 0x00099, 0x0006F, - 0x00048, 0x00024, 0x00002,-0x0001C,-0x00038,-0x00052,-0x00069,-0x0007E, - -0x00091,-0x000A2,-0x000B0,-0x000BC,-0x000C7,-0x000CF,-0x000D6,-0x000DC, - -0x000DF,-0x000E2,-0x000E3,-0x000E3,-0x000E2,-0x000E0,-0x000DD,-0x000D9, - 0x000D5, 0x000D0, 0x000CA, 0x000C4, 0x000BE, 0x000B7, 0x000B0, 0x000A9, - 0x000A1, 0x0009A, 0x00093, 0x0008B, 0x00084, 0x0007D, 0x00075, 0x0006F, - 0x00068, 0x00061, 0x0005B, 0x00055, 0x0004F, 0x00049, 0x00044, 0x0003F, - 0x0003A, 0x00035, 0x00031, 0x0002D, 0x00029, 0x00026, 0x00023, 0x0001F, - 0x0001D, 0x0001A, 0x00018, 0x00015, 0x00013, 0x00011, 0x00010, 0x0000E, - 0x0000D, 0x0000B, 0x0000A, 0x00009, 0x00008, 0x00007, 0x00007, 0x00006, - 0x00005, 0x00005, 0x00004, 0x00004, 0x00003, 0x00003, 0x00002, 0x00002, - 0x00002, 0x00002, 0x00001, 0x00001, 0x00001, 0x00001, 0x00001, 0x00001]; - -///////////// Table 3-B.2: Possible quantization per subband /////////////////// - -// quantizer lookup, step 1: bitrate classes -/* -static const char quant_lut_step1[2][16] = { - // 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384 <- bitrate - { 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, // mono - // 16, 24, 28, 32, 40, 48, 56, 64, 80, 96,112,128,160,192 <- BR / chan - { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2 } // stereo -}; -*/ -var quant_lut_step1= [ - [ 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2 ], - [ 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2 ]]; -/* -// quantizer lookup, step 2: bitrate class, sample rate -> B2 table idx, sblimit -#define QUANT_TAB_A (27 | 64) // Table 3-B.2a: high-rate, sblimit = 27 -#define QUANT_TAB_B (30 | 64) // Table 3-B.2b: high-rate, sblimit = 30 -#define QUANT_TAB_C 8 // Table 3-B.2c: low-rate, sblimit = 8 -#define QUANT_TAB_D 12 // Table 3-B.2d: low-rate, sblimit = 12 -*/ - -// quantizer lookup, step 2: bitrate class, sample rate -> B2 table idx, sblimit -var QUANT_TAB_A= (27 | 64); // Table 3-B.2a: high-rate, sblimit = 27 -var QUANT_TAB_B= (30 | 64); // Table 3-B.2b: high-rate, sblimit = 30 -var QUANT_TAB_C = 8; // Table 3-B.2c: low-rate, sblimit = 8 -var QUANT_TAB_D = 12 ; // Table 3-B.2d: low-rate, sblimit = 12 -/* -static const char quant_lut_step2[3][4] = { - // 44.1 kHz, 48 kHz, 32 kHz - { QUANT_TAB_C, QUANT_TAB_C, QUANT_TAB_D }, // 32 - 48 kbit/sec/ch - { QUANT_TAB_A, QUANT_TAB_A, QUANT_TAB_A }, // 56 - 80 kbit/sec/ch - { QUANT_TAB_B, QUANT_TAB_A, QUANT_TAB_B }, // 96+ kbit/sec/ch -}; -*/ -var quant_lut_step2 = [ - [ QUANT_TAB_C, QUANT_TAB_C, QUANT_TAB_D ], - [ QUANT_TAB_A, QUANT_TAB_A, QUANT_TAB_A ], - [ QUANT_TAB_B, QUANT_TAB_A, QUANT_TAB_B ]]; - -/* -// quantizer lookup, step 3: B2 table, subband -> nbal, row index -// (upper 4 bits: nbal, lower 4 bits: row index) -static const char quant_lut_step3[2][32] = { - // low-rate table (3-B.2c and 3-B.2d) - { 0x44,0x44, // SB 0 - 1 - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34 // SB 2 - 12 - }, - // high-rate table (3-B.2a and 3-B.2b) - { 0x43,0x43,0x43, // SB 0 - 2 - 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42, // SB 3 - 10 - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, // SB 11 - 22 - 0x20,0x20,0x20,0x20,0x20,0x20,0x20 // SB 23 - 29 - } -}; -*/ -// quantizer lookup, step 3: B2 table, subband -> nbal, row index -// (upper 4 bits: nbal, lower 4 bits: row index) -var quant_lut_step3 = [ - [ 0x44,0x44, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34 - ], - [ 0x43,0x43,0x43, - 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20 ]]; -/* -// quantizer lookup, step 4: table row, allocation[] value -> quant table index -static const char quant_lut_step4[5][16] = { - { 0, 1, 2, 17 }, - { 0, 1, 2, 3, 4, 5, 6, 17 }, - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17 }, - { 0, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }, - { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17 } -}; -*/ -// quantizer lookup, step 4: table row, allocation[] value -> quant table index -var quant_lut_step4 = [ - [ 0, 1, 2, 17 ], - [ 0, 1, 2, 3, 4, 5, 6, 17 ], - [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17 ], - [ 0, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 ], - [ 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17 ] ]; -// quantizer specification structure -/* -struct quantizer_spec { - unsigned short nlevels; - char grouping; - char cw_bits; - unsigned short Smul, Sdiv; -}; -*/ -/* -Have to change to function; -// quantizer specification structure -var quantizer_spec= { - nlevels: 0, - grouping: 0, - cw_bits:0 , - Smul: 0, Sdiv:0 }; -*/ - -var quantizer_spec=function(nlevels, grouping, cw_bits , Smul, Sdiv){ -return { - nlevels: nlevels, - grouping: grouping, - cw_bits: cw_bits, - Smul: Smul, - Sdiv: Sdiv }; -}; - -/* -// quantizer table -static const struct quantizer_spec quantizer_table[17] = { - { 3, 1, 5, 0x7FFF, 0xFFFF }, - { 5, 1, 7, 0x3FFF, 0x0002 }, - { 7, 0, 3, 0x2AAA, 0x0003 }, - { 9, 1, 10, 0x1FFF, 0x0002 }, - { 15, 0, 4, 0x1249, 0xFFFF }, - { 31, 0, 5, 0x0888, 0x0003 }, - { 63, 0, 6, 0x0421, 0xFFFF }, - { 127, 0, 7, 0x0208, 0x0009 }, - { 255, 0, 8, 0x0102, 0x007F }, - { 511, 0, 9, 0x0080, 0x0002 }, - { 1023, 0, 10, 0x0040, 0x0009 }, - { 2047, 0, 11, 0x0020, 0x0021 }, - { 4095, 0, 12, 0x0010, 0x0089 }, - { 8191, 0, 13, 0x0008, 0x0249 }, - { 16383, 0, 14, 0x0004, 0x0AAB }, - { 32767, 0, 15, 0x0002, 0x3FFF }, - { 65535, 0, 16, 0x0001, 0xFFFF } -}; -*/ - - -// quantizer table -var quantizer_table =[ - quantizer_spec ( 3, 1, 5, 0x7FFF, 0xFFFF ), - quantizer_spec ( 5, 1, 7, 0x3FFF, 0x0002 ), - quantizer_spec ( 7, 0, 3, 0x2AAA, 0x0003 ), - quantizer_spec ( 9, 1, 10, 0x1FFF, 0x0002 ), - quantizer_spec ( 15, 0, 4, 0x1249, 0xFFFF ), - quantizer_spec ( 31, 0, 5, 0x0888, 0x0003 ), - quantizer_spec ( 63, 0, 6, 0x0421, 0xFFFF ), - quantizer_spec ( 127, 0, 7, 0x0208, 0x0009 ), - quantizer_spec ( 255, 0, 8, 0x0102, 0x007F ), - quantizer_spec ( 511, 0, 9, 0x0080, 0x0002 ), - quantizer_spec ( 1023, 0, 10, 0x0040, 0x0009 ), - quantizer_spec ( 2047, 0, 11, 0x0020, 0x0021 ), - quantizer_spec ( 4095, 0, 12, 0x0010, 0x0089 ), - quantizer_spec ( 8191, 0, 13, 0x0008, 0x0249 ), - quantizer_spec ( 16383, 0, 14, 0x0004, 0x0AAB ), - quantizer_spec ( 32767, 0, 15, 0x0002, 0x3FFF ), - quantizer_spec ( 65535, 0, 16, 0x0001, 0xFFFF )]; - -//////////////////////////////////////////////////////////////////////////////// -// STATIC VARIABLES AND FUNCTIONS // -//////////////////////////////////////////////////////////////////////////////// -/* -#define KJMP2_MAGIC 0x32706D - -static int initialized = 0; -static int bit_window; -static int bits_in_window; -static const unsigned char *frame_pos; -*/ - - -var KJMP2_MAGIC= 0x32706D; - -var initialized = 0; -var bit_window; -var bits_in_window; -var frame_pos; -/* -#define show_bits(bit_count) (bit_window >> (24 - (bit_count))) - -static int FASTCALL get_bits(int bit_count) { - int result = show_bits(bit_count); - bit_window = (bit_window << bit_count) & 0xFFFFFF; - bits_in_window -= bit_count; - while (bits_in_window < 16) { - bit_window |= (*frame_pos++) << (16 - bits_in_window); - bits_in_window += 8; - } - return result; -} -*/ - -var show_bits=function(bit_count){return (bit_window >> (24 - (bit_count)))}; - -var get_bits=function(bit_count) { - var result = show_bits(bit_count); - bit_window = (bit_window << bit_count) & 0xFFFFFF; - bits_in_window -= bit_count; - while (bits_in_window < 16) { - bit_window = bit_window | (sys.peek(frame + frame_pos++) << (16 - bits_in_window)); - bits_in_window += 8; - } - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -// INITIALIZATION // -//////////////////////////////////////////////////////////////////////////////// -/* -static int N[64][32]; // N[i][j] as 8-bit fixed-point - -void kjmp2_init(kjmp2_context_t *mp2) { - int i, j; - // check if global initialization is required - if (!initialized) { - int *nptr = &N[0][0]; - // compute N[i][j] - for (i = 0; i < 64; ++i) - for (j = 0; j < 32; ++j) - *nptr++ = (int) (256.0 * cos(((16 + i) * ((j << 1) + 1)) * 0.0490873852123405)); - initialized = 1; - } - - // perform local initialization: clean the context and put the magic in it - for (i = 0; i < 2; ++i) - for (j = 1023; j >= 0; --j) - mp2->V[i][j] = 0; - mp2->Voffs = 0; - mp2->id = KJMP2_MAGIC; -} -*/ - - -var N=[]; -(function(){for(var i=0;i<64;i++){N.push([])}})(); - -var kjmp2_init=function(mp2) { - var i, j; - // check if global initialization is required - if (!initialized) { - var nptr = N; - // compute N[i][j] - for (i = 0; i < 64; ++i){ - for (j = 0; j < 32; ++j){ - nptr[i][j] = Math.floor(256.0 * Math.cos(((16 + i) * ((j << 1) + 1)) * 0.0490873852123405)); - } - } - initialized = 1; - } - - // perform local initialization: clean the context and put the magic in it - for (i = 0; i < 2; ++i){ - for (j = 1023; j >= 0; --j){ - mp2.V[i][j] = 0; - }; - }; - mp2.Voffs = 0; - mp2.id = KJMP2_MAGIC; -}; - -/* -int kjmp2_get_sample_rate(const unsigned char *frame) { - if (!frame) - return 0; - if ((frame[0] != 0xFF) // no valid syncword? - || (frame[1] != 0xFD) // no MPEG-1 Audio Layer II w/o redundancy? - || ((frame[2] - 0x10) >= 0xE0)) // invalid bitrate? - return 0; - return sample_rates[(frame[2] >> 2) & 3]; -} -*/ - -var kjmp2_get_sample_rate=function(frame) { - if (frame == null){ - return 0;}; - if ((sys.peek(frame) != 0xFF) || (sys.peek(frame +1) != 0xFD) || ((sys.peek(frame +2) - 0x10) >= 0xE0)) { - return 0;}; - return sample_rates[(sys.peek(frame +2) >> 2) & 3]; -}; - -//////////////////////////////////////////////////////////////////////////////// -// DECODE HELPER FUNCTIONS // -//////////////////////////////////////////////////////////////////////////////// -/* -static const struct quantizer_spec* FASTCALL read_allocation(int sb, int b2_table) { - int table_idx = quant_lut_step3[b2_table][sb]; - table_idx = quant_lut_step4[table_idx & 15][get_bits(table_idx >> 4)]; - return table_idx ? (&quantizer_table[table_idx - 1]) : 0; -} -*/ - -var read_allocation=function(sb, b2_table) { - var table_idx = quant_lut_step3[b2_table][sb]; - table_idx = quant_lut_step4[table_idx & 15][get_bits(table_idx >> 4)]; - return table_idx ? (quantizer_table[table_idx - 1]) : 0; -} - -/* -static void FASTCALL read_samples(const struct quantizer_spec *q, int scalefactor, int *sample) { - int idx, adj; - register int val; - if (!q) { - // no bits allocated for this subband - sample[0] = sample[1] = sample[2] = 0; - return; - } - // resolve scalefactor - scalefactor = scf_value[scalefactor]; - - // decode samples - adj = q->nlevels; - if (q->grouping) { - // decode grouped samples - val = get_bits(q->cw_bits); - sample[0] = val % adj; - val /= adj; - sample[1] = val % adj; - sample[2] = val / adj; - } else { - // decode direct samples - for(idx = 0; idx < 3; ++idx) - sample[idx] = get_bits(q->cw_bits); - } - - // postmultiply samples - adj = ((adj + 1) >> 1) - 1; - for (idx = 0; idx < 3; ++idx) { - // step 1: renormalization to [-1..1] - val = adj - sample[idx]; - val = (val * q->Smul) + (val / q->Sdiv); - // step 2: apply scalefactor - sample[idx] = ( val * (scalefactor >> 12) // upper part - + ((val * (scalefactor & 4095) + 2048) >> 12)) // lower part - >> 12; // scale adjust - } -} -*/ - - -var read_samples=function(q,scalefactor, sample) { -var idx, adj; -var val; - if (!q) { - // no bits allocated for this subband - sample[0] = sample[1] = sample[2] = 0; - return; - } - // resolve scalefactor - scalefactor = scf_value[scalefactor]; - - // decode samples - adj = q.nlevels; - if (q.grouping) { - // decode grouped samples - val = get_bits(q.cw_bits); - sample[0] = val % adj; - val = Math.floor(val/adj); - sample[1] = val % adj; - sample[2] = Math.floor(val / adj); - } else { - // decode direct samples - for(idx = 0; idx < 3; ++idx) - sample[idx] = get_bits(q.cw_bits); - } - - // postmultiply samples - adj = ((adj + 1) >> 1) - 1; - for (idx = 0; idx < 3; ++idx) { - // step 1: renormalization to [-1..1] - val = adj - sample[idx]; - val = (val * q.Smul) + Math.floor(val / q.Sdiv); - // step 2: apply scalefactor - sample[idx] = ( val * (scalefactor >> 12) + ((val * (scalefactor & 4095) + 2048) >> 12)) >> 12; // scale adjust - } -} - -//////////////////////////////////////////////////////////////////////////////// -// FRAME DECODE FUNCTION // -//////////////////////////////////////////////////////////////////////////////// -/* -static const struct quantizer_spec *allocation[2][32]; -static int scfsi[2][32]; -static int scalefactor[2][32][3]; -static int sample[2][32][3]; -static int U[512]; -*/ - -var allocation=[[],[]]; -var scfsi=[[],[]]; -var scalefactor=[[],[]]; -(function(){ - -for(var j=0;j<2;j++){ -for(var i=0;i<32;i++){ - scalefactor[j][i]=[[],[],[]]; -} -} -})(); -var sample=[[],[]]; -(function(){ - -for(var j=0;j<2;j++){ -for(var i=0;i<32;i++){ - sample[j][i]=[[],[],[]]; -} -} -})(); -var U=[]; - -var kjmp2_decode_frame=function(mp2,fr,pcm,outL,outR) { - - let pushSizeL = 0 - let pushSizeR = 0 - function pushL(sampleL) { - sys.poke(outL + pushSizeL + 0, (sampleL & 255)) - sys.poke(outL + pushSizeL + 1, (sampleL >>> 8)) - pushSizeL += 2 - } - function pushR(sampleR) { - sys.poke(outR + pushSizeR + 0, (sampleR & 255)) - sys.poke(outR + pushSizeR + 1, (sampleR >>> 8)) - pushSizeR += 2 - } - - - if (fr == null) { - throw Error("Frame is null") - } - frame=fr; - var bit_rate_index_minus1; - var sampling_frequency; - var padding_bit; - var mode; - var frame_size; - var bound, sblimit; - var sb, ch, gr, part, idx, nch, i, j, sum; - var table_idx; - // general sanity check - if (!initialized || !mp2 || (mp2.id !== KJMP2_MAGIC)){ - throw Error("MP2 not initialised") - }; - // check for valid header: syncword OK, MPEG-Audio Layer 2 - if ((sys.peek(frame) != 0xFF) || ((sys.peek(frame +1) & 0xFE) != 0xFC)){ - throw Error("Invalid header") - }; - - // set up the bitstream reader - bit_window = sys.peek(frame +2) << 16; - bits_in_window = 8; - frame_pos = 3; - - // read the rest of the header - bit_rate_index_minus1 = get_bits(4) - 1; - if (bit_rate_index_minus1 > 13){ - throw Error("Invalid bit rate") // invalid bit rate or 'free format' - }; - sampling_frequency = get_bits(2); - if (sampling_frequency === 3){ - throw Error("Invalid sampling frequency") - }; - padding_bit = get_bits(1); - get_bits(1); // discard private_bit - mode = get_bits(2); - - // parse the mode_extension, set up the stereo bound - if (mode === JOINT_STEREO) { - bound = (get_bits(2) + 1) << 2; - } else { - get_bits(2); - bound = (mode === MONO) ? 0 : 32; - } - - // discard the last 4 bits of the header and the CRC value, if present - get_bits(4); - if ((sys.peek(frame +1) & 1) == 0) - get_bits(16); - - // compute the frame size - frame_size = Math.floor(144000 * bitrates[bit_rate_index_minus1] / sample_rates[sampling_frequency]) + padding_bit; - if (!pcm){ - return [frame_size, pushSizeL]; // no decoding - }; - - // prepare the quantizer table lookups - table_idx = (mode === MONO) ? 0 : 1; - table_idx = quant_lut_step1[table_idx][bit_rate_index_minus1]; - table_idx = quant_lut_step2[table_idx][sampling_frequency]; - sblimit = table_idx & 63; - table_idx >>= 6; - if (bound > sblimit){ - bound = sblimit; - }; - // read the allocation information - for (sb = 0; sb < bound; ++sb){ - for (ch = 0; ch < 2; ++ch){ - allocation[ch][sb] = read_allocation(sb, table_idx); - }; - }; - - for (sb = bound; sb < sblimit; ++sb){ - allocation[0][sb] = allocation[1][sb] = read_allocation(sb, table_idx); - }; - - // read scale factor selector information - nch = (mode === MONO) ? 1 : 2; - for (sb = 0; sb < sblimit; ++sb) { - for (ch = 0; ch < nch; ++ch){ - if (allocation[ch][sb]){ - scfsi[ch][sb] = get_bits(2); - }; - } - if (mode === MONO){ - scfsi[1][sb] = scfsi[0][sb]; - }; - }; - // read scale factors - for (sb = 0; sb < sblimit; ++sb) { - for (ch = 0; ch < nch; ++ch) - if (allocation[ch][sb]) { - switch (scfsi[ch][sb]) { - case 0: scalefactor[ch][sb][0] = get_bits(6); - scalefactor[ch][sb][1] = get_bits(6); - scalefactor[ch][sb][2] = get_bits(6); - break; - case 1: scalefactor[ch][sb][0] = - scalefactor[ch][sb][1] = get_bits(6); - scalefactor[ch][sb][2] = get_bits(6); - break; - case 2: scalefactor[ch][sb][0] = - scalefactor[ch][sb][1] = - scalefactor[ch][sb][2] = get_bits(6); - break; - case 3: scalefactor[ch][sb][0] = get_bits(6); - scalefactor[ch][sb][1] = - scalefactor[ch][sb][2] = get_bits(6); - break; - } - } - if (mode == MONO){ - for (part = 0; part < 3; ++part){ - scalefactor[1][sb][part] = scalefactor[0][sb][part]; - }; - }; - } -// let ppcm=0; - // coefficient input and reconstruction - for (part = 0; part < 3; ++part){ - for (gr = 0; gr < 4; ++gr) { - - // read the samples - for (sb = 0; sb < bound; ++sb){ - for (ch = 0; ch < 2; ++ch){ - read_samples(allocation[ch][sb], scalefactor[ch][sb][part], sample[ch][sb]); - }; - }; - for (sb = bound; sb < sblimit; ++sb) { - read_samples(allocation[0][sb], scalefactor[0][sb][part], sample[0][sb]); - - for (idx = 0; idx < 3; ++idx){ - sample[1][sb][idx] = sample[0][sb][idx]; - }; - }; - for (ch = 0; ch < 2; ++ch){ - for (sb = sblimit; sb < 32; ++sb){ - for (idx = 0; idx < 3; ++idx){ - sample[ch][sb][idx] = 0; - }; - }; - }; - - // synthesis loop - for (idx = 0; idx < 3; ++idx) { - // shifting step - mp2.Voffs = table_idx = (mp2.Voffs - 64) & 1023; - - for (ch = 0; ch < 2; ++ch) { - // matrixing - for (i = 0; i < 64; ++i) { - sum = 0; - for (j = 0; j < 32; ++j) - sum += N[i][j] * sample[ch][j][idx]; // 8b*15b=23b - // intermediate value is 28 bit (23 + 5), clamp to 14b - mp2.V[ch][table_idx + i] = (sum + 8192) >> 14; - } - - // construction of U - for (i = 0; i < 8; ++i){ - for (j = 0; j < 32; ++j) { - U[(i << 6) + j] = mp2.V[ch][(table_idx + (i << 7) + j ) & 1023]; - U[(i << 6) + j + 32] = mp2.V[ch][(table_idx + (i << 7) + j + 96) & 1023]; - }; - }; - // apply window - for (i = 0; i < 512; ++i){ - U[i] = (U[i] * D[i] + 32) >> 6; - }; - // output samples - for (j = 0; j < 32; ++j) { - sum = 0; - for (i = 0; i < 16; ++i){ - sum -= U[(i << 5) + j]; - }; - sum = (sum + 8) >> 4; - if (sum < -32768) {sum = -32768}; - if (sum > 32767) {sum = 32767}; - if (ch == 0) { pushL(sum) } - if (ch == 1) { pushR(sum) } - } - } // end of synthesis channel loop - } // end of synthesis sub-block loop - - - - // adjust PCM output pointer: decoded 3 * 32 = 96 stereo samples -// ppcm += 192; - - } // decoding of the granule finished - } - if (pushSizeL != pushSizeR && pushSizeR > 0) { - throw Error(`Push size mismatch -- U${pushSizeL} != R${pushSizeR}`) - } - serial.println(pushSizeL) - return [frame_size, pushSizeL]; -// return [frame_size, 2304]; -}; - -var kjmp2_make_mp2_state=function(){ -return {id: null, V:[[],[]], - Voffs: null}; - -}; - -exports={kjmp2_decode_frame: kjmp2_decode_frame ,kjmp2_get_sample_rate: kjmp2_get_sample_rate,kjmp2_init: kjmp2_init, kjmp2_get_sample_rate: kjmp2_get_sample_rate, kjmp2_make_mp2_state: kjmp2_make_mp2_state }; - diff --git a/assets/disk0/tvdos/include/seqread.js b/assets/disk0/tvdos/include/seqread.js index d6287ba..96b5971 100644 --- a/assets/disk0/tvdos/include/seqread.js +++ b/assets/disk0/tvdos/include/seqread.js @@ -1,6 +1,7 @@ let readCount = 0 let port = undefined +let fileHeader = new Uint8Array(4096) function prepare(fullPath) { if (fullPath[2] != '/' && fullPath[2] != '\\') throw Error("Expected full path with drive letter, got " + fullPath) @@ -33,6 +34,14 @@ function prepare(fullPath) { throw Error("READ failed with "+statusCode) return statusCode } + + sys.poke(-4093 - port, 6);sys.sleep(0) + + for (let i = 0; i < 4096; i++) { + fileHeader[i] = sys.peek(-4097 - port*4096 - i) + } + + return 0 } function readBytes(length, ptrToDecode) { @@ -50,7 +59,7 @@ function readBytes(length, ptrToDecode) { if (readCount % 4096 == 0) { // serial.println("READ from serial") // pull the actual message - sys.poke(-4093 - port, 6);sys.sleep(0) // spinning is required as Graal run is desynced with the Java side + if (readCount > 0) { sys.poke(-4093 - port, 6);sys.sleep(0) } // spinning is required as Graal run is desynced with the Java side let blockTransferStatus = ((sys.peek(-4085 - port*2) & 255) | ((sys.peek(-4086 - port*2) & 255) << 8)) let thisBlockLen = blockTransferStatus & 4095 @@ -65,7 +74,7 @@ function readBytes(length, ptrToDecode) { // serial.println(`Pulled a block (${thisBlockLen}); readCount = ${readCount}, completedReads = ${completedReads}, remaining = ${remaining}`) // copy from read buffer to designated position - sys.memcpy(-4097, ptr + completedReads, remaining) + sys.memcpy(-4097 - port*4096, ptr + completedReads, remaining) // increment readCount properly readCount += remaining @@ -81,7 +90,7 @@ function readBytes(length, ptrToDecode) { // serial.println(`Reusing a block (${thisBlockLen}); readCount = ${readCount}, completedReads = ${completedReads}`) // copy from read buffer to designated position - sys.memcpy(-4097 - padding, ptr + completedReads, thisBlockLen) + sys.memcpy(-4097 - port*4096 - padding, ptr + completedReads, thisBlockLen) // increment readCount properly readCount += thisBlockLen @@ -134,4 +143,4 @@ function getReadCount() { return readCount } -exports = {prepare, readBytes, readInt, readShort, readFourCC, readString, skip, getReadCount} \ No newline at end of file +exports = {fileHeader, prepare, readBytes, readInt, readShort, readFourCC, readString, skip, getReadCount} \ No newline at end of file diff --git a/assets/disk0/tvdos/tuidev/zfm.js b/assets/disk0/tvdos/tuidev/zfm.js index 89af466..464c982 100644 --- a/assets/disk0/tvdos/tuidev/zfm.js +++ b/assets/disk0/tvdos/tuidev/zfm.js @@ -25,8 +25,8 @@ const COL_HL_EXT = { "bat": 215, "wav": 31, "adpcm": 31, - "pcm": 33, - "mp3": 34, + "pcm": 32, + "mp3": 33, "mp2": 34, "mov": 213, "ipf1": 190, @@ -39,6 +39,7 @@ const EXEC_FUNS = { "wav": (f) => _G.shell.execute(`playwav ${f} /i`), "adpcm": (f) => _G.shell.execute(`playwav ${f} /i`), "mp3": (f) => _G.shell.execute(`playmp3 ${f} /i`), + "mp2": (f) => _G.shell.execute(`playmp2 ${f} /i`), "mov": (f) => _G.shell.execute(`playmov ${f} /i`), "pcm": (f) => _G.shell.execute(`playpcm ${f} /i`), "ipf1": (f) => _G.shell.execute(`decodeipf ${f} /i`), diff --git a/tsvm_core/src/net/torvald/tsvm/AudioJSR223Delegate.kt b/tsvm_core/src/net/torvald/tsvm/AudioJSR223Delegate.kt index d156a35..845a97e 100644 --- a/tsvm_core/src/net/torvald/tsvm/AudioJSR223Delegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/AudioJSR223Delegate.kt @@ -80,6 +80,31 @@ class AudioJSR223Delegate(private val vm: VM) { + /* + js-mp3 + https://github.com/soundbus-technologies/js-mp3 + + Copyright (c) 2018 SoundBus Technologies CO., LTD. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + private val synthNWin = Array(64) { i -> FloatArray(32) { j -> cos(((16 + i) * (2 * j + 1)) * (Math.PI / 64.0)).toFloat() } } private val synthDtbl = floatArrayOf( 0.000000000f, -0.000015259f, -0.000015259f, -0.000015259f, @@ -408,6 +433,48 @@ class AudioJSR223Delegate(private val vm: VM) { + + /* + mp2dec.js JavaScript MPEG-1 Audio Layer II decoder + Copyright (C) 2011 Liam Wilson + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/. + */ + /* Note this is a port of kjmp2 by Martin J. Fiedler: */ + + /****************************************************************************** + ** kjmp2 -- a minimal MPEG-1 Audio Layer II decoder library ** + ******************************************************************************* + ** Copyright (C) 2006 Martin J. Fiedler martin.fiedler@gmx.net ** + ** ** + ** This software is provided 'as-is', without any express or implied ** + ** warranty. In no event will the authors be held liable for any damages ** + ** arising from the use of this software. ** + ** ** + ** Permission is granted to anyone to use this software for any purpose, ** + ** including commercial applications, and to alter it and redistribute it ** + ** freely, subject to the following restrictions: ** + ** 1. The origin of this software must not be misrepresented; you must not ** + ** claim that you wrote the original software. If you use this software ** + ** in a product, an acknowledgment in the product documentation would ** + ** be appreciated but is not required. ** + ** 2. Altered source versions must be plainly marked as such, and must not ** + ** be misrepresented as being the original software. ** + ** 3. This notice may not be removed or altered from any source ** + ** distribution. ** + ******************************************************************************/ + private var mp2_frame: Long? = null; // ptr private var STEREO=0; // #define JOINT_STEREO 1 @@ -563,7 +630,6 @@ class AudioJSR223Delegate(private val vm: VM) { var V: Array = Array(2) { IntArray(1024) } ) - fun createNewMP2context() = MP2() private fun show_bits(bit_count: Int) = (mp2_bit_window shr (24 - (bit_count))); private fun get_bits(bit_count: Int): Int { @@ -577,7 +643,9 @@ class AudioJSR223Delegate(private val vm: VM) { return result; } - fun kjmp2_init(mp2: MP2) { + fun mp2Init(): MP2 { + val mp2 = MP2() + // check if global initialization is required if (!mp2_initialized) { mp2_initialized = true; @@ -591,6 +659,8 @@ class AudioJSR223Delegate(private val vm: VM) { }; mp2.Voffs = 0; mp2.id = KJMP2_MAGIC; + + return mp2 }; private fun kjmp2_get_sample_rate(frame: Long?): Int { @@ -652,9 +722,26 @@ class AudioJSR223Delegate(private val vm: VM) { private var mp2_sample = Array(2) { Array(32) { IntArray(3) } } + fun mp2GetInitialFrameSize(bytes: IntArray): Int { + val b0 = bytes[0] + val b1 = bytes[1] + val b2 = bytes[2] + // check sync pattern + if ((b0 != 0xFF) || (b1 != 0xFD) || ((b2 - 0x10) >= 0xE0)) { + throw Error("Not a MP2 Frame Head: ${listOf(b0, b1, b2).map { it.toString(16).padStart(2,'0') }.joinToString(" ")}") + } - fun kjmp2_decode_frame(mp2: MP2, framePtr: Long?, pcm: Boolean, outL: Long, outR: Long): IntArray { + val sampling_frequency = (b2 shr 2) and 3 + val bit_rate_index_minus1 = ((b2 shr 4) and 15) - 1 + if (bit_rate_index_minus1 > 13){ + throw Error("Invalid bit rate") // invalid bit rate or 'free format' + } + val padding_bit = b2.shr(1) and 1 + return Math.floor(144000.0 * mp2_bitrates[bit_rate_index_minus1] / mp2_sample_rates[sampling_frequency]).toInt() + padding_bit + } + + fun mp2DecodeFrame(mp2: MP2, framePtr: Long?, pcm: Boolean, outL: Long, outR: Long): IntArray { var pushSizeL = 0 var pushSizeR = 0 @@ -880,7 +967,6 @@ class AudioJSR223Delegate(private val vm: VM) { if (pushSizeL != pushSizeR && pushSizeR > 0) { throw Error("Push size mismatch -- U${pushSizeL} != R${pushSizeR}") } - println(pushSizeL) return intArrayOf(frame_size, pushSizeL); // return intArrayOf(frame_size, 2304); };