I have made my own Audio Player with JavaScript using the p5.js library. The script loops through all elements of the webpage with onload()
and adds a canvas
(The thing that displays the graphics) object to all html elements of class audioPlayer
. With Firefox it all works fine and it can play an audio file from a specified file path. When i load my website inside of Chrome or Edge, I get the following error message in the console:
Not allowed to load local resource: blob:null/59e0d5f9-cf73-4135-9595-3214e6cc964e
This error message occurs multiple times, every time with another string after the blop:null/
. There is also the error message:
The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on
the page. https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio
I believe the issue is that JavaScript doesn't like loading in local files because of safety and stuff. But if that's the case, why does it works on Firefox? Is it an unsafe browser? Also, if the Audio has to be loaded in with the help of user interaction, is there a way to get around that? Like I said, on Firefox, it's no problem.
I should probably add that the website is not online, it's running locally and that I'm using Firefox Developer Edition.
Also, if there are any p5.js users out there, I used the function windowResized()
to make the size of the canvas adapt to the browser window. Again, it works fine using Firefox, but in Chrome and Edge it throws an error because I'm using variables of a class that I haven't created before (even though I create them inside of function setup()
which should run before windowResized()
and - again - it works fine on Firefox.
Here's the code of the JavaScript file:
$(document).ready(function () {
let audioPanel = function (p) {
let track;
let isPlaying;
let width;
let height;
let margin;
let x;
let y;
let dim;
let volumeSlider;
let timeSlider;
let parentTag;
let filename;
let playMeta;
p.windowResized = function () {
width = innerWidth * 0.6;
height = innerWidth * 9 / 16 * 0.18;
p.resizeCanvas(width, height);
margin = 20;
x = margin;
y = margin;
dim = height - 2 * margin;
volumeSlider = new slider(this, margin * 3 + dim, height * 0.8, width * 0.5 - margin * 4 - dim, volumeSlider.min, volumeSlider.max, volumeSlider.actualValue, volumeSlider.decimalPrecision, width, height);
timeSlider = new slider(this, margin * 3 + dim, height * 0.5, width - margin * 12 - dim, timeSlider.min, timeSlider.max, timeSlider.actualValue, timeSlider.decimalPrecision, width, height);
};
p.setup = function () {
p.soundFormats('mp3', 'ogg');
width = innerWidth * 0.6;
height = innerWidth * 9 / 16 * 0.18;
var window = p.createCanvas(width, height);
//window.parent(parentTag.id);
parentTag = p.canvas.parentElement;
filename = parentTag.getElementsByTagName('meta')[0].getAttribute('content');
track = new Audio(filename);
let element = p.createElement('h1', parentTag.id);
element.parent(parentTag.id);
track.addEventListener('ended', p.finished);
isPlaying = false;
margin = 20;
x = margin;
y = margin;
dim = height - 2 * margin;
track.volume = 0.1;
volumeSlider = new slider(this, margin * 3 + dim, height * 0.8, width * 0.5 - margin * 4 - dim, 0, 100, 20, 0, width, height);
timeSlider = new slider(this, margin * 3 + dim, height * 0.5, width - margin * 12 - dim, 0, track.duration, 0, 2, width, height);
track.addEventListener('loadeddata', function () {
timeSlider.max = track.duration;
timeSlider.Update();
});
playMeta = p.createElement('meta');
playMeta.attribute('name', 'isPlaying');
playMeta.attribute('content', 'false');
};
p.draw = function () {
p.clear();
p.background(0, 0, 0, 50);
p.noStroke();
p.fill(0, 20);
p.rectMode(p.CORNER);
p.rect(0, 0, dim + 2 * margin, dim + 2 * margin);
p.ellipseMode(p.CORNER);
let alpha = 100;
if (p.insideButton()) {
alpha = 200;
}
p.fill(255, 255, 255, alpha);
p.ellipse(x, y, dim, dim);
p.fill(0, 150);
p.noStroke();
if (isPlaying) {
let dist = dim * 0.15;
p.rectMode(p.CENTER);
let w = dim * 0.15;
let h = dim * 0.5;
p.rect(x + dim / 2 - dist, y + dim / 2, w, h);
p.rect(x + dim / 2 + dist, y + dim / 2, w, h);
} else {
p.beginShape();
let r = dim * 0.35;
let angle = 0;
let da = p.TWO_PI / 3;
for (let i = 0; i < 3; i++) {
angle = da * i;
p.vertex(Math.cos(angle) * r + x + dim / 2, Math.sin(angle) * r + y + dim / 2);
}
p.endShape(p.CLOSE);
}
timeSlider.Update();
timeSlider.showText(p.SecondsToTime(track.currentTime) + ' / ' + p.SecondsToTime(track.duration));
timeSlider.actualValue = track.currentTime;
timeSlider.onChange = function () {
track.currentTime = timeSlider.actualValue;
}
timeSlider.Render();
volumeSlider.Update();
volumeSlider.showText('Volume: ' + volumeSlider.value + '%');
track.volume = volumeSlider.value / 100;
volumeSlider.Render();
if (playMeta.elt.getAttribute('content') == 'false' && isPlaying) {
p.PauseTrack();
} else if (playMeta.elt.getAttribute('content') == 'true' && !isPlaying) {
p.PlayTrack();
}
};
p.PlayTrack = function () {
track.play();
isPlaying = true;
playMeta.attribute('content', 'true');
let audioPlayers = document.getElementsByClassName('audioPlayer');
let otherPlayers = [];
for (let i = 0; i < audioPlayers.length; i++) {
if (audioPlayers[i].id != parentTag.id) {
otherPlayers.push(audioPlayers[i]);
}
}
for (let i = 0; i < otherPlayers.length; i++) {
let metas = otherPlayers[i].getElementsByTagName('meta');
let others = [];
for (let j = 0; j < metas.length; j++) {
if (metas[j].getAttribute('content') != filename && metas[j].getAttribute('name') == 'isPlaying') {
others.push(metas[j]);
}
}
for (let j = 0; j < others.length; j++) {
let otherPlayMeta = others[j];
otherPlayMeta.setAttribute('content', false);
}
}
}
p.PauseTrack = function () {
track.pause();
isPlaying = false;
playMeta.attribute('content', 'false');
}
p.SecondsToTime = function (secs) {
let minutes = p.nf(p.floor(secs / 60), 2);
let seconds = p.nf(p.floor(secs % 60), 2, 0);
let time = minutes + ':' + seconds;
return time;
};
p.mousePressed = function () {
if (p.insideButton() && p.mouseButton == p.LEFT) {
if (isPlaying) {
p.PauseTrack();
} else {
p.PlayTrack();
}
}
if (volumeSlider.insideSlider() && p.mouseButton == p.LEFT) {
volumeSlider.followMouse();
} else if (timeSlider.insideSlider() && p.mouseButton == p.LEFT) {
timeSlider.followMouse();
}
};
p.mouseReleased = function () {
volumeSlider.letGo();
timeSlider.letGo();
};
p.finished = function () {
p.PauseTrack();
track.currentTime = 0;
timeSlider.actualValue = track.currentTime;
};
p.insideButton = function () {
return (p.dist(p.mouseX, p.mouseY, x + dim / 2, y + dim / 2) <= dim / 2);
};
sketchhandleFile = function (file) {
track = createAudio(file.data, '');
track.hide();
};
};
let audioPlayers = document.getElementsByClassName('audioPlayer');
for (let i = 0; i < audioPlayers.length; i++) {
let newP5 = new p5(audioPanel, audioPlayers[i].id);
}
class slider {
constructor(p, x, y, w, min, max, startVal, decPris) {
this.width = p.width;
this.height = p.height;
this.decimalPrecision = decPris;
this.x = x;
this.y = y;
this.w = w;
this.stickToMouse = false;
this.margin = this.width * 0.08;
this.offset = 0;
this.min = min;
this.max = max;
this.actualValue = startVal;
this.onChange = function () { };
this.p = p;
this.dotR = p.height * 0.05;
// this.dotX = map(startVal, min, max, this.x, this.x + w);
this.value = startVal;
this.Update();
}
Update() {
if (this.stickToMouse) {
this.actualValue = this.p.constrain(this.p.map(this.p.mouseX - this.offset, this.x, this.x + this.w, this.min, this.max), this.min, this.max);
this.onChange();
}
// console.log(this.actualValue);
// console.log(this.min);
// console.log(this.max);
// console.log(this.x);
this.dotX = this.p.map(this.actualValue, this.min, this.max, this.x, this.x + this.w);
this.value = Math.round(this.actualValue * 10 ^ this.decimalPrecision) / 10 ^ this.decimalPrecision;
}
Render() {
this.p.strokeWeight(this.height * 0.05);
this.p.stroke(255, 255, 255, 100);
this.p.strokeCap(this.p.SQUARE);
this.p.line(this.x, this.y, this.x + this.w, this.y);
this.p.noStroke();
let alpha = 150;
let magnifier = 0;
if (this.insideSlider() || this.stickToMouse) {
alpha = 255;
}
if (this.stickToMouse) {
magnifier = this.dotR;
}
this.p.fill(0, 0, 0, alpha);
this.p.rectMode(this.p.CENTER);
this.p.rect(this.dotX, this.y, this.dotR * 2 + magnifier, this.dotR * 2 + magnifier);
}
showText(txt) {
this.p.fill(0, 0, 0, 100);
//textFont(font);
this.p.textAlign(this.p.LEFT, this.p.CENTER);
this.p.textSize(20);
this.p.text(txt, this.x + this.w + this.margin / 3, this.y);
}
followMouse() {
this.stickToMouse = true;
this.offset = this.p.mouseX - this.dotX;
}
letGo() {
this.stickToMouse = false;
}
insideSlider() {
return (this.p.dist(this.p.mouseX, this.p.mouseY, this.dotX, this.y) <= this.dotR);
}
}
});
and here the part of the html file:
<div id="Interstellar - Piano Version" class="audioPlayer">
<meta name="file" content="audioTracks/interstellar.mp3">
</div>