You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 02:45:50