Question

lets say i wan't to have an app that has variable audio sources as audio tags like so:

<audio preload="auto" src="1.mp3" controls="" class="muzz"></audio>
<audio preload="auto" src="track.mp3" controls="" class="muzz"></audio>

Depending on which of them is played it should be passed to createMediaElementSource and then the sound would be sent to analyser and various things would be done with it, but it doesn't work:

var trackName;
//get the source of clicked track
$(".muzz").on("play", function(){
    trackName = $(this).attr("src");
    console.log("got a source: ", trackName);
    audio = new Audio();
    audio.src=trackName;




    context = new AudioContext();
    analyser = context.createAnalyser();
    source = context.createMediaElementSource(audio);
    source.connect(analyser);
    analyser.connect(context.destination); 

    letsDraw();


});

the console log displays the correct source name, the letsDraw() method is supposed to draw a spectrogram of the audio playing:

function letsDraw(){
console.log("draw called");
window.requestAnimationFrame(letsDraw);
fbc_array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(fbc_array); //get frequency from the analyser node
ctx.clearRect(0, 0, canvas.width, canvas.height);

ctx.fillStyle="white";
ctx.font = "bold 12px Arial";
ctx.fillText("currently playing:" + trackName, 10, 20);//this works

bars =  150;
for(var i = 0; i < analyser.frequencyBinCount; i++){ //but this doesn't


    /*fill the canvas*/
    x = i *2;
    barWidth = 1;
    barHeight = -(fbc_array[i]/1.8); 

    //colours react to the  frequency loudness
        hue = parseInt(500 * (1 - (barHeight / 200)), 10); 
            ctx.fillStyle = 'hsl(' + hue + ',75%,50%)';

    ctx.fillRect(x, canvas.height, barWidth, barHeight);

}

}

it was working fine with one set audio source, but fails with variable sources, any ideas would be very appreciated.

of course, no errors are even thrown in the console at all.

Was it helpful?

Solution

What I don't get is why you take the src and put that in a new Audio object, as you already have them.

It is also way better to create a source from both <audio> tags. You just create a function that runs on page load (so when everything on the page is ready so you won't get any errors about elements not yet existing etc.).

Before I start writing a piece of code, what do you expect to happen? Should it be possible to have both tags playing at the same time, or should one be stopped if you click play on the other? If it shouldn't play at the same time, you'd better make one <audio> tag and create two buttons which each set the src of the tag.

Another problem with your code is that you already have the <audio> elements, and when you want them to play you just create a new audio element and append the src to it.. What is the logic behind that?

EDIT:

Here is an example of using multiple sources with only one <audio> element.

The HTML code should look like this:

<audio id="player" src="" autoplay="" controls=""></audio>
<div id="buttons">
    <!--The javascript code will generate buttons with which you can play the audio-->
</div>

Then you use this JS code:

onload = function () { //this will be executed when the page is ready
    window.audioFiles = ['track1.mp3', 'track2.mp3']; //this is gonna be the array with all file names
    window.player = document.getElementById('player');
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    context = new AudioContext();
    source = context.createMediaElementSource(player);
    analyser = context.createAnalyser();
    source.connect(analyser);
    analyser.connect(context.destination);

    //now we take all the files and create a button for every file
    for (var x in audioFiles) {
        var btn = document.createElement('button');
        btn.innerHTML = audioFiles[x];
        btn.onclick = function () {
            player.src = audioFiles[x];
            //so when the user clicks the button, the new source gets appended to the audio element
        }
        document.getElementById('buttons').appendChild(btn);
    }

}

Hope the comments explain it good enough

EDIT2:

You want to know how to do this for multiple elements. What you want to do is to create all the audio elements when the page loads, and create all sources for it. This will decrease mess when starting to play audio. The code is here.

All you need to do is have the for loop that runs for every media file you have, which it will create an audio element for with the appropriate source, and then create a sourcenode for that (createMediaElementSource), and connect that sourcenode to the analyser.

I also want to say something about your visualiser code though. If you do not override the font, color or anything, you don't need to execute that every animationframe. Once on init is enough.

OTHER TIPS

At the top of your first code block, try this:

var trackName,
  context = new AudioContext();

And remove context = new AudioContext(); from the click handler.

You should only have one AudioContext for the page.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top