Project 2 - Prototype for an alternative interface

     My vision for the second project was to come up with a way for people to share experiences through non visual mediums. I ended up choosing sound for the medium because it seemed the most practical and varied way to convey what I wanted. So much of what we share today is visually based even if it does incorporate sound into it, like videos of concerts or vlogs for instance. My goal was to simply take the inputs from person A and convey that data through sound to person B. The device would be wearable and measure a variety of environmental factors (wind, temperature, sun, rain, humidity) but also measure biological factors (heartrate, recent movement, body temp, brain waves) in order to convey how the user was feeling as well as what the environment was like, with the output sound taking the form of a procedurally generated song. This could serve a variety of purposes: an installation with two closed booths that contain environmental controls, a platform to share experiences around the world, or with enough knowledge of how the sensors work a way to describe an event without words or recordings. As the world becomes more complex I believe we need to adapt and develop novel ways to describe it.

   In terms of prototyping it though I was limited by sensors, but mainly by lack of any musical ability. I settled for four sensors that can affect a basic octave of notes in different ways both individually and as they are combined.
The picture above makes it look a lot more complicated than it is so I've broken down the two halves of the circuit in fritzing below. Power wires are red, ground is black, sensor inputs are green, and button inputs are either yellow or orange. These colors are the same in fritzing and the circuit except I ran out of short red jumpers and used gray for two of the button's power.

 The half pictured above contains, two buttons, a photo resistor, and a water level sensor. The wiring is very straight forward and had no issues, although providing power to so many things on a mini bread board did get awkward. The water level sensor was interesting to use as it feels very counter intuitive to dip a circuit into water so I connected it though longer cables to prevent accidents.
The second half (pictured above) contains two buttons, a temperature sensor, and a metal sensor. The wiring was fairly standard for both of them but the documentation was difficult at best. I've determined the metal or "mental" sensor as it was called in the documentation detects anything conductive coming into contact and is a digital sensor, not analog, but other than a little confusion on values returned it was not difficult to hook up. The temperature sensor on the other hand was quite the handful, it required two external .h files which were provided but had a typo causing an error in one which had to be corrected before I could get it to work. It also conveys its data in the form of a float but through a non PWM digital pin which has a moderate delay. The programming for getting the data in a usable form was probably the most difficult part of the circuit.
     Overall the programming was probably the most difficult part of the prototype and I approached it in steps. The first step was to get the sensor data input on button press and map it to a value 1-255 so it could fit into a single byte which was fairly easy with a heavy use of the map function(). The next step was sending the data across to processing so I could use the processing sound library to create the sounds for my output which also was fairly straight forward, barring the metal sensor button having inconstant behavior that would overflow the buffer.
    Getting to processing sound I struggled with creating anything musical let alone something musical that could be meaningfully influenced by me and still sound good so I settled for an octave of MIDI notes and gave each sensor something to affect. The goal was, based on the sound of the scale someone else would be able to tell what kind of values were passed in. The temperature sensor controlled tempo, hotter is faster. The metal sensor controlled direction, up the scale for no contact, down for having contact. The light sensor controlled the pitch with dark being deeper notes that are closer together and lighter is higher notes that are spaced farther apart. The water sensor affects the envelope the notes are played using. The board can also enter a state where the notes are all muffled and the way to clear it and return to normal is activate all four sensors after the state is entered, this was designed to simulate some of the more complex measurements the device could take in a more realized form like recent movement or pattern activation.

I've included my code below but there isn't anymore content after it so feel free to stop reading here.
//Arduino Code
#include "DallasTemperature.h"
#include "OneWire.h"

//player 1 -----------------------------------------------------------------------------------------------
//water sensor ............................................
const int waterSensorPin = A0;
int waterSensorValueRaw;
int waterSensorMax = 255;
int waterSensorValue;

const int waterButton = 13;
int waterButtonPrev;

//light sensor ............................................
const int lightSensorPin = A1;
int lightSensorValueRaw;
int lightSensorValueBase;
int lightSensorValue;
int lightSensorMax = 50;
int lightSensorMin = -50;

const int lightButton = 12;
int lightButtonPrev;

//player 2 -----------------------------------------------------------------------------------------------
//metal sensor ............................................
const int metalSensorPin = 9;
int metalSensorValueRaw;
int metalSensorValue;

const int metalButton = 11;
int metalButtonPrev;

//temp sensor ............................................
#define tempSensorPin 2
OneWire oneWire(tempSensorPin);
DallasTemperature sensors(&oneWire);
int tempSensorValueRaw;
int tempSensorValue;
const int tempButton = 10;
int tempButtonPrev;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  lightSensorValueBase = analogRead(lightSensorPin);
  sensors.begin();

  sensors.requestTemperatures();
  tempSensorValueRaw = sensors.getTempCByIndex(0);
  tempSensorValue = tempSensorValueRaw + 175;
  
  //buttons
  pinMode(lightButton,INPUT_PULLUP);
  pinMode(waterButton,INPUT_PULLUP);
  pinMode(metalButton,INPUT_PULLUP);
  pinMode(tempButton,INPUT_PULLUP);

  Serial.println("q");
}

