0

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.

1
  • Please trim your code to make it easier to find your problem. Follow these guidelines to create a minimal reproducible example. Commented Jul 2 at 13:56

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.