Is there a simple way to generate brown noise audio? (in C++)

427 Views Asked by At

(This question isn't really C++ specific, I just want to know how this could be generally implemented)

I am working on a hobby project where I want to generate audio data featuring different "colors" of noise, including white, brown, pink, etc..

White noise is fairly easy, in my selfmade framework I can simply write:

for(int i = 0; i < audioSamples.size(); i++)
{
    audioSamples[i] = generateRandomNumberBetween(-1.0, 1.0);
}

This works. In Audacity, the waveform looks like this:

White noise

However, I am not sure how I could implement brown noise.

The wikipedia page says:

Brown noise can be produced by integrating white noise. That is, whereas (digital) white noise can be produced by randomly choosing each sample independently, Brown noise can be produced by adding a random offset to each sample to obtain the next one. A leaky integrator might be used in audio or electromagnetic applications to ensure the signal does not "wander off", that is, exceed the limits of the system's dynamic range.

I came to understand that "brownian motion" is basically just the concept of a "stateful random walk", (like it is described here) and I see how that could be applied to audio data. But I simply lack the specific knowledge on how that could be implemented in the program (the sources on wikipedia weren't of great help).

A first draft of generating brown noise could look like this:

audioSamples[0] = generateRandomNumberBetween(-1.0, 1.0);
for(int i = 1; i < audioSamples.size(); i++)
{
    double randomOffset = generateRandomNumberBetween(-1.0, 1.0)
    audioSamples[i] += audioSamples[i-1] + randomOffset;
}

The resulting audiofile looks like this (after normalizing):

Brown noise prototype

This kind of sounds like brown noise (like the example sample on wikipedia) but it is apparent that there is a problem. Since the value isn't bounded, it can just "walk" off limits and create a nonsensical looking waveform. The wikipedia article also doesn't mention anything about the parameters for this "random offset" (like mean or deviation). However, it does mention that this can be prevented with a "leaky integrator" but I can't imagine how that could be implemented here.

I know that there is an alternative way of generating brown noise by fourier transforming white noise and scaling the amplitudes of the waveforms depending on their wavelength and add them back together again, but I wanted to know if there is any way I could do it the "simple" way first.

1

There are 1 best solutions below

0
On BEST ANSWER

The input signal is $x(n)$ (a real number for each integer $n$) and the output is $y(n)$, it is a convolution (a filtered version of $x$) whenever $$y(n)=\sum_{k=-\infty}^\infty h(k) x(n-k)$$ This is denoted $y=x\ast h$.

The main question is if $h\in \ell^1$ (summable/integrable) that is $\sum_{k=-\infty}^\infty |h(k)|<\infty$. In your code you are taking $h(k)=1$ for $k\ge 0$, $h(k)=0$ for $k< 0$ so your $h$ isn't $\ell^1$.

With this $h$, if $x=0$ for $n < 0$ then $y(n)=0$ for $n<0$ and $y(n)=y(n-1)+x(n)$ for $n\ge 0$, so there is an efficient algorithm.

You can replace $h$ by $h(k)=0$ if $k< 0$ or $k> 10^3$ and $h(k)=1$ otherwise,

or perhaps better by $h(k)=e^{-k/1000}$ if $k\ge 0$ and $h(k)=0$ otherwise, to see what you get. Thisone can be computed as $y(n)=e^{-1/100} y(n-1)+x(n)$.

There are many ways to create filters (ie. the impulse response $h$) the FFT and ARMA are the two most common ones in music.