【发布时间】:2017-09-07 06:26:25
【问题描述】:
下面我的代码将从麦克风获取输入,如果音频块的平均值超过某个阈值,它将生成音频块的频谱图(长 30 毫秒)。以下是正常对话中生成的频谱图的样子:
据我所见,考虑到音频及其环境,这看起来不像我期望的频谱图。我期待更像以下的东西(转置以节省空间):
我正在录制的麦克风是我的 Macbook 上的默认麦克风,有什么建议可以解决问题吗?
record.py:
import pyaudio
import struct
import math
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
THRESHOLD = 40 # dB
RATE = 44100
INPUT_BLOCK_TIME = 0.03 # 30 ms
INPUT_FRAMES_PER_BLOCK = int(RATE * INPUT_BLOCK_TIME)
def get_rms(block):
return np.sqrt(np.mean(np.square(block)))
class AudioHandler(object):
def __init__(self):
self.pa = pyaudio.PyAudio()
self.stream = self.open_mic_stream()
self.threshold = THRESHOLD
self.plot_counter = 0
def stop(self):
self.stream.close()
def find_input_device(self):
device_index = None
for i in range( self.pa.get_device_count() ):
devinfo = self.pa.get_device_info_by_index(i)
print('Device %{}: %{}'.format(i, devinfo['name']))
for keyword in ['mic','input']:
if keyword in devinfo['name'].lower():
print('Found an input: device {} - {}'.format(i, devinfo['name']))
device_index = i
return device_index
if device_index == None:
print('No preferred input found; using default input device.')
return device_index
def open_mic_stream( self ):
device_index = self.find_input_device()
stream = self.pa.open( format = pyaudio.paInt16,
channels = 1,
rate = RATE,
input = True,
input_device_index = device_index,
frames_per_buffer = INPUT_FRAMES_PER_BLOCK)
return stream
def processBlock(self, snd_block):
f, t, Sxx = signal.spectrogram(snd_block, RATE)
plt.pcolormesh(t, f, Sxx)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.savefig('data/spec{}.png'.format(self.plot_counter), bbox_inches='tight')
self.plot_counter += 1
def listen(self):
try:
raw_block = self.stream.read(INPUT_FRAMES_PER_BLOCK, exception_on_overflow = False)
count = len(raw_block) / 2
format = '%dh' % (count)
snd_block = np.array(struct.unpack(format, raw_block))
except Exception as e:
print('Error recording: {}'.format(e))
return
amplitude = get_rms(snd_block)
if amplitude > self.threshold:
self.processBlock(snd_block)
else:
pass
if __name__ == '__main__':
audio = AudioHandler()
for i in range(0,100):
audio.listen()
基于 cmets 的编辑:
如果我们将速率限制为 16000 Hz 并为颜色图使用对数刻度,则这是在麦克风附近轻敲的输出:
这在我看来仍然有些奇怪,但似乎也是朝着正确方向迈出的一步。
使用 Sox 并与我的程序生成的频谱图进行比较:
【问题讨论】:
-
您的频谱图包含许多非常高的频率。如果您将轴限制限制在与预期示例类似的范围内(例如,停止在 8000Hz)怎么办?颜色图也可能存在差异。
-
@BrenBarn 我在调用
signal.spectrogram时正在这样做,但是输出看起来仍然与现在产生的相似。我认为匹配它的采样音频和它用来生成频谱图的内容可能是目前最好的。但是,是的,我应该在最终结果中限制在这个范围内! -
尝试对颜色图使用对数刻度;例如类似
plt.pcolormesh(t, f, np.log(Sxx))。如果Sxx包含 0,您可能需要对其进行正则化。也许类似于np.log(1+Sxx)。 -
@WarrenWeckesser 实施建议的更改,我已经根据您的建议使用频谱图更新了问题。
-
您正在尝试制作 30 毫秒音频块的频谱图,这是可以认为是静止的时间。这是无意义的,因为频谱图是“声音或其他信号中频率频谱的视觉表示,因为它们随时间或其他变量而变化”(维基百科)。您可以在frank-zalkow.de/en/code-snippets/… 找到一些鼓舞人心的东西
标签: python numpy audio matplotlib scipy