globular-mvc
Version:
Generic template to create web-application that made use of globular as backend and materialize as css (wrap in web-component's)
346 lines (303 loc) • 8.84 kB
JavaScript
export var AUDIO = AUDIO || {};
AUDIO.VISUALIZER = (function () {
'use strict';
var FFT_SIZE = 512;
var TYPE = {
'lounge': 'renderLounge'
};
/**
* @description
* Visualizer constructor.
*
* @param {Object} cfg
*/
function Visualizer(cfg) {
this.isPlaying = false;
this.autoplay = cfg.autoplay || false;
this.loop = cfg.loop || false;
this.canvas = document.getElementById(cfg.canvas) || {};
this.canvasCtx = this.canvas.getContext('2d') || null;
this.ctx = null;
this.analyser = null;
this.sourceNode = null;
this.frequencyData = null;
this.style = cfg.style || 'lounge';
this.barWidth = cfg.barWidth || 2;
this.barHeight = cfg.barHeight || 2;
this.barSpacing = cfg.barSpacing || 5;
this.barColor = cfg.barColor || '#ffffff';
this.shadowBlur = cfg.shadowBlur || 10;
this.shadowColor = cfg.shadowColor || '#ffffff';
this.font = cfg.font || ['12px', 'Helvetica'];
this.gradient = null;
this.title = ""
this.featuring = ""
this.author = ""
this.url = ""
this.time = "--:--:--"
}
/**
* Set the context reference
*/
Visualizer.prototype.setContext = function (ctx) {
if(this.ctx){
return this
}
this.ctx = ctx;
return this;
}
/**
* @description
* Set buffer analyser.
*
* @return {Object}
*/
Visualizer.prototype.setAnalyser = function () {
if(this.analyser){
return this
}
this.analyser = this.ctx.createAnalyser();
this.analyser.smoothingTimeConstant = 0.6;
this.analyser.fftSize = FFT_SIZE;
return this;
};
/**
* @description
* Set frequency data.
*
* @return {Object}
*/
Visualizer.prototype.setFrequencyData = function () {
if(!this.analyser){
return this
}
if( this.frequencyData){
return this
}
this.frequencyData = new Uint8Array(this.analyser.frequencyBinCount);
return this;
};
/**
* @description
* Set source buffer and connect processor and analyser.
*
* @return {Object}
*/
Visualizer.prototype.setBufferSourceNode = function (sourceNode) {
if(!sourceNode){
return
}else{
this.analyser.disconnect()
}
this.sourceNode = sourceNode;
this.sourceNode.connect(this.analyser);
return this;
};
/**
* @description
* Set canvas gradient color.
*
* @return {Object}
*/
Visualizer.prototype.setCanvasStyles = function () {
this.gradient = this.canvasCtx.createLinearGradient(0, 0, 0, 300);
this.gradient.addColorStop(1, this.barColor);
this.canvasCtx.fillStyle = this.gradient;
this.canvasCtx.shadowBlur = this.shadowBlur;
this.canvasCtx.shadowColor = this.shadowColor;
this.canvasCtx.font = this.font.join(' ');
this.canvasCtx.textAlign = 'center';
return this;
};
/**
* @description
* Bind click events.
*
* @return {Object}
*/
Visualizer.prototype.bindEvents = function () {
this.canvas.onclick = (e) => {
e.stopPropagation();
if (this.onclick) {
this.onclick()
}
}
};
/**
* @description
* Play sound from the given buffer.
*
* @param {Object} buffer
*/
Visualizer.prototype.start = function (time) {
this.isPlaying = true;
this.renderFrame();
};
/**
* @description
* Stop the visualiser
*/
Visualizer.prototype.stop = function () {
this.isPlaying = false;
this.renderTime()
}
/**
* @description
* Pause current sound.
*/
Visualizer.prototype.pause = function () {
this.isPlaying = false;
};
/**
* @description
* On audio data stream error fn.
*
* @param {Object} e
*/
Visualizer.prototype.onError = function (e) {
console.info('Error decoding audio file. -- ', e);
};
/**
* @description
* Render frame on canvas.
*/
Visualizer.prototype.renderFrame = function () {
if(!this.frequencyData){
return
}
if(!this.canvasCtx){
return
}
requestAnimationFrame(this.renderFrame.bind(this));
this.analyser.getByteFrequencyData(this.frequencyData);
this.canvasCtx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.renderTime();
this.renderText();
this.renderByStyleType();
};
/**
* @description
* Render audio author and title.
*/
Visualizer.prototype.renderText = function () {
var cx = this.canvas.width / 2;
var cy = this.canvas.height / 2;
var correction = 10;
let author = ""
let featuring = ""
if (this.author) {
author = "by " + this.author
}
if (this.featuring) {
featuring = "ft. " + this.featuring
}
this.canvasCtx.textBaseline = 'top';
this.canvasCtx.fillText(author, cx + correction, cy);
this.canvasCtx.fillText(featuring, cx + correction, cy + 20);
this.canvasCtx.font = parseInt(this.font[0], 10) + 8 + 'px ' + this.font[1];
this.canvasCtx.textBaseline = 'bottom';
this.canvasCtx.fillText(this.title, cx + correction, 80);
this.canvasCtx.font = this.font.join(' ');
};
/**
* @description
* Render audio time.
*/
Visualizer.prototype.renderTime = function () {
if (this.featuring) {
this.canvasCtx.fillText(this.time, this.canvas.width / 2 + 10, this.canvas.height / 2 + 60);
} else {
if (this.author) {
this.canvasCtx.fillText(this.time, this.canvas.width / 2 + 10, this.canvas.height / 2 + 40);
} else {
this.canvasCtx.fillText(this.time, this.canvas.width / 2 + 10, this.canvas.height / 2 + 20);
}
}
};
/**
* @description
* Render frame by style type.
*
* @return {Function}
*/
Visualizer.prototype.renderByStyleType = function () {
return this[TYPE[this.style]]();
};
/**
* @description
* Render lounge style type.
*/
Visualizer.prototype.renderLounge = function () {
var cx = this.canvas.width / 2;
var cy = this.canvas.height / 2;
var radius = 140;
var maxBarNum = Math.floor((radius * 2 * Math.PI) / (this.barWidth + this.barSpacing));
var slicedPercent = Math.floor((maxBarNum * 25) / 100);
var barNum = maxBarNum - slicedPercent;
var freqJump = Math.floor(this.frequencyData.length / maxBarNum);
for (var i = 0; i < barNum; i++) {
var amplitude = this.frequencyData[i * freqJump];
var alfa = (i * 2 * Math.PI) / maxBarNum;
var beta = (3 * 45 - this.barWidth) * Math.PI / 180;
var x = 0;
var y = radius - (amplitude / 12 - this.barHeight);
var w = this.barWidth;
var h = amplitude / 6 + this.barHeight;
this.canvasCtx.save();
this.canvasCtx.translate(cx + this.barSpacing, cy + this.barSpacing);
this.canvasCtx.rotate(alfa - beta);
this.canvasCtx.fillRect(x, y, w, h);
this.canvasCtx.restore();
}
};
/**
* @description
* Create visualizer object instance.
*
* @param {Object} cfg
* {
* autoplay: <Bool>,
* loop: <Bool>,
* canvas: <String>,
* style: <String>,
* barWidth: <Integer>,
* barHeight: <Integer>,
* barSpacing: <Integer>,
* barColor: <String>,
* shadowBlur: <Integer>,
* shadowColor: <String>,
* font: <Array>
* }
* @return {Function}
* @private
*/
function _createVisualizer(cfg) {
var visualizer = new Visualizer(cfg);
return function () {
visualizer
.setCanvasStyles()
.bindEvents();
return visualizer;
};
}
/**
* @description
* Get visualizer instance.
*
* @param {Object} cfg
* @return {Object}
* @public
*/
function getInstance(cfg) {
return _createVisualizer(cfg)();
}
/**
* @description
* Visualizer module API.
*
* @public
*/
return {
getInstance: getInstance
};
})();