I’m currently learning JavaScript and trying to build a simple SoundCloud clone. I’m using WaveSurfer.js for audio waveform visualization, but I’ve run into a couple of issues:
Problem 1: Double playback
Originally, I used a single <audio> element with audio.play() to control playback. After integrating WaveSurfer, when I click “play”, the track plays twice — once via audio.play() and once via WaveSurfer’s internal playback.
Should I fully replace my audio logic with WaveSurfer’s API (e.g., .play() / .pause()), or is there a way to keep my custom audio element and just use WaveSurfer for visualization?
Problem 2: All waveforms play together
On my profile page, I list multiple tracks (e.g., 3 songs), each with its own waveform. I initialize WaveSurfer like this:
const ws = WaveSurfer.create({
container: el,
backend: 'MediaElement',
media: audio,
waveColor: '#ccc',
progressColor: '#ff5500',
height: 60,
responsive: true,
barWidth: 2,
});
But when I click to play one song, all the waveforms start playing at the same time.
I suspect it’s because they’re all linked to the same <audio> element. How can I isolate playback so that only one waveform plays when clicked?
I’m using JavaScript-based page preloading (like PJAX) to avoid full reloads and keep music playing across pages. It works great — the audio continues — but the waveform visualization disappears after switching pages.
function loadPage(event, url) {
event?.preventDefault();
fetch(url)
.then(res => res.text())
.then(html => {
const doc = new DOMParser().parseFromString(html, 'text/html');
const content = doc.getElementById('main-content');
document.getElementById('main-content').innerHTML = content.innerHTML;
document.body.className = doc.body.className;
document.querySelector('.parent').className = doc.querySelector('.parent').className;
window.history.pushState({}, '', url);
initMusic();
});
}
window.addEventListener('popstate', () =>
loadPage(null, location.pathname)
);
Also, I'm using only one audio element in base.html and an example of WaveSurfer.js in my profile.html
<div class="waveform" data-src="{{ item.audio_file.url }}" id="waveform-{{ forloop.counter }}"></div>
document.addEventListener('DOMContentLoaded', () => {
const waveformElements = document.querySelectorAll('.waveform');
if (waveformElements.length === 0) return;
const audio = document.getElementById('player');
waveformElements.forEach((el) => {
const src = el.dataset.src;
const ws = WaveSurfer.create({
container: el,
backend: 'MediaElement',
media: audio,
waveColor: '#ccc',
progressColor: '#ff5500',
height: 60,
responsive: true,
barWidth: 2,
});
ws.load(src);
window.wavesurfers = window.wavesurfers || {};
window.wavesurfers[src] = ws;
});
});
Any advice or best practices would be greatly appreciated!
I tried initializing WaveSurfer with the same <audio> element using the MediaElement backend. I expected it to display the waveform and control playback for each track individually. I also tried preloading pages using JavaScript to keep the music playing across pages.
However, when I play one track, all waveforms start playing at once. Also, after switching pages, the waveform disappears even though the audio keeps playing.