Similarity JukeBox @ ITP Winter Show

Showing my final at the ITP Winter Show was the most intense user testing process that taught me a lot about how to display my work and how to quickly explain what my project was about to the public.

If I had to do it all over again I would probably make the buttons on the interface have the play, next set, and last set symbols on them and move the fader down a little more. Although some people knew exactly how to use controls, there were a few that didn’t know where to start. Musically inclined people spent more time playing around with it and I was especially surprised to find that it was a big hit with high school students. I assumed that because a majority of the music referenced is from the 60’s and 70’s that they wouldn’t find it entertaining but I was wrong!

Laser cutting Illustrator File

I realized after putting my wood panel into the laser cutting machine that I needed to make the squares for the buttons double the size. I also added the symbols for the buttons underneath which could explain why they were so close to the fader. This was my first try at the laser cutting machine, and my first solo fabrication project – not too shabby! I tried using the same font that was on my cigar box but it looks like I should have adjusted the spacing of the font because it’s a little bit different. I used Berthold Akzidenz Grotesk Bold and found it by uploading a picture of a word on the box to fontsgeek.com.

The final code:

P5.JS
let playbutton, stopbutton, nextbutton, backbutton;
let slider;
let fader = 0;
let songAFileNames =
['SweetLittleSixteen',
'HesSoFine',
'MaryJanesLastDance',
'BrownSugar',
'ObLaDiObLaDa',
'SpiritInTheSky',
'RunThroughTheJungle',
'PumpItUp',
'YouNeedLove',
'AmericanGirl',
'LadyMadonna',
'DontStopTilYouGetEnough',
'TwoPrinces',
'Mmmbop',
'IWontBackDown',
'Taurus',
'TheAirThatIBreathe',
//'PictureBook',
'TomorrowNeverKnows',
'UnderPressure',
'LittleMermaid'];
let songBFileNames =
['SurfinUSA',
'MySweetLord',
'DaniCalifornia',
'WalkAndTalkIt',
'WhyDontYouGetAJob',
'BabyDidABadBadThing',
'TheOldManDownTheRoad',
'GetOnYourBoots',
'WholeLottaLove',
'LastNight',
'WhatIGot',
'SteppinOut',
'SemiCharmedLife',
'Unpretty',
'StayWithMe',
'StairwayToHeaven',
'Creep',
//'SaladDays',
'LetForeverBe',
'IceIceBaby',
'Nude'];
let songAs = [];
let songBs = [];
let albumAs = [];
let albumBs = [];
let currentIndex = 0;
let serial;
let portName = '/dev/cu.usbmodem1411';
let hasStarted = false;
let isPlaying = false;
let volumeA = 1;
let volumeB = 1;
function preload() {
for (let i = 0; i < songAFileNames.length; i++) { songAs[i] = loadSound("assets/sounds/" + songAFileNames[i] + ".mp3"); songBs[i] = loadSound("assets/sounds/" + songBFileNames[i] + ".mp3"); albumAs[i] = loadImage("assets/images/" + songAFileNames[i] + ".jpg"); albumBs[i] = loadImage("assets/images/" + songBFileNames[i] + ".jpg"); } } function setup() { createCanvas(1334, 750); background(255); serial = new p5.SerialPort('172.16.250.39'); // make an instance of the serial library serial.open(portName); // open port serial.on('connected', function(){ console.log("CONNECTED"); background(15); }); serial.on('data', gotData); // declare serial data callback function } function draw() { //checkSliderAndUpdateSound(); if(hasStarted) checkFaderAndUpdateSound(); } function checkFaderAndUpdateSound() { console.log("checkFaderAndUpdateSound"); volumeA = map(fader, 0, 1023, 0, 1); volumeB = map(fader, 0, 1023, 1, 0); console.log(volumeA); songAs[currentIndex].setVolume(volumeA); songBs[currentIndex].setVolume(volumeB); tint(255,255); let xPos = width/2 - 750/2; image(albumBs[currentIndex], xPos, 0, 750, 750); tint(255, fader/4); image(albumAs[currentIndex], xPos, 0, 750, 750); } function playsound() { if (!songAs[currentIndex].isPlaying()) { songAs[currentIndex].loop(); songBs[currentIndex].loop(); } } function pausesound(){ songAs[currentIndex].pause(); songBs[currentIndex].pause(); } function stopsound() { songAs[currentIndex].stop(); songBs[currentIndex].stop(); } function nextsetsound() { stopsound(); currentIndex++; if (currentIndex > songAs.length - 1) {
currentIndex = 0;
}
playsound();
}
function lastsetsound() {
stopsound();
currentIndex--;
if (currentIndex < 0) { currentIndex = songAs.length - 1; } playsound(); } function gotData() { let arduinoInput = serial.readLine(); // read an ASCII-encoded string if(arduinoInput.length > 0) {
if (arduinoInput === 'P') {
if(isPlaying) {
pausesound();
isPlaying = false;
} else {
playsound();
isPlaying = true;
} hasStarted = true;
}
else if (arduinoInput === 'B') {
lastsetsound();
}
else if (arduinoInput === 'N') {
nextsetsound();
}
else {
if(arduinoInput == NaN) arduinoInput = 0;
fader = arduinoInput;
console.log(fader);
}
}
}

