The Ultimate DIY Noise Machine

I’ve always wanted to buy a noise machine to drown out extraneous sounds and make it easier to sleep or just relax. However, I’ve never found one with the level of quality and features I want at any price. A large full range speaker and strong amplification are key. (One unit boasted that it had a 52mm speaker! Why not just call it a 52,000,000 nm speaker?) The sounds are typically monophonic and generated in real time (“non-looping”) by an approximation algorithm.

Generating sounds in real time is actually not a bad idea for something constant like white noise or pink noise. In fact, my colleague Tomas has an excellent white noise generator currently available on balenaHub. A fan or air cleaner is also a great way to generate constant noise. A few noise machines do use an internal fan-like system and those seem to work well if that’s the only sound you need.

However, my requirements for a noise machine are somewhat steeper:

  • Must produce CD-quality stereophonic audio.
  • Use real audio samples with gapless undetectable looping
  • A high quality amplifier and speaker system and/or line level audio output
  • Intuitive control panel with rotary wheel and LCD screen
  • Web-based control with a responsive UI for any client

Here’s my initial plan for the ultimate noise machine, a ridiculously over-engineered device running on a Raspberry Pi 3B+ and taking advantage of many features of the balena platform:

I’ve decided to forego an internal amplifier/speaker initially to keep things simpler, and use a line out jack to connect a powerful amplified speaker with subwoofer.


Since the core functionality will be audio playback, I’m looking for a good Python library to play back audio files. This will likely happen in its own container that exposes an API for play, stop, etc…

The most important feature is that it can loop the audio file playback without any gap or audible clicks. It would be nice if it also has PulseAudio support so it works seamlessly with the balena audio block which will take care of all audio setup and routing on the device so I don’t have to worry about that aspect.

I tested playsound, PyAudio, MPV, headless VLC and SOX. Although they all had their strengths, I could not get gapless looping of audio files to work with them. (That could be my fault somehow and not a weakness of the library itself!)

I finally tried Pygame and was able to get it working in a few lines of code:

import pygame


One catch is that to work seamlessly it must use uncompressed PCM format wav files (not mp3) so I’ll have to make sure to convert any files I want to use. Nothing that Audacity can’t handle.

That plus a little more code along with FlaskAPI and my noise service was ready! Here is the repo: GitHub - alanb128/ultimate-noise-box: Turn a Raspberry Pi 3 into the ultimate noise and relaxation mac

1 Like

Yes! This is going to be great to follow along with Mr @alanb128

I’ve come up with a block diagram of how this will all work - it’s going to use a lot of containers!


Here’s the list:

minio - S3 compatible object storage. This provides a web interface for uploading new audio files and their associated jpegs to the device.

redis - An in-memory data structure store. It can periodically write to the local storage as well. I’ll use this to store the values of the preset buttons, last volume level and most recently played file. I could use SQLite but I don’t feel like writing any SQL today and this is cooler.

audio block - our beloved docker image that runs a PulseAudio server optimized for balenaOS and is the core of balenaSound.

noise - The first custom piece of software for this project, as decribed above. A simple Python application that exposes an API for playing or stopping a selected audio file.

webserver - A simple Node.js and Express web server, with a page for controlling the noise box and assigning presets. Based on this example.

controller - A custom Python program that responds to button presses on the control panel, reads the rotary dial position and drives the LCD display.

WiFi Connect - A balena block for for dynamically setting the WiFi configuration on a Linux device via a captive portal.

The web server is (mostly) completed! The web interface mirrors all of the functions available on the physical control panel. This includes playing, stopping and volume control.

In addition, the web interface allows any available sound to be set as one of the four presets, available at the touch of a button on the physical control panel.

I’ve added the rest of the containers to the docker-compose file with the exception of the controller. That’s the container that will interface with the physical control panel buttons. However, I have created the schematic diagram for the control panel:

Next I’ll create a parts list that includes everything required to complete the build. Note that the control panel and display are optional - the entire project could be operated solely using the webpage.

Progress has been slow on this project, but not a complete standstill. Setting up the rotary encoder has proven challenging, so I switched to a more streamlined option: The Adafruit I2C QT Rotary Encoder with NeoPixel. This is a small 1" by 1" PCB with an onboard processor that handles all of the rotary encoder logic and provides position data via an I2C output. (You still need to solder on a rotary encoder though because it’s not included.)

The best part about this unit is that it provides an interrupt pin you can connect to the Pi. When the encoder is rotated or clicked, it sends a pulse out to the Pi so you can read the new value.

I’ll be updating the code, schematic and parts list to reflect this new design!

My first prototype was recently completed. I used a stock case but 3D printed my own front control panel to hold the buttons, screen, and encoder board. This version uses a Pi 3B+ or Pi4 and I’ll be posting the STL files and updated code to my repository soon after a little more tweaking.

Next up: a smaller version using a Pi Zero 2W!