Sound Visualization Lighting Effect

For this project my partners Aastha, Effy and I decided to play around with sound and light applying the fundamentals of physical computing.

We decided to create a lighting instrument which displayed different colors based on sound input from an external source.

SONY DSC SONY DSC

During the three weeks we spent working on this project, we tested various LED strips and sound sensors (ultimately we used Processing code for sound input ) to use for this project. We also learned of FFT (Fast Fourier Transform) which is an algorithm used to convert time to frequency- something we required to make the instrument light up in sync with the music’s beat.

We faced a lot of challenges in the duration of this project both with the code and the model.

SONY DSC SONY DSC

The initial model we built for the instrument had a tiny hole for the LEDs instead of the slits we later designed. Although the former ensured consistency with the placement of the LEDs, we miscalculated leaving room for all the wires when we brought the individual parts together.

Photo Nov 03, 11 41 51 PM

Overview

A lighting instrument which displayed different colors based on sound input from an external source.

Step 1: Sound sensor sensor external music source, and send data to processing

Step 2: Processing use FFT library analysis input data, modify the float data to int data readable  for ardurino

(Data distribution picture)

Step 3: Ardurino receive the data from processing, analysis data distribution, set range, color, time, then send these values to addressable led strip

Step 4: Upload the code, install led strip to the object we designed, ready to go!

Material: 

Sound sensor : We use laptop’s mic as sound sensor in this case

Ardurino: Ardurino Leonardo

Addressable Led Stripe: WS2812B NeoPixel RGB LED Weather Proof Strip

Plastic, paper, wire, breadboard,5V power supplier

Code:

Library:
Adafruit_NeoPixel.h

Processing code:

//3D Spectrogram with Microphone Input
//Modified by kylejanzen 2011 – http://kylejanzen.wordpress.com
//Based on script wwritten by John Locke 2011 –http://gracefulspoon.com

//Output .DXF file at any time by pressing “r” on the keyboard
import processing.serial.*;
import processing.dxf.*;
import ddf.minim.analysis.*;
import ddf.minim.*;

FFT fftLin;
FFT fftLog;

Waveform audio3D;

Minim minim;
AudioInput microphone;

Serial myPort;
float val;

boolean record;

PFont font;
float jitter;
float camzoom;
float maxX = 0;float maxY = 0;float maxZ = 0;
float minX = 0;float minY = 0;float minZ = 0;

