Just a brief of the code before showing the gold. HAH! Rhymes. Didn’t really make sense since they’re referring to the same thing..anyway.
With the FFFT library I can use the microphone to pick up sound across the spectrum and store each frequency value in an array. From the tutorial, this array is size 64. I decided to reduce it to half that size by adding every pair of numbers in the array, which also allows for higher tolerance of sound input.
Next step was to figure out the prominent note which was a simple find max value loop with some smoothing thrown in there to, well, smooth things out.
For the buttons I have one to set a new password and one to test new input against the password. This was done by recording the loudest note for 30 frames and saving that to an array. The saved array from the set password would then be compared to the new input. There is an error tolerance to accommodate for offsets in timing or being off-key. If you are too off in timing or too off key, you’ll get a point, and after 5 points out of the 30, you got the password wrong. This makes the input pretty picky, considering how sketchy the microphone seems to be with ambiance and the like.
I could have done more with the buttons. I wanted to have a light turn on to indicate that a password is being set and stay on once it is set. A light for the new input as well, which would blink a couple times to celebrate your correctness. I wanted to incorporate protection around the premise of inputting a password before setting one, which currently means that you automatically got it right. There are a few other simple situations I could have delved in to to enrich the experience and make it more fluid, easy to understand, and functional. But hey, at least writing about it shows awareness.
Here is my very, very messy code. Stick THAT in your Arduino and run it.
#include <stdint.h>
#include <ffft.h>
#include <Servo.h>
//SOUND STUFF
volatile byte position = 0;
volatile long zero = 0;
int16_t capture[FFT_N]; /* Wave captureing buffer */
complex_t bfly_buff[FFT_N]; /* FFT buffer */
uint16_t spektrum[FFT_N/2]; /* Spectrum output buffer */
//AUDIO INPUT
#define IR_AUDIO 0 // ADC channel to cap
//SOUND AVG
const int fftNum = int(FFT_N / 2);
//SOUND SMOOTHE
const int smoothFrames = 5;
int sIndex = 0;
uint16_t readings[smoothFrames][fftNum/2];
uint16_t average[fftNum/2];
uint16_t total[fftNum/2];
//INPUT RECORDER
const int totalFrames = 30;
int thisFrame = 0;
int indexRec[totalFrames];
bool recorded = false;
//INPUT PASSWORD
int passFrame = 0;
int indexPass[totalFrames];
bool passworded = false;
int worked = 0;
//BUTTON STUFF
//int ledPin1 = 12; // choose the pin for the LED
//int ledPin2 = 13;
int butPin1 = 7; // choose the input pin (for a pushbutton)
int butPin2 = 6;
int butVal1 = 0; // variable for reading the pin status
int butVal2 = 0;
//SERVO
Servo box;
int boxPint = 13;
void setup()
{
Serial.begin(9600);
adcInit();
adcCalb();
box.attach(boxPint);
pinMode(13, OUTPUT);
Serial.println(fftNum);
box.write(180);
}
void loop()
{
//SOUND STUFF
if (position == FFT_N)
{
fft_input(capture, bfly_buff);
fft_execute(bfly_buff);
fft_output(bfly_buff, spektrum);
position = 0;
}
int ind = 0;
// //SMOOTHER
for(int i = 0; i < fftNum/2; i++)
{
total[i] = total[i] – readings[sIndex][i];
readings[sIndex][i] = spektrum[ind] + spektrum[ind + 1];
total[i] += readings[sIndex][i];
average[i] = total[i]/smoothFrames;
ind += 2;
}
//FOR DEBUGGING INPUT WITH SMOOTHING
// Serial.println(“THIS IS A SPEKTRUM”);
// Serial.print(“[“);
//
// for (byte i = 0; i < fftNum/2; i++){
// Serial.print(average[i]);
// Serial.print(“,”);
// }
// Serial.println(“]”);
sIndex ++;
if (sIndex >= smoothFrames) sIndex = 0;
int thisNote = getNote(average);
Serial.println(thisNote);
//BUTTON STUFF
// if (recorded) digitalWrite(ledPin1, HIGH); // turn LED ON
butVal1 = digitalRead(butPin1); // read input value
if (butVal1 == HIGH) { // check if the input is HIGH (button released)
// digitalWrite(ledPin1, LOW); // turn LED OFF
}
else {
// digitalWrite(ledPin1, HIGH); // turn LED ON
//RECORDER
if(!recorded)
{
if (thisFrame < totalFrames){
Serial.println(“RECORDING!”);
indexRec[thisFrame] = thisNote;
thisFrame ++;
}
else{
Serial.println(“DONE RECORDING!”);
recorded = true;
delay(5000);
}
}
}
butVal2 = digitalRead(butPin2); // read input value
// if (passworded) digitalWrite(ledPin2, HIGH);
if (butVal2 == HIGH) { // check if the input is HIGH (button released)
// digitalWrite(ledPin2, LOW); // turn LED OFF
}
else {
// digitalWrite(ledPin2, HIGH); // turn LED ON
//PASSWORD
if(!passworded)
{
Serial.println(“INPUT PASSWORD”);
indexPass[passFrame] = thisNote;
passFrame ++;
if (passFrame >= thisFrame){
Serial.println(“DONE”);
passworded = true;
}
}
if(passworded)
{
Serial.println(“PASSWORD ENTERED”);
for(int i = 0; i < thisFrame; i++)
{
//FOR DIRECT COMPARISON OF INPUTS
// Serial.println(“RECORDER:”);
// Serial.println(indexRec[i]);
// Serial.println(“PASSWORD:”);
// Serial.println(indexPass[i]);
if(abs(indexPass[i] – indexRec[i]) > 2)
{
Serial.println(“THIS WAS WRONG!”);
worked ++;
}
}
Serial.println(“DID IT WORK?”);
if (worked < 5) {
box.write(0);
delay(1000);
passworded = false;
passFrame = 0;
}
Serial.println( worked<10);
delay(3000);
passFrame = 0;
}
}
}
// free running ADC fills capture buffer
ISR(ADC_vect)
{
if (position >= FFT_N)
return;
capture[position] = ADC + zero;
if (capture[position] == -1 || capture[position] == 1)
capture[position] = 0;
position++;
}
void adcInit(){
/* REFS0 : VCC use as a ref, IR_AUDIO : channel selection, ADEN : ADC Enable, ADSC : ADC Start, ADATE : ADC Auto Trigger Enable, ADIE : ADC Interrupt Enable, ADPS : ADC Prescaler */
// free running ADC mode, f = ( 16MHz / prescaler ) / 13 cycles per conversion
ADMUX = _BV(REFS0) | IR_AUDIO; // | _BV(ADLAR);
// ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) //prescaler 64 : 19231 Hz – 300Hz per 64 divisions
ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // prescaler 128 : 9615 Hz – 150 Hz per 64 divisions, better for most music
sei();
}
void adcCalb(){
Serial.println(“Start to calc zero”);
long midl = 0;
// get 2 meashurment at 2 sec
// on ADC input must be NO SIGNAL!!!
for (byte i = 0; i < 2; i++)
{
position = 0;
delay(100);
midl += capture[0];
delay(900);
}
zero = -midl/2;
Serial.println(“Done.”);
}
int getNote(uint16_t thisInput[])
{
int index = 0;
uint16_t note = 0;
for(int i = 4; i < fftNum/2; i++)
{
if (thisInput[i] > note)
{
note = thisInput[i];
index = i;
}
}
return index;
}