How can I dynamically change the speed of a .wav or. aiff file using an arduino in real time

Viewed 213

I'm working on a prototype for a lightsaber that changes the pitch and volume of its hum sound as it moves. The current solution only changes the volume (easy), and it doesn't sound realistic enough. I know I need to use .wav or .aiff (not lossy like mp3) to accomplish this. Ideally I'm looking for a lightweight solution, as I plan on running the final iteration of this on an Arduino Nano extra. So, the question is, how can I alter the speed a .wav or .aiff is read/output (thus changing the pitch of the sound)? Regardless of computing power, does anyone know ANY approaches that could accomplish this in real time?

2 Answers

To change the pitch of a stream of audio samples, you need to change its sample-rate. The "easy" way to do that would be to change the frequency of the audio hardware's sample-clock, e.g. if you wanted to increase the playback pitch by 10% you would set the DAC to convert 52,800 samples-per-second rather than its normal 48,000 samples per second.

On most platforms I've used, however, you aren't allowed that level of control over the output-sample-rate setting. Usually they only let you choose from a small number of "standard" output rates like 44100, 48000, 96000, etc. Perhaps Arduino allows fine-grained control over the DAC's sample rate, however; in that case you have an easy solution.

If not, the alternative approach is to instead change the contents of the sample-stream you are feeding to the audio device in such a way that it acts like it is playing samples at a different rate. This is called sample rate conversion, and doing it accurately is non-trivial. If you don't need accuracy (e.g. because you are just doing lightsaber sound effects and adding noise to the output isn't a problem) you could do a quick-and-dirty job by simply dropping every (nth) sample when you want to increase the pitch, or repeating every (nth) sample when you want to decrease the pitch. The value of n would be determined by the ratio of your desired "virtual sample rate" compared to the audio output's actual sample rate; you'd need to do some math to figure it out but it shouldn't be too hard.

If, OTOH, you want a decent-quality sample rate conversion that doesn't add artifacts and noise into the output, then you'll want to use a proper sample-rate-conversion library like libsamplerate to handle the necessary math for you. It does a very good job of avoiding added noise and artifacts, and you can specify varying levels of quality if you need to trade off quality to get reduced CPU usage. For a real-time effect, you'd probably want to use the callback interface so that you can change the pitch-ratio on the fly.

Note that either of the above two approaches change not only the pitch of the playback but also its duration -- e.g. if you increase the perceived pitch of the sound effect by 10%, you'll also end up with a sound effect that finishes playing back 10% faster than the original. If you want to be able to change the sound's pitch without changing its duration, there are algorithms out there that can do that, but I don't have any experience with them so I can't comment on their applicability to this use case.

Hmm... I'm not entirely sure how this would work. It's my understanding that .wav and .aiff files are raw audio (maybe that's why you say you need to use them) I did find this answer Python change pitch of wav file but it uses python, which won't work for your Arduino, but its possible you could apply this technique using C++. Maybe someone else who knows more about this could take a look at that and explain how it might be done in C++

Related