I figure this is a Game Development question as this is a sound generation tool made specifically for games (in particular, Ludum Dare games).

I have a basic understanding of how sound works, with the changing amplitudes causing changes in pressure to produce sound. What I wonder though is how you go about making sounds through programming, and more specifically how sfxr does it. My approach would be to have an array of values representing each amplitude and then some how send it to the speakers. But how do you do that? Are there libraries that sfxr uses?

| improve this question | | | | |
  • 2
    \$\begingroup\$ You do know it is open source right? Here is an XNA port of it: xnasfxrsynth.codeplex.com \$\endgroup\$ – zfedoran Mar 22 '11 at 3:24
  • \$\begingroup\$ I noticed he did say you could get the source code, but where is the code to the original? I quickly glanced over the sfxr-sdl-1.1.tar.gz link he has on there, but couldn't find the audio bits. I'll take a closer look at it later, as well as that link to the XNA one (which is REALLY useful btw. I had no idea you could get that much control over sound in XNA. Thanks!) \$\endgroup\$ – Jeff Mar 22 '11 at 12:17

Well, you usually don't have to go low level and transport the audio data to the speakers. The operating system has an interface for that (be it ALSA, DirectSound, CoreAudio, etc). Using that library, you just have to periodically give it a block of samples of a fixed length (for example, 512 samples). The sound library stores that array in an internal buffer and plays it.

If your block is, for example, 512 samples long, and the sampling frequency is 44.1Khz, this means that you have 512/44100 = 11 milliseconds to generate the next block of 512 samples. If you take longer to update, usually the old block is replayed again (the sound doesn't stop). That sounds like a broken CD, very annoying. You don't want that. I guess what sfxr does is store the whole wave and just copy the relevant chunk to memory, that operation takes virtually nothing.

On top of that, there are other libraries that provide an abstracted API and "talk" to the operating system's sound architecture. This way you can easily write multiplatform applications without having to adapt your sound code to each system. Examples of them are fmod, OpenAL, SDL, PortAudio, and a long etcetera.


sfxr uses PortAudio for its Windows version and SDL for the other platforms. If you look at the very end of main.cpp, you will see how these engines are initialized. PortAudio is passed pointer to a function called AudioCallback, and SDL is passed a pointer to SDLAudioCallback. You can see that what these functions do is to process a block of 512 samples and copy it to the output buffer. The processing itself is done in a rather complex function called SynthSample, which is the one that produces the desired output samples for a block given all the internal parameters of sfxr's synthesiser.

| improve this answer | | | | |
  • \$\begingroup\$ Thanks, that's exactly what I was looking for! I wonder why not use PortAudio or SDL for both? In the comments it says "ancient portaudio stuff" before defining it for win32. But aren't SDL and PortAudio both cross platform? \$\endgroup\$ – Jeff Mar 22 '11 at 16:59

I started writing this answer, and it just got longer and longer, so this will be the verbose answer, so take from it what you will. Like CeeJay said though, you don't need to worry about this stuff typically. Especially so if you can use an API like FMOD, Wwise, or XACT that lets your sound designer hook everything up themselves so that you're not saying "play this.wav" but instead "trigger the 'PlayExplosionSound' event" you'll have a much easier time integrating sound into your game.

SFXR works by building some fundamental sound generators and offers the parameters you see in the GUI. Both XNA and ActionScript 3 have recently provided a way to directly pass samples to the underlying mixing engine on-the-fly. XNA could already define static sample buffers (looks like XNASfxrSynth uses this), but now you can have a DynamicSoundEffectInstance fire an event requesting you to feed it a sample buffer. This greatly reduces your memory footprint for continuously generated audio signals. You could technically write your own mixing engine as well, just have a single master sound instance to which all your sample buffers are sent for mixing.

A general example of making a sine wave generator can be found in Adobe's documentation for their new sampleDataEvent event in the Sound class. It's really just about knowing how digital audio works and constructing the correct sample buffers to get the sound you want. Also, look at Andre Michelle's site for more awesome advanced audio processing in Flash.

Like CeeJay said, audio data typically has an associated sampling frequency (usually 44.1kHz or 48kHz--Battlefield Bad Company uses 48 to achieve high fidelity playback when you've got a good 5.1 system hooked up). When working with digital audio, you have to worry about something called the Nyquist frequency. Basically, the highest frequency you can represent in an audio signal is half of your sampling frequency. The reason why 44.1kHz and 48kHz are the most common sampling frequencies is that the range of human hearing is roughly 0 to 20kHz. Thus 44.1kHz and 48kHz do a pretty good job at reconstructing a high fidelity sound on most consumer's systems.

It also has a bit depth, which is typically 16 for the final mix. This means that you have 16 bits to represent the amplitude of each sample, -32768 to 32767. This translates roughly to having a volume range of 96 dB to work with. The standard intensity limit for sound in a movie theater is 85 dB SPL (the SPL bit is a way to standardize the loudness, since the decibel system is relative), so 16 bits work really well for a final mix on most consumer's systems.

Often a game will do some internal mixing using 32 bit floating point values and then convert to 16 bit before pushing to the sound card. The reason for this is the same reason you will record in 24 bit with a 96kHz sampling frequency. When you start manipulating sound, you want as much headroom as you can get. Digital audio effects can sometimes introduce cool new high frequency signals that then get manipulated further down the signal chain and have an affect on the final output. These may get cut off when you mix down to 16 bit, 48/44.1k, but you will have preserved all the data along the way. It's like keeping a copy of your high-res .PSD file that just gets re-exported every time you need to alter an art asset. Except this is all happening in real-time in the audio engine.

If you want to read more about the lower level concepts of audio programming, I recommend looking at The Audio Programming Book by Richard Boulanger & Victor Lazzarini. I just received my copy a few weeks ago, and it does a great job at easing you into the concepts of audio programming (the introductory C chapter's kind of a tedious though since there's important concepts in it you can't miss, but you also have to sit through explanations of pointer arithmetic).

Another good book is Who Is Fourier?. It assumes little math background and covers the basics of the Fourier transform and general wave theory in the context of language researchers trying to study speech patterns. Kind of has the kiddie introductory Japanese language textbook feel with cute hand-drawn characters, but at the same time it's talking about Riemann sums by the second chapter.

| improve this answer | | | | |
  • \$\begingroup\$ I already have a basic familiarity with the Nyquist frequency and some Fourier transform understandings. I'm more interested in how you actually go about sending say a sample that you made to the speakers. The links you posted look interesting, I'm especially interested in getting that Audio Programming Book, thanks! \$\endgroup\$ – Jeff Mar 22 '11 at 16:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.