Dino Fizzotti

Engineer, maker, hacker, thinker, funner.

Aug 21, 2017 - 10 minute read - Comments - Electronics Arduino

NoiseBlanket: Arduino White Noise Player with IR Remote Control

Overview

After a recent sinus/ear infection I began to experience tinnitus. In my case it presents itself as a constant high frequency static hiss/whine in my left ear. It’s been about a month since I first noticed it. Hopefully it will eventually disappear. During the day when I’m at work or around friends I don’t really notice it. However when I’m in a quiet room, such as when falling asleep or in the early morning after waking up, it is quite noticeable and distracting.

I found that playing white noise found on various Spotify playlists (this one is my current favourite) as I fall asleep helps mask the hiss in my ear.

So to help me fall asleep and relax in the bedroom I put together a remote control capable Arduino-based white noise player, using the Adafruit Wave Shield and an IR receiver from SparkFun. This allows me to use my phone to watch Netflix or YouTube, whilst still having the white noise play in the background.

Finished product

Features

  • Plays audio files from an SD card in an endless loop
  • Remote control volume adjust
  • Remote control mute
  • LED activity indicator
  • USB powered, using a micro USB connecter
  • Power on/off with toggle switch.

Components

Generating White Noise With Audacity

The Adafruit Wave Shield plays audio files from an SD card. I am using just one audio file, an hour long recording of white noise I generated using Audacity. The audio file needs to be in a specific format (uncompressed 16 bit, mono, 22050 Hz) to be readable by the Wave Shield. Here I describe how this file was generated and saved.

Open Audacity

Excuse the dark UI theme in my screenshots, it will look different on different operating systems/desktop environments.

Open Audacity

Change the Project Sample Rate

Click drop down on the bottom left of the screen to change the project rate from 44100 Hz to 22050 Hz.

Change the sample rate

Generate White Noise

Click the “Generate” menu option and select “Noise…”

Generate menu option
Audacity noise dialog
Result of Audacity white noise generation

Export the Audio

You are now ready to export this Audacity project to a format that is playable on the Wave Shield. Select the export option from the File menu.

Audacity export audio menu option

Audacity export audio dialog window

Arduino Libraries

The latest version of the Arduino IDE includes a library manager, which makes it easy to import the required libraries for this project.

You will need the “WaveHC” library for operation of the Wave Shield, and the “IRremote” library for decoding the IR signal from the remote control.

To install the libraries, open the Arduino IDE, click “Sketch” -> “Include Library” -> “Manage Libraries…”

Navigate to the Arduino Library Manager

From the library manager you should search for and install the latest versions of the following libraries:

Adafruit Wave Shield

Mimi investigates the Wave Shield

I won’t go into much detail on assembling and getting the Wave Shield working, as there is a comprehensive tutorial available directly from Adafruit:

https://learn.adafruit.com/adafruit-wave-shield-audio-shield-for-arduino/overview

Follow all the instructions and make sure you can play audio files from the SD Card.

Here is a short video of the Wave Shield playing my white noise file:

Software Volume Control

The Wave Shield itself uses a large round potentiometer to allow for manual control of the output volume. However I wanted to control the volume remotely, without needing to turn the volume wheel. Adafruit provide a sample Arduino sketch which makes use of software volume control to adjust the volume: https://github.com/adafruit/WaveHC/blob/master/WaveHC/examples/SoftVolumeHC/SoftVolumeHC.pde

The comment at the top of this sketch reads:

