for this week I did not have a ton to do. I did all the assembly last week, so this week all I had to do was program the teensy, and do the audio analysis.
using the teensy audio library made things pretty easy, I am still doing some minor adjustments, but for the most part the project is completed there is still some averaging and little tweaks to make but I am very pleased with the project
these are two videos of the head in operation 🙂
here is my current Arduino code:
#include <Adafruit_NeoPixel.h> #include <Audio.h> #include <Wire.h> #include <SerialFlash.h> #ifdef __AVR__ #include <avr/power.h> #endif void setLedColorHSV(byte h, byte s, byte v); // Create the Audio components. These should be created in the // order data flows, inputs/sources -> processing -> outputs // AudioInputAnalog adc1(A0); // ADC0 input AudioAnalyzeFFT1024 myFFT; // Connect either the live input or synthesized sine wave AudioConnection patchCord1(adc1, 0, myFFT, 0); // Which pin on the Arduino is connected to the NeoPixels? // On a Trinket or Gemma we suggest changing this to 1 #define PIN 5 const int POWER_LED_PIN = 13; // Output pin for power LED (pin 13 to use Teensy 3.0's onboard LED). byte h; byte s; byte v; byte RedLight; byte GreenLight; byte BlueLight; int currentlight; float avg_fft[512]; int avg_fft_cout = 1; #define NUMPIXELS 41 #define NUMCELLS 25 int cells[NUMCELLS] = {3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 3, 4, 3, 2}; // ----------- ALL THE DIFFERENT MAPPINGS THAT I HAVE MADE!!! --------------------------------------- // even maping base at the neck int mapping[NUMCELLS] = {0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0}; // random mapping //int mapping[NUMCELLS] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0}; // random mapping base at the left ear //int mapping[NUMCELLS] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 5, 5, 5}; // random mapping base in the neck //int mapping[NUMCELLS] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 0, 5, 5, 5, 5, 1, 2, 3}; // -------------------------------------------------- #define freq_bands 6 // defines the frequency ranges for each band int freq_high[freq_bands] = {90, 40, 30, 20, 12, 6}; int freq_low[freq_bands] = {40, 31, 21, 13, 6, 1}; // stores the results of going through each band int freq_max_bin[freq_bands] = {}; float freq_max_amp[freq_bands] = {}; float prev_freq_max_amp[freq_bands] = {}; byte freq_hue[freq_bands] = {}; byte prev_freq_hue[freq_bands] = {}; int top_freq = 0; // When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals. // Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest // example for more information on possible values. Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); void setup() { // Turn on the power indicator LED. pinMode(POWER_LED_PIN, OUTPUT); digitalWrite(POWER_LED_PIN, HIGH); randomSeed(10); pixels.begin(); // This initializes the NeoPixel library. // Audio connections require memory to work. For more // detailed information, see the MemoryAndCpuUsage example AudioMemory(12); // Configure the window algorithm to use myFFT.windowFunction(AudioWindowHanning1024); //myFFT.windowFunction(NULL); } void loop() { float n; int i; int fft_count = 0; delay(10); // ________________________________________________________ // copy initial sample if (myFFT.available()) { for (i = 0; i < 512; i++) { avg_fft[i] = myFFT.read(i); } // averge other samples while (fft_count < avg_fft_cout) { if (myFFT.available()) { for (i = 0; i < 512; i++) { avg_fft[i] = (avg_fft[i] + myFFT.read(i))/2.0; } fft_count++; } } } // ________________________________________________________ int f; // used as intex for band we are in int bin = 0; // hold on to the current bin for (f = 0; f < freq_bands; f++) { freq_max_amp[f] = 0; bin = 0; for (i=freq_high[f]; i > freq_low[f]; i--) { n = avg_fft[i]; if ( n > 0.01) { freq_max_amp[f] = max(freq_max_amp[f], n); // recently added might make things worse? we will see... //if (freq_max_amp[f] == n) { bin = i; //} } } if (bin != 0 && bin != freq_max_bin[f]){ freq_max_bin[f] = bin; // TODO: the bins are off!! bin 5 should be RED!! currently bin 0 is red freq_hue[f] = 252 - ((f+1%6)*42 + random((freq_max_bin[f]-freq_low[f])*(42/(freq_high[f]-freq_low[f])))); } if (freq_max_amp[f] == 0){ freq_max_bin[f] = 0; } // Serial.println(); // Serial.print((255/f)); // Serial.println(); // freq_hue[f] = (255/f); // set the hue to the bin hue if (freq_max_bin[f] != 0){ Serial.println(); Serial.print("BAND "); Serial.print(f); Serial.print(" amplitude is "); Serial.print(freq_max_amp[f], 20); Serial.print("the bin is "); Serial.print(freq_max_bin[f]); } } // PUSH ALL THE DATA TO THE LIGHTS!!! // ________________________________________________________ currentlight = 0; for(int i=0;i<NUMCELLS;i++) { h = freq_hue[mapping[i]]; if (h != 0 && prev_freq_hue[mapping[i]] != 0) { h = (h - prev_freq_hue[mapping[i]])/3 + prev_freq_hue[mapping[i]]; } prev_freq_hue[mapping[i]] = h; s = 255; if (freq_max_amp[mapping[i]] != 0.0){ // v = (int)(freq_max_amp[mapping[i]]*1000.0); v = (int)(freq_max_amp[mapping[i]]*1000.0); v = (int) abs(v - prev_freq_max_amp[mapping[i]])/3 + prev_freq_max_amp[mapping[i]]; top_freq = max(top_freq, v); // Serial.println(); // Serial.print(top_freq); // Serial.println(); prev_freq_max_amp[mapping[i]] = v/1.1-1; } else { //v = ((int)(prev_freq_max_amp[mapping[i]]*1000.0))/2-1; v = prev_freq_max_amp[mapping[i]]; prev_freq_max_amp[mapping[i]] = (int) prev_freq_max_amp[mapping[i]]/1.2; if (v != 0) { Serial.println(); Serial.print(prev_freq_max_amp[mapping[i]]); Serial.println(); } } setLedColorHSV(h,s,v); for (int j=0;j<cells[i];j++) { // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255 pixels.setPixelColor(currentlight, pixels.Color(RedLight, GreenLight, BlueLight)); currentlight = currentlight + 1; } } pixels.show(); // This sends the updated pixel color to the hardware. // ________________________________________________________ } void setLedColorHSV(byte h, byte s, byte v) { // this is the algorithm to convert from RGB to HSV h = (h * 192) / 256; // 0..191 unsigned int i = h / 32; // We want a value of 0 thru 5 unsigned int f = (h % 32) * 8; // 'fractional' part of 'i' 0..248 in jumps unsigned int sInv = 255 - s; // 0 -> 0xff, 0xff -> 0 unsigned int fInv = 255 - f; // 0 -> 0xff, 0xff -> 0 byte pv = v * sInv / 256; // pv will be in range 0 - 255 byte qv = v * (256 - s * f / 256) / 256; byte tv = v * (256 - s * fInv / 256) / 256; switch (i) { case 0: RedLight = v; GreenLight = tv; BlueLight = pv; break; case 1: RedLight = qv; GreenLight = v; BlueLight = pv; break; case 2: RedLight = pv; GreenLight = v; BlueLight = tv; break; case 3: RedLight = pv; GreenLight = qv; BlueLight = v; break; case 4: RedLight = tv; GreenLight = pv; BlueLight = v; break; case 5: RedLight = v; GreenLight = pv; BlueLight = qv; break; } }