Comparing version 0.1.2 to 1.0.0
/** | ||
* Plays the WAVE audio file from stdin out the of the computer's speakers. | ||
* Only PCM format audio WAVE (codec 1) are supported. | ||
* Plays the WAVE audio file from stdin out of the computer's speakers | ||
* via `node-speaker`. | ||
*/ | ||
@@ -6,0 +6,0 @@ |
1.0.0 / 2015-05-01 | ||
================== | ||
* add MIT license file | ||
* add appveyor.yml file for Windows testing | ||
* examples: fix comment | ||
* index: add link to RFC2361 | ||
* reader: add clarifying comment | ||
* reader: add initial `float` WAV file support | ||
* reader: add a few more formats defined by the RFC | ||
* reader: add `formats` map and set `float`, `alaw` and `ulaw` on the "format" object | ||
* reader: use %o debug v1 formatters | ||
* reader, writer: always use "readable-stream" copy of Transform | ||
* package: remove "engines" field | ||
* package: update all dependency versions | ||
* README: use svg for Travis badge | ||
* travis: don't test node v0.7 and v0.9, test v0.11 | ||
0.1.2 / 2014-01-11 | ||
@@ -3,0 +21,0 @@ ================== |
/** | ||
* References: | ||
* - http://tools.ietf.org/html/rfc2361 | ||
* - http://www.sonicspot.com/guide/wavefiles.html | ||
@@ -5,0 +6,0 @@ * - https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ |
@@ -8,11 +8,24 @@ | ||
var assert = require('assert'); | ||
var Parser = require('stream-parser'); | ||
var Transform = require('readable-stream/transform'); | ||
var debug = require('debug')('wave:reader'); | ||
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'); | ||
/** | ||
* Values for the `audioFormat` byte. | ||
*/ | ||
var formats = { | ||
WAVE_FORMAT_UNKNOWN: 0x0000, // Microsoft Unknown Wave Format | ||
WAVE_FORMAT_PCM: 0x0001, // Microsoft PCM Format | ||
WAVE_FORMAT_ADPCM: 0x0002, // Microsoft ADPCM Format | ||
WAVE_FORMAT_IEEE_FLOAT: 0x0003, // IEEE float | ||
WAVE_FORMAT_VSELP: 0x0004, // Compaq Computer's VSELP | ||
WAVE_FORMAT_IBM_CVSD: 0x0005, // IBM CVSD | ||
WAVE_FORMAT_ALAW: 0x0006, // 8-bit ITU-T G.711 A-law | ||
WAVE_FORMAT_MULAW: 0x0007, // 8-bit ITU-T G.711 µ-law | ||
WAVE_FORMAT_EXTENSIBLE: 0xFFFE // Determined by SubFormat | ||
}; | ||
/** | ||
@@ -53,3 +66,3 @@ * Module exports. | ||
Reader.prototype._onRiffID = function (chunk) { | ||
debug('onRiffID:', chunk); | ||
debug('onRiffID: %o', chunk); | ||
var id = this.riffId = chunk.toString('ascii'); | ||
@@ -71,3 +84,3 @@ if ('RIFF' === id) { | ||
Reader.prototype._onChunkSize = function (chunk) { | ||
debug('onChunkSize:', chunk); | ||
debug('onChunkSize: %o', chunk); | ||
this.chunkSize = chunk['readUInt32' + this.endianness](0); | ||
@@ -79,3 +92,3 @@ this._bytes(4, this._onFormat); | ||
Reader.prototype._onFormat = function (chunk) { | ||
debug('onFormat:', chunk); | ||
debug('onFormat: %o', chunk); | ||
this.waveId = chunk.toString('ascii'); | ||
@@ -91,3 +104,3 @@ if ('WAVE' === this.waveId) { | ||
Reader.prototype._onSubchunk1ID = function (chunk) { | ||
debug('onSubchunk1ID:', chunk); | ||
debug('onSubchunk1ID: %o', chunk); | ||
var subchunk1ID = chunk.toString('ascii'); | ||
@@ -103,3 +116,3 @@ this.chunkId = subchunk1ID; | ||
Reader.prototype._onSubchunk1Size = function (chunk) { | ||
debug('onSubchunk1Size:', chunk); | ||
debug('onSubchunk1Size: %o', chunk); | ||
this.subchunk1Size = chunk['readUInt32' + this.endianness](0); | ||
@@ -111,4 +124,3 @@ // TODO: assert should be 16 for PCM | ||
Reader.prototype._onSubchunk1 = function (chunk) { | ||
debug('onSubchunk1:', chunk); | ||
// TODO: support formats other than PCM? | ||
debug('onSubchunk1: %o', chunk); | ||
this.audioFormat = chunk['readUInt16' + this.endianness](0); | ||
@@ -122,3 +134,3 @@ this.channels = chunk['readUInt16' + this.endianness](2); | ||
this.emit('format', { | ||
var format = { | ||
audioFormat: this.audioFormat, | ||
@@ -132,4 +144,21 @@ endianness: this.endianness, | ||
signed: this.signed | ||
}); | ||
}; | ||
switch (format.audioFormat) { | ||
case formats.WAVE_FORMAT_PCM: | ||
// default, common case. don't need to do anything. | ||
break; | ||
case formats.WAVE_FORMAT_IEEE_FLOAT: | ||
format.float = true; | ||
break; | ||
case formats.WAVE_FORMAT_ALAW: | ||
format.alaw = true; | ||
break; | ||
case formats.WAVE_FORMAT_MULAW: | ||
format.ulaw = true; | ||
break; | ||
} | ||
this.emit('format', format); | ||
this._bytes(4, this._onSubchunk2ID); | ||
@@ -139,8 +168,16 @@ }; | ||
Reader.prototype._onSubchunk2ID = function (chunk) { | ||
debug('onSubchunk2ID:', chunk); | ||
debug('onSubchunk2ID: %o', chunk); | ||
var subchunk2ID = chunk.toString('ascii'); | ||
if ('data' === subchunk2ID) { | ||
this._bytes(4, this._onSubchunk2Size); | ||
// Data Chunk - "data" | ||
this._bytes(4, this._onDataChunkSize); | ||
} else if ('fact' === subchunk2ID) { | ||
// Fact Chunk - "fact" | ||
this._bytes(4, this._onFactChunkSize); | ||
} else { | ||
this.emit('error', new Error(f('bad "data" chunk: expected "data", got %j', subchunk2ID))); | ||
// Unknown Chunk - parse it an emit a "chunk" event | ||
debug('parsing unknown %o chunk', subchunk2ID); | ||
this.unknownID = subchunk2ID; | ||
this._bytes(4, this._onUnknownChunkSize); | ||
} | ||
@@ -150,13 +187,65 @@ }; | ||
// size of the remaining data in this WAV file | ||
Reader.prototype._onSubchunk2Size = function (chunk) { | ||
debug('onSubchunk2Size:', chunk); | ||
this.subchunk2Size = chunk['readUInt32' + this.endianness](0); | ||
Reader.prototype._onDataChunkSize = function (chunk) { | ||
debug('onDataChunkSize: %o', chunk); | ||
var chunkSize = chunk['readUInt32' + this.endianness](0); | ||
// 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); | ||
if (0 === chunkSize) { | ||
// Some encoders write `0` for the byte length here in the case of a WAV file | ||
// being generated on-the-fly. In that case, we're just gonna passthrough the | ||
// remaining bytes assuming they're going to be audio data. | ||
chunkSize = Infinity; | ||
} | ||
this._passthrough(chunkSize, this._onDataChunkDone); | ||
}; | ||
Reader.prototype._onDataChunkDone = function () { | ||
debug('onFactChunkDone'); | ||
// now we're done with the "data" chunk so read a new "chunk ID" to figure out | ||
// what's next | ||
this._bytes(4, this._onSubchunk2ID); | ||
}; | ||
Reader.prototype._onFactChunkSize = function (chunk) { | ||
debug('onFactChunkSize: %o', chunk); | ||
var chunkDataSize = chunk['readUInt32' + this.endianness](0); | ||
this._bytes(chunkDataSize, this._onFactChunkData); | ||
}; | ||
Reader.prototype._onFactChunkData = function (chunk) { | ||
debug('onFactChunkData: %o', chunk); | ||
// There is currently only one field defined for the format dependant data. | ||
// It is a single 4-byte value that specifies the number of samples in the | ||
// waveform data chunk. | ||
// | ||
// The number of samples field is redundant for sampled data, since the Data | ||
// chunk indicates the length of the data. The number of samples can be | ||
// determined from the length of the data and the container size as determined | ||
// from the Format chunk. | ||
var numSamples = chunk['readUInt32' + this.endianness](0); | ||
debug('number of samples: %o', numSamples); | ||
this.numSamples = numSamples; | ||
// now we're done with the "fact" chunk so read a new "chunk ID" to figure out | ||
// what's next | ||
this._bytes(4, this._onSubchunk2ID); | ||
}; | ||
Reader.prototype._onUnknownChunkSize = function (chunk) { | ||
debug('onUnknownChunkSize: %o', chunk); | ||
var chunkSize = chunk['readUInt32' + this.endianness](0); | ||
this._bytes(chunkSize, this._onUnknownChunkData); | ||
}; | ||
Reader.prototype._onUnknownChunkData = function (chunk) { | ||
debug('onUnknownChunkData: %o', chunk); | ||
this.emit('chunk', { | ||
id: this.unknownID, | ||
data: chunk | ||
}); | ||
// now we're done with the "unknown" chunk so read a new "chunk ID" to figure | ||
// out what's next | ||
this._bytes(4, this._onSubchunk2ID); | ||
}; |
@@ -7,8 +7,5 @@ | ||
var inherits = require('util').inherits; | ||
var Transform = require('readable-stream/transform'); | ||
var debug = require('debug')('wave:writer'); | ||
var Transform = require('stream').Transform; | ||
// for node v0.8.x support, remove after v0.12.x | ||
if (!Transform) Transform = require('readable-stream/transform'); | ||
/** | ||
@@ -15,0 +12,0 @@ * Module exports. |
{ | ||
"name": "wav", | ||
"description": "`Reader` and `Writer` streams for Microsoft WAVE audio files", | ||
"version": "0.1.2", | ||
"version": "1.0.0", | ||
"author": "Nathan Rajlich <nathan@tootallnate.net>", | ||
@@ -12,5 +12,5 @@ "repository": { | ||
"dependencies": { | ||
"debug": "*", | ||
"readable-stream": "~1.1.10", | ||
"stream-parser": "~0.1.0" | ||
"debug": "~1.0.0", | ||
"readable-stream": "1.0", | ||
"stream-parser": "~0.3.0" | ||
}, | ||
@@ -23,6 +23,3 @@ "devDependencies": { | ||
"test": "mocha --reporter spec" | ||
}, | ||
"engines": { | ||
"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) | ||
[![Build Status](https://secure.travis-ci.org/TooTallNate/node-wav.svg)](http://travis-ci.org/TooTallNate/node-wav) | ||
@@ -52,3 +52,3 @@ This module offers streams to help work with Microsoft WAVE files. | ||
## Reader() | ||
### Reader() | ||
@@ -61,3 +61,3 @@ The `Reader` class accepts a WAV audio file written to it and outputs the raw | ||
## Writer() | ||
### Writer() | ||
@@ -82,4 +82,4 @@ The `Writer` class accepts raw audio data written to it (only PCM audio data is | ||
## FileWriter() | ||
### FileWriter() | ||
The `FileWriter` class. |
@@ -68,2 +68,53 @@ | ||
describe('M1F1-float32-AFsp.wav', function () { | ||
var fixture = path.resolve(__dirname, 'fixtures', 'M1F1-float32-AFsp.wav'); | ||
it('should emit a "format" event', function (done) { | ||
var reader = new Reader(); | ||
reader.on('format', function (format) { | ||
assert.equal(3, format.audioFormat); | ||
assert.equal(2, format.channels); | ||
assert.equal(8000, format.sampleRate); | ||
assert.equal(32, format.bitDepth); | ||
assert.equal(true, format.signed); | ||
assert.equal(true, format.float); | ||
done(); | ||
}); | ||
fs.createReadStream(fixture).pipe(reader).resume(); | ||
}); | ||
it('should emit an "end" event', function (done) { | ||
var reader = new Reader(); | ||
reader.on('end', done); | ||
fs.createReadStream(fixture).pipe(reader).resume(); | ||
}); | ||
}); | ||
describe('M1F1-float64-AFsp.wav', function () { | ||
var fixture = path.resolve(__dirname, 'fixtures', 'M1F1-float64-AFsp.wav'); | ||
it('should emit a "format" event', function (done) { | ||
var reader = new Reader(); | ||
reader.on('format', function (format) { | ||
assert.equal(3, format.audioFormat); | ||
assert.equal(2, format.channels); | ||
assert.equal(8000, format.sampleRate); | ||
assert.equal(64, format.bitDepth); | ||
assert.equal(true, format.signed); | ||
assert.equal(true, format.float); | ||
done(); | ||
}); | ||
fs.createReadStream(fixture).pipe(reader).resume(); | ||
}); | ||
it('should emit an "end" event', function (done) { | ||
var reader = new Reader(); | ||
reader.on('end', done); | ||
fs.createReadStream(fixture).pipe(reader).resume(); | ||
}); | ||
}); | ||
}); | ||
@@ -70,0 +121,0 @@ |
Sorry, the diff of this file is not supported yet
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
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 32 instances in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1184348
663
1
0
5
19
+ Addeddebug@2.6.9(transitive)
+ Addedreadable-stream@1.0.34(transitive)
+ Addedstream-parser@0.3.1(transitive)
- Removeddebug@4.4.0(transitive)
- Removedms@2.1.3(transitive)
- Removedreadable-stream@1.1.14(transitive)
- Removedstream-parser@0.1.2(transitive)
Updateddebug@~1.0.0
Updatedreadable-stream@1.0
Updatedstream-parser@~0.3.0