暫時記錄。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()