Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export const infoByFilename: (
fileName: string,
cb:
| ((err: IInfoByFilenameError | Error, data: null | undefined) => any)
| ((err: null | undefined, data: IInfoByFilenameData) => any)
) => void;

export interface IInfoByFilenameHeader {
/* Marks the file as a riff file. Characters are each 1 byte long. */
riff_head: string;
/** Size of the overall file - 8 bytes, in bytes (32-bit integer). Typically, you’d fill this in after creation. */
chunk_size: number;
/** File Type Header. For our purposes, it always equals “WAVE”. */
wave_identifier: string;
/** Format chunk marker. Includes trailing null */
fmt_identifier: string;
/** Length of format data as listed above */
sub_chunk_size: number;
/** Type of format (1 is PCM) - 2 byte integer */
audio_format: number;
/** Number of Channels - 2 byte integer */
num_channels: number;
/** Sample Rate - 32 byte integer. Common values are 44100 (CD), 48000 (DAT). Sample Rate = Number of Samples per second, or Hertz. */
sample_rate: number;
/** (Sample Rate * BitsPerSample * Channels) / 8. */
byte_rate: number;
/** (BitsPerSample * Channels) / 8.1 - 8 bit mono2 - 8 bit stereo/16 bit mono4 - 16 bit stereo */
block_align: number;
/** Bits per sample */
bits_per_sample: number;
/** “data” chunk header. Marks the beginning of the data section. */
data_identifier: string;
/** Size of the data section. */
sub_chunk2_size: number;
}
export interface IInfoByFilenameError {
error: true,
invalid_reasons: Array<string>;
header: IInfoByFilenameHeader;
stats: any;
}
export interface IInfoByFilenameData {
header: IInfoByFilenameHeader;
stats: any;
duration: number;
}
8 changes: 8 additions & 0 deletions test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { infoByFilename } from './'

infoByFilename('./test.wav', (err, data) => {
if (err) {
return void console.error(err.header);
}
return void console.log(data);
});
163 changes: 79 additions & 84 deletions wav-file-info.js
Original file line number Diff line number Diff line change
@@ -1,101 +1,96 @@
// Hi Welcome to WFI by David Jones / RackFX, LLC
var fs = require('fs');
var wfi = {}
var headerSize = 44;

