LED Sound Instrument by Aastha Bhargava, Effy Zhang, and Mikey Chen

LED Sound Instrument
Physical Computing Midterm Project
SVA Interaction Design MFA

Aastha Bhargava, Effy Zhang, and Mikey Chen

For our mid term project my partners Mikey, Effy and I decided to play around with sound and light applying the fundamentals of physical computing. We created a lighting instrument which displayed different colours based on sound input from an external source.

During the three weeks we spent working on this project, we tested various LED strips and sound sensors to use for this project (ultimately we used Processing for sound input ). 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.

The initial model we built for the instrument had a tiny holes 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.

Overview

Computer microphone senses music played from an external source and sends data to Processing

Processing FFT library analysis this data and modifies the same to be readable for Arduino

Arduino receives the data from Processing, analysis the data distribution, sets range, color, time and then sends these values to the addressable LED strip

The code is then uploaded to the LED strip.

Materials Used: 

Sound sensor : Our computer’s microphone

Arduino Board : Arduino Leonardo

LED : WS2812B NeoPixel RGB LED Weather Proof Strip (addressable LED strip)

Plastic

Paper

Wire

Breadboard

5V Power Source

Code:

For Processing:

//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);
}
}
}
}

For Arduino:

#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);
}

}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a website or blog at WordPress.com

Up ↑

%d bloggers like this: