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()
相关文章
相关标签/搜索