Talk:DreamTeam

From Noisebridge
Jump to: navigation, search

https://github.com/search?q=neurosky&type=&ref=simplesearch (found 48 repository results)

https://github.com/nbdt == NB dream team

// Audio Spectrum Display
// Copyright 2013 Tony DiCola (tony@tonydicola.com)

// This code is part of the guide at http://learn.adafruit.com/fft-fun-with-fourier-transforms/

#define ARM_MATH_CM4
#include <arm_math.h>
#include "FastLED.h"


// ebw code
#include <avr/pgmspace.h> // PROGMEM 
#include <Cycler.h>
#include <EightBitWaves.h>

//#define LED_COUNT 13
//#define LED_CLASS WS2812
//#define LED_COLOR_ORDER GRB
#define LED_MAX_BRIGHTNESS 64  // 1/8
//#define LED_DT 2  // SERIAL DATA PIN
//#define LED_CK 6  // SERIAL CLOCK PIN
//#define SERIAL_BAUDRATE 9600
#define SERIAL_TIMEOUT 5

//Ticker ticker;
//Cycler hue_cycler, brightness_cycler;
Cycler brightness_cycler;
//struct CRGB pixel, fastled_buffer[LED_COUNT];

uint8_t minWave = 0, maxWave = 255;
uint32_t ticks_per_second = 1000;
uint32_t prevMillis = millis();
// ebw code

////////////////////////////////////////////////////////////////////////////////
// CONIFIGURATION 
// These values can be changed to alter the behavior of the spectrum display.
////////////////////////////////////////////////////////////////////////////////

#define DEBUG           false
#define OUTPUT_LED_DATA false
#define FULL_SET        false

#define BAUD_RATE      38400

#define NUM_LEDS 12
#define DATA_PIN 2

#define ARRAY_SZ(x)  (sizeof(x) / sizeof((x)[0]))

uint SAMPLE_RATE_HZ = 9000;             // Sample rate of the audio in hertz.
float SPECTRUM_MIN_DB = 30.0;          // Audio intensity (in decibels) that maps to low LED brightness.
float SPECTRUM_MAX_DB = 60.0;          // Audio intensity (in decibels) that maps to high LED brightness.

const int FFT_SIZE = 256;              // Size of the FFT.  Realistically can only be at most 256 
                                       // without running out of memory for buffers and other state.
const int AUDIO_INPUT_PIN = 14;        // Input ADC pin for audio data.
const int ANALOG_READ_RESOLUTION = 10; // Bits of resolution for the ADC.
const int ANALOG_READ_AVERAGING = 16;  // Number of samples to average with each ADC reading.

const int ONBOARD_LED_PIN = 13;        // Output pin for power LED (pin 13 to use Teensy 3.0's onboard LED).

const int MAX_CHARS = 65;              // Max size of the input command buffer

uint8_t brightness = 128;

CRGB leds[NUM_LEDS];

////////////////////////////////////////////////////////////////////////////////
// INTERNAL STATE
// These shouldn't be modified unless you know what you're doing.
////////////////////////////////////////////////////////////////////////////////

IntervalTimer samplingTimer;
float samples[FFT_SIZE*2];
float magnitudes[FFT_SIZE];
int sampleCounter = 0;
char commandBuffer[MAX_CHARS];
float frequencyWindow[NUM_LEDS+1];

boolean ledState = false;

uint loopCounter;

////////////////////////////////////////////////////////////////////////////////
// setup
////////////////////////////////////////////////////////////////////////////////

void setup() {
  // Set up serial port.
  Serial.begin(BAUD_RATE);
  delay(1000);

  loopCounter = 0;
  
  // Set up ADC and audio input.
  pinMode(AUDIO_INPUT_PIN, INPUT);
  analogReadResolution(ANALOG_READ_RESOLUTION);
  analogReadAveraging(ANALOG_READ_AVERAGING);
  
  // Turn on the power indicator LED.
  pinMode(ONBOARD_LED_PIN, OUTPUT);
  digitalWrite(ONBOARD_LED_PIN, LOW);
  
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  
  // Clear the input command buffer
  memset(commandBuffer, 0, sizeof(commandBuffer));
  
  // Initialize spectrum display
  spectrumSetup();
//  Serial.println("** setup() spectrumSetup **********************");
//  delay(1000);
  
  brightness_cycler.setup((float) 6.0, ticks_per_second);

// Begin sampling audio
  samplingBegin();
}

////////////////////////////////////////////////////////////////////////////////
// loop
////////////////////////////////////////////////////////////////////////////////

void loop() {
  // Calculate FFT if a full sample is available.
  if (samplingIsDone()) {
    processFFT();
  }
  updateBrightness();
}

////////////////////////////////////////////////////////////////////////////////
// UTILITY FUNCTIONS
////////////////////////////////////////////////////////////////////////////////
void updateBrightness() {
  uint16_t delta_ticks = (uint16_t)(millis() - prevMillis);
  prevMillis += delta_ticks;
  brightness_cycler.update(delta_ticks);
//  unsigned char brightness = EightBitWaves::sine(brightness_cycler.phase(), minWave, maxWave);
  brightness = EightBitWaves::sine(brightness_cycler.phase(), minWave, maxWave);
}

void processFFT() {
    
  // Run FFT on sample data.
  arm_cfft_radix4_instance_f32 fft_inst;
//    These functions have been depricated
  arm_cfft_radix4_init_f32(&fft_inst, FFT_SIZE, 0, 1);
  arm_cfft_radix4_f32(&fft_inst, samples);

//    arm_cfft_f32(&fft_inst, samples, 0, 1);

  // Calculate magnitude of complex numbers output by the FFT.
  arm_cmplx_mag_f32(samples, magnitudes, FFT_SIZE);
  
  updateLEDs();
  
  // Restart audio sampling.
  samplingBegin();
}


void outputFFTData() { 

  if (DEBUG && FULL_SET) {
    Serial.println("** FFT Data ****************************");
    Serial.print("** Total size of magnitude array: ");
    Serial.println(sizeof(magnitudes));

    Serial.print("** Number of elements in magnitude: ");
    Serial.println(sizeof(magnitudes)/sizeof(*magnitudes));

//  Serial.print("** Number of elements in magnitude: ");
//  Serial.println(sizeOfFloatArray(magnitudes));
  }

//  for (int i = 0; i < sizeof(magnitudes)/sizeof(*magnitudes); ++i) {    // was FFT_SIZE
  for (size_t i = 0; i < ARRAY_SZ(magnitudes); ++i) {
    float intensity = magnitudes[i];
    intensity = 20.0*log10(intensity);

    // Scale the intensity and clamp between 0 and 1.0.
    intensity -= SPECTRUM_MIN_DB;
    intensity = intensity < 0.0 ? 0.0 : intensity;
    intensity /= (SPECTRUM_MAX_DB-SPECTRUM_MIN_DB);
    intensity = intensity > 1.0 ? 1.0 : intensity;

    if (FULL_SET) {
      if (DEBUG) {
        Serial.print("FFT[");
        Serial.print(i);
        Serial.print("] = ");
        Serial.println((byte)(254 * intensity));
      } else {
        Serial.write((byte)(254 * intensity));
      }
    }
  }

  if (FULL_SET) {
    if (DEBUG) {
      Serial.println("** End FFT Results **********************");
    } else {
      Serial.write(255);
    }
  }
}

/*
    if (DEBUG) {
      Serial.print("FFT[");
      Serial.print(i);
      Serial.print("] = ");
      Serial.println(magnitudes[i]);
    } else {
//      Serial.write();       // send out the data
      Serial.write(255);                     // Send stop Byte
    }
  }
*/

//**************************************************************************
// updateGrnLED
//**************************************************************************
//
void updateGrnLED() {
  // The measured time between two consecutive events (rock solid on the scope):
  // FHT_N     mSec  Baud Rate    
  //
//  Serial.print("updateOnboardLED");

  digitalWrite(ONBOARD_LED_PIN, HIGH && ledState);      // turn the LED on or off (HIGH is the voltage level)
  ledState = !ledState;
}

//**************************************************************************
// frequencyToBin
// Function - Convert a frequency to the appropriate FFT bin it will fall within.
//**************************************************************************
//
int frequencyToBin(float frequency) {
  float binFrequency = float(SAMPLE_RATE_HZ) / float(FFT_SIZE);
  return int(frequency / binFrequency);
}

