Web Audio - How to change playbackRate of all sounds instantly?

337 views Asked by At

When using Web Audio, you can connect all sounds you create to one globally created gainNode and use that node to have a "Master Volume" property. This is very handy when you want to be able to change the master volume on the fly and want it to affect all sounds immediately.

Now, I am trying to accomplish the same, but for playbackRate. For reference: this would be for a web game where you can use a power-up to slow down time, which should also slow down all music and sounds.

Each sound I create is a AudioBufferSourceNode linked to a chain of processing nodes. Now I know that the the AudioBufferSourceNode itself has a playbackRate property you can change. This is great, but it'd require me to cache all AudioBufferSourceNodes I create, loop over them and change their playbackRate if I wanted to change a "global playbackRate" on the fly. It'd be perfect if I could accomplish this in the same way as with the global gainNode, but couldn't find a way to do that.

What would be the proper way to implement such a feature? Would you recommend caching all AudioBufferSourceNodes created (can be thousands) and loop over them? That's the way I do this with HTML5 Audio, but it seems hacky for Web Audio, which is much more advanced.

If you want more information, please ask and I will update the question!

2

There are 2 answers

0
cwilso On BEST ANSWER

You can't directly do that. There are some source nodes that don't have playback rate controls - like live input. In this case, you're best off doing what you suggest - keeping a list of active sounds to loop through.

You could use a granular method to resample and pitch-bend it down - like the "pitch bend" code in my audio input effects demo (https://webaudiodemos.appspot.com/input/). That's a bit costly to keep around just in case you want to make the effect, though.

0
Elizabeth Hudnott On
  1. Set the playbackRate parameter of each of your AudioBufferSourceNodes to zero.
  2. Create a ConstantSourceNode.
  3. Connect the constant node to the playbackRate parameter of each of your AudioBufferSourceNodes.
  4. Invoke the constant node's start() method.
  5. Use the constant node's offset parameter to change the playback rate of all of the audio buffer sources simultaneously.

However, depending on what other nodes exist in your audio graph you may need to have the constant node influence more than just the sample playback rate in order to achieve the desired effect. For example, if you have a BiquadFilterNode then you'll want to connect the constant node into a gain node and then connect the output of that gain node into the filter's frequency parameter so that when the playback rate is halved then the filter's cutoff frequency is correspondingly halved and everything is kept consistent.

However, even if you implement all of this architecture the pitch of the audio will still change whenever the playback rate is changed because that's just the nature of what it means to alter the playback rate. If you don't want that to happen then you have a problem. Playing samples at twice the speed means twice as many cycles of each frequency that's present in the audio sample will reach the speakers each second and twice as many cycles occupying the same amount of time means a doubling in frequency. That's just how physics works. Modern time stretching techniques which permit manipulation of time independently of frequency are rather more complicated than just pumping through the samples at a different rate. Instead such algorithms rely on sophisticated editing of the sample data itself. Essentially what you would do is:

  1. Divide each sample into a sequence of short blocks.
  2. Perform a Fourier analysis of each block in order to determine which frequencies are present in each block and the amplitude of each one.
  3. Synthesize an entirely new sample based on playing back each of those mixtures of frequencies for a correspondingly longer or shorter period of time than duration of the original block.

Coding the ability to perform such "resynthesis" on the web sounds like a good application for a potential audio worklet.