diff --git a/cmd/audio-player/adpcm.js b/cmd/audio-player/adpcm.js index 784145b7..eb11bd26 100644 --- a/cmd/audio-player/adpcm.js +++ b/cmd/audio-player/adpcm.js @@ -61,9 +61,10 @@ class Decoder { ]; } - static get byteDepth() { return 2; } // We are working with 16-bit samples. TODO(Trek): make configurable. - static get headSize() { return 8; } // Number of bytes in the header of ADPCM. - static get chunkLenSize() { return 4; } + static get byteDepth() { return 2; } // We are working with 16-bit samples. TODO(Trek): make configurable. + static get headSize() { return 8; } // Number of bytes in the header of ADPCM. + static get chunkLenSize() { return 4; } // Length in bytes of the chunk length field in header. + static get compFact() { return 4; } // In general ADPCM compresses by a factor of 4. // decodeSample takes 4 bits which represents a single ADPCM nibble, and returns a 16 bit decoded PCM sample. decodeSample(nibble) { @@ -152,4 +153,27 @@ class Decoder { (b[2] << 16) | (b[3] << 24)); } + + // decBytes takes a parameter that is assumed to be a byte array containing one or more adpcm chunks. + // It reads the chunk lengths from the chunk headers to calculate and return the number of pcm bytes that are expected to be decoded from the adpcm. + static decBytes(b){ + let chunkLen; + let n = 0; + for (let off = 0; off + Decoder.headSize <= b.length; off += chunkLen) { + chunkLen = Decoder.bytesToInt32(b.slice(off, off + Decoder.chunkLenSize)) + if (off + chunkLen > b.length) { + break; + } + + // Account for uncompressed sample in header. + n += Decoder.byteDepth; + // Account for PCM bytes that will result from decoding ADPCM. + n += (chunkLen - Decoder.headSize)*Decoder.compFact; + // Account for padding. + if(b[off+Decoder.chunkLenSize+3] == 0x01){ + n -= Decoder.byteDepth; + } + } + return n; + } } \ No newline at end of file