Arduino
const int playButton = 2;
const int backButton = 3;
const int nextButton = 4;
int threshold = 2;
const int fader = A0;
int faderValue = 0;
int playButtonState = LOW;
int backButtonState = LOW;
int nextButtonState = LOW;
int prevFaderValue = 1;
int prevPlayButtonState;
int prevBackButtonState;
int prevNextButtonState;
void setup() {
pinMode(playButton, INPUT);
pinMode(backButton, INPUT);
pinMode(nextButton, INPUT);
Serial.begin(9600);
}
void loop() {
faderValue = analogRead(fader);
backButtonState = digitalRead(backButton);
playButtonState = digitalRead(playButton);
nextButtonState = digitalRead(nextButton);
if (playButtonState != prevPlayButtonState && playButtonState == HIGH) {
Serial.println('P');
}
if (backButtonState != prevBackButtonState && backButtonState == HIGH) {
Serial.println('B');
}
if (nextButtonState != prevNextButtonState && nextButtonState == HIGH) {
Serial.println('N');
}
if (abs(faderValue - prevFaderValue) > threshold) {
Serial.println(faderValue);
prevFaderValue = faderValue;
}
prevPlayButtonState = playButtonState;
prevBackButtonState = backButtonState;
prevNextButtonState = nextButtonState;
}

I’m shocked that in three months I was able to go from making an LED blink and a circle move on the screen to creating a jukebox which has been an idea of mine for quite some time. I can’t say that I love coding, but using code to create this project definitely made me appreciate the power of that language.

Unreal Engine

Using Unreal Engine proved to be very time consuming particularly because of all the computational errors I kept running into. It took some serious getting used to working with the mouse, placing items in space and configuring them in the program. I regret upgrading to High Sierra a few months back because most of the problems I ran into were related to my OS.

I played around in Fuse quite a lot creating my character who I originally tried to make look like me but it became more fun to randomly play around with the face morphing tools. Upon bringing my character into Unreal Engine, I had to re-mask all the skin from transparent to opaque in order to get him looking like he did in Fuse. All in all, it was fun to learn how to use a program that is so commonly used to create games I’m familiar with. It gives me a greater respect for all the intense work that goes into creating surreal worlds.

Character Skin File – creepy!

When I exported the short clip of my character losing his keys and dancing about it, the color and facial features were very off. Below is an image of how I wanted the animation to look, but the results I got were different.

Reflecting upon all the different ways of animating we learned about during the class, I enjoyed stop motion the best because of it’s physicality – and the fact that I didn’t run into any computational errors during the process!

Drew The Needle Animation

Stevie and I finished up our animation of a needle getting a blood test. Using After Effects was a lot of fun. It’s such a powerful program, I found myself putting a lot of work into getting to know the shortcuts on the keyboard and understanding the layout of the workspace. Unfortunately, I had deleted Drew’s key-framed animation by accident in one screen and loaded a pre-animated version of him walking in another scene to a completely different scene which confused me greatly. Once I sorted that problem out, the rest of the animation became fun and interesting!

Drew from Marco Wylie on Vimeo.

 

Finals Update #2: The coding is DONE!!!

HORRAY! The coding side of my project is finished! I have to give thanks where it’s deserved: Mimi, Tom, Mathura, Mithru thank you all so much for your help and support.

Here is the final-ish p5.js code (it will include more songs)
let playbutton, stopbutton, nextbutton, backbutton;
let slider;
let fader = 0;
let songBFileNames = ['SpiritInTheSky', 'RunThroughTheJungle', 'HesSoFine','UnderPressure', 'YouNeedLove', 'AmericanGirl', 'SweetLittleSixteen','MaryJanesLastDance', 'BrownSugar', 'LadyMadonna','DontStopTilYouGetEnough', 'TwoPrinces', 'Mmmbop', 'PumpItUp','ObLaDiObLaDa', 'IWontBackDown', 'Taurus', 'TheAirThatIBreathe','PictureBook','TomorrowNeverKnows', 'LittleMermaid'];
let songAFileNames = ['BabyDidABadBadThing', 'TheOldManDownTheRoad', 'MySweetLord','IceIceBaby', 'WholeLottaLove', 'LastNight', 'SurfinUSA','DaniCalifornia', 'WalkAndTalkIt', 'WhatIGot','SteppinOut', 'SemiCharmedLife', 'Unpretty', 'GetOnYourBoots','WhyDontYouGetAJob', 'StayWithMe', 'StairwayToHeaven', 'Creep','SaladDays','LetForeverBe', 'Nude'];
let songAs = [];
let songBs = [];
let albumAs = [];
let albumBs = [];
let currentIndex = 0;
let serial;
let portName = '/dev/cu.usbmodem1421';
let hasStarted = false;
let isPlaying = false;
let volumeA = 1;
let volumeB = 1;
function preload() {
for (let i = 0; i < songAFileNames.length; i++) { songAs[i] = loadSound("assets/sounds/" + songAFileNames[i] + ".mp3"); songBs[i] = loadSound("assets/sounds/" + songBFileNames[i] + ".mp3"); albumAs[i] = loadImage("assets/images/" + songAFileNames[i] + ".jpg"); albumBs[i] = loadImage("assets/images/" + songBFileNames[i] + ".jpg"); } } function setup() { createCanvas(400, 400); background(255); serial = new p5.SerialPort('192.168.1.151'); // make an instance of the serial library serial.open(portName); // open port serial.on('connected', function(){ console.log("CONNECTED"); background(215); }); serial.on('data', gotData); // declare serial data callback function } function draw() { //checkSliderAndUpdateSound(); if(hasStarted) checkFaderAndUpdateSound(); } function checkFaderAndUpdateSound() { console.log("checkFaderAndUpdateSound"); volumeA = map(fader, 0, 1023, 0, 1); volumeB = map(fader, 0, 1023, 1, 0); console.log(volumeA); songAs[currentIndex].setVolume(volumeA); songBs[currentIndex].setVolume(volumeB); tint(255,255); image(albumBs[currentIndex], 55, 20); tint(255, fader/4); image(albumAs[currentIndex], 55, 20); } function playsound() { songAs[currentIndex].loop(); songBs[currentIndex].loop(); } function pausesound(){ songAs[currentIndex].pause(); songBs[currentIndex].pause(); } function stopsound() { songAs[currentIndex].stop(); songBs[currentIndex].stop(); } function nextsetsound() { stopsound(); currentIndex++; if (currentIndex > songAs.length - 1) {
currentIndex = 0;
}
playsound();
}
function lastsetsound() {
stopsound();
currentIndex--;
if (currentIndex < 0) { currentIndex = songAs.length - 1; } playsound(); } function gotData() { let arduinoInput = serial.readLine(); // read an ASCII-encoded string if(arduinoInput.length > 0) {
if (arduinoInput === 'P') {
if(isPlaying) {
pausesound();
isPlaying = false;
} else {
playsound();
isPlaying = true;
} hasStarted = true;
}
else if (arduinoInput === 'B') {
lastsetsound();
}
else if (arduinoInput === 'N') {
nextsetsound();
}
else {
if(arduinoInput == NaN) arduinoInput = 0;
fader = arduinoInput;
console.log(fader);
}
}
}

And the Arduino code:
const int playButton = 2;
const int backButton = 3;
const int nextButton = 4;
int threshold = 2;
const int fader = A0;
int faderValue = 0;
int playButtonState = LOW;
int backButtonState = LOW;
int nextButtonState = LOW;
int prevFaderValue = 1;
int prevPlayButtonState;
int prevBackButtonState;
int prevNextButtonState;
void setup() {
pinMode(playButton, INPUT);
pinMode(backButton, INPUT);
pinMode(nextButton, INPUT);
Serial.begin(9600);
}
void loop() {
faderValue = analogRead(fader);
backButtonState = digitalRead(backButton);
playButtonState = digitalRead(playButton);
nextButtonState = digitalRead(nextButton);
if (playButtonState != prevPlayButtonState && playButtonState == HIGH) {
Serial.println('P');
}
if (backButtonState != prevBackButtonState && backButtonState == HIGH) {
Serial.println('B');
}
if (nextButtonState != prevNextButtonState && nextButtonState == HIGH) {
Serial.println('N');
}
if (abs(faderValue - prevFaderValue) > threshold) {
Serial.println(faderValue);
prevFaderValue = faderValue;
}
prevPlayButtonState = playButtonState;
prevBackButtonState = backButtonState;
prevNextButtonState = nextButtonState;
}

Final proto from Marco Wylie on Vimeo.

Things I need to fix on the coding side:

  1. When streaming the p5.js sketch to the iphone, you have to press on the iphone’s screen in order to start the sketch, even after you press the physical Play button.
  2. When you start the sketch the album cover from the other side of the slider starts on the opposite side and then suddenly switches to the correct one and acts normally when you move the fader.

Similarity JukeBox

My song comparison box has finally started to come together. Although I haven’t figured out one section of code on the p5.js side that will let the physical fader control not only the sound but the album display, the rest of the functionality seems to be working.

What I hope to convey with this project is how similar two songs can be, using clips of the songs to emphasize exactly what sounds the same between the two.

I’ll be running the p5.js script through an old iphone  which will be fastened to the interface shown in the video below. All I need to do is figure out the following:

  1. How to get the songs to play in the order I wanted and not randomly after pressing the next button.
  2. How to map the tint function in p5.js so that the fader works with the album images as well as the song clips.
  3. How to properly fabricate everything so that it fits neatly inside the cigar box.

A p5.js functional sketch version of the project can be seen here.

Serial Problems

I’m having a lot of trouble making a serial connection between my Arduino, the three buttons, and my p5.js sketch. Here is my current Arduino sketch:

const int pinButton2 = 2;
const int pinButton3 = 3;
const int pinButton4 = 4;
int lastButtonState = LOW;
int buttonPressCount = 0;
void setup() {
pinMode(pinButton2, INPUT);
pinMode(pinButton3, INPUT);
pinMode(pinButton4, INPUT);
Serial.begin(9600);
}
void loop() {
char incoming = Serial.read(); // read incoming bytes
if (incoming == 'P') { // if you get P
digitalWrite(2, HIGH); // Play is Pressed
}
int currentButtonState = digitalRead(2); //read the play button
if (currentButtonState != lastButtonState) { // if the button changed
buttonPressCount++; // increment buttonPressCount
Serial.print('P'); // send a P
Serial.println(buttonPressCount);
}
// int stateButton2 = digitalRead(pinButton2);
// int stateButton3 = digitalRead(pinButton3);
// int stateButton4 = digitalRead(pinButton4);
// Serial.println(stateButton2);
// Serial.println(stateButton3);
// Serial.println(stateButton4);
// delay(20);
lastButtonState = currentButtonState; // save the current state for next time
// int sensorValue = analogRead(A0);
// Serial.println(sensorValue);
// int sensorValue1 = analogRead(A1);
// Serial.println(sensorValue1);
}

(Based on this code)

And my p5.js sketch is here.

Every time I press the button on my breadboard I get a serial monitor reading of “P” but then I get another “P” when I release the button as well. This is making the song clips play twice and distorting the sound heavily in my p5.js sketch. Although, now I’m not getting anything on the p5.js side since I changed “1” to “P” in the .js sketch.

Button Press from Marco Wylie on Vimeo.

 

ICM Conclusion

Showing my final ICM project to the class allowed me to see some changes I need to think about when combing this sketch with an Arudino based interface. The p5.js sketch for my ICM final is exactly the way it will look when I combine it with a physical interface. The buttons on the screen were added to illustrate the way the interface will look once it is fabricated. All I’m going to need is the image of the album covers fading and the sound to function through p5.js for my pComp final.

Upgrades:

  1. On either side of the slider I want to have all the original songs on the left and all the rip offs on the right. √
  2. Slider should start on the left side when the sketch is opened (doesn’t really apply once I have a physical interface) √
  3. Get rid of the Stop button and combine a Play Button with a Pause function
  4. Add master volume (needed for physical interface)

Updated Song List:

