From 1a26fecca152f6f3c054d4b82297c56007413160 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Thu, 2 Feb 2017 14:53:17 -0500 Subject: [PATCH] Comment all the things! --- src/ADPCMSoundLoader.js | 47 +++++++++++++----- src/ArrayBufferStream.js | 58 +++++++++++++++++----- src/DrumPlayer.js | 15 ++++++ src/InstrumentPlayer.js | 30 ++++++++++- src/SoundPlayer.js | 29 +++++++++++ src/effects/EchoEffect.js | 5 -- src/effects/FuzzEffect.js | 7 +-- src/effects/PanEffect.js | 7 +-- src/effects/PitchEffect.js | 7 +-- src/effects/ReverbEffect.js | 5 -- src/effects/RoboticEffect.js | 5 -- src/effects/WobbleEffect.js | 5 -- src/index.js | 96 ++++++++++++++++++++++++++++++------ 13 files changed, 239 insertions(+), 77 deletions(-) diff --git a/src/ADPCMSoundLoader.js b/src/ADPCMSoundLoader.js index 70541bb..7af0c1a 100644 --- a/src/ADPCMSoundLoader.js +++ b/src/ADPCMSoundLoader.js @@ -1,19 +1,24 @@ -/* - -ADPCMSoundLoader loads wav files that have been compressed with the ADPCM format - -based on code from Scratch-Flash: -https://github.com/LLK/scratch-flash/blob/master/src/sound/WAVFile.as - -*/ - var ArrayBufferStream = require('./ArrayBufferStream'); var Tone = require('tone'); var log = require('./log'); +/* + * Load wav audio files that have been compressed with the ADPCM format. + * This is necessary because, while web browsers have native decoders for many audio + * formats, ADPCM is a non-standard format used by Scratch since its early days. + * This decoder is based on code from Scratch-Flash: + * https://github.com/LLK/scratch-flash/blob/master/src/sound/WAVFile.as + * @constructor + */ function ADPCMSoundLoader () { } +/** + * Load an ADPCM sound file from a URL, decode it, and return a promise + * with the audio buffer. + * @param {string} url - a url pointing to the ADPCM wav file + * @return {Tone.Buffer} + */ ADPCMSoundLoader.prototype.load = function (url) { return new Promise(function (resolve, reject) { @@ -73,7 +78,10 @@ ADPCMSoundLoader.prototype.load = function (url) { }.bind(this)); }; - +/** + * Data used by the decompression algorithm + * @type {Array} + */ ADPCMSoundLoader.prototype.stepTable = [ 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, @@ -82,10 +90,20 @@ ADPCMSoundLoader.prototype.stepTable = [ 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} + */ ADPCMSoundLoader.prototype.indexTable = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8]; +/** + * Extract a chunk of audio data from the stream, consisting of a set of audio data bytes + * @param {string} chunkType - the type of chunk to extract. 'data' or 'fmt' (format) + * @param {ArrayBufferStream} stream - an stream containing the audio data + * @return {ArrayBufferStream} a stream containing the desired chunk + */ ADPCMSoundLoader.prototype.extractChunk = function (chunkType, stream) { stream.position = 12; while (stream.position < (stream.getLength() - 8)) { @@ -100,9 +118,14 @@ ADPCMSoundLoader.prototype.extractChunk = function (chunkType, stream) { } }; +/** + * Decompress sample data using the IMA ADPCM algorithm. + * Note: Handles only one channel, 4-bits per sample. + * @param {ArrayBufferStream} compressedData - a stream of compressed audio samples + * @param {number} blockSize - the number of bytes in the stream + * @return {Int16Array} the uncompressed audio samples + */ ADPCMSoundLoader.prototype.imaDecompress = function (compressedData, blockSize) { - // Decompress sample data using the IMA ADPCM algorithm. - // Note: Handles only one channel, 4-bits/sample. var sample, step, code, delta; var index = 0; var lastByte = -1; // -1 indicates that there is no saved lastByte diff --git a/src/ArrayBufferStream.js b/src/ArrayBufferStream.js index df50782..dfc1378 100644 --- a/src/ArrayBufferStream.js +++ b/src/ArrayBufferStream.js @@ -1,39 +1,59 @@ -/* - -ArrayBufferStream wraps the built-in javascript ArrayBuffer, adding the ability to access -data in it like a stream. You can request to read a value from the front of the array, -such as an 8 bit unsigned int, a 16 bit int, etc, and it will keep track of the position -within the byte array, so that successive reads are consecutive. - -*/ +/** + * ArrayBufferStream wraps the built-in javascript ArrayBuffer, adding the ability to access + * data in it like a stream, tracking its position. + * You can request to read a value from the front of the array, and it will keep track of the position + * within the byte array, so that successive reads are consecutive. + * The available types to read include: + * Uint8, Uint8String, Int16, Uint16, Int32, Uint32 + * @param {ArrayBuffer} arrayBuffer - array to use as a stream + * @constructor + */ function ArrayBufferStream (arrayBuffer) { this.arrayBuffer = arrayBuffer; this.position = 0; } -// return a new ArrayBufferStream that is a slice of the existing one +/** + * Return a new ArrayBufferStream that is a slice of the existing one + * @param {number} length - the number of bytes of extract + * @return {ArrayBufferStream} the extracted stream + */ ArrayBufferStream.prototype.extract = function (length) { var slicedArrayBuffer = this.arrayBuffer.slice(this.position, this.position+length); var newStream = new ArrayBufferStream(slicedArrayBuffer); return newStream; }; +/** + * @return {number} the length of the stream in bytes + */ ArrayBufferStream.prototype.getLength = function () { return this.arrayBuffer.byteLength; }; +/** + * @return {number} the number of bytes available after the current position in the stream + */ ArrayBufferStream.prototype.getBytesAvailable = function () { return (this.arrayBuffer.byteLength - this.position); }; +/** + * Read an unsigned 8 bit integer from the stream + * @return {number} + */ ArrayBufferStream.prototype.readUint8 = function () { var val = new Uint8Array(this.arrayBuffer, this.position, 1)[0]; this.position += 1; return val; }; -// convert a sequence of bytes of the given length to a string -// for small length strings only +/** + * Read a sequence of bytes of the given length and convert to a string. + * This is a convenience method for use with short strings. + * @param {number} length - the number of bytes to convert + * @return {String} a String made by concatenating the chars in the input + */ ArrayBufferStream.prototype.readUint8String = function (length) { var arr = new Uint8Array(this.arrayBuffer, this.position, length); this.position += length; @@ -44,24 +64,40 @@ ArrayBufferStream.prototype.readUint8String = function (length) { return str; }; +/** + * Read a 16 bit integer from the stream + * @return {number} + */ ArrayBufferStream.prototype.readInt16 = function () { var val = new Int16Array(this.arrayBuffer, this.position, 1)[0]; this.position += 2; // one 16 bit int is 2 bytes return val; }; +/** + * Read an unsigned 16 bit integer from the stream + * @return {number} + */ ArrayBufferStream.prototype.readUint16 = function () { var val = new Uint16Array(this.arrayBuffer, this.position, 1)[0]; this.position += 2; // one 16 bit int is 2 bytes return val; }; +/** + * Read a 32 bit integer from the stream + * @return {number} + */ ArrayBufferStream.prototype.readInt32 = function () { var val = new Int32Array(this.arrayBuffer, this.position, 1)[0]; this.position += 4; // one 32 bit int is 4 bytes return val; }; +/** + * Read an unsigned 32 bit integer from the stream + * @return {number} + */ ArrayBufferStream.prototype.readUint32 = function () { var val = new Uint32Array(this.arrayBuffer, this.position, 1)[0]; this.position += 4; // one 32 bit int is 4 bytes diff --git a/src/DrumPlayer.js b/src/DrumPlayer.js index 018400b..6df833b 100644 --- a/src/DrumPlayer.js +++ b/src/DrumPlayer.js @@ -1,6 +1,11 @@ var SoundPlayer = require('./SoundPlayer'); var Tone = require('tone'); +/** + * A prototype for the drum sound functionality that can load drum sounds, play, and stop them. + * @param {Tone.Gain} outputNode - a webAudio node that the drum sounds will send their output to + * @constructor + */ function DrumPlayer (outputNode) { this.outputNode = outputNode; @@ -35,11 +40,21 @@ function DrumPlayer (outputNode) { } } +/** + * Play a drum sound. + * The parameter for output node allows sprites or clones to send the drum sound + * to their individual audio effect chains. + * @param {number} drum - the drum number to play (0-indexed) + * @param {Tone.Gain} outputNode - a node to send the output to + */ DrumPlayer.prototype.play = function (drum, outputNode) { this.drumSounds[drum].outputNode = outputNode; this.drumSounds[drum].start(); }; +/** + * Stop all drum sounds. + */ DrumPlayer.prototype.stopAll = function () { for (var i=0; i { @@ -24,6 +44,11 @@ InstrumentPlayer.prototype.playNoteForSecWithInst = function (note, sec, instrum }); }; +/** + * Load an instrument by number + * @param {number} instrumentNum - an instrument number (0-indexed) + * @return {Promise} a Promise that resolves once the instrument audio data has been loaded + */ InstrumentPlayer.prototype.loadInstrument = function (instrumentNum) { if (this.instruments[instrumentNum]) { return Promise.resolve(); @@ -36,6 +61,9 @@ InstrumentPlayer.prototype.loadInstrument = function (instrumentNum) { } }; +/** + * Stop all notes being played on all instruments + */ InstrumentPlayer.prototype.stopAll = function () { for (var i=0; i