Simple technique for car engine sounds in video games
Andrew Buntine May 28, 2016
When I was working on Swervin' Mervin, there was one thing that constantly sat on my TODO list. It seemed simple enough, but getting rid of it proved a lot harder than I'd initially thought.
All I wanted to do was:
Generate engine sounds based on speed
I didn't know exactly how I was going to do it, but I knew a couple of things. For example, I knew that the effect didn't need to be perfect. It just needed to get the general idea into the players head and their imagination would do the rest. I also knew that I didn't want to fall too far into the rabbit hole of audio signal processing because I knew that once I climbed in, I'd either never come out or I'd come crawling out a defeated mess of a Human.
My first thought was to generate a sawtooth wave and set the frequency based on the players speed. I knew it could theoretically work because the sound programmer(s) on the classic arcade game Pole Position used a similar (but more advanced) technique. I setup a little prototype and it worked fine, but unfortunately, sounded almost nothing like a car engine. I've recreated the effect using the WebAudio API. I started dabbling with more advanced waveforms, but quickly realised I was slipping into the aforementioned rabbit hole of doom.
If I was releasing Swervin' Mervin in 1979, my half-baked attempt at waveform generation may have been sufficient. Alas...
My next idea was to find a soundbite of a running engine that I could seamlessly loop and simply shift the pitch and/or playback rate in response to the increase of the players speed. This idea fell to pieces when I realised that the sound libraries in Pygame simply didn't support seamless looping. There was a few milliseconds gap between each loop, which totally ruined the effect. But then I noticed in the documentation that I could queue sounds. Awesome! But, to my dismay, it simply didn't work. I tried everything I could, until I eventually found out that it kinda' just doesn't work. Damn...
I have recreated the car engine soundbite effect again using the (quite obviously) far more powerful WebAudio API. As for a simple engine effect, this one actually works pretty well for me...
I had one final idea that involved playing a soundbite of a car engine from idle to full acceleration and keeping track of the position we were at in the stream. If the player stopped accelerating, another soundbite that was a reverse of the first would start playing from the same position. Pretty simple, huh? Well, it turns out that Pygame doesn't provide us with an easy way of tracking the current position in a sound file! The WebAudio API does, of course...
These little experiments taught me an important lesson:
Be extra careful in the dependencies you choose!
I always knew that car engine sounds was something I wanted to add into Swervin' Mervin, but I was so confident in Pygame that I never really bothered to look into exactly how "powerful" it was. As it turns out, Pygame is all but dead and the last stable release was from over 6 years ago! Like all things in life - don't make decisions lightly... Happy coding.
The WebAudio API examples I mentioned here can also be found in my repository on Github.