RaspyFi is an open source linux distribution. It will transform your Raspberry Pi into anaudiophile source, in 10 minutes without hassles. It comes ready to play, and it’s compatible with almost every USB DAC available.This was perfect for me because I had for some time been thinking of building some kind of "music station" that I could use together with my NuForce uDAC 2 and my Sennheiser HD598. I was thinking about using an old laptop but an Raspberry Pi is even better. Small, quiet, power efficient and just very cool.
After writing the image to an SD-card I was playing music within minutes and it worked great! I controlled the music from a web-browser and my Android phone which was ok but it made me start thinking about building some control functionality into the device itself. Then I realized was that I had the solution in one my electronics storage boxes! I had a Adafruit Blue&White 16x2 LCD+Keypad Kit for Raspberry Pi that I didn't had time to put together earlier.
After some soldering I had a nice display with five buttons on top of the Raspberry Pi. The soldering and software installation was very easy thanks to Adafruits excellent user-guide that can be found here.
The last piece of the puzzle was to display song information on the 16x2 LCD display and use the keypad to control the playback. First I was inspired by this thread in the RaspyFi forums, they used lcdproc and mpdlcd but I didn't find drivers for the Adafruit LCD and I didn't feel like writing my own drivers (maybe its not that hard?).
Instead of using something "ready" I decided to make my own "driver" based on a simple python script using Adafruits python library for communicating with the display and the command line program mpc for communicating with mpd.
The software features:
- Presentation of play mode (playing/paused/stopped), Artist and Song name scrolling on line 1
- The elapsed song time, total song time and percentage of song played on line 2.
- Left button: Skip back
- Right button: Skip forward
- Up button: Play
- Down button: Stop
- Select button: Toggle Play/Pause
Here is the code (showSongInfo.py):
#!/usr/bin/python
# Todo
# * display brightness timout, i.e. turn off display when stopped or paused for a while
#
import subprocess
import textwrap
from time import sleep
from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate
class TextScroller:
'Class for scrolling text'
text = ''
position = 0
textLength = 0
def __init__(self, initialText, textLength):
self.text = initialText
self.textLength = textLength
def scroll(self):
doubleText = self.text + ' ' + self.text
scrolledText = doubleText[self.position:len(doubleText)]
self.position = self.position + 1
# We add five extra spaces between each complete text scroll.
if self.position > len(self.text) + 4 :
self.position = 0
return scrolledText
def setNewText(self, newText):
self.text = newText
self.position = 0
# Initialize the LCD plate. Should auto-detect correct I2C bus. If not,
# pass '0' for early 256 MB Model B boards or '1' for all later versions
lcd = Adafruit_CharLCDPlate()
lcd.begin(16,2)
# Clear display and turn on backlight
lcd.clear()
lcd.backlight(lcd.ON)
# Poll buttons
btn = (lcd.LEFT, lcd.UP, lcd.DOWN, lcd.RIGHT, lcd.SELECT)
lastArtistSong = ''
scroller = TextScroller('', 16)
while True:
# Get current status and playtime
process = subprocess.Popen('mpc', shell=True, stdout=subprocess.PIPE)
status = process.communicate()[0]
statusLines = status.split('\n')
# Check if mpc returns more that one line plus an extra, in that case we dont have stopped the music and can parse additional information
if len(statusLines) > 2:
# Extract the songName (first line)
songName = statusLines[0]
# Extract play status
playStatus = statusLines[1].split(' ',1)[0].strip()
# Extract a string like '2:01/3:43 (54%)' from the string '[playing] #2/13 2:01/3:43 (54%)'
time = statusLines[1].split(' ',1)[1].strip()
else:
songName = ''
playStatus = '[stopped]'
time = '0:00/0:00 (0%)'
lcd.setCursor(0,0)
# Without scolling of text
#lcd.message((playStatus + ' ' + songName)[0:16] + '\n' + (time + ' ')[0:16])
# with scolling text
artistSong = (playStatus + ' ' + songName)
if artistSong != lastArtistSong:
scroller.setNewText(artistSong)
lastArtistSong = artistSong
if songName != '':
lcd.message(scroller.scroll()[0:16] + '\n' + (time + ' ')[0:16])
else:
lcd.message((playStatus + ' ')[0:16] + '\n' + (time + ' ')[0:16])
# Poll the buttons most of the sleep time, to make them responsive the plan is to
# poll the buttons for 400ms and then update the status on the display
# If we sleep for 40ms between each poll time and have five buttons that equals to 200 ms
# Two iterations of this gives us 400 ms.
# for i in range (0, 10):
for i in range (0, 5):
for b in btn:
if lcd.buttonPressed(b):
if b is lcd.RIGHT:
subprocess.Popen('mpc next', shell=True)
sleep(0.2) # Sleep a little extra to avoid dubble registrations
if b is lcd.LEFT:
subprocess.Popen('mpc prev', shell=True)
sleep(0.2) # Sleep a little extra to avoid dubble registrations
if b is lcd.UP:
subprocess.Popen('mpc play', shell=True)
sleep(0.2) # Sleep a little extra to avoid dubble registrations
if b is lcd.DOWN:
subprocess.Popen('mpc stop', shell=True)
sleep(0.2) # Sleep a little extra to avoid dubble registrations
if b is lcd.SELECT:
subprocess.Popen('mpc toggle', shell=True)
sleep(0.2) # Sleep a little extra to avoid dubble registrations
break
sleep(0.04)
I autostart the python script by adding the following line to the root crontab (sudo crontab -e):
@reboot sudo python /home/pi/Adafruit-Raspberry-Pi-Python-Code/Adafruit_CharLCDPlate/showSongInfo.py
Video of the display in action.
Part list
- Raspberry Pi
- 5V power supply
- 16 GB SD-card
- Adafruit 16x2 LCD Plate
- NuForce uDAC 2
- Network Cable
- Sennheiser HD598
- Case (e.g. Adafruit Pi Box or similar)
Todo
That is left to do is to assemble my PiSupply kit and connect to the wireless network using an USB WIFI dongle and maybe mount all parts in some clever way.