Christian Heilmann

Back to basics: adding a playback speed control to an audio player

Monday, December 28th, 2020 at 7:38 pm

Currently I am publishing the new Developer Advocacy Handbook chapter by chapter and I also started recording audio versions of each chapter. A common request of people is to be able to control the speed of a audio/video recording. Luckily enough, using basic HTML5 and JavaScript, this is not that hard to achieve, so let’s do it.

You can see and hear the result in the following video:

You can check the final version on Codepen


See the Pen
Audio with speed control
by Christian Heilmann (@codepo8)
on CodePen.


The best start is always sensible HTML.

<div class="speedcontrolcontainer">
  <audio src="https://file-examp…xample_MP3_2MG.mp3" controls></audio>
  <div>
    <label for="pbrate">Speed:</label>
    <input type="range" id="pbrate" min=.5 max=3 value=1 step=.1>
    <span></span>
  </div>
</div>

In this case, using the audio element with a controls attribute already gives us a play button, a scrubber, time display, volume and an overflow menu with download option. For the speed control, we need a slider with a label to keep it accessible and a span element to show the current value of the playback speed. The range control is good for this as it also gives us keyboard access and allows us to limit the speeds we want to allow. In this case, from half speed to four times the speed.

Let’s only go into basic CSS for styling here:

.scc {
  max-width: 30em;
  display: block;
  border: 1px solid #000;
  padding: 10px;
  font-family: Sans-serif;
}
.scc audio { 
  width: 100%; display: block; 
}
.scc div {
  display: flex;
  padding: .5em 0;
  gap: 5px;
}
.scc label { flex: 1; }
.scc input[type="range"] { flex: 5; }
.scc span {
  flex: 1;
  text-align: center;
}

We give the control a container element and set it to a max-width of 30em. We display the audio element as block and make it use up all the available space. We give the new speed control a bit of padding and use flexbox to lay it out.

The last bit is to use JavaScript to create the rest of the functionality:

const audio = document.querySelector('.scc  audio');
const playbackrate = document.querySelector('.scc input');
const display = document.querySelector('.scc span');
const displayvalue = val => {
  return parseInt(val * 100, 10) + '%'
}
display.innerText = displayvalue(audio.playbackRate);
playbackrate.addEventListener('change', e => {
  audio.playbackRate = playbackrate.value;
  display.innerText = displayvalue(playbackrate.value);
});

  • We get references to the audio element, the slider and the span we want to display the current value of the slide in.
  • As the playback speed in the audio API is a number, we need to convert it to a percentage. This is what the displayvalue method does for us.
  • We display the current playbackRate of the audio element in the span next to the slider.
  • We apply an event Listener to the input element that fires every time it changed.
  • When there is a change, we set the playbackRate of the audio element to the value of the slider
  • And we display the percentage in the span

One thing that is missing is that users may want to have their favourite speed stored so they don’t have to set it again chapter by chapter. To do this, we can use localStorage, set the playbackRate and value when we load the document and store it when the slider changed.

const audio = document.querySelector('.scc  audio');
const playbackrate = document.querySelector('.scc input');
const display = document.querySelector('.scc span');
const displayvalue = val => {
  return parseInt(val * 100, 10) + '%'
}
if (window.localStorage.pbspeed) {
  audio.playbackRate = window.localStorage.pbspeed;
  playbackrate.value = window.localStorage.pbspeed;
}
display.innerText = displayvalue(audio.playbackRate);
playbackrate.addEventListener('change', e => {
  audio.playbackRate = playbackrate.value;
  display.innerText = displayvalue(playbackrate.value);
  window.localStorage.pbspeed = playbackrate.value;
});

And that’s it! An audio playback control with playback speed option.

Share on Mastodon (needs instance)

Share on Twitter

Newsletter

Check out the Dev Digest Newsletter I write every week for WeAreDevelopers. Latest issues:

Dev Digest 146: 🥱 React fatigue 📊 Query anything with SQL 🧠 AI News

Why it may not be needed to learn React, why Deepfake masks will be a big problem and your spirit animal in body fat! 

Dev Digest 147: Free Copilot! Panel: AI and devs! RTO is bad! Pi plays!

Free Copilot! Experts discuss what AI means for devs. Don't trust containers. Mandated RTO means brain drain. And Pi plays Pokemon!

Dev Digest 148: Behind the scenes of Dev Digest & end of the year reports.

In 50 editions of Dev Digest we gave you 2081 resources. Join us in looking back and learn about all the trends this year.

Dev Digest 149: Wordpress break, VW tracking leak, ChatGPT vs Google.

Slowly starting 2025 we look at ChatGPT vs Google, Copilot vs. Cursor and the state of AI crawlers to replace web search…

Dev Digest 150: Shifting manually to AI.

Manual coding is becoming less of a skill. How can we ensure the quality of generated code? Also, unpacking an APK can get you an AI model.

My other work: