The baudio module returns a readable stream that generates raw audio data. It requires SoX to play or record audio, which should be installable from your package manager (Debian has it, and so does Homebrew).

The callback passed to the baudio function receives two arguments: t and i – the time in seconds, and a counter. The callback will be run using process.nextTick to generate a stream of audio data. The audio data will be passed to SoX for playback or recording using child_process.spawn.

The audio data itself is where things get interesting. The baudio stream is sent directly into SoX through SoX’s “pipeline” mode, in which audio data is read from standard input, using the “s16” format – it’s streams all the way down! Internally, baudio converts the float values returned from the callback into integers, which are written to a buffer using Node’s buf.writeInt16LE method.

Your callback should generate floating point values between -1.0 and 1.0. By default, baudio is set to use a frequency of 44 kHz – that’s 44,000 values a second. This is close to CD quality (44.1 kHz).

Unless you’re well-versed in audio programming, generating sounds with baudio is going to be hard work. To help you understand what’s going on, I’ve written a small example that uses gnuplot to visualise the output.

Now your graph should look like a wave, but you won’t hear much sound:

A much shorter sample shows the output really is a sine wave.

Wave Period and Amplitude

The simple example I’ve used above is focused on controlling the “wave period”, or the pitch of the output. To demonstrate this, try changing 261.626 to 60.0:

Some sub-bass.

Now the output is a lower pitch, and the graph makes this clear because you can see there are less cycles in the same amount of time. So we’ve mastered pitch, but what about volume?

It’s actually easy once you know what the wave equation is doing. The generalised equation is A sin(t - K) + b (from Amplitude on Wikipedia). In programmer-speak, this equation can be written as A * sin(t - K) + b, where A is the “peak amplitude of the wave”, t is time (which we already know baudio gives us), and K and b are offsets for the wave (which I’m not going to talk about here).

That gives rise to the following example that allows volume to be controlled by adding a variable, vol, for A:

A quieter audio sample, plotted with set yrange [-1.0:1.0] to correct the axis.

More Fun Stuff

If you’ve managed to get gnuplot and SoX installed and played around with these examples, then there’s more! First, try taking a look at plucky, which can be used to make “arrangements” of callbacks that generate different channels of audio. Also, James wrote beepstep.js which is a much more involved example than anything I’ve talked about here.

And, James tweets about this stuff, so follow @substack if you’re into streams and audio hacking.