""" 均衡器效果处理器 实现专业的音频均衡器效果处理 """ import uuid import math import numpy as np from typing import Dict, List, Any, Optional from scipy import signal class EQProcessor: """ 均衡器效果处理器 实现专业的音频均衡器效果处理 """ def __init__(self, plugin): """ 初始化均衡器效果处理器 Args: plugin: 音频效果插件实例 """ self.plugin = plugin self.effects: Dict[str, Dict[str, Any]] = {} self.filters = {} # 滤波器缓存 self.stats = { 'total_effects': 0, 'active_effects': 0, 'effects_processed': 0, 'processing_time': 0.0, 'memory_usage': 0 } self.buffer_size = plugin.buffer_size if plugin else 4096 self.sample_rate = 44100 # 默认采样率 self.max_bands = 32 # 最大频段数 def create_effect(self, parameters: Dict[str, Any]) -> str: """ 创建均衡器效果 Args: parameters: 均衡器参数 Returns: 效果ID """ try: # 生成唯一ID effect_id = str(uuid.uuid4()) # 默认参数 default_params = { 'bands': { 60: 0.0, # 60Hz - 低频 200: 0.0, # 200Hz - 低中频 500: 0.0, # 500Hz - 中频 1000: 0.0, # 1kHz - 中高频 3000: 0.0, # 3kHz - 高频 8000: 0.0, # 8kHz - 超高频 12000: 0.0 # 12kHz - 极高频 }, 'master_gain': 0.0, # 主增益 (dB) 'filter_type': 'peaking', # 滤波器类型: peaking, low_shelf, high_shelf 'q_factor': 1.0, # Q因子 'solo_band': None, # 独奏频段 'bypass_bands': [] # 绕过频段 } # 合并参数 effect_params = default_params.copy() effect_params.update(parameters) # 验证频段数 if len(effect_params['bands']) > self.max_bands: # 限制频段数 bands = dict(list(effect_params['bands'].items())[:self.max_bands]) effect_params['bands'] = bands print(f"⚠ 频段数超过限制,已限制为 {self.max_bands} 个频段") # 创建效果对象 effect = { 'id': effect_id, 'type': 'eq', 'parameters': effect_params, 'active': True, 'filters': {}, # 各频段滤波器 'buffers': {}, # 缓冲区 'created_time': self._get_current_time(), 'process_count': 0 } # 初始化滤波器 self._initialize_filters(effect) # 初始化缓冲区 self._initialize_buffers(effect) # 存储效果 self.effects[effect_id] = effect # 更新统计信息 self.stats['total_effects'] += 1 self.stats['active_effects'] += 1 # 在插件中注册效果 if self.plugin: self.plugin.effects[effect_id] = effect.copy() print(f"✓ 均衡器效果创建成功: {effect_id}") return effect_id except Exception as e: print(f"✗ 创建均衡器效果失败: {e}") import traceback traceback.print_exc() return "" def _initialize_filters(self, effect: Dict[str, Any]): """ 初始化均衡器滤波器 Args: effect: 效果对象 """ effect_id = effect['id'] parameters = effect['parameters'] bands = parameters['bands'] filter_type = parameters.get('filter_type', 'peaking') q_factor = parameters.get('q_factor', 1.0) filters = {} # 为每个频段创建滤波器 for frequency, gain in bands.items(): # 限制频率范围 frequency = max(20, min(20000, frequency)) # 限制增益范围 gain = max(-24, min(24, gain)) # 创建滤波器系数 filter_coeffs = self._create_filter_coefficients( frequency, gain, q_factor, filter_type) filters[frequency] = { 'frequency': frequency, 'gain': gain, 'q_factor': q_factor, 'type': filter_type, 'coeffs': filter_coeffs, 'state': np.zeros(2) # 滤波器状态 } effect['filters'] = filters def _create_filter_coefficients(self, frequency: float, gain: float, q_factor: float, filter_type: str) -> Dict[str, float]: """ 创建滤波器系数 Args: frequency: 频率 (Hz) gain: 增益 (dB) q_factor: Q因子 filter_type: 滤波器类型 Returns: 滤波器系数字典 """ # 将增益从dB转换为线性 linear_gain = 10 ** (gain / 20.0) # 归一化频率 nyquist = self.sample_rate / 2.0 normalized_freq = frequency / nyquist # 根据滤波器类型创建系数 if filter_type == 'peaking': # 峰值滤波器 coeffs = self._design_peaking_filter(normalized_freq, linear_gain, q_factor) elif filter_type == 'low_shelf': # 低频搁架滤波器 coeffs = self._design_low_shelf_filter(normalized_freq, linear_gain, q_factor) elif filter_type == 'high_shelf': # 高频搁架滤波器 coeffs = self._design_high_shelf_filter(normalized_freq, linear_gain, q_factor) else: # 默认使用峰值滤波器 coeffs = self._design_peaking_filter(normalized_freq, linear_gain, q_factor) return coeffs def _design_peaking_filter(self, freq: float, gain: float, q: float) -> Dict[str, float]: """ 设计峰值滤波器 Args: freq: 归一化频率 gain: 线性增益 q: Q因子 Returns: 滤波器系数 """ # 这里使用简化的设计方法 # 实际应用中会使用更精确的双线性变换设计 # 计算带宽 bandwidth = freq / q # 简化的系数计算 alpha = bandwidth / 2.0 beta = 0.5 * ((1.0 - alpha) / (1.0 + alpha)) gamma = (0.5 + beta) * math.cos(2 * math.pi * freq) if gain >= 1.0: # 提升 delta = (0.5 + beta) * gain - (0.5 - beta) / gain epsilon = ((0.5 + beta) / gain - (0.5 - beta) * gain) * math.cos(2 * math.pi * freq) else: # 衰减 delta = (0.5 + beta) / gain - (0.5 - beta) * gain epsilon = ((0.5 + beta) * gain - (0.5 - beta) / gain) * math.cos(2 * math.pi * freq) # 滤波器系数 a0 = (0.5 + beta) * gain a1 = -gamma a2 = (0.5 - beta) * gain b0 = (0.5 + beta) b1 = -delta b2 = (0.5 - beta) return { 'a0': a0, 'a1': a1, 'a2': a2, 'b0': b0, 'b1': b1, 'b2': b2 } def _design_low_shelf_filter(self, freq: float, gain: float, q: float) -> Dict[str, float]: """ 设计低频搁架滤波器 Args: freq: 归一化频率 gain: 线性增益 q: Q因子 Returns: 滤波器系数 """ # 简化的低频搁架滤波器设计 return self._design_peaking_filter(freq, gain, q) def _design_high_shelf_filter(self, freq: float, gain: float, q: float) -> Dict[str, float]: """ 设计高频搁架滤波器 Args: freq: 归一化频率 gain: 线性增益 q: Q因子 Returns: 滤波器系数 """ # 简化的高频搁架滤波器设计 return self._design_peaking_filter(freq, gain, q) def _initialize_buffers(self, effect: Dict[str, Any]): """ 初始化缓冲区 Args: effect: 效果对象 """ effect_id = effect['id'] buffers = {} # 输入和输出缓冲区 buffers['input'] = np.zeros(self.buffer_size) buffers['output'] = np.zeros(self.buffer_size) effect['buffers'] = buffers def delete_effect(self, effect_id: str) -> bool: """ 删除均衡器效果 Args: effect_id: 效果ID Returns: 是否删除成功 """ if effect_id not in self.effects: print(f"✗ 均衡器效果不存在: {effect_id}") return False try: # 删除效果 del self.effects[effect_id] # 更新统计信息 self.stats['active_effects'] -= 1 # 从插件中移除效果 if self.plugin and effect_id in self.plugin.effects: del self.plugin.effects[effect_id] print(f"✓ 均衡器效果已删除: {effect_id}") return True except Exception as e: print(f"✗ 删除均衡器效果失败: {e}") return False def process(self, audio_data: Any, parameters: Dict[str, Any]) -> Any: """ 处理均衡器效果 Args: audio_data: 输入音频数据 parameters: 效果参数 Returns: 处理后的音频数据 """ try: import time process_start = time.time() # 如果输入是NumPy数组 if isinstance(audio_data, np.ndarray): processed_data = self._process_numpy_array(audio_data, parameters) else: # 对于其他类型的数据,返回原始数据 processed_data = audio_data # 更新统计信息 self.stats['effects_processed'] += 1 self.stats['processing_time'] += (time.time() - process_start) return processed_data except Exception as e: print(f"✗ 均衡器效果处理失败: {e}") return audio_data def _process_numpy_array(self, audio_data: np.ndarray, parameters: Dict[str, Any]) -> np.ndarray: """ 处理NumPy数组音频数据 Args: audio_data: 输入音频数据 parameters: 效果参数 Returns: 处理后的音频数据 """ # 获取参数 bands = parameters.get('bands', {}) master_gain = parameters.get('master_gain', 0.0) solo_band = parameters.get('solo_band', None) bypass_bands = parameters.get('bypass_bands', []) # 应用主增益 if master_gain != 0.0: linear_master_gain = 10 ** (master_gain / 20.0) audio_data = audio_data * linear_master_gain # 应用各频段增益 if bands: # 如果有独奏频段,只处理该频段 if solo_band is not None and solo_band in bands: frequency = solo_band gain = bands[frequency] if frequency not in bypass_bands: audio_data = self._apply_band_filter(audio_data, frequency, gain) else: # 处理所有频段 for frequency, gain in bands.items(): if frequency not in bypass_bands: audio_data = self._apply_band_filter(audio_data, frequency, gain) # 确保输出在有效范围内 processed_data = np.clip(audio_data, -1.0, 1.0) return processed_data def _apply_band_filter(self, audio_data: np.ndarray, frequency: float, gain: float) -> np.ndarray: """ 应用单个频段滤波器 Args: audio_data: 输入音频数据 frequency: 频率 (Hz) gain: 增益 (dB) Returns: 处理后的音频数据 """ # 这里实现简化的频段处理 # 实际应用中会使用更复杂的滤波器设计 if gain == 0.0: return audio_data # 将增益从dB转换为线性 linear_gain = 10 ** (gain / 20.0) # 简化的频率响应应用 # 根据频率调整处理方式 if frequency < 200: # 低频 - 更平滑的处理 processed = audio_data * (0.5 + 0.5 * linear_gain) elif frequency < 2000: # 中频 - 标准处理 processed = audio_data * linear_gain else: # 高频 - 更锐利的处理 processed = audio_data * (1.0 + 0.2 * (linear_gain - 1.0)) return processed def set_parameter(self, effect_id: str, parameter: str, value: Any) -> bool: """ 设置效果参数 Args: effect_id: 效果ID parameter: 参数名 value: 参数值 Returns: 是否设置成功 """ if effect_id not in self.effects: print(f"✗ 均衡器效果不存在: {effect_id}") return False try: self.effects[effect_id]['parameters'][parameter] = value # 如果是滤波器参数,重新初始化滤波器 if parameter == 'bands': self._initialize_filters(self.effects[effect_id]) # 如果是插件中的效果,也更新插件中的副本 if self.plugin and effect_id in self.plugin.effects: self.plugin.effects[effect_id]['parameters'][parameter] = value if parameter == 'bands': self.plugin.effects[effect_id]['filters'] = self.effects[effect_id]['filters'].copy() print(f"✓ 均衡器效果参数已设置: {effect_id}.{parameter} = {value}") return True except Exception as e: print(f"✗ 设置均衡器效果参数失败: {e}") return False def get_parameters(self, effect_id: str) -> Dict[str, Any]: """ 获取效果参数 Args: effect_id: 效果ID Returns: 参数字典 """ if effect_id not in self.effects: return {} return self.effects[effect_id]['parameters'].copy() def enable_effect(self, effect_id: str) -> bool: """ 启用均衡器效果 Args: effect_id: 效果ID Returns: 是否启用成功 """ if effect_id not in self.effects: print(f"✗ 均衡器效果不存在: {effect_id}") return False try: self.effects[effect_id]['active'] = True self.stats['active_effects'] += 1 # 如果是插件中的效果,也更新插件中的副本 if self.plugin and effect_id in self.plugin.effects: self.plugin.effects[effect_id]['active'] = True print(f"✓ 均衡器效果已启用: {effect_id}") return True except Exception as e: print(f"✗ 启用均衡器效果失败: {e}") return False def disable_effect(self, effect_id: str) -> bool: """ 禁用均衡器效果 Args: effect_id: 效果ID Returns: 是否禁用成功 """ if effect_id not in self.effects: print(f"✗ 均衡器效果不存在: {effect_id}") return False try: self.effects[effect_id]['active'] = False self.stats['active_effects'] -= 1 # 如果是插件中的效果,也更新插件中的副本 if self.plugin and effect_id in self.plugin.effects: self.plugin.effects[effect_id]['active'] = False print(f"✓ 均衡器效果已禁用: {effect_id}") return True except Exception as e: print(f"✗ 禁用均衡器效果失败: {e}") return False def cleanup(self): """清理所有资源""" self.effects.clear() self.filters.clear() self.stats = { 'total_effects': 0, 'active_effects': 0, 'effects_processed': 0, 'processing_time': 0.0, 'memory_usage': 0 } print("✓ 均衡器效果处理器资源已清理") def get_stats(self) -> Dict[str, int]: """ 获取统计信息 Returns: 统计信息字典 """ return self.stats.copy() def _get_current_time(self) -> float: """ 获取当前时间(秒) Returns: 当前时间 """ if self.plugin and self.plugin.plugin_manager and self.plugin.plugin_manager.world: return self.plugin.plugin_manager.world.globalClock.getFrameTime() import time return time.time() def update(self, dt: float): """ 更新处理器状态 Args: dt: 时间增量 """ # 这里可以更新任何需要定期更新的状态 pass def set_sample_rate(self, sample_rate: int): """ 设置采样率 Args: sample_rate: 采样率 (Hz) """ old_sample_rate = self.sample_rate self.sample_rate = sample_rate print(f"✓ 均衡器处理器采样率已从 {old_sample_rate} 更新为: {sample_rate} Hz") # 重新初始化所有滤波器以适应新的采样率 for effect_id, effect in self.effects.items(): self._initialize_filters(effect) def set_band_gain(self, effect_id: str, frequency: int, gain: float) -> bool: """ 设置频段增益 Args: effect_id: 效果ID frequency: 频率 (Hz) gain: 增益 (dB) Returns: 是否设置成功 """ if effect_id not in self.effects: print(f"✗ 均衡器效果不存在: {effect_id}") return False try: # 限制增益范围 gain = max(-24, min(24, gain)) # 更新频段增益 parameters = self.effects[effect_id]['parameters'] parameters['bands'][frequency] = gain # 更新滤波器 self._initialize_filters(self.effects[effect_id]) # 更新插件中的副本 if self.plugin and effect_id in self.plugin.effects: self.plugin.effects[effect_id]['parameters']['bands'][frequency] = gain self.plugin.effects[effect_id]['filters'] = self.effects[effect_id]['filters'].copy() print(f"✓ 频段增益已设置: {effect_id} -> {frequency}Hz: {gain}dB") return True except Exception as e: print(f"✗ 设置频段增益失败: {e}") return False def set_master_gain(self, effect_id: str, gain: float) -> bool: """ 设置主增益 Args: effect_id: 效果ID gain: 主增益 (dB) Returns: 是否设置成功 """ return self.set_parameter(effect_id, 'master_gain', max(-24, min(24, gain))) def set_solo_band(self, effect_id: str, frequency: Optional[int]) -> bool: """ 设置独奏频段 Args: effect_id: 效果ID frequency: 频率 (Hz),None表示取消独奏 Returns: 是否设置成功 """ return self.set_parameter(effect_id, 'solo_band', frequency) def bypass_band(self, effect_id: str, frequency: int, bypass: bool = True) -> bool: """ 绕过频段 Args: effect_id: 效果ID frequency: 频率 (Hz) bypass: 是否绕过 Returns: 是否设置成功 """ if effect_id not in self.effects: print(f"✗ 均衡器效果不存在: {effect_id}") return False try: parameters = self.effects[effect_id]['parameters'] bypass_bands = parameters.get('bypass_bands', []) if bypass and frequency not in bypass_bands: bypass_bands.append(frequency) elif not bypass and frequency in bypass_bands: bypass_bands.remove(frequency) parameters['bypass_bands'] = bypass_bands # 更新插件中的副本 if self.plugin and effect_id in self.plugin.effects: self.plugin.effects[effect_id]['parameters']['bypass_bands'] = bypass_bands.copy() print(f"✓ 频段绕过已设置: {effect_id} -> {frequency}Hz: {'是' if bypass else '否'}") return True except Exception as e: print(f"✗ 设置频段绕过失败: {e}") return False def add_band(self, effect_id: str, frequency: int, gain: float = 0.0) -> bool: """ 添加频段 Args: effect_id: 效果ID frequency: 频率 (Hz) gain: 增益 (dB) Returns: 是否添加成功 """ if effect_id not in self.effects: print(f"✗ 均衡器效果不存在: {effect_id}") return False try: # 检查频段数是否超过限制 parameters = self.effects[effect_id]['parameters'] bands = parameters['bands'] if len(bands) >= self.max_bands: print(f"✗ 频段数已达到最大限制: {self.max_bands}") return False # 添加频段 bands[frequency] = gain # 重新初始化滤波器 self._initialize_filters(self.effects[effect_id]) # 更新插件中的副本 if self.plugin and effect_id in self.plugin.effects: self.plugin.effects[effect_id]['parameters']['bands'] = bands.copy() self.plugin.effects[effect_id]['filters'] = self.effects[effect_id]['filters'].copy() print(f"✓ 频段已添加: {effect_id} -> {frequency}Hz: {gain}dB") return True except Exception as e: print(f"✗ 添加频段失败: {e}") return False def remove_band(self, effect_id: str, frequency: int) -> bool: """ 移除频段 Args: effect_id: 效果ID frequency: 频率 (Hz) Returns: 是否移除成功 """ if effect_id not in self.effects: print(f"✗ 均衡器效果不存在: {effect_id}") return False try: parameters = self.effects[effect_id]['parameters'] bands = parameters['bands'] if frequency in bands: del bands[frequency] # 重新初始化滤波器 self._initialize_filters(self.effects[effect_id]) # 更新插件中的副本 if self.plugin and effect_id in self.plugin.effects: self.plugin.effects[effect_id]['parameters']['bands'] = bands.copy() self.plugin.effects[effect_id]['filters'] = self.effects[effect_id]['filters'].copy() print(f"✓ 频段已移除: {effect_id} -> {frequency}Hz") return True else: print(f"⚠ 频段不存在: {effect_id} -> {frequency}Hz") return False except Exception as e: print(f"✗ 移除频段失败: {e}") return False def get_frequency_response(self, effect_id: str, frequencies: List[float] = None) -> Dict[str, Any]: """ 获取频率响应 Args: effect_id: 效果ID frequencies: 频率点列表,如果为None则使用默认频率点 Returns: 频率响应数据 """ if effect_id not in self.effects: return {} if frequencies is None: # 默认频率点(对数分布) frequencies = np.logspace(np.log10(20), np.log10(20000), 1000) parameters = self.effects[effect_id]['parameters'] bands = parameters['bands'] # 计算每个频率点的响应 response = [] for freq in frequencies: gain = 0.0 # 计算所有频段在该频率点的贡献 for band_freq, band_gain in bands.items(): # 简化的频率响应计算 distance = abs(freq - band_freq) / band_freq if distance < 1.0: # 在影响范围内 influence = 1.0 - distance gain += band_gain * influence response.append(gain) return { 'frequencies': frequencies.tolist(), 'response': response, 'master_gain': parameters.get('master_gain', 0.0) } def create_preset(self, preset_name: str) -> Dict[str, Any]: """ 创建均衡器预设 Args: preset_name: 预设名称 Returns: 预设参数字典 """ presets = { 'flat': { 'bands': { 60: 0.0, 200: 0.0, 500: 0.0, 1000: 0.0, 3000: 0.0, 8000: 0.0, 12000: 0.0 } }, 'pop': { 'bands': { 60: -1.0, 200: 2.0, 500: 3.0, 1000: 1.0, 3000: 2.0, 8000: 3.0, 12000: 2.0 }, 'master_gain': 1.0 }, 'rock': { 'bands': { 60: 3.0, 200: 2.0, 500: -1.0, 1000: -2.0, 3000: 1.0, 8000: 3.0, 12000: 2.0 }, 'master_gain': 2.0 }, 'jazz': { 'bands': { 60: 2.0, 200: 1.0, 500: 0.0, 1000: -1.0, 3000: 1.0, 8000: 2.0, 12000: 1.0 }, 'master_gain': 1.0 }, 'classical': { 'bands': { 60: -2.0, 200: -1.0, 500: 0.0, 1000: 1.0, 3000: 2.0, 8000: 1.0, 12000: 0.0 }, 'master_gain': 0.0 }, 'vocal_booster': { 'bands': { 60: -2.0, 200: -1.0, 500: 1.0, 1000: 3.0, 3000: 2.0, 8000: 1.0, 12000: 0.0 }, 'master_gain': 1.0 }, 'bass_boost': { 'bands': { 60: 5.0, 200: 3.0, 500: 1.0, 1000: 0.0, 3000: -1.0, 8000: -2.0, 12000: -3.0 }, 'master_gain': 2.0 }, 'treble_boost': { 'bands': { 60: -3.0, 200: -2.0, 500: -1.0, 1000: 0.0, 3000: 1.0, 8000: 3.0, 12000: 5.0 }, 'master_gain': 1.0 } } return presets.get(preset_name, {}).copy()