Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Evan Rust
Published © GPL3+

Teensy 4 Musical Lightshow Using FFT

Use a Teensy 4 and Audio board to read audio files and display them along a string of LEDs.

IntermediateFull instructions provided2 hours4,764

Things used in this project

Hardware components

Teensy 4.0 Development Board
Teensy 4.0 Development Board
×1
Teensy Audio Board
Teensy Audio Board
Rev D
×1
WS2812b LED Strip 144/m
×1
PC or Laptop
×1

Software apps and online services

VS Code
Microsoft VS Code
Arduino IDE
Arduino IDE
Teensy Audio Configuration Tool

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Audio Shield Pins

Code

audioDisplay.ino

C/C++
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <WS2812Serial.h>
#include <Entropy.h>

#define NUM_BINS 16
#define NUM_LED_PER_BIN 15
#define UPDATE_DELAY 0.016

#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  11
#define SDCARD_SCK_PIN   13

const int numLed = NUM_BINS * NUM_LED_PER_BIN, pin = 1;
const float scale = 60.0;

byte drawingMemory[numLed * 3];
DMAMEM byte displayMemory[numLed * 12];
uint16_t binCombinations[NUM_BINS][2] = {{0, 0}, {1, 1}, {2, 3}, {4, 6}, {7, 10}, 
    {11, 15}, {16, 22}, {23, 32}, {33, 46}, {47, 66}, {67, 93}, {94, 131}, {132, 184},
    {185, 257}, {258, 359}, {360, 511}};

WS2812Serial leds(numLed, displayMemory, drawingMemory, pin, WS2812_GRB);

float level[NUM_BINS];
int shown[NUM_BINS];
uint32_t binColors[NUM_BINS];

// GUItool: begin automatically generated code
AudioPlaySdWav           playSdWav1;     //xy=172,369
AudioMixer4              mixer1;         //xy=353,382
AudioOutputUSB           usb1;           //xy=358,317
AudioOutputI2S           i2s1;           //xy=367,277
AudioAnalyzePeak         peak1;          //xy=546,377
AudioAnalyzeFFT1024      fft1024_1;      //xy=556,333
AudioConnection          patchCord1(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord2(playSdWav1, 0, usb1, 0);
AudioConnection          patchCord3(playSdWav1, 0, i2s1, 0);
AudioConnection          patchCord4(playSdWav1, 1, mixer1, 1);
AudioConnection          patchCord5(playSdWav1, 1, usb1, 1);
AudioConnection          patchCord6(playSdWav1, 1, i2s1, 1);
AudioConnection          patchCord7(mixer1, fft1024_1);
AudioConnection          patchCord8(mixer1, peak1);
AudioControlSGTL5000     audioShield;     //xy=258,462
// GUItool: end automatically generated code

void setup()
{
    leds.begin();
    leds.setBrightness(0);
    AudioMemory(20);

    SPI.setMOSI(SDCARD_MOSI_PIN);
    SPI.setSCK(SDCARD_SCK_PIN);
    if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here, but print a message repetitively
        while (1) {
        delay(500);
        }
    }

    audioShield.enable();
    audioShield.volume(0.2);
    mixer1.gain(0, 0.5);
    mixer1.gain(1, 0.5);

    Entropy.Initialize();
    generateColors();
}

void loop()
{
    playFile("TEST1.WAV");
    delay(500);
    playFile("TEST2.WAV");
    delay(500);
    playFile("TEST3.WAV");
    delay(500);
    playFile("TEST4.WAV");
    delay(500);
    playFile("TEST5.WAV");
    delay(500);
    playFile("TEST6.WAV");
    delay(500);
}

void analyzeAudio()
{
    if(peak1.available())
    {
        leds.setBrightness(peak1.read() * 100);
        leds.show();
    }
    if(fft1024_1.available())
    {
        for(int i = 0; i < NUM_BINS; i++)
        {
            int bin1 = binCombinations[i][0];
            int bin2 = binCombinations[i][1];

            if(bin1 - bin2 == 0)
                level[i] = fft1024_1.read(bin1);
            else
                level[i] = fft1024_1.read(bin1, bin2);

            int val = level[i] * scale;
            val = constrain(val, 0, 8);

            if(val >= shown[i])
            {
                shown[i] = val;
            } else {
                if(shown[i] > 0)
                    shown[i] = shown[i] - 1;
                val = shown[i];
            }

            int ledMidpoint = (i * NUM_LED_PER_BIN) + (NUM_LED_PER_BIN / 2);
            for(int j = 0; j < NUM_LED_PER_BIN / 2; j++)
            {
                if(j <= shown[i] - 1)
                {
                    leds.setPixelColor(ledMidpoint + j, binColors[i]);
                    leds.setPixelColor(ledMidpoint - j, binColors[i]);
                } else {
                    leds.setPixelColor(ledMidpoint + j, 0);
                    leds.setPixelColor(ledMidpoint - j, 0);
                }
            }
        }
        leds.show();
    }
}

void playFile(const char* filename)
{
    playSdWav1.play(filename);
    delay(5);
    while(playSdWav1.isPlaying())
    {
        analyzeAudio();
    }
}

void generateColors()
{
    for(int i = 0; i < NUM_BINS; i++)
    {
        int randomR = Entropy.random(0, 256);
        int randomG = Entropy.random(0, 256);
        int randomB = Entropy.random(0, 256);

        binColors[i] = leds.Color(randomR, randomG, randomB);
    }
}

Credits

Evan Rust
123 projects • 1111 followers
IoT, web, and embedded systems enthusiast. Contact me for product reviews or custom project requests.
Contact

Comments

Please log in or sign up to comment.