音楽プレイヤー『音律魔装《冥響輪舞》』 ソースコード

以下は『音律魔装《冥響輪舞》』のソースコード全文です:



        import tkinter as tk
        from tkinter import filedialog, messagebox
        import pygame.mixer
        import time
        import threading
        
        class MusicPlayer:
            def __init__(self, root):
                self.root = root
                self.root.title("音楽プレイヤー - 音律魔装《冥響輪舞》")
                
                pygame.mixer.init()
                
                self.file_path = ""
                self.play_count = 1
                self.current_play = 0
                self.is_playing = False
                self.is_paused = False
                self.pause_pos = 0  # 一時停止位置を記録
                
                self.label = tk.Label(root, text="音楽ファイルを選択してください", font=("Arial", 12))
                self.label.pack(pady=10)
                
                self.select_button = tk.Button(root, text="ファイルを選択", command=self.load_file)
                self.select_button.pack()
                
                self.count_label = tk.Label(root, text="再生回数 (1-100):")
                self.count_label.pack()
                
                self.count_entry = tk.Entry(root)
                self.count_entry.pack()
                self.count_entry.insert(0, "1")
                
                self.play_button = tk.Button(root, text="再生", command=self.start_playback)
                self.play_button.pack()
                
                self.pause_button = tk.Button(root, text="一時停止", command=self.pause_music, state=tk.DISABLED)
                self.pause_button.pack()
                
                self.stop_button = tk.Button(root, text="再生終了", command=self.stop_playback, state=tk.DISABLED)
                self.stop_button.pack()
                
                self.status_label = tk.Label(root, text="", font=("Arial", 12))
                self.status_label.pack(pady=10)
                
                # ウィンドウを閉じる処理を追加
                self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
            
            def load_file(self):
                self.file_path = filedialog.askopenfilename(filetypes=[("Audio Files", "*.mp3;*.aac")])
                if self.file_path:
                    self.label.config(text=f"選択されたファイル: {self.file_path.split('/')[-1]}")
            
            def start_playback(self):
                if not self.file_path:
                    messagebox.showwarning("警告", "ファイルを選択してください")
                    return
                
                try:
                    self.play_count = int(self.count_entry.get())
                    if self.play_count < 1 or self.play_count > 100:
                        raise ValueError
                except ValueError:
                    messagebox.showerror("エラー", "再生回数は1から100の間で入力してください")
                    return
                
                self.play_button.config(state=tk.DISABLED)
                self.pause_button.config(state=tk.NORMAL)
                self.stop_button.config(state=tk.NORMAL)
                
                self.is_playing = True
                self.is_paused = False
                threading.Thread(target=self.play_loop, daemon=True).start()
            
            def play_loop(self):
                while self.is_playing and self.current_play < self.play_count:
                    if self.is_paused:
                        time.sleep(0.5)
                        continue
                    
                    pygame.mixer.music.load(self.file_path)
                    pygame.mixer.music.play(start=self.pause_pos)
                    self.update_status()
                    
                    while pygame.mixer.music.get_busy() and self.is_playing:
                        if self.is_paused:
                            pygame.mixer.music.pause()
                            while self.is_paused and self.is_playing:
                                time.sleep(0.5)
                            pygame.mixer.music.unpause()
                        time.sleep(0.5)
                    
                    if not self.is_paused and self.is_playing:
                        self.current_play += 1
                        self.pause_pos = 0  # 曲の最後まで再生したらリセット
                        self.update_status()
                    
                    if not self.is_playing:
                        break
                
                self.play_button.config(state=tk.NORMAL)
                self.pause_button.config(state=tk.DISABLED)
                self.stop_button.config(state=tk.DISABLED)
                self.is_playing = False
                self.update_status()
            
            def pause_music(self):
                if self.is_paused:
                    self.is_paused = False
                    self.pause_button.config(text="一時停止")
                else:
                    self.pause_pos = pygame.mixer.music.get_pos() / 1000.0  # ミリ秒単位を秒に変換
                    self.is_paused = True
                    self.pause_button.config(text="一時停止解除")
            
            def stop_playback(self):
                self.is_playing = False
                pygame.mixer.music.stop()
                self.pause_pos = 0  # 完全に停止したら位置をリセット
                self.play_button.config(state=tk.NORMAL)
                self.pause_button.config(state=tk.DISABLED)
                self.stop_button.config(state=tk.DISABLED)
                self.update_status()
            
            def update_status(self):
                remaining = max(self.play_count - self.current_play, 0)
                self.status_label.config(text=f"再生中: {self.current_play}/{self.play_count} 回 残り: {remaining} 回")
            
            def on_closing(self):
                """ウィンドウを閉じたときにプログラムを完全に終了"""
                self.is_playing = False
                pygame.mixer.music.stop()
                self.root.destroy()
        
        if __name__ == "__main__":
            root = tk.Tk()
            app = MusicPlayer(root)
            root.mainloop()