【Python】スタートボタン、スキップボタン、ストップボタンがあるミュージックプレーヤーを作る

はじめに

この前、【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で構成されたウィンドウ

実行すると下のようなウィンドウが表示されます。

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枚ずつセットして聴いていて何だか面倒だなとずっと思っていました。

今はそれなりに快適に聴くことができるようになりました。



© 2025 サニーサイド