void loop() {
  //buttons........................................................................................
  waterButtonPrev = checkButton(waterButton,waterButtonPrev);
  lightButtonPrev = checkButton(lightButton,lightButtonPrev);
  metalButtonPrev = checkButton(metalButton,metalButtonPrev);
  tempButtonPrev = checkButton(tempButton,tempButtonPrev);
  
  //water sensor........................................................................................
  waterSensorValueRaw = analogRead(waterSensorPin);
  if(waterSensorValueRaw > waterSensorMax){
    waterSensorMax = waterSensorValueRaw;
  }
  waterSensorValue = map(waterSensorValueRaw,0,waterSensorMax,1,255);

  //light sensor ........................................................................................
  lightSensorValueRaw = analogRead(lightSensorPin) - lightSensorValueBase;
  if(lightSensorValueRaw > lightSensorMax){
    lightSensorMax = lightSensorValueRaw;
  }
  if(lightSensorValueRaw < lightSensorMin){
    lightSensorMin = lightSensorValueRaw;
  }
  lightSensorValue = map(lightSensorValueRaw, lightSensorMin, lightSensorMax, 1, 255);

  //metal sensor ........................................................................................
  metalSensorValueRaw = digitalRead(metalSensorPin);
  metalSensorValue = map(metalSensorValueRaw,0,1,1,255);

  //temp sensor ........................................................................................
  //done in setupan on button press bc it slow
}

int checkButton(int button, int prev){
  int val = digitalRead(button);
  if(prev == 0 && val == 1){
    switch(button){
      
      case waterButton:
        waterButtonPressed();
      break;
      
      case lightButton:
        lightButtonPressed();
      break;

      case metalButton:
        metalButtonPressed();
       break;

       case tempButton:
        tempButtonPressed();
       break;
    } //end switch
  } //endif
  return val;
} //end check

void lightButtonPressed(){
  Serial.print('a');
  Serial.println(lightSensorValue);
}

void waterButtonPressed(){
  Serial.print('b');
  Serial.println(waterSensorValue);
}

void metalButtonPressed(){
  Serial.print('c');
  Serial.println(metalSensorValue);
}
void tempButtonPressed(){
  sensors.requestTemperatures();
  tempSensorValueRaw = sensors.getTempCByIndex(0);
  tempSensorValue = tempSensorValueRaw + 175;
  Serial.print('d');
  Serial.println(tempSensorValue);
}

This is a divider between arduino (above) and processing (below)

import processing.sound.*;
import processing.serial.*;
Serial arduinoPort;

String sensor;

int waterValue = 0;
int tempValue = 70;
int metalValue = 0;
int lightValue = 0;

boolean water = false;
boolean temp = false;
boolean light = false;
boolean metal = false;
//start sound stuff
TriOsc triOsc;
Env env; 

// envelope data
float attackTime = 0.001;
float sustainTime = 0.004;
float sustainLevel = 0.2;
float releaseTime = 0.2;

//midi octave thing
int[] midiSequence = { 
  60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72
}; 

// Set the duration between the notes
int duration = 200;
// Set the note trigger
int trigger = 0; 

// An index to count up the notes
int note = 0; 

void setup(){
  String portName = Serial.list()[1];
  arduinoPort = new Serial(this, portName, 9600);
  //start sound stuff
  size(640, 360);
  background(255);

  // Create triangle wave and envelope 
  triOsc = new TriOsc(this);
  env  = new Env(this);
  
}

void draw(){
  try{
    if(arduinoPort.available() > 0){
       sensor = arduinoPort.readStringUntil('\n');
       char sensorChar = sensor.charAt(0);
       String val = sensor.substring(1,sensor.length()-1).trim();
       //println(val);
       switch(sensorChar){
         case 'a':     
         println("Light");
         lightValue = int(val);
         light = true;
         //use said value
         regenMidiScale(lightValue);
         break;
         case 'b':
         println("Water");
         waterValue = int(val);
         water = true;
         break;
         case 'c':
         println("Metal");
         metalValue = int(val);
         metal = true;
         break;
         case 'd':
         println("Temp");
         tempValue = int(val);
         temp = true;
         break;
         case 'q':
         println("Initialized");
         break;
       }
    }
  } catch(NullPointerException e){
     refreshEnvelope();
  }
    if(water && temp && metal && light){
     resetEnvelope(); 
    }
    //start sound stuff
  if ((millis() > trigger) && (note<midiSequence.length)) {
    triOsc.play(midiToFreq(midiSequence[note]), 0.8);
    env.play(triOsc, attackTime, sustainTime, sustainLevel, releaseTime);
    
    //use temp sensor
    duration = int(map(tempValue,78,62,50,350));
    trigger = millis() + duration;

    incrementScale(metalValue);
  }
} //end draw

float midiToFreq(int note) {
  return (pow(2, ((note-69)/12.0)))*440;
}

//used by the light sensor
void regenMidiScale(int scale){
  scale = int(map(scale,1,255,1,7));
  int base = 45;
  for(int i = 0;i<12;i++){
   midiSequence[i] = (base + i * scale); 
  }
}

//pass in metal sensor val <125 down >125 up
void incrementScale(int val){
  // Advance by one note in the midiSequence;
    if(val < 125){note--; }
    if(val>= 125){note++;}

    // Loop the sequence
    if (note == 12) {
      note = 0;
    }
    if (note == -1){
     note = 11; 
    }
}

void refreshEnvelope(){  
  attackTime = map(waterValue,1,255,0,0.004);//0.001;
  sustainTime =  map(tempValue,1,255,0,0.007);//0.004;
  sustainLevel =  map(waterValue,1,255,0,0.3);//0.2;
  releaseTime =  map(lightValue,1,255,0,0.3);//0.2; 
}

void resetEnvelope(){
   attackTime = 0.001;
   sustainTime = 0.004;
   sustainLevel = 0.2;
   releaseTime = 0.2;
   water = false;
   temp = false;
   light = false;
   metal = false;
}

Comments