pygame开发音乐播放器 随机/循环/顺序播放功能异常求助
Pygame 音乐播放器功能异常修复
共性核心问题
三个异常的本质原因都是对pygame.mixer.music的接口逻辑不熟悉:mixer.music.play()是异步非阻塞调用,执行这行代码只会触发播放动作,不会等待歌曲播放完成就直接运行后续代码,导致所有依赖播放完成才能推进的逻辑全部提前执行,音频也会被后续的load操作反复覆盖无法正常输出。
分问题具体原因
- 随机播放无输出:调用play后立刻进入下一轮循环,反复加载新的音频路径覆盖当前播放队列,音频根本没有时间输出;同时
os.listdir()会读取路径下所有文件/文件夹,未做音频格式过滤时,加载非音频文件会直接静默失败。 - 循环播放询问提前触发:每轮循环刚调用play就给播放计数+1,不需要等歌曲播放完,几毫秒就能跑完设定的循环次数,直接触发后续的询问逻辑。
- 顺序播放直接终止:for循环瞬间遍历完所有歌曲路径,连续触发load和play,最后只会停在列表最后一首歌的加载状态(甚至因为加载太快直接退出),看起来就像循环没有执行。
修复后完整代码
import os import time import random from pygame import mixer # 支持的音频格式后缀 AUDIO_EXTS = ('.mp3', '.wav', '.flac', '.ogg', '.m4a') def dir_path(path): try: mixer.init() songs_list = [] lis = os.listdir(path) # 过滤非音频文件 for i in lis: file_path = os.path.join(path, i) if os.path.isfile(file_path) and i.lower().endswith(AUDIO_EXTS): songs_list.append(file_path) if not songs_list: print("指定路径下未找到可播放的音频文件") return shuffle = input('enable shuffling? y/n: ') if shuffle.lower() == 'y': played_index = [] play_minutes = float(input('play time in minutes: ')) t_end = time.time() + 60 * play_minutes while time.time() < t_end: # 所有歌都播过一轮就清空已播列表 if len(played_index) == len(songs_list): played_index.clear() rand_idx = random.randint(0, len(songs_list) - 1) if rand_idx not in played_index: played_index.append(rand_idx) mixer.music.load(songs_list[rand_idx]) mixer.music.play() # 等待当前歌曲播放完成/到达设定的总播放时长 while mixer.music.get_busy() and time.time() < t_end: time.sleep(0.1) mixer.music.stop() print('thanks for listening :)') elif shuffle.lower() == 'n': loop = input('enable looping? y/n: ') if loop.lower() == 'y': sl_num = 1 for idx, song_path in enumerate(songs_list): print(f'{sl_num}) {os.path.basename(song_path)}') sl_num += 1 sl_no = int(input('sl_no of the song: ')) loop_no = int(input('number of loops: ')) if 1 <= sl_no <= len(songs_list): loop_times = 0 while loop_times < loop_no: mixer.music.load(songs_list[sl_no - 1]) mixer.music.play() # 等当前这遍播完再计数 while mixer.music.get_busy(): time.sleep(0.1) loop_times += 1 # 所有循环次数跑完再询问 while True: conn = input('continue listening? y/n: ') if conn.lower() == 'y': dir_path(path) return elif conn.lower() == 'n': print('Thanks for listening :)') return else: print('invalid command') else: print(f'only {len(songs_list)} songs are available') elif loop.lower() == 'n': # 顺序播放,每首播完再切下一首 for song_path in songs_list: mixer.music.load(song_path) mixer.music.play() while mixer.music.get_busy(): time.sleep(0.1) print('thanks for listening :)') else: print('invalid command') else: print('invalid command') except KeyboardInterrupt: mixer.music.stop() print('Thanks for listening :)') if __name__ == "__main__": # 替换为实际歌曲目录路径 dir_path('song directory path')
修复点说明
- 新增音频后缀过滤逻辑,避免加载非音频文件导致播放失败
- 所有
play()调用后新增while mixer.music.get_busy()阻塞等待逻辑,确保当前歌曲播放完成后再执行后续逻辑 - 调整循环播放的计数时机,每遍歌曲完整播放完成后再给循环计数+1,询问逻辑挪到所有循环次数执行完成后触发
- 把模块导入挪到函数外部,避免重复调用函数时反复导入模块
- 修正了文件列表显示逻辑,只展示有效音频文件,过滤文件夹/无效文件
- 补全递归调用后的返回逻辑,避免多层函数调用残留导致逻辑错乱
内容的提问来源于stack exchange,提问作者FIRE BOLT
相关产品推荐
相关产品推荐

