The Triangle shirtwaist company fire

Historical Context
I learned about the Triangle shirtwaist company fire watching the great New York Documentary series by Ric Burns. The tragedy took place on March 25th 1911, in the eighth, ninth, and tenth floors of a building, located on Washington Place, that belongs today to the New York University Campus.

Around 4:40PM, a fire flared up and, as a common practice at the time was to lock the doors to prevent the workers to go away, most of the women got stuck in the building and could not escape the flames. 146 of them died from the fire, smoke inhalation, or falling or jumping to their deaths.

This event occurred after an intensive period of protests organized by women workers and unions of various factories of the city. During the months prior to the deadly fire, workers had taken the streets in an attempt to convince the owners that the working conditions were dangerous and unsanitary. The protest were in vain and the cold winter weather forced the women to go back to work without seeing any improvement of their working conditions. And then, the deadly fire happened. The sad event arose the politicians consciousness and a commission, presided by Al Smith, was set up to analyse the working conditions of the factory workers. The outcomes of the commission led to the first involvements of an american public administration in regulating the private sector. The politicians learned from the Triangle shirtwaist fire marked the start of the modern labor movement  and led the politicians to a new governing approach that inspired the New Deal.

The Pop-up Book Project
The Triangle building is located a block from the ITP NYU building. Almost everyday on my way to school, I pass by the building, since I learned about this fire, I can not help but imagining the scene. Every time it feels like my mind is taken by glitches of images and sounds from the event. I imagine the fire flames, the powerless firemen, the onlookers, the horses, the water, the screams of the women. The sound of their bodies landing on the sidewalks.

This spontaneous jump into the past has made me realized how we take for granted what we see. The past is easily erased. My pop-up book project is an attempt to share my feelings and relationship to the fire

I will a mix of archive images and contemporary ones. The content will first be show in the contemporary period, telling the story of a dreamy girl walking in the neighborhood. Then, all the pop-up content will be revealing archival material showing and explaining aspects of the fire. The story of the book will be constructed this way:

Page 1:

  • a girl is walking on the sidewalk facing the building as it is today;
  • the pop-up options will open a door to the past (pop-up windows at the top of the building showing flames, pop-up side-walk/street revealing a firetruck, a window slider showing scared women, pop-up street showing people watching the fire).
Page 2:
  • from the inside of the building, showing staircases and sewing machines.
  • and the girl going up the stairs
Page 3:
  • To be determined.
I want to make this book to share the story and find out what is the best storytelling option to combine various time periods in the same piece.
Also, what triggered my interest to this sad event was another one that occured the same month, 100 years after the Triangle fire. On November 24th 2012, 112 factory workers were killed in the Tazreen Fashions Factory fire. Same as in 1911, the workers were locked in the factory and could not escape the flames. Since 2006, more than 500 Bangladeshi workers have died in factory fires.

Interior Weather – Coding a Twitter Switch using Processing and Arduino

Here is the code to connect Processing to the Twitter Live Stream and have Processing sending Serial to an Arduino:
/// TWITTER //////////////////////////////////////////////////////////////////////////////////////

////// ALONE – Connecting to the Twitter API
static String OAuthConsumerKeyA = “NDgkkBotZeXcoAPMOsemA”;
static String OAuthConsumerSecretA = “XusVVwearPNjGwhYpYkgnlAM4WRSwu2EnGVHjQdSaOw”;
static String AccessTokenA = “102763568-uuNmUvzeOBFNyDaX1GA1XyW5TTiUekQKhLRYjuhV”;
static String AccessTokenSecretA = “TUpkVOftKcLAjsFVnzkjJV9bB30bRSbixgOF983appk”;

////// SAD – Connecting to the Twitter API
static String OAuthConsumerKeyB = “Z1PMOJj7f3jP0LCvl32ng”;
static String OAuthConsumerSecretB = “WRehjiit2gEk1TOb2kDvKbG8Wdwg2Qg0IoDYCZof7ek”;
static String AccessTokenB = “981269682-0kVLQO6tmaZKC8UOm49spp4K1u3e9q4vptKMcPMw”;
static String AccessTokenSecretB = “d1VLGSeKALv2dz61xx9eLdhpCqTZGuCDE1ms311w”;

////// ANGRY – Connecting to the Twitter API
static String OAuthConsumerKeyC = “”;
static String OAuthConsumerSecretC = “”;
static String AccessTokenC = “”;
static String AccessTokenSecretC = “”;

////// AFRAID – Connecting to the Twitter API
static String OAuthConsumerKeyD = “”;
static String OAuthConsumerSecretD = “”;
static String AccessTokenD = “”;
static String AccessTokenSecretD = “”;

////// Declaring the Twitter Factories
TwitterStream twitterA = new TwitterStreamFactory().getInstance();
TwitterStream twitterB = new TwitterStreamFactory().getInstance();
TwitterStream twitterC = new TwitterStreamFactory().getInstance();
TwitterStream twitterD = new TwitterStreamFactory().getInstance();

////// Find I FEEL ALONE in the live Twitter live stream
String keywordsA[] = { “I feel alone”};
String alone = “”;
ArrayList allTweetsAlone = new ArrayList();
boolean aloneOn;

////// Find I AM SAD in the live Twitter live stream
String keywordsB[] = {“I am sad”};
String sad = “”;
ArrayList allTweetsSad = new ArrayList();
boolean sadOn;

////// Find I AM ANGRY in the live Twitter live stream
String keywordsC[] = {“I am angry”};
String angry = “”;
ArrayList allTweetsAngry = new ArrayList();
boolean angryOn;

////// Find I AM HAPPY in the live Twitter live stream
String keywordsD[] = {“I am afraid of”};
String afraid = “”;
ArrayList allTweetsAfraid = new ArrayList();
boolean afraidOn;

/// ARDUINO //////////////////////////////////////////////////////////////////////////////////////

////// Declaring for the Serial communication
import processing.serial.*;
Serial port;

/// MINIM ////////////////////////////////////////////////////////////////////////////////////////
import ddf.minim.*;

Minim minim;
AudioPlayer[] track = new AudioPlayer [9];

/// SETUP ////////////////////////////////////////////////////////////////////////////////////////

