27

Is it possible to change the tempo of audio (in the form of loaded MP3 files) without changing the pitch using the Web Audio API?

I'm aware of the playbackRate property on the AudioBufferSourceNode, but that also changes pitch. I'm also aware of the playbackRate property for <audio> and <video> elements, but I need to use the Web Audio API.

I'm very new to the Web Audio API. Is there anything I can do?

JaredCubilla
  • 538
  • 1
  • 8
  • 24
  • Web Audio doesn't support this out of the box. You'll need specialized software to change the tempo of a sound file. – Robert Harvey Jul 07 '15 at 17:00
  • It will be possible due to the low level access you get via AudioBuffer.getChannelData() but will need coding from scratch. Do you need to speed up, slow down or both? – imcg Jul 09 '15 at 22:39
  • @imcg i want to do the both . can u explain how to go for this –  Mar 28 '16 at 12:20
  • Did you solve it in the end? – Jun Sep 22 '21 at 00:28

3 Answers3

16

There is a way to do this - its called granular synthesis (link points to a pd theory link, but the theory is universal). The idea of granular synthesis is that a sound is sampled at the original speed, but it is played at a different speed from each sample point, however with the advantage that the pitch is not altered.

These Github Web Audio Granular Synthesiser links may help you (the first one is better): 1. Web-Audio-Granular-synthesis 2. Another link on Github2

Failing any success with WebAudio, there is the alternative; bring the mp3 into Audacity and change the tempo that way, and then use the new file! ;)

Believe me, I understand your pain, I spent weeks in uni trying to do exactly the same thing with pd-extended. Came near to tearing my hair out. My professor introduced me to the concept of granular synthesis - saved the day!

Good luck!

Rachel Gallen
  • 27,943
  • 21
  • 72
  • 81
  • Based on your research, do you have any idea if "preserve pitch" is going to be added natively to the Web Audio API? – Brian FitzGerald Jul 11 '16 at 14:43
  • @BrianFitzGerald i don't think it has been raised as an issue with the developers of the WebAudioAPI, but as others have developed plugins for it, i see it as a possibility that they will integrate them. I don't know for sure! – Rachel Gallen Jul 11 '16 at 14:48
  • 1
    Thanks Rachel! I have raised it on the Chromium issue tracker just now. Not sure if that's the best place, but hopefully someone sees it: https://bugs.chromium.org/p/chromium/issues/detail?id=627111 – Brian FitzGerald Jul 11 '16 at 15:02
  • @BrianFitzGerald brilliant, you may have paved the way for developers everywhere!!! :) – Rachel Gallen Jul 11 '16 at 15:04
  • 1
    Thank you, thank you. You're too kind. First, I would like to thank my parents for inspiring me to be my best, my fellow developers for always pushing the limits of technology, and finally the Chromium team (in advance) for adding this wonderful feature to the Web Audio API. You da real MVP. – Brian FitzGerald Jul 11 '16 at 15:14
  • 1
    @hahaha your oscar awaits!! ;) – Rachel Gallen Jul 11 '16 at 15:15
  • 1
    @BrianFitzGerald i raised it just now with w3c, they developed it initially. https://www.w3.org/Bugs/Public/show_bug.cgi?id=29728 add yourself to the cc list! – Rachel Gallen Jul 11 '16 at 15:43
  • CC Added! Thanks a lot for doing that Rachel. It would be an amazing feature to have. – Brian FitzGerald Jul 11 '16 at 15:54
  • Hi, changing AudioBufferSourceNode.playbackRate still doesn't seem to preserve pitch as of 2021. Do you know any way to preserve the pitch when changing playbackRate? – Jun Sep 22 '21 at 00:33
5

That's not natively (easily) supported by the current version of WebAudio, but it's possible using Tone.js:

let semitones = 3;
let source = new Tone.Player(AudioBuffer);
let shift = new Tone.PitchShift(semitones);
source.connect(shift);
shift.toMaster();
source.start();
dhilt
  • 18,707
  • 8
  • 70
  • 85
Jacob
  • 527
  • 1
  • 5
  • 14
  • This will work to slow playback down, and to shift the pitch… but how do you figure the relation between the two? i.e.: which speed requires which pitch shift? – Fabien Snauwaert Nov 22 '18 at 01:30
  • 4
    @FabienSnauwaert try `shiftToSemitones = shift => -12*Math.log2(1/shift)` and `semitonesToShift = semitones => (2 ** (1/12)) ** semitones` – Jacob Nov 22 '18 at 08:56
  • Hi Jacob, can you give some examples using playbackRate as an example? For example, when I change playbackRate to 1.5, how much pitchShift do I need? Thank you – Jun Sep 22 '21 at 01:18
  • @Jun711 You can use the functions in my previous comment to calculate the necessary pitch shift. For example, `shiftToSemitones(1.5)` returns just over 7 semitones (a perfect 5th). In other words, increasing the playbackRate by 1.5 will shift up by 7 semitones, so you'll need to shift down by 7 semitones to compensate. Here's a chart you can also refer to: http://moz.ac.at/sem/lehre/lib/cdp/cdpr5/html/TRNSCHRT.HTM – Jacob Sep 23 '21 at 03:07
  • @Jacob ok, I will try your suggestion tomorrow. I asked on Tone.js github and https://github.com/Tonejs/Tone.js/issues/951 and Yotam asked me to try GrainPlayer from Tone.js I tried it and it seems to have some echo compared to changing playbackRate using audio element https://codepen.io/juny711/pen/abwjaJE You can read more on the Github thread – Jun Sep 23 '21 at 03:18
1

There is now a property called playbackRate on the audio and video elements that do just this. I don't need modify the audio data itself, just play it back more slowly - so this is perfect for my scenario.

var myAudio = document.createElement('audio');
myAudio.setAttribute('src','audiofile.mp3');
myAudio.playbackRate = 0.5;

More Info:

https://developer.mozilla.org/en-US/docs/Web/Guide/Audio_and_video_delivery/WebAudio_playbackRate_explained

Live Example:

https://jsbin.com/UGIxoJis/1/edit?html,output

Brian
  • 6,910
  • 8
  • 44
  • 82