| #include <LiquidCrystal.h> | |||||
| #include <Audio.h> | #include <Audio.h> | ||||
| #include <Wire.h> | #include <Wire.h> | ||||
| #include <SPI.h> | #include <SPI.h> | ||||
| #include <SD.h> | #include <SD.h> | ||||
| #include <LiquidCrystal.h> | |||||
| //const int myInput = AUDIO_INPUT_LINEIN; | |||||
| const int myInput = AUDIO_INPUT_MIC; | |||||
| // GUItool: begin automatically generated code | |||||
| AudioInputI2S i2s1; //xy=139,91 | |||||
| AudioMixer4 mixer1; //xy=312,134 | |||||
| AudioOutputI2S i2s2; //xy=392,32 | |||||
| AudioAnalyzeFFT1024 fft1024; //xy=467,147 | |||||
| AudioConnection patchCord1(i2s1, 0, mixer1, 0); | |||||
| AudioConnection patchCord2(i2s1, 0, i2s2, 0); | |||||
| AudioConnection patchCord3(i2s1, 1, mixer1, 1); | |||||
| AudioConnection patchCord4(i2s1, 1, i2s2, 1); | |||||
| AudioConnection patchCord5(mixer1, fft1024); | |||||
| AudioControlSGTL5000 audioShield; //xy=366,225 | |||||
| // GUItool: end automatically generated code | |||||
| // Create the Audio components. These should be created in the | |||||
| // order data flows, inputs/sources -> processing -> outputs | |||||
| // | |||||
| AudioInputI2S audioInput; // audio shield: mic or line-in | |||||
| AudioAnalyzeFFT256 myFFT(11); | |||||
| AudioOutputI2S audioOutput; // audio shield: headphones & line-out | |||||
| // Create Audio connections between the components | |||||
| // | |||||
| AudioConnection c1(audioInput, 0, audioOutput, 0); | |||||
| AudioConnection c2(audioInput, 0, myFFT, 0); | |||||
| AudioConnection c3(audioInput, 1, audioOutput, 1); | |||||
| const int myInput = AUDIO_INPUT_LINEIN; | |||||
| //const int myInput = AUDIO_INPUT_MIC; | |||||
| // The scale sets how much sound is needed in each frequency range to | |||||
| // show all 8 bars. Higher numbers are more sensitive. | |||||
| float scale = 60.0; | |||||
| // An array to hold the 16 frequency bands | |||||
| float level[16]; | |||||
| // This array holds the on-screen levels. When the signal drops quickly, | |||||
| // these are used to lower the on-screen level 1 bar per update, which | |||||
| // looks more pleasing to corresponds to human sound perception. | |||||
| int shown[16]; | |||||
| // Create an object to control the audio shield. | |||||
| // | |||||
| AudioControlSGTL5000 audioShield; | |||||
| // Use the LiquidCrystal library to display the spectrum | // Use the LiquidCrystal library to display the spectrum | ||||
| // | // | ||||
| LiquidCrystal lcd(0, 1, 2, 3, 4, 5); | LiquidCrystal lcd(0, 1, 2, 3, 4, 5); | ||||
| byte bar1[8] = {0,0,0,0,0,0,0,255}; | byte bar1[8] = {0,0,0,0,0,0,0,255}; | ||||
| byte bar2[8] = {0,0,0,0,0,0,255,255}; | |||||
| byte bar3[8] = {0,0,0,0,0,255,255,255}; | |||||
| byte bar4[8] = {0,0,0,0,255,255,255,255}; | |||||
| byte bar2[8] = {0,0,0,0,0,0,255,255}; // 8 bar graph | |||||
| byte bar3[8] = {0,0,0,0,0,255,255,255}; // custom | |||||
| byte bar4[8] = {0,0,0,0,255,255,255,255}; // characters | |||||
| byte bar5[8] = {0,0,0,255,255,255,255,255}; | byte bar5[8] = {0,0,0,255,255,255,255,255}; | ||||
| byte bar6[8] = {0,0,255,255,255,255,255,255}; | byte bar6[8] = {0,0,255,255,255,255,255,255}; | ||||
| byte bar7[8] = {0,255,255,255,255,255,255,255}; | byte bar7[8] = {0,255,255,255,255,255,255,255}; | ||||
| byte bar8[8] = {255,255,255,255,255,255,255,255}; | byte bar8[8] = {255,255,255,255,255,255,255,255}; | ||||
| void setup() { | void setup() { | ||||
| // Audio connections require memory to work. For more | |||||
| // detailed information, see the MemoryAndCpuUsage example | |||||
| // Audio requires memory to work. | |||||
| AudioMemory(12); | AudioMemory(12); | ||||
| // Enable the audio shield and set the output volume. | // Enable the audio shield and set the output volume. | ||||
| audioShield.enable(); | audioShield.enable(); | ||||
| audioShield.inputSelect(myInput); | audioShield.inputSelect(myInput); | ||||
| audioShield.volume(0.6); | |||||
| audioShield.volume(0.5); | |||||
| // turn on the LCD and define the custom characters | |||||
| lcd.begin(16, 2); | lcd.begin(16, 2); | ||||
| lcd.print("Audio Spectrum"); | lcd.print("Audio Spectrum"); | ||||
| lcd.createChar(0, bar1); | lcd.createChar(0, bar1); | ||||
| lcd.createChar(6, bar7); | lcd.createChar(6, bar7); | ||||
| lcd.createChar(7, bar8); | lcd.createChar(7, bar8); | ||||
| // configure the mixer to equally add left & right | |||||
| mixer1.gain(0, 0.5); | |||||
| mixer1.gain(1, 0.5); | |||||
| // pin 21 will select rapid vs animated display | // pin 21 will select rapid vs animated display | ||||
| pinMode(21, INPUT_PULLUP); | pinMode(21, INPUT_PULLUP); | ||||
| } | } | ||||
| int count=0; | |||||
| const int nsum[16] = {1, 1, 2, 2, 3, 4, 5, 6, 6, 8, 12, 14, 16, 20, 28, 24}; | |||||
| int maximum[16]; | |||||
| void loop() { | void loop() { | ||||
| if (myFFT.available()) { | |||||
| // convert the 128 FFT frequency bins | |||||
| // to only 16 sums, for a 16 character LCD | |||||
| int sum[16]; | |||||
| int i; | |||||
| for (i=0; i<16; i++) { | |||||
| sum[i] = 0; | |||||
| } | |||||
| int n=0; | |||||
| int count=0; | |||||
| for (i=0; i<128; i++) { | |||||
| sum[n] = sum[n] + myFFT.output[i]; | |||||
| count = count + 1; | |||||
| if (count >= nsum[n]) { | |||||
| Serial.print(count); | |||||
| Serial.print(" "); | |||||
| n = n + 1; | |||||
| if (n >= 16) break; | |||||
| count = 0; | |||||
| } | |||||
| } | |||||
| // The range is set by the audio shield's | |||||
| // knob, which connects to analog pin A1. | |||||
| int scale; | |||||
| scale = 2 + (1023 - analogRead(A1)) / 7; | |||||
| Serial.print(" - "); | |||||
| Serial.print(scale); | |||||
| Serial.print(" "); | |||||
| if (fft1024.available()) { | |||||
| // read the 512 FFT frequencies into 16 levels | |||||
| // music is heard in octaves, but the FFT data | |||||
| // is linear, so for the higher octaves, read | |||||
| // many FFT bins together. | |||||
| level[0] = fft1024.read(0); | |||||
| level[1] = fft1024.read(1); | |||||
| level[2] = fft1024.read(2, 3); | |||||
| level[3] = fft1024.read(4, 6); | |||||
| level[4] = fft1024.read(7, 10); | |||||
| level[5] = fft1024.read(11, 15); | |||||
| level[6] = fft1024.read(16, 22); | |||||
| level[7] = fft1024.read(23, 32); | |||||
| level[8] = fft1024.read(33, 46); | |||||
| level[9] = fft1024.read(47, 66); | |||||
| level[10] = fft1024.read(67, 93); | |||||
| level[11] = fft1024.read(94, 131); | |||||
| level[12] = fft1024.read(132, 184); | |||||
| level[13] = fft1024.read(185, 257); | |||||
| level[14] = fft1024.read(258, 359); | |||||
| level[15] = fft1024.read(360, 511); | |||||
| // if you have the volume pot soldered to your audio shield | |||||
| // uncomment this line to make it adjust the full scale signal | |||||
| //scale = 8.0 + analogRead(A1) / 5.0; | |||||
| // begin drawing at the first character on the 2nd row | |||||
| lcd.setCursor(0, 1); | lcd.setCursor(0, 1); | ||||
| for (int i=0; i<16; i++) { | for (int i=0; i<16; i++) { | ||||
| // Reduce the range to 0-8 | |||||
| int val = sum[i] / scale; | |||||
| Serial.print(level[i]); | |||||
| // TODO: conversion from FFT data to display bars should be | |||||
| // exponentially scaled. But how keep it a simple example? | |||||
| int val = level[i] * scale; | |||||
| if (val > 8) val = 8; | if (val > 8) val = 8; | ||||
| // Compute an animated maximum, where increases | |||||
| // show instantly, but if the number is less that | |||||
| // the last displayed value, decrease it by 1 for | |||||
| // a slow decay (looks pretty) | |||||
| if (val >= maximum[i]) { | |||||
| maximum[i] = val; | |||||
| if (val >= shown[i]) { | |||||
| shown[i] = val; | |||||
| } else { | } else { | ||||
| if (maximum[i] > 0) maximum[i] = maximum[i] - 1; | |||||
| if (shown[i] > 0) shown[i] = shown[i] - 1; | |||||
| val = shown[i]; | |||||
| } | } | ||||
| // a switch on pin 22 select whether we show the | |||||
| // slower animation or the direct/fast data | |||||
| if (digitalRead(21) == HIGH) { | |||||
| val = maximum[i]; | |||||
| } | |||||
| //Serial.print(shown[i]); | |||||
| Serial.print(" "); | |||||
| // print each custom digit | // print each custom digit | ||||
| if (val == 0) { | |||||
| if (shown[i] == 0) { | |||||
| lcd.write(' '); | lcd.write(' '); | ||||
| } else { | } else { | ||||
| lcd.write(val - 1); | |||||
| lcd.write(shown[i] - 1); | |||||
| } | } | ||||
| Serial.print(sum[i]); | |||||
| Serial.print("="); | |||||
| Serial.print(val); | |||||
| Serial.print(","); | |||||
| } | } | ||||
| Serial.println(); | |||||
| count = 0; | |||||
| Serial.print(" cpu:"); | |||||
| Serial.println(AudioProcessorUsageMax()); | |||||
| } | } | ||||
| } | } | ||||