python实现环形可视化器,要求有波浪动效或者粒子特效,要求有频谱分析
时间: 2023-05-26 13:02:52 浏览: 130
实现过程:
1.导入相关库:
```python
import numpy as np
import pyaudio
import wave
import sys
import time
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
```
2.读取音频文件并将其转换为numpy数组
```python
file = 'music.wav'
with wave.open(file,'rb') as f:
params = f.getparams()
nchannels,sampwidth,framerate,nframes=f.getparams()[:4]
str_data = f.readframes(nframes)
#将波形数据转换成数组格式
wave_data = np.fromstring(str_data,dtype=np.int16)
#将数组调整为左右声道
if nchannels==2:
wave_data.shape=-1,2
wave_data=wave_data.T
else:
pass
```
3.计算频率
```python
#计算出采样周期对应的秒数
sample_duration = 1.0/framerate
#计算出采样点数对应的时间长度
time_seq = np.arange(0,nframes)*sample_duration
#对音频波形数据进行快速傅里叶变换,得到频谱数据
freq_seq = np.fft.fftfreq(nframes,sample_duration)
pidxs = np.where(freq_seq>0)
fft_freqs = freq_seq[pidxs]
#使用象限取反将FFT输出的第4象限移到第1象限,第3象限移到第2象限
fft_data = abs(np.fft.fft(wave_data))[pidxs]
fft_data[100:]
```
4.实现动效
```python
# 定义一个环形可视化类
class CircularVisualizer(object):
def __init__(self, fft_data, fft_freqs, fps=30, colors="bgyr"):
# 绘制帧率
self.fps = fps
# 绘制颜色
self.colors = colors
# 音频频率
self.fft_data = fft_data
# 音频位置
self.fft_freqs = fft_freqs
# 频谱数据长度
self.n = len(self.fft_data)
# 绘图范围
self.fig, self.ax = plt.subplots(subplot_kw=dict(projection='polar'))
# 设置极坐标中的0度位置
self.ax.set_theta_zero_location('E')
# 设置绘图范围
self.ax.set_ylim(0, np.amax(self.fft_data))
# 设置绘图数据
self.lines = [self.ax.plot([],[],c=c)[0] for c in self.colors]
# 设置坐标轴
self.ax.grid(False)
plt.axis('off')
# 定义动画
self.anim = FuncAnimation(self.fig, self.update, frames=range(self.n), init_func=self.init, blit=True)
# 初始化函数
def init(self):
for line in self.lines:
line.set_data([],[])
return self.lines
# 更新函数
def update(self, frame):
for i, line in enumerate(self.lines):
r = self.fft_data[frame][i]
theta = np.radians(self.fft_freqs[frame])
x = np.append(line.get_xdata(), theta)
y = np.append(line.get_ydata(), r)
line.set_data(x, y)
return self.lines
# 显示函数
def show(self):
plt.show()
```
5. 注意事项
由于是频域可视化,所以需要先对音频信号进行FFT变换得到频域数据,然后将数据转换成极坐标系坐标再进行展示
6. 完整代码:
```python
import numpy as np
import pyaudio
import wave
import sys
import time
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
file = 'music.wav'
with wave.open(file,'rb') as f:
params = f.getparams()
nchannels,sampwidth,framerate,nframes=f.getparams()[:4]
str_data = f.readframes(nframes)
#将波形数据转换成数组格式
wave_data = np.fromstring(str_data,dtype=np.int16)
#将数组调整为左右声道
if nchannels==2:
wave_data.shape=-1,2
wave_data=wave_data.T
else:
pass
#计算出采样周期对应的秒数
sample_duration = 1.0/framerate
#计算出采样点数对应的时间长度
time_seq = np.arange(0,nframes)*sample_duration
#对音频波形数据进行快速傅里叶变换,得到频谱数据
freq_seq = np.fft.fftfreq(nframes,sample_duration)
pidxs = np.where(freq_seq>0)
fft_freqs = freq_seq[pidxs]
#使用象限取反将FFT输出的第4象限移到第1象限,第3象限移到第2象限
fft_data = abs(np.fft.fft(wave_data))[pidxs]
fft_data[100:]
# 定义一个环形可视化类
class CircularVisualizer(object):
def __init__(self, fft_data, fft_freqs, fps=30, colors="bgyr"):
# 绘制帧率
self.fps = fps
# 绘制颜色
self.colors = colors
# 音频频率
self.fft_data = fft_data
# 音频位置
self.fft_freqs = fft_freqs
# 频谱数据长度
self.n = len(self.fft_data)
# 绘图范围
self.fig, self.ax = plt.subplots(subplot_kw=dict(projection='polar'))
# 设置极坐标中的0度位置
self.ax.set_theta_zero_location('E')
# 设置绘图范围
self.ax.set_ylim(0, np.amax(self.fft_data))
# 设置绘图数据
self.lines = [self.ax.plot([],[],c=c)[0] for c in self.colors]
# 设置坐标轴
self.ax.grid(False)
plt.axis('off')
# 定义动画
self.anim = FuncAnimation(self.fig, self.update, frames=range(self.n), init_func=self.init, blit=True)
# 初始化函数
def init(self):
for line in self.lines:
line.set_data([],[])
return self.lines
# 更新函数
def update(self, frame):
for i, line in enumerate(self.lines):
r = self.fft_data[frame][i]
theta = np.radians(self.fft_freqs[frame])
x = np.append(line.get_xdata(), theta)
y = np.append(line.get_ydata(), r)
line.set_data(x, y)
return self.lines
# 显示函数
def show(self):
plt.show()
# 创建一个环形可视化器对象
visualizer = CircularVisualizer(fft_data, fft_freqs)
# 显示可视化器
visualizer.show()
```
阅读全文