Lab 2 – Team Cake

Members: Connie, Angie, Kiran, Edward
Lab Group 13

We built two sets of hardware interfaces: our final instrument was a wind instrument that played chords when you blew into “pipes” (straws), and our alternate interface was a “force-sensitive softpot” that combined the two sensors into a single control element. In our final instrument, we blew on a thermistor to change its temperature and combined three of these to create a wind-like instrument. We liked the weirdness of using heat to play music, as well as the quirky design: we used straws as the blowholes on our Arduino. The simple but exotic interface also lent itself well to our eerie synthesis mappings. However, it would have been better if we could have had a larger array of thermistors. Then, instead of mapping each thermistor change to a scale of notes, we could have done more complicated things and given the user more control. All in all, we were very satisfied with the sounds created by our final instrument – the ambiance that it gave off was really cool, and we thought it went really well together with our wind instrument interface.

Force-sensitive Softpot Instrument

For our first two instruments, we used the same hardware interface. We wanted to design an instrument that deeply combined two sensors to create a different experience than we made in previous labs, where all the sensors were separate in the interface. Thus, we decided to make a Force-sensitive Softpot, that sensed not only where on a slider you were touching but also how hard. Combining the two dimensions of input like this made controlling two parameters into one action, allowing for more artistic effects.

We created two different mappings for our FSS instrument. The first was very simple, where position along the softpot mapped directly to frequency and the force on the FSR mapped to volume. Our choice of waveform (sine wave with a slight reverb) this created an eerie-sounding howling effect. We found after some experimentation that the softpot required a certain minimum level of force to give stable readings, so we adapted the FSR mapping to be thresholded instead (only mapping readings above the threshold to volume).

Our second mapping was a little bit more radical. We mapped force on the FSR to timbral parameters used in waveshaping synthesis, to make a sine tone sound more “sharp” or “buzzy”. We also changed the softpot mapping to a discrete frequency mapping, so that tones were constrained to the 12 notes of the western chromatic scale. The timbral effects were especially cool – we could make sounds that almost sounded like speech, since the different levels of timbre sounded almost like different vowels, and changing between them sounded like “Wa” noises.

Final Instrument: Wind instrument


This “wind instrument” used the user’s breath to warm up thermistors placed at the bottom of the “pipes” (straws). Each pipe is responsible for a different chord and a different tempo. For example, in our demonstration we have a fast Fm6, a fast Cm9, and a slower, lower Cm9. The actual pitch classes played are randomly selected from the chord. The temperature reading controls the octave in which the chord is played: as you blow into the pipe, the chord gets higher, and as you stop blowing, the chord gradually falls down to a lower range as the thermistor cools off. This causes a fancy decaying effect, almost like the fading resonance of a struck bell.

Parts List

  • 3x Thermistor
  • 3x 330K Resistors
  • 3x Straws
  • Arduino Uno
  • Wires
  • Straws

We also require a computer installed with Processing and ChucK (and Arduino, of course).

Instructions

  1. Connect one thermistor to 5V and to A0. Connect A0 to ground through a 330K pull down resistor.
  2. Cut a straw so it is about 5cm in length. Place it on top of the thermistor
  3. Repeat steps 1 and 2 twice more for your two remaining thermistors, connecting them to A1 and A2.
  4. Loosely tape the straws together.
  5. Take some readings of the thermistor with the straws on, but without blowing into them. Set the maximum such value as the baseline in the ChucK code.
  6. To play the instrument, blow into the straws. The raised temperature of your breath should warm up the thermistors, which will gradually cool. Take off the straws if you want it to cool down faster.

Source Code

Arduino Code

/*
 Temperature Blow Straw Music Instrument
 Lab 2
 COS 436: Human-Computer Interfaces
 March 6, 2013
 Arduino Code
 */

//variables 
int temperature1; //temp sensor 1
int temperature2; //temp sensor 2 
int temperature3; //temp sensor 3

