Comparing version 2.0.0-alpha.0 to 2.0.0-alpha.2
@@ -1,4 +0,4 @@ | ||
window.imaadpcm=function(n){function g(d){if(h[d])return h[d].a;var f=h[d]={m:d,f:!1,a:{}};n[d].call(f.a,f,f.a,g);f.f=!0;return f.a}var h={};g.l=n;g.h=h;g.b=function(d,f){g.c(d)||Object.defineProperty(d,"a",{configurable:!1,enumerable:!0,get:f})};g.i=function(d){var f=d&&d.g?function(){return d["default"]}:function(){return d};g.b(f,f);return f};g.c=function(d){return Object.prototype.hasOwnProperty.call(d,"a")};g.j="";return g(g.o=0)}([function(n){function g(b){return 32768<b?b-65536:b}function h(b){var a= | ||
b-k;0<=a?b=0:(b=8,a=-a);var c=r[p],e=c>>3;a>c&&(b|=4,a-=c,e+=c);c>>=1;a>c&&(b|=2,a-=c,e+=c);c>>=1;a>c&&(b|=1,e+=c);a=b;k=a&8?k-e:k+e;-32768>k?k=-32768:32767<k&&(k=32767);p+=t[a&7];0>p?p=0:88<p&&(p=88);return b}function d(b){var a=0;b&4&&(a+=q);b&2&&(a+=q>>1);b&1&&(a+=q>>2);a+=q>>3;b&8&&(a=-a);l+=a;32767<l?l=32767:-32767>l&&(l=-32767);m+=t[b];0>m?m=0:88<m&&(m=88);q=r[m];return l}function f(b){var a=b[0];h(a);var c=[];c.push(a&255);c.push(a>>8&255);c.push(p);c.push(0);for(a=3;a<b.length;a+=2){var e= | ||
h(b[a]),d=h(b[a+1]);c.push(d<<4|e)}for(;256>c.length;)c.push(0);return c}function u(b){l=g(b[1]<<8|b[0]);m=b[2];q=r[m];for(var a=[l,g(b[3]<<8|b[2])],c=4;c<b.length;c++){var e=b[c],f=e>>4;a.push(d(f<<4^e));a.push(d(f))}return a}var t=[-1,-1,-1,-1,2,4,6,8,-1,-1,-1,-1,2,4,6,8],r=[7,8,9,10,11,12,13,14,16,17,19,21,23,25,28,31,34,37,41,45,50,55,60,66,73,80,88,97,107,118,130,143,157,173,190,209,230,253,279,307,337,371,408,449,494,544,598,658,724,796,876,963,1060,1166,1282,1411,1552,1707,1878,2066,2272,2499, | ||
2749,3024,3327,3660,4026,4428,4871,5358,5894,6484,7132,7845,8630,9493,10442,11487,12635,13899,15289,16818,18500,20350,22385,24623,27086,29794,32767],k=0,p=0,l=0,m=0,q=7;n.a.encode=function(b){for(var a=[],c=[],e=0;e<b.length;e++)if(c.push(b[e]),0==e%505&&0!=e||e==b.length-1)a=a.concat(f(c)),c=[];return a};n.a.decode=function(b,a){a=void 0===a?256:a;for(var c=[],e=[],d=0;d<b.length;d++)0==d%a&&0!=d&&(c=c.concat(u(e)),e=[]),e.push(b[d]);return c};n.a.encodeBlock=f;n.a.decodeBlock=u}]); | ||
window.imaadpcm=function(m){function g(d){if(n[d])return n[d].a;var f=n[d]={m:d,f:!1,a:{}};m[d].call(f.a,f,f.a,g);f.f=!0;return f.a}var n={};g.l=m;g.h=n;g.b=function(d,f){g.c(d)||Object.defineProperty(d,"a",{configurable:!1,enumerable:!0,get:f})};g.i=function(d){var f=d&&d.g?function(){return d["default"]}:function(){return d};g.b(f,f);return f};g.c=function(d){return Object.prototype.hasOwnProperty.call(d,"a")};g.j="";return g(g.o=0)}([function(m){function g(b){var a=b[0];f(a);var c=[];c.push(a& | ||
255);c.push(a>>8&255);c.push(p);c.push(0);for(a=3;a<b.length;a+=2){var e=f(b[a]),d=f(b[a+1]);c.push(d<<4|e)}for(;256>c.length;)c.push(0);return c}function n(b){h=d(b[1]<<8|b[0]);k=b[2];q=r[k];for(var a=[h,d(b[3]<<8|b[2])],c=4;c<b.length;c++){var e=b[c],f=e>>4;a.push(t(f<<4^e));a.push(t(f))}return a}function d(b){return 32768<b?b-65536:b}function f(b){var a=b-l;0<=a?b=0:(b=8,a=-a);var c=r[p],e=c>>3;a>c&&(b|=4,a-=c,e+=c);c>>=1;a>c&&(b|=2,a-=c,e+=c);c>>=1;a>c&&(b|=1,e+=c);a=b;l=a&8?l-e:l+e;-32768>l? | ||
l=-32768:32767<l&&(l=32767);p+=u[a&7];0>p?p=0:88<p&&(p=88);return b}function t(b){var a=0;b&4&&(a+=q);b&2&&(a+=q>>1);b&1&&(a+=q>>2);a+=q>>3;b&8&&(a=-a);h+=a;32767<h?h=32767:-32767>h&&(h=-32767);k+=u[b];0>k?k=0:88<k&&(k=88);q=r[k];return h}var u=[-1,-1,-1,-1,2,4,6,8,-1,-1,-1,-1,2,4,6,8],r=[7,8,9,10,11,12,13,14,16,17,19,21,23,25,28,31,34,37,41,45,50,55,60,66,73,80,88,97,107,118,130,143,157,173,190,209,230,253,279,307,337,371,408,449,494,544,598,658,724,796,876,963,1060,1166,1282,1411,1552,1707,1878, | ||
2066,2272,2499,2749,3024,3327,3660,4026,4428,4871,5358,5894,6484,7132,7845,8630,9493,10442,11487,12635,13899,15289,16818,18500,20350,22385,24623,27086,29794,32767],l=0,p=0,h=0,k=0,q=7;m.a.encode=function(b){for(var a=[],c=[],e=0;e<b.length;e++)if(c.push(b[e]),0==e%505&&0!=e||e==b.length-1)a=a.concat(g(c)),c=[];return a};m.a.decode=function(b,a){a=void 0===a?256:a;for(var c=[],e=[],d=0;d<b.length;d++)0==d%a&&0!=d&&(c=c.concat(n(e)),e=[]),e.push(b[d]);return c};m.a.encodeBlock=g;m.a.decodeBlock=n}]); |
272
index.js
/* | ||
* imaadpcm | ||
* JavaScript IMA ADPCM codec. | ||
* Copyright (c) 2018 Rafael da Silva Rocha. | ||
* imaadpcm: IMA ADPCM codec in JavaScript. | ||
* https://github.com/rochars/imaadpcm | ||
* | ||
* References: | ||
* http://www.cs.columbia.edu/~hgs/audio/dvi/ | ||
* https://github.com/acida/pyima | ||
* https://wiki.multimedia.cx/index.php/IMA_ADPCM | ||
* | ||
* Copyright (c) 2017-2018 Rafael da Silva Rocha. | ||
* | ||
* 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 */ | ||
/** | ||
* @fileoverview imaadpcm public API and private methods. | ||
*/ | ||
/** @module imaadpcm */ | ||
/** | ||
* @type {!Array<number>} | ||
* @private | ||
*/ | ||
const INDEX_TABLE = [ | ||
-1, -1, -1, -1, 2, 4, 6, 8, | ||
-1, -1, -1, -1, 2, 4, 6, 8]; | ||
/** @private */ | ||
/** | ||
* @type {!Array<number>} | ||
* @private | ||
*/ | ||
const STEP_TABLE = [ | ||
@@ -32,16 +58,123 @@ 7, 8, 9, 10, 11, 12, 13, 14, | ||
32767]; | ||
/** @private */ | ||
var encoderPredicted_ = 0; | ||
/** @private */ | ||
var encoderIndex_ = 0; | ||
/** @private */ | ||
var encoderStep_ = 7; | ||
/** @private */ | ||
var decoderPredicted_ = 0; | ||
/** @private */ | ||
var decoderIndex_ = 0; | ||
/** @private */ | ||
var decoderStep_ = 7; | ||
/** | ||
* @type {number} | ||
* @private | ||
*/ | ||
let encoderPredicted_ = 0; | ||
/** | ||
* @type {number} | ||
* @private | ||
*/ | ||
let encoderIndex_ = 0; | ||
/** | ||
* @type {number} | ||
* @private | ||
*/ | ||
let encoderStep_ = 7; | ||
/** | ||
* @type {number} | ||
* @private | ||
*/ | ||
let decoderPredicted_ = 0; | ||
/** | ||
* @type {number} | ||
* @private | ||
*/ | ||
let decoderIndex_ = 0; | ||
/** | ||
* @type {number} | ||
* @private | ||
*/ | ||
let decoderStep_ = 7; | ||
/** | ||
* Encode 16-bit PCM samples into 4-bit IMA ADPCM samples. | ||
* @param {!Array<number>} samples A array of samples. | ||
* @return {!Array<number>} | ||
*/ | ||
function encode(samples) { | ||
/** @type {!Array<number>} */ | ||
let adpcmSamples = []; | ||
/** @type {Array<number>} */ | ||
let block = []; | ||
for (let i=0; i<samples.length; i++) { | ||
block.push(samples[i]); | ||
if ((i % 505 == 0 && i != 0) || i == samples.length - 1) { | ||
adpcmSamples = adpcmSamples.concat(encodeBlock(block)); | ||
block = []; | ||
} | ||
} | ||
return adpcmSamples; | ||
} | ||
/** | ||
* Decode IMA ADPCM samples into 16-bit PCM samples. | ||
* @param {!Array<number>} adpcmSamples A array of ADPCM samples. | ||
* @param {number} blockAlign The block size. | ||
* @return {!Array<number>} | ||
*/ | ||
function decode(adpcmSamples, blockAlign=256) { | ||
/** @type {!Array<number>} */ | ||
let samples = []; | ||
/** @type {!Array<number>} */ | ||
let block = []; | ||
for (let i=0; i<adpcmSamples.length; i++) { | ||
if (i % blockAlign == 0 && i != 0) { | ||
samples = samples.concat(decodeBlock(block)); | ||
block = []; | ||
} | ||
block.push(adpcmSamples[i]); | ||
} | ||
return samples; | ||
} | ||
/** | ||
* Encode a block of 505 16-bit samples as 4-bit ADPCM samples. | ||
* @param {!Array<number>} block A sample block of 505 samples. | ||
* @return {!Array<number>} | ||
*/ | ||
function encodeBlock(block) { | ||
/** @type {!Array<number>} */ | ||
let adpcmSamples = blockHead_(block[0]); | ||
for (let i=3; i<block.length; i+=2) { | ||
/** @type {number} */ | ||
let sample2 = encodeSample_(block[i]); | ||
/** @type {number} */ | ||
let sample = encodeSample_(block[i + 1]); | ||
adpcmSamples.push((sample << 4) | sample2); | ||
} | ||
while (adpcmSamples.length < 256) { | ||
adpcmSamples.push(0); | ||
} | ||
return adpcmSamples; | ||
} | ||
/** | ||
* Decode a block of ADPCM samples into 16-bit PCM samples. | ||
* @param {!Array<number>} block A adpcm sample block. | ||
* @return {!Array<number>} | ||
*/ | ||
function decodeBlock(block) { | ||
decoderPredicted_ = sign_((block[1] << 8) | block[0]); | ||
decoderIndex_ = block[2]; | ||
decoderStep_ = STEP_TABLE[decoderIndex_]; | ||
/** @type {!Array<number>} */ | ||
let result = [ | ||
decoderPredicted_, | ||
sign_((block[3] << 8) | block[2]) | ||
]; | ||
for (let i=4; i<block.length; i++) { | ||
/** @type {number} */ | ||
let original_sample = block[i]; | ||
/** @type {number} */ | ||
let second_sample = original_sample >> 4; | ||
/** @type {number} */ | ||
let first_sample = (second_sample << 4) ^ original_sample; | ||
result.push(decodeSample_(first_sample)); | ||
result.push(decodeSample_(second_sample)); | ||
} | ||
return result; | ||
} | ||
/** | ||
* Sign a 16-bit integer. | ||
@@ -89,3 +222,5 @@ * @param {number} num A 16-bit integer. | ||
function encodeSample_(sample) { | ||
/** @type {number} */ | ||
let delta = sample - encoderPredicted_; | ||
/** @type {number} */ | ||
let value = 0; | ||
@@ -98,3 +233,5 @@ if (delta >= 0) { | ||
} | ||
/** @type {number} */ | ||
let step = STEP_TABLE[encoderIndex_]; | ||
/** @type {number} */ | ||
let diff = step >> 3; | ||
@@ -128,2 +265,3 @@ if (delta > step) { | ||
function decodeSample_(nibble) { | ||
/** @type {number} */ | ||
let difference = 0; | ||
@@ -149,2 +287,12 @@ if (nibble & 4) { | ||
} | ||
updateDecoder_(nibble); | ||
return decoderPredicted_; | ||
} | ||
/** | ||
* Update the index and step after decoding a sample. | ||
* @param {number} nibble A 4-bit adpcm sample. | ||
* @private | ||
*/ | ||
function updateDecoder_(nibble) { | ||
decoderIndex_ += INDEX_TABLE[nibble]; | ||
@@ -157,3 +305,2 @@ if (decoderIndex_ < 0) { | ||
decoderStep_ = STEP_TABLE[decoderIndex_]; | ||
return decoderPredicted_; | ||
} | ||
@@ -169,2 +316,3 @@ | ||
encodeSample_(sample); | ||
/** @type {!Array<number>} */ | ||
let adpcmSamples = []; | ||
@@ -178,80 +326,2 @@ adpcmSamples.push(sample & 0xFF); | ||
/** | ||
* Encode a block of 505 16-bit samples as 4-bit ADPCM samples. | ||
* @param {!Array<number>} block A sample block of 505 samples. | ||
* @return {!Array<number>} | ||
*/ | ||
function encodeBlock(block) { | ||
let adpcmSamples = blockHead_(block[0]); | ||
for (let i=3; i<block.length; i+=2) { | ||
let sample2 = encodeSample_(block[i]); | ||
let sample = encodeSample_(block[i + 1]); | ||
adpcmSamples.push((sample << 4) | sample2); | ||
} | ||
while (adpcmSamples.length < 256) { | ||
adpcmSamples.push(0); | ||
} | ||
return adpcmSamples; | ||
} | ||
/** | ||
* Decode a block of 256 ADPCM samples into 16-bit PCM samples. | ||
* @param {!Array<number>} block A adpcm sample block of 256 samples. | ||
* @return {!Array<number>} | ||
*/ | ||
function decodeBlock(block) { | ||
decoderPredicted_ = sign_((block[1] << 8) | block[0]); | ||
decoderIndex_ = block[2]; | ||
decoderStep_ = STEP_TABLE[decoderIndex_]; | ||
let result = [ | ||
decoderPredicted_, | ||
sign_((block[3] << 8) | block[2]) | ||
]; | ||
for (let i=4; i<block.length; i++) { | ||
let original_sample = block[i]; | ||
let second_sample = original_sample >> 4; | ||
let first_sample = (second_sample << 4) ^ original_sample; | ||
result.push(decodeSample_(first_sample)); | ||
result.push(decodeSample_(second_sample)); | ||
} | ||
return result; | ||
} | ||
/** | ||
* Encode 16-bit PCM samples into 4-bit IMA ADPCM samples. | ||
* @param {!Array<number>} samples A array of samples. | ||
* @return {!Array<number>} | ||
*/ | ||
function encode(samples) { | ||
let adpcmSamples = []; | ||
let block = []; | ||
for (let i=0; i<samples.length; i++) { | ||
block.push(samples[i]); | ||
if ((i % 505 == 0 && i != 0) || i == samples.length - 1) { | ||
adpcmSamples = adpcmSamples.concat(encodeBlock(block)); | ||
block = []; | ||
} | ||
} | ||
return adpcmSamples; | ||
} | ||
/** | ||
* Decode IMA ADPCM samples into 16-bit PCM samples. | ||
* @param {!Array<number>} adpcmSamples A array of ADPCM samples. | ||
* @param {number} blockAlign The block size. | ||
* @return {!Array<number>} | ||
*/ | ||
function decode(adpcmSamples, blockAlign=256) { | ||
let samples = []; | ||
let block = []; | ||
for (let i=0; i<adpcmSamples.length; i++) { | ||
if (i % blockAlign == 0 && i != 0) { | ||
samples = samples.concat(decodeBlock(block)); | ||
block = []; | ||
} | ||
block.push(adpcmSamples[i]); | ||
} | ||
return samples; | ||
} | ||
/** @export */ | ||
@@ -258,0 +328,0 @@ module.exports.encode = encode; |
{ | ||
"name": "imaadpcm", | ||
"version": "2.0.0-alpha.0", | ||
"version": "2.0.0-alpha.2", | ||
"description": "IMA ADPCM codec in JavaScript.", | ||
"homepage": "https://github.com/rochars/imaadpcm", | ||
"author": "Rafael da Silva Rocha <rocha.rafaelsilva@gmail.com>", | ||
"author": "Rafael S. Rocha <rocha.rafaelsilva@gmail.com>", | ||
"license": "MIT", | ||
@@ -39,3 +39,3 @@ "keywords": [ | ||
"docdash": "^0.4.0", | ||
"google-closure-compiler-js": "^20170910.0.1", | ||
"google-closure-compiler-js": "^20180610.0.0", | ||
"jsdoc": "~3.5.5", | ||
@@ -42,0 +42,0 @@ "jshint": "^2.9.5", |
@@ -9,3 +9,3 @@ # imaadpcm | ||
## About | ||
IMA-ADPCM codec for Node.js and the browser. | ||
IMA ADPCM codec in JavaScript. | ||
@@ -29,5 +29,5 @@ ## Install | ||
## Use | ||
Files: | ||
### Files: | ||
```javascript | ||
const imaadpcm = require("imaadpcm"); | ||
@@ -48,15 +48,16 @@ | ||
Streaming: | ||
### Streaming: | ||
```javascript | ||
const imaadpcm = require("imaadpcm"); | ||
// Decompressing, blocks of 256 bytes assumed by default | ||
// Decompressing a ADPCM block | ||
// 256 block align is assumed by default | ||
samples = imaadpcm.decodeBlock(adpcm_block); | ||
// Decompressing using a different block size | ||
// Decompressing using a different block align (1024) | ||
samples = imaadpcm.decodeBlock(adpcm_block, 1024); | ||
// Compressing, only blocks of 505 samples | ||
// Only 16-bit samples are supported | ||
// Compressing PCM samples into a block of ADPCM samples | ||
// Only blocks of 505 samples are supported as input | ||
// Only 16-bit samples are supported as input | ||
adpcm_samples = imaadpcm.encodeBlock(sample_block); | ||
@@ -66,9 +67,9 @@ | ||
## In the browser | ||
### In the browser | ||
```html | ||
<script src="imaadpcm.min.js"></script> | ||
<script> | ||
adpcmSamples = imaadpcm.encode(pcmSamples); | ||
var adpcmSamples = imaadpcm.encode(pcmSamples); | ||
pcmSamples = imaadpcm.decode(adpcmSamples); | ||
adpcmBlock = imaadpcm.encodeBlock(pcmBlock); | ||
var adpcmBlock = imaadpcm.encodeBlock(pcmBlock); | ||
pcmBlock = imaadpcm.decodeBlock(adpcmBlock); | ||
@@ -78,2 +79,34 @@ </script> | ||
## API | ||
```javascript | ||
/** | ||
* Encode 16-bit PCM samples into 4-bit IMA ADPCM samples. | ||
* @param {!Array<number>} samples A array of samples. | ||
* @return {!Array<number>} | ||
*/ | ||
function encode(samples) {} | ||
/** | ||
* Decode IMA ADPCM samples into 16-bit PCM samples. | ||
* @param {!Array<number>} adpcmSamples A array of ADPCM samples. | ||
* @param {number} blockAlign The block size. | ||
* @return {!Array<number>} | ||
*/ | ||
function decode(adpcmSamples, blockAlign=256) {} | ||
/** | ||
* Encode a block of 505 16-bit samples as 4-bit ADPCM samples. | ||
* @param {!Array<number>} block A sample block of 505 samples. | ||
* @return {!Array<number>} | ||
*/ | ||
function encodeBlock(block) {} | ||
/** | ||
* Decode a block of ADPCM samples into 16-bit PCM samples. | ||
* @param {!Array<number>} block A adpcm sample block. | ||
* @return {!Array<number>} | ||
*/ | ||
function decodeBlock(block) {} | ||
``` | ||
## References | ||
@@ -80,0 +113,0 @@ http://www.cs.columbia.edu/~hgs/audio/dvi/ |
18088
318
132