void setup () {

size(500, 500);

///// Communicating with Twitter
connectTwitter();
twitterA.addListener(listenerA);
twitterA.filter(new FilterQuery().track(keywordsA));

twitterB.addListener(listenerB);
twitterB.filter(new FilterQuery().track(keywordsB));

twitterC.addListener(listenerC);
twitterC.filter(new FilterQuery().track(keywordsC));

twitterD.addListener(listenerD);
twitterD.filter(new FilterQuery().track(keywordsD));

////// Serial Communicatione
println(Serial.list());
port = new Serial(this, Serial.list()[8], 115200);
println(Serial.list());

////// MINIM
minim = new Minim(this);

for (int i = 0; i < track.length; i++) {
track [i] = minim.loadFile( i + “.mp3″);
}
}

/// DRAW /////////////////////////////////////////////////////////////////////////////////////////

void draw () {
background(0);

// ALONE // H
if (aloneOn == true) {
ellipse (width/2, height/2, 30, 30);
port.write(‘H’);
if (track[7].position() > track[7].length()-1000) {
aloneOn = false;
track[7].rewind();
}
else if (track[7].isPlaying() ==false) {
track[7].play();
port.write(‘H’);
}
}

// SAD // L
if (sadOn == true) {
ellipse (30, 250, 30, 30);
port.write(‘L’);
if (track[6].position() > track[6].length()-1000) {
sadOn = false;
track[6].rewind();
}
else if (track[6].isPlaying() ==false) {
track[6].play();
port.write(‘L’);
}
}

// ANGRY // M
if (angryOn == true) {
ellipse (250, 30, 30, 30);
port.write(‘M’);
if (track[1].position() > track[1].length()-1000) {
angryOn = false;
track[1].rewind();
}
else if (track[1].isPlaying() ==false) {
track[1].play();
port.write(‘M’);
}
}

// AFRAID // N
if (afraidOn == true) {
ellipse (420, 250, 30, 30);
port.write(‘N’);
if (track[8].position() > track[8].length()-500) {
afraidOn = false;
track[8].rewind();
}
else if (track[8].isPlaying() ==false) {
track[8].play();
port.write(‘N’);
}
}

if(aloneOn == false && sadOn == false && angryOn == false && afraidOn == false) {
track[5].play();
if(track[5].position() > track[5].length()-500) {
track[5].rewind();
}
}

}
////////////////////////////////////////////////////////////////////////////////////////////////////

void stop () {
track[9].close();
minim.stop();

///////// This listens for new tweet with ALONE ///////////////////////////////////////////////////
StatusListener listenerA = new StatusListener() {
public void onStatus(Status status) {

alone = status.getText();
allTweetsAlone.add(alone);

for (int i = 0; i < allTweetsAlone.size(); i++) {
String thisTweet = (String) allTweetsAlone.get(i);
println (“stringAlone: ” + thisTweet);
}
aloneOn = true;
println (“stringAlonesize: ” + allTweetsAlone.size());
};
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
System.out.println(“Got a status deletion notice id:” + statusDeletionNotice.getStatusId());
}
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
System.out.println(“Got track limitation notice:” + numberOfLimitedStatuses);
}
public void onScrubGeo(long userId, long upToStatusId) {
System.out.println(“Got scrub_geo event userId:” + userId + ” upToStatusId:” + upToStatusId);
}

public void onException(Exception ex) {
ex.printStackTrace();
}
};

 

///////// This listens for new tweet with SAD ///////////////////////////////////////////////////
StatusListener listenerB = new StatusListener() {
public void onStatus(Status status) {

sad = status.getText();
allTweetsSad.add(sad);

for (int i = 0; i < allTweetsSad.size(); i++) {
String thisTweet = (String) allTweetsSad.get(i);
println (“stringSAD: ” + thisTweet);
}
sadOn = true;
println (“stringSADsize: ” + allTweetsSad.size());
};
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
System.out.println(“Got a status deletion notice id:” + statusDeletionNotice.getStatusId());
}
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
System.out.println(“Got track limitation notice:” + numberOfLimitedStatuses);
}
public void onScrubGeo(long userId, long upToStatusId) {
System.out.println(“Got scrub_geo event userId:” + userId + ” upToStatusId:” + upToStatusId);
}

public void onException(Exception ex) {
ex.printStackTrace();
}
};

 

///////// This listens for new tweet with SAD ///////////////////////////////////////////////////
StatusListener listenerC = new StatusListener() {
public void onStatus(Status status) {

angry = status.getText();
allTweetsAngry.add(angry);

for (int i = 0; i < allTweetsAngry.size(); i++) {
String thisTweet = (String) allTweetsAngry.get(i);
println (“stringANGRY: ” + thisTweet);
}
angryOn = true;
println (“stringANGRYsize: ” + allTweetsAngry.size());
};
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
System.out.println(“Got a status deletion notice id:” + statusDeletionNotice.getStatusId());
}
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
System.out.println(“Got track limitation notice:” + numberOfLimitedStatuses);
}
public void onScrubGeo(long userId, long upToStatusId) {
System.out.println(“Got scrub_geo event userId:” + userId + ” upToStatusId:” + upToStatusId);
}

public void onException(Exception ex) {
ex.printStackTrace();
}
};

 

///////// This listens for new tweet with HAPPY ///////////////////////////////////////////////////
StatusListener listenerD = new StatusListener() {
public void onStatus(Status status) {

afraid = status.getText();
allTweetsAfraid.add(afraid);

for (int i = 0; i < allTweetsAfraid.size(); i++) {
String thisTweet = (String) allTweetsAfraid.get(i);
println (“stringAfraid: ” + thisTweet);
}
afraidOn = true;
println (“stringAfraidsize: ” + allTweetsAfraid.size());
};
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
System.out.println(“Got a status deletion notice id:” + statusDeletionNotice.getStatusId());
}
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
System.out.println(“Got track limitation notice:” + numberOfLimitedStatuses);
}
public void onScrubGeo(long userId, long upToStatusId) {
System.out.println(“Got scrub_geo event userId:” + userId + ” upToStatusId:” + upToStatusId);
}

public void onException(Exception ex) {
ex.printStackTrace();
}
};

 

////// Initial connection
void connectTwitter() {

// Connection for ALONE
twitterA.setOAuthConsumer(OAuthConsumerKeyA, OAuthConsumerSecretA);
AccessToken accessTokenA = loadAccessTokenA();
twitterA.setOAuthAccessToken(accessTokenA);

// Connection for SAD
twitterB.setOAuthConsumer(OAuthConsumerKeyB, OAuthConsumerSecretB);
AccessToken accessTokenB = loadAccessTokenB();
twitterB.setOAuthAccessToken(accessTokenB);

// Connection for ANGRY
twitterC.setOAuthConsumer(OAuthConsumerKeyC, OAuthConsumerSecretC);
AccessToken accessTokenC = loadAccessTokenC();
twitterC.setOAuthAccessToken(accessTokenC);

// Connection for Happy
twitterD.setOAuthConsumer(OAuthConsumerKeyD, OAuthConsumerSecretD);
AccessToken accessTokenD = loadAccessTokenD();
twitterD.setOAuthAccessToken(accessTokenD);

}

/////// Loading up the access token

// Access token for ALONE
private static AccessToken loadAccessTokenA() {
return new AccessToken(AccessTokenA, AccessTokenSecretA);
}
// Access token for Sad
private static AccessToken loadAccessTokenB() {
return new AccessToken(AccessTokenB, AccessTokenSecretB);
}
// Access token for ANGRY
private static AccessToken loadAccessTokenC() {
return new AccessToken(AccessTokenC, AccessTokenSecretC);
}
// Access token for HAPPY
private static AccessToken loadAccessTokenD() {
return new AccessToken(AccessTokenD, AccessTokenSecretD);
}

Here is the code to have the Arduino receiving the serial communication from Processing and activating the devices:

 
//MotorA
const int enablePin = 7;
const int motor1Pin = 6;
const int motor2Pin = 5;
//MotorB
const int enableBPin = 4;
const int motorB1Pin = 3;
const int motorB2Pin = 2;

const int ledPinA = 8;
const int ledPinB = 9;
const int ledPinC = 10;
const int ledPinD = 11;
const int ledPinF = 12;

int incomingByte;

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

pinMode(motor1Pin, OUTPUT);
pinMode(motor2Pin, OUTPUT);
pinMode(enablePin, OUTPUT);

pinMode(enableBPin, OUTPUT);
pinMode(motorB1Pin,OUTPUT);
pinMode(motorB2Pin, OUTPUT);

pinMode(ledPinA, OUTPUT);
pinMode(ledPinB, OUTPUT);
pinMode(ledPinC, OUTPUT);
pinMode(ledPinD, OUTPUT);
pinMode(ledPinF, OUTPUT);

//digitalWrite(enablePin,HIGH);
//digitalWrite(enableBPin,HIGH);

}
void loop(){
if (Serial.available() > 0) {
incomingByte = Serial.read();

if (incomingByte == ‘H’) {
digitalWrite(enablePin,HIGH);
digitalWrite(motor1Pin, HIGH);
digitalWrite(motor2Pin, LOW);

digitalWrite(enableBPin,HIGH);
digitalWrite(motorB1Pin, HIGH);
digitalWrite(motorB2Pin, LOW);

digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinF, LOW);

Serial.println(“ALONE”);
}
if (incomingByte == ‘L’) {
digitalWrite(enablePin,LOW);
digitalWrite(motor1Pin, LOW);
digitalWrite(motor2Pin, LOW);

digitalWrite(enableBPin,LOW);
digitalWrite(motorB1Pin, LOW);
digitalWrite(motorB2Pin, LOW);

digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinF, LOW);

Serial.println(“SAD”);
}
if (incomingByte == ‘M’) {
digitalWrite(enablePin,LOW);
digitalWrite(motor1Pin, LOW);
digitalWrite(motor2Pin, LOW);

digitalWrite(enableBPin,LOW);
digitalWrite(motorB1Pin, LOW);
digitalWrite(motorB2Pin, LOW);

digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinF, LOW);

Serial.println(“ANGRY”);
}
if (incomingByte == ‘N’) {
digitalWrite(enablePin,LOW);
digitalWrite(motor1Pin, LOW);
digitalWrite(motor2Pin, LOW);

digitalWrite(enableBPin,LOW);
digitalWrite(motorB1Pin, LOW);
digitalWrite(motorB2Pin, LOW);

digitalWrite(ledPinA, HIGH);
digitalWrite(ledPinB, HIGH);
digitalWrite(ledPinC, HIGH);
digitalWrite(ledPinD, HIGH);
digitalWrite(ledPinF, HIGH);

Serial.println(“AFRAID”);
}
}

}

 

 

 

 

 

 

The Universe Experiencing Itself

We wanted to make an experimental film that would explore extremes: normal/abnormal, alone/not alone. Most of us moved to New York City especially to study at ITP. For the first weeks here, we all felt that even if we were always surrounded by people anywhere and anytime, we also felt loneliness. In a City like New York, you quickly feel like you have no past and no future. As soon as you move here, you feel like you belong to the City. There is so much diversity, you could become or be whoever you wanted to be.

There is diversity in the city but it still feel “normal”. Everybody walking, working, in the streets and the subway. Crowds. Crowds of people. Of people alone. What is it that they have in mind? Was is it that trouble them?

This short film is an attempt to explore the weird site everybody carries but never show. Like in this great novel I have been reading: “Remainder” by Tom McCarthy. e all carry an abnormal self. What if we would start sharing it? What would happen?

This video was made for the Comm Lab Video and sound taught by Marianne Petit.

Interior Weather

Interior Weather is a helmet that makes you experience and feel a storm triggered by emotions shared on Twitter.

Concept
Twitter, as the other social networks, has changed how we conceive collective trust and how the strategies to position oneself within the social spectrum. It generates an individualization of professional credibility and collective exchanges. It explodes waht was concentrated under the umbrellas of organizations, governments, institutions into unique and independent particules. Every person can build his own reputation, credibility and image without belonging to a group, a business of a media.

This triggers the phenomenon of intensive self promotion. Tweets and statuses focuses on positive and optimistic content shared by the person herself. Enough so that the narcissism personality disorder has recently been withdrawn from the official psychiatry manuels. It is no longer socially awkward to talk about ourselves all the time. Pretension is no longer perceived as a lack of social skills, but has become an asset. Be yourself please, and be the best.

The thing is at the same time we collectively accept self-promotion as a normal behavior, the rate of depression and other mental disorder keeps increasing. Cat walk yourself on Twitter, but keep your dark feelings in the darkness of your mind. It has always been that way. But what has changed, is that in addition to be the one who have to deal with your own personality, you now have to be the one to promote it, no matter how you feel. What you can and how you show it is what you are worth.

How it works
Interior Weather attempts to show how compartmentalized our lives can be on the social networks by putting the dark feelings we would like to ignore forward.

It uses the Twitter API to connect Processing to 4 different live stream. Each of those live stream trigger an physical assets that translate the emotion into a weather aspect in the helmet.

“I feel alone” tweets trigger a wind sound and a fan;
“I am sad” tweets trigger sound of rain;
“I am angry” tweets trigger thunder sounds;
“I am afraid of” tweets trigger broken glass sounds and an intensive strobe light.

Connecting Twitter to Processing
I used the Twitter 4j library to connect Processing to the Twitter API. To do so, you first need to create yourself a developer account. Once you have it, you create an Twitter “app” that works with the oauth system to secure communication between services and clients.

When you create your “app”, Twitter gives you the following:

OAuth Consumer Key;
OAuth Consumer Secret;
Access Token;
Access Token Secret;

and those:

OAuth Consumer Key;
OAuth Consumer Secret;
Access Token;
Access Token Secret.

You need them to create the handshake between Processing and the Twitter API. Then, you need to create a “Twitter Stream Factory” and a Listener. They goe on and get the tweets from the stream and wait to see how you will se them. To clarify your use of the stream, you have to create queries. You could look for tweets coming from a specific username, datas, etc. It is recommended to have only one query by Twitter Factory.

This means that for Interior Weather, I had to build 4 different Twitter Factories (meaning 4 developer accounts, 4 times the oauth keys details and 4 times the access token details) to have 4 different queries live.

Triggering Storm Sounds
I needed to find way to have Processing triggering sounds for every different tweet query. I started by using the OscP5 Library. It allows Processing to send and receive MIDI message to and from another software. I connected Processing to Ableton Live.

Every time there was a tweet coming from a query, Processing was sending an osc message to Ableton and an .mp3 clip was triggered. There were limitations when it was time to play more then one .mp3 at the same time. I did not find a way to send Processing message from Ableton when the track was done or when the track was already playing. This means that every tweet would play the song from the start causing cuts and bugs. Per example, if there were more than one tweet about anger within 5 seconds, the track would start 5 times instead of playing till the end before it being triggered by another tweet. After 2 days of trying, I discovered I could do it in a better and simpler way using the Minim Library.

The Minim Library is pretty simple. You do not need to connect Processing to an external sound software to play tracks, it transform Processing into a audio player itself. Which is exactly what I needed as I was using .mp3 and was not doing anything live involving visuals effects.

The code is pretty simple. You load the .mp3 in an array the same way you would do for pictures:

import ddf.minim.*;

Minim minim;
AudioPlayer[] track = new AudioPlayer [9];

minim = new Minim(this);

for (int i = 0; i < track.length; i++) {
track [i] = minim.loadFile( i + “.mp3″);
}

Then, when you want to play the tracks you use the .play(); function. Click here is the list of the Minim functions of the AudioPlayer. What is tricky with Minim is that each time Processing plays an .mp3, it expects to play it from where it played last time. You have to .rewind(); the track in the loop so it start from the beginning the next time. My tracks are very short and will be triggered a lot of time in draw, depending on the incoming tweets. So I had to come up with a solution so Processing would know:

  • when a track has to be triggered;
  • when a track is already playing
  • when it has to go back to the beginning of the track.
I achieved so by using the .length(); and .isPlaying(); and .position(); functions:

if (aloneOn == true) {
ellipse (width/2, height/2, 30, 30);
port.write(‘H’);
if (track[7].position() > track[7].length()-1000) {
aloneOn = false;
track[7].rewind();
}
else if (track[7].isPlaying() ==false) {
track[7].play();
}
}

The Physical Interface
The idea with this project was to create an object:

  • you would have to put on your head, as to being forced to assume and experience those negative ideas we make so much effort to push away and deny;
  • that would be intimate, that would make you feel that the storm created by the tweets was yours, as if it would be happening in your own head;
The ideal would have been to create an helmet, that would be tight and that would make you feel in your own space, the same as putting a motorbike helmet. But for several reasons, this was not possible.
The key work: Prototyping
The best thing I learned during this class, is the idea of prototyping. It took me a long time to accept:

  • my lacks of certain skills: 3D design, structure design, etc.;
  • the time I could allow to the project was limited, that I would never have the time to build the perfect object, as there were so many things to learn to do so;
  • that my budget was limited. I had to come to terms with the idea that I would have to compromise a lot. I cannot afford to invest a lot of money in all my project. so I needed to accept they would look unfinished. This project is not a project, it is a prototype of a project.
For all those reason, I decided to let it go. To stop forcing me into the perfection path, as it would lead towards disappointment. I needed to accept the process was more important that the project itself.
The Challenges
The code in itself is not that complicated. (Well, it is not complicated when I look at it now but t was pretty hard to come up with it). The Arduino code is pretty simple as I do not have any inputs to monitor.
One of the most challenging things was to deal with a live stream of data. How do you build a coherent experience without knowing what would come up from Twitter? How to build an experience that would be ready for every eventualities. I still have a lot of work to do regarding the sounds. The .mp3 are of 15 seconds. I might have to change the length so it works better.
Another challenge was the delays. There is a short delay in between Twitter and Processing. It takes half a second for Processing to trigger the .mp3 when a tweet is received. There is also a delay in between Processing and Arduino. It takes a little time for Arduino to receive the byte and read it. There is also a delay for the DC motors to start. This means that the motors do not start exactly at the same time as the .mp3 they are supposed to be aligned with.

The biggest challenge was to build the object itself. For the reasons mentioned above, I did not managed to create was I wanted in first place. I decided to build something bigger than a helmet. Something that would look like a cloud. This meant that :
  • it would have to be hung up somewhere, that it would not fit every body, as it was too complicated to deal with the height at this point;
  • it would not be sound proof. That you would heard the sounds from the room while experiencing the storm;
  • I did not have budget to by more LEDs and more fans. So the experience is limited.
The limitations led me to do stuff I had not envisioned. I learned how to soder with galvanized wire, I spent a lot of time trying to build the object in Rhino. So I discovered the software.

Here is the code to connect Processing to the Twitter Live Stream and have Processing sending Serial to an Arduino:

/// TWITTER //////////////////////////////////////////////////////////////////////////////////////

////// ALONE – Connecting to the Twitter API
static String OAuthConsumerKeyA = “NDgkkBotZeXcoAPMOsemA”;
static String OAuthConsumerSecretA = “XusVVwearPNjGwhYpYkgnlAM4WRSwu2EnGVHjQdSaOw”;
static String AccessTokenA = “102763568-uuNmUvzeOBFNyDaX1GA1XyW5TTiUekQKhLRYjuhV”;
static String AccessTokenSecretA = “TUpkVOftKcLAjsFVnzkjJV9bB30bRSbixgOF983appk”;

////// SAD – Connecting to the Twitter API
static String OAuthConsumerKeyB = “Z1PMOJj7f3jP0LCvl32ng”;
static String OAuthConsumerSecretB = “WRehjiit2gEk1TOb2kDvKbG8Wdwg2Qg0IoDYCZof7ek”;
static String AccessTokenB = “981269682-0kVLQO6tmaZKC8UOm49spp4K1u3e9q4vptKMcPMw”;
static String AccessTokenSecretB = “d1VLGSeKALv2dz61xx9eLdhpCqTZGuCDE1ms311w”;

////// ANGRY – Connecting to the Twitter API
static String OAuthConsumerKeyC = “”;
static String OAuthConsumerSecretC = “”;
static String AccessTokenC = “”;
static String AccessTokenSecretC = “”;

////// AFRAID – Connecting to the Twitter API
static String OAuthConsumerKeyD = “”;
static String OAuthConsumerSecretD = “”;
static String AccessTokenD = “”;
static String AccessTokenSecretD = “”;

////// Declaring the Twitter Factories
TwitterStream twitterA = new TwitterStreamFactory().getInstance();
TwitterStream twitterB = new TwitterStreamFactory().getInstance();
TwitterStream twitterC = new TwitterStreamFactory().getInstance();
TwitterStream twitterD = new TwitterStreamFactory().getInstance();

////// Find I FEEL ALONE in the live Twitter live stream
String keywordsA[] = { “I feel alone”};
String alone = “”;
ArrayList allTweetsAlone = new ArrayList();
boolean aloneOn;

////// Find I AM SAD in the live Twitter live stream
String keywordsB[] = {“I am sad”};
String sad = “”;
ArrayList allTweetsSad = new ArrayList();
boolean sadOn;

////// Find I AM ANGRY in the live Twitter live stream
String keywordsC[] = {“I am angry”};
String angry = “”;
ArrayList allTweetsAngry = new ArrayList();
boolean angryOn;

////// Find I AM HAPPY in the live Twitter live stream
String keywordsD[] = {“I am afraid of”};
String afraid = “”;
ArrayList allTweetsAfraid = new ArrayList();
boolean afraidOn;

/// ARDUINO //////////////////////////////////////////////////////////////////////////////////////

////// Declaring for the Serial communication
import processing.serial.*;
Serial port;

/// MINIM ////////////////////////////////////////////////////////////////////////////////////////
import ddf.minim.*;

Minim minim;
AudioPlayer[] track = new AudioPlayer [9];

/// SETUP ////////////////////////////////////////////////////////////////////////////////////////

void setup () {

size(500, 500);

///// Communicating with Twitter
connectTwitter();
twitterA.addListener(listenerA);
twitterA.filter(new FilterQuery().track(keywordsA));

twitterB.addListener(listenerB);
twitterB.filter(new FilterQuery().track(keywordsB));

twitterC.addListener(listenerC);
twitterC.filter(new FilterQuery().track(keywordsC));

twitterD.addListener(listenerD);
twitterD.filter(new FilterQuery().track(keywordsD));

////// Serial Communicatione
println(Serial.list());
port = new Serial(this, Serial.list()[8], 115200);
println(Serial.list());

////// MINIM
minim = new Minim(this);

for (int i = 0; i < track.length; i++) {
track [i] = minim.loadFile( i + “.mp3″);
}
}

/// DRAW /////////////////////////////////////////////////////////////////////////////////////////

void draw () {
background(0);

// ALONE // H
if (aloneOn == true) {
ellipse (width/2, height/2, 30, 30);
port.write(‘H’);
if (track[7].position() > track[7].length()-1000) {
aloneOn = false;
track[7].rewind();
}
else if (track[7].isPlaying() ==false) {
track[7].play();
port.write(‘H’);
}
}

// SAD // L
if (sadOn == true) {
ellipse (30, 250, 30, 30);
port.write(‘L’);
if (track[6].position() > track[6].length()-1000) {
sadOn = false;
track[6].rewind();
}
else if (track[6].isPlaying() ==false) {
track[6].play();
port.write(‘L’);
}
}

// ANGRY // M
if (angryOn == true) {
ellipse (250, 30, 30, 30);
port.write(‘M’);
if (track[1].position() > track[1].length()-1000) {
angryOn = false;
track[1].rewind();
}
else if (track[1].isPlaying() ==false) {
track[1].play();
port.write(‘M’);
}
}

// AFRAID // N
if (afraidOn == true) {
ellipse (420, 250, 30, 30);
port.write(‘N’);
if (track[8].position() > track[8].length()-500) {
afraidOn = false;
track[8].rewind();
}
else if (track[8].isPlaying() ==false) {
track[8].play();
port.write(‘N’);
}
}

if(aloneOn == false && sadOn == false && angryOn == false && afraidOn == false) {
track[5].play();
if(track[5].position() > track[5].length()-500) {
track[5].rewind();
}
}

}
////////////////////////////////////////////////////////////////////////////////////////////////////

void stop () {
track[9].close();
minim.stop();

///////// This listens for new tweet with ALONE ///////////////////////////////////////////////////
StatusListener listenerA = new StatusListener() {
public void onStatus(Status status) {

alone = status.getText();
allTweetsAlone.add(alone);

for (int i = 0; i < allTweetsAlone.size(); i++) {
String thisTweet = (String) allTweetsAlone.get(i);
println (“stringAlone: ” + thisTweet);
}
aloneOn = true;
println (“stringAlonesize: ” + allTweetsAlone.size());
};
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
System.out.println(“Got a status deletion notice id:” + statusDeletionNotice.getStatusId());
}
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
System.out.println(“Got track limitation notice:” + numberOfLimitedStatuses);
}
public void onScrubGeo(long userId, long upToStatusId) {
System.out.println(“Got scrub_geo event userId:” + userId + ” upToStatusId:” + upToStatusId);
}

public void onException(Exception ex) {
ex.printStackTrace();
}
};

 

///////// This listens for new tweet with SAD ///////////////////////////////////////////////////
StatusListener listenerB = new StatusListener() {
public void onStatus(Status status) {

sad = status.getText();
allTweetsSad.add(sad);

for (int i = 0; i < allTweetsSad.size(); i++) {
String thisTweet = (String) allTweetsSad.get(i);
println (“stringSAD: ” + thisTweet);
}
sadOn = true;
println (“stringSADsize: ” + allTweetsSad.size());
};
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
System.out.println(“Got a status deletion notice id:” + statusDeletionNotice.getStatusId());
}
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
System.out.println(“Got track limitation notice:” + numberOfLimitedStatuses);
}
public void onScrubGeo(long userId, long upToStatusId) {
System.out.println(“Got scrub_geo event userId:” + userId + ” upToStatusId:” + upToStatusId);
}

public void onException(Exception ex) {
ex.printStackTrace();
}
};

 

///////// This listens for new tweet with SAD ///////////////////////////////////////////////////
StatusListener listenerC = new StatusListener() {
public void onStatus(Status status) {

angry = status.getText();
allTweetsAngry.add(angry);

for (int i = 0; i < allTweetsAngry.size(); i++) {
String thisTweet = (String) allTweetsAngry.get(i);
println (“stringANGRY: ” + thisTweet);
}
angryOn = true;
println (“stringANGRYsize: ” + allTweetsAngry.size());
};
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
System.out.println(“Got a status deletion notice id:” + statusDeletionNotice.getStatusId());
}
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
System.out.println(“Got track limitation notice:” + numberOfLimitedStatuses);
}
public void onScrubGeo(long userId, long upToStatusId) {
System.out.println(“Got scrub_geo event userId:” + userId + ” upToStatusId:” + upToStatusId);
}

public void onException(Exception ex) {
ex.printStackTrace();
}
};

 

///////// This listens for new tweet with HAPPY ///////////////////////////////////////////////////
StatusListener listenerD = new StatusListener() {
public void onStatus(Status status) {

afraid = status.getText();
allTweetsAfraid.add(afraid);

for (int i = 0; i < allTweetsAfraid.size(); i++) {
String thisTweet = (String) allTweetsAfraid.get(i);
println (“stringAfraid: ” + thisTweet);
}
afraidOn = true;
println (“stringAfraidsize: ” + allTweetsAfraid.size());
};
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {
System.out.println(“Got a status deletion notice id:” + statusDeletionNotice.getStatusId());
}
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {
System.out.println(“Got track limitation notice:” + numberOfLimitedStatuses);
}
public void onScrubGeo(long userId, long upToStatusId) {
System.out.println(“Got scrub_geo event userId:” + userId + ” upToStatusId:” + upToStatusId);
}

public void onException(Exception ex) {
ex.printStackTrace();
}
};

 

////// Initial connection
void connectTwitter() {

// Connection for ALONE
twitterA.setOAuthConsumer(OAuthConsumerKeyA, OAuthConsumerSecretA);
AccessToken accessTokenA = loadAccessTokenA();
twitterA.setOAuthAccessToken(accessTokenA);

// Connection for SAD
twitterB.setOAuthConsumer(OAuthConsumerKeyB, OAuthConsumerSecretB);
AccessToken accessTokenB = loadAccessTokenB();
twitterB.setOAuthAccessToken(accessTokenB);

// Connection for ANGRY
twitterC.setOAuthConsumer(OAuthConsumerKeyC, OAuthConsumerSecretC);
AccessToken accessTokenC = loadAccessTokenC();
twitterC.setOAuthAccessToken(accessTokenC);

// Connection for Happy
twitterD.setOAuthConsumer(OAuthConsumerKeyD, OAuthConsumerSecretD);
AccessToken accessTokenD = loadAccessTokenD();
twitterD.setOAuthAccessToken(accessTokenD);

}

/////// Loading up the access token

// Access token for ALONE
private static AccessToken loadAccessTokenA() {
return new AccessToken(AccessTokenA, AccessTokenSecretA);
}
// Access token for Sad
private static AccessToken loadAccessTokenB() {
return new AccessToken(AccessTokenB, AccessTokenSecretB);
}
// Access token for ANGRY
private static AccessToken loadAccessTokenC() {
return new AccessToken(AccessTokenC, AccessTokenSecretC);
}
// Access token for HAPPY
private static AccessToken loadAccessTokenD() {
return new AccessToken(AccessTokenD, AccessTokenSecretD);
}

Here is the code to have the Arduino receiving the serial communication from Processing and activating the devices:
//MotorA
const int enablePin = 7;
const int motor1Pin = 6;
const int motor2Pin = 5;
//MotorB
const int enableBPin = 4;
const int motorB1Pin = 3;
const int motorB2Pin = 2;

const int ledPinA = 8;
const int ledPinB = 9;
const int ledPinC = 10;
const int ledPinD = 11;
const int ledPinF = 12;

int incomingByte;

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

pinMode(motor1Pin, OUTPUT);
pinMode(motor2Pin, OUTPUT);
pinMode(enablePin, OUTPUT);

pinMode(enableBPin, OUTPUT);
pinMode(motorB1Pin,OUTPUT);
pinMode(motorB2Pin, OUTPUT);

pinMode(ledPinA, OUTPUT);
pinMode(ledPinB, OUTPUT);
pinMode(ledPinC, OUTPUT);
pinMode(ledPinD, OUTPUT);
pinMode(ledPinF, OUTPUT);