//pins
int pinT1 = A0; 
int pinT2 = A1; 
int pinT3 = A2; 

void setup()
{
  // initialize the serial communication:
  Serial.begin(9600);
}

void loop() {
  temperature1 = analogRead(pinT1);
  temperature2 = analogRead(pinT2);
  temperature3 = analogRead(pinT3);
  
  //Serial.print("Temperature 1: ");
  Serial.print(temperature1);
  Serial.print(" ");
  Serial.print(temperature2);
  Serial.print(" ");
  Serial.println(temperature3);
  
  delay(100);
}

Processing Code

/* Generic numerical message forwarding from Arduino to OSC */
import java.util.*;
import oscP5.*;
import netP5.*;
import processing.serial.*;

Serial myPort;

OscP5 oscP5;
NetAddress dest;
int port = 6448;
String oscName = "/arduinoData";

String data;

void setup() {
  size( 400, 300 );
  myPort = new Serial(this, Serial.list()[0], 9600);
  myPort.bufferUntil('\n');
  oscP5 = new OscP5(this,12000);
  dest = new NetAddress("127.0.0.1",port);
}

void serialEvent(Serial myPort) {
  String instr = myPort.readStringUntil('\n');
  data = instr;
  sendOsc();
}

void draw() {
 ;
}

void sendOsc() {
  OscMessage msg = new OscMessage(oscName);
  String[] tokens = data.split("\\s");
  for (int i = 0; i  0) {
      msg.add(Float.parseFloat(tokens[i]));  
    }
  }
  oscP5.send(msg, dest);
}

ChucK Code

// HCI Lab 2 - Wind Instrument 
// ChucK Synthesis Script
// Generates random notes in chords, with the octave based on the readings from the arduino.
JCRev r => Gain g => dac;
.1 => r.mix;
.7 => r.gain; 
.5 => g.gain;

// ---------------- Globals ---------------
32 => float baseline;   // Ambient temperature readings for thermistors

1 @=> float octave[];  // Current octave
1 @=> float in[];      // Current reading
// ----------------------------------------

// ---------------- Chords ----------------
[0, 2, 4, 7] @=> int chord1[];    // I9
[5, 7, 9, 12] @=> int chord2[];   // IV
[7, 11, 14, 17] @=> int chord3[]; // V7

[0, 2, 3, 7] @=> int chord4[];    // i9
[5, 8, 12, 14] @=> int chord5[];  // iv6
[7, 11, 14, 17] @=> int chord6[]; // V7
// ----------------------------------------


// Function that plays notes in appropriate chord
fun void playstuff(int chord[], int index, int tonic, int speed) {
    SinOsc s => r;
    .2 => s.gain;
    3 => int x;
    1 => int off;
    while (true) {
        if (in[index] >= baseline) {
            Math.round((in[index] - baseline)/2) => octave[index];
            0.5 => s.gain;
            if (Math.random2(0,1) == 0) {
                1 => off;
            } else {
                3 => off;
            }
            Std.mtof(tonic + chord[(x + off)%4] + 12*octave[index]) => s.freq;
        } else {
            0 => s.gain;
        }
        x + 3 => x;
        if (x > 3) x - 4 => x;
        speed::ms => now;
    }
}

// Initialize one thread for each thermistor
spork ~ playstuff(chord4, 0, 60, 150);
spork ~ playstuff(chord5, 1, 60, 150);
//spork ~ playstuff(chord6, 2, 60, 150);
spork ~ playstuff(chord4, 2, 48, 600);


// --------------------- OSC Processing -------------------------
OscRecv recv;
6448 => recv.port;

recv.listen();

recv.event("/arduinoData, f f f") @=> OscEvent @ oe;

while(true) {
    oe => now;
    while(oe.nextMsg()) {       
		oe.getFloat() => in[0];
        oe.getFloat() => in[1];
        oe.getFloat() => in[2];
        <<>>;
    }
}

  1. ,0.,0.
  2. ,0.,0.