//**************************************************************************
// updateLEDs
// Function - Processes the FFT data and outputs to LEDs. Update each LED based 
//   on the intensity of the audio in the associated frequency window.
//**************************************************************************
//
void updateLEDs() {
  float intensity, otherMean;

  if (OUTPUT_LED_DATA && DEBUG) 
    Serial.println("** Start LED FFT Results **********************");

//  Serial.print("ARRAY_SZ(leds) = ");
//  Serial.print(ARRAY_SZ(leds));
//  Serial.print(", sizeof magnitudes = ");
//  Serial.println(ARRAY_SZ(magnitudes));

  for (size_t i = 0; i < ARRAY_SZ(leds); ++i) {
//    windowMean(magnitudes, 
//               frequencyToBin(frequencyWindow[i]),
    windowMean(frequencyToBin(frequencyWindow[i]),
               frequencyToBin(frequencyWindow[i+1]),
               &intensity,
               &otherMean);

//    Serial.print("**1 intensity[");
//    Serial.print(i);
//    Serial.print("] = ");
//    Serial.println(intensity);

    // Convert intensity to decibels.
    intensity = 20.0*log10(intensity);

    // Scale the intensity and clamp between 0 and 1.0.
    intensity -= SPECTRUM_MIN_DB;
    intensity = intensity < 0.0 ? 0.0 : intensity;
    intensity /= (SPECTRUM_MAX_DB-SPECTRUM_MIN_DB);
    intensity = intensity > 1.0 ? 1.0 : intensity;

//    Serial.print("**2 intensity[");
//    Serial.print(i);
//    Serial.print("] = ");
//    Serial.println(intensity);

    // Output intensity value to LED
    float newHue = 255*intensity;
    if (newHue < 64) {
      newHue = 0;
    } else {
      newHue = map(newHue, 64, 255, 0, 255);
    }
    
    leds[i] = CHSV(newHue, 255, brightness);
    
    if (OUTPUT_LED_DATA) {
      if (DEBUG) {
        Serial.print("FFT[");
        Serial.print(i);
        Serial.print("] = ");
        Serial.println(255.0 * intensity);
      } else {
//        Serial.write((byte)(254 * intensity));
        Serial.write((byte)(newHue));
      }
    }
  }

  if (OUTPUT_LED_DATA) {
    if (DEBUG) {
      Serial.println("** End FFT Results **********************");
    } else {
      Serial.write(255);
    }
  }

//  pixels.show();
  FastLED.show();
}

/*
//**************************************************************************
// setHSVColor
// Function - Converts HSV values to RGB and assigns the result to the specified LED
//**************************************************************************
//
void setHSVColor(int ledIndex, float hue, float saturation, float brightness) {
    uint32_t myColor = pixelHSVtoRGBColor(hue, saturation, brightness);
    pixels.setPixelColor(ledIndex, myColor);

//    Serial.print("LED num = ");
//    Serial.print(ledIndex);
//    Serial.print(", color = ");
//    Serial.println(myColor);
}

//**************************************************************************
// setHSVColor
// Function - Convert from HSV values to RGB colors usable by neo pixel functions.
//   hue:        0.0 - 360.0
//   saturation: 0.0 - 1.0
//   value:      0.0 - 1.0
//**************************************************************************
//
uint32_t pixelHSVtoRGBColor(float hue, float saturation, float value) {
  // Implemented from algorithm at http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
  float chroma = value * saturation;
  float h1 = float(hue)/60.0;
  float x = chroma*(1.0-fabs(fmod(h1, 2.0)-1.0));
  float r = 0;
  float g = 0;
  float b = 0;
  if (h1 < 1.0) {
    r = chroma;
    g = x;
  }
  else if (h1 < 2.0) {
    r = x;
    g = chroma;
  }
  else if (h1 < 3.0) {
    g = chroma;
    b = x;
  }
  else if (h1 < 4.0) {
    g = x;
    b = chroma;
  }
  else if (h1 < 5.0) {
    r = x;
    b = chroma;
  }
  else // h1 <= 6.0
  {
    r = chroma;
    b = x;
  }
  float m = value - chroma;
  r += m;
  g += m;
  b += m;
  return pixels.Color(int(255*r), int(255*g), int(255*b));
}

*/
 
////////////////////////////////////////////////////////////////////////////////
// SPECTRUM DISPLAY FUNCTIONS
///////////////////////////////////////////////////////////////////////////////

void spectrumSetup() {
  // Set the frequency window values by evenly dividing the possible frequency
  // spectrum across the number of neo pixels.

//  Serial.println("** spectrumSetup **********************");

  float windowSize = (SAMPLE_RATE_HZ / 2.0) / float(NUM_LEDS);
  for (size_t i = 0; i < ARRAY_SZ(leds) + 1; ++i) {
    frequencyWindow[i] = i*windowSize;
//    Serial.print("frequencyWindow[");
//    Serial.print(i);
//    Serial.print("] = ");
//    Serial.println(frequencyWindow[i]);
  }
}

//**************************************************************************
// windowMean
// Function - Compute the average magnitude of a target frequency window vs. 
//            all other frequencies.
// Parameters    magnitudes, 
//               frequencyToBin(frequencyWindow[i]),
//               frequencyToBin(frequencyWindow[i+1]),
//               &intensity,
//               &otherMean
//**************************************************************************
//
//void windowMean(float* magnitudes, uint lowBin, uint highBin, float* windowMean, float* otherMean) {
void windowMean(uint lowBin, uint highBin, float* windowMean, float* otherMean) {
    *windowMean = 0;
    *otherMean = 0;
    // Notice the first magnitude bin is skipped because it represents the
    // average power of the signal.
//    Serial.print("sizeof magnitudes: ");
//    Serial.print( sizeof(magnitudes) );
//    Serial.print(", ARRAY_SZ(magnitudes): ");
//    Serial.println( ARRAY_SZ(magnitudes) );
    for (size_t i = 1; i < (ARRAY_SZ(magnitudes))/2; ++i) {

//      Serial.print("i = ");
//      Serial.print(i);
//
//      Serial.print(", lowBin = ");
//      Serial.print(lowBin);
//
//      Serial.print(", highBin = ");
//      Serial.print(highBin);

      if (i >= lowBin && i <= highBin) {
        *windowMean += magnitudes[i];
//        Serial.print(", magnitude: ");
//        Serial.print(magnitudes[i]);
      }
      else {
        *otherMean += magnitudes[i];
      }
//      Serial.println();
    }
    *windowMean /= (highBin - lowBin) + 1;

//    Serial.print(" **** windowMean: ");
//    Serial.println(*windowMean);

    *otherMean /= (FFT_SIZE / 2 - (highBin - lowBin));
}

