/audiobox

>> A music-reactive LED box with Spotify integration

Primary LanguageC++

Audiobox application icon Audiobox XL

Audiobox XL is a music-reactive LED box with Spotify integration.

Table of Contents

  1. Features
  2. Images
  3. Software Design
  4. Hardware Design
  5. Tools, Libraries, and Attributions
  6. Additional Examples

Features

  • Display album art corresponding to the music playing on a linked Spotify account
  • Extract the color palette from the current album art and use it to color visualizations
  • Display a variety of FFT-based music visualizations using an external microphone
  • Automatically adjust the physical LED panel position for diffuse vs sharply defined art
  • Two push-buttons for mode control
  • Browser-based UI for control and setup
  • Command line interface for setup

Images

Album art for the album "Ganging Up on the Sun" by Guster
Audiobox with album art
Transition to lava lamp display mode
Audiobox with lava display Audiobox with lava display
Music-reactive display modes
Side view of Audiobox with vertical music-reactive display Front view of Audiobox with diffuse music-reactive display

Software Design

Tasks

Seven FreeRTOS tasks are utilized to manage various control loops. A global event handler object manages communication between tasks. Tasks can independently emit messages to the event handler object, which then passes messages back to tasks that have subscribed to specific message types. In this way, no task needs to communicate directly with another -- all inter-task communication happens via the event handler.

Note the Spotify task is pinned to CORE0 and all others to CORE1. Empirically, the Spotify task has proven to be significantly more stable on CORE0, perhaps due to the WiFi libraries also running there.

Spotify Integration

Spotify's Web API provides music playback information pertaining to the currently linked user account. The authorization flow requires a Spotify user to log into their account and allow the application to read "user-read-playback-state" and "user-read-playback-position" information.

Control

The browser-based UI is served directly from the ESP32 using the ESPAsyncWebServer library. Server-sent-events (SSE) are used to update the UI contents in realtime as audio tracks change.

Desktop and mobile browser UI
Screenshot of desktop browser controller with music playing Screenshot of mobile browser controller with music playing

Color Palettes

Color palette generation uses a "mean cut" algorithm (similar to median cut) to recursively sort and split groups of pixels at their mean (e.g. average R, G, and B). This results in "buckets" of pixels with similar colors. The average of the pixels in each final bucket approximate the most dominant colors in the input image. By default the algorithm runs to a depth of 4, resulting in 2^4 = 16 final colors.

Example color palettes
Screenshot of album art and color palette Screenshot of album art and color palette
Screenshot of album art and color palette Screenshot of album art and color palette

Memory Allocation

In general the code in this project makes use of static memory allocation and avoids use of Arduino Strings where possible to avoid heap fragmentation. However, album art jpgs, ArduinoJson objects for Spotify response parsing, and the LEDNoisePattern object are all allocated on the heap.

The event handler task can optionally dump the maximum stack usage for each task, allowing for fine-tuning of stack allocation. Note that the ESPAsyncWebServer dynamically allocates memory to manage HTTP requests, drastically reducing available heap memory during client requests.

Hardware Design

Why XL?

Designing the Audiobox XL was an iterative process, with an initial version that was based on an 8x8 LED panel with no LED panel actuation. I've retroactively named the earlier device Audibox Mini. While the much lower pixel resolution meant album art couldn't be accurately displayed on the Audiobox Mini, the initial prototype helped flesh out many of the electrical, mechanical, and software design elements that made it into the Audiobox XL.

Audiobox Mini and Audiobox XL

Electrical Design

The core elements of the Audiobox are an Espressif ESP32 development board and a 16x16 LED panel consisting of WS2812B RGB LEDs, arranged in a serpentine pattern. An SG90 micro servo motor adjusts the distance of the LED panel from the front diffuser. The LED panel and servo motor consume significant current and necessitate the use of an external power supply (5V 10A) to avoid instability and brown-out.

ESP32 dev board

The SPH0645 digital I2S MEMS microphone provides audio input. I wanted to find a way to make the microphone user-adjustable in order to configure the Audiobox with different speaker arrangements, and came up with a way to utilize an off-the-shelf telephone cable and jack to do so. The SPH0645 requires a 6-pin connection, which matches perfectly with RJ12 telephone cables/jacks. The current design uses this RJ12 cable, with one end cut and individual wires soldered onto the SPH0645 break-out board. The board is then enclosed within a custom 3D printed shell with an acoustic port for the microhpone.

