Building a music server the hard way having fun with Arduino.
Using Arduino, LCD screen and SC-card reader to start a selected album in iTunes on a pc.
First step is to control iTunes with Arduino. I tried to use Gobetwino but this doesn't always make the right selections. I ended up using AAC-Keys to translate serial data to key presses and Auto Hot Key (AHK) to control iTunes.
The most difficult part was to select the iTunes search field.
Second step is to make al list of albums. In iTunes export a playlist to Excel. In Excel remove all info except artist and album name. Save as csv-file. Rename to txt-file and copy to SD-card. This creates a list for Arduino to read like:
Giant Sand;Selections Circa 1990 - 2000
Joan Baez;Play Me Backwards
Room Eleven;Mmm... Gumbo?
Nina Simone;The Very Best Of Nina Simone
The Walkabouts;Nighttown
Calexico;The Black Light
Third step is to make Arduino scroll up and down this list. To make Arduino read this list all at once is explained in the SD-card examples.
The scolling function is based on line feeds. During setup al line feed positions are stored in an array. Now we know the starting points of all next lines (albums). The ";" is used to display the album title on the 2nd row.
Setup ends with displaying the first album on the LCD screen. I use a Nuelectronics LCD screen with buttons like this:
Use up and down buttons to display the next or previous album on the LCD screen (see next()). Pushing key 0 sends an AHK command to the pc, adds the title of the selected album and starts the first song in iTunes (see start()).
All works fine on my laptop for now:
Next is to set up a second hand pc as iTunes server with digital out (toslink or coax). This I will connect through a dac to my stereo. I'd like to convert an old AKAI digital tuner into the music server by exchanging the screen with the Arduino LCD screen. But this will take some time.
The code works well and certainly fast enough. Improvements and suggestions on how to use a NAS instead of a pc are welcome.
#include <SD.h>
#include <PString.h>
#include <LCD4Bit_mod.h>
LCD4Bit_mod lcd = LCD4Bit_mod(2);
int keyarray[5] = {30, 150, 360, 535, 760 }; //see LCD button shield
int NUM_KEYS = 5;
int keypad;
int key = -1;
int oldkey = -1;
const int chipSelect = 10;
File dataFile;
char x;
int myLines[24]; // array of 24 albums based on line feed positions
int n = 0; // album counter
int pos = 0; // album position variable
char album[60]; // "artist name;album name" variable
PString myPstring(album, sizeof(album)); // to built a string out of characters
void setup(){
Serial.begin(9600);
pinMode(10, OUTPUT);
SD.begin(chipSelect);
dataFile = SD.open("SAVONDS2.TXT");
if (dataFile) {
while (dataFile.available()) {
x = dataFile.read(); //characters read one by one
if (x == 10){ //line feed is 10
myLines[n] = dataFile.position(); //array of line feed positions
n++;
} }
dataFile.close();
myLines[23] = 0; //change last pos into first album position
n = 23;
}
lcd.init();
next(); //print first album to LCD
delay(200);
}
void loop(){
keypad = analogRead(0); //detect key press
key = getkey(keypad);
if (key != oldkey){
delay(25);
keypad = analogRead(0);
key = getkey(keypad);
if (key != oldkey){
oldkey = key;
if (key >=0){buttons();} // LCD shield with 5 buttons
}
}
delay(25);
}
void buttons(){
if (key == 0){start();} // itunes starts displayed album
if (key == 1){n=n-1; next();} // display next album
if (key == 2){n=n+1; next();} // display previous album
if (key == 3){Serial.println("\033,hold,alt.s");} // AHK start/pause itunes
if (key == 4){Serial.println("\033,hold,alt.s");}
delay(100);
}
void next(){ //read artist and album name (n) from SD-card
if(n<0){n=23;} //scroll from first to last album
if(n>23){n=0;} //scroll from last to first album
pos = myLines[n]; //position of line feed preceding ablum (n)
myPstring = "";
dataFile = SD.open("SAVONDS2.TXT");
if (dataFile) {
lcd.clear();
lcd.cursorTo(1, 0); //artist name on first row
dataFile.seek(pos); //position to read
int q = 0;
while (dataFile.available()) {
x=dataFile.read(); //read next character 'x'
q++; //character counter
if (x == ';'){
lcd.cursorTo(2, 0); //album name on second row
q=0; //reset character counter for next row
myPstring.print(' ');} //space between artist and album
else{
if (x != 10 && x != 13){
if(q<17){lcd.print(x);} //send 'x' to LCD screen
myPstring.print(x); //add 'x' to album
}
else{
dataFile.close(); //stop while loop
} //myPstring contains artist and album name
}
}
}
}
void start(){
Serial.println("\033,hold,alt.z"); //AHK open itunes search field
delay(500); //wait for blank search field
Serial.println(album); //copy album from myPstring
delay(1500); //wait for itunes
Serial.println("\033,hold,alt.s"); //itunes start album
}
int getkey(unsigned int input){
int k;
for (k=0; k<NUM_KEYS; k++){
if (input < keyarray[k]){return k;}
}
if (k >= NUM_KEYS){k = -1; return k;}
}
AHK script:
; based on code snippets from the iTunes Anywhere topic
; thanks to daorc for activating the search control
; thanks to brohan for ComObjCreate function
#SingleInstance, Force
itunes := ComObjCreate("iTunes.Application")
ControlSend, ahk_parent,{Tab}, iTunes ahk_class iTunes
ControlSend, ahk_parent,{Tab}, iTunes ahk_class iTunes
DetectHiddenWindows, On
!s::
itunes.PlayPause()
return
!z::
IfWinExist,ahk_class iTunes
{
itunes.Pause()
winset,top
winactivate
controlclick,Edit1,iTunes ahk_class iTunes ;activate the "search" control
controlfocus,Edit1,iTunes ahk_class iTunes ;activate the "search" control
ControlSend, ahk_parent,{Esc}, iTunes ahk_class iTunes
}
return