python 音頻可視化

  暫時記錄。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()
相關文章
相關標籤/搜索