Pycord开发Discord机器人:如何合并多段Wave音频实现同步播放?
问题:Discord语音频道多用户音频合成同步播放失败
我正在开发一款Discord机器人,使用Pycord库录制语音频道内的音频,每个用户的音频会生成独立文件。现在需要将这些音频合成为单个Wave文件,实现像Discord客户端那样多人同时说话的同步播放效果,但当前代码仅能完成音频叠加,实际只能听到一个音频流。
当前代码如下:
async def after_recording(self, sink: discord.sinks.WaveSink, channel: discord.VoiceChannel): audio_segments = [] for audio_data in sink.audio_data.values(): audio_data.file.seek(0) audio_segments.append(AudioSegment.from_file(audio_data.file)) # Determine the maximum duration of the audio files max_duration = max([len(segment) for segment in audio_segments]) # Pad the shorter audio files with silence for i, segment in enumerate(audio_segments): if len(segment) < max_duration: audio_segments[i] = segment + AudioSegment.silent(duration=max_duration - len(segment)) # Overlay the audio files overlaid_segment = audio_segments[0] for segment in audio_segments[1:]: overlaid_segment = overlaid_segment.overlay(segment) # Export the overlaid audio to a BytesIO object overlaid_bytes = BytesIO() overlaid_segment.export(overlaid_bytes, format='wav') overlaid_bytes.seek(0) # Send the overlaid audio as a message attachment to the specified channel await channel.send(file=discord.File(overlaid_bytes, filename='overlaid_audio.wav')) # Cleanup for audio_data in sink.audio_data.values(): audio_data.file.close()
注:代码由ChatGPT辅助生成,已多次审阅修改,是目前能找到的唯一类似解决方案,并非完全由AI生成。
解决方案
出现只能听到一个音频流的核心原因,大概率是各用户音频的采样率、声道数、位深不一致,导致overlay操作无法正确混合;另外AudioSegment.silent默认参数可能和原音频格式不匹配,填充的静音段格式不对也会干扰混合效果。
以下是修正后的代码,关键优化点已标注:
from pydub import AudioSegment import io import discord async def after_recording(self, sink: discord.sinks.WaveSink, channel: discord.VoiceChannel): audio_segments = [] # 先获取第一个音频的格式参数,统一后续所有音频的格式 first_audio = next(iter(sink.audio_data.values())) first_audio.file.seek(0) base_segment = AudioSegment.from_file(first_audio.file) sample_rate = base_segment.frame_rate channels = base_segment.channels sample_width = base_segment.sample_width audio_segments.append(base_segment) # 处理剩余音频,统一格式后加入列表 for audio_data in list(sink.audio_data.values())[1:]: audio_data.file.seek(0) segment = AudioSegment.from_file(audio_data.file) # 转换为统一格式:采样率、声道、位深与第一个音频一致 segment = segment.set_frame_rate(sample_rate).set_channels(channels).set_sample_width(sample_width) audio_segments.append(segment) # 计算最长音频时长 max_duration = max(len(seg) for seg in audio_segments) # 用匹配格式的静音填充短音频 silent_segment = AudioSegment.silent( duration=max_duration, frame_rate=sample_rate, channels=channels, sample_width=sample_width ) padded_segments = [] for seg in audio_segments: # 将原音频叠加到静音段上,保证时长一致且格式匹配 padded = silent_segment.overlay(seg) padded_segments.append(padded) # 混合所有音频(替代原有的逐个overlay,效率更高且效果更稳定) mixed_segment = padded_segments[0] for seg in padded_segments[1:]: # 使用"+"操作符实现音频混合,而非overlay(overlay是叠加到原音频的指定位置,"+"是直接混合) mixed_segment = mixed_segment + seg # 导出混合后的音频 mixed_bytes = io.BytesIO() mixed_segment.export(mixed_bytes, format='wav') mixed_bytes.seek(0) # 发送文件 await channel.send(file=discord.File(mixed_bytes, filename='mixed_audio.wav')) # 清理文件 for audio_data in sink.audio_data.values(): audio_data.file.close()
关键优化说明
- 统一音频格式:强制所有用户的音频转换为相同的采样率、声道数和位深,避免格式不兼容导致混合失败。
- 匹配格式的静音填充:生成与原音频格式一致的静音段,再将原音频叠加到静音段上,确保填充后的音频格式完全统一。
- 改用"+"操作符混合音频:
pydub中+操作符会直接将两个音频的波形数据相加(自动处理音量溢出),比overlay更适合多人语音的同步混合场景,overlay更适合将一段音频叠加到另一段的指定位置(比如背景音叠加)。
如果问题仍然存在,可以检查以下几点:
- 确认Pycord的
sink是否正确捕获了所有用户的音频数据,可以单独播放每个用户的音频文件验证。 - 调整混合后的音频音量,避免多个音频叠加后音量溢出导致失真或被截断。
- 尝试使用
pydub的AudioSegment.from_raw方法读取音频数据,确保解析格式正确。
内容的提问来源于stack exchange,提问作者ConchDev
相关产品推荐
相关产品推荐

