저번에 PiFaceCAD를 이용해 만들었던 음악플레이어에 이어서 인터넷 라디오 스트리머를 만들어보자.

먼저 PiFaceCAD를 위한 SW설치, IR Remote 설정, Configuring LIRC 는 저번 음악플레이어 만들기와 동일하니 혹시 안했다면 아래 링크에 가서 한번 해보자.


2017/03/29 - [Raspberry] - PiFaceCAD를 이용해 MusicPlayer 만들기



인터넷 라디오 스트리밍하기

인터넷 라디오 스트리밍을 위해 mplayer를 사용할 것이기 때문에 설치해 주자.
$ sudo apt-get install mplayer

간단하게 다음 코드를 입력해보자.

$ mplayer mms://211.181.136.136/livefm

여러 줄로 뭐라고 뜨며 라디오가 재생된다면 성공이다. 인터넷 라디오는 환경에 따라 되는 주소도 아닌 주소도 있기 때문에 아래의 링크 혹은 검색을 통해 더 많은 주소들을 찾아보자.


http://changjhyun.tistory.com/35


mplayer 사용하기

mplayer 를 위와 같은 방식이 아닌 slave모드로 켜면 mplayer 가 실행되는 도중 command를 읽어 들여 일시정지나 볼륨조정 같은 설정을 할 수 있다. 또는 FIFO 파일을 통해 mplayer를 조종할 수 있다.

$ mkfifo /tmp/mplayer-control $ mplayer -slave -input file=/tmp/mplayer-control mms://211.181.136.136/livefm

위와 같이 mplayer를 실행 시키면 fifo 파일을 읽어 mplayer를 조종할 수 있게 된다.


위 명령을 실행시킨 후 다른 터미널 창을 하나 더 켜서 다음 명령어를 입력해보자

$ echo "pause" > /tmp/mplayer-control


다른 터미널에서 실행되던 mplayer가 일시 정지하는가? 일시정지 했을 것이다. 이것으로 fifo파일로 mplayer를 조종 할 수 있는것을 확인할 수 있다, 위에서 사용한 pause 함수 말고도 mplayer가 slave 모드로 실행 되었을 때 사용할 수 있는 함수들이 많다. 따라서 아래 링크를 따라가 documents를 확인하여 사용할 함수들을 알아보도록 한다.


http://www.mplayerhq.hu/DOCS/tech/slave.txt




파이썬에서 mplayer 실행시키기

python에서 mplayer를 실행시키는 것 뿐만아니라, python코드에서 터미널에 명령을 내리고 싶다면 어떻게 해야할까? 파이썬의 라이브러리에서 이와 같은 경우를 위해 os.system 함수를 제공하고 있다. os.system함수의 인자로 문자열을 주면, 해당 문자열을 터미널에 치는 것과 같은 결과가 나타나게 된다.


터미널 창에 mplayer 명령을 치는 것과 같은 효과가 있다.



 따라서 mplayer를 조종할 fifo 파일에 보낼 echo 명령도 os.system 함수를 통해 구현하면 된다. 그러나 코드안에서 mplayer를 실행시켰다 해도 mplayer가 실행되는 동안에는 코드가 os.system("mplayer ...")의 다음 줄로 넘어가지 못한다. 따라서 mplayer를 실행시키는 동안 스레드를 통해 echo 명령을 내려 mplayer를 조종하도록 구현하겠다.



이를 바탕으로 인터넷 라디오 스트리머를 구현해 보았다.

curNum = 0

channelLink = ["mms://211.181.136.136/livefm", "mms://114.108.140.39/magicfm_live",\
				"mms://live.febc.net/LiveFm","mms://vod.ysmbc.co.kr/YSFM",\
				"mms://121.254.230.3/FMLIVE","mms://210.96.79.102/Incheon"]
channelName = ["MBC", "SBS","SeoulFBEC","YeosooMBC","JIBS","TBN"]
cad.lcd.write('CH : '+channelName[curNum])

path = '/tmp/mplayer-control'
pin = -1
remote = -1
mute = False
play = True
volume = 50