Microhone wiring and enclosure

Mechanical Design

Under the hood, the LED panel is attached to a rack-and-pinion system that moves the display with respect to the diffuser. This allows for different LED effects (soft and diffuse vs sharply defined). The ESP32 drives this behavior via commands to the servo motor. The rack-and-pinion is a custom 3D printed design, taking inspiration from various linear actuator designs I found online. One change I made was to have the rack be stationary instead of the motor/pinion/base. This helped enable a more robust attachment mechanism between the LED panel and the rack-and-pinion structure. To reduce wobble of the LED panel as the motor actuates, two small "sleds" were 3D printed and attached to the bottom of the panel as guides. This, along with the use of synthetic grease (Super Lube) on the sleds, rack, and pinion provide smooth actuation.

LED panel actuation

The LED panel itself has a laser cut grid placed atop it, which helps limit light bleed between neighboring LEDs. This is particularly noticeable when the LED panel is very close to the diffuser and gives each LED the appearance of a square pixel. One downside is that as the panel moves away from the diffuser some edge effects from the grid are still visible. This is one aspect of the design that still needs some tuning.

LED grid

The plastic diffuser on the front of the box is 1/8" thick Chemcast Black LED Acrylic from TAP Plastics. Unlike typical white diffusers, I think the black acrylic matches the dark wood aesthetic of the box as well as other devices in the the living room where the Audiobox typically resides. The diffuser has 4 small magnets attached to the corners, which mate with 4 magnets on the front of the box, making it easily removable.

The outer enclosure is a custom-designed, laser cut wooden box, using 1/4" sapele. I used simple box joints along with T-slots and hex nuts/bolts to enable assembly without the need for glue. Initial prototypes utilized 1/8" Baltic birch, which proved to be too flimsy for a box of this size. The 1/4" wood is sturdy and feels nice in the hand. I finished the sapele with a few coats of Watco Danish Oil (Natural), which I discovered while working on a separate jewelry box project. The Danish Oil adds an amazing color and depth to the wood while providing protection without the plasticky feel of typical polyurethane finishes.

Danish Oil magic

I set up a camera to record a timelapse of the final assembly of the Audiobox XL, after applying the finish on the wood pieces. See it here!

Tools, Libraries, and Attributions

IDE

Libraries & Code

This project makes use of the open source libraries listed below. All libraries are installed via the PlatformIO plugin in VS Code. Links below do not necessarily map to the same version of the library used in this project. See platformio.ini for the actual dependencies.

  • Arduino - base libraries for ESP32
  • FastLED - for manipulating LEDs
  • ArduinoJson - for decoding responses from Spotify Web API
  • TJpg_Decoder - for decoding album art jpgs
  • ESP32Servo - for controlling servo motor
  • ArduinoSort - for sorting pixels as part of color palette subroutine
  • fft - for converting audio signal to frequency domain for visualizations
  • base64 - for managing Spotify Web API authentication
  • ESP Async Webserver - for managing browser-based UI
  • s-marley - reference code for vertical bar LED visualization modes
  • Random Nerd Tutorials - variety of references for working with ESP32 libaries

Similar Projects

During my time developing the Audiobox I have come across a few projects with many similarities, some available commercially:

Additional Examples

"Golden Hour" by Kacey Musgraves
Audiobox with album art
Audiobox with music reactive display Audiobox with music reactive display
"The Resistance" by Muse
Audiobox with album art
Audiobox with lava display Audiobox with lava display
"The Phosphorescent Blues" by Punch Brothers
Audiobox with album art
Audiobox with lava display Audiobox with lava display
"Unlimited Love" by Red Hot Chili Peppers
Audiobox with album art
Audiobox with lava display Audiobox with lava display
"Mars Audiac Quintet" by Stereolab
Audiobox with album art
Audiobox with lava display Audiobox with lava display
"seeds" by TV On The Radio
Audiobox with album art
Audiobox with lava display Audiobox with lava display
"American Idiot" by Green Day
Audiobox with album art
Audiobox with music reactive display
"Nice." by Super Guitar Bros.
Audiobox with album art