void setup()
{
size(1250,750,P3D); //screen proportions
String portName = Serial.list()[1];
myPort = new Serial(this, portName, 9600);

noStroke();
minim = new Minim(this);
microphone = minim.getLineIn(Minim.STEREO, 4096); //repeat the song

background(255);

fftLog = new FFT(microphone.bufferSize(),microphone.sampleRate());
fftLog.logAverages(1,2); //adjust numbers to adjust spacing;
float w = float (width/fftLog.avgSize());
float x = w;
float y = 0;
float z = 50;
float radius = 10;
audio3D = new Waveform(x,y,z,radius);
}
void draw()
{
background(0);
directionalLight(126,126,126,sin(radians(frameCount)),cos(radians(frameCount)),1);
ambientLight(102,102,102);

if (frameCount>200)
{
for(int i = 0; i < fftLog.avgSize(); i++){
float zoom = 1;
jitter = (fftLog.getAvg(i)*2);

PVector foc = new PVector(audio3D.x+jitter, audio3D.y+jitter, 0);
PVector cam = new PVector(zoom, zoom, -zoom);
camera(foc.x+cam.x+50,foc.y+cam.y+50,foc.z+cam.z,foc.x,foc.y,foc.z,0,0,1);

// int tempJ = round(jitter*500);
// println(“rounded ->”+ tempJ);
// myPort.write(tempJ);
}
int tempJ = round(jitter*5000);
println(tempJ);
myPort.write(tempJ);
}
//play the song
fftLog.forward(microphone.mix);

audio3D.update();
audio3D.textdraw();

if(record)
{
beginRaw(DXF, “output.dxf”);
}
audio3D.plotTrace();

if(record)
{
endRaw();
record = false;
println(“hello,world!”);
}
}
void stop()
{
// always close Minim audio classes when you finish with them
microphone.close();
// always stop Minim before exiting
minim.stop();
super.stop();
}
class Waveform
{
float x,y,z;
float radius;

PVector[] pts = new PVector[fftLog.avgSize()];

PVector[] trace = new PVector[0];

Waveform(float incomingX, float incomingY, float incomingZ, float incomingRadius)
{
x = incomingX;
y = incomingY;
z = incomingZ;
radius = incomingRadius;
}
void update()
{
plot();
}
void plot()
{
for(int i = 0; i < fftLog.avgSize(); i++)
{
int w = int(width/fftLog.avgSize());

x = i*w;
y = frameCount*5;
z = height/4-fftLog.getAvg(i)*4; //change multiplier to reduces height default ‘10’

stroke(0);
point(x, y, z);
pts[i] = new PVector(x, y, z);
//increase size of array trace by length+1
trace = (PVector[]) expand(trace, trace.length+1);
//always get the next to last
trace[trace.length-1] = new PVector(pts[i].x, pts[i].y, pts[i].z);
}
}
void textdraw()
{
for(int i =0; i<fftLog.avgSize(); i++){
pushMatrix();
translate(pts[i].x, pts[i].y, pts[i].z);
rotateY(PI/2);
rotateZ(PI/2);

fill(255,200);
text(round(fftLog.getAvg(i)*100),0,0,0);
popMatrix();
}
}
void plotTrace()
{
stroke(255,80);
int inc = fftLog.avgSize();

for(int i=1; i<trace.length-inc; i++)
{
if(i%inc != 0)
{
beginShape(TRIANGLE_STRIP);

float value = (trace[i].z*100);
float m = map(value, -500, 20000, 0, 255);
fill(m*2, 125, -m*2, 140);
vertex(trace[i].x, trace[i].y, trace[i].z);
vertex(trace[i-1].x, trace[i-1].y, trace[i-1].z);
vertex(trace[i+inc].x, trace[i+inc].y, trace[i+inc].z);
vertex(trace[i-1+inc].x, trace[i-1+inc].y, trace[i-1+inc].z);
endShape(CLOSE);
}
}
}
}
Ardurino code:

#include <Adafruit_NeoPixel.h>

#define PIN 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800); // Parameter 1 = number of pixels in strip shown as 60. Parameter 2 = pin number defined above as 6

char val;// Data received from the serial port
int b;

void setup() {
strip.begin();
strip.show(); // Initialize all pixels to ‘off’
Serial.begin(9600);

}

void loop() {
if (Serial.available()) { // If data is available to read,
val = Serial.read(); // read it and store it in val
b=val;
}
if (b< 20) {
for (int i=0; i <= 20; i++){
strip.setPixelColor(i,0,0,0);
strip.show();
}
delay (5);

}

if (b> 20) {
for (int i=0; i <= 20;i++){ //Blink up
if (i%2==0){
strip.setPixelColor(i,249,4,86); // Shorcking pink
strip.show();}
}
delay (15);

for (int i=0; i <= 20;i++){ //Blink off
strip.setPixelColor( i,0,0,0); // p1
strip.show();
}
delay (15);
}

if(b> 30) {
for (int i=0; i <= 20;i++){
if (i%2==1){
strip.setPixelColor( i,161,0,205); // purple
strip.show();}
}
delay (15);

for (int i=0; i <= 20;i++){ //Blink off
strip.setPixelColor( i,0,0,0); // p1
strip.show();
}
delay (15);
}

if(b> 60) {
for (int i=0; i <= 5;i++){
strip.setPixelColor(i,0,0,0); // Teal
strip.show();}

for (int i=6; i <= 15;i++){
strip.setPixelColor(i,4,180,183); // Teal
strip.show();}
delay (50);

for (int i=16; i <= 20;i++){
strip.setPixelColor(i,0,0,0); // Teal
strip.show();}

delay (15);
}

if(b> 100) {
for (int i=0; i <= 5;i++){
strip.setPixelColor(i,4,180,183); //blue
strip.show();}

for (int i=6; i <= 15;i++){
strip.setPixelColor(i,89,211,122); //green
strip.show();}

for (int i=16; i <= 20;i++){
strip.setPixelColor(i,4,180,183); //blue
strip.show();}

delay (100);
}

}

 

Advertisements