2011-10-19 65 views
6

如何创建一个440赫兹的声音,可以在Pygame中永久使用音频播放?我认为这应该很容易,但我不想使用任何愚蠢的文件来完成任务。最后一个意图是当一个关键被阻止时弹奏一个音符,正如我在另一个问题中提出的那样。任何帮助将不胜感激,因为我浪费了大量的时间试图找到答案。简单的Pygame音频频率

回答

3

什么样的440赫兹的声音? “440赫兹”有许多类型的波:正弦波,锯齿波,方波波等。你可以用长笛演奏A,这也可以算得上。

假设你想要一个正弦波,它看起来像你可以用pygame.sndarray.samples生成一个声音对象。 (我没有测试过这一点)你可以创建样本:

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

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

看起来你可能传递到pygame.sndarray.samples之前samples转换为numpy.array。文档指出音频应与pygame.mixer.get_init返回的格式相匹配,因此适当调整samples,但这是基本思路。 (mixer.get_init会告诉你sample_rate变量上,以及是否需要考虑音响,如果你需要调整波的振幅或移位了。)

samples波的整数倍长,它应循环。

+0

我该如何让声音永远播放? – Paul

+0

通过告诉它在您播放时永久循环。你有没有试过阅读文档? (pygame.org/docs)具体来说,你想要http://pygame.org/docs/ref/mixer.html#Sound.play – Thanatos

6

得到完全太多的“ValueError:阵列深度必须匹配混频器通道数量”和其他类似的错误后,我发现了这个工作示例http://www.mail-archive.com/[email protected]/msg16140.html。它可以正确生成一个多维16位整数阵列,可以与立体声混音器配合使用。下面的最小工作示例,主要是从前面的链接中提取出必要的pygame位。通过pygame.ver'1.9.1release'在Python 2.7.2中测试。

本示例将在立体声设置中播放一个扬声器中的440 Hz音调和另一个扬声器中的550 Hz音调。经过一段时间的演奏后,我发现如果将“duration”变量设置为除整数以外的任何其他值,声音循环中将弹出可听到的喀嗒声。

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()