python 音频可视化

  暂时记录。

  这里的简单原理就是获取声卡输入输出设备中的数据(注意驱动什么的没有问题,能用麦克风),然后 matplotlib 绘制出来,想要看到音乐的节奏振动就再 fft 一下。至于如何不断更新波形,matplotlib 有一个 animation 方法可以用(见下面第二种方法),但实际上我用了之后发现显示效果不如第一种(可能是姿势不对)。之前用 matlab 做的,也很不错。

  第一种方法(波形显示更流畅,代码参考这个视频):

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]) * 2 / (256 * 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]) * 2 / (256 * 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()

  

猜你喜欢

转载自www.cnblogs.com/darkchii/p/11827461.html