Skip to content

Instantly share code, notes, and snippets.

@Twipped
Created May 29, 2014 19:08
Show Gist options
  • Save Twipped/4b667562b5d1437da629 to your computer and use it in GitHub Desktop.
Save Twipped/4b667562b5d1437da629 to your computer and use it in GitHub Desktop.
Code to generate SVG waveforms from mp3 files.
var lame = require('lame');
var through = require('through2');
var fs = require('fs');
var d3 = require('d3');
var file = fs.createReadStream('source.mp3');
var frames = [], frameBuffer = [];
var format;
var decoder = new lame.Decoder();
decoder.on('format', function (form) {
format = form;
switch (format.bitDepth) {
case 8:
format.readName = 'readInt8';
format.increment = 1;
break;
case 16:
format.readName = 'readInt16LE';
format.increment = 2;
break;
case 32:
format.readName = 'readInt32LE';
format.increment = 4;
break;
default:
console.error('Unsupported bitdepth: ', format.bitDepth);
process.exit();
}
decoder.pipe(through(frameReader, process));
});
var max = 0;
function frameReader (chunk, enc, next) {
var i = 0, c = chunk.length;
var channel;
var frame;
while (i < c) {
frame = [];
for (channel=0;channel < format.channels;channel++) {
frame[channel] = chunk[format.readName](i);
i += format.increment;
max = Math.max(max, Math.abs(frame[channel]));
}
frames.push(frame);
}
next();
}
file.pipe(decoder);
function reduce (frames) {
var result = [], set, channel, sum, avg,
offset = 0,
len = frames.length,
sampleSize = format.sampleRate / 100;
while (offset < len) {
set = frames.slice(offset, offset + sampleSize);
offset += sampleSize;
if (set.length) {
sum = [];
avg = [];
for (channel=0;channel < format.channels;channel++) {
sum[channel] = set.reduce(function(a, b) { return a + b[channel]; }, 0);
avg[channel] = Math.round(sum[channel] / set.length);
}
result.push(avg);
}
}
return result;
}
function process () {
var reduction = reduce(frames);
var height = 600;
var y = d3.scale.linear()
.domain([-max, max])
.range([-height, height]);
var svg = d3.select('body').append('svg')
.attr('width', reduction.length)
.attr('height', height)
.append('g')
.attr("transform", "translate(0," + (height / 2) + ")");
var line = d3.svg.line()
.x(function(d, i) { return i; })
.y(function(d) { return y(d[0]); });
svg.append('path')
.datum(reduction)
.style("fill:none;stroke:black;stroke-width: 0.5px;")
.attr('d', line);
var html = d3.select('body').node().innerHTML;
fs.writeFileSync('waveform.html', html);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment