Close

Complete Circuit Prototype

A project log for Audio Visualizer Hat

A hat to display audio frequencies.

andymacAndyMac 10/05/2015 at 03:480 Comments

Before putting together the final circuit I put (mostly) everything together on a protoboard. Halfway through the project I found a great resource in Imgur user [omenSP]'s http://imgur.com/a/jYhRk. Before I invested in the NeoPixel strip I tested the circuit with a pixel ring I had onhand.

Once I got the complete strip in I realized I had to cut and resolder for the hat. Every time I work with these pixels I burn out or otherwise damage a pixel. Because of the design I had to cut and resolder the strip. One final test before soldering the complete board:

The code I used is below. Credit for large portions of the code goes to [omenSP].

/*
  Test #3 adds neopixel ring for visual representation and responsiveness
  MSGEQ7 bands = 63Hz, 160Hz, 400Hz, 1,000Hz, 2,500Hz, 6,250Hz, 16,000Hz
  
  Most of this was inspired by
  http://pastebin.com/4hHQfq49#  &  http://imgur.com/a/jYhRk
  http://www.eetimes.com/author.asp?section_id=216&doc_id=1323030

  I'm sure there is a better way to split L&R channels (omenSP's code averages them for 1 EQ).  For right
  now I did it fairly manually by doubling up on nearly every variable

  At the moment I am sharing strobe and reset pins across both MSGEQ7 chips
*/

//------------------------------------LIBRARIES---------------------------------
#include <Adafruit_NeoPixel.h>            // NeoPixel Library
#include <Event.h>                        // Comes with Timer.h library?
#include <Timer.h>                        // Timer library 
#include <math.h>                         // Math library

//------------------------------------PIN DECLARATIONS---------------------------------
//int ctrlReset    = 2;                   // Digital pin 2 = signal to reset MSGEQ7s
//int ctrlStrobe   = 3;                   // Digital pin 3 = signal to strobe (read data from) MSGEQ7s
//int Led4  =  4;                         //LED to light up and test 1 band
const byte dataPinL            = 8;   // Data pin for Neopixels
const byte dataPinR            = 9;   // Data pin for Neopixels
//int channelLeft  =  A0;                 // Analog pin 0 = spectrum data from left channel
//int channelRight =  A1;                   // Analog pin 1 = spectrum data from right channel
const byte analogPinL         = A0;   // left channel analog data from shield
const byte analogPinR         = A1;   // right channel analog data from shield
const byte strobePin          = 4;   // data strobe for shield
const byte resetPin           = 5;   // reset strobe for shield

//------------------------------------VARIABLES/CONSTANTS DECLARATIONS---------------------------------
//int spectrumLeft[7];                    // Array to store 7 bands of spectrum data from left channel 
//int spectrumRight[7];                   // Array to store 7 bands of spectrum data from right channel
const byte numBand = 16;                // Number of LEDS per band.  **change for strip
const byte numTop = 0;                  // The number of LEDs to have top color
int peakArrayL[7];                       // Holds peak values for each of the 7 bands
int peakArrayR[7];                       // Holds peak values for each of the 7 bands
Timer t;                                // Timing variable
String colorPick = "GreenYellowRed";    //Select color palette for EQ.  See uint32_t Wheel
int spectrumReadR;  //R magnitude from shield
int spectrumReadL;  //L magnitude from shield
//int audio = MONO;   //set audio mode to mono, combine R&L channels **dunno what this does
int magL = 0;        //the magnitude of a freq band
int magR = 0;        //the magnitude of a freq band
int numONL = 0;      //the number of LEDs on in a freq band
int numONR = 0;      //the number of LEDs on in a freq band
float fl_magL = 0.0; //floating point mag after noise removal and scaling
float fl_magR = 0.0; //floating point mag after noise removal and scaling

const int noise[]             = {1, 1, 1, 1, 1, 1, 1}; // set this to magnitude of noise from shield
const float gain[]            = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; // - gain for each band
const unsigned long loop_dlay = 35;  // loop delay to slow down display update rate

byte                //**not the faintest idea what this does, and i feel like it will throw an error
  peak = 0,
  dotCount = 0;

Adafruit_NeoPixel stripL = Adafruit_NeoPixel(numBand, dataPinL, NEO_GRB + NEO_KHZ800); //**mult #pins for strip?
Adafruit_NeoPixel stripR = Adafruit_NeoPixel(numBand, dataPinR, NEO_GRB + NEO_KHZ800); //**mult #pins for strip?

void setup()
{
  Serial.begin(9600);
/*-------------FROM OLD PROGRAM--------------
  pinMode(ctrlReset,OUTPUT);             // Define reset as output
  pinMode(ctrlStrobe,OUTPUT);            // Define strobe as output
  pinMode(Led4,OUTPUT);
  digitalWrite(ctrlReset,LOW);           // Pull the reset signal low
  digitalWrite(ctrlStrobe,HIGH);         // Drive the strobe signal high
  digitalWrite(Led4,LOW);
*/
  pinMode(resetPin, OUTPUT);
  pinMode(strobePin, OUTPUT);
  pinMode(dataPinL, OUTPUT);
  pinMode(dataPinR, OUTPUT);

  // Start strip communication and start them at 1/4 brightness and blank
  stripL.begin();
  stripR.begin();
  stripL.setBrightness(64);               // Control strip brightness **see how well it works in a lit room
  stripR.setBrightness(64);               // Control strip brightness **see how well it works in a lit room  
  stripL.show();                          // Initialize all pixels to 'off'
  stripR.show();                          // Initialize all pixels to 'off'
  
  digitalWrite(resetPin,HIGH);
    delayMicroseconds(5);
  digitalWrite(strobePin,HIGH);
    delayMicroseconds(50);              // strobe PW > 18 usec min
  digitalWrite(strobePin,LOW);
    delayMicroseconds(50);              //reset PW > 100 usec min
  digitalWrite(resetPin,LOW);
    delayMicroseconds(5);              
  digitalWrite(strobePin,HIGH);
    delayMicroseconds(100);             // allow reset to strobe falling > 72 usec min
  
  t.every(100,peakLower);                 // calls peakLower function every 100 ms **(why?) (or 10ms?)
}


/*void loop() //---------VOID LOOP FROM OLD PROGRAM---------------
{
  readMSGEQ7();

//-----------debug lines from the old program. update this, b/c it could be helpful--------------
  // Display values from the left channel on the serial monitor
  for (int i = 0; i < 7; i++)
  {
    if (spectrumLeft[i] < 100) Serial.print(" ");
    if (spectrumLeft[i] <  10) Serial.print(" ");
    Serial.print(spectrumLeft[i]);
    Serial.print(" ");
  }
  Serial.print("  ");

  // Display values from the right channel on the serial monitor
  for (int i = 0; i < 7; i++)
  {
    if (spectrumRight[i] < 100) Serial.print(" ");
    if (spectrumRight[i] <  10) Serial.print(" ");
    Serial.print(spectrumRight[i]);
    Serial.print(" ");
  }

  Serial.println();

//-------LED DEBUG FROM OLD PROGRAM. PROBABLY DELETE THIS---------
  if (spectrumLeft[4] > 100)
    digitalWrite(Led4,HIGH);
  else
    digitalWrite(Led4,LOW);    
}
*/

/*-------------THE READ FUNCTION FROM EETIMES PROGRAM.  USING omenSP's FOR NOW---------------
void readMSGEQ7() {                                  // Read the seven spectrum bands from the MSGEQ7 chips
  digitalWrite(ctrlReset, HIGH);                     // Pulse the reset signal, which causes
  digitalWrite(ctrlReset, LOW);                      // the MSGEQ7s to latch the spectrum values
  delayMicroseconds(75);                             // Delay to meet minimum reset-to-strobe time

  for(int i=0; i <7; i++)                            // Cycle through the 7 spectrum bands
  {
    digitalWrite(ctrlStrobe,LOW);                    // Read current band (then increment to next band)
    delayMicroseconds(40);                           // Wait for outputs to settle

    spectrumLeft[i] = analogRead(channelLeft) / 4;   // Store current values from left & right channels 
//    spectrumRight[i] = analogRead(channelRight) / 4; // Divide 0-1023 by 4 to give 0-255
//Dividing by 4 is really for PWM output and I can probably eliminate that later

    digitalWrite(ctrlStrobe,HIGH);
    delayMicroseconds(40);                           // Delay to meet minimum strobe-to-strobe time
  }
}
*/

void loop() {
  for(byte band = 1; band <= 7; band++) {
    digitalWrite(strobePin, LOW); //set analyzer to low to read
    delayMicroseconds(40);
   
    spectrumReadR = analogRead(analogPinR); //read right audio
    spectrumReadL = analogRead(analogPinL); //read left audio
   
    digitalWrite(strobePin, HIGH); //set analyzer back to high

//---------NOT SURE WHY THIS SECTION IS IN BOTH LOOP() AND READBAND()---------   
//    mag = (spectrumReadR + spectrumReadL) / 2;
    magL = max(0, (magL - noise[band-1])); //creates magnitude of frequency
    magR = max(0, (magR - noise[band-1])); //creates magnitude of frequency
    fl_magL = gain[band-1] * float(magL); //adjusts magnitude for gain
    fl_magR = gain[band-1] * float(magR); //adjusts magnitude for gain    
    numONL = map(fl_magL, 0, 1024, 0, numBand+1); //maps magnitude to number of active pixels
    numONR = map(fl_magR, 0, 1024, 0, numBand+1); //maps magnitude to number of active pixels    
 
    anyBand(band);
   
    //Serial.print(band);
    //Serial.println(peakArray[band-1]);
    if(peakArrayL[band-1]==0) stripL.setPixelColor(peakArrayL[band-1] + numBand*(band-1), stripL.Color(0,0,0));
    else stripL.setPixelColor(peakArrayL[band-1] + numBand*(band-1), stripL.Color(255,0,0));
    if(peakArrayR[band-1]==0) stripR.setPixelColor(peakArrayR[band-1] + numBand*(band-1), stripR.Color(0,0,0));
    else stripR.setPixelColor(peakArrayR[band-1] + numBand*(band-1), stripR.Color(255,0,0));    
    t.update();
  }
//  strip.setBrightness(40);  //I already did this up top.  why do it again?
  stripL.show();
  stripR.show();
 
  delay(loop_dlay);
}

void readBand(byte band) {
  for(byte band = 1; band <= 7; band++) {
    digitalWrite(strobePin, LOW); //set analyzer to low to read
    delayMicroseconds(40);                  //minimum delay for MSGEQ7
   
    spectrumReadR = analogRead(analogPinR); //read right audio
    spectrumReadL = analogRead(analogPinL); //read left audio
   
    digitalWrite(strobePin, HIGH); //set analyzer back to high
   
    //mag = (spectrumReadR + spectrumReadL) / 2; //average L and R spectrums to make mono
    magL = max(0, (magL - noise[band-1])); //creates magnitude of frequency
    magR = max(0, (magR - noise[band-1])); //creates magnitude of frequency
    fl_magL = gain[band-1] * float(magL); //adjusts magnitude for gain
    fl_magR = gain[band-1] * float(magR); //adjusts magnitude for gain
    numONL = map(fl_magL, 0, 1024, 0, numBand+1); //maps magnitude to number of active pixels
    numONR = map(fl_magR, 0, 1024, 0, numBand+1); //maps magnitude to number of active pixels
 
    anyBand(band);
  }
}

void anyBand(byte band) {                            // For each LED on a single freq band, turn on or off
  for(byte i = 0; i < numBand; i++){                 // depending on if that freq was seen.  Also provides
    if(i < (numONL - numTop - 1)){                   // for a falling peak **that i may want to comment out
      stripL.setPixelColor(i + numBand*(band-1), Wheel(map(i,0,numBand-1,20,83))); //main wheel colors
    }
    else if(i >= numONL){
      stripL.setPixelColor(i + numBand*(band-1), stripL.Color(0,0,0)); //unused colors on wheel
    }
    else{
      if(i > peakArrayL[band-1]) peakArrayL[band-1] = i; //used for falling peak dot
    }
  }  
  for(byte i = 0; i < numBand; i++){                 
    if(i < (numONR - numTop - 1)){                    
      stripR.setPixelColor(i + numBand*(band-1), Wheel(map(i,0,numBand-1,20,83))); //main wheel colors
    }
    else if(i >= numONR){
      stripR.setPixelColor(i + numBand*(band-1), stripR.Color(0,0,0)); //unused colors on wheel
    }
    else{
      if(i > peakArrayR[band-1]) peakArrayR[band-1] = i; //used for falling peak dot
    }
  }
}

void peakLower() {                                   // **Not quite sure what this does yet
  for(byte i = 0; i < 7; i++) {
    if(peakArrayL[i] > 0) peakArrayL[i]--;
    if(peakArrayL[i] > 0) peakArrayL[i]--;           //**Not sure if I implemented these 2 channels right
    else continue;
  }
}

uint32_t Wheel(byte WheelPos) {                      // Allows to select color palette
  if(colorPick == "GreenYellowRed") {
    return stripL.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
    return stripR.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  }
  else if(colorPick == "PinkPurpleBlue") {
    return stripL.Color(255 - WheelPos * 3, 0, WheelPos * 3);
    return stripR.Color(255 - WheelPos * 3, 0, WheelPos * 3);    
  }
  else if(colorPick == "GreenTealBlue") {
    return stripL.Color(0, 255 - WheelPos * 3, WheelPos * 3);
    return stripR.Color(0, 255 - WheelPos * 3, WheelPos * 3);    
  }
}

Discussions