python音乐可视化
立即下载
资源介绍:
项目简介
MusicVisualizer 是一个基于 Python 的实时音乐可视化项目,旨在将音频数据转化为动态的视觉效果。通过结合 analyzer 库进行音乐分析和 pygame 库进行图形绘制,MusicVisualizer 能够实时显示音乐的声波和鼓点,使用户在听觉之外还能享受视觉上的盛宴。
项目原理
音乐分析:
使用 analyzer 库对输入的音频文件进行分析。
提取音频的关键特征,如声波形状和鼓点位置。
实时处理音频数据,确保可视化效果与音乐同步。
图形绘制:
利用 pygame 库创建一个图形窗口。
在窗口中动态绘制声波形状,根据音频频谱的变化显示不同的视觉效果。
通过鼓点检测,将鼓点转化为视觉上的高亮或其他特殊效果,增强音乐的节奏感。
项目特点
实时处理:MusicVisualizer 能够实时分析音频并动态显示声波和鼓点,保证视觉效果与音频同步。
直观界面:使用 pygame 提供简洁直观的图形界面,用户可以轻松观看音乐的可视化效果。
高扩展性:项目结构清晰,代码模块化设计,便于扩展和定制新的可视化效果。
欢迎大家下载使用。
import math
import matplotlib.pyplot as plt
import librosa.display
import numpy as np
# binary search
import pygame
def bin_search(arr, target):
# 初始化中间索引、最小索引和最大索引
index = int(len(arr) / 2)
min_index = 0
max_index = len(arr) - 1
found = False
# 如果目标值小于数组最小值,返回0
if target < arr[0]:
return 0
# 如果目标值大于数组最大值,返回数组长度减1
if target > arr[len(arr) - 1]:
return len(arr) - 1
# 循环直到找到目标值
while not found:
# 如果最小索引接近数组末尾,返回数组长度减1
if min_index == len(arr) - 2:
return len(arr) - 1
# 如果目标值在当前索引值和下一个索引值之间或等于当前索引值,返回当前索引
if arr[index] < target < arr[index + 1] or arr[index] == target:
return index
# 如果当前索引值大于目标值,更新最大索引
if arr[index] > target:
max_index = index
else:
# 否则更新最小索引
min_index = index
# 更新中间索引
index = int((min_index + max_index) / 2)
def rotate(xy, theta):
# 通过旋转矩阵在二维平面上旋转点
cos_theta, sin_theta = math.cos(theta), math.sin(theta)
# 返回旋转后的坐标
return (
xy[0] * cos_theta - xy[1] * sin_theta,
xy[0] * sin_theta + xy[1] * cos_theta
)
def translate(xy, offset):
# 根据偏移量平移点
return xy[0] + offset[0], xy[1] + offset[1]
def clamp(min_value, max_value, value):
# 将值限制在最小值和最大值之间
if value < min_value:
return min_value
if value > max_value:
return max_value
return value
class AudioAnalyzer:
# 音频分析器类,用于加载音频文件并进行频谱分析
def __init__(self):
# 初始化类实例的属性
self.frequencies_index_ratio = 0 # 频率索引比率
self.time_index_ratio = 0 # 时间索引比率
self.spectrogram = None # 频谱图,包含根据频率和时间索引的分贝值
def load(self, filename):
# 加载音频文件并生成频谱图
time_series, sample_rate = librosa.load(filename) # 从文件中获取音频信息
# 获取包含根据频率和时间索引的幅度值的矩阵
stft = np.abs(librosa.stft(time_series, hop_length=512, n_fft=2048*4))
self.spectrogram = librosa.amplitude_to_db(stft, ref=np.max) # 将矩阵转换为分贝矩阵
frequencies = librosa.core.fft_frequencies(n_fft=2048*4) # 获取频率数组
# 获取时间周期数组
times = librosa.core.frames_to_time(np.arange(self.spectrogram.shape[1]), sr=sample_rate, hop_length=512, n_fft=2048*4)
self.time_index_ratio = len(times)/times[len(times) - 1] # 计算时间索引比率
self.frequencies_index_ratio = len(frequencies)/frequencies[len(frequencies)-1] # 计算频率索引比率
def show(self):
# 显示频谱图
librosa.display.specshow(self.spectrogram,
y_axis='log', x_axis='time')
plt.title('spectrogram')
plt.colorbar(format='%+2.0f dB')
plt.tight_layout()
plt.show()
def get_decibel(self, target_time, freq):
# 根据给定的时间和频率获取分贝值
return self.spectrogram[int(freq*self.frequencies_index_ratio)][int(target_time*self.time_index_ratio)]
def get_decibel_array(self, target_time, freq_arr):
# 根据给定的时间和频率数组获取分贝值数组
arr = []
for f in freq_arr:
arr.append(self.get_decibel(target_time,f))
return arr
class AudioBar:
# 初始化音频条的属性
def __init__(self, x, y, freq, color, width=50, min_height=10, max_height=100, min_decibel=-80, max_decibel=0):
# 初始化音频分析器的基本属性
self.x, self.y, self.freq = x, y, freq
self.color = color
self.width, self.min_height, self.max_height = width, min_height, max_height
self.height = min_height
self.min_decibel, self.max_decibel = min_decibel, max_decibel
self.__decibel_height_ratio = (self.max_height - self.min_height)/(self.max_decibel - self.min_decibel)
# 更新音频条的高度
def update(self, dt, decibel):
# 计算期望的高度,基于当前的音量和高度比例
desired_height = decibel * self.__decibel_height_ratio + self.max_height
# 计算速度,基于期望高度和当前高度的差异
speed = (desired_height - self.height)/0.1
# 更新当前高度,基于计算的速度和时间差
self.height += speed * dt
# 确保当前高度在最小和最大高度之间
self.height = clamp(self.min_height, self.max_height, self.height)
# 在屏幕上渲染音频条
def render(self, screen):
pygame.draw.rect(screen, self.color, (self.x, self.y + self.max_height - self.height, self.width, self.height))
class AverageAudioBar(AudioBar):
"""
继承自AudioBar类,用于表示音频条的平均值。
"""
def __init__(self, x, y, rng, color, width=50, min_height=10, max_height=100, min_decibel=-80, max_decibel=0):
"""
初始化AverageAudioBar对象。
参数:
x (int): 音频条的x坐标。
y (int): 音频条的y坐标。
rng (range): 用于计算平均值的范围。
color (str): 音频条的颜色。
width (int): 音频条的宽度,默认为50。
min_height (int): 音频条的最小高度,默认为10。
max_height (int): 音频条的最大高度,默认为100。
min_decibel (int): 最小分贝值,默认为-80。
max_decibel (int): 最大分贝值,默认为0。
"""
# 调用父类的初始化方法,传递相关参数
super().__init__(x, y, 0, color, width, min_height, max_height, min_decibel, max_decibel)
# 设置随机数生成器
self.rng = rng
# 初始化平均值为0
self.avg = 0
def update_all(self, dt, time, analyzer):
"""
更新音频条的平均值。
参数:
dt (float): 时间间隔。
time (float): 当前时间。
analyzer (AudioAnalyzer): 音频分析器对象。
"""
# 初始化平均值为0
self.avg = 0
# 遍历范围中的每个元素,累加分析器获取的分贝值
for i in self.rng:
self.avg += analyzer.get_decibel(time, i)
# 计算平均值
self.avg /= len(self.rng)
# 更新数据
self.update(dt, self.avg)
class RotatedAverageAudioBar(AverageAudioBar):
# 继承自AverageAudioBar类,用于处理旋转的音频条
def __init__(self, x, y, rng, color, angle=0, width=50, min_height=10, max_height=100, min_decibel=-80, max_decibel=0):
# 初始化方法,设置旋转音频条的属性
super().__init__(x, y, 0, color, width, min_height, max_height, min_decibel, max_decibel)
self.rng = rng
self.rect = None
self.angle = angle
def render(self, screen):
# 在屏幕上绘制旋转音频条
pygame.draw.polygon(screen, self.color, self.rect.points)
def render_c(self, screen, color):
# 在屏幕上绘制旋转音频条,使用指定的颜色
pygame.draw.polygon(screen, color, self.rect.points)
def update_rect(self):
# 更新旋转音频条的矩形