Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

scratch-audio

Package Overview
Dependencies
Maintainers
1
Versions
435
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

scratch-audio - npm Package Compare versions

Comparing version 0.1.0-prerelease.20181023163139 to 0.1.0-prerelease.20181023202904

2

package.json
{
"name": "scratch-audio",
"version": "0.1.0-prerelease.20181023163139",
"version": "0.1.0-prerelease.20181023202904",
"description": "audio engine for scratch 3.0",

@@ -5,0 +5,0 @@ "main": "dist.js",

@@ -5,2 +5,54 @@ const ArrayBufferStream = require('./ArrayBufferStream');

/**
* Data used by the decompression algorithm
* @type {Array}
*/
const STEP_TABLE = [
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
];
/**
* Data used by the decompression algorithm
* @type {Array}
*/
const INDEX_TABLE = [
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
];
let _deltaTable = null;
/**
* Build a table of deltas from the 89 possible steps and 16 codes.
* @return {Array<number>} computed delta values
*/
const deltaTable = function () {
if (_deltaTable === null) {
const NUM_STEPS = STEP_TABLE.length;
const NUM_INDICES = INDEX_TABLE.length;
_deltaTable = new Array(NUM_STEPS * NUM_INDICES).fill(0);
let i = 0;
for (let index = 0; index < NUM_STEPS; index++) {
for (let code = 0; code < NUM_INDICES; code++) {
const step = STEP_TABLE[index];
let delta = 0;
if (code & 4) delta += step;
if (code & 2) delta += step >> 1;
if (code & 1) delta += step >> 2;
delta += step >> 3;
_deltaTable[i++] = (code & 8) ? -delta : delta;
}
}
}
return _deltaTable;
};
/**
* Decode wav audio files that have been compressed with the ADPCM format.

@@ -20,2 +72,3 @@ * This is necessary because, while web browsers have native decoders for many audio

}
/**

@@ -26,10 +79,3 @@ * Data used by the decompression algorithm

static get STEP_TABLE () {
return [
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
];
return STEP_TABLE;
}

@@ -42,6 +88,3 @@

static get INDEX_TABLE () {
return [
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
];
return INDEX_TABLE;
}

@@ -88,11 +131,8 @@

const samples = this.imaDecompress(this.extractChunk('data', stream), this.adpcmBlockSize);
const compressedData = this.extractChunk('data', stream);
const sampleCount = this.numberOfSamples(compressedData, this.adpcmBlockSize);
const buffer = this.audioContext.createBuffer(1, samples.length, this.samplesPerSecond);
const buffer = this.audioContext.createBuffer(1, sampleCount, this.samplesPerSecond);
this.imaDecompress(compressedData, this.adpcmBlockSize, buffer.getChannelData(0));
// @todo optimize this? e.g. replace the divide by storing 1/32768 and multiply?
for (let i = 0; i < samples.length; i++) {
buffer.getChannelData(0)[i] = samples[i] / 32768;
}
resolve(buffer);

@@ -123,2 +163,25 @@ });

/**
* Count the exact number of samples in the compressed data.
* @param {ArrayBufferStream} compressedData - the compressed data
* @param {number} blockSize - size of each block in the data in bytes
* @return {number} number of samples in the compressed data
*/
numberOfSamples (compressedData, blockSize) {
if (!compressedData) return 0;
compressedData.position = 0;
const available = compressedData.getBytesAvailable();
const blocks = (available / blockSize) | 0;
// Number of samples in full blocks.
const fullBlocks = blocks * (2 * (blockSize - 4)) + 1;
// Number of samples in the last incomplete block. 0 if the last block
// is full.
const subBlock = Math.max((available % blockSize) - 4, 0) * 2;
// 1 if the last block is incomplete. 0 if it is complete.
const incompleteBlock = Math.min(available % blockSize, 1);
return fullBlocks + subBlock + incompleteBlock;
}
/**
* Decompress sample data using the IMA ADPCM algorithm.

@@ -128,7 +191,6 @@ * Note: Handles only one channel, 4-bits per sample.

* @param {number} blockSize - the number of bytes in the stream
* @return {Int16Array} the uncompressed audio samples
* @param {Float32Array} out - the uncompressed audio samples
*/
imaDecompress (compressedData, blockSize) {
imaDecompress (compressedData, blockSize, out) {
let sample;
let step;
let code;

@@ -138,47 +200,54 @@ let delta;

let lastByte = -1; // -1 indicates that there is no saved lastByte
const out = [];
// Bail and return no samples if we have no data
if (!compressedData) return out;
if (!compressedData) return;
compressedData.position = 0;
// @todo Update this loop ported from Scratch 2.0 to use a condition or a for loop.
while (true) { // eslint-disable-line no-constant-condition
if (((compressedData.position % blockSize) === 0) && (lastByte < 0)) { // read block header
if (compressedData.getBytesAvailable() === 0) break;
sample = compressedData.readInt16();
index = compressedData.readUint8();
compressedData.position++; // skip extra header byte
if (index > 88) index = 88;
out.push(sample);
} else {
const size = out.length;
const samplesAfterBlockHeader = (blockSize - 4) * 2;
const DELTA_TABLE = deltaTable();
let i = 0;
while (i < size) {
// read block header
sample = compressedData.readInt16();
index = compressedData.readUint8();
compressedData.position++; // skip extra header byte
if (index > 88) index = 88;
out[i++] = sample / 32768;
const blockLength = Math.min(samplesAfterBlockHeader, size - i);
const blockStart = i;
while (i - blockStart < blockLength) {
// read 4-bit code and compute delta from previous sample
if (lastByte < 0) {
if (compressedData.getBytesAvailable() === 0) break;
lastByte = compressedData.readUint8();
code = lastByte & 0xF;
} else {
code = (lastByte >> 4) & 0xF;
lastByte = -1;
}
step = ADPCMSoundDecoder.STEP_TABLE[index];
delta = 0;
if (code & 4) delta += step;
if (code & 2) delta += step >> 1;
if (code & 1) delta += step >> 2;
delta += step >> 3;
lastByte = compressedData.readUint8();
code = lastByte & 0xF;
delta = DELTA_TABLE[index * 16 + code];
// compute next index
index += ADPCMSoundDecoder.INDEX_TABLE[code];
index += INDEX_TABLE[code];
if (index > 88) index = 88;
if (index < 0) index = 0;
else if (index < 0) index = 0;
// compute and output sample
sample += (code & 8) ? -delta : delta;
sample += delta;
if (sample > 32767) sample = 32767;
if (sample < -32768) sample = -32768;
out.push(sample);
else if (sample < -32768) sample = -32768;
out[i++] = sample / 32768;
// use 4-bit code from lastByte and compute delta from previous
// sample
code = (lastByte >> 4) & 0xF;
delta = DELTA_TABLE[index * 16 + code];
// compute next index
index += INDEX_TABLE[code];
if (index > 88) index = 88;
else if (index < 0) index = 0;
// compute and output sample
sample += delta;
if (sample > 32767) sample = 32767;
else if (sample < -32768) sample = -32768;
out[i++] = sample / 32768;
}
}
const samples = Int16Array.from(out);
return samples;
}

@@ -185,0 +254,0 @@ }

@@ -10,7 +10,49 @@ class ArrayBufferStream {

* @param {ArrayBuffer} arrayBuffer - array to use as a stream
* @param {number} start - the start position in the raw buffer. position
* will be relative to the start value.
* @param {number} end - the end position in the raw buffer. length and
* bytes available will be relative to the end value.
* @param {ArrayBufferStream} parent - if passed reuses the parent's
* internal objects
* @constructor
*/
constructor (arrayBuffer) {
constructor (
arrayBuffer, start = 0, end = arrayBuffer.byteLength,
{
_uint8View = new Uint8Array(arrayBuffer)
} = {}
) {
/**
* Raw data buffer for stream to read.
* @type {ArrayBufferStream}
*/
this.arrayBuffer = arrayBuffer;
this.position = 0;
/**
* Start position in arrayBuffer. Read values are relative to the start
* in the arrayBuffer.
* @type {number}
*/
this.start = start;
/**
* End position in arrayBuffer. Length and bytes available are relative
* to the start, end, and _position in the arrayBuffer;
* @type {number};
*/
this.end = end;
/**
* Cached Uint8Array view of the arrayBuffer. Heavily used for reading
* Uint8 values and Strings from the stream.
* @type {Uint8Array}
*/
this._uint8View = _uint8View;
/**
* Raw position in the arrayBuffer relative to the beginning of the
* arrayBuffer.
* @type {number}
*/
this._position = start;
}

@@ -24,5 +66,3 @@

extract (length) {
const slicedArrayBuffer = this.arrayBuffer.slice(this.position, this.position + length);
const newStream = new ArrayBufferStream(slicedArrayBuffer);
return newStream;
return new ArrayBufferStream(this.arrayBuffer, this._position, this._position + length, this);
}

@@ -34,3 +74,3 @@

getLength () {
return this.arrayBuffer.byteLength;
return this.end - this.start;
}

@@ -42,6 +82,25 @@

getBytesAvailable () {
return (this.arrayBuffer.byteLength - this.position);
return this.end - this._position;
}
/**
* Position relative to the start value in the arrayBuffer of this
* ArrayBufferStream.
* @type {number}
*/
get position () {
return this._position - this.start;
}
/**
* Set the position to read from in the arrayBuffer.
* @type {number}
* @param {number} value - new value to set position to
*/
set position (value) {
this._position = value + this.start;
return value;
}
/**
* Read an unsigned 8 bit integer from the stream

@@ -51,4 +110,4 @@ * @return {number} the next 8 bit integer in the stream

readUint8 () {
const val = new Uint8Array(this.arrayBuffer, this.position, 1)[0];
this.position += 1;
const val = this._uint8View[this._position];
this._position += 1;
return val;

@@ -64,8 +123,9 @@ }

readUint8String (length) {
const arr = new Uint8Array(this.arrayBuffer, this.position, length);
this.position += length;
const arr = this._uint8View;
let str = '';
for (let i = 0; i < arr.length; i++) {
const end = this._position + length;
for (let i = this._position; i < end; i++) {
str += String.fromCharCode(arr[i]);
}
this._position += length;
return str;

@@ -79,4 +139,4 @@ }

readInt16 () {
const val = new Int16Array(this.arrayBuffer, this.position, 1)[0];
this.position += 2; // one 16 bit int is 2 bytes
const val = new Int16Array(this.arrayBuffer, this._position, 1)[0];
this._position += 2; // one 16 bit int is 2 bytes
return val;

@@ -90,4 +150,4 @@ }

readUint16 () {
const val = new Uint16Array(this.arrayBuffer, this.position, 1)[0];
this.position += 2; // one 16 bit int is 2 bytes
const val = new Uint16Array(this.arrayBuffer, this._position, 1)[0];
this._position += 2; // one 16 bit int is 2 bytes
return val;

@@ -101,4 +161,4 @@ }

readInt32 () {
const val = new Int32Array(this.arrayBuffer, this.position, 1)[0];
this.position += 4; // one 32 bit int is 4 bytes
const val = new Int32Array(this.arrayBuffer, this._position, 1)[0];
this._position += 4; // one 32 bit int is 4 bytes
return val;

@@ -112,4 +172,4 @@ }

readUint32 () {
const val = new Uint32Array(this.arrayBuffer, this.position, 1)[0];
this.position += 4; // one 32 bit int is 4 bytes
const val = new Uint32Array(this.arrayBuffer, this._position, 1)[0];
this._position += 4; // one 32 bit int is 4 bytes
return val;

@@ -116,0 +176,0 @@ }

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc