如何用pygame.mixer调整MP3播放速度?现有方案失效求解决
50%速度播放MP3并支持播放控制的解决方案
为什么修改pygame.mixer.init(frequency)无效
你尝试通过修改初始化采样率来变速的思路不对——pygame.mixer.music会自动将MP3的采样率重新采样到初始化的频率,这只是改变了音频的播放采样率,并不会改变播放速度或音调,所以无论怎么设置都不会有效果。
方案一:基于pygame.Sound+手动进度管理(无需额外依赖)
这个方案通过numpy处理音频变速,再用线程手动管理播放进度,实现暂停、停止、跳转功能:
1. 音频变速函数
import numpy as np import pygame def speed_change(sound: pygame.mixer.Sound, speed: float = 1.0) -> pygame.mixer.Sound: # 将音频转换为numpy数组 sound_array = np.frombuffer(sound.get_raw(), dtype=np.int16) # 计算变速后的数组长度 new_length = int(len(sound_array) / speed) # 线性插值实现变速 sound_array = np.interp( np.linspace(0, len(sound_array), new_length), np.arange(len(sound_array)), sound_array ).astype(np.int16) # 转换回pygame Sound对象 return pygame.mixer.Sound(sound_array.tobytes())
2. 播放控制逻辑
import threading import time # 初始化pygame mixer pygame.mixer.init() # 加载原始音频并生成变速版本 original_sound = pygame.mixer.Sound("track.mp3") slow_sound = speed_change(original_sound, 0.5) # 播放状态变量 current_pos = 0.0 is_playing = False is_paused = False def _play_loop(): """后台播放线程""" global current_pos, is_playing, is_paused channel = pygame.mixer.Channel(0) while is_playing: if is_paused: time.sleep(0.1) continue # 计算剩余播放时长 remaining = slow_sound.get_length() - current_pos if remaining <= 0: is_playing = False break # 从当前位置开始播放 channel.play(slow_sound, start=current_pos) start_time = time.time() # 跟踪播放进度,直到播放结束、被暂停或停止 while channel.get_busy() and is_playing and not is_paused: current_pos = time.time() - start_time + current_pos time.sleep(0.01) # 暂停时停止当前播放 if is_paused: channel.stop() # 对外暴露的控制函数 def start(): global is_playing, is_paused if not is_playing: is_playing = True is_paused = False threading.Thread(target=_play_loop, daemon=True).start() def pause(): global is_paused is_paused = True def resume(): global is_paused is_paused = False def stop(): global is_playing, is_paused, current_pos is_playing = False is_paused = False current_pos = 0.0 pygame.mixer.Channel(0).stop() def seek(seconds: float): global current_pos, is_paused # 确保跳转位置在有效范围内 current_pos = max(0.0, min(seconds, slow_sound.get_length())) # 如果正在播放,停止当前片段,线程会从新位置继续 if is_playing and not is_paused: pygame.mixer.Channel(0).stop() # 示例用法 if __name__ == "__main__": start() time.sleep(5) # 播放5秒 pause() time.sleep(2) # 暂停2秒 resume() time.sleep(3) # 继续播放3秒 seek(10) # 跳转到10秒位置 time.sleep(10) # 播放10秒 stop()
方案二:用pydub处理变速+pygame控制播放(更稳定的变速效果)
pydub提供了更成熟的音频变速处理,不需要手动写插值逻辑,但需要依赖ffmpeg:
1. 安装依赖
pip install pydub # 还需要安装ffmpeg,根据系统自行安装: # Windows: 下载ffmpeg并添加到环境变量 # macOS: brew install ffmpeg # Linux: sudo apt install ffmpeg
2. 实现代码
from pydub import AudioSegment import pygame import threading import time # 加载音频并变速(0.5倍速度) audio = AudioSegment.from_mp3("track.mp3") # speedup方法的playback_speed是倍数,0.5就是降速到一半 slow_audio = audio.speedup(playback_speed=0.5, chunk_size=150, crossfade=25) # 导出为WAV格式(pygame对WAV支持更好) slow_audio.export("slow_track_temp.wav", format="wav") # 初始化pygame并加载变速后的音频 pygame.mixer.init() slow_sound = pygame.mixer.Sound("slow_track_temp.wav") # 以下播放控制逻辑和方案一完全相同,直接复用start/pause/resume/stop/seek函数即可 # ...(复制方案一中的_play_loop和控制函数)
这个方案的优点是变速效果更自然,缺点是需要生成临时WAV文件,且依赖外部工具ffmpeg。
内容的提问来源于stack exchange,提问作者Simon Mayrshofer
相关产品推荐
相关产品推荐

