PiFaceCAD를 이용해 음악 플레이어를 만들어보자
기능 ( 버튼과 리모콘을 이용해 구현)
- 현재 시간 표시
- Next, Play or Stop, Prev 곡 선택
- 현재 곡 제목 표시 (화면을 넘어갈 시 왼쪽으로 흐르게 한다.)
- 볼륨 조절, 음소거 가능
준비물
- Raspberry PI
- PiFace CAD
- IR 리모콘 또는 IR센서가 내장된 스마트폰(IR 리모콘 어플을 받을 것)
- 스피커 혹은 이어폰
1. PiFace CAD 를 사용하기 위한 SW 설치
SPI Enable on Pi
<Advanced Options> - <SPI> - <Yes>
install PiFace CAD Python package
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install python-pifacecad
2. IR Remote 설정하기
LIRC : Linux Infrared Remote Control
LIRC를 설치하고 재부팅
$ wget https://raw.github.com/piface/pifacecad/master/bin/setup_pifacecad_lirc.sh
$ chmod +x setup_pifacecad_lirc.sh
$ sudo ./setup_pifacecad_lirc.sh
$ sudo apt-get install lirc
$ sudo modprobe lirc_rpi gpio_in_pin=23
$ sudo reboot
3. Configuring LIRC
먼저 어떤 키를 입력할 수 있는 지 확인한다.
$ irrecord --list-namespace

위와 같이 설정 가능한 command들의 list가 나오게 된다.
$ sudo rm /etc/lirc/lircd.conf
$ sudo irrecord -f -d /dev/lirc0 /etc/lirc/lircd.conf
위의 코드를 실행해 자신만의 configuration 을 만들자
실행하면 아래와 같은 창이 나오게 된다. 잘 따라 가보자



그리고 재부팅을 하고나서 잘 등록이 되었는지 확인해보자.
$ sudo reboot
$ irw
위의 명령어를 실행하고 리모콘의 버튼을 눌러 제대로 입력을 받는지 확인한다. 입력이 제대로 되면 다음과 같이 자신이 등록한 키가 버튼을 누를 때마다 나오게된다.

버튼과 그 버튼의 이름이 잘 나오는 것을 확인할 수 있다.
이제 각 버튼에 대한 configuration을 하자.
$ nano ~/.lircrc
begin
prog = myprogram
button = KEY_OK
config = 1
end
begin
prog = myprogram
button = KEY_MENU
config = 2
end
~/.lircrc 내용을 위와 같이 수정한다. 내가 아까 입력한 button의 이름을 button에 넣고 config에는 해당 button에 대한 반환값을 자신 임의대로 넣어주자.
$ python
>>> import lirc
>>> sockid = lirc.init("myprogram")
>>> lirc.nextcode() # press KEY_OK on remote after this
['1']
>>> lirc.nextcode() # press KEY_MENU on remote after this
['2']
위 코드를 실행하면 해당 버튼을 눌렀을 때에 설정한 값이 잘 나오는지 확인할 수 있다.
나는 리모콘의 버튼과 config를 아래와 같이 설정하였다.

