特定频率的简单 Pygame 音频

发布于 2024-12-10 23:37:39 字数 145 浏览 0 评论 0原文

如何使用 Pygame 中的音频创建永远流畅播放的 440 Hz 声音?我认为这应该很容易,但我不想使用任何愚蠢的文件来完成任务。这样做的最终目的是在按住某个键的同时演奏一个音符,正如我在另一个问题中所问的那样。任何帮助将不胜感激,因为我浪费了大量时间试图找到这个问题的答案。

How can I create a 440 Hz sound that plays smoothly forever using audio with Pygame? I assume this should be easy enough, but I don't want to use any stupid files to accomplish the task. The final intent of this is to play a note while a key is being held down as I have asked in another question. Any help would be greatly appreciated as I have wasted great quantities of time trying to find an answer to this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

随梦而飞# 2024-12-17 23:37:39

在收到太多的“ValueError:数组深度必须与混合器通道数匹配”和其他类似错误之后,我发现了这个工作示例 http://www.mail-archive.com/[电子邮件受保护]/msg16140.html。它正确生成可与立体声混音器配合使用的多维 16 位整数数组。下面的最小工作示例,大部分是从上一个链接中提取的,并添加了必要的 pygame 位。在 Python 2.7.2 中使用 pygame.ver '1.9.1release' 进行了测试。

此示例将在立体声设置中从一个扬声器播放 440 Hz 音调,并从另一个扬声器播放 550 Hz 音调。经过一番玩弄持续时间后,我发现如果将“持续时间”变量设置为除整数之外的任何值,声音循环中会弹出可听见的咔嗒声。

import pygame
from pygame.locals import *

import math
import numpy

size = (1366, 720)

bits = 16
#the number of channels specified here is NOT 
#the channels talked about here http://www.pygame.org/docs/ref/mixer.html#pygame.mixer.get_num_channels

pygame.mixer.pre_init(44100, -bits, 2)
pygame.init()
_display_surf = pygame.display.set_mode(size, pygame.HWSURFACE | pygame.DOUBLEBUF)


duration = 1.0          # in seconds
#freqency for the left speaker
frequency_l = 440
#frequency for the right speaker
frequency_r = 550

#this sounds totally different coming out of a laptop versus coming out of headphones

sample_rate = 44100

n_samples = int(round(duration*sample_rate))

#setup our numpy array to handle 16 bit ints, which is what we set our mixer to expect with "bits" up above
buf = numpy.zeros((n_samples, 2), dtype = numpy.int16)
max_sample = 2**(bits - 1) - 1

for s in range(n_samples):
    t = float(s)/sample_rate    # time in seconds

    #grab the x-coordinate of the sine wave at a given time, while constraining the sample to what our mixer is set to with "bits"
    buf[s][0] = int(round(max_sample*math.sin(2*math.pi*frequency_l*t)))        # left
    buf[s][1] = int(round(max_sample*0.5*math.sin(2*math.pi*frequency_r*t)))    # right

sound = pygame.sndarray.make_sound(buf)
#play once, then loop forever
sound.play(loops = -1)


#This will keep the sound playing forever, the quit event handling allows the pygame window to close without crashing
_running = True
while _running:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            _running = False
            break

pygame.quit()

After getting entirely too many "ValueError: Array depth must match number of mixer channels", and other similar errors, I discovered this working example http://www.mail-archive.com/[email protected]/msg16140.html. It properly generates a multi-dimensional 16 bit integer array that works with a stereo mixer. Minimum working example below, mostly lifted from the previous link with the necessary pygame bits thrown in. Tested in Python 2.7.2 with pygame.ver '1.9.1release'.

This example will play a 440 Hz tone out of one speaker and a 550 Hz tone out of the other speaker in a stereo setup. After a bit of playing with the duration I discovered that audible clicks will pop up in the sound loop if you set the "duration" variable to anything other than a whole number.

import pygame
from pygame.locals import *

import math
import numpy