////////////////////////////////////////////////////////////////////////////////
// SAMPLING FUNCTIONS
////////////////////////////////////////////////////////////////////////////////

//**************************************************************************
// samplingCallback
// Function - Does an analog to digital conversion of the microphone input.
//**************************************************************************
//
void samplingCallback() {

  // Read from the microphone input pin and store the sample data
  samples[sampleCounter] = (float32_t)analogRead(AUDIO_INPUT_PIN);

  // Complex FFT functions require a coefficient for the imaginary part of the input.
  // Since we only have real data, set this coefficient to zero.
  samples[sampleCounter+1] = 0.0;

  // Update sample buffer position and stop after the buffer is filled
  sampleCounter += 2;
  if (sampleCounter >= FFT_SIZE*2) {
    samplingTimer.end();
  }
}

//**************************************************************************
// samplingBegin
// Function - Starts the microphone ADC sampling timer function.
//**************************************************************************
//
void samplingBegin() {
  // Reset sample buffer position and start callback at necessary rate.
  sampleCounter = 0;
  samplingTimer.begin(samplingCallback, 1000000/SAMPLE_RATE_HZ); // 1,000,000 / 9000 = 111 uSec
}

//**************************************************************************
// samplingIsDone
// Function - Indicates if a complete sample set of microphone data has been captured.
//**************************************************************************
//
boolean samplingIsDone() {
  return sampleCounter >= FFT_SIZE*2;
}


////////////////////////////////////////////////////////////////////////////////
// COMMAND PARSING FUNCTIONS
// These functions allow parsing simple commands input on the serial port.
// Commands allow reading and writing variables that control the device.
//
// All commands must end with a semicolon character.
// 
// Example commands are:
// GET SAMPLE_RATE_HZ;
// - Get the sample rate of the device.
// SET SAMPLE_RATE_HZ 400;
// - Set the sample rate of the device to 400 hertz.
// 
////////////////////////////////////////////////////////////////////////////////

void parserLoop() {
  // Process any incoming characters from the serial port
  while (Serial.available() > 0) {
    char c = Serial.read();
    // Add any characters that aren't the end of a command (semicolon) to the input buffer.
    if (c != ';') {
      c = toupper(c);
      strncat(commandBuffer, &c, 1);
    }
    else
    {
      // Parse the command because an end of command token was encountered.
      parseCommand(commandBuffer);
      // Clear the input buffer
      memset(commandBuffer, 0, sizeof(commandBuffer));
    }
  }
}

// Macro used in parseCommand function to simplify parsing get and set commands for a variable
#define GET_AND_SET(variableName) \
  else if (strcmp(command, "GET " #variableName) == 0) { \
    Serial.println(variableName); \
  } \
  else if (strstr(command, "SET " #variableName " ") != NULL) { \
    variableName = (typeof(variableName)) atof(command+(sizeof("SET " #variableName " ")-1)); \
  }

//**************************************************************************
// parseCommand
// Function - Parses commands received via the serial input.
//**************************************************************************
//
void parseCommand(char* command) {
  if (strcmp(command, "GET MAGNITUDES") == 0) {
    for (size_t i = 0; i < ARRAY_SZ(magnitudes); ++i) {
      Serial.println(magnitudes[i]);
    }
  }
  else if (strcmp(command, "GET SAMPLES") == 0) {
    for (size_t i = 0; i < ARRAY_SZ(samples); i+=2) {
      Serial.println(samples[i]);
    }
  }
  else if (strcmp(command, "GET FFT_SIZE") == 0) {
    Serial.println(FFT_SIZE);
  }
  GET_AND_SET(SAMPLE_RATE_HZ)
//  GET_AND_SET(LEDS_ENABLED)
  GET_AND_SET(SPECTRUM_MIN_DB)
  GET_AND_SET(SPECTRUM_MAX_DB)
  
  // Update spectrum display values if sample rate was changed.
  if (strstr(command, "SET SAMPLE_RATE_HZ ") != NULL) {
    spectrumSetup();
  }
}
Personal tools