I'm creating a custom audio player. That looks like so:
The darker grey colour a the bottom is an SVG, which is an audio visualisation, in the form of a wave. (which should change based on the audio frequency)
Currently the animation plays when the audio is played and stops when the audio is paused.
However, the animation is not connected to the audioContext or analyser and this is the problem.
The twig/html file:
<svg class="visualiser-{{ id }}" {{ stimulus_target('audio-player', 'visualiser') }} width="100%">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0,59.88H1200.19v-19.82l-50.01,5.65c-50.01,5.65-150.02,16.94-250.04,11.29-100.02-5.65-200.03-39.78-300.05-44.02-100.02-4.23-200.03,21.44-300.05,29.9-100.02,8.47-200.03,11.29-250.04,12.7L0,57v2.89Z" fill="#cccccc"/>
</svg>
when the js is initialized I do a bit of setup:
this.audio.addEventListener("loadeddata", () => {
this.audioContext = new AudioContext();
this.gain = this.audioContext.createGain();
this.analyser = this.audioContext.createAnalyser();
this.track = this.audioContext.createMediaElementSource(this.audio);
this.track
.connect(this.gain)
.connect(this.analyser)
.connect(this.audioContext.destination);
});
then get the data from Audio:
getDataFromAudio(){
this.analyser.fftSize = 2048;
this.freqByteData = new Uint8Array(this.analyser.fftSize/2);
this.timeByteData = new Uint8Array(this.analyser.fftSize/2);
this.analyser.getByteFrequencyData(this.freqByteData);
this.analyser.getByteTimeDomainData(this.timeByteData);
return {f:this.freqByteData, t:this.timeByteData};
}
Display the audio visualisation graphic, which is the part I don't know, how to match up the output of the audio analyser to the animejs SVG.
graphic() {
this.audio.addEventListener("timeupdate", () => {
let data = this.getDataFromAudio()
console.log(data.f)
});
let
wave0 = "M0,59.88H1200.19v-14.82l-50.01,5.65c-50.01,5.65-150.02,11.94-250.04,6.29-100.02-5.65-191.22-45.52-291.24-49.75-100.02-4.23-208.84,37.17-308.86,45.64-100.02,8.47-200.03-8.71-250.04-7.3L0,47v12.89Z",
wave1 = "M0,59.88H1200.19v-19.82l-50.01,5.65c-50.01,5.65-150.02,16.94-250.04,11.29-100.02-5.65-200.03-39.78-300.05-44.02-100.02-4.23-200.03,21.44-300.05,29.9-100.02,8.47-200.03,11.29-250.04,12.7L0,57v2.89Z",
wave4 = "M0,59.88H1200.19v-19.82l-50.01,5.65c-50.01,5.65-150.02,16.94-250.04,11.29-100.02-5.65-200.03-19.78-300.05-24.02-100.02-4.23-200.03,1.44-300.05,9.9-100.02,8.47-200.03,11.29-250.04,12.7L0,57v2.89Z",
wave3 = "M0,59.88H1200.19V25.06l-50.01,5.65c-50.01,5.65-150.02,31.94-250.04,26.29-100.02-5.65-200.03-22.82-300.05-27.05-100.02-4.23-200.03,14.47-300.05,22.94C200.03,61.35,50.01,12.38,0,13.79H0V59.88Z";
this.visualiser = anime({
targets: `.visualiser-${this.audioId} > path`,
duration: this.audio.duration * 60,
loop: true,
autoplay: false,
easing: 'easeInOutSine',
d: [
{value: [wave0, wave1]},
{value: wave3},
{value: wave4},
],
});
}
The console log from the previous code example gives the following output:
Perhaps my approach of using an SVG to accomplish this is too complicated. Any suggestions are welcome.