Ring LEDs + Teensy 3.2 + FFT Fun

Neutronned

Well-known member

Something a little different from my prior audio/LED projects - an inexpensive 241 LED circular array, driven by a Teensy 3.2 to create a pseudo plasma effect. I printed an enclosure with translucent PLA and the infill pattern diffuses the LEDs such that the light smears out in interesting patterns. Simple design, simple code and really nice effect.

Code:
// Ring Panel - a simple audio device that utilizes 241 LEDs in concentric rings.
//   A Teensy 3.2 + the Teensy Audio Adapter is utilizes to sample the incoming
//   stereo audio signal and generate the color pattern to be displayed.  The left
//   and right channels are mixed then run through the Teensy FFT audio library
//   function to get 512 frequency bins of level information.  The color pattern
//   sums two adjacent bins (0+1, 1+2, etc.) to create a level value that controls
//   the brightness of each of the 241 pixels.  The display start with the lower
//   frequencies in the center and moves outward.
//    Note that the ring is mounted in a translucent 3D printed case that diffuses
//    the LED output, creating a simulated plasma effect.
//   Based on sample code from Adafruit and prior Teensy projects
//   Rev 1.0 - Nov 18, 2020

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Adafruit_NeoPixel.h>

// **************************************************  * LED PARAMETERS
// pins on the Teensy that are connected to the NeoPixel strings
#define RING_LED_PIN    6

// Number of NeoPixels in each string
#define RING_LED_COUNT 241    // 241 LEDS in the ring

// Declare the two NeoPixel strip objects:
Adafruit_NeoPixel ring(RING_LED_COUNT, RING_LED_PIN, NEO_GRB + NEO_KHZ800);

// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)

#define BRIGHTNESS  64   // default brightness

// **************************************************  * AUDIO ADAPTER PARAMETERS

const int my_input = AUDIO_INPUT_LINEIN; // use line input from adapter board

AudioInputI2S          linein;  //The line input pads on the Audio Adapter
AudioMixer4            mixer;   // mix the L & R channels
AudioAnalyzeFFT1024    my_FFT;  // Compute a 1024 point FFT
AudioConnection        patchCord1(linein, 0, mixer, 0); // send L to mixer input 0
AudioConnection        patchCord2(linein, 1, mixer, 1); // send R to mixer input 1
AudioConnection        patchCord3(mixer, my_FFT);   // send mixed signal to FFT object
AudioOutputI2S         audio_output; // output to the adapter's headphones & line-out
AudioControlSGTL5000   audio_adapter; // object for audio adapter control signals

int colorBase = 0;      // the last color wheel position value for the head LEDs
int pixelHue = 0 ;       // value of the calculated color
byte saturation = 255 ;
byte bright = 0 ;


// **************************************************  ******************** SETUP
void setup() {
  delay(1000);  // 1 sec delay on power up or reset - let's voltages stabilize
  
// **************************************************  ********************
// configure the LED ring
  ring.begin();                   // initialize the NeoPixel object
  ring.show();                    // Turn off all pixels
  ring.setBrightness(BRIGHTNESS); // Set default brightness

// **************************************************  ********************
// configure the Audio adapter
  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(12);

  // Enable the audio shield and set the output volume.
  audio_adapter.enable();
  audio_adapter.inputSelect(my_input);
  audio_adapter.volume(0.5);

  // Configure the window algorithm to use for the FFT
  my_FFT.windowFunction(AudioWindowHanning1024);

}

void loop() {

// FFT **************************************************  ****************** FFT
//  FFTs are sampled in the background, so process when done
  if (my_FFT.available()) {
  // the FFT function creates 512 discrete frequency bins.

  // LED Display **************************************************  ** LED Display
    
    for (int i = 0; i < RING_LED_COUNT; i++){   // cycle through the ring LEDs
 
      // this will shift the colors 
      colorBase++;

      // calculate the color - somewhat hand-tuned
      pixelHue = ((colorBase + (i * 65536L / RING_LED_COUNT)) % 65536L);

      // set brightness based on the summed levels of two adjacent frequency bins
      // 50 is set as minimum so the LEDs are just barely on at low audio levels
      bright = 50 + 215 * my_FFT.read(i*2, i*2+1) * (i / 5);  

      // set the specfic LED to the calculated color and brightness
      ring.setPixelColor(RING_LED_COUNT - i - 1, ring.gamma32(ring.ColorHSV(pixelHue, saturation, bright)));

    }

    // all new LED values are set - time to display them!
    ring.show();

  }

}
IMG_6830.jpegIMG_6833.jpeg
 
Back
Top