From e6697b9de9d765e72c9d399eadf8ed0f03ebf134 Mon Sep 17 00:00:00 2001 From: Trek H Date: Sat, 10 Aug 2019 21:00:26 +0930 Subject: [PATCH] audio-player: added ability to decode consecutive chunks to js decoder. --- cmd/audio-player/adpcm.js | 69 ++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/cmd/audio-player/adpcm.js b/cmd/audio-player/adpcm.js index 6767452e..32d66d6b 100644 --- a/cmd/audio-player/adpcm.js +++ b/cmd/audio-player/adpcm.js @@ -30,7 +30,7 @@ LICENSE const indexTable = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8 -] +]; const stepTable = [ 7, 8, 9, 10, 11, 12, 13, 14, @@ -45,15 +45,11 @@ const stepTable = [ 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 -] +]; const byteDepth = 2, // We are working with 16-bit samples. TODO(Trek): make configurable. - initSamps = 2, // Number of samples used to initialise the encoder. - initBytes = initSamps * byteDepth, - headBytes = 4, // Number of bytes in the header of ADPCM. - samplesPerEnc = 2, // Number of sample encoded at a time eg. 2 16-bit samples get encoded into 1 byte. - bytesPerEnc = samplesPerEnc * byteDepth, - compFact = 4; // In general ADPCM compresses by a factor of 4. + headSize = 8, // Number of bytes in the header of ADPCM. + chunkLenSize = 4; let est = 0, // Estimation of sample based on quantised ADPCM nibble. idx = 0, // Index to step used for estimation. @@ -93,28 +89,40 @@ function decodeSample(nibble) { // decode takes an array of bytes of arbitrary length representing adpcm and decodes it into pcm. function decode(b) { - // Initialize Decoder with first 4 bytes of b. - est = bytesToInt16(b[0], b[1]); - idx = b[byteDepth]; - step = stepTable[idx]; + // Iterate over each chunk and decode it. + let chunkLen; + var result = []; + for (var off = 0; off + headSize <= b.length; off += chunkLen) { + // Read length of chunk and check if whole chunk exists. + chunkLen = bytesToInt32(b.slice(off, off + chunkLenSize)) + if (off + chunkLen > b.length) { + break; + } + console.log(b.length, chunkLen, off); - var result = b.slice(0, 2); + // Initialize Decoder with first 4 bytes of b. + est = bytesToInt16(b.slice(off + chunkLenSize, off + chunkLenSize + byteDepth)); + idx = b[off + chunkLenSize + byteDepth]; + step = stepTable[idx]; - for (var i = headBytes; i < b.length - b[3]; i++) { - var twoNibs = b[i]; - var nib2 = twoNibs >> 4; - var nib1 = (nib2 << 4) ^ twoNibs + result.push(...b.slice(off + chunkLenSize, off + chunkLenSize + byteDepth)); - var sample1 = int16ToBytes(decodeSample(nib1)) - result.push(...sample1) + for (var i = off + headSize; i < off + chunkLen - b[off + chunkLenSize + 3]; i++) { + var twoNibs = b[i]; + var nib2 = twoNibs >> 4; + var nib1 = (nib2 << 4) ^ twoNibs; - var sample2 = int16ToBytes(decodeSample(nib2)) - result.push(...sample2) - } - if (b[3] == 1) { - var padNib = b[b.length - 1] - var sample = int16ToBytes(decodeSample(padNib)) - result.push(...sample) + var sample1 = int16ToBytes(decodeSample(nib1)); + result.push(...sample1); + + var sample2 = int16ToBytes(decodeSample(nib2)); + result.push(...sample2); + } + if (b[off + chunkLenSize + 3] == 1) { + var padNib = b[off + chunkLen - 1]; + var sample = int16ToBytes(decodeSample(padNib)); + result.push(...sample); + } } return result; } @@ -124,5 +132,12 @@ function int16ToBytes(num) { } function bytesToInt16(b) { - return (b[0] | (b[1] << 8)) + return (b[0] | (b[1] << 8)); +} + +function bytesToInt32(b) { + return (b[0] | + (b[1] << 8) | + (b[2] << 16) | + (b[3] << 24)); } \ No newline at end of file