diff --git a/.travis.yml b/.travis.yml index e526ffa..c2ffb26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: node_js node_js: - - '6' - - '4' - - '0.12' - - '0.10' + - '12' + - '14' + - '16' diff --git a/appveyor.yml b/appveyor.yml index d4b9843..fae1753 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,10 +3,9 @@ # Test against these versions of Node.js. environment: matrix: - - nodejs_version: '6' - - nodejs_version: '4' - - nodejs_version: '0.12' - - nodejs_version: '0.10' + - nodejs_version: '12' + - nodejs_version: '14' + - nodejs_version: '16' # Install scripts. (runs after repo cloning) install: diff --git a/index.js b/index.js index 95a0aef..249995e 100644 --- a/index.js +++ b/index.js @@ -15,7 +15,7 @@ * responsible for uncompressing in that case if necessary). */ -exports.Reader = require('./lib/reader'); +exports.Reader = require('./lib/reader.js'); /** * The `Writer` class outputs a valid WAVE file from the audio data written to @@ -26,7 +26,7 @@ exports.Reader = require('./lib/reader'); * written. */ -exports.Writer = require('./lib/writer'); +exports.Writer = require('./lib/writer.js'); /** * The `FileWriter` is a subclass of `Writer` that automatically takes care of @@ -34,4 +34,4 @@ exports.Writer = require('./lib/writer'); * output file. */ -exports.FileWriter = require('./lib/file-writer'); +exports.FileWriter = require('./lib/file-writer.js'); diff --git a/lib/file-writer.js b/lib/file-writer.js index aa0c916..c21e81b 100644 --- a/lib/file-writer.js +++ b/lib/file-writer.js @@ -4,14 +4,7 @@ */ var fs = require('fs'); -var Writer = require('./writer'); -var inherits = require('util').inherits; - -/** - * Module exports. - */ - -module.exports = FileWriter; +var Writer = require('./writer.js'); /** * The `FileWriter` class. @@ -21,45 +14,54 @@ module.exports = FileWriter; * @api public */ -function FileWriter (path, opts) { - if (!(this instanceof FileWriter)) return new FileWriter(path, opts); - Writer.call(this, opts); - this.path = path; - this.file = fs.createWriteStream(path, opts); - this.pipe(this.file); - this.on('header', this._onHeader); -} -inherits(FileWriter, Writer); +class FileWriter extends Writer { + constructor (path, opts) { + super(opts); + this.path = path; + this.file = fs.createWriteStream(path, opts); + this.pipe(this.file); + this.on('header', this._onHeader); + } -/** - * Writes the updated WAVE header to the beginning of the file. - * Emits a "done" event when everything is all good. - * - * @api private - */ + /** + * Writes the updated WAVE header to the beginning of the file. + * Emits a "done" event when everything is all good. + * + * @api private + */ + _onHeader(header) { + var self = this; + var fd; -FileWriter.prototype._onHeader = function (header) { - var self = this; - var fd; + function onOpen(err, f) { + if (err) + return self.emit('error', err); + fd = f; + fs.write(fd, header, 0, header.length, 0, onWrite); + } - function onOpen (err, f) { - if (err) return self.emit('error', err); - fd = f; - fs.write(fd, header, 0, header.length, 0, onWrite); - } + function onWrite(err, bytesWritten) { + if (err) + return self.emit('error', err); + if (bytesWritten !== header.length) { + return self.emit('error', new Error('problem writing "header" data')); + } + fs.close(fd, onClose); + } - function onWrite (err, bytesWritten) { - if (err) return self.emit('error', err); - if (bytesWritten !== header.length) { - return self.emit('error', new Error('problem writing "header" data')); + function onClose(err) { + if (err) + return self.emit('error', err); + self.emit('done'); } - fs.close(fd, onClose); - } - function onClose (err) { - if (err) return self.emit('error', err); - self.emit('done'); + fs.open(self.path, 'r+', onOpen); } +} + + +/** + * Module exports. + */ - fs.open(self.path, 'r+', onOpen); -}; +module.exports = FileWriter; \ No newline at end of file diff --git a/lib/reader.js b/lib/reader.js index 9a90f1f..cb1ba38 100644 --- a/lib/reader.js +++ b/lib/reader.js @@ -3,12 +3,10 @@ * Module dependencies. */ -var util = require('util'); +var { format: f } = require('util'); +var { Transform } = require('stream'); var Parser = require('stream-parser'); -var Transform = require('readable-stream/transform'); var debug = require('debug')('wave:reader'); -var inherits = util.inherits; -var f = util.format; /** * Values for the `audioFormat` byte. @@ -26,12 +24,6 @@ var formats = { WAVE_FORMAT_EXTENSIBLE: 0xFFFE // Determined by SubFormat }; -/** - * Module exports. - */ - -module.exports = Reader; - /** * 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 @@ -43,197 +35,202 @@ module.exports = Reader; * @api public */ -function Reader (opts) { - if (!(this instanceof Reader)) { - return new Reader(opts); +class Reader extends Transform { + constructor (opts) { + super(opts); + + this._bytes(4, this._onRiffID); } - Transform.call(this, opts); - this._bytes(4, this._onRiffID); -} -inherits(Reader, Transform); + // the beginning of the WAV file + _onRiffID(chunk) { + debug('onRiffID: %o', chunk); + var id = this.riffId = chunk.toString('ascii'); + if (id === 'RIFF') { + debug('detected little-endian WAVE file'); + this.endianness = 'LE'; + this._bytes(4, this._onChunkSize); + } else if (id === 'RIFX') { + 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" or "RIFX", got %j', id))); + } + } -/** - * Mixin `Parser`. - */ + // size of the WAV + _onChunkSize(chunk) { + debug('onChunkSize: %o', chunk); + this.chunkSize = chunk['readUInt32' + this.endianness](0); + this._bytes(4, this._onFormat); + } -Parser(Reader.prototype); + // the RIFF "format", should always be "WAVE" + _onFormat(chunk) { + debug('onFormat: %o', chunk); + this.waveId = chunk.toString('ascii'); + if (this.waveId === 'WAVE') { + this._bytes(4, this._onSubchunk1ID); + } else { + this.emit('error', new Error(f('bad "format": expected "WAVE", got %j', this.waveId))); + } + } -// the beginning of the WAV file -Reader.prototype._onRiffID = function (chunk) { - debug('onRiffID: %o', chunk); - var id = this.riffId = chunk.toString('ascii'); - if (id === 'RIFF') { - debug('detected little-endian WAVE file'); - this.endianness = 'LE'; - this._bytes(4, this._onChunkSize); - } else if (id === 'RIFX') { - 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" or "RIFX", got %j', id))); + // size of the "subchunk1" (the header) + _onSubchunk1ID(chunk) { + debug('onSubchunk1ID: %o', chunk); + var subchunk1ID = chunk.toString('ascii'); + this.chunkId = subchunk1ID; + if (subchunk1ID === 'fmt ') { + this._bytes(4, this._onSubchunk1Size); + } else { + this.emit('error', new Error(f('bad "fmt id": expected "fmt ", got %j', subchunk1ID))); + } } -}; -// size of the WAV -Reader.prototype._onChunkSize = function (chunk) { - debug('onChunkSize: %o', chunk); - this.chunkSize = chunk['readUInt32' + this.endianness](0); - this._bytes(4, this._onFormat); -}; + _onSubchunk1Size(chunk) { + debug('onSubchunk1Size: %o', chunk); + this.subchunk1Size = chunk['readUInt32' + this.endianness](0); + // TODO: assert should be 16 for PCM + this._bytes(this.subchunk1Size, this._onSubchunk1); + } -// the RIFF "format", should always be "WAVE" -Reader.prototype._onFormat = function (chunk) { - debug('onFormat: %o', chunk); - this.waveId = chunk.toString('ascii'); - if (this.waveId === 'WAVE') { - this._bytes(4, this._onSubchunk1ID); - } else { - this.emit('error', new Error(f('bad "format": expected "WAVE", got %j', this.waveId))); + _onSubchunk1(chunk) { + debug('onSubchunk1: %o', chunk); + this.audioFormat = chunk['readUInt16' + this.endianness](0); + this.channels = chunk['readUInt16' + this.endianness](2); + this.sampleRate = chunk['readUInt32' + this.endianness](4); + this.byteRate = chunk['readUInt32' + this.endianness](8); // useless... + this.blockAlign = chunk['readUInt16' + this.endianness](12); // useless... + this.bitDepth = chunk['readUInt16' + this.endianness](14); + this.signed = this.bitDepth !== 8; + + var format = { + audioFormat: this.audioFormat, + endianness: this.endianness, + channels: this.channels, + sampleRate: this.sampleRate, + byteRate: this.byteRate, + blockAlign: this.blockAlign, + bitDepth: this.bitDepth, + 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); } -}; -// size of the "subchunk1" (the header) -Reader.prototype._onSubchunk1ID = function (chunk) { - debug('onSubchunk1ID: %o', chunk); - var subchunk1ID = chunk.toString('ascii'); - this.chunkId = subchunk1ID; - if (subchunk1ID === 'fmt ') { - this._bytes(4, this._onSubchunk1Size); - } else { - this.emit('error', new Error(f('bad "fmt id": expected "fmt ", got %j', subchunk1ID))); + _onSubchunk2ID(chunk) { + debug('onSubchunk2ID: %o', chunk); + var subchunk2ID = chunk.toString('ascii'); + + if (subchunk2ID === 'data') { + // Data Chunk - "data" + this._bytes(4, this._onDataChunkSize); + } else if (subchunk2ID === 'fact') { + // Fact Chunk - "fact" + this._bytes(4, this._onFactChunkSize); + } else { + // Unknown Chunk - parse it an emit a "chunk" event + debug('parsing unknown %o chunk', subchunk2ID); + this.unknownID = subchunk2ID; + this._bytes(4, this._onUnknownChunkSize); + } } -}; -Reader.prototype._onSubchunk1Size = function (chunk) { - debug('onSubchunk1Size: %o', chunk); - this.subchunk1Size = chunk['readUInt32' + this.endianness](0); - // TODO: assert should be 16 for PCM - this._bytes(this.subchunk1Size, this._onSubchunk1); -}; + // size of the remaining data in this WAV file + _onDataChunkSize(chunk) { + debug('onDataChunkSize: %o', chunk); + var chunkSize = chunk['readUInt32' + this.endianness](0); -Reader.prototype._onSubchunk1 = function (chunk) { - debug('onSubchunk1: %o', chunk); - this.audioFormat = chunk['readUInt16' + this.endianness](0); - this.channels = chunk['readUInt16' + this.endianness](2); - this.sampleRate = chunk['readUInt32' + this.endianness](4); - this.byteRate = chunk['readUInt32' + this.endianness](8); // useless... - this.blockAlign = chunk['readUInt16' + this.endianness](12); // useless... - this.bitDepth = chunk['readUInt16' + this.endianness](14); - this.signed = this.bitDepth !== 8; - - var format = { - audioFormat: this.audioFormat, - endianness: this.endianness, - channels: this.channels, - sampleRate: this.sampleRate, - byteRate: this.byteRate, - blockAlign: this.blockAlign, - bitDepth: this.bitDepth, - 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; - } + if (chunkSize === 0) { + // 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.emit('format', format); + this._passthrough(chunkSize, this._onDataChunkDone); + } - this._bytes(4, this._onSubchunk2ID); -}; + _onDataChunkDone() { + 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._onSubchunk2ID = function (chunk) { - debug('onSubchunk2ID: %o', chunk); - var subchunk2ID = chunk.toString('ascii'); - - if (subchunk2ID === 'data') { - // Data Chunk - "data" - this._bytes(4, this._onDataChunkSize); - } else if (subchunk2ID === 'fact') { - // Fact Chunk - "fact" - this._bytes(4, this._onFactChunkSize); - } else { - // Unknown Chunk - parse it an emit a "chunk" event - debug('parsing unknown %o chunk', subchunk2ID); - this.unknownID = subchunk2ID; - this._bytes(4, this._onUnknownChunkSize); + _onFactChunkSize(chunk) { + debug('onFactChunkSize: %o', chunk); + var chunkDataSize = chunk['readUInt32' + this.endianness](0); + this._bytes(chunkDataSize, this._onFactChunkData); } -}; -// size of the remaining data in this WAV file -Reader.prototype._onDataChunkSize = function (chunk) { - debug('onDataChunkSize: %o', chunk); - var chunkSize = chunk['readUInt32' + this.endianness](0); + _onFactChunkData(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); + } - if (chunkSize === 0) { - // 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; + _onUnknownChunkSize(chunk) { + debug('onUnknownChunkSize: %o', chunk); + var chunkSize = chunk['readUInt32' + this.endianness](0); + this._bytes(chunkSize, this._onUnknownChunkData); } - this._passthrough(chunkSize, this._onDataChunkDone); -}; + _onUnknownChunkData(chunk) { + debug('onUnknownChunkData: %o', chunk); -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); -}; + this.emit('chunk', { + id: this.unknownID, + data: chunk + }); -Reader.prototype._onFactChunkSize = function (chunk) { - debug('onFactChunkSize: %o', chunk); - var chunkDataSize = chunk['readUInt32' + this.endianness](0); - this._bytes(chunkDataSize, this._onFactChunkData); -}; + // 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); + } +} -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); -}; +/** + * Mixin `Parser`. + */ -Reader.prototype._onUnknownChunkSize = function (chunk) { - debug('onUnknownChunkSize: %o', chunk); - var chunkSize = chunk['readUInt32' + this.endianness](0); - this._bytes(chunkSize, this._onUnknownChunkData); -}; +Parser(Reader.prototype); -Reader.prototype._onUnknownChunkData = function (chunk) { - debug('onUnknownChunkData: %o', chunk); - this.emit('chunk', { - id: this.unknownID, - data: chunk - }); +/** + * Module exports. + */ - // 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); -}; +module.exports = Reader; \ No newline at end of file diff --git a/lib/writer.js b/lib/writer.js index 49a9e1d..026fc72 100644 --- a/lib/writer.js +++ b/lib/writer.js @@ -2,18 +2,9 @@ /** * Module dependencies. */ - -var inherits = require('util').inherits; -var Transform = require('readable-stream/transform'); +var { Transform } = require('stream'); +var { Buffer } = require('buffer'); var debug = require('debug')('wave:writer'); -var bufferAlloc = require('buffer-alloc'); -var bufferFrom = require('buffer-from'); - -/** - * Module exports. - */ - -module.exports = Writer; /** * RIFF Chunk IDs in Buffers. @@ -21,10 +12,10 @@ module.exports = Writer; * @api private */ -var RIFF = bufferFrom('RIFF'); -var WAVE = bufferFrom('WAVE'); -var fmt = bufferFrom('fmt '); -var data = bufferFrom('data'); +var RIFF = Buffer.from('RIFF'); +var WAVE = Buffer.from('WAVE'); +var fmt = Buffer.from('fmt '); +var data = Buffer.from('data'); /** * The max size of the "data" chunk of a WAVE file. This is the max unsigned @@ -58,182 +49,185 @@ var MAX_WAV = 4294967295 - 100; * @api public */ -function Writer (opts) { - if (!(this instanceof Writer)) { - return new Writer(opts); +class Writer extends Transform { + constructor (opts) { + super(opts); + + // TODO: allow/properly handle other WAVE audio formats + this.endianness = 'LE'; + this.format = 1; // raw PCM + this.channels = 2; + this.sampleRate = 44100; + this.bitDepth = 16; + this.bytesProcessed = 0; + + if (opts) { + if (opts.format != null) + this.format = opts.format; + if (opts.channels != null) + this.channels = opts.channels; + if (opts.sampleRate != null) + this.sampleRate = opts.sampleRate; + if (opts.bitDepth != null) + this.bitDepth = opts.bitDepth; + } + + this._writeHeader(); } - Transform.call(this, opts); - - // TODO: allow/properly handle other WAVE audio formats - this.endianness = 'LE'; - this.format = 1; // raw PCM - this.channels = 2; - this.sampleRate = 44100; - this.bitDepth = 16; - this.bytesProcessed = 0; - - if (opts) { - if (opts.format != null) this.format = opts.format; - if (opts.channels != null) this.channels = opts.channels; - if (opts.sampleRate != null) this.sampleRate = opts.sampleRate; - if (opts.bitDepth != null) this.bitDepth = opts.bitDepth; - } - - this._writeHeader(); -} -inherits(Writer, Transform); - -/** - * Writes the WAVE header. - * - * @api private - */ - -Writer.prototype._writeHeader = function () { - debug('_writeHeader()'); - // TODO: 44 is only for format 1 (PCM), any other - // format will have a variable size... - var headerLength = 44; - - var dataLength = this.dataLength; - if (dataLength == null) { - debug('using default "dataLength" of %d', MAX_WAV); - dataLength = MAX_WAV; - } - var fileSize = dataLength + headerLength; - var header = bufferAlloc(headerLength); - var offset = 0; - - // write the "RIFF" identifier - RIFF.copy(header, offset); - offset += RIFF.length; - - // write the file size minus the identifier and this 32-bit int - header['writeUInt32' + this.endianness](fileSize - 8, offset); - offset += 4; - - // write the "WAVE" identifier - WAVE.copy(header, offset); - offset += WAVE.length; - - // write the "fmt " sub-chunk identifier - fmt.copy(header, offset); - offset += fmt.length; - - // write the size of the "fmt " chunk - // XXX: value of 16 is hard-coded for raw PCM format. other formats have - // different size. - header['writeUInt32' + this.endianness](16, offset); - offset += 4; - - // write the audio format code - header['writeUInt16' + this.endianness](this.format, offset); - offset += 2; - - // write the number of channels - header['writeUInt16' + this.endianness](this.channels, offset); - offset += 2; - - // write the sample rate - header['writeUInt32' + this.endianness](this.sampleRate, offset); - offset += 4; - - // write the byte rate - var byteRate = this.byteRate; - if (byteRate == null) { - byteRate = this.sampleRate * this.channels * this.bitDepth / 8; + /** + * Writes the WAVE header. + * + * @api private + */ + _writeHeader() { + debug('_writeHeader()'); + + // TODO: 44 is only for format 1 (PCM), any other + // format will have a variable size... + var headerLength = 44; + + var dataLength = this.dataLength; + if (dataLength == null) { + debug('using default "dataLength" of %d', MAX_WAV); + dataLength = MAX_WAV; + } + var fileSize = dataLength + headerLength; + var header = Buffer.alloc(headerLength); + var offset = 0; + + // write the "RIFF" identifier + RIFF.copy(header, offset); + offset += RIFF.length; + + // write the file size minus the identifier and this 32-bit int + header['writeUInt32' + this.endianness](fileSize - 8, offset); + offset += 4; + + // write the "WAVE" identifier + WAVE.copy(header, offset); + offset += WAVE.length; + + // write the "fmt " sub-chunk identifier + fmt.copy(header, offset); + offset += fmt.length; + + // write the size of the "fmt " chunk + // XXX: value of 16 is hard-coded for raw PCM format. other formats have + // different size. + header['writeUInt32' + this.endianness](16, offset); + offset += 4; + + // write the audio format code + header['writeUInt16' + this.endianness](this.format, offset); + offset += 2; + + // write the number of channels + header['writeUInt16' + this.endianness](this.channels, offset); + offset += 2; + + // write the sample rate + header['writeUInt32' + this.endianness](this.sampleRate, offset); + offset += 4; + + // write the byte rate + var byteRate = this.byteRate; + if (byteRate == null) { + byteRate = this.sampleRate * this.channels * this.bitDepth / 8; + } + header['writeUInt32' + this.endianness](byteRate, offset); + offset += 4; + + // write the block align + var blockAlign = this.blockAlign; + if (blockAlign == null) { + blockAlign = this.channels * this.bitDepth / 8; + } + header['writeUInt16' + this.endianness](blockAlign, offset); + offset += 2; + + // write the bits per sample + header['writeUInt16' + this.endianness](this.bitDepth, offset); + offset += 2; + + // write the "data" sub-chunk ID + data.copy(header, offset); + offset += data.length; + + // write the remaining length of the rest of the data + header['writeUInt32' + this.endianness](dataLength, offset); + offset += 4; + + // save the "header" Buffer for the end, we emit the "header" event at the end + // with the "size" values properly filled out. if this stream is being piped to + // a file (or anything else seekable), then this correct header should be placed + // at the very beginning of the file. + this._header = header; + this.headerLength = headerLength; + + this.push(header); } - header['writeUInt32' + this.endianness](byteRate, offset); - offset += 4; - // write the block align - var blockAlign = this.blockAlign; - if (blockAlign == null) { - blockAlign = this.channels * this.bitDepth / 8; + /** + * Called for the "end" event of this Writer instance. + * + * @api private + */ + _onEnd(write) { + debug('_onEnd()'); } - header['writeUInt16' + this.endianness](blockAlign, offset); - offset += 2; - - // write the bits per sample - header['writeUInt16' + this.endianness](this.bitDepth, offset); - offset += 2; - // write the "data" sub-chunk ID - data.copy(header, offset); - offset += data.length; - - // write the remaining length of the rest of the data - header['writeUInt32' + this.endianness](dataLength, offset); - offset += 4; - - // save the "header" Buffer for the end, we emit the "header" event at the end - // with the "size" values properly filled out. if this stream is being piped to - // a file (or anything else seekable), then this correct header should be placed - // at the very beginning of the file. - this._header = header; - this.headerLength = headerLength; - - this.push(header); -}; - -/** - * Called for the "end" event of this Writer instance. - * - * @api private - */ - -Writer.prototype._onEnd = function (write) { - debug('_onEnd()'); -}; - -/** - * Transform incoming data. We don't do anything special, just pass it through. - * - * @api private - */ - -Writer.prototype._transform = function (chunk, enc, done) { - this.push(chunk); - this.bytesProcessed += chunk.length; - done(); -}; + /** + * Transform incoming data. We don't do anything special, just pass it through. + * + * @api private + */ + _transform(chunk, enc, done) { + this.push(chunk); + this.bytesProcessed += chunk.length; + done(); + } -/** - * Emits a "header" event after the readable side of the stream has finished. - * - * @api private - */ + /** + * Emits a "header" event after the readable side of the stream has finished. + * + * @api private + */ + _flush(done) { + debug('_flush()'); + done(); + this.dataLength = this.bytesProcessed; + process.nextTick(this._emitHeader.bind(this)); + } -Writer.prototype._flush = function (done) { - debug('_flush()'); - done(); - this.dataLength = this.bytesProcessed; - process.nextTick(this._emitHeader.bind(this)); -}; + /** + * Emits the "header" event. This can safely be ignored, or if you are writing + * this WAVE file to somewhere that is seekable (i.e. the filesystem), then you + * should write this "header" buffer at the beginning of the file to get the + * correct file size values in the file. This isn't too important since most audio + * players look at the file size rather than those byte values in the header, but + * it's good to when when possible. + * + * @api private + */ + _emitHeader() { + debug('_emitHeader()'); + var dataLength = this.dataLength; + var headerLength = this.headerLength; + var header = this._header; + + // write the file length at the beginning of the header + header['writeUInt32' + this.endianness](dataLength + headerLength - 8, 4); + + // write the data length at the end of the header + header['writeUInt32' + this.endianness](dataLength, headerLength - 4); + + this.emit('header', header); + } +} /** - * Emits the "header" event. This can safely be ignored, or if you are writing - * this WAVE file to somewhere that is seekable (i.e. the filesystem), then you - * should write this "header" buffer at the beginning of the file to get the - * correct file size values in the file. This isn't too important since most audio - * players look at the file size rather than those byte values in the header, but - * it's good to when when possible. - * - * @api private + * Module exports. */ -Writer.prototype._emitHeader = function () { - debug('_emitHeader()'); - var dataLength = this.dataLength; - var headerLength = this.headerLength; - var header = this._header; - - // write the file length at the beginning of the header - header['writeUInt32' + this.endianness](dataLength + headerLength - 8, 4); - - // write the data length at the end of the header - header['writeUInt32' + this.endianness](dataLength, headerLength - 4); - - this.emit('header', header); -}; +module.exports = Writer; \ No newline at end of file diff --git a/package.json b/package.json index 9f24691..40ddfaf 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,12 @@ "author": "Nathan Rajlich ", "repository": "TooTallNate/node-wav", "dependencies": { - "buffer-alloc": "^1.1.0", - "buffer-from": "^1.0.0", "debug": "^2.2.0", - "readable-stream": "^1.1.14", "stream-parser": "^0.3.1" }, + "engines": { + "node": ">=12" + }, "devDependencies": { "mocha": "^2.5.3", "semistandard": "^12.0.1" diff --git a/test/reader.js b/test/reader.js index cc7ff12..7aaee3f 100644 --- a/test/reader.js +++ b/test/reader.js @@ -7,7 +7,7 @@ var fs = require('fs'); var path = require('path'); var assert = require('assert'); -var Reader = require('../').Reader; +var Reader = require('../lib/reader.js'); describe('Reader', function () { describe('RIFF - Little-endian', function () {