//digitalWrite(enablePin,HIGH);
//digitalWrite(enableBPin,HIGH);

}
void loop(){
if (Serial.available() > 0) {
incomingByte = Serial.read();

if (incomingByte == ‘H’) {
digitalWrite(enablePin,HIGH);
digitalWrite(motor1Pin, HIGH);
digitalWrite(motor2Pin, LOW);

digitalWrite(enableBPin,HIGH);
digitalWrite(motorB1Pin, HIGH);
digitalWrite(motorB2Pin, LOW);

digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinF, LOW);

Serial.println(“ALONE”);
}
if (incomingByte == ‘L’) {
digitalWrite(enablePin,LOW);
digitalWrite(motor1Pin, LOW);
digitalWrite(motor2Pin, LOW);

digitalWrite(enableBPin,LOW);
digitalWrite(motorB1Pin, LOW);
digitalWrite(motorB2Pin, LOW);

digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinF, LOW);

Serial.println(“SAD”);
}
if (incomingByte == ‘M’) {
digitalWrite(enablePin,LOW);
digitalWrite(motor1Pin, LOW);
digitalWrite(motor2Pin, LOW);

digitalWrite(enableBPin,LOW);
digitalWrite(motorB1Pin, LOW);
digitalWrite(motorB2Pin, LOW);

digitalWrite(ledPinA, LOW);
digitalWrite(ledPinB, LOW);
digitalWrite(ledPinC, LOW);
digitalWrite(ledPinD, LOW);
digitalWrite(ledPinF, LOW);

Serial.println(“ANGRY”);
}
if (incomingByte == ‘N’) {
digitalWrite(enablePin,LOW);
digitalWrite(motor1Pin, LOW);
digitalWrite(motor2Pin, LOW);

digitalWrite(enableBPin,LOW);
digitalWrite(motorB1Pin, LOW);
digitalWrite(motorB2Pin, LOW);

digitalWrite(ledPinA, HIGH);
digitalWrite(ledPinB, HIGH);
digitalWrite(ledPinC, HIGH);
digitalWrite(ledPinD, HIGH);
digitalWrite(ledPinF, HIGH);

Serial.println(“AFRAID”);
}
}

}

 

 

 

 

PComp Final PART 2 – Interior Weather

I spent the last two weeks (mostly working on my Applications presentation) thinking about what my ICM/PComp final should be. Since the beginning I knew I wanted to :

  • build an immersive installation that makes the user to feel something that is shared live on social networks;
  • use Twitter as a “switch” to activate a physical interface;
  • use non technological material to build the installation;
  • use those non technological material to build a “visualization” of data sent by Twitter.

My final will be called Interior Weather and is an interactive installation that transforms emotions shared live on Twitter into weather. The tweets containing:

  • “I feel alone” will put the light of (darkness);
  • “I feel sad” will activate water mist (rain);
  • “I feel angry” will activate a thunder sound;
  • “I feel happy” will turn the light on;

Connecting Processing to a Twitter stream
Today, I managed to connect Processing to a live stream using the Twitter API. It “println ” the tweets stream.

  1. You first need to activate your developer account on Twitter;
  2. Then you can connect to the API using this example.
Here is the code:

// This is where you enter your Oauth info
static String OAuthConsumerKey = “put your key here”;
static String OAuthConsumerSecret = “put your secret here”;
// This is where you enter your Access Token info
static String AccessToken = “put your access token here”;
static String AccessTokenSecret = “put you token secret here”;

// if you enter keywords here it will filter, otherwise it will sample
String keywords[] = {“any keywords you want”
};

TwitterStream twitter = new TwitterStreamFactory().getInstance();

void setup() {
size(800, 600);

connectTwitter();
twitter.addListener(listener);
if (keywords.length==0) twitter.sample();
else twitter.filter(new FilterQuery().track(keywords));
}

void draw() {
background(0);
}

// Initial connection
void connectTwitter() {
twitter.setOAuthConsumer(OAuthConsumerKey, OAuthConsumerSecret);
AccessToken accessToken = loadAccessToken();
twitter.setOAuthAccessToken(accessToken);
}

// Loading up the access token
private static AccessToken loadAccessToken() {
return new AccessToken(AccessToken, AccessTokenSecret);
}

// This listens for new tweet
StatusListener listener = new StatusListener() {
public void onStatus(Status status) {

println(“@” + status.getUser().getScreenName() + ” – ” + status.getText());
}
}

The next step is to parse the incoming tweets into strings and have them send various outputs to the Arduino.
Sending data from Processing to an Arduino
Today I did the Arduino example Physical Pixel to send data from Processing to an Arduino.

 

 

B – Transforming the space into a musical instrument

The Orproject

C – Using normal and existing daily gestures as instruments

21 balançoires

D – The interactivity is conscious or unconscious

Solarbeat

The Physical Equalizer

By Anne-Marie Lavigne and Sarah Rothberg
Sample track by Yotam Mann

The physical equalizer is a midi volume fader made from 6 fabric flex sensors and 20 wooden cubes. In this application, each sensor is linked to a track on Ableton Live through MAX/MSP. Placing a cube of wood on the base of the controller activates a corresponding track. The cubes are stackable, and the more cubes there are on a sensor, the louder the volume of that track. This device can be played as a music instrument, as a live performance tool, a mixing device for engineers. It can be experienced through speakers for a public performance or headphones for a individual experience.

Personal Statement
Interactivity is a mix of gestures and interfaces. We wanted to create a device that puts the emphasis on the gesture, not on the technology. How can we put the user into a special and unique creative mode? How can we build a tool that invites the user to be spontaneous and engaged? We aimed to create a simple, recognizable interface using materials that encourage child-like play.

Background

Our main research was on soft fabric sensors. We discovered and learned how to make them and which fabric is best for the device. We have built our own sensors and created a template that can be shared.

Audience

The target audience is diverse. Any adult or child can play or perform. Musicians can use it as a performance tool, as it acts as a visualization of what is happening on a computer. Sound engineers can use it as a mixing device.

User Scenario

The user is invited to play with wooden cubes to manipulate the volume of a track, or turn that track on and off, using it as a musical instrument. Using the cubes to increase or decrease the volume of a specific track allows the user to visualize the music. The cubes are made of wood and are reminiscent of toy construction blocks, encouraging users to build and play. to put the user into a playing mode. The wooden interface puts the emphasis on the gestures of the user, not on the technology.

Implementation

The physical equalizer is made of a rectangular platform with 6 soft fabric flex sensors and 20 wooden cubes. Each sensor is linked to a music track on Ableton Live. The user stacks the cubes on the sensors to activate the music tracks. The more cubes there are on a sensor, the louder the volume of the track.

Conclusion

We learned how to conceptualize and build a simple user interface that can have multiple uses and purposes. Making simple and clear interfaces is a complex task. We think we succeeded creating a full and entertaining interactive experience with the physical equalizer.

RE : Leave me alone, Self 1!

This is a response to this great post by my friend Christina for the Applications readings.

My first ITP weeks were challenging. Even though I have been working on projects created with cutting edge technology, I had never been the one developing the technology itself. My job was to feed technologists with content ideas and strategies: knowing and discovering technologies through the content filter.

