我正在 matplotlib 中创建一个简单的频谱图
- 我想知道如何(或从哪里开始,以便学习)创建一个简单的光标跟踪器,告诉我图表峰值处的频率值。我试图重现的频谱图如下。红色的频谱标记是我想要实现的。
我想创建一个简单的可移动垂直标记,就像上面的那个,它告诉我播放声音的频率(在某个点测量我的图表上的 x 值的东西)。
- 我还想知道如何插入像上面那样的暂停按钮。这应该可以使整个屏幕可以随时暂停
当前解决方案
截至目前,我的程序如下图所示。这是我用python制作的一个简单的频谱图。
我的代码如下。如果有任何问题,请告诉我,因为我对 Stack Overflow 很陌生,使用这个网站对我来说非常陌生 - 我有很多东西要学!
Program: Spectrogram
"""
#preamble
import pyaudio, matplotlib.pyplot as plt, numpy as np, struct, sys
from scipy.fftpack import fft
#set constants
CHUNK = 1024 * 2 #samples per frame
FORMAT = pyaudio.paInt16 #audio format
CHANNELS = 1 #single channel for microphone
RATE = 44100 #samples per second
#create matplotlib figure and axes
fig, (ax, ax2) = plt.subplots(2, figsize=(10, 7))
p = pyaudio.PyAudio()
plt.ion()
#stream object to get data from microphone
stream = p.open(
format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
output=True,
frames_per_buffer=CHUNK
)
# variables for plotting
x = np.arange(0, 2 * CHUNK, 2) #samples for waveform
x_fft = np.linspace(0, RATE, CHUNK) #frequencies for spectrum
#create a line object with random data
line, = ax.plot(x, np.random.rand(CHUNK), 'b-', lw=1)
#create a semilog x line for spectrum
line_fft, = ax2.semilogx(x_fft, np.random.rand(CHUNK), 'b-', lw=1)
#axes formatting for waveform
ax.set_title('Audio Waveform')
ax.set_xlabel('Samples')
ax.set_ylabel('Volume')
ax.set_xlim(0, 2 * CHUNK)
ax.set_ylim(0, 255)
plt.setp(ax, xticks=[0, CHUNK, 2 * CHUNK], yticks=[0, 128, 255])
#axis formatting for spectrum
ax2.set_title('Audio Spectrum')
ax2.set_xlabel('Frequency (Hz)')
ax2.set_ylabel('Volume')
ax2.set_xlim(20, RATE/2)
ax2.set_ylim(0, 1.2)
#ax2.set_xticks(np.arange(50, 1000, 50))
#ax2.grid(True, which='both')
#show plot
plt.tight_layout()
plt.show(block=False)
# close stuff
def handle_close(evt):
sys.exit()
fig.canvas.mpl_connect('close_event', handle_close)
while True:
#binary data
data = stream.read(CHUNK, False)
#convert data to integers
data_int = struct.unpack(str(2 * CHUNK) + 'B', data)
#create np array and offset by 128
data_np = np.array(data_int, dtype='b')[::2] + 128
line.set_ydata(data_np)
#compute FFT and update line
y_fft = fft(data_int)
line_fft.set_ydata(np.abs(y_fft[0:CHUNK]) / (128 * CHUNK))
#update figure canvas
plt.pause(.0001)
plt.show()