리모콘 버튼 설정
begin
prog = myprogram
button = KEY_VOLUMEUP
config = 7
end
begin
prog = myprogram
button = KEY_VOLUMEDOWN
config = 6
end
begin
prog = myprogram
button = KEY_CHANNELUP
config = 3
end
begin
prog = myprogram
button = KEY_CHANNELDOWN
config = 1
end
begin
prog = myprogram
button = KEY_MUTE
config = 5
end
begin
prog = myprogram
button = KEY_MENU
config = 4
end
begin
prog = myprogram
button = KEY_OK
config = 2
end
Configuration
4. 음악 플레이어 준비하기
나는 여기서 pygame의 mixer를 사용했기 때문에 pygame이 없다면 설치해 주자.
$ sudo apt-get install mercurial
$ sudo pip install hg+http://bitbucket.org/pygame/pygame
5. 본격적으로 음악 플레이어 만들기
from pygame import mixer
import pifacecad
import time
import datetime
import threading
pin = -1
remote = -1
volume = 50
play = True
mute = False
curSong = 0
stridx = 0
song = ['We Don\'t Talk Anymore.mp3','Closer.mp3','Shape Of You.mp3','Starving.mp3','The Ocean.mp3'\
,'Happy.mp3','Daft Punk.mp3', 'Chandelier.mp3','The Greatest.mp3', 'Lean On.mp3']
cad = pifacecad.PiFaceCAD()
cad.lcd.backlight_on()
cad.lcd.blink_off()
cad.lcd.cursor_off()
bmp_note = pifacecad.LCDBitmap([2,3,2,2,14,30,12,0])
bmp_play = pifacecad.LCDBitmap([0,8,12,14,12,8,0,0])
bmp_pause = pifacecad.LCDBitmap([0,27,27,27,27,27,0,0])
bmp_clock = pifacecad.LCDBitmap([0,14,21,23,17,14,0,0])
bmp_vol1 = pifacecad.LCDBitmap([1,3,15,15,15,3,1,0])
bmp_vol2 = pifacecad.LCDBitmap([8,16,0,24,0,16,8,0])
cad.lcd.store_custom_bitmap(0, bmp_note)
cad.lcd.store_custom_bitmap(1, bmp_play)
cad.lcd.store_custom_bitmap(2, bmp_pause)
cad.lcd.store_custom_bitmap(3, bmp_clock)
cad.lcd.store_custom_bitmap(4, bmp_vol1)
cad.lcd.store_custom_bitmap(5, bmp_vol2)
코드의 첫 부분에는 라이브러리의 import와 사용할 전역변수 선언, 노래 리스트 저장, LCD 초기화, LCD에 출력할 bitmap을 저장하였다.
def showTime():
now = datetime.datetime.now()
nowTime = now.strftime('%H:%M')
cad.lcd.set_cursor(10,1)
cad.lcd.write_custom_bitmap(3)
cad.lcd.write(nowTime)
cad.lcd.set_cursor(0,0)
showTime()은 현재 시간과 분을 LCD 오른쪽 아래에 출력 하는 함수이다. 주기적으로 출력하여 시간을 바꾸어 출력해준다.
def updateVolume():
global volume
cad.lcd.set_cursor(2,1)
if mute:
cad.lcd.write('mute')
else:
cad.lcd.write(str(volume).rjust(4))
cad.lcd.set_cursor(0,0)
def writeVolume():
global volume
global mute
cad.lcd.set_cursor(0,1)
cad.lcd.write_custom_bitmap(4)
cad.lcd.write_custom_bitmap(5)
updateVolume()
updateVolume() 은 현재 볼륨 상태(0~100)를 LCD왼쪽 아래에 출력한다. 음소거 중 일 경우에는 'mute' 문자열을 출력한다.
writeVolume()은 스피커 모양 비트맵을 함께 출력한다.
def writeBottomLine():
global play
showTime()
writeVolume()
cad.lcd.set_cursor(7,1)
if play:
cad.lcd.write_custom_bitmap(1)
else:
cad.lcd.write_custom_bitmap(2)
cad.lcd.set_cursor(0,0)
writeBottomLine()은 말그대로 LCD의 아랫줄을 출력하는 함수이다. showTime() 함수와 writeVolume() 함수를 통해 시간과 볼륨을 출력하고, 현재 재생상태를 읽어서 재생 중이라면 재생모양 비트맵을, 일시정지중이라면 일시정지 비트맵을 출력한다.
def writeTopLine():
global curSong
global stridx
cad.lcd.set_cursor(0,0)
str = song[curSong]
if len(str)>16:
str_rotate = (str+' '+str)[stridx:stridx+15]
stridx += 1
if stridx == len(str)+4:
stridx = 0
cad.lcd.write(str_rotate)
else :
cad.lcd.write(str)
writeTopLine()은 LCD의 윗줄을 출력하는 함수이다. 윗줄에는 노래 제목이 들어가게 되는데, LCD 최대 길이인 16글자를 넘어 갈 경우가 있을 수도 있다. 이 함수는 글자가 16자 이상이라면 한번 실행할 때마다 한 칸씩 흐르게 되어있다. 따라서 main함수에서 writeTopLine()함수를 1초에 한번씩 실행하게 하여 글자가 16자 이상이라면 흐르게 하도록 하자.
def update_pin_text(event):
global pin
pin = event.pin_num
def print_ir_code(event):
global remote
remote = int(event.ir_code)
listener = pifacecad.SwitchEventListener(chip=cad)
for i in range(8):
listener.register(i, pifacecad.IODIR_FALLING_EDGE, update_pin_text)
listener.activate()
remote_listener = pifacecad.IREventListener(prog='myprogram')
for i in range(8):
remote_listener.register(str(i), print_ir_code)
remote_listener.activate()
listener는 PiFace CAD 의 버튼에 대한 인터럽트이고, remote_listener는 IR리모콘에 대한 인터럽트이다. listener는 PiFace CAD버튼이 눌렸을 때 update_pin_text함수를 실행 시키고, remote_listener는 리모콘이 눌렀을 때 print_ir_code 함수를 실행하게 된다. event.pin_num는 누른 버튼의 번호이고, event.ir_code는 리모콘 버튼에 대응하는 config 값이다. 내가 사용할 버튼들을 listener의 register에 등록하고 그에 대한 콜백함수(update_pin_text, print_ir_code)도 입력한다. 콜백함수에서는 버튼에 대한 값을 전역 변수에 저장하도록 하였다. pin과 remote의 값을 통해 음악플레이어를 조종할 것이다.
음악들은 pygame의 mixer를 통해 재생하고, 조종한다.
mixer.music 에는 여러 함수가 있지만, 여기서 사용할 함수들만 소개하겠다.
pygame.mixer.music.load : 파일을 불러온다.
pygame.mixer.music.play : 불러온 파일을 재생한다.
pygame.mixer.music.get_volume : 현재 볼륨을 반환한다.
pygame.mixer.music.set_volume : 해당 값으로 볼륨을 설정한다.
pygame.mixer.music.get_busy : 불러온 파일 스트림이 진행중인지 확인한다.
pygame.mixer.music.pause : 음악을 일시 정지 한다
pygame.mixer.music.unpause : 음악의 일시정지를 푼다.
인터럽트를 통해 pin과 remote에 어떠한 값이 들어왔을 때 그에 대응하는 mixer.music의 함수를 실행시키는 방식으로 구현해보자.
def musicMainfunc():
global pin
global remote
global volume
global play
global mute
global curSong
global stridx
curSong = 0
pin = -1
remote = -1
mixer.init()
mixer.music.set_volume(float(volume)/100)
while True:
if curSong == len(song):
curSong = 0
cad.lcd.clear()
cad.lcd.blink_off()
cad.lcd.cursor_off()
mixer.music.load(song[curSong])
mixer.music.play()
writeTopLine()
count_t = time.time()
while mixer.music.get_busy() == True:
writeBottomLine()
if time.time()-count_t > 1:
writeTopLine()
count_t = time.time()
if pin == 1 or remote == 1:
curSong-=2
if curSong==-2:
curSong=len(song)-2
pin = -1
remote = -1
stridx = 0
break;
elif pin == 3 or remote == 3:
pin = -1
remote = -1
stridx = 0
break;
elif pin == 2 or remote == 2:
if play:
mixer.music.pause()
play = False
else:
mixer.music.unpause()
play = True
pin = -1
remote = -1
elif pin == 6 or remote == 6:
while True:
volume -= 3
if volume < 0:
volume = 0
mixer.music.set_volume(float(volume)/100)
updateVolume();
sleep(0.2)
if not cad.switches[6].value:
break
pin = -1
remote = -1
elif pin == 7 or remote == 7:
while True:
volume += 3
if volume > 100:
volume = 100
mixer.music.set_volume(float(volume)/100)
updateVolume();
sleep(0.2)
if not cad.switches[7].value:
break
pin = -1
remote = -1
elif pin == 5 or remote == 5:
if mute:
mixer.music.set_volume(float(volume)/100)
mute = False
else:
mixer.music.set_volume(0)
mute = True
pin = -1
remote = -1
elif pin == 4 or remote == 4:
pin = -1
remote = -1
mixer.quit()
return
curSong+=1
위에서 부터 pin과 remote 값이 1이 되면 이전 곡을 튼다. 3이 되면 다음곡을 틀고, 2가 되면 일시 정지 및 재생을 한다. 6과 7은 볼륨을 낮추고 올리며, 5는 음소거를 하고 해제한다. 마지막으로 4는 mixer를 종료한다.
정리하여 PiFace CAD 버튼과 리모콘 버튼의 역할은 다음과 같다.

1. 이전 곡 <- KEY_CHANNELDOWN
2. 재생 및 일시정지 <- KEY_OK
3. 다음 곡 <- KEY_CHANNELUP
4. 종료 <- KEY_MENU
5. 음소거 및 해제 <- KEY_MUTE
6. 볼륨 낮추기 <- KEY_VOLUMEUP
7. 볼륨 올리기 <- KEY_VOLUMEDOWN
이제 위의 코드들을 합치고 musicMainfunc()을 실행시키면 PiFaceCAD를 이용해 음악플레이어를 확인할 수 있다. 아래의 데모영상을 보고 잘 구현되었는지 확인해보자.