SpiritInTheSky 1969 BabyDidABadBadThing 1995
RunThroughTheJungle 1970 TheOldManDownTheRoad 1985
HesSoFine 1962 MySweetLord 1970
UnderPressure 1982 IceIceBaby 1990
YouNeedLove 1962 WholeLottaLove 1969
AmericanGirl 1976 LastNight 2001
SweetLittleSixteen 1958 SurfinUSA 1963
MaryJanesLastDance 1993 DaniCalifornia 2006
BrownSugar 1971 WalkAndTalkIt 1972
LadyMadonna 1969 WhatIGot 1996
DontStopTilYouGetEnough 1979 SteppinOut 1981
TwoPrinces 1991 SemiCharmedLife 1997
Mmmbop 1997 UnPretty 1999
PumpItUp 1978 GetOnYourBoots 2009
ObLaDiObLaDa 1968 WhyDontYouGetAJob 1998
IWontBackDown 1989 StayWithMe 2014
Taurus 1968 StairwayToHeaven 1971
TheAirThatIBreathe 1974 Creep 1993
PictureBook 1968 SaladDays 2014
TomorrowNeverKnows 1966 LetForeverBe 1999
LittleMermaid 1989 Nude 2007

One problem I’ve had since the conception of this idea is the what I’m going to call this project. When trying to come up with a word for the “sound-a-like” song on the other side of the slider I realized that this was part of the problem I’m having with a title. I don’t know what to call the song that songs like the original. And further than that, I don’t know what to call the project itself!

On the left side will be “Original Songs” or just “Original” so the listener knows what they’re listening to, so that they are grounded in the experience, and so hopefully, it will be obvious what the intent of the installation is. On the other side…here are my ideas:

Copy-written, Plagiarized, Trademark, RipOff, Similar, Doppelgänger, Sound-a-like, Imitative, Copy, Stolen, Ripped

For the name of the project itself I want something more than just a one word descriptive  title. A few weeks back I presented a few options for the title in ICM, I’m not really happy with any of the names I came up with. Perhaps this part will come together once I put together the pComp side of the project.

pComp Final Update

Started soldering and testing my connections. My 10k sliding potentiometer is working when tested with this code:

void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A0);
Serial.println(sensorValue);
}

Sliding Potentiometer from Marco Wylie on Vimeo.

And the other potentiometer for the volume is working as well.

Potentiometer from Marco Wylie on Vimeo.

Once I got home with all my soldered pieces I assembled the code for the two potentiometers and three buttons to print the sensor values.

const int pinButton2 = 2;
const int pinButton3 = 3;
const int pinButton4 = 4;
void setup() {
pinMode(pinButton2, INPUT);
pinMode(pinButton3, INPUT);
pinMode(pinButton4, INPUT);
Serial.begin(9600);
}
void loop() {
int stateButton2 = digitalRead(pinButton2);
int stateButton3 = digitalRead(pinButton3);
int stateButton4 = digitalRead(pinButton4);
Serial.println(stateButton2);
Serial.println(stateButton3);
Serial.println(stateButton4);
delay(20);
int sensorValue = analogRead(A0);
Serial.println(sensorValue);
int sensorValue1 = analogRead(A1);
Serial.println(sensorValue1);
}

Final progress from Marco Wylie on Vimeo.

I’m having a lot of trouble making a serial connection between my Arduino, the three buttons, and my p5.js sketch. Here is my current Arduino sketch:

const int pinButton2 = 2;
const int pinButton3 = 3;
const int pinButton4 = 4;
int lastButtonState = LOW;
int buttonPressCount = 0;
void setup() {
pinMode(pinButton2, INPUT);
pinMode(pinButton3, INPUT);
pinMode(pinButton4, INPUT);
Serial.begin(9600);
}
void loop() {
char incoming = Serial.read(); // read incoming bytes
if (incoming == 'P') { // if you get P
digitalWrite(2, HIGH); // Play is Pressed
}
int currentButtonState = digitalRead(2); //read the play button
if (currentButtonState != lastButtonState) { // if the button changed
buttonPressCount++; // increment buttonPressCount
Serial.print('P'); // send a P
Serial.println(buttonPressCount);
}
// int stateButton2 = digitalRead(pinButton2);
// int stateButton3 = digitalRead(pinButton3);
// int stateButton4 = digitalRead(pinButton4);
// Serial.println(stateButton2);
// Serial.println(stateButton3);
// Serial.println(stateButton4);
// delay(20);
lastButtonState = currentButtonState; // save the current state for next time
// int sensorValue = analogRead(A0);
// Serial.println(sensorValue);
// int sensorValue1 = analogRead(A1);
// Serial.println(sensorValue1);
}

Every time I press the button on my breadboard I get a serial monitor reading of “P” but then I get another “P” when I release the button as well. This is making the song clips play twice and distorting the sound heavily in my p5.js sketch.

Button Press from Marco Wylie on Vimeo.