/*
 * DVOLUME must be set nonzero in WaveHC.h to use this example.
 *

To change the value of DVOLUME you will need to find the location of WaveHC.h. On my system it is found at ~/Arduino/libraries/WaveHC/WaveHC.h.

Modify the line #define DVOLUME 0 so that it is changed to #define DVOLUME 1:

Modify DVOLUME in WaveHC.h to be non-zero

You might want to upload and run the SoftVolumeHC sketch to test that your changes were made correctly.

Infrared Remote Control

Arduino IR Remote Control

To provide the remote control functionality I am using a infrared (IR) “PC Remote” which I purchased a while ago to use with a Raspberry Pi. It comes with an USB IR receiver, but I won’t be using that.

To receive IR signals on the Arduino I am using an IR receiver module from SparkFun. SparkFun currently lists this product as “retired”. I bought a bunch a few years ago, and haven’t needed to use one until now! It looks like this product should just about do the same job.

Almost all consumer electronics which use IR remote control do so using a 38 kHz modulation scheme. SparkFun has a great tutorial covering IR basics here.

Capture the Codes

To change and mute the volume for this white noise player you need to be able to read the IR codes sent from the remote on the various button presses, and match them with some hard-coded values in our Arduino sketch which represent the intended action.

The Arduino IRremote library that was installed in an earlier step contains IR codes for many consumer electronics brands, such as SONY, PANASONIC, LG. Unfortunately it does not contain the codes for my “PC Remote”.

Determining which button sends which exact code is done by wiring up the IR receiver to the Arduino and loading this “IR Recorder” sketch to the Arduino. The IR receiver needs 3 connections:

  • VCC to the Arduino’s 5V supply
  • GND to the Arduino’s GND supply
  • OUT to one of the Arduino’s digital pins (in my sketch I am using pin 11)

Once the sketch has been uploaded, you can run the Serial Monitor from the Arduino IDE to view any incoming IR codes, which are printed out as integers. I simply pointed my “PC Remote” at the receiver and recorded the various numbered codes for various buttons. For NoiseBlanket I am really only interested in the codes for the “Power” button and “Volume Up” and “Volume Down”.

Serial Monitor showing the IR recorder codes

Now that I have the Wave Shield working and the IR receiver codes for PC Remote I can put everything together!

NoiseBlanket Arduino Sketch

The sketch running on the Arduino is a modified version of one of the WaveHC library sample sketches: daphc.pde

The “daphc.pde” sketch simply plays every compatible .WAV file that it can find on the SD card in an endless loop. If you wish to learn more about the operation of the WaveHC library I recommend you read through the sketch’s source code, as it contains many comments which explain the setup of the Wave Shield and how the files are read from the SD card.

A great feature of the WaveHC library is that it plays the audio “asynchronously” with respect to the Arduino’s main loop. This allows one to do other things with the Arduino while the audio is playing.

For my sketch I modified a portion of the “play” method to continuously read from the IR receiver, and when matching IR codes are found the intended action is performed. Currently the sketch handles the following three codes:

  • POWER
    • Integer IR code received: 3243761281
    • Mutes/un-mutes the audio playback.
  • VOLUME_UP
    • Integer IR code received: 3223725573
    • Increases the volume of audio playback.
  • VOLUME_DOWN
    • Integer IR code received: 694752261
    • Decreases the volume of audio playback.

My sketch can be found on my GitHub page here.

Here is a snippet of the sketch which shows the handling of the IR codes:

Note that the WaveHC software volume control implementation uses a value for 0 as the maximum volume MAX_VOLUME, with positive integer values representing lower volume levels. A volume level of 12 represents the lowest volume level MIN_VOLUME.

...
while (wave.isplaying) {

    activityBlink();

    if (irrecv.decode(&results)) {
    unsigned long ir_result = results.value;            

    switch (ir_result) {
        case VOLUME_UP:
        if (volumeLevel > MAX_VOLUME && volumeLevel != MIN_VOLUME) {
            wave.volume--;
            volumeLevel--;
        }
        break;
        case VOLUME_DOWN:
        if (volumeLevel < MIN_VOLUME && volumeLevel != MIN_VOLUME) {
            wave.volume++;
            volumeLevel++;
        }
        break;
        case POWER:
        if (volumeLevel != MIN_VOLUME) {
            storedVolume = volumeLevel;
            wave.volume = MIN_VOLUME;
            volumeLevel = MIN_VOLUME;
        }
        else {
            wave.volume = storedVolume;
            volumeLevel = storedVolume;
        }
        break;
        default:
        break;
    }
    
    blink(1, 200); // [Dino] Blink to indicate we did receive something.
    irrecv.resume();
    }

    delay(100);
}
...

You will notice that the statements tracking and adjusting the volume control are seemingly “doubled”. I need to modify the WaveHC library wave object’s volume, as well as keep a local variable volumeLevel updated with the same volume level. This is because the wave object is created anew for each file playback, and the initial volume after object creation is set to be the maximum volume. So I set each new wave object’s volume to be that of the my local volumeLevel value to preserve volume levels between tracks. (I suppose I could also be saving the volume level at the end of track playback and restoring it when the new wave object is created).

I have added some helper functions for the LED activity light:

  • blink will repeat a flash of an LED for a specified number of repetitions and duration.
  • errorLoop will flash the LED repeatedly indefinitely.
  • activityBlink forces a single blink of the LED every 10 seconds.
...
/*
  Helper function which blinks the LED the specified number of times for the
  specified duration.
*/
void blink(uint8_t repetitions, uint16_t delay_duration) {
  for (int i = 0; i < repetitions; i++) {
    digitalWrite(LED_PIN, HIGH);
    delay(delay_duration);
    digitalWrite(LED_PIN, LOW);
    delay(delay_duration);
  }
}

/*
  Helper function which blinks the LED at a rapid pace, endlessly.
*/
void errorLoop() {
   while (1) {
    blink(10, 100); // [Dino] Blink rapidly to indicate something went wrong.
  }
}

/*
  Blinks the activity LED once every ACTIVITY_INTERVAL_MILLIS.
*/
void activityBlink() {
  unsigned long currentMillis = millis();
  unsigned long deltaMillis = currentMillis - savedMillis;

  if (deltaMillis > ACTIVITY_INTERVAL_MILLIS) {
    blink(1, 200);
    savedMillis = currentMillis;
  }
}
...

Finishing Touches

Enclosure

I used a spare black ABS plastic enclosure I found in one of my drawers. I used a Dremel to (not very neatly) cut out holes for the toggle switch, LED, IR receiver, micro USB breakout and speaker.

I used double sided tape to secure the Arduino + Wave Shield to the bottom of the enclosure.

Inside the enclosure

Micro USB Power

I decided to provide 5V DC to the Arduino via a micro USB connector breakout board. I have tons of micro USB cables and USB power supplies from various devices lying around, and this also means less cutting into the enclosure than I would need to in order to expose either the Arduino’s barrel jack or the large USB type B socket.

I soldered some coloured ribbon cable to the breakout, and then added some female header connectors so they can plug straight into the exposed header pins of the Wave Shield.

Toggle switch

I used a single pull, single throw toggle switch inline with the 5V from the micro USB breakout to switch the Arduino on and off.

Activity LED

The activity LED is a 5mm red LED connected in series with a 330 Ohm resistor to one of the Arduino’s digital pins.

Arduino Pins

Here is a rundown of the Arduino pins used, excluding the ones used by the Wave Shield:

  • Vin: 5V from Micro USB breakout (via toggle switch)
  • GND: GND from Micro USB breakout
  • GND: to IR Receiver GND
  • 5V: to IR Receiver Vcc
  • Digital pin 7: to IR Receiver output
  • Digital pin 6: to red activity LED anode
  • GND: to red activity LED cathode

Conclusion

I’m really happy with this build. I use it every night, it definitely helps mask out the noise in my head as I lie in bed trying to fall asleep (or trying to wake up!).

Enclosure closeup