mp3-duration
Advanced tools
Comparing version 1.0.5 to 1.0.6
295
index.js
@@ -1,66 +0,77 @@ | ||
var fs = require('fs'), | ||
suspend = require('suspend'), | ||
thunkify = require('thunkify'); | ||
var fs = require('fs') | ||
, suspend = require('suspend') | ||
, promisify = require('promisify').cb_func() | ||
var $open=thunkify(fs.open), //(filename, flags [, mode]) | ||
$read=thunkify(fs.read).bind(fs), //(fd, buffer, bufferOffset, length, position) | ||
$fstat=thunkify(fs.fstat).bind(fs), //(fs) | ||
$close=thunkify(fs.close).bind(fs); | ||
, $open = promisify(fs.open) //(filename, flags [, mode]) | ||
, $read = promisify(fs.read).bind(fs) //(fd, buffer, bufferOffset, length, position) | ||
, $fstat = promisify(fs.fstat).bind(fs) //(fs) | ||
, $close = promisify(fs.close).bind(fs) | ||
; | ||
function skipId3(buffer) { | ||
var id3v2Flags, z0, z1, z2, z3, tagSize, footerSize; | ||
//http://id3.org/d3v2.3.0 | ||
if (buffer[0]==0x49 && buffer[1]==0x44 && buffer[2]==0x33){ //'ID3' | ||
id3v2Flags=buffer[5]; | ||
footerSize=(id3v2Flags & 0x10) ? 10 : 0; | ||
var id3v2Flags | ||
, z0 | ||
, z1 | ||
, z2 | ||
, z3 | ||
, tagSize | ||
, footerSize | ||
; | ||
//ID3 size encoding is crazy (7 bits in each of 4 bytes) | ||
z0 = buffer[6]; | ||
z1 = buffer[7]; | ||
z2 = buffer[8]; | ||
z3 = buffer[9]; | ||
if (((z0 & 0x80) == 0) && ((z1 & 0x80) == 0) && ((z2 & 0x80) == 0) && ((z3 & 0x80) == 0)) { | ||
tagSize = ((z0 & 0x7f) * 2097152) + ((z1 & 0x7f) * 16384) + ((z2 & 0x7f) * 128) + (z3 & 0x7f); | ||
return 10 + tagSize + footerSize; | ||
} | ||
//http://id3.org/d3v2.3.0 | ||
if (buffer[0] == 0x49 && buffer[1] == 0x44 && buffer[2] == 0x33) { //'ID3' | ||
id3v2Flags = buffer[5]; | ||
footerSize = (id3v2Flags & 0x10) ? 10 : 0; | ||
//ID3 size encoding is crazy (7 bits in each of 4 bytes) | ||
z0 = buffer[6]; | ||
z1 = buffer[7]; | ||
z2 = buffer[8]; | ||
z3 = buffer[9]; | ||
if (((z0 & 0x80) == 0) && ((z1 & 0x80) == 0) && ((z2 & 0x80) == 0) && ((z3 & 0x80) == 0)) { | ||
tagSize = ((z0 & 0x7f) * 2097152) + ((z1 & 0x7f) * 16384) + ((z2 & 0x7f) * 128) + (z3 & 0x7f); | ||
return 10 + tagSize + footerSize; | ||
} | ||
return 0; | ||
} | ||
return 0; | ||
} | ||
var versions = ['2.5','x','2','1'], | ||
layers = ['x','3','2','1'], | ||
bitRates = { | ||
'V1Lx' : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | ||
'V1L1' : [0,32,64,96,128,160,192,224,256,288,320,352,384,416,448], | ||
'V1L2' : [0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384], | ||
'V1L3' : [0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320], | ||
'V2Lx' : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | ||
'V2L1' : [0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256], | ||
'V2L2' : [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160], | ||
'V2L3' : [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160] | ||
}, | ||
sampleRates = { | ||
'x' : [ 0, 0, 0], | ||
'1' : [44100,48000,32000], | ||
'2' : [22050,24000,16000], | ||
'2.5' : [11025,12000, 8000] | ||
}, | ||
samples = { | ||
1 : { //MPEGv1, Layers 1,2,3 | ||
1 :384, | ||
2 :1152, | ||
3 :1152 | ||
}, | ||
2 : { //MPEGv2/2.5, Layers 1,2,3 | ||
1 : 384, | ||
2 : 1152, | ||
3 : 576 | ||
} | ||
}; | ||
var versions = ['2.5', 'x', '2', '1'] | ||
, layers = ['x', '3', '2', '1'] | ||
, bitRates = { | ||
'V1Lx' : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | ||
'V1L1' : [0,32,64,96,128,160,192,224,256,288,320,352,384,416,448], | ||
'V1L2' : [0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384], | ||
'V1L3' : [0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320], | ||
'V2Lx' : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | ||
'V2L1' : [0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256], | ||
'V2L2' : [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160], | ||
'V2L3' : [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160] | ||
} | ||
, sampleRates = { | ||
'x': [ 0, 0, 0], | ||
'1': [44100, 48000, 32000], | ||
'2': [22050, 24000, 16000], | ||
'2.5': [11025, 12000, 8000] | ||
} | ||
, samples = { | ||
1: { //MPEGv1, Layers 1,2,3 | ||
1: 384, | ||
2: 1152, | ||
3: 1152 | ||
}, | ||
2: { //MPEGv2/2.5, Layers 1,2,3 | ||
1: 384, | ||
2: 1152, | ||
3: 576 | ||
} | ||
} | ||
; | ||
function frameSize(layer, bitRate, sampleRate, paddingBit) { | ||
if (layer==1) | ||
return (((12 * bitRate*1000 /sampleRate) + paddingBit) * 4)|0; | ||
else //layer 2, 3 | ||
return (((144 * bitRate*1000)/sampleRate) + paddingBit)|0; | ||
if (layer == 1) { | ||
return (((12 * bitRate * 1000 / sampleRate) + paddingBit) * 4) | 0; | ||
} else { //layer 2, 3 | ||
return (((144 * bitRate * 1000) / sampleRate) + paddingBit) | 0; | ||
} | ||
} | ||
@@ -70,111 +81,115 @@ | ||
var b1, b2, | ||
versionBits, | ||
version, | ||
simpleVersion, | ||
layerBits, | ||
layer, | ||
bitRateKey, | ||
bitRateIndex, | ||
bitRate, | ||
sampleRateIdx, | ||
sampleRate, | ||
paddingBit; | ||
var b1 | ||
, b2 | ||
, versionBits | ||
, version | ||
, simpleVersion | ||
, layerBits | ||
, layer | ||
, bitRateKey | ||
, bitRateIndex | ||
, bitRate | ||
, sampleRateIdx | ||
, sampleRate | ||
, paddingBit | ||
; | ||
b1=header[1]; | ||
b2=header[2]; | ||
b1 = header[1]; | ||
b2 = header[2]; | ||
versionBits = (b1 & 0x18) >> 3; | ||
version = versions[versionBits]; | ||
simpleVersion = (version=='2.5' ? 2 : version); | ||
versionBits = (b1 & 0x18) >> 3; | ||
version = versions[versionBits]; | ||
simpleVersion = (version == '2.5' ? 2 : version); | ||
layerBits = (b1 & 0x06) >> 1; | ||
layer = layers[layerBits]; | ||
layerBits = (b1 & 0x06) >> 1; | ||
layer = layers[layerBits]; | ||
bitRateKey = 'V'+simpleVersion+'L'+layer; | ||
bitRateIndex = (b2 & 0xf0) >> 4; | ||
bitRate=bitRates[bitRateKey][bitRateIndex] || 0; | ||
bitRateKey = 'V' + simpleVersion + 'L' + layer; | ||
bitRateIndex = (b2 & 0xf0) >> 4; | ||
bitRate = bitRates[bitRateKey][bitRateIndex] || 0; | ||
sampleRateIdx = (b2 & 0x0c) >> 2; | ||
sampleRate = sampleRates[version][sampleRateIdx] || 0; | ||
sampleRateIdx = (b2 & 0x0c) >> 2; | ||
sampleRate = sampleRates[version][sampleRateIdx] || 0; | ||
paddingBit = (b2 & 0x02) >> 1; | ||
paddingBit = (b2 & 0x02) >> 1; | ||
return { | ||
bitRate: bitRate, | ||
sampleRate : sampleRate, | ||
frameSize: frameSize(layer, bitRate, sampleRate, paddingBit), | ||
samples : samples[simpleVersion][layer] | ||
}; | ||
return { | ||
bitRate: bitRate, | ||
sampleRate: sampleRate, | ||
frameSize: frameSize(layer, bitRate, sampleRate, paddingBit), | ||
samples: samples[simpleVersion][layer] | ||
}; | ||
} | ||
function estimateDuration(bitRate, offset, fileSize) { | ||
var kbps = (bitRate*1000)/8, | ||
dataSize = fileSize - offset; | ||
return round(dataSize / kbps); | ||
var kbps = (bitRate * 1000) / 8 | ||
, dataSize = fileSize - offset | ||
; | ||
return round(dataSize / kbps); | ||
} | ||
function round(duration){ | ||
return Math.round(duration*1000)/1000; //round to nearest ms | ||
function round(duration) { | ||
return Math.round(duration * 1000) / 1000; //round to nearest ms | ||
} | ||
function mp3Duration(filename, cbrEstimate, callback) { | ||
if (typeof cbrEstimate == "function") { | ||
callback = cbrEstimate; | ||
cbrEstimate = false; | ||
} | ||
suspend.run(function*() { | ||
var duration = 0 | ||
, fd | ||
, buffer | ||
, bytesRead | ||
, offset | ||
, stat | ||
, info | ||
; | ||
function mp3Duration(filename,cbrEstimate,callback){ | ||
if (typeof cbrEstimate=="function") { | ||
callback=cbrEstimate; | ||
cbrEstimate=false; | ||
} | ||
suspend.run(function*(){ | ||
var fd, | ||
duration=0, | ||
buffer, | ||
bytesRead, | ||
offset, | ||
stat, | ||
info; | ||
fd = yield $open(filename, 'r'); | ||
try { | ||
fd=yield $open(filename,'r'); | ||
try { | ||
stat = yield $fstat(fd); | ||
stat=yield $fstat(fd); | ||
buffer = new Buffer(100); | ||
bytesRead = yield $read(fd, buffer, 0, 100, 0); | ||
if (bytesRead < 100) return 0; | ||
buffer=new Buffer(100); | ||
bytesRead = yield $read(fd, buffer, 0, 100, 0); | ||
if (bytesRead<100) return 0; | ||
offset = skipId3(buffer); | ||
offset = skipId3(buffer); | ||
while (offset < stat.size) { | ||
bytesRead = yield $read(fd, buffer, 0, 10, offset); | ||
if (bytesRead < 10) return duration; | ||
while (offset<stat.size) { | ||
bytesRead = yield $read(fd, buffer, 0, 10, offset); | ||
if (bytesRead<10) return duration; | ||
//Looking for 1111 1111 111 (frame synchronization bits) | ||
if (buffer[0] == 0xff && (buffer[1] & 0xe0) == 0xe0) { | ||
info = parseFrameHeader(buffer); | ||
if (!info.frameSize) { | ||
//some corrupt mp3 files | ||
return round(duration); | ||
} | ||
offset += info.frameSize; | ||
duration += ( info.samples / info.sampleRate ); | ||
} else if (buffer[0] == 0x54 && buffer[1] == 0x41 && buffer[2] == 0x47) {//'TAG' | ||
offset += 128; //Skip over id3v1 tag size | ||
} else { | ||
offset++; //Shouldn't happen much | ||
} | ||
//Looking for 1111 1111 111 (frame synchronization bits) | ||
if (buffer[0]==0xff && (buffer[1] & 0xe0)==0xe0 ) { | ||
info = parseFrameHeader(buffer); | ||
if (!info.frameSize) { | ||
//some corrupt mp3 files | ||
return round(duration); | ||
} | ||
offset += info.frameSize; | ||
duration += ( info.samples / info.sampleRate ); | ||
} else if (buffer[0]==0x54 && buffer[1]==0x41 && buffer[2]==0x47) {//'TAG' | ||
offset+=128; //Skip over id3v1 tag size | ||
} else { | ||
offset++; //Shouldn't happen much | ||
} | ||
if (cbrEstimate && info) { | ||
return round(estimateDuration(info.bitRate, offset, stat.size)); | ||
} | ||
} | ||
if (cbrEstimate && info) { | ||
return round(estimateDuration(info.bitRate, offset, stat.size)); | ||
} | ||
} | ||
return round(duration); | ||
return round(duration); | ||
} finally { | ||
yield $close(fd); | ||
} | ||
} finally { | ||
yield $close(fd); | ||
} | ||
},callback); | ||
}, callback); | ||
} | ||
module.exports=mp3Duration; | ||
module.exports = mp3Duration; |
{ | ||
"name": "mp3-duration", | ||
"version": "1.0.5", | ||
"version": "1.0.6", | ||
"description": "Get the duration of an MP3 file", | ||
@@ -30,4 +30,4 @@ "main": "index.js", | ||
"dependencies": { | ||
"suspend": "^0.6.1", | ||
"thunkify": "^2.1.2" | ||
"promisify": "0.0.3", | ||
"suspend": "^0.6.1" | ||
}, | ||
@@ -34,0 +34,0 @@ "devDependencies": { |
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
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
183
7874093
+ Addedpromisify@0.0.3
+ Addedpromisify@0.0.3(transitive)
+ Addedwhen@3.7.8(transitive)
- Removedthunkify@^2.1.2
- Removedthunkify@2.1.2(transitive)