ZIPpython音乐可视化BOB2009100922.25MB需要积分:1立即下载资源文件列表: music_visual.zip 大约有6个文件 music_visual/ music_visual/1.wav 25.1MB music_visual/__pycache__/ music_visual/__pycache__/AudioAnalyzer.cpython-310.pyc 7.43KB music_visual/AudioAnalyzer.py 9.01KB music_visual/main.py 7.95KB 资源介绍: 项目简介 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): # 更新旋转音频条的矩形