はじめに
この前、【Python】tkinterを使用して簡単なミュージックプレーヤーを作るで簡単なミュージックプレーヤーを作って本当に動くのか確認しました。今回は、スタート、スキップ、ストップの機能を持つミュージックプレーヤーをPythonで作ってみようと思います。
前回と同様、コントロール部分はTkinterで構成します。音を出すライブラリはpygameの方が細かい設定ができそうなので、今回はpygameにしました。
開発環境
- Windows 10
- Python 3.10.5
- Windows Media Player
プログラム
プログラムは以下です。
import tkinter
from tkinter import *
import tkinter as tk
import os
import glob
import random
import pygame
import threading
# グローバル
play_setteing = 0
title_order = 0
tune_order = 0
flag_start = False
flag_skip = False
lst_title = []
lst_title_rdm = []
def ButtonPush600_00(e):
MusicStart()
def ButtonPush600_01(e):
MusicSkip()
def ButtonPush600_02(e):
MusicStop()
# スタートボタンが押されたときに呼ばれるルーチン
def MusicStart():
print('MusicStart')
global flag_start
global play_setteing, title_order, tune_order
play_setteing = int(var100_00.get())
title_order = int(var200_00.get())
tune_order = int(var200_10.get())
global lst_title
lst_title = os.listdir('DataForMusicPlayer')
#exit()
if (play_setteing==0 and title_order==1):
global lst_title_rdm
lst_title_rdm = random.sample(lst_title, len(lst_title)) # シャッフルされたタイトルのリスト
flag_start = True
# スキップボタンが押されたときに呼ばれるルーチン
def MusicSkip():
print('MusicSkip')
global flag_skip
flag_skip = True
# ストップボタンが押されたときに呼ばれるルーチン
def MusicStop():
print('MusicStop')
global flag_start
flag_start = False
# スレッドで動くルーチン
def Operation():
print('Operation')
global flag_start
global flag_skip
global play_setteing, title_order, tune_order
global lst_title, lst_title_rdm
while(1):
if (flag_start==True):
if (play_setteing==0):
if (title_order==0):
for title in lst_title:
lst_tune = glob.glob('DataForMusicPlayer'+'\\'+title+'\\'+'*.mp3')
#exit()
if (tune_order==1):
random.shuffle(lst_tune)
for tune in lst_tune:
fn = os.path.basename(tune)
name_title, name_musician, name_tune = ExtractName(fn)
label300_01['text'] = name_title
label400_01['text'] = name_musician
label500_01['text'] = name_tune
#exit()
pygame.mixer.music.load(tune)
pygame.mixer.music.play(1)
while (pygame.mixer.music.get_busy()==True):
if (flag_skip==True or flag_start==False):
flag_skip = False
break
if (flag_start==False):
break
if (flag_start==False):
break
else:
for title in lst_title_rdm:
lst_tune = glob.glob('DataForMusicPlayer'+'\\'+title+'\\'+'*.mp3')
if (tune_order==1):
random.shuffle(lst_tune)
for tune in lst_tune:
fn = os.path.basename(tune)
name_title, name_musician, name_tune = ExtractName(fn)
label300_01['text'] = name_title
label400_01['text'] = name_musician
label500_01['text'] = name_tune
#exit()
pygame.mixer.music.load(tune)
pygame.mixer.music.play(1)
while (pygame.mixer.music.get_busy()==True):
if (flag_skip==True or flag_start==False):
flag_skip = False
break
if (flag_start==False):
break
if (flag_start==False):
break
else:
random.shuffle(lst_title)
lst_tune = glob.glob('DataForMusicPlayer'+'\\'+lst_title[0]+'\\'+'*.mp3')
random.shuffle(lst_tune)
tune = lst_tune[0]
fn = os.path.basename(tune)
name_title, name_musician, name_tune = ExtractName(fn)
label300_01['text'] = name_title
label400_01['text'] = name_musician
label500_01['text'] = name_tune
#exit()
pygame.mixer.music.load(tune)
pygame.mixer.music.play(1)
while (pygame.mixer.music.get_busy()==True):
if (flag_skip==True or flag_start==False):
flag_skip = False
break
print('pygame.mixer.music.get_busy() = ', pygame.mixer.music.get_busy())
else:
pygame.mixer.music.stop()
# タイトル名、ミュージシャン名、曲名を抽出
def ExtractName(fn):
sdot = fn.split('.')
subar = sdot[0].split('_')
name_title = subar[0]
name_musician = subar[1]
name_tune = subar[3]
return name_title, name_musician, name_tune
# pygame設定
pygame.mixer.init(frequency = 44100)
print('frequency = 44100')
# スレッド
thread1 = threading.Thread(target=Operation)
thread1.start()
#-- tkinter --
root = tkinter.Tk()
root.title('ミュージックプレーヤー')
frame_100 = Frame(root, pady=5, padx=5)
frame_200 = Frame(root, pady=5, padx=5)
frame_300 = Frame(root, pady=5, padx=5)
frame_300 = Frame(root, pady=5, padx=5)
frame_400 = Frame(root, pady=5, padx=5)
frame_500 = Frame(root, pady=5, padx=5)
frame_600 = Frame(root, pady=5, padx=5)
var100_00 = tkinter.IntVar()
var100_00.set(0)
# ラベル
label100_00 = tkinter.Label(frame_100, text="プレイ設定 ", font=("MS明朝", "14"))
# ラジオボタン
rdo100_00 = tkinter.Radiobutton(frame_100, value=0, variable=var100_00, text='下設定プレイ順 ', font=("MS明朝", "14"))
rdo100_01 = tkinter.Radiobutton(frame_100, value=1, variable=var100_00, text='ランダムプレイ ', font=("MS明朝", "14"))
label100_00.pack(side=tk.LEFT)
rdo100_00.pack(side = 'left')
rdo100_01.pack(side = 'left')
frame_100.pack(fill=tk.X, padx=2, pady=2)
var200_00 = tkinter.IntVar()
var200_00.set(0)
# ラベル
label200_00 = tkinter.Label(frame_200, text="プレイ順 ", font=("MS明朝", "14"))
# ラベル
label200_01 = tkinter.Label(frame_200, text="タイトル ", font=("MS明朝", "14"))
# ラジオボタン
rdo200_00 = tkinter.Radiobutton(frame_200, value=0, variable=var200_00, text='アルファベット順 ', font=("MS明朝", "14"))
rdo200_01 = tkinter.Radiobutton(frame_200, value=1, variable=var200_00, text='ランダム ', font=("MS明朝", "14"))
label200_00.pack(side = 'left')
label200_01.pack(side = 'left')
rdo200_00.pack(side = 'left')
rdo200_01.pack(side = 'left')
frame_200.pack(fill=tk.X, padx=2, pady=2)
var200_10 = tkinter.IntVar()
var200_10.set(0)
# ラベル
label200_10 = tkinter.Label(frame_200, text=" 曲順 ", font=("MS明朝", "14"))
# ラジオボタン
rdo200_10 = tkinter.Radiobutton(frame_200, value=0, variable=var200_10, text='リスト順 ', font=("MS明朝", "14"))
rdo200_11 = tkinter.Radiobutton(frame_200, value=1, variable=var200_10, text='ランダム ', font=("MS明朝", "14"))
label200_00.pack(side = 'left')
rdo200_00.pack(side = 'left')
rdo200_01.pack(side = 'left')
label200_10.pack(side = 'left')
rdo200_10.pack(side = 'left')
rdo200_11.pack(side = 'left')
frame_200.pack(fill=tk.X, padx=2, pady=2)
# ラベル
label300_00 = tkinter.Label(frame_300, text="タイトル ", font=("MS明朝", "14", 'bold'))
# ラベル
label300_01 = tkinter.Label(frame_300, text=" ", font=("MS明朝", "14"))
label300_00.pack(side = 'left')
label300_01.pack(side = 'left')
frame_300.pack(fill=tk.X, padx=2, pady=2)
# ラベル
label400_00 = tkinter.Label(frame_400, text="ミュージシャン ", font=("MS明朝", "14", 'bold'))
# ラベル
label400_01 = tkinter.Label(frame_400, text=" ", font=("MS明朝", "14"))
label400_00.pack(side = 'left')
label400_01.pack(side = 'left')
frame_400.pack(fill=tk.X, padx=2, pady=2)
# ラベル
label500_00 = tkinter.Label(frame_500, text="曲 ", font=("MS明朝", "14", 'bold'))
# ラベル
label500_01 = tkinter.Label(frame_500, text=" ", font=("MS明朝", "14"))
label500_00.pack(side = 'left')
label500_01.pack(side = 'left')
frame_500.pack(fill=tk.X, padx=2, pady=2)
#ボタン
button600_00 = tkinter.Button(frame_600, text="スタート", fg="white", bg="blue", height="1", width="20", font=("MS明朝", "14"))
#ボタン
button600_01 = tkinter.Button(frame_600, text="スキップ", fg="white", bg="green", height="1", width="20", font=("MS明朝", "14"))
#ボタン
button600_02 = tkinter.Button(frame_600, text="ストップ", fg="white", bg="orange", height="1", width="20", font=("MS明朝", "14"))
button600_00.pack(side=tk.LEFT, padx=5, pady=30)
button600_01.pack(side=tk.LEFT, padx=5, pady=30)
button600_02.pack(side=tk.LEFT, padx=5, pady=30)
frame_600.pack(fill=tk.X, padx=2, pady=2)
#ボタンのバインド
button600_00.bind("<Button-1>", ButtonPush600_00)
#ボタンのバインド
button600_01.bind("<Button-1>", ButtonPush600_01)
#ボタンのバインド
button600_02.bind("<Button-1>", ButtonPush600_02)
root.mainloop()
Tkinterで構成されたウィンドウ
実行すると下のようなウィンドウが表示されます。

機能を簡単に説明すると、ストップの状態のとき、プレイ設定で「下設定プレイ順」を選択した場合、スタートボタンを押したとき下の「プレイ順」と「曲順」の設定に従って実行されます。「ランダムプレイ」が選択された場合、タイトル、曲はランダムに実行されます。
スタートの状態で曲が実行されているとき、早く次の曲に変えたい場合、スキップボタンを押すと次の曲が開始されます。
プログラムの説明
プログラムを簡単に説明します。
今回のプログラムで割と重要なことは、スタートさせた後、必要に応じてストップやスキップをさせる必要があるので、別にスレッドを起動させてマルチスレッドを行うことです。そのスレッドで今スタートなのかストップなのか、またスキップをしなければならないのかをモニターして、ステータスに応じてコントロールします。
このプログラムを置くフォルダにDataForMusicPlayerというフォルダを作成し、この下に音楽用ファイル(mp3ファイル)を置きます。具体的な内容は下で説明します。
ライブラリpygame
このライブラリのいいと思うところは、スタートとストップができることです。他にもいろいろと細かい設定ができます。
インストールは以下のコマンドを実行します。
pip install pygame
ボタン操作
# スタートボタンが押されたときに呼ばれるルーチン
def MusicStart():
print('MusicStart')
global flag_start
global play_setteing, title_order, tune_order
play_setteing = int(var100_00.get())
title_order = int(var200_00.get())
tune_order = int(var200_10.get())
global lst_title
lst_title = os.listdir('DataForMusicPlayer')
#exit()
if (play_setteing==0 and title_order==1):
global lst_title_rdm
lst_title_rdm = random.sample(lst_title, len(lst_title)) # シャッフルされたタイトルのリスト
flag_start = True
# スキップボタンが押されたときに呼ばれるルーチン
def MusicSkip():
print('MusicSkip')
global flag_skip
flag_skip = True
スタートボタン、スキップボタン、ストップボタンが押されたときのルーチンです。それぞれで変数flag_startやflag_skipを設定します。
スレッドで動くルーチン
# スレッドで動くルーチン
def Operation():
print('Operation')
global flag_start
global flag_skip
global play_setteing, title_order, tune_order
global lst_title, lst_title_rdm
while(1):
if (flag_start==True):
if (play_setteing==0):
if (title_order==0):
for title in lst_title:
lst_tune = glob.glob('DataForMusicPlayer'+'\\'+title+'\\'+'*.mp3')
#exit()
if (tune_order==1):
random.shuffle(lst_tune)
for tune in lst_tune:
fn = os.path.basename(tune)
name_title, name_musician, name_tune = ExtractName(fn)
label300_01['text'] = name_title
label400_01['text'] = name_musician
label500_01['text'] = name_tune
#exit()
pygame.mixer.music.load(tune)
pygame.mixer.music.play(1)
while (pygame.mixer.music.get_busy()==True):
if (flag_skip==True or flag_start==False):
flag_skip = False
break
if (flag_start==False):
break
if (flag_start==False):
break
else:
for title in lst_title_rdm:
lst_tune = glob.glob('DataForMusicPlayer'+'\\'+title+'\\'+'*.mp3')
if (tune_order==1):
random.shuffle(lst_tune)
for tune in lst_tune:
fn = os.path.basename(tune)
name_title, name_musician, name_tune = ExtractName(fn)
label300_01['text'] = name_title
label400_01['text'] = name_musician
label500_01['text'] = name_tune
#exit()
pygame.mixer.music.load(tune)
pygame.mixer.music.play(1)
while (pygame.mixer.music.get_busy()==True):
if (flag_skip==True or flag_start==False):
flag_skip = False
break
if (flag_start==False):
break
if (flag_start==False):
break
else:
random.shuffle(lst_title)
lst_tune = glob.glob('DataForMusicPlayer'+'\\'+lst_title[0]+'\\'+'*.mp3')
random.shuffle(lst_tune)
tune = lst_tune[0]
fn = os.path.basename(tune)
name_title, name_musician, name_tune = ExtractName(fn)
label300_01['text'] = name_title
label400_01['text'] = name_musician
label500_01['text'] = name_tune
#exit()
pygame.mixer.music.load(tune)
pygame.mixer.music.play(1)
while (pygame.mixer.music.get_busy()==True):
if (flag_skip==True or flag_start==False):
flag_skip = False
break
print('pygame.mixer.music.get_busy() = ', pygame.mixer.music.get_busy())
else:
pygame.mixer.music.stop()
ここは別スレッドで動くルーチンです。先ほどの変数flag_startやflag_skipをモニターし、必要に応じて全体をコントロールします。
ファイル名の設定について
# タイトル名、ミュージシャン名、曲名を抽出
def ExtractName(fn):
sdot = fn.split('.')
subar = sdot[0].split('_')
name_title = subar[0]
name_musician = subar[1]
name_tune = subar[3]
return name_title, name_musician, name_tune
DataForMusicPlayerというフォルダの下にタイトル名のフォルダ、そしてその下にmp3ファイルという構成にしており、そのmp3ファイルからタイトルやミュージシャン、曲名を抽出するように作っています。
例えば
Eliane Elias_Bossa Nova Stories_01_The Girl From Ipanema.mp3
というファイル名です。今回はWindows Media Playerで生成しました。
Windows Media Playerを起動し、「整理」 - 「オプション」をクリックし、「音楽の取り込み」を選択します。
保存する場所などは、もちろん任意の場所でかまいません。

「ファイル名」をクリックし、以下のようにチェックを入れ、区切り記号を「_(下線)」にしてOKをクリックします。

すると先程のようなファイル名が構成されて生成されます。
ミュージシャン名フォルダ - タイトル名フォルダ - mpファイル、という構成で生成されるので、タイトル名フォルダ及びその下のmp3ファイルをDataForMusicPlayerの下にそっくりコピーします。
このあたりはあまり追及しないで作りました。もしかしたら他にもっと簡単なステップがあるかもしれません。
プログラムを実行したところ、確認した限りでは正常に動きました。手持ちのCDがかなりたくさんあり、毎回1枚ずつセットして聴いていて何だか面倒だなとずっと思っていました。
今はそれなりに快適に聴くことができるようになりました。