size = (1366, 720)

bits = 16
#the number of channels specified here is NOT 
#the channels talked about here http://www.pygame.org/docs/ref/mixer.html#pygame.mixer.get_num_channels

pygame.mixer.pre_init(44100, -bits, 2)
pygame.init()
_display_surf = pygame.display.set_mode(size, pygame.HWSURFACE | pygame.DOUBLEBUF)


duration = 1.0          # in seconds
#freqency for the left speaker
frequency_l = 440
#frequency for the right speaker
frequency_r = 550

#this sounds totally different coming out of a laptop versus coming out of headphones

sample_rate = 44100

n_samples = int(round(duration*sample_rate))

#setup our numpy array to handle 16 bit ints, which is what we set our mixer to expect with "bits" up above
buf = numpy.zeros((n_samples, 2), dtype = numpy.int16)
max_sample = 2**(bits - 1) - 1

for s in range(n_samples):
    t = float(s)/sample_rate    # time in seconds

    #grab the x-coordinate of the sine wave at a given time, while constraining the sample to what our mixer is set to with "bits"
    buf[s][0] = int(round(max_sample*math.sin(2*math.pi*frequency_l*t)))        # left
    buf[s][1] = int(round(max_sample*0.5*math.sin(2*math.pi*frequency_r*t)))    # right

sound = pygame.sndarray.make_sound(buf)
#play once, then loop forever
sound.play(loops = -1)


#This will keep the sound playing forever, the quit event handling allows the pygame window to close without crashing
_running = True
while _running:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            _running = False
            break

pygame.quit()
温馨耳语 2024-12-17 23:37:39

440Hz 是什么样的声音? “440 Hz”有多种类型的波:正弦波、锯齿波、方波等。您可以用长笛演奏 A,这也可能算在内。

假设您想要一个正弦波,看起来您可以使用 pygame.sndarray.samples 生成一个 Sound 对象。 (我还没有测试过这个)您可以使用以下内容创建样本:

samples = [math.sin(2.0 * math.pi * frequency * t / sample_rate) for t in xrange(0, duration_in_samples)]

这希望是基本的正弦波东西。 频率是所需的频率,以Hz为单位。 sample_rate 是生成的音频中每秒的样本数:44100 Hz 是典型值。 duration_in_samples 是音频的长度。 (5 * 44100 == 5 秒,如果您的音频采样率为 44100 Hz。)

看起来您可能必须先将 samples 转换为 numpy.array传递到 pygame.sndarray.samples 。文档表明音频应与 pygame.mixer.get_init 返回的格式匹配,因此适当调整样本,但这是基本思想。 (mixer.get_init 将告诉您上面的 sample_rate 变量,以及您是否需要考虑立体声,以及是否需要调整波的幅度或移动它。 )

samples设置为整数个波长,并且它应该循环。

What kind of 440 Hz sound? There are many types of waves at "440 Hz": sine, saw, square, etc. You could have a flute playing an A, and that might count too.

Assuming you want a sine wave, it looks like you can generate a Sound object with pygame.sndarray.samples. (I haven't tested this) You can create the samples with:

samples = [math.sin(2.0 * math.pi * frequency * t / sample_rate) for t in xrange(0, duration_in_samples)]

This is hopefully basic sine wave stuff. frequency is the desired frequency, in Hz. sample_rate is the number of samples / second in the generated audio: 44100 Hz is a typical value. duration_in_samples is the length of the audio. (5 * 44100 == 5 seconds, if your audio is at a 44100 Hz sample rate.)

It looks like you might have to convert samples to a numpy.array before passing to pygame.sndarray.samples. The docs indicate that the audio should match the format returned by pygame.mixer.get_init, so adjust samples appropriately, but that's the basic idea. (mixer.get_init will tell you the sample_rate variable above, and whether you need to account for stereo, and if you need to adjust the amplitude of the wave or shift it.)

Make samples a integral number of waves long, and it should loop.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文