wfi.infoByFilename = function(filename, cb){
var stats = fs.statSync(filename)
var buffer = new Buffer(40); // first 40 bytes are RIFF header
fs.open(filename, 'r', function(err, fd) {
if(err) return cb(err); // error probably TODO:check this!
wfi.infoByFilename = function (filename, cb) {
var stats = fs.statSync(filename)
var buffer = Buffer.alloc(headerSize); // first 44 bytes are RIFF header
fs.open(filename, 'r', function (err, fd) {
if (err) return cb(err); // error probably TODO:check this!

// ex error -
// { [Error: ENOENT: no such file or directory, open './test.wav'] errno: -2, code: 'ENOENT', syscall: 'open', path: './test.wav' }
var read_result = {}
// ex error -
// { [Error: ENOENT: no such file or directory, open './test.wav'] errno: -2, code: 'ENOENT', syscall: 'open', path: './test.wav' }
var read_result = {}

// this a list of sequenced bytes in the 44 byte header. This builds the read_result object.
// Property name / Data type / Length
var props = [
['riff_head', 'string', 4],
['chunk_size', 'uint32', 4],
['wave_identifier', 'string', 4],
['fmt_identifier', 'string', 4],
['sub_chunk_size', 'uint32', 4],
['audio_format', 'uint16', 2],
['num_channels', 'uint16', 2],
['sample_rate', 'uint32', 4],
['byte_rate', 'uint32', 4],
['block_align', 'uint16', 2],
['bits_per_sample', 'uint16', 2],
['data_identifier', 'string', 4],
['sub_chunk2_size', 'uint32', 4],

// this a list of sequenced bytes in the 40 byte header. This builds the read_result object.
// Property name / Data type / Length
var reads = [
['riff_head', 'string', 4],
['chunk_size','uinteger', 4],
['wave_identifier', 'string', 4],
['fmt_identifier', 'string', 4],
['subchunk_size','integer',4],
['audio_format','integer',2],
['num_channels','integer',2],
['sample_rate','uinteger',4],
['byte_rate','integer',4],
['block_align','integer',2],
['bits_per_sample','integer',2],
//['uhm','integer',2],
['data_identifier','string', 4],
//['sub_chunk2_size', 'integer', 4],
];
fs.read(fd, buffer, 0, headerSize, 0, function (err, num) {
var pointer = 0;

]
fs.read(fd, buffer, 0, 40, 0, function(err, num) {
try {
for (var i = 0; i < props.length; i++) {
var prop = props[i];
var name = prop[0];
var type = prop[1];
var size = prop[2];

var i=0;
var pointer = 0;
function read_wav(){
var read = reads[i];
if (type === 'uint16') {
read_result[name] = buffer.readUInt16LE(pointer)
} else if (type === 'uint32') {
read_result[name] = buffer.readUInt32LE(pointer)
} else {
read_result[name] = buffer.toString('ascii', pointer, pointer + size);
}
pointer += size;
}
} catch (e) {
return void cb(e);
}

i++;
if(read[1]=='string'){
read_result[read[0]] = buffer.toString('ascii', pointer , pointer + read[2]);
pointer = pointer + read[2]; // pointer = pointer plus # bytes
}
else if(read[1]=='integer'){

read_result[read[0]] = buffer.readUInt16LE(pointer, read[2])
pointer = pointer + read[2];
}
else if(read[1]=='uinteger'){
fs.close(fd, post_process);
});

read_result[read[0]] = buffer.readInt32LE(pointer, read[2])
pointer = pointer + read[2];
}
if(i < reads.length) { return read_wav()}
else { return fs.close(fd, post_process); }
function post_process() {
var error = false;
var invalid_reasons = []

}
//console.log(i)
read_wav();
}); // end fs.read
if (read_result.riff_head != "RIFF") invalid_reasons.push("Expected \"RIFF\" string at 0")
if (read_result.wave_identifier != "WAVE") invalid_reasons.push("Expected \"WAVE\" string at 4")
if (read_result.fmt_identifier != "fmt ") invalid_reasons.push("Expected \"fmt \" string at 8")
if (
(read_result.audio_format != 1) && // Wav PCM
(read_result.audio_format != 65534) && // Extensible PCM
(read_result.audio_format != 2) && // Wav
(read_result.audio_format != 6) && // Wav ALAW
(read_result.audio_format != 7) && // Wav MULAW
(read_result.audio_format != 22127) && // Vorbis ?? (issue #11)
(read_result.audio_format != 3)) // Wav
invalid_reasons.push("Unknown format: " + read_result.audio_format)
if ((read_result.chunk_size + 8) !== stats.size) invalid_reasons.push("chunk_size does not match file size")
//if ((read_result.data_identifier) != "data") invalid_reasons.push("Expected data identifier at the end of the header")

function post_process(){
var error = false;
var invalid_reasons = []
if (invalid_reasons.length > 0) error = true;

if (read_result.riff_head != "RIFF") invalid_reasons.push("Expected \"RIFF\" string at 0" )
if (read_result.wave_identifier != "WAVE") invalid_reasons.push("Expected \"WAVE\" string at 4")
if (read_result.fmt_identifier != "fmt ") invalid_reasons.push("Expected \"fmt \" string at 8")
if (
(read_result.audio_format != 1) && // Wav PCM
(read_result.audio_format != 65534) && // Extensible PCM
(read_result.audio_format != 2) && // Wav
(read_result.audio_format != 6) && // Wav ALAW
(read_result.audio_format != 7) && // Wav MULAW
(read_result.audio_format != 22127) && // Vorbis ?? (issue #11)
(read_result.audio_format != 3)) // Wav
invalid_reasons.push("Unknown format: "+read_result.audio_format)
if ((read_result.chunk_size + 8) !== stats.size) invalid_reasons.push("chunk_size does not match file size")
//if ((read_result.data_identifier) != "data") invalid_reasons.push("Expected data identifier at the end of the header")
if (error) return cb({
error: true,
invalid_reasons: invalid_reasons,
header: read_result,
stats: stats
});

if (invalid_reasons.length > 0) error = true;

if (error) return cb({
error : true,
invalid_reasons: invalid_reasons,
header: read_result,
stats: stats
});

cb(null, {
header: read_result,
stats: stats,
duration: ((read_result.chunk_size) / (read_result.sample_rate * read_result.num_channels * (read_result.bits_per_sample / 8)))
});
}
});
cb(null, {
header: read_result,
stats: stats,
duration: ((read_result.chunk_size) / (read_result.sample_rate * read_result.num_channels * (read_result.bits_per_sample / 8)))
});
}
});
}
module.exports = wfi;