def radioMainFunc():
	global pin
	global remote
	global volume
	global play
	global mute
	
	f = open(path,'w')
	if mute:
		f.write('volume 0 1\n')
	else:
		f.write('volume '+ str(volume) +' 1\n')
	f.close()
	
	play = True;
	curCh = 0
	cad.lcd.clear()
	writeBottomLine()
	cad.lcd.write('CH : '+channelName[curCh])

	while True:
		showTime()
		# play control
		if pin == 2 or remote == 2:		# pause and unpause
			os.system('echo \"pause\" > /tmp/mplayer-control')
			if play:
				play = False;
			else:
				play = True;
			writeBottomLine()
			pin = -1
			remote = -1
		elif pin == 3 or remote == 3:	# next channel
			curCh = (curCh + 1) % len(channelLink)
			os.system('echo \"loadfile '+channelLink[curCh] +'\" > /tmp/mplayer-control')
			cad.lcd.clear()
			writeBottomLine()
			cad.lcd.write('CH : '+channelName[curCh])
			pin = -1
			remote = -1
		elif pin == 1 or remote == 1:	# prev channel
			if curCh == 0:
				curCh = len(channelLink)-1
			else:
				curCh -= 1
			os.system('echo \"loadfile '+channelLink[curCh] +'\" > /tmp/mplayer-control')
			cad.lcd.clear()
			writeBottomLine()
			cad.lcd.write('CH : '+channelName[curCh])
			pin = -1
			remote = -1
		# volume control
		elif pin == 6 or remote == 6:	# volume down
			while True:
				volume -= 3
				if volume < 0:
					volume = 0
				os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
				updateVolume();
				sleep(0.2)
				remote = -1
				if not cad.switches[6].value:
					break
			pin = -1
		elif pin == 7 or remote == 7:	# volume up
			while True:
				volume += 3
				if volume > 100 :
					volume = 100
				os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
				updateVolume();
				sleep(0.2)
				remote = -1
				if not cad.switches[7].value:
					break
			pin = -1
		elif pin == 5 or remote == 5:	# mute
			if mute:
				os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
				mute = False;
			else:
				os.system('echo \"volume 0 1\" > /tmp/mplayer-control')
				mute = True;
			updateVolume();
			pin = -1
			remote = -1
		elif pin == 4 or remote == 4: 
				pin = -1
				remote = -1
				os.system('echo \"quit\" > /tmp/mplayer-control')
				return

main = threading.Thread(target=radioMainFunc)
main.start()

os.system('mplayer -slave -input file='+path+' '+channelLink[0])

 radioMainFunc() 이외의 함수는 저번 음악플레이어를 만들었을 때 사용한 함수들을 그대로 사용하였다. 인터럽트 또한 이전과 같은 방식으로 작성하고 사용하였다. PiFace CAD의 버튼과 리모콘도 거의 같은 역할을 한다. 달라진 점이라고는 스레드를 사용한 것과 mplayer를 조종할 때 fifo파일과, echo 명령을 사용한다는 것이다.


인터럽트 반환 값이 2일 때 : echo "pause" > [path]  명령을 통해 일시정지 및 재생

1,3일 때 : echo "loadfile" [url] > [path] 명령을 통해 이전채널, 다음채널 스트리밍

5,6,7일 때 : echo "volume" <value> 1  > [path] 명령을 통해 볼륨 조정(5: 음소거 및 해제, 6: 감소, 7: 증가)

4  일 떄 : echo "quit"] > [path]  명령을 통해 mplayer 종료




 이 코드와 저번에 작성한 음악플레이어 코드를 병합 및 수정하여 라디오와 음악플레이어를 선택하여 들을 수 있는 플레이어를 구현하였다.

from pygame import mixer # Load the required library
import pifacecad
import time
import datetime
import threading
import os


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)

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

# radio
path = '/tmp/mplayer-control'
channelLink = ["mms://211.181.136.136/livefm", "mms://114.108.140.39/magicfm_live",\
				"mms://live.febc.net/LiveFm","mms://vod.ysmbc.co.kr/YSFM",\
				"mms://121.254.230.3/FMLIVE","mms://210.96.79.102/Incheon"]
channelName = ["MBC", "SBS","SeoulFBEC","YeosooMBC","JIBS","TBN"]


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

