繁体   English   中英

如何在 pygame 中连续播放声音样本?

[英]How to play sound samples continuously in pygame?

我想播放一个连续的正弦波(暂时),它会根据鼠标指针 position(暂时)改变其频率(暂时)。 因此,我生成并播放一帧长度的波(下面代码中的 1/2 秒)。 产生的声音在声音中有很小的间隙,足以非常显着。 增加单个声音的持续时间没有帮助,改变缓冲区大小没有帮助,使用 dtick 而不是 dt 没有帮助。

有没有办法以这种方式实现连续的声音? 还是有什么其他方式?

谢谢

版本:Python 3.9.3、pygame 2.0.1

最小(仍然很长)代码:

import numpy as np
import pygame
from pygame import Color
from pygame.locals import KEYDOWN, KMOD_CTRL, QUIT, K_q

fade_out = np.linspace(1, 0, 100)
fade_in = np.linspace(0, 1, 100)

bits = 16
sample_rate = 44100
max_sample = 2 ** (bits - 1) - 1


def gen_sound(duration, freq):
    n_samples = int(duration / 1000 * sample_rate)
    buf = np.zeros((n_samples, 2), dtype=np.int16)
    buf[:, 0] = (
        0.25
        * max_sample
        * np.sin(2 * np.pi * freq[0] * np.arange(n_samples) / sample_rate)
    )
    buf[:, 1] = (
        0.25
        * max_sample
        * np.sin(2 * np.pi * freq[1] * np.arange(n_samples) / sample_rate)
    )
    buf[-100:, 0] = (buf[-100:, 0] * fade_out).astype(int)
    buf[-100:, 1] = (buf[-100:, 1] * fade_out).astype(int)
    buf[:100, 0] = (buf[:100, 0] * fade_in).astype(int)
    buf[:100, 1] = (buf[:100, 1] * fade_in).astype(int)

    return pygame.sndarray.make_sound(buf)


def main(argv: list = None):

    # initialize sound
    pygame.mixer.pre_init(sample_rate, -bits, 2, 512)

    # initialize pygame
    pygame.init()
    size = (1000, 800)
    surf = pygame.display.set_mode(size)
    surf.fill(Color("black"))
    clock = pygame.time.Clock()

    # frames per second and duration of a frame in ms
    FPS = 2
    dt = 1000 / FPS
    dtick = 1000 / FPS
    # position of the mouse pointer, None means outside of the window
    mpos = None

    # event loop
    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == QUIT:
                return
            # shutdown with C-q
            if e.type == KEYDOWN:
                if e.mod & KMOD_CTRL and e.key == K_q:
                    return

        if pygame.mouse.get_focused():
            mpos = pygame.mouse.get_pos()
        else:
            mpos = None

        freq = mpos if mpos else (440, 440)
        sound = gen_sound(dt, freq)
        sound.play(loops=0, fade_ms=0)

        pygame.display.update()
        dtick = clock.tick(FPS)


if __name__ == "__main__":
    main()

您可以在播放时直接修改Sound数据,无需每帧调用.play()

def gen_sound(buf, freq):
    buf[:, 0] = (
            0.25
            * max_sample
            * np.sin(2 * np.pi * freq[0] * np.arange(n_samples) / sample_rate)
    )
    buf[:, 1] = (
            0.25
            * max_sample
            * np.sin(2 * np.pi * freq[1] * np.arange(n_samples) / sample_rate)
    )

主要是:

def main(argv: list = None):
    # ...

    clock = pygame.time.Clock()

    buf = np.zeros((n_samples, 2), dtype=np.int16)
    sound = pygame.sndarray.make_sound(buf)
    buf = pygame.sndarray.samples(sound) # This is required because make_sound copies the array, but we want a reference
    gen_sound(buf, (440, 440))
    sound.play(loops=-1, fade_ms=0)

    # ...
    # event loop
    while True:
        # ...

        freq = mpos if mpos else (440, 440)
        gen_sound(buf, freq)

        pygame.display.update()
        dtick = clock.tick(FPS)

请注意,这将遇到此处描述和解决的问题,例如,正弦波转换不平滑。 但这超出了这个问题的 scope 和我的知识。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM