Press "Enter" to skip to content

Analyse sonore Arduino LED + vibreur et visualisation du spectre Processing

La partie Arduino analyse le son capté par un micro et actionne des vibreurs suivant l’intensité de chaque bande du spectre sonore. Le son influence également la couleur d’une led 256.
La partie Processing permet de visualiser l’analyse du spectre à travers la communication série.

Source: SoundVibrationVizualisation.zip

Programme Arduino

//Il est necessaire d'augmenter le tampon de la communication série pour recevoir les données correctement
//Modifer le fichier suivant C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h
// #if ((RAMEND - RAMSTART) < 1023)
// #define SERIAL_TX_BUFFER_SIZE 16
// #else
// #define SERIAL_TX_BUFFER_SIZE 8

#include <LedControl.h>
#include "arduinoFFT.h"

 
#define SAMPLES 128             //Doit rester un multiple de 2
#define SAMPLING_FREQUENCY 10000 //Hz, doit rester inférieur à 10000

arduinoFFT FFT = arduinoFFT();
 
unsigned int sampling_period_us;
unsigned long microseconds;
 
double vReal[SAMPLES];
double vImag[SAMPLES];

const int partNum = 12;        //Nombre de section de l'échantillon du spectre
int samplesTab[partNum];
boolean newData = false;
int vibrator[] = {3,5,6,9,10,11};
int led256Pin1[] = {9,10,11};
int vibPin = 5;
int ampli;
String serialText;
 
void setup() {
    Serial.begin(115200);
    for(int i=0; i<sizeof(vibrator); i++){
      pinMode(vibrator[i], OUTPUT);
    }
    pinMode(vibPin, OUTPUT);
    pinMode(led256Pin1[0], OUTPUT);
    pinMode(led256Pin1[1], OUTPUT);
    pinMode(led256Pin1[2], OUTPUT);
 
    sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY));
}
 
void loop() {
   
  /*SAMPLING*/
  for(int i=0; i<SAMPLES; i++)
  {
      microseconds = micros();    //risque de débordement au-delà de 70 mn
      vReal[i] = analogRead(0);
      vImag[i] = 0;
      while(micros() < (microseconds + sampling_period_us)){
      }
  }

  /*FFT*/
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
  //Serial.println(peak);

  writeAverageSerialText();
  //writeSerialText();

  if(newData){
    int sampleMap = map(samplesTab[5],0, 20, 0, 255);
    Serial.print("volume band: ");
    Serial.println(samplesTab[5]);
    Serial.print("puissance vibration: ");
    Serial.println(sampleMap);
    analogWrite(vibPin, sampleMap);
    digitalWrite(led256Pin1[0], HIGH);
    digitalWrite(led256Pin1[1], HIGH);
    digitalWrite(led256Pin1[2], HIGH);
  }

  //analogWrite(vibPin, sampleMap);
}


//Envoi de l'ensemble du spectre
void writeSerialText(){
  serialText = String(SAMPLING_FREQUENCY) + "/";
  serialText += String(SAMPLES) + "/";
  
  for(int i=0; i<SAMPLES; i++)
  { 
      serialText += String(vReal[i]) + "/";
  }
  //Serial.print("Sound total spectrum: ");
  //Serial.println(serialText); // sample feedback
}

//Envoi d'une moyenne du spectre
void writeAverageSerialText(){
  int tabId = 0;
  int averageTreshold = floor(SAMPLES / partNum);
  int nextI = 0;
  float averageSamples;

  serialText = String(SAMPLING_FREQUENCY) + "/";
  serialText += String(averageTreshold) + "/";
  
  for(int i=0; i<SAMPLES; i++)
  {
    if(nextI < averageTreshold){
      averageSamples += vReal[i];
      nextI += 1;
    }else{
      averageSamples = averageSamples/nextI;
      samplesTab[tabId] = averageSamples;
      tabId += 1;
      serialText += String(averageSamples) + "/";
      nextI = 0;
    }
  }

  newData = true;
  //Serial.print("Sound average spectrum: ");
  //Serial.println(serialText); // spectrum feedback
}

Programme Processing

import processing.serial.*;
Serial port;

String data  = "";
boolean newData;
float samples;
float samplingFreq;
String[] samplePart;
float sampleWidth;
float sampleHeight;

void setup() {
  size (800,600);
  background(255);
  
  rectMode(CORNERS);
  
  port = new Serial(this, "COM11", 115200);
  port.bufferUntil('\n');
  
  newData = false;
  sampleWidth = 4;
}

void draw() {
  background(255,255,255,0.5);

  if(newData){
    if(samplePart.length > 2){
      samplingFreq = float(samplePart[0]);
      samples = float(samplePart[1]);
    }
    
    //display all frequency
    for(int i=4; i<samplePart.length; i++){
      if(i < samplePart.length){
        pushStyle();
        noStroke();
        float sampleHz = float(samplePart[i]);
        int colorRange = 50;
        int rightMargin = 100;
        int interMargin = 2;
        //println("i: " + i + " / sPl: " + samplePart.length);
        float sampleAjust = map(sampleHz, 0, 40, 0, 200);
        
        if ( mouseX >= i*sampleWidth+rightMargin+interMargin && mouseX < i*(sampleWidth)+sampleWidth+rightMargin )
        {
          fill(120);
          String samplePartFrequency = samplingFreq/samples*i + "Hz";
          text(samplePartFrequency, rightMargin - textWidth(samplePartFrequency), height*0.3);
          fill(255,0,0); 
        }else{
          fill(0,255,0);
        }
        
        rect(i*sampleWidth+rightMargin+interMargin, height*0.3-sampleAjust/2, i*(sampleWidth)+sampleWidth+rightMargin, height*0.3+sampleAjust/2);
        popStyle();
      }
    }
  }
}

void serialEvent(Serial port) {
  data = port.readStringUntil('\n');
  println(data);
  newData = true;
  samplePart = split(data, '/');
}

Comments are closed.