User login

Powered by Drupal, an open source content management system

Theory and Practice of Tangible User Interfaces

Lab 9: Musical Instrument

Submitted by Seth Horrigan on Sun, 11/09/2008 - 19:55

Assignment: Synthesis: Music Instrument (group work)

Collaborators:

Assignment: Synthesis: Music Instrument (group work)
Collaborators: Sarah van Wart, Tilman Dingler

Description

We set out to make a completely unique musical instrument. We approached the problem rather backwards - we started by coming up with interesting ways of providing the input, then once we had those, we came up with sounds to associate with the inputs. We first attempted to use Jello as a variable resistor, but when we discovered that it is far too conductive, we expanded our conception to playing with your food in general. Thus was born the Edible Symphony!

One apple acts as a variable resistor, with a ground inserted into the flesh of the apple and the source connected to the finger of the musician. We vary the frequency of a triangle wave superimposed on the sine wave then synthesize that waveform using ESS. The Jello is similar, except due to the very low resistance of Jello, we employ it instead as a switch wherein the completed circuit moves the current above a threshold value at which point we play a sample. The syrup has a force sensitive resistor connected to it so that when the syrup is squeezed it can also play a sample. Lastly, the second apple is connected to a potentiometer. As the potentiometer is turned it reaches five separate thresholds. As each threshold is reached, another sample is introduced into the beat being played.

The mixer instrument is specifically designed to be played collaboratively, so the input transducers require more than two hands to play simultaneously. Also, the input method for each transducer is unique so as to encourage different people to play them, allowing each person to focus on the technique for his or her own piece of the Edible Symphony.

 

Components Used

  • 1 Arduino board
  • 1 generic solderless breadboard
  • 2 rubber bands to secure the Arduino board to the breadboard
  • wires
  • 2 apples
  • 1 cup of Jello
  • 1 bottle of chocolate syrup
  • 1 FSR
  • 1 Potentiometer
  • 3 10 k resistors

 

Images and Video

Musical Instrument - first full demonstration

Musical Instrument - first test

 

The creative process

Just finished

 

Processing Code

/*
* Control the musical responses to various food-based
* musical instrument inputs.
*
* Theory and Practice of Tangible User Interfaces
* Nov 8, 2008
*
* Seth Horrigan
* Sarah Van Wart and Tilman Dingler
*/

import krister.Ess.*;
import processing.serial.*;

AudioStream myStream;
SineWave myWave1;
TriangleWave myWave2;

FadeOut myFadeOut;
FadeIn myFadeIn;
Reverb myReverb;

AudioChannel fsrChannel;
AudioChannel jelloChannel;

AudioChannel track01;
AudioChannel track02;
AudioChannel track03;
AudioChannel track04;
AudioChannel track05;

Normalize myNormalize;

int oldFrequency=0;
int frequency = 0;

boolean doFadeIn=false;
boolean playing = false;
int jelloTimer = 0;

// Change this to the portname your Arduino board
String portname = "COM4";
Serial port;
String buf="";
int cr = 13; // ASCII return == 13
int lf = 10; // ASCII linefeed == 10

void setup() {
//We need to get input to change the pitch
port = new Serial(this, portname, 9600);

// start up Ess
Ess.start(this);

jelloChannel = new AudioChannel("whip.wav");
fsrChannel = new AudioChannel("newage-adventure1.aif");
// Load audio file into a AudioChannel, file must be in the sketch's "data" folder
track01 = new AudioChannel("track01.aif");
track02 = new AudioChannel("track02.aif");
track03 = new AudioChannel("track03.aif");
track04 = new AudioChannel("track05.aif");
track05 = new AudioChannel("track04.aif");

track01.volume(0.4);
track02.volume(0.4);
track03.volume(0.4);
track04.volume(0.4);
track05.volume(0.4);
fsrChannel.volume(0.4);
jelloChannel.volume(0.4);

// create a new AudioStream
myStream=new AudioStream();
myStream.volume(1.0);

// our waves
myWave1=new SineWave(0,.33);
myWave2=new TriangleWave(0,.66);

// our effects
myFadeOut=new FadeOut();
myFadeIn=new FadeIn();
myReverb=new Reverb();
myNormalize = new Normalize();

myNormalize.filter(fsrChannel); // Normalize the audio
myNormalize.filter(jelloChannel);

track01.play(Ess.FOREVER);
track01.mute(true);

track02.play(Ess.FOREVER);
track02.mute(true);

track03.play(Ess.FOREVER);
track03.mute(true);

track04.play(Ess.FOREVER);
track04.mute(true);

track05.play(Ess.FOREVER);
track05.mute(true);

// start
myStream.start();
}

// called whenever serial data arrives
void serialEvent(Serial p) {
int c = port.read();

//println("c = " + c + "; buf: " + buf);

if (c != lf && c != cr) {
buf += char(c);
return;
}else if (c == lf) {
char mode = buf.charAt(0);
buf = buf.substring(1, buf.length());
//println("mode: " + mode + "; val: " + buf);
// Parse the String into an integer
switch(mode)
{
case 'j': //jello Input:
jello(Integer.parseInt(buf));
break;
case 's': //FSR Input:
syrup(Integer.parseInt(buf));
break;
case 'p': //pot Input:
pot(Integer.parseInt(buf));
break;
case 'a':
apple(Integer.parseInt(buf));
break;
}//end switch
buf = "";
}
}


void pot(int val) {
//println("Pot " + val);
try{
if (val <=5) {
track01.mute(true);
track02.mute(true);
track03.mute(true);
track04.mute(true);
track05.mute(true);
}
else if(val<=204) {
track01.mute(false);
track02.mute(true);
track03.mute(true);
track04.mute(true);
track05.mute(true);
}
else if (val<=408) {
track01.mute(false);
track02.mute(false);
track03.mute(true);
track04.mute(true);
track05.mute(true);
}
else if (val<= 612) {
track01.mute(false);
track02.mute(false);
track03.mute(false);
track04.mute(true);
track05.mute(true);
}
else if (val<= 816) {
track01.mute(false);
track02.mute(false);
track03.mute(false);
track04.mute(false);
track05.mute(true);
}
else {
track01.mute(false);
track02.mute(false);
track03.mute(false);
track04.mute(false);
track05.mute(false);
}
}catch(Exception e){}
}

void apple(int val){
//println("Apple " + val);
if(val > 25){
frequency = 50 + val;
}else{
frequency = 0;
}
}

void audioStreamWrite(AudioStream theStream) {
//println("frequency = " + frequency);

myWave1.generate(myStream);
myWave2.generate(myStream, Ess.ADD);

// adjust our phases
myWave1.phase+=myStream.size;
myWave1.phase%=myStream.sampleRate;
myWave2.phase=myWave1.phase;

if (doFadeIn) {
myFadeIn.filter(myStream);
doFadeIn=false;
}

if (frequency!=oldFrequency) {
// we have a new frequency
myWave1.frequency=frequency;

// non integer frequencies can cause timing issues with our simple timing code
myWave2.frequency=(int)(frequency*4.33);

myWave1.phase=myWave2.phase=0;

// out with the old
// fade out the old sound to create a
myFadeOut.filter(myStream);

doFadeIn=true;
//println("Playing frequency: "+frequency);

oldFrequency=frequency;
}

// reverb
myReverb.filter(myStream,.5);
}


void syrup(int val)
{
//println("Syrup " + val + "; playing " + playing);
if(val > 100 && !playing)
{
fsrChannel.play(Ess.FOREVER);
playing = true;
}else if(val < 100 && playing){
fsrChannel.stop();
playing = false;
}
}

void jello(int val)
{
//println("Jello " + val);
if(val > 300 && millis() > jelloTimer + 400)
{
jelloTimer = millis();
jelloChannel.stop();
jelloChannel.play(1);
}
}

void draw(){
}

void keyPressed(){
}

// we are done, clean up Ess
public void stop() {
Ess.stop();
super.stop();
}

Arduino Code

/*
* Read input from our food-based transducers and pass it on to
* the processing environment.
*
* Theory and Practice of Tangible User Interfaces
* Nov 8, 2008
*
* Seth Horrigan
*/



int applePin = 0;
int jelloPin = 1;
int potPin = 2;
int syrupPin = 3;
int val = 0; // variable to store the value coming from the sensor

void setup() {
Serial.begin(9600);
}

void loop() {
int aval = analogRead(applePin);
int jval = analogRead(jelloPin);
int pval = analogRead(potPin);
int sval = analogRead(syrupPin);

Serial.print("a");
Serial.println(aval);
Serial.print("j");
Serial.println(jval);
Serial.print("p");
Serial.println(pval);
Serial.print("s");
Serial.println(sval);

delay(50);
}