How to code audio visualizer with Javascript - javascript

I'm trying to code this particular audio visualization: https://codepen.io/nfj525/pen/rVBaab .
I'm struggling because instead of uploading the audio file like in the example, I want the code to run by clicking the play button of the audio. I want to use my own pre existing audio and play that and not have to upload a file. I'm new to coding and i'm not sure how to edit the javascript to do that.
This is the html I added in the audio I want to be played, "song.mp3"
<div id="content">
<input type="file" id="thefile" accept="audio/*" />
<canvas id="canvas"></canvas>
<audio src="song.mp3" id="audio" controls></audio>
</div>
and this is the js for it
window.onload = function() {
var file = document.getElementById("thefile");
var audio = document.getElementById("audio");
file.onchange = function() {
var files = this.files;
audio.src = URL.createObjectURL(files[0]);
audio.load();
audio.play();
var context = new AudioContext();
var src = context.createMediaElementSource(audio);
var analyser = context.createAnalyser();
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
src.connect(analyser);
analyser.connect(context.destination);
analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var barWidth = (WIDTH / bufferLength) * 2.5;
var barHeight;
var x = 0;
function renderFrame() {
requestAnimationFrame(renderFrame);
x = 0;
analyser.getByteFrequencyData(dataArray);
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i < bufferLength; i++) {
barHeight = dataArray[i];
var r = barHeight + (25 * (i/bufferLength));
var g = 250 * (i/bufferLength);
var b = 50;
ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
audio.play();
renderFrame();
};
};

So, for this you don't need the file input element anymore in your html, so your first piece becomes:
<div id="content">
<canvas id="canvas"></canvas>
<audio src="song.mp3" id="audio" controls></audio>
</div>
As for the Javascript, there is a little more work. In summary, we will extract and name the function that actually does the entire work, and then call it on the window.onload event. So your script section should look like:
<script>
function playAudio() {
var audio = document.getElementById("audio");
// var files = this.files; // not needed
// audio.src = URL.createObjectURL(files[0]); // not needed
audio.load();
audio.play();
var context = new AudioContext();
var src = context.createMediaElementSource(audio);
var analyser = context.createAnalyser();
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
src.connect(analyser);
analyser.connect(context.destination);
analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var barWidth = WIDTH / bufferLength * 2.5;
var barHeight;
var x = 0;
function renderFrame() {
requestAnimationFrame(renderFrame);
x = 0;
analyser.getByteFrequencyData(dataArray);
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i < bufferLength; i++) {
barHeight = dataArray[i];
var r = barHeight + 25 * (i / bufferLength);
var g = 250 * (i / bufferLength);
var b = 50;
ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
audio.play();
renderFrame();
};
window.onload = function () {
// start playing audio once the page is fully loaded
playAudio();
};
</script>
Note that this will have to be hosted on some server.

Related

Multiple JavaScript audio visualizers

This is my first post here as a noob in coding. I'm trying JavaScript tricks with audio visualizers with the tutorial of FrankLaboratory's YouTube channel as a starting point.
I tried to make several zones on the page (overlays) with a click event and a different sound for each one. Everything runs fine but I only had one shape of visualizer for every zone which I found annoying (with one drawVisualizer function called for each overlay).
So I'm trying to modify this to have one sound and one visualizer for each zone.
But it acts strangely: I click a zone and it's ok, I click the second and it's ok too. But if I click the first one again, sound still plays but no more visualizer. Different combinations are possible, I mean if I keep playing the second one, it's working, same if I keep playing the first but as soon as I change, I can't go back on the first which was played.
Here is the code
I just let the two first zones for the example but the goal is to have 16 one the page.
I have the error " Failed to execute 'createMediaElementSource' on 'AudioContext': HTMLMediaElement already connected previously to a different MediaElementSourceNode."
But actually I had it also on the first version of my script with only one visualizer for all zone with the drawVisualizer function and everything run smooth nonetheless, so...
I'm missing something but I don't know what, so any help would be appreciated.
I put the code here too:
const container = document.getElementById('container');
const canvas = document.getElementById('canvas1');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');
let audioSource;
let analyser;
const overlay = document.getElementsByClassName('overlay')[0];
overlay.addEventListener('click' , function(){
const audio0 = document.getElementById('audio0');
audio0.src = 'sound1.mp3 which I put in base64 on the jsfiddle';
const audioContext = new AudioContext();
audio0.play();
audioSource = audioContext.createMediaElementSource(audio0);
analyser = audioContext.createAnalyser();
audioSource.connect(analyser);
analyser.connect(audioContext.destination);
analyser.fftSize = 2048;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const barWidth = canvas.width/bufferLength;
let barHeight;
let x;
function animate(){
x = 0;
ctx.clearRect(0, 0, canvas.width, canvas.height);
analyser.getByteFrequencyData(dataArray);
for (let i = 0; i < bufferLength; i++){
barHeight = dataArray[i];
const red = i * 50;
const green = i ;
const blue = i / 2;
ctx.fillStyle = 'rgb('+ red + ',' + green + ',' + blue + ')';
ctx.fillRect(x, canvas.height - barHeight, barWidth * 4, barHeight / 2);
x += barWidth;
}
requestAnimationFrame(animate);
}
animate();
});
const overlay1 = document.getElementsByClassName('overlay')[1];
overlay1.addEventListener('click' , function(){
const audio1 = document.getElementById('audio1');
audio1.src = 'sound2.mp3 which I put in base64 on the jsfiddle';
const audioContext = new AudioContext();
audio1.play();
audioSource = audioContext.createMediaElementSource(audio1);
analyser = audioContext.createAnalyser();
audioSource.connect(analyser);
analyser.connect(audioContext.destination);
analyser.fftSize = 2048;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const barWidth = canvas.width/bufferLength;
let barHeight;
let x;
function animate(){
x = 0;
ctx.clearRect(0, 0, canvas.width, canvas.height);
analyser.getByteFrequencyData(dataArray);
for (let i = 0; i < bufferLength; i++){
barHeight = dataArray[i]*10;
ctx.save();
ctx.translate(canvas.width, canvas.height);
ctx.rotate(i * Math.PI *24 / bufferLength);
const red = i * 50;
const green = i ;
const blue = i / 2;
ctx.fillStyle = 'rgb('+ red + ',' + green + ',' + blue + ')';
ctx.fillRect(x, canvas.height - barHeight, barWidth * 4, barHeight / 2);
x += barWidth;
ctx.restore();
}
requestAnimationFrame(animate);
}
animate();
});

Fitting Multiple Images on a web page that update from an API

I am Trying to Build a simple web page to display a feed from my cameras that pulls a still image from the camera via the cameras api and then regrabs the image with the API (so i can configure the frame rate of the cameras to cut down on mobile data)
I have managed to build a simple website with just one of the displays, but i want to be able to display all 8 of my cameras, IP addresses 192.168.0.157 - 165
My current code is
<html>
<head>
<script type="text/JavaScript">
var refreshInterval = 1000;
var url1 = "http://192.168.0.157/api/still?passwd=pass&"
var drawDate = true;
var img1;
function init() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
img = new Image();
img.onload = function() {
canvas.setAttribute("width", img.width)
canvas.setAttribute("height", img.height)
context.drawImage(this, 0, 0);
if(drawDate) {
var now = new Date();
var text = now.toLocaleDateString() + " " + now.toLocaleTimeString();
var maxWidth = 100;
var x = img.width-10-maxWidth;
var y = img.height-10;
context.strokeStyle = 'black';
context.lineWidth = 2;
context.strokeText(text, x, y, maxWidth);
context.fillStyle = 'white';
context.fillText(text, x, y, maxWidth);
}
};
refresh();
}
function refresh()
{
img.src = img.src = url1 + "t=" + new Date().getTime();
setTimeout("refresh()",refreshInterval);
}
</script>
<title>Test4</title>
</head>
<body onload="JavaScript:init();">
<canvas id="canvas"/>
</body>
</html>
Thanks in advance
I'm thinking make an array for every camera IP, and do all the API stuff for each of those.
var ip = [
"192.168.0.157",
"192.168.0.158",
"192.168.0.159",
"192.168.0.160",
"192.168.0.161",
"192.168.0.162",
"192.168.0.163",
"192.168.0.164",
"192.168.0.165"
];
var img = [];
function init() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
for (var i = 0; i < ip.length; i++) {
img[i] = new Image();
img[i].onload = (function() {
canvas.setAttribute("width", img[i].width);
canvas.setAttribute("height", img[i].height);
context.drawImage(this, 0, 0);
if (drawDate) {
var now = new Date();
var text = now.toLocaleDateString() + " " + now.toLocaleTimeString();
var maxWidth = 100;
var x = img[i].width - 10 - maxWidth;
var y = img[i].height - 10;
context.strokeStyle = 'black';
context.lineWidth = 2;
context.strokeText(text, x, y, maxWidth);
context.fillStyle = 'white';
context.fillText(text, x, y, maxWidth);
}
})();
}
refresh();
};
function refresh() {
for (var i = 0; i < img.length; i++) {
img[i].src = "http://" + ip[i] + "/api/still?passwd=pass&t=" + new Date().getTime();
}
setTimeout("refresh()",refreshInterval);
}

