在 Pygame.mixer 的声音结束时防止 "popping"

Prevent "popping" at end of sound in Pygame.mixer

已解决 - 请参阅底部的解决方案。

使用pygame.mixer时,每次声音播放完毕(无论是在频道中排队,未排队但仍通过频道播放,还是直接通过Sound.play()播放),都会听到"popping" 可以听到噪音。有什么办法可以避免这种情况吗?

示例代码:

import math
import pygame
import array

pygame.mixer.init()

rawArr=[]
for i in range(41000):
    freq1=int(math.sin(i/220.0*math.pi*2)*32767.0)
    if i>40900: freq1=int(freq1*(41000-i)/100.0) #Solution - see Final Solution
    rawArr.append(freq1)

sndArr=array.array('h',rawArr)

snd=pygame.mixer.Sound(sndArr)

snd.play()

更新:淡出声音不会造成明显差异。通过对 fadeTime=1,10,100,200,1000maxTime=0,1,10,100,1000.

使用 mixer.fadeout(fadeTime)Sound.fadeout(fadeTime)Sound.play(0,maxTime,fadeTime) 进行测试

更新 2:mixer.stop()mixer.pause() 都没有移除爆音。

更新 3:通过缓慢降低音量来实现手动淡出对于足够慢的淡入淡出时间是有效的,但是对于小于大约 0.1 秒的淡入淡出时间是无效的。此外,在淡入淡出期间,有一系列更小的 "clicks",虽然比原来的更安静,但仍然可以听到并且比原来的 "popping" 数量更多。测试代码,在原代码末尾追加:

while snd.get_volume():
     snd.set_volume(snd.get_volume()-0.005)
     pygame.time.wait(5)

最终解决方案:感谢用户 msw,能够通过在原始音频数据中实施手动淡出来删除 "popping"。 if i>40900: freq1=int(freq1*(41000-i)/100.0) 被添加到生成循环中 - 这个大约 0.0024 秒的淡入淡出时间几乎是 "popping" 发生之前可以使用的最短时间。示例代码已更新为固定代码。

这被称为 "dread audio cliff of noise"。

当你有一个高于 0 的数字信号并且你突然将其切断时,波形必须直线下降到 0。正如处理模拟信号的人会告诉你的那样,数字悬崖已经(原则上)所有以某种幅度存在的频率。到达扬声器时,此过渡听起来像 "pop"。

几乎所有音频都经过母带处理,因此在样本结束时振幅逐渐衰减为零。如果您的样本没有此特征,请在播放时将样本淡化为零。正如 OP 所指出的,即使是 2.5 毫秒的淡入淡出也足以避免爆裂声。