暂时记录。html
这里的简单原理就是获取声卡输入输出设备中的数据(注意驱动什么的没有问题,能用麦克风),而后 matplotlib 绘制出来,想要看到音乐的节奏振动就再 fft 一下。至于如何不断更新波形,matplotlib 有一个 animation 方法能够用(见下面第二种方法),但实际上我用了以后发现显示效果不如第一种(多是姿式不对)。以前用 matlab 作的,也很不错。python
21:58:43 更新,测试了一下对原始信号作平滑处理,发现效率十分低,彻底无法看效果,不过目前用的是本身实现的高斯滤波算法。。。算法
22:17:15 更新,由于 python 3.8 和 scipy 暂时不兼容,因此用不了scipy 对信号作平滑处理,不过网上找了一段代码,效率不错,这是连接,或者直接把下面代码加到合适的地方。canvas
width = 20 box = np.ones(width) / width y_smooth = np.convolve(data_int, box, mode='same') yf = np.fft.fft(y_smooth) ...
23:27:12 更新,为了更加突出重要的频率,我又加了一些代码,就是把振幅大于平均值的那些振幅加倍,主要代码以下:api
y_vals = yf[:chunk] / (256 * chunk) ind = np.where(y_vals > np.mean(y_vals)) y_vals[ind[0]] *= 4 lf.set_ydata(y_vals)
第一种方法(波形显示更流畅,代码参考这个视频):dom
from _tkinter import TclError import pyaudio import numpy as np import matplotlib.pyplot as plt import struct channels = 1 rate = 44100 chunk = 1024 * 2 p = pyaudio.PyAudio() stream = p.open( format=pyaudio.paInt16, channels=channels, rate=rate, input=True, output=True, frames_per_buffer=chunk ) stream.start_stream() xf = np.linspace(0, rate, chunk) fig, ax = plt.subplots() lf, = ax.semilogx(xf, np.zeros(chunk), '-', lw=1) ax.set_xlim(20, rate / 2) ax.set_ylim(0, 1) plt.show(block=False) while stream.is_active(): data = stream.read(chunk) data_int = struct.unpack(str(chunk * 2) + 'B', data) yf = np.fft.fft(data_int) lf.set_ydata(np.abs(yf[:chunk]) / (128 * chunk)) try: ax.figure.canvas.draw() ax.figure.canvas.flush_events() except TclError: stream.stop_stream() stream.close() break
第二种方法:测试
import pyaudio import numpy as np # from scipy.fftpack import fft import matplotlib.pyplot as plt import struct from matplotlib.animation import FuncAnimation channels = 1 rate = 44100 chunk = 1024 * 2 p = pyaudio.PyAudio() stream = p.open( format=pyaudio.paInt16, channels=channels, rate=rate, input=True, output=True, ) stream.start_stream() x = np.arange(0, 2*chunk, 2) xf = np.linspace(0, rate, chunk) fig, (ax1, ax2) = plt.subplots(2) l, = ax1.plot(x, np.zeros(chunk), '-', lw=1) lf, = ax2.semilogx(xf, np.zeros(chunk), '-', lw=1) ax1.set_xlim(0, 2*chunk) ax1.set_ylim(0, 255) ax2.set_xlim(20, rate / 2) ax2.set_ylim(0, 1) plt.setp(ax1, xticks=[0, chunk, 2 * chunk], yticks=[0, 128, 255]) def gen(): while stream.is_active(): data = stream.read(chunk) data_int = struct.unpack(str(chunk*2) + 'B', data) data_np = np.array(data_int, dtype='b')[::2] + 128 yf = np.fft.fft(data_int) yield data_np, yf def init(): lf.set_ydata(np.random.rand(chunk)) return lf, def update(data): ax1.figure.canvas.draw() ax2.figure.canvas.draw() l.set_ydata(data[0]) lf.set_ydata(np.abs(data[1][:chunk]) / (128 * chunk)) return lf, animate = FuncAnimation(fig, update, gen, blit=True, interval=0.1, repeat=False, init_func=init) plt.show() stream.stop_stream() stream.close()