IMG 7267 from Lindsey Frances on Vimeo.
This music controller has six buttons that control music: shuffle, back, stop/play, pause/play, forward, and fast forward. As an added feature, a toggle switch is located in the front that allows the user to switch between controlling a Javascript sketch and Spotify.

For feedback, this plays a sound before the button press on the Javascript side. This originally had notes playing with sound in the Arduino code along with a speaker. It was taken out as a design choice so that the sound doesn’t interfere with the Spotify side.
Circuit Diagram
Laser cut file
Source code
Arduino:
#include <Keyboard.h> | |
char ctrlKey = KEY_LEFT_GUI; | |
//Variables | |
const int firstBack = 2; | |
const int secondPlay = 3; | |
const int thirdForward = 4; | |
const int fourthSpeed = 5; | |
const int fifthShuffle = 6; | |
const int sixthRandom = 7; | |
//Toggle Switch | |
int TGLPIN = 8; | |
void setup() { | |
// put your setup code here, to run once:sw | |
Serial.begin(9600); | |
pinMode(firstBack, INPUT); | |
digitalWrite(firstBack, HIGH); | |
pinMode(secondPlay, INPUT); | |
digitalWrite(secondPlay, HIGH); | |
pinMode(thirdForward, INPUT); | |
digitalWrite(thirdForward, HIGH); | |
pinMode(fourthSpeed, INPUT); | |
digitalWrite(fourthSpeed, HIGH); | |
pinMode(fifthShuffle, INPUT); | |
digitalWrite(fifthShuffle, HIGH); | |
pinMode(sixthRandom, INPUT); | |
digitalWrite(sixthRandom, HIGH); | |
pinMode(TGLPIN, INPUT); | |
} | |
void loop() { | |
// put your main code here, to run repeatedly: | |
int valueFirst = digitalRead(firstBack); | |
int valueSecond = digitalRead(secondPlay); | |
int valueThird = digitalRead(thirdForward); | |
int valueFourth = digitalRead(fourthSpeed); | |
int valueFifth = digitalRead(fifthShuffle); | |
int valueSixth= digitalRead(sixthRandom); | |
int tglOn = digitalRead(TGLPIN); | |
if (tglOn == HIGH) { //if toggle switch is high do spotify | |
Serial.println("Spotify"); | |
//shuffle | |
if(valueFirst == HIGH){ | |
delay(100); | |
Keyboard.press(KEY_LEFT_GUI); | |
Keyboard.press('s'); | |
}else{ | |
delay(100); | |
Keyboard.release(KEY_LEFT_GUI); | |
Keyboard.release('s'); | |
} | |
//back | |
if(valueSecond == HIGH){ | |
delay(100); | |
Keyboard.press(KEY_LEFT_GUI); | |
Keyboard.press(KEY_LEFT_ARROW); | |
}else{ | |
Keyboard.release(KEY_LEFT_GUI); | |
Keyboard.release(KEY_LEFT_ARROW); | |
} | |
//stop | |
if(valueThird == HIGH){ | |
delay(100); | |
Keyboard.press(' '); | |
}else{ | |
Keyboard.release(' '); | |
} | |
//play pause | |
if(valueFourth == HIGH){ | |
delay(100); | |
Keyboard.press(' '); | |
}else{ | |
Keyboard.release(' '); | |
} | |
//skip | |
if(valueFifth == HIGH){ | |
delay(200); | |
Keyboard.press(KEY_RIGHT_GUI); | |
Keyboard.press(KEY_RIGHT_ARROW); | |
}else{ | |
Keyboard.release(KEY_RIGHT_GUI); | |
Keyboard.release(KEY_RIGHT_ARROW); | |
} | |
if(valueSixth == HIGH){ | |
delay(100); | |
Keyboard.press(KEY_LEFT_SHIFT); | |
Keyboard.press(KEY_LEFT_GUI); | |
Keyboard.press(KEY_RIGHT_ARROW); | |
}else{ | |
Keyboard.release(KEY_LEFT_SHIFT); | |
Keyboard.release(KEY_LEFT_GUI); | |
Keyboard.release(KEY_RIGHT_ARROW); | |
} | |
} //this is for toggle switch | |
else{ //else use js code | |
Serial.println("JS"); | |
//random | |
if(valueFirst == HIGH){ | |
Keyboard.press('6'); | |
}else{ | |
Keyboard.release('6'); | |
}; | |
//back | |
if(valueSecond == HIGH){ | |
Keyboard.press('4'); | |
}else{ | |
Keyboard.release('4'); | |
} | |
//stop | |
if(valueThird == HIGH){ | |
delay(200); | |
Keyboard.press('1'); | |
}else{ | |
Keyboard.release('1'); | |
} | |
//pause play | |
if(valueFourth == HIGH){ | |
delay(100); | |
Keyboard.press('2'); | |
}else{ | |
Keyboard.release('2'); | |
} | |
//forward | |
if(valueFifth == HIGH){ | |
delay(100); | |
Keyboard.press('3'); | |
}else{ | |
Keyboard.release('3'); | |
} | |
//fast forward | |
if(valueSixth == HIGH){ | |
delay(100); | |
Keyboard.press('5'); | |
}else{ | |
Keyboard.release('5'); | |
} | |
} //this is for toggle switch | |
} |
Javascript:
/* | |
Music player | |
Plays a directory of music | |
Plays songs in a subdirectory of the sketch called music | |
Put any songs you want in the music subdirectory, then | |
copy the list of song names into the songs[] array. | |
created by Tom Igoe | |
5 Feb 2017 | |
*/ | |
var song; // the sound file to be played | |
var stp; | |
var pl; | |
var ps; | |
var ffwd; | |
var fwd; | |
var bck; | |
var shfl; | |
// the list of songs: | |
var songs = ['Song1.mp3','Song2.mp3']; | |
var songCount = songs.length; // number of songs in the music dir | |
var currentSong = 0; // current song number | |
function preload() { // load the first song on preload | |
song = loadSound('music/' + songs[currentSong]); | |
stp = loadSound('stop.wav'); | |
pl = loadSound('play.wav'); | |
ps = loadSound('pause.wav'); | |
ffwd = loadSound('fastforward.wav'); | |
fwd = loadSound('forward.wav'); | |
bck = loadSound('back.wav'); | |
shfl = loadSound('shuffle.wav'); | |
} | |
function setup() { | |
createCanvas(400, 300); | |
} | |
function draw() { | |
background(30, 20, 180); | |
fill(255); | |
// draw the song's name and current time in seconds: | |
text(songs[currentSong], 20, 50); | |
text(song.currentTime().toFixed(3), 20, 100); | |
} | |
function controlSound(input) { | |
switch(input) { | |
case 49: // start/stop, press 1 | |
if (song.isPlaying()){ | |
// song.stop(); | |
stp.play(); | |
song.stop(); | |
console.log("song is stopped, 1 is pressed"); | |
} else { | |
pl.play(); | |
beep.onended(song.play()); | |
//song.play(); | |
console.log("song is playing, 1 is pressed"); | |
} | |
break; | |
case 50: // play/pause, press 2 | |
if (song.isPlaying()){ | |
ps.play(); | |
song.pause(); | |
console.log("song is paused, 2 is pressed"); | |
} else { | |
pl.play(); | |
song.play(); | |
console.log("song is playing, 2 is pressed"); | |
} | |
break; | |
case 51: // skip ahead, press 3 | |
// make sure the song number is valid, and increment: | |
if (currentSong < songs.length-1) { | |
fwd.play(); | |
currentSong++; | |
console.log("song is skipped forward, 3 is pressed"); | |
} else { | |
currentSong = 0; | |
} | |
// get new song: | |
getSong(currentSong); | |
break; | |
case 52: // skip back, press 4 | |
// in the first second, just rewind the current track: | |
if (song.currentTime() > 1.0) { | |
bck.play(); | |
song.jump(0); | |
console.log("song is skipped back, 4 is pressed"); | |
// if more than a second has elapsed, then | |
// make sure the song number is valid, and decrement: | |
} else { | |
if (currentSong > 0) { | |
currentSong--; | |
} else { | |
currentSong = songs.length-1; | |
} | |
// get new song: | |
getSong(currentSong); | |
} | |
break; | |
case 53: // fast forward, press 5 | |
song.rate(2.0); // double the play speed | |
if (!song.isPlaying()){ | |
ffwd.play(); | |
song.play(); | |
console.log("song is fast forwarded, 5 is pressed"); | |
} | |
break; | |
case 54: // random song, press 6 | |
currentSong = Math.round(random(songCount)); // get a new song number | |
shfl.play(); | |
getSong(currentSong); // play it | |
console.log("song is random, 6 is pressed"); | |
break; | |
} | |
} | |
function getSong(songNumber) { | |
if (songNumber < songs.length) { // if the song number is in range | |
if (song.isPlaying()) { | |
song.stop(); | |
} | |
// load a new song: | |
song = loadSound('music/'+ songs[currentSong], resumePlay); | |
return true; | |
} else { // if the song number was out of range, return false | |
return false; | |
} | |
} | |
function resumePlay() { | |
// if the song isn't playing, play it | |
if (song.isPlaying()){ | |
song.stop(); | |
} else { | |
song.play(); | |
} | |
} | |
function keyReleased() { | |
controlSound(keyCode); // send the ASCII number of the key | |
} |
Citation
For Toggle Switch – http://www.connectedly.com/using-buttons-and-switches-arduino
Box Making – http://www.makercase.com/