diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3aadc51 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Created by .ignore support plugin (hsz.mobi) +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen +node_modules/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/index.js b/index.js new file mode 100644 index 0000000..07a9a76 --- /dev/null +++ b/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/render') diff --git a/lib/render.js b/lib/render.js new file mode 100644 index 0000000..597d65e --- /dev/null +++ b/lib/render.js @@ -0,0 +1,92 @@ +var AudioContext = require('web-audio-api').AudioContext; +var fs = require('fs'); +var Canvas = require('canvas') + +Array.prototype.max = function () { + return Math.max.apply(null, this); +}; + +var defaultSetting = { + width: 600, + height: 80, + barWidth: 3, + barGap: 0.2, + waveColor: "blue", + waveAlpha: 1, + backgroundColor: '#fff', + baseline: 60, +} + +function bufferMeasure(position, length, data) { + var sum = 0.0 + for (var i = position; i <= (position + length) - 1; i++) { + sum += Math.pow(data[i], 2) + } + return Math.sqrt(sum / data.length) +} + +module.exports = function render(url, options, cb) { + var audioContext = new AudioContext + if (typeof options === "function") { + cb = options + options = {} + } + + options = Object.assign({}, defaultSetting, options) + if (options.baseline < 0 && options.height < 0 && options.width < 0) { + return cb( new Error('Size must be greater than 0')) + } + + if (options.baseline > options.height) { + return cb( new Error('Baseline must be smaller than waveform height')) + } + + var canvas = new Canvas(options.width, options.height) + var canvasContext = canvas.getContext('2d') + + fs.readFile("Canon.mp3", function (err, buffer) { + + if (err) { + return cb(err) + } + + audioContext.decodeAudioData(buffer, function (result) { + var data = result.getChannelData(0) + var step = Math.floor(result.length / options.width) + var ratio = options.baseline / options.height + var vals = [] + + canvasContext.fillStyle = options.backgroundColor + canvasContext.fillRect(0, 0, options.width, options.height) + + canvasContext.fillStyle = options.waveColor + + for (var i = 0; i < options.width; i += options.barWidth) { + vals.push(bufferMeasure(i * step, step, data) * 10000); + } + + for (var j = 0; j < options.width; j += options.barWidth) { + var scale = options.height / vals.max(); + var val = bufferMeasure(j * step, step, data) * 10000; + val *= scale; + val += 1; + var w = options.barWidth; + if (options.barGap !== 0) { + w *= Math.abs(1 - options.barGap); + } + var x = j + (w / 2); + + var lowerHeight = val * ratio; + var upperHeight = val * (1 - ratio); + + if(options.waveAlpha < 1) { + canvasContext.clearRect(x, options.baseline, w, upperHeight); + canvasContext.clearRect(x, options.baseline, w, -lowerHeight); + } + canvasContext.fillRect(x, options.baseline, w, upperHeight); + canvasContext.fillRect(x, options.baseline, w, -lowerHeight); + } + cb(null, canvas.toBuffer()) + }) + }); +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9001065 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "node-wave", + "version": "0.0.1", + "description": "", + "main": "index.js", + "scripts": { + "test": "standard && node index.js" + }, + "author": "Tran Quoc Cuong ", + "license": "MIT", + "dependencies": { + "canvas": "^1.6.2", + "web-audio-api": "^0.2.2" + }, + "devDependencies": { + "standard": "^8.6.0" + } +} diff --git a/test/Canon.mp3 b/test/Canon.mp3 new file mode 100644 index 0000000..2ce52fa Binary files /dev/null and b/test/Canon.mp3 differ diff --git a/test/out.png b/test/out.png new file mode 100644 index 0000000..33091f0 Binary files /dev/null and b/test/out.png differ diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..b25462a --- /dev/null +++ b/test/test.js @@ -0,0 +1,6 @@ +var render = require('../lib/render') +var fs = require('fs') + +render('Canon.mp3', function (err, buffer) { + fs.writeFileSync('out.png', buffer); +})