tl;dr - How to generate different types of noise in Python.
Fixing An Annoyance
I’ve recently been experimenting with using different types of noise to help me relax. As I quickly learned, there are several different types of noise named after different colors. Before starting on this project, I really could only say that one sounded “harsher” than another.
I started looking for playlists on Spotify and Youtube for different types to try and see which would help me focus and which would be the most relaxing. Some types mimic sounds in nature like a rain storm, or a waterfall, etc.. The most basic type of noise is white noise and I definitely found it to be the hardest to listen to for any length of time. There are other types like red and pink noise which have the higher frequencies reduced. These types of sound way less like static and are much easier on the ears.
So What’s the problem?
I found a few “rain storm” tracks that I liked but there were a couple of issues with looping them. For one, they often fade in at the beginning and out at the end of the track. This completely breaks the immersion every ten minutes when it restarts. Secondly, my phone stops the streaming app after several minutes/hours, so having a local file would probably be better. Now, I could have probably found a random free noise online and edited it to try and make a loop-able version, but I would have to do this for every different type of noise I want and hope the quality was good enough. So instead, I decided I would write a script to generate them for me!
White Noise
Like I mentioned earlier, white noise is the simplist type of noise and its the easiest to create as well. White noise is just totally random values. This is why it sounds like general static, because it has roughly equal amplitudes for any part of the sound spectrum. To generate this, you just need to generate “sample rate * number of channels * number of seconds” values and them write them to a new wave file.
Generating these values is super easy with numpy:
size = sample_rate * num_channels * seconds
rng = np.random.default_rng()
return rng.integers(
low=min_value,
high=max_value,
size=size,
dtype=np.short
)
Here, the min_value and max_value are the lowest and highest int16 value, respectively. Next, these values just need to be written to a wave file with a valid header. Python’s wave library makes this super easy since I don’t need to create the header manually like I did for my post on creating wyoming-cli.
Fourier Transforms
Next, to create some of the other types of noise. One easy method is to just take the white noise I generated and modify the different frequency’s amplitudes using fourier transforms. Again, numpy to the rescue.
I transform the generated values using the ‘rfft’ function. This outputs a list of complex values and gives access to different amplitude groups:
np.fft.rfft(white_noise)
Then, by passing the sample count and sample rate to the ‘rfftfreq’ function, I get access to a list of the frequencies the ‘rfft’ list elements represent:
np.fft.rfftfreq(size, d=(1./sample_rate))
With that I have everything I need. For example, Pink noise can be generated by adjusting each frequency element by 1/sqrt(freq). This makes it so that the higher the frequency, the lower the amplitude just like you’d expect. And then the values can be converted back to a signal for the wave file:
freq_modifier = 1./np.where(freq == 0, float('inf'), np.sqrt(freq))
...
np.fft.irfft(white_noise_rfft * freq_modifier).astype(np.short)
Note the astype conversion at the end. This is needed so that when I write the final values to the wave file they are the correct size. Several other types of noise can be created using this method of adjusting white noise based on frequency. I published a Python project called noise-generator-cli, check it out if you want to try generating different types of noise yourself!
Bonus: Creating Album Art With Imagemagick
I really dislike seeing the default album artwork in my music app. So, I took a photo of some clouds while on a walk. Then using Imagemagick’s “tint” feature, I generated artwork for each different type of noise by changing the color of the mid-tones:
magick white_clouds.jpg -colorspace gray -fill red -tint 100 red_clouds.jpg

Time To Relax
And with that, I can create as much noise as I want. I enjoyed learning how to use the ‘fft’ functions in Numpy and I have some interesting ideas on what to tackle next, so stay tuned for that.
Until next time!