Final Blog : Headbanger's Ball
This blog shall cover the conception, development, and completion of my final physical computing project, entitled 'Headbanger's Ball".
Concept
The concept behind 'Headbanger's Ball' is a stress relief device in the form of a boxing pad attached to the wall (in a public or semi-public space) that, when hit (preferably with the head) will insult the user with a vaiety of pre-recorded audio samples. The user presumably hits the device until they find the insults funny, or have hit the pad enough that their rage has subsided.
The user then has the option of recording an insult or joke of their own into the array of audio samples so that future users shall get the benefit of their own wisdom, and give the inital user incentive to come back and see their contributions in practice.
The idea was concieved while I was struggling with a particular part of a project; so much so that I wanted to bang my head against the wall - and therein lies the epiphany.
Design
The physical structure of 'Headbanger's Ball' is relatively simple; two thin pieces of plywood, one with four buttons at the corners, are inserted into a boxing practice pad. This way, a hit anywhere on the surface of the pad will trigger at least one of the buttons, all of which are connected to the same digital input pin on the microcontroller (thus, a hit triggering one of the buttons is as good as a hit triggering all four).
The pad is sheltered in a wooden frame (made lovingly by myself). The frame is meant to limit the pad's movement along and the X and Y axises, and give some extra support along the Z axis. The frame also has hooks on the top to facilite the mounting process.
The wires from the buttons come through a hold cut in the back of the frame, so as to minimalize the stress on the wiring. They go from the back of the frame into the case containing the breadboard, microconroller, and the mechanism to record your own vocal additions.
Click on the link below for a simple diagram of the Headbanger's Ball:
http://itp.nyu.edu/~blm272/PComp/HBB_Diagram.pdf
(copy and paste the above if the other one doesn't appear)
The programing, in theory, wasn't that difficult, though I personally had a few stumbling blocks along the way which made this the mose challanging part of the project, next to refining the hit response.
In sum, I created an arraylist of audio samples using the Sonia library. I then prerecorded and preloaded about 20 samples to populate the array. The tricky part was writing code that would record the sample based on a chage in incoming serial data and put it in the correct spot in the array. Obviously, the problem was eventually solved.
Here's a copy of the processing code, just for kicks (and in the name of open source):
//Headbanger's Ball
//Ben Leduc-Mills
//Final Project, Fall 2006
import processing.serial.*;
import pitaru.sonia_v2_9.*; // import necessary libraries
import java.util.ArrayList.*;
ArrayList allSamples = new ArrayList(); //declare array list
int whichSample; //var for sample that is playing
int inByte; // var to read bytes from serial port
int sampleTime = 5; //max length of live sample in seconds
int preLoadedSamples = 23; //var to chnage # of preloaded samples (= to # -1)
Serial myPort;
Sample mySample;
Sample myLiveSample;
void setup(){
size(512,200);
Sonia.start(this); // Start Sonia engine.
LiveInput.start(); // start Live Input engine
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 9600);
// create a new sample object.
mySample = new Sample("file1.wav");
//write loop to go through and load all the samples in the array list
for (int i = 1; i < preLoadedSamples; i++) { //test = number of PRELOADED samples +1
Sample mySample =new Sample ("file" + i + ".wav");
allSamples.add(mySample);
}
myPort.write(65); //send an "A" out the serial port
}
void draw(){
while (myPort.available() > 0) {
int inByte = myPort.read();
println(inByte);
}
delay (100);
//play samples in array on hit
if (myPort.read() == 49){
println("play");
Sample currentSample = (Sample) allSamples.get(whichSample);
currentSample.play();
//mySample.play();
delay (1000);
whichSample++;
if (whichSample >= allSamples.size()){
whichSample = 0;
}
}
//record new sample when button is pushed
if (myPort.read() == 51){
println("record");
myLiveSample = new Sample (44100 * sampleTime);
LiveInput.startRec(myLiveSample);
delay (5000);
myLiveSample.setVolume(7); //adjust volume
myLiveSample.play();
allSamples.add(myLiveSample);
}
}
/*void keyPressed(){
println("play");
//on mouseclick, play current sample in arraylist, wait 1 second, cue next sample, wait for next click
Sample currentSample = (Sample) allSamples.get(whichSample);
currentSample.play();
delay(1000);
whichSample++;
//if we get to the end, start over
if (whichSample >= allSamples.size()){ //allSample.size (returns # of things in array)
whichSample = 0;
}
}*/
/*void mousePressed(){
println ("recording");
myLiveSample = new Sample (44100 * sampleTime); //five seconds worth of sample @ 44100 rate
LiveInput.startRec(myLiveSample); // start recording
delay (1000); //wait
}
void mouseReleased(){
println ("stopped");
LiveInput.stopRec(myLiveSample); //stop recording on key (button) released
delay(200);
myLiveSample.play();
allSamples.add(myLiveSample);
}*/
// Safely close the sound engine upon Browser shutdown.
public void stop(){
Sonia.stop();
super.stop();
}
Conclusions
I was quite happy overall with the way this project turned out. Apart from the frame being less sturdy then I had hoped, the actual circuit interface took a lot of abuse and still works, an aspect integral to the cathartic success of the project.
I am interested in pursuing some further work on this project, specifically in two main areas; refining the response actions, and refining the strutural interface.
Ideally, I think a variety of responses based on such things as how hard the hit was, the rapidity of the hits, and even proximity sensing might enhance the user experience tremendously. In addition, I am interested in looking into alternate (or at least more stable) housing for the project. Perhaps a correctly weighted stand could allow for the pad to be disconnected from the wall. There are also a myriad of possibilities concerning the actual look of the pad; covered by a mask, encased in a life-sized dummy, embedded or hidden into a wall, and turning the pad back into a handheld portable device are all ideas that seem to have some merit. All in all, this was a very rewarding process and I look forward to continuing it.
Concept
The concept behind 'Headbanger's Ball' is a stress relief device in the form of a boxing pad attached to the wall (in a public or semi-public space) that, when hit (preferably with the head) will insult the user with a vaiety of pre-recorded audio samples. The user presumably hits the device until they find the insults funny, or have hit the pad enough that their rage has subsided.
The user then has the option of recording an insult or joke of their own into the array of audio samples so that future users shall get the benefit of their own wisdom, and give the inital user incentive to come back and see their contributions in practice.
The idea was concieved while I was struggling with a particular part of a project; so much so that I wanted to bang my head against the wall - and therein lies the epiphany.
Design
The physical structure of 'Headbanger's Ball' is relatively simple; two thin pieces of plywood, one with four buttons at the corners, are inserted into a boxing practice pad. This way, a hit anywhere on the surface of the pad will trigger at least one of the buttons, all of which are connected to the same digital input pin on the microcontroller (thus, a hit triggering one of the buttons is as good as a hit triggering all four).
The pad is sheltered in a wooden frame (made lovingly by myself). The frame is meant to limit the pad's movement along and the X and Y axises, and give some extra support along the Z axis. The frame also has hooks on the top to facilite the mounting process.
The wires from the buttons come through a hold cut in the back of the frame, so as to minimalize the stress on the wiring. They go from the back of the frame into the case containing the breadboard, microconroller, and the mechanism to record your own vocal additions.
Click on the link below for a simple diagram of the Headbanger's Ball:
http://itp.nyu.edu/~blm272/PComp/HBB_Diagram.pdf
(copy and paste the above if the other one doesn't appear)
The programing, in theory, wasn't that difficult, though I personally had a few stumbling blocks along the way which made this the mose challanging part of the project, next to refining the hit response.
In sum, I created an arraylist of audio samples using the Sonia library. I then prerecorded and preloaded about 20 samples to populate the array. The tricky part was writing code that would record the sample based on a chage in incoming serial data and put it in the correct spot in the array. Obviously, the problem was eventually solved.
Here's a copy of the processing code, just for kicks (and in the name of open source):
//Headbanger's Ball
//Ben Leduc-Mills
//Final Project, Fall 2006
import processing.serial.*;
import pitaru.sonia_v2_9.*; // import necessary libraries
import java.util.ArrayList.*;
ArrayList allSamples = new ArrayList(); //declare array list
int whichSample; //var for sample that is playing
int inByte; // var to read bytes from serial port
int sampleTime = 5; //max length of live sample in seconds
int preLoadedSamples = 23; //var to chnage # of preloaded samples (= to # -1)
Serial myPort;
Sample mySample;
Sample myLiveSample;
void setup(){
size(512,200);
Sonia.start(this); // Start Sonia engine.
LiveInput.start(); // start Live Input engine
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 9600);
// create a new sample object.
mySample = new Sample("file1.wav");
//write loop to go through and load all the samples in the array list
for (int i = 1; i < preLoadedSamples; i++) { //test = number of PRELOADED samples +1
Sample mySample =new Sample ("file" + i + ".wav");
allSamples.add(mySample);
}
myPort.write(65); //send an "A" out the serial port
}
void draw(){
while (myPort.available() > 0) {
int inByte = myPort.read();
println(inByte);
}
delay (100);
//play samples in array on hit
if (myPort.read() == 49){
println("play");
Sample currentSample = (Sample) allSamples.get(whichSample);
currentSample.play();
//mySample.play();
delay (1000);
whichSample++;
if (whichSample >= allSamples.size()){
whichSample = 0;
}
}
//record new sample when button is pushed
if (myPort.read() == 51){
println("record");
myLiveSample = new Sample (44100 * sampleTime);
LiveInput.startRec(myLiveSample);
delay (5000);
myLiveSample.setVolume(7); //adjust volume
myLiveSample.play();
allSamples.add(myLiveSample);
}
}
/*void keyPressed(){
println("play");
//on mouseclick, play current sample in arraylist, wait 1 second, cue next sample, wait for next click
Sample currentSample = (Sample) allSamples.get(whichSample);
currentSample.play();
delay(1000);
whichSample++;
//if we get to the end, start over
if (whichSample >= allSamples.size()){ //allSample.size (returns # of things in array)
whichSample = 0;
}
}*/
/*void mousePressed(){
println ("recording");
myLiveSample = new Sample (44100 * sampleTime); //five seconds worth of sample @ 44100 rate
LiveInput.startRec(myLiveSample); // start recording
delay (1000); //wait
}
void mouseReleased(){
println ("stopped");
LiveInput.stopRec(myLiveSample); //stop recording on key (button) released
delay(200);
myLiveSample.play();
allSamples.add(myLiveSample);
}*/
// Safely close the sound engine upon Browser shutdown.
public void stop(){
Sonia.stop();
super.stop();
}
Conclusions
I was quite happy overall with the way this project turned out. Apart from the frame being less sturdy then I had hoped, the actual circuit interface took a lot of abuse and still works, an aspect integral to the cathartic success of the project.
I am interested in pursuing some further work on this project, specifically in two main areas; refining the response actions, and refining the strutural interface.
Ideally, I think a variety of responses based on such things as how hard the hit was, the rapidity of the hits, and even proximity sensing might enhance the user experience tremendously. In addition, I am interested in looking into alternate (or at least more stable) housing for the project. Perhaps a correctly weighted stand could allow for the pad to be disconnected from the wall. There are also a myriad of possibilities concerning the actual look of the pad; covered by a mask, encased in a life-sized dummy, embedded or hidden into a wall, and turning the pad back into a handheld portable device are all ideas that seem to have some merit. All in all, this was a very rewarding process and I look forward to continuing it.