123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- from mpl_toolkits.mplot3d import Axes3D
- import pyaudio
- import numpy as np
- import matplotlib.pyplot as plt
- import struct
- from scipy.signal import detrend
- from _tkinter import TclError
- from matplotlib.animation import FuncAnimation
- from pydub import AudioSegment
- from matplotlib.collections import LineCollection
- class AudioVisualize(object):
- def __init__(self, filename: str = None, rate=1., delay=4.):
- p = pyaudio.PyAudio()
- self.record_delay = delay
- if filename is None:
- self.channels = 1
- self.rate = 48000
- self.window = int(self.rate * 0.02)
- self.fwhm = 20
- self.stream = p.open(
- format=pyaudio.paInt16,
- channels=self.channels,
- rate=self.rate,
- input=True,
- )
- else:
- sound = AudioSegment.from_file(filename)
- self.left = sound.split_to_mono()[0]
- self.size = len(self.left.get_array_of_samples())
- self.rate = self.left.frame_rate
- self.window = int(self.rate * 0.02)
- self.stream = p.open(
- format=p.get_format_from_width(self.left.sample_width),
- channels=self.left.channels,
- rate=int(self.rate * rate),
- output=True,
- )
- self.stream.start_stream()
- def audio_visualize_1d(self):
- xf = np.linspace(20, self.rate / 2, self.window)
- fig, ax = plt.subplots(figsize=(14, 5))
- lf, = ax.semilogx(xf, np.zeros(self.window), lw=1, color='lightblue')
- ax.set_ylim(-0.5, 1.5)
- ax.set_axis_off()
- plt.show(block=False)
- plt.pause(self.record_delay)
- while self.stream.is_active():
- data = self.stream.read(self.window)
- data_int = struct.unpack(str(self.window * 2) + 'B', data)
- y_detrend = detrend(data_int)
- box = np.ones(self.fwhm) / self.fwhm
- y_smooth = np.convolve(y_detrend, box, mode='same')
- yft = np.abs(np.fft.fft(y_smooth))
- y_vals = yft[:self.window] / (64 * self.window)
- ind = np.where(y_vals > (np.max(y_vals) + np.min(y_vals)) / 2)
- y_vals[ind[0]] *= 4
- lf.set_ydata(y_vals)
- try:
- ax.figure.canvas.draw()
- ax.figure.canvas.flush_events()
- except TclError:
- self.stream.stop_stream()
- self.stream.close()
- break
- def audio_visualize_2d(self):
- t = np.linspace(0, 2. * np.pi, self.window * 2)
- xf = np.cos(t)
- yf = np.sin(t)
- fig, ax = plt.subplots(figsize=(7, 7))
- lf, = ax.plot(xf, yf, lw=1, color='lightblue')
- ax.set_xlim(-3, 3)
- ax.set_ylim(-3, 3)
- ax.set_axis_off()
- plt.show(block=False)
- plt.pause(self.record_delay)
- while self.stream.is_active():
- data = self.stream.read(self.window)
- data_int = struct.unpack(str(self.window * 2) + 'B', data)
- y_detrend = detrend(data_int)
- yft = np.abs(np.fft.fft(y_detrend))
- y_vals = yft / (64 * self.window)
- ind = np.where(y_vals > (np.max(y_vals) + np.min(y_vals)) / 2)
- y_vals[ind[0]] *= 4
- lf.set_xdata(xf + y_vals * np.cos(t))
- lf.set_ydata(yf + y_vals * np.sin(t))
- try:
- ax.figure.canvas.draw()
- ax.figure.canvas.flush_events()
- except TclError:
- self.stream.stop_stream()
- self.stream.close()
- break
- def audio_visualize_3d(self):
- t = np.linspace(0, 2. * np.pi, self.window * 2)
- xf = np.cos(t)
- yf = np.sin(t)
- fig = plt.figure()
- ax = fig.gca(projection='3d')
- lf, = ax.plot(xf, yf, np.zeros(self.window * 2), lw=1, color='lightblue')
- ax.set_zlim(-0.2, 1.2)
- ax.set_axis_off()
- plt.show(block=False)
- plt.pause(self.record_delay)
- while self.stream.is_active():
- data = self.stream.read(self.window)
- data_int = struct.unpack(str(self.window * 2) + 'B', data)
- z_detrend = detrend(data_int)
- zf = np.abs(np.fft.fft(z_detrend))
- z_vals = zf / (64 * self.window)
- ind = np.where(z_vals > (np.max(z_vals) + np.min(z_vals)) / 2)
- z_vals[ind[0]] *= 4
- lf.set_xdata(xf)
- lf.set_ydata(yf)
- lf.set_3d_properties(z_vals)
- try:
- ax.figure.canvas.draw()
- ax.figure.canvas.flush_events()
- except TclError:
- self.stream.stop_stream()
- self.stream.close()
- break
- def music_visualize_1d(self):
- fig = plt.figure(facecolor='black')
- ax = fig.gca()
- norm = plt.Normalize(-1., 1.)
- lc = LineCollection([], cmap='cool', norm=norm)
- ax.set_ylim(-1.5, 1.5)
- ax.set_axis_off()
- time = np.linspace(0, 2 * np.pi, self.window)
- ax.add_collection(lc)
- plt.pause(self.record_delay)
- def update(frames):
- if self.stream.is_active():
- slice = self.left.get_sample_slice(frames, frames + self.window)
- self.stream.write(slice.raw_data)
- y = np.array(slice.get_array_of_samples()) / 30000
- points = np.array([np.cos(time), y]).T.reshape((-1, 1, 2)) # 控制曲线精细程度和振幅
- segments = np.concatenate([points[:-1], points[1:]], axis=1)
- lc.set_segments(segments)
- lc.set_array(y) # 控制颜色
- return lc,
- ani = FuncAnimation(fig, update, frames=range(0, self.size, self.window), interval=0, blit=True)
- plt.show()
- def music_visualize_2d(self):
- t = np.linspace(0, 2 * np.pi, self.window)
- fig = plt.figure(facecolor='black')
- ax = fig.gca(projection='polar')
- ax.set_axis_off()
- lf, = ax.plot(t, np.zeros(self.window), lw=1, color='lightblue')
- plt.pause(self.record_delay)
- def update(frames):
- if self.stream.is_active():
- slice = self.left.get_sample_slice(frames, frames + self.window)
- self.stream.write(slice.raw_data)
- y = np.array(slice.get_array_of_samples()) / 1000000
- # yft = np.abs(np.fft.fft(y)) / self.window
- lf.set_ydata(y)
- return lf,
- ani = FuncAnimation(fig, update, frames=range(0, self.size, self.window), interval=0, blit=True)
- plt.show()
- def music_visualize_3d(self):
- t = np.linspace(0, 2 * np.pi, self.window)
- x, y = np.cos(t), np.sin(t)
- fig = plt.figure()
- ax = fig.gca(projection='3d')
- ax.set_axis_off()
- lf, = ax.plot(x, y, np.zeros(self.window), lw=1, color='lightblue')
- lf2, = ax.plot(x, y, np.zeros(self.window), lw=1, color='orange')
- plt.pause(self.record_delay)
- def update(frames):
- if self.stream.is_active():
- slice = self.left.get_sample_slice(frames, frames + self.window)
- self.stream.write(slice.raw_data)
- z = np.array(slice.get_array_of_samples())
- zft = np.abs(np.fft.fft(z / max(z))) / (self.window * 4)
- lf.set_xdata(x)
- lf.set_ydata(y)
- lf.set_3d_properties(zft)
- lf2.set_xdata(x)
- lf2.set_ydata(y)
- lf2.set_3d_properties(z / 1000000)
- return lf, lf2,
- ani = FuncAnimation(fig, update, frames=range(0, self.size, self.window), interval=0, blit=True)
- plt.show()
|