def update_pin_text(event):
	 global pin
	 pin = event.pin_num

def print_ir_code(event):
	 global remote
	 remote = int(event.ir_code)
	 
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)
	
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)
	if mute:
		cad.lcd.write('mute')
	else:
		cad.lcd.write(str(volume).rjust(4))
	
def updateVolume():
	global volume
	cad.lcd.set_cursor(2,1)
	if mute:
		cad.lcd.write('mute')
	else:
		cad.lcd.write(str(volume).rjust(4))
	
	
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)
	
	
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)
	
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();
					time.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();
					time.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
		
		
def radioMainFunc():	# Internet radio streaming player
	global pin
	global remote
	global volume
	global play
	global mute
	
	f = open(path,'w')
	if mute:
		f.write('volume 0 1\n')
	else:
		f.write('volume '+ str(volume) +' 1\n')
	f.close()
	
	play = True;
	curCh = 0
	cad.lcd.clear()
	writeBottomLine()
	cad.lcd.write('CH : '+channelName[curCh])

	while True:
		showTime()
		# play control
		if pin == 2 or remote == 2:		# pause and unpause
			os.system('echo \"pause\" > /tmp/mplayer-control')
			if play:
				play = False;
			else:
				play = True;
			writeBottomLine()
			pin = -1
			remote = -1
		elif pin == 3 or remote == 3:	# next channel
			curCh = (curCh + 1) % len(channelLink)
			os.system('echo \"loadfile '+channelLink[curCh] +'\" > /tmp/mplayer-control')
			cad.lcd.clear()
			writeBottomLine()
			cad.lcd.write('CH : '+channelName[curCh])
			pin = -1
			remote = -1
		elif pin == 1 or remote == 1:	# prev channel
			if curCh == 0:
				curCh = len(channelLink)-1
			else:
				curCh -= 1
			os.system('echo \"loadfile '+channelLink[curCh] +'\" > /tmp/mplayer-control')
			cad.lcd.clear()
			writeBottomLine()
			cad.lcd.write('CH : '+channelName[curCh])
			pin = -1
			remote = -1
		# volume control
		elif pin == 6 or remote == 6:	# volume down
			while True:
				volume -= 3
				if volume < 0:
					volume = 0
				os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
				updateVolume();
				time.sleep(0.2)
				remote = -1
				if not cad.switches[6].value:
					break
			pin = -1
		elif pin == 7 or remote == 7:	# volume up
			while True:
				volume += 3
				if volume > 100 :
					volume = 100
				os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
				updateVolume();
				time.sleep(0.2)
				remote = -1
				if not cad.switches[7].value:
					break
			pin = -1
		elif pin == 5 or remote == 5:	# mute
			if mute:
				os.system('echo \"volume '+ str(volume) +' 1\" > /tmp/mplayer-control')
				mute = False;
			else:
				os.system('echo \"volume 0 1\" > /tmp/mplayer-control')
				mute = True;
			updateVolume();
			pin = -1
			remote = -1
		elif pin == 4 or remote == 4: 	# quit
				pin = -1
				remote = -1
				os.system('echo \"quit\" > /tmp/mplayer-control')
				return
			

def mainFunc():
	global volume
	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()

	radioMain = threading.Thread(target=radioMainFunc)
	while True:
		musicMainfunc()
		radioMain = threading.Thread(target=radioMainFunc)
		os.mkfifo(path)
		radioMain.start()
		os.system('mplayer -slave -input file='+path+' '+channelLink[0])
		radioMain.join()
		os.remove(path)
	
mainFunc()


1. 이전 곡 & 이전 채널        <-  KEY_CHANNELDOWN

2. 재생 및 일시정지            <-  KEY_OK

3. 다음 곡 & 다음 채널        <-  KEY_CHANNELUP

4. 음악, 라디오 모드 변경     <-  KEY_MENU

5. 음소거 및 해제               <-  KEY_MUTE

6. 볼륨 낮추기                   <-  KEY_VOLUMEUP

7. 볼륨 올리기                   <-  KEY_VOLUMEDOWN


위와 같이 수정 하였다. 아래 데모를 보고 제대로 실행되는지 확인해 보자.








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