From the first class of my first semester, I understood ITP were the place I had been searching for years. A place where you simultaneously create technology and content ideas. The approach we are taught here is that technology frames creative ideas and as much as ideas frame technology. The more you know how the technology works, the more creative ideas you have. The more you have creative ideas the more you discover technology.

As of the first day, I also understood the next two years are gonna be a challenge. To be creative, you must let yourself go and dive into that creative space that generates inspiration. The thing is that with technology, this is hard to achieve. There are so many codes, algorithmes, softwares to master before you can let yourself go, that I doubted for weeks I could succeed in being creative using those tools. It felt like my Self 1 was constantly thinking that I had to completely master every single technology before I could pretend creating with it.

Also, the tools we learn here are not simple tools. They are complex and elaborated computed languages that demands a lot of cerebral work to be performed. Unlike a pen on paper, or paint on a canvas, or dance, I first found it hard to let myself go and be creative. How far do you have to master a technology so it becomes an extension of your body and you hands? So it becomes part of your Self 2 impulsions? It sometimes feels like learning technology implements an intermediary in between my ideas and and my creativity. Can technological creation be spontaneous? Or is it always mediated by a third entity that you can never completely control and understand? Is technology a filter with which we comprehend society or is it simply a tool?

How can we let our Self 2 be spontaneous when our brain has to continuously process code and cerebral knowledge?

Also, how can we build interactive art and experiences that allows the public to expose their Selves 2? I have always wanted to create immersive art that generate a simple emotion and impulse inspiring the individuals’ Selves 2 to act. Not to think and judge themselves but impulsively move and react. Having people behaving spontaneously with their Self 2.

What is interesting and paradoxical is the fact that to create such simple and instinctive environments, I do have to master cerebral and logical knowledge using Self 1…

 

 

Physical Equalizer – Play Test

First of all, we have to say we are so stoked to have done the play test. It confirmed us our physical equalizer concept totally works! Every user who tried it really liked it. Preparing the play test and doing it made us realized tons of things. We set up our play test on the floor. We had prepared a cardboard version of the device:

  • a piece of paper on which we drew 4 squares;
  • 13 cardboard blocks of 10cm x 10cm;
  • headphones plugged into a laptop;
  • which was plugged to an online sequencer to fake the music interaction. Every time a user would pile a cube, we would fake the equalizer effect in real time using that online sequencer.
The size of the device was arbitrary and depended on the cardboard available. We wanted to have enough blocks to inspire the users and see what they would do with them.
Eight users tried the device.

The Concept
Watching people interacting with the device made us realized we have to ask ourselves: what is the purpose of the device?

  • is it a functional device? Is its purpose to be an functional equalizer people would use mainly to manage and equalize the music they listen too?
  • is it a game people can play with? With instructions and a rewarding system?
  • or is it an instrument and/or a performing tool musicians/djs would use?
We have to think about it to make sure the way it is programmed is fluid and its working is clear. The way the play test was organized made it easy to transform it into a game and an instrument device. The tracks we used were made of multiple sounds and it was hard to clearly understand it could act as a real equalizer.
All the users liked the idea of composing and constructing their own music piece using the blocks. The performance aspect was also really interesting.

 

The Instructions
The blocks were displayed around four squares drawn on a piece of paper. When the user was in front of it ready to start, we only said: go! We did not give any instructions.

  • All the users understood at first glance they had to put the cubes on the 4 squares drawings;
  • it was clear for every user he had to build something with the cubes displayed in front of them;
  • it took a little while for everybody to understand that stacking up the cubes had an impact on the music. This was mostly due to the fact Sarah and I could not go as fast as the users movements. The sound change was thus not in sync with the cubes movements;
  • Those who understood the sound was being controlled by the cubes (two user did not) really enjoyed trying to figure out how the device worked. They did not mind not having any instruction to help, and thought it was nice they had to play with the cubes to get it. We could see a clear reaction once the user got it and started to play, which was really nice;
  • It was also nice to see that the users did not need any trime frame. Some of them played for 2 minutes, others 5 minutes. It really depended on their willingness to try various tricks with the cubes stacking and movements.
  • Over all, the play test showed us our device can offer a clear visual framework preventing us having to write instructions or orienting the users. The functionalities are pretty simple to understand, and when they get them, the device is really fun.

The Sound/Volume
Two of the users did not understand the cubes add an impact on the sound. The persons focused on the shape that could be build and did not pay attention to the sound scheme. They thought it was an accompanying music. This might be due to the online equalizer we used. Every tracks had basses and highs and it was not easy to identify which tracks was linked to which pile of cubes. Because we were operating by hand, the sound changes were not always in sync with the user movements. Anyhow, we will have to make sure the music changes will be immediate and clearly responsive to the cubes movements.

  • It totally works when the volume changes respond immediately to the adding of a cube on a stack;
  • we could add a slider to change tempo;
  • the users liked to feel rewarded with a sound change and would definitely like to have more rows, at least 6;
  • the users really liked the idea of building a track with the blocks. Composing/constructing music in 3D;
  • the users liked to listen and play multiple tracks but also wanted to hear them separately

The Blocks
The play test made  showed us the cubes weight and material are gonna be crucial in the definition of the device interactivity.

  • if we decide to go for light and not so fragile cubes, the users will be tempted in moving the blocks quickly. For instance, they could stack them all on the same pile and push them away all at once to “destroy” the pile and start again;
  • if we go for heavy blocks, the users will be more into slow moves and might move them separately.
Here are some suggestions from the users:
  • to use a raw material not associated with digital culture like wood or bricks;
  • to put LED in the blocks;
  • to add a key so the blocks would fit together like lego blocks

Here are some observations from the play test:

  • All the users understood right away they had to use the blocks to build something;
  • all the users wanted to use all the blocks. This means we will have to come up with an appropriate number of blocks, not too many, not too few. This will depend on the sensor’s sensitivity.
The Interactivity
It was really nice to watch the users interact with the device. They all played with their own style and highlighted a new creative interaction with the cubes. Here are some examples of what they did:
  • piled the blocks all the way up on the same column and then slide it to another column;
  • slided them from one column to another;
  • played with only one block at a time;
  • piled them on a stack and then took them away all at once;
  • piled them up before putting them on a pile so it would sound with the highest volume at first;
  • piled them into a pyramid.

Every user did something the precedent did not do. It was really nice to see there are so many ways to use the same device.

I CAN’T WAIT TO BUILD IT!!