PiFaceCAD를 이용해 음악 플레이어를 만들어보자

기능 ( 버튼과 리모콘을 이용해 구현)

  • 현재 시간 표시
  • Next, Play or Stop, Prev 곡 선택
  • 현재 곡 제목 표시 (화면을 넘어갈 시 왼쪽으로 흐르게 한다.)
  • 볼륨 조절, 음소거 가능

준비물

  • Raspberry PI
  • PiFace CAD
  • IR 리모콘 또는 IR센서가 내장된 스마트폰(IR 리모콘 어플을 받을 것)
  • 스피커 혹은 이어폰

1. PiFace CAD 를 사용하기 위한 SW 설치

SPI Enable on Pi
$ sudo raspi-config
<Advanced Options> - <SPI> - <Yes>
$ sudo reboot
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 # Load the required library
import pifacecad
import time
import datetime
import threading


pin = -1		# PiFaceCAD button
remote = -1		# IR remote control button
volume = 50		# current volume
play = True		# current playing status (playing : True, pause: False)
mute = False	# current mute status
curSong = 0		# current song number
stridx = 0		# current printed song string index

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']

# init LCD
cad = pifacecad.PiFaceCAD()
cad.lcd.backlight_on()
cad.lcd.blink_off()
cad.lcd.cursor_off()

# bitmap
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():			# print current hour and minute
	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():		# print current volume without bitmap
	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():		# print current volume
	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():	#print LCD bottom line
	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():		#print LCD top line and rotate when length > 16
	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 every 1 second
				writeTopLine()
				count_t = time.time()
			# song control
			if pin == 1 or remote == 1:	# prev song
				curSong-=2
				if curSong==-2:
					curSong=len(song)-2
				pin = -1
				remote = -1
				stridx = 0
				break;
			elif pin == 3 or remote == 3:	# next song
				pin = -1
				remote = -1
				stridx = 0
				break;
				
			elif pin == 2 or remote == 2:	# play and pause
				if play:
					mixer.music.pause()
					play = False
				else:
					mixer.music.unpause()
					play = True
				pin = -1
				remote = -1
					
			# volume control
			elif pin == 6 or remote == 6:	# volume down
				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:	# volume up
				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:	# mute
				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:	# quit
				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를 이용해 음악플레이어를 확인할 수 있다. 아래의 데모영상을 보고 잘 구현되었는지 확인해보자.







+ Recent posts