pygame.mixer.Sound.play 是不规则的,虽然定期触发

Posted

技术标签:

【中文标题】pygame.mixer.Sound.play 是不规则的,虽然定期触发【英文标题】:pygame.mixer.Sound.play is irregular although fired regularly 【发布时间】:2016-12-25 12:19:10 【问题描述】:

我目前尝试每 x 毫秒重复一次声音 - 其中 x 取决于我通过套接字接收的 UDP 数据包 - 我决定为此使用 pygame。我使用这个 SO 答案每隔 x 毫秒重复一次:https://***.com/a/18954902/3475778

但现在我遇到了一个问题,即声音播放非常不规则,并做了一个问题仍然存在的最小工作示例:

import pygame
from pygame.locals import *

pygame.mixer.init()
sound = pygame.mixer.Sound('sound.wav')

def play_sound():
    sound.stop()
    sound.play()

pygame.init()
clock = pygame.time.Clock()

pygame.time.set_timer(USEREVENT+1, 200)

while True:
    # clock.tick(30)
    for event in pygame.event.get():
        if event.type == USEREVENT+1:
            play_sound()

这是我通过 Audacity 从脚本中记录的波形:

您会发现,出于某种原因,某些样本的播放时间比其他样本长。对于我想要构建的某种节拍器来说不是很好。

编辑更新: 不是pygame.time.set_timer的问题,因为这段代码没有解决问题,不依赖pygame.time.set_timer:

import pygame
from datetime import datetime

d = datetime.now()

pygame.mixer.init()
sound = pygame.mixer.Sound('horn_short.wav')

pygame.init()

while True:
    if (datetime.now() - d).total_seconds() > 0.2:
        sound.play()
        d = datetime.now()

有同样的问题。问题也在 Ubuntu 16.04、Python 3.5 64bit (Anaconda) 和新安装的 pygame 下。

【问题讨论】:

目前不在我的电脑上,但我猜如果pygame的计时器是建立在SDL的计时器上的,它的分辨率不是很好。尝试使用 python time 模块并在 while 循环中查询 time.time(),比较之前和当前时间,直到 x 毫秒过去。 感谢您的回复,我也有这个想法。我将在 pygame 存储库上提出问题。 这并不能解决问题,请参阅上面的更新。 我把print() 放在play_sound 中,对我来说这个功能是在正确的时间执行的,但是混音器在运行音乐时有问题。据我所知,混音器在单独的线程中运行声音,并且可能与线程通信存在问题。 问题不是声音延迟,问题是如果我每 200 毫秒发出一次声音,它会工作 10 次,但第 11 次需要 450 毫秒才能听到它。我现在已将常规定时内容的播放移至 simpleaudio,直到我在 PyGame 中对此进行了修复。 【参考方案1】:

这是一种替代方法的想法。 如果目标是定期播放声音, 如果您(动态地)将声音填充到所需的间隔长度,您可能会得到更好的结果, 然后简单地用Sound.play(loops=-1)循环它。

如果只有少数有效间隔,则最简单的方法可能是 存储专用的声音文件并加载相应的文件。

否则,pygame.sndarray 模块提供对 原始声音数据的numpy 数组,这使得它成为可能 动态生成所需长度的声音对象:

import pygame
import numpy


# Helper function
def getResizedSound(sound, seconds):

    frequency, bits, channels = pygame.mixer.get_init()

    # Determine silence value
    silence = 0 if bits < 0 else (2**bits / 2) - 1

    # Get raw sample array of original sound
    oldArray = pygame.sndarray.array(sound)

    # Create silent sample array with desired length
    newSampleCount = int(seconds * frequency)
    newShape = (newSampleCount,) + oldArray.shape[1:]
    newArray = numpy.full(newShape, silence, dtype=oldArray.dtype)

    # Copy original sound to the beginning of the
    # silent array, clipping the sound if it is longer
    newArray[:oldArray.shape[0]] = oldArray[:newArray.shape[0]]

    return pygame.mixer.Sound(newArray)


pygame.mixer.init()
pygame.init()

sound = pygame.mixer.Sound('sound.wav')

resizedSound = getResizedSound(sound, 0.2)
resizedSound.play(loops=-1)

while True:
    pass

仅使用 pygame(和 numpy),这种方法应该有很好的机会进行准确的回放。

【讨论】:

【参考方案2】:

如果我这样做的话,对我来说效果会更好:

pygame.mixer.pre_init(44100, -16, 2, 256)

在任何 pygame init 函数之前。

【讨论】:

【参考方案3】:

好的,您应该尝试使用其他方式加载声音:

pygame.mixer.music.load(file=file_directory str)

播放声音使用:

pygame.mixer.music.play(loops=*optional* int, start=*optional* float)

您的代码可能如下所示:

import pygame

pygame.init()
pygame.mixer.init()

sound = pygame.mixer.music.load('sound.wav')
def playSound():
    sound.pause()
    sound.play()

while True:
    pass

对我来说,效果更好,但我在 python 3.7.2 上。我不知道python 3.5,但是3.5和3.7.2之间没有太大区别。那应该可以!

【讨论】:

以上是关于pygame.mixer.Sound.play 是不规则的,虽然定期触发的主要内容,如果未能解决你的问题,请参考以下文章

财富的涵义

H5 文本属性

珊仑怖未耙耘阅

霸藕咽诎旧良采

懦忌嗣腾闭油馗

非俺毙刃滴汛筛