0
votes

I'm trying to build a mock-up audio visual analyser using requestAnimationFrame and canvas. My setup is building an analyser constructor, load audio source etc into it. I have a canvas draw function that is attached to Array of numbers updating as requestAnimationFrame runs. I'd like to be able to toggle that animation on/off with music play/pause button.

I have tried making a custom button that toggles music on/off and a variable that keeps track of isPlaying state but can't successfully attach it to animation function. https://jsfiddle.net/kshatriiya/p8u5h3dz/6/ I can't find a suitable mp3 source online so please place a source at object creation at the end.

<div id="playlist-container">
        <div id="mp3_player">
        <div id="audiobox">
            <canvas id="analyser"></canvas>
        </div>
        </div>
</div>

js

var canvas, ctx, source, context, bars, bar_x, bar_width, bar_height;
var frameArray = [0, 0, 0, 0, 0, 0];
var analyser = function(source, fps, element) {

this.fpsInterval = 1000/fps;
this.source = source;
this.element = element;
this.audio = new Audio();
this.audio.src = this.source;
this.audio.controls = false;
this.isPlaying = false;
}

analyser.prototype.buildframeArray = function() {
var origin = 6;
for (var i= 0; i < 6; i++) {
frameArray[i] = Math.floor((Math.random() * 100) + 70);
}   
}

analyser.prototype.frameLooper = function() {

window.requestAnimationFrame(this.frameLooper.bind(this));

now = Date.now();
elapsed = now - then;

if (elapsed > fpsInterval) {
then = now - (elapsed % fpsInterval);

this.buildframeArray();

ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillstyle = "white";
bars = 20;
for (var i = 0; i < bars; i++) {

bar_x = i*20;
bar_width = 20;
bar_height = -(frameArray[i] / 2);
ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);

}
}
}

analyser.prototype.setFps = function() {

fpsInterval = 200;
then = Date.now();
startTime = then;
this.frameLooper();
}

analyser.prototype.initMp3Player = function() {

document.getElementById(this.element).appendChild(this.audio);
var playButton = document.createElement("BUTTON");
playButton.innerHTML = "Play/Pause";
document.getElementById(this.element).appendChild(playButton);
var self = this.audio;
canvas = document.getElementById("analyser");
ctx = canvas.getContext("2d");
playButton.addEventListener("click", function() {

if (!self.isPlaying) {
    self.play();
    self.isPlaying = true;

} else { self.pause(); self.isPlaying = false;}

});
this.setFps();
}

var audioOne = new analyser("FeintWords.mp3", 5, "audiobox");

audioOne.initMp3Player();  

css

#playlist-container{

width: 100vw;
height: 300px;
display: flex;
flex-direction: row;
align-content: center;
align-items: center;
justify-content: center;
}

#mp3_player, #audiobox  {
background-color: gray;
height: 100%;
width: 60%;
display: flex;
flex-direction: row;
align-content: center;
align-items: center;
justify-content: center;

}

#analyser {

height: 100px;
width: 150px;
background: #002D3C;
}

button {
width: 150px;
height: 50px;
}
1
var self = this.audio; looks suspicious since the isPlaying property is on this, not on this.audioJaromanda X
having said that, this.isPlaying is not used for anything other than tracking the state of play/pause - how is it you are trying to "attach it to the animation function", I see no attempt, successful or, as you say, not successfully.Jaromanda X
Hi yes, the variable is there and I have played around with if statements with it. I have remove the if statements since they weren't working. I just forgot to delete the isPlaying variable, it is not in use atm. Edit: Ops, what am I saying, the variable is actually there to stop/pause the audio with the button. The audio stop/pause function work but I can't find a way to implement similar method to requestAnimationFrame.kshatriiya

1 Answers

1
votes

change frameLooper to check for isPlaying state

analyser.prototype.frameLooper = function() {

    window.requestAnimationFrame(this.frameLooper.bind(this));

    now = Date.now();
    elapsed = now - then;

    if (this.isPlaying && elapsed > fpsInterval) {
    ... etc

And change the initMp3Player so self = this ... therefore play/pause audio needs to invoke on self.audio.play() / self.audio.pause()

analyser.prototype.initMp3Player = function() {

    document.getElementById(this.element).appendChild(this.audio);
    var playButton = document.createElement("BUTTON");
    playButton.innerHTML = "Play/Pause";
    document.getElementById(this.element).appendChild(playButton);
    var self = this; // self is this, not this.audio
    canvas = document.getElementById("analyser");
    ctx = canvas.getContext("2d");
    playButton.addEventListener("click", function() {

        if (!self.isPlaying) {
            self.audio.play(); // <= changed
            self.isPlaying = true;

        } else {
            self.audio.pause();  // <= changed
            self.isPlaying = false;
        }

    });
    this.setFps();
}