Why i can't to get canvas todataurl in ie 11?

I try to render diagram from xml to svg,then svg to draw in canvas and save at the computer.
Canvas.toDataUrl() SecurityError in ie 11,but for google chrome is fine.
How did resolve this problem
It the same with this ,but it not help me
this my file for rendering diagram
Please,help me.
I have this function
$('#exportBtn').click(function () {
var object = new Object();
object.xml=xml;
render(object)
var svg = document.querySelector("svg");
var img = document.createElement("img");
var canvas = document.createElement("canvas");
var svgSize = svg.getBoundingClientRect();
canvas.width = svgSize.width * 3;
canvas.height = svgSize.height * 3;
canvas.style.width = svgSize.width;
canvas.style.height = svgSize.height;
var svgData = new XMLSerializer().serializeToString(svg);
var svg64 = btoa(svgData);
var b64Start = 'data:image/svg+xml;base64,';
var image64 = b64Start + svg64;
img.onload = function () {
var ctx = canvas.getContext("2d");
ctx.scale(3, 3);
var x0 = Math.floor(0);
var y0 = Math.floor(0);
ctx.translate(-x0, -y0);
var bg = graph.background;
if (bg == null || bg == '' || bg == mxConstants.NONE) {
bg = '#ffffff';
}
ctx.save();
ctx.fillStyle = bg;
ctx.fillRect(x0, y0, Math.ceil(svgSize.width * 3), Math.ceil(svgSize.height * 3));
ctx.restore();
ctx.drawImage(img, 0, 0,canvas.width,canvas.height);
var canvasdata = canvas.toDataURL("image/png", 1);
var a = document.createElement("a");
a.download = "download_img" + ".png";
a.href = canvasdata;
document.body.appendChild(a);
a.click();
};
img.src = image64;
}
);
this my error

Trying to make audio visualization with circle ripples on Canvas and with javascript

Basically I'm trying to make an audio visualization with circle ripple explosions. I am not sure how to exactly name it, but it looks something like this: https://codepen.io/alek/pen/EyyLgp, except I'm looking for more like when you click a circle appears, expands and disappear. It doesn't necessarily have to be a filled circle.
Here's my js code for audio visualization (Note: I did take the code from Nick Jones - website: https://codepen.io/nfj525/pen/rVBaab, and I credit him for the cool audio visualizations made)
let file = document.querySelector("choose-file");
let audio = document.querySelector("audio-player");
file.onchange = function() {
let files = this.files;
audio.src = URL.createObjectURL(files[0]);
audio.load();
audio.play();
let context = new AudioContext();
let src = context.createMediaElementSource(audio);
let analyser = context.createAnalyser();
let canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let ctx = canvas.getContext("2d");
src.connect(analyser);
analyser.connect(context.destination);
analyser.fftSize = 256;
let bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
let dataArray = new Uint8Array(bufferLength);
let WIDTH = canvas.width;
let HEIGHT = canvas.height;
let barWidth = (WIDTH / bufferLength) * 2.5;
let barHeight;
let x = 0;
function renderFrame() {
requestAnimationFrame(renderFrame);
x = 0;
analyser.getByteFrequencyData(dataArray);
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, WIDTH, HEIGHT);
for (let i = 0; i < bufferLength; i++) {
barHeight = dataArray[i];
let r = barHeight + (25 * (i/bufferLength));
let g = 250 * (i/bufferLength);
let b = 50;
ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
audio.play();
renderFrame();
};
So currently this audio visualization is creating rectangles according to the music, but I would like to change that to circles instead. So on the canvas, circles would appear randomly on the screen and have this ripple, explosion effect, disappear and a new circle would appear. I thought maybe I could replace fillRect() with arc(), but I realize that there is more logic behind it. Does anybody have any ideas how I could possibly change the rectangles to circles?
usually i'm using p5.js, i think p5.js preety good for something like that, just a suggestion if you want to use that, this the link : https://p5js.org/libraries/

Need assistance with audio visualizer using HTML5 canvas + web audio API

I'm looking at making a simple audio visualizer using canvas and the web audio API. I found this example online and want to learn more in depth to what exactly each part of the code is doing. I have some understanding to a few things.
Also importantly I also wish to change the canvas background color but have yet been successful in trying to do so.
var analyser, canvas, ctx, random = Math.random, circles = [];
window.onload = function() {
canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
ctx = canvas.getContext('2d');
setupWebAudio();
for (var i = 0; i < 280; i++) {
circles[i] = new Circle();
circles[i].draw();
}
draw();
};
function setupWebAudio() {
var audio = document.createElement('audio');
audio.src = 'flume.mp3';
document.body.appendChild(audio);
var audioContext = new AudioContext();
analyser = audioContext.createAnalyser();
var source = audioContext.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(audioContext.destination);
audio.play();
}
function draw() {
requestAnimationFrame(draw);
var freqByteData = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(freqByteData);
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 1; i < circles.length; i++) {
circles[i].radius = freqByteData[i] * 1;
circles[i].y = circles[i].y > canvas.height ? 0 : circles[i].y + 1;
circles[i].draw();
}
}
function getRandomColor(){
return random() * 1 >> 0;
}
function Circle() {
this.x = random() * canvas.width;
this.y = random() * canvas.height;
this.radius = random() * 20 + 20;
this.color = 'rgb(' + getRandomColor() + ',' + getRandomColor() + ',' +
getRandomColor() + ')';
}
Circle.prototype.draw = function() {
var that = this;
ctx.save();
ctx.beginPath();
ctx.globalAlpha = random() / 8 + 0.2;
ctx.arc(that.x, that.y, that.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.restore();
}
Change the color in draw() function.
This lines creates a rectangle as the background.
ctx.clearRect(0, 0, canvas.width, canvas.height);
Just before it, set the color, e.g.:
ctx.fillStyle = rgb(1, 2, 3);
ctx.clearRect(0, 0, canvas.width, canvas.height);

Categories

Resources