我想用Python制作音频频谱分析仪。我使用了pyaudio库,正在从麦克风中读取流。每次读取,我得到4410个值,我使用numpy将其转换为数字,然后将它们绘制到pygame屏幕上。看起来像这样:https://photos.google.com/share/AF1QipMCWVk1pR0dmrrsTlpE3gHQ9GTUV25MqwUxw4JuW8TrItkGkuU9X3ZpY2ZQ-RLHew?key=UE9Id19IU1dtSHZfUk43TjB3SWxFcVhRRTFYOWFB(图形上下颠倒)
我拥有的代码是这样的:
import pyaudio, math, struct,pygame, numpy
pa = pyaudio.PyAudio()
#open audio stream
stream = pa.open(input_device_index=1,rate=44100,format=pyaudio.paInt16,channels=2,input=True)
#read bytes from stream and convert to numbers
def get_data():
data = stream.read(int(44100*0.05))
s = numpy.fromstring(data, numpy.int16)
return struct.unpack('h'*4410, data)
pygame.init()
screen = pygame.display.set_mode((4000,1000))
def redraw():
data = get_data()
#draw every number as a bar onto pygame windows
#last 4410 values are missin
for x in range(4000):
val = data[x]
pygame.draw.rect(screen,(0,0,0),(x,0,1,1000),0)
pygame.draw.rect(screen,(255,255,255),(x,0,1,val),0)
pygame.display.update()
pygame.event.clear()
while 1:
redraw()
有没有什么花哨的方法可以将这4410个值合并为15个,所以我可以在合理大小的窗口中放置漂亮的绿色和红色条形图形,而不是需要3个屏幕的丑陋图形?
最佳答案
频域与时域
在编写时,您的代码绘制了样本的time-domain表示,而频谱分析仪则是frequency domain表示。
可以使用Discrete Fourier Transform实现时频域转换。实际上,您需要在转换之前将Window function应用于数据。
DFT的输出是一系列大小相等的频点,每个频点包含一个实部和虚部。频谱分析仪通常具有感知宽度相等的频段-即相等数量的 Octave 音阶(或 Octave 音阶的分数)。因此,每个频段中的频段将是之前频段的两倍。 15个频段相当于每个频段的2/3倍频程。
图形输出说明
您已经绘制了时域样本,每个样本水平使用一个像素,并将幅度直接映射到Y坐标。由于幅度范围是-32767 < x < 32768
,因此绝大多数样本将小于或大于显示屏中提供的范围0 <= x < 4000
-因此,大多数样本将被裁剪为0
或3999
。
您可以通过缩放样本以使其适合并通过500
对结果进行偏差来纠正此问题,以便在0
的Y坐标处呈现500
的样本值。
关于python - 音频频谱分析仪(4410个值,成15条),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44478845/