Pythonで音楽を流し、ライトの色を変える。

音楽に合わせてライトの色を変えたら面白そうって思ったので、作ってみました。

#1. フローチャート
簡単に作りたいイメージをフローチャートにしてみた。
音楽をGUIで選んで、音楽を再生、ライトアップして、音楽が終わったら、ライトがフェードアウトして、終了するように作ります。
![Untitled Diagram.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176158/aa97d019-c0a6-ea85-3f09-7e37128c0833.png)

#2. codeの説明
コードについて分割して説明していきます。

##2-1 mp3ファイルの選択。
 mp3ファイルは、PySimpleGUIを使って選択します。下記のようなGUIを作成しました。ライトの色の変更を3,5,10秒間隔で変更できるようにラジオボタンも入れています。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176158/2029c2ff-a4d1-41e4-7d8e-65df892f2de6.png)

##2-2 音楽の再生
音楽を再生できるライブラリはいくつあったのですが、再生、停止ができるのが分かりやすかったのでpygame.mixerを使うことにしました。pygameのドキュメントがまとまっていてわかりやすかったので、リンク入れておきます。

http://westplain.sakuraweb.com/translate/pygame/Music.cgi#pygame.mixer.music.play

また、音楽が終わったらライトをフェードアウトしたかったので、mutagen.mp3を使って、音楽の長さを取得しています。取得する方法については、下記を参考にさせていただいています。

https://qiita.com/kon_yu/items/6a556b6411a7291a3333

##2-3 ライトの色の選択
ライトの色は、16進数のカラーコードをcsvファイルに入力し、その中からランダムで１つ色を選ぶようにしました。カラーコードをまとめているサイトがいくつかあり、ジャンルごとに色合いが違うので、曲に合わせてカラーを選択しやすいかなと思い、そうしています。私は、やわらかい音楽をよく聞くのでパステルカラーコードを入力しています。カラーコードのcsvは、下記のように記述しています。色が選択できたらyeelightを光らせるために、RGBごと色を分ける操作をしています。

![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176158/2886cfd7-58a4-bd97-b45f-7308b43c5046.png)

##2-4 ライトのフェードアウト
yeelightにフェードアウトの構文がなかったので作りました。brightの量をfor分を使って、徐々に下げて暗くし、最後にoffにするようにしています。wait timeは、何度か試してみて自然に消えるかなっていうところで、時間を決めています。

##2-5 code
コードは、下記のようになっています。不明点あれば、コメントいただけると幸いです。

```main.py
import yeelight
import time
#user module
import light_action
import work

#Set up 
#GUI
gui_class   = work.gui_operation() #instance

#sound
sound_class = work.sound() #instance

#Yeelight
ye_address = "IPアドレス"
light_action_class = light_action.light_up_rgb_color() #instance
light_action_class.address_set(ye_address) # light address set

# 1.music start 
file,action_term = gui_class.read_mp3_file()
music_time = sound_class.music_length(file)
sound_class.sound_play(file)

#2.Turn on light up
light_action_class.light_turn_on()

#3 Change the color
event_term = music_time // action_term
for i in range(int(event_term)):
    yee_R, yee_G,yee_B = light_action_class.rgb_select()
    light_action_class.rgb_random(yee_R,yee_G,yee_B)
    time.sleep(action_term)

#Turn off 
time.sleep(3)
sound_class.sound_stop()
light_action_class.fade_out()
light_action_class.light_turn_off()

```


```light_action.py
import yeelight
import csv 
from random import randint
import pandas as pd
import time

class light_up_rgb_color :
    # 初期処理
    def __init__(self) : 
        bulb_def = ""
        print("initilize")

    def address_set(self, ac_address) :
        self.bulb_def  = yeelight.Bulb(ac_address)        

    def light_turn_on(self) :
        self.bulb_def.turn_on()
        self.bulb_def.set_brightness(50)

    def light_turn_off(self) :
        self.bulb_def.turn_off()

    def rgb_random(self, r, g, b):
        self.bulb_def.set_rgb(r,g,b)
    
    def rgb_select (self):
        df = pd.read_csv('16進数で表示したcsvファイル', header=None)
        color_select = randint(0,df.size-1) # get ramdon number 
        color_row    = color_select // len(df.columns)
        color_column = color_select %  len(df.columns)
        color_code   = (df.iloc[color_row, color_column]) # select color code cell.
        
        # Extract RGB
        R_Hexa = color_code[1:3]
        G_Hexa = color_code[3:5]
        B_Hexa = color_code[5:7]
        # x16  => 10
        R_int = int(R_Hexa, 16)
        G_int = int(G_Hexa, 16)
        B_int = int(B_Hexa, 16)
        return R_int,G_int,B_int

    def fade_out (self):
        for i in range (50):
            bright_term = 50 // 50
            bright      = 50 - bright_term * i
            self.bulb_def.set_brightness(bright)
            time.sleep(0.05)
      
```

```work.py
import PySimpleGUI as sg
from mutagen.mp3 import MP3
import pygame.mixer

class gui_operation :
    def read_mp3_file(self):
        
        # GUI color select
        sg.change_look_and_feel('Light Blue 2')
        radio_dic = {
            '3': '3sec',
            '5': '5sec',
            '10': '10sec',
        }
        layout = [[sg.Text('Data'),
                sg.InputText(' file path',key='-file-'),
                sg.FilesBrowse('Read file', target='-file-', file_types=(('mp3 file', '.mp3'),))],
                [sg.Text('term')],
                [sg.Radio(item[1], key=item[0], group_id='0') for item in radio_dic.items()],
                [sg.Submit(), sg.Cancel()]
        ]
  
        # Make a window
        window = sg.Window('Charting', layout)#window title

        # Event operation
        while True:
            event, values = window.read() # Event read 
            if event in 'Submit': 
                Get_file = values['-file-'] # Get file path
                if values['3']  == True: sec = 3
                if values['5']  == True: sec = 5 
                if values['10'] == True: sec = 10
                if  Get_file == ' file path':
                    Get_file = 'NULL'
                break
            else:
                Get_file = 'NULL' # Get file path
                break
        window.close()
        return Get_file,sec

class sound :

    def music_length(self,path):
        try:
            audio = MP3(path)
            length = audio.info.length
            return length
        except:
            return None
            
    def sound_play(self,f):
        pygame.mixer.init()
        pygame.mixer.music.stop() 
        pygame.mixer.music.load(f) 
        pygame.mixer.music.play() 
    
    def sound_stop(self):
        pygame.mixer.music.stop() 


```