Comparing version 0.0.1 to 0.1.0
/** | ||
* Pipe a WAVE file to stdin, or specify the | ||
* Pipe a WAVE file to stdin, or specify the filename as the first argument, | ||
* and information about the wave file will be printed out. | ||
* | ||
* Mimics the `wavinfo` program: | ||
* http://www.morphet.org.uk/comp/wavtools.html | ||
*/ | ||
@@ -5,0 +9,0 @@ |
/** | ||
* References: | ||
* - http://www.sonicspot.com/guide/wavefiles.html | ||
* - https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ | ||
* - http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html | ||
* - http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/wave.htm | ||
*/ | ||
/** | ||
* The `Reader` class accepts a WAVE audio file, emits a "format" event, and | ||
@@ -4,0 +12,0 @@ * outputs the raw "data" from the WAVE file (usually raw PCM data, but if the |
@@ -37,2 +37,4 @@ | ||
* Emits a "done" event when everything is all good. | ||
* | ||
* @api private | ||
*/ | ||
@@ -39,0 +41,0 @@ |
@@ -9,6 +9,10 @@ | ||
var debug = require('debug')('wave:reader'); | ||
var Parser = require('../parser'); | ||
var Transform = require('stream').Transform; | ||
var Parser = require('stream-parser'); | ||
var inherits = util.inherits; | ||
var f = util.format; | ||
// for node v0.8.x support, remove after v0.12.x | ||
if (!Transform) Transform = require('readable-stream/transform'); | ||
/** | ||
@@ -21,9 +25,10 @@ * Module exports. | ||
/** | ||
* The `Reader` class reads WAV audio files and output raw PCM audio data. | ||
* The `Reader` class accepts a WAV audio file written to it and outputs the raw | ||
* audio data with the WAV header stripped (most of the time, PCM audio data will | ||
* be output, depending on the `audioFormat` property). | ||
* | ||
* References: | ||
* - http://www.sonicspot.com/guide/wavefiles.html | ||
* - https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ | ||
* - http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html | ||
* - http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/wave.htm | ||
* A `"format"` event gets emitted after the WAV header has been parsed. | ||
* | ||
* @param {Object} opts optional options object | ||
* @api public | ||
*/ | ||
@@ -35,17 +40,28 @@ | ||
} | ||
Parser.call(this, opts); | ||
this.endianness = 'LE'; | ||
this.buffer(4, this._onRiffID); | ||
Transform.call(this, opts); | ||
this._bytes(4, this._onRiffID); | ||
} | ||
inherits(Reader, Parser); | ||
inherits(Reader, Transform); | ||
/** | ||
* Mixin `Parser`. | ||
*/ | ||
Parser(Reader.prototype); | ||
// the beginning of the WAV file | ||
Reader.prototype._onRiffID = function (chunk) { | ||
debug('onRiffID:', chunk); | ||
// TODO: support RIFX | ||
this.riffId = chunk.toString('ascii'); | ||
if ('RIFF' === this.riffId) { | ||
this.buffer(4, this._onChunkSize); | ||
var id = this.riffId = chunk.toString('ascii'); | ||
if ('RIFF' === id) { | ||
debug('detected little-endian WAVE file'); | ||
this.endianness = 'LE'; | ||
this._bytes(4, this._onChunkSize); | ||
} else if ('RIFX' === id) { | ||
debug('detected big-endian WAVE file'); | ||
this.endianness = 'BE'; | ||
this._bytes(4, this._onChunkSize); | ||
} else { | ||
this.emit('error', new Error(f('bad "chunk id": expected "RIFF", got %j', this.riffId))); | ||
this.emit('error', new Error(f('bad "chunk id": expected "RIFF" or "RIFX", got %j', id))); | ||
} | ||
@@ -58,3 +74,3 @@ }; | ||
this.chunkSize = chunk['readUInt32' + this.endianness](0); | ||
this.buffer(4, this._onFormat); | ||
this._bytes(4, this._onFormat); | ||
}; | ||
@@ -67,3 +83,3 @@ | ||
if ('WAVE' === this.waveId) { | ||
this.buffer(4, this._onSubchunk1ID); | ||
this._bytes(4, this._onSubchunk1ID); | ||
} else { | ||
@@ -80,3 +96,3 @@ this.emit('error', new Error(f('bad "format": expected "WAVE", got %j', this.waveId))); | ||
if ('fmt ' === subchunk1ID) { | ||
this.buffer(4, this._onSubchunk1Size); | ||
this._bytes(4, this._onSubchunk1Size); | ||
} else { | ||
@@ -91,3 +107,3 @@ this.emit('error', new Error(f('bad "fmt id": expected "fmt ", got %j', subchunk1ID))); | ||
// TODO: assert should be 16 for PCM | ||
this.buffer(this.subchunk1Size, this._onSubchunk1); | ||
this._bytes(this.subchunk1Size, this._onSubchunk1); | ||
}; | ||
@@ -108,2 +124,3 @@ | ||
audioFormat: this.audioFormat, | ||
endianness: this.endianness, | ||
channels: this.channels, | ||
@@ -117,3 +134,3 @@ sampleRate: this.sampleRate, | ||
this.buffer(4, this._onSubchunk2ID); | ||
this._bytes(4, this._onSubchunk2ID); | ||
}; | ||
@@ -125,3 +142,3 @@ | ||
if ('data' === subchunk2ID) { | ||
this.buffer(4, this._onSubchunk2Size); | ||
this._bytes(4, this._onSubchunk2Size); | ||
} else { | ||
@@ -136,8 +153,10 @@ this.emit('error', new Error(f('bad "data" chunk: expected "data", got %j', subchunk2ID))); | ||
this.subchunk2Size = chunk['readUInt32' + this.endianness](0); | ||
this.passthrough(this.subchunk2Size, this._onEnd); | ||
}; | ||
Reader.prototype._onEnd = function () { | ||
debug('onEnd'); | ||
this.done = true; | ||
// even though the WAV file reports a remaining byte length, in practice it | ||
// can't really be trusted since in streaming situations where the WAV file is | ||
// being generated on-the-fly, the number of remaining bytes would be impossible | ||
// to know beforehand. For this reason, some encoders write `0` for the byte | ||
// length here... In any case, we are just gonna pass through the rest of the | ||
// stream until EOF. | ||
this._passthrough(Infinity, this._onEnd); | ||
}; |
@@ -9,4 +9,8 @@ | ||
var debug = require('debug')('wave:writer'); | ||
var Parser = require('../parser'); | ||
var Transform = require('stream').Transform; | ||
var Parser = require('stream-parser'); | ||
// for node v0.8.x support, remove after v0.12.x | ||
if (!Transform) Transform = require('readable-stream/transform'); | ||
/** | ||
@@ -20,2 +24,4 @@ * Module exports. | ||
* RIFF Chunk IDs in Buffers. | ||
* | ||
* @api private | ||
*/ | ||
@@ -31,2 +37,4 @@ | ||
* 32-bit int value, minus 100 bytes (overkill, 44 would be safe) for the header. | ||
* | ||
* @api private | ||
*/ | ||
@@ -37,3 +45,22 @@ | ||
/** | ||
* The `Writer` class. | ||
* The `Writer` class accepts raw audio data written to it (only PCM audio data is | ||
* currently supported), and outputs a WAV file with a valid WAVE header at the | ||
* beginning specifying the formatting information of the audio stream. | ||
* | ||
* Note that there's an interesting problem, because the WAVE header also | ||
* specifies the total byte length of the audio data in the file, and there's no | ||
* way that we can know this ahead of time. Therefore the WAVE header will contain | ||
* a byte-length if `0` initially, which most WAVE decoders will know means to | ||
* just read until `EOF`. | ||
* | ||
* Optionally, if you are in a situation where you can seek back to the beginning | ||
* of the destination of the WAVE file (like writing to a regular file, for | ||
* example), then you may listen for the `"header"` event which will be emitted | ||
* _after_ all the data has been written, and you can go back and rewrite the new | ||
* header with proper audio byte length into the beginning of the destination | ||
* (though if your destination _is_ a regular file, you should use the the | ||
* `FileWriter` class instead). | ||
* | ||
* @param {Object} opts optional options object | ||
* @api public | ||
*/ | ||
@@ -45,6 +72,6 @@ | ||
} | ||
Parser.call(this, opts); | ||
Transform.call(this, opts); | ||
// TODO: allow/properly handle other WAVE audio formats | ||
this.endianness = 'LE'; | ||
this.format = 1; // raw PCM | ||
@@ -64,8 +91,16 @@ this.channels = 2; | ||
//this.immediate(this._writeHeader); | ||
this.buffer(0, this._writeHeader); | ||
this._bytes(0, this._writeHeader); | ||
} | ||
inherits(Writer, Parser); | ||
inherits(Writer, Transform); | ||
/** | ||
* Mixin `Parser`. | ||
*/ | ||
Parser(Writer.prototype); | ||
/** | ||
* Writes the WAVE header. | ||
* | ||
* @api private | ||
*/ | ||
@@ -78,3 +113,6 @@ | ||
var dataLength = this.dataLength; | ||
if (null == dataLength) dataLength = MAX_WAV; | ||
if (null == dataLength) { | ||
debug('using default "dataLength" of %d', MAX_WAV); | ||
dataLength = MAX_WAV; | ||
} | ||
var fileSize = dataLength + headerLength; | ||
@@ -155,5 +193,11 @@ var header = new Buffer(headerLength); | ||
write(header); | ||
this.passthrough(dataLength, this._onEnd); | ||
this._passthrough(dataLength, this._onEnd); | ||
}; | ||
/** | ||
* Called for the "end" event of this Writer instance. | ||
* | ||
* @api private | ||
*/ | ||
Writer.prototype._onEnd = function (write) { | ||
@@ -165,2 +209,4 @@ debug('_onEnd()'); | ||
* Emits a "header" event after the readable side of the stream has finished. | ||
* | ||
* @api private | ||
*/ | ||
@@ -182,2 +228,4 @@ | ||
* it's good to when when possible. | ||
* | ||
* @api private | ||
*/ | ||
@@ -184,0 +232,0 @@ |
{ | ||
"name": "wav", | ||
"description": "`Reader` and `Writer` streams for Microsoft WAVE audio files", | ||
"version": "0.0.1", | ||
"version": "0.1.0", | ||
"author": "Nathan Rajlich <nathan@tootallnate.net>", | ||
@@ -13,2 +13,3 @@ "repository": { | ||
"debug": "*", | ||
"stream-parser": "*", | ||
"readable-stream": "~0.0.3" | ||
@@ -21,7 +22,7 @@ }, | ||
"scripts": { | ||
"test": "mocha" | ||
"test": "mocha --reporter spec" | ||
}, | ||
"engines": { | ||
"node": "*" | ||
"node": ">= v0.8.x" | ||
} | ||
} |
node-wav | ||
======== | ||
### `Reader` and `Writer` streams for Microsoft WAVE audio files | ||
[![Build Status](https://secure.travis-ci.org/TooTallNate/node-wav.png)](http://travis-ci.org/TooTallNate/node-wav) | ||
@@ -47,9 +48,36 @@ This module offers streams to help work with Microsoft WAVE files. | ||
### Reader class | ||
- [Reader()](#reader) | ||
- [Writer()](#writer) | ||
- [FileWriter()](#filewriter) | ||
## Reader() | ||
### Writer class | ||
The `Reader` class accepts a WAV audio file written to it and outputs the raw | ||
audio data with the WAV header stripped (most of the time, PCM audio data will | ||
be output, depending on the `audioFormat` property). | ||
A `"format"` event gets emitted after the WAV header has been parsed. | ||
### FileWriter class | ||
## Writer() | ||
The `Writer` class accepts raw audio data written to it (only PCM audio data is | ||
currently supported), and outputs a WAV file with a valid WAVE header at the | ||
beginning specifying the formatting information of the audio stream. | ||
Note that there's an interesting problem, because the WAVE header also | ||
specifies the total byte length of the audio data in the file, and there's no | ||
way that we can know this ahead of time. Therefore the WAVE header will contain | ||
a byte-length if `0` initially, which most WAVE decoders will know means to | ||
just read until `EOF`. | ||
Optionally, if you are in a situation where you can seek back to the beginning | ||
of the destination of the WAVE file (like writing to a regular file, for | ||
example), then you may listen for the `"header"` event which will be emitted | ||
_after_ all the data has been written, and you can go back and rewrite the new | ||
header with proper audio byte length into the beginning of the destination | ||
(though if your destination _is_ a regular file, you should use the the | ||
`FileWriter` class instead). | ||
## FileWriter() | ||
The `FileWriter` class. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 2 instances in 1 package
1056175
47
545
83
35
3
2
3
+ Addedstream-parser@*
+ Addeddebug@2.6.9(transitive)
+ Addedms@2.0.0(transitive)
+ Addedstream-